/*
* AbstractOutbreak.java
*
* Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
*
* This file is part of BEAST.
* See the NOTICE file distributed with this work for additional
* information regarding copyright ownership and licensing.
*
* BEAST is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* BEAST is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with BEAST; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
package dr.evomodel.epidemiology.casetocase;
import dr.evolution.alignment.PatternList;
import dr.evolution.datatype.DataType;
import dr.evolution.datatype.GeneralDataType;
import dr.evolution.util.Taxa;
import dr.evolution.util.Taxon;
import dr.evolution.util.TaxonList;
import dr.inference.model.AbstractModel;
import dr.inference.model.Parameter;
import java.util.*;
/**
* Abstract class for outbreaks. Implements PatternList for ease of compatibility with AbstractTreeLikelihood,
* but there is one and only one pattern.
*
* User: Matthew Hall
* Date: 14/04/13
*/
public abstract class AbstractOutbreak extends AbstractModel implements PatternList {
protected GeneralDataType caseDataType;
protected TaxonList taxa;
private boolean hasLatentPeriods;
protected final boolean hasGeography;
private final String CASE_NAME = "hostID";
protected ArrayList<AbstractCase> cases;
protected int infectedSize = 0;
public AbstractOutbreak(String name, Taxa taxa){
this(name, taxa, false, true);
}
public AbstractOutbreak(String name, Taxa taxa, boolean hasLatentPeriods, boolean hasGeography){
super(name);
this.taxa = taxa;
ArrayList<String> caseNames = new ArrayList<String>();
for(int i=0; i<taxa.getTaxonCount(); i++){
caseNames.add((String)taxa.getTaxonAttribute(i, CASE_NAME));
}
caseDataType = new GeneralDataType(caseNames);
this.hasLatentPeriods = hasLatentPeriods;
this.hasGeography = hasGeography;
}
public ArrayList<AbstractCase> getCases(){
return new ArrayList<AbstractCase>(cases);
}
public boolean hasLatentPeriods() {
return hasLatentPeriods;
}
public boolean hasGeography(){
return hasGeography;
}
// todo this should be in terms of arbitary distance functions, not kernels
public abstract double getLatentPeriod(AbstractCase aCase);
public double getKernelValue(AbstractCase a, AbstractCase b, SpatialKernel kernel){
if(!hasGeography){
return 1;
} else {
return kernel.value(getDistance(a,b));
}
}
// all the kernel values going TO case a (this is symmetric, usually, but potentially might not be)
public double[] getKernelValues(AbstractCase aCase, SpatialKernel kernel){
double[] out = new double[cases.size()];
for(int i=0; i<out.length; i++){
out[i] = kernel.value(getDistance(aCase, cases.get(i)));
}
return out;
}
public int getCaseIndex(AbstractCase thisCase){
return cases.indexOf(thisCase);
}
public int size(){
return cases.size();
}
public int infectedSize(){
return infectedSize;
}
public abstract double getDistance(AbstractCase a, AbstractCase b);
public AbstractCase getCase(int i){
return cases.get(i);
}
public AbstractCase getCase(String name){
for(AbstractCase thisCase: cases){
if(thisCase.getName().equals(name)){
return thisCase;
}
}
return null;
}
public TaxonList getTaxa(){
return taxa;
}
//************************************************************************
// PatternList implementation
//************************************************************************
// not considering the possibility that we are simultaneously reconstructing more than one transmission tree!
public int getPatternCount(){
return 1;
}
public int getStateCount(){
return size();
}
public int getPatternLength(){
return taxa.getTaxonCount();
}
// @todo if these are never going to be used, get them to throw exceptions
public int[] getPattern(int patternIndex){
int[] out = new int[cases.size()];
for(int i=0; i<cases.size(); i++){
out[i] = i;
}
return out;
}
public int getPatternState(int taxonIndex, int patternIndex){
return taxonIndex;
}
public double getPatternWeight(int patternIndex){
return 1;
}
public double[] getPatternWeights(){
return new double[]{1};
}
public double[] getStateFrequencies(){
double[] out = new double[cases.size()];
Arrays.fill(out, 1/cases.size());
return out;
}
@Override
public boolean areUnique() {
return false;
}
public DataType getDataType(){
return caseDataType;
}
//************************************************************************
// TaxonList implementation
//************************************************************************
public int getTaxonCount(){
return taxa.getTaxonCount();
}
public Taxon getTaxon(int taxonIndex){
return taxa.getTaxon(taxonIndex);
}
public String getTaxonId(int taxonIndex){
return taxa.getTaxonId(taxonIndex);
}
public int getTaxonIndex(String id){
return taxa.getTaxonIndex(id);
}
public int getTaxonIndex(Taxon taxon){
return taxa.getTaxonIndex(taxon);
}
public List<Taxon> asList(){
return taxa.asList();
}
public Object getTaxonAttribute(int taxonIndex, String name){
return taxa.getTaxonAttribute(taxonIndex, name);
}
public Iterator<Taxon> iterator() {
if (taxa == null) throw new RuntimeException("Patterns has no TaxonList");
return taxa.iterator();
}
}