/*
* GeoDiffusionSimulator.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.app.seqgen;
import dr.evolution.util.Taxa;
import dr.evolution.datatype.Microsatellite;
import dr.evolution.tree.Tree;
import dr.evolution.tree.NodeRef;
import dr.evolution.sequence.Sequence;
import dr.oldevomodel.sitemodel.SiteModel;
import dr.evomodel.branchratemodel.BranchRateModel;
import dr.math.MathUtils;
import dr.inference.model.Parameter;
import java.util.ArrayList;
/**
* @author Chieh-Hsi Wu
*/
public class GeoDiffusionSimulator extends SequenceSimulator{
public static final int LATITUDE_INDEX = 0;
public static final int LONGITUDE_INDEX = 1;
private Taxa taxa;
private Microsatellite dataType;
private double maxLat;
private double minLat;
private double maxLong;
private double minLong;
public GeoDiffusionSimulator(
Microsatellite dataType,
Taxa taxa,
Tree tree,
SiteModel siteModel,
BranchRateModel branchRateModel,
double maxLat,
double minLat,
double maxLong,
double minLong) {
super(tree, siteModel, branchRateModel, 1);
this.dataType = dataType;
this.taxa = taxa;
this.maxLat = maxLat;
this.minLat = minLat;
this.maxLong = maxLong;
this.minLong = minLong;
}
/**
* Convert integer representation of microsatellite length to string.
*/
Sequence intArray2Sequence(int [] seq, NodeRef node) {
String sSeq = ""+seq[0];
return new Sequence(m_tree.getNodeTaxon(node), sSeq);
} // intArray2Sequence
public double[][] simulateLocations() {
NodeRef root = m_tree.getRoot();
//assume uniform
double[][] latLongs = new double[m_tree.getNodeCount()][2];
double rootLat = MathUtils.nextDouble()*(maxLat-minLat)+minLat;
double rootLong = MathUtils.nextDouble()*(maxLong-minLong)+minLong;
int rootNum = root.getNumber();
latLongs[rootNum] [LATITUDE_INDEX] = rootLat;
latLongs[rootNum] [LONGITUDE_INDEX] = rootLong;
traverse(root, latLongs[rootNum], latLongs);
return latLongs;
}
void traverse(NodeRef node, double [] parentSequence, double[][] latLongs) {
for (int iChild = 0; iChild < m_tree.getChildCount(node); iChild++) {
NodeRef child = m_tree.getChild(node, iChild);
//find the branch length
final double branchRate = m_branchRateModel.getBranchRate(m_tree, child);
final double branchLength = branchRate * (m_tree.getNodeHeight(node) - m_tree.getNodeHeight(child));
if (branchLength < 0.0) {
throw new RuntimeException("Negative branch length: " + branchLength);
}
double childLat = MathUtils.nextGaussian()*Math.sqrt(branchLength)+parentSequence[LATITUDE_INDEX];
double childLong = MathUtils.nextGaussian()*Math.sqrt(branchLength)+parentSequence[LONGITUDE_INDEX];
int childNum = child.getNumber();
latLongs[childNum][LATITUDE_INDEX] = childLat;
latLongs[childNum][LONGITUDE_INDEX] = childLong;
traverse(m_tree.getChild(node, iChild), latLongs[childNum], latLongs);
}
}
/**
* Convert an alignment to a pattern
*/
public ArrayList simulateGeoAttr(){
double[][] locations = simulateLocations();
ArrayList<Parameter> locationList = new ArrayList<Parameter>();
for(int i = 0; i < m_tree.getExternalNodeCount(); i++){
NodeRef node = m_tree.getNode(i);
String taxaName = m_tree.getTaxon(node.getNumber()).getId();
Parameter location = new Parameter.Default(locations[i]);
System.out.println("taxon: "+taxaName+", lat: "+locations[i][0]+", long: "+locations[i][1]);
locationList.add(location);
}
return locationList;
}
}