/*
* TwoEpochDemographic.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.evolution.coalescent;
/**
* This class models a demographic function that contains two epochs.
*
* @author Alexei Drummond
*
* @version $Id: TwoEpochDemographic.java,v 1.7 2005/05/24 20:25:56 rambaut Exp $
*/
public class TwoEpochDemographic extends DemographicFunction.Abstract {
private DemographicFunction epoch1;
private DemographicFunction epoch2;
private double transitionTime;
/**
* Construct demographic model with default settings.
*/
public TwoEpochDemographic(DemographicFunction epoch1, DemographicFunction epoch2, Type units) {
super(units);
this.epoch1 = epoch1;
this.epoch2 = epoch2;
}
/**
* @return the time of the transition between the two demographic functions.
*/
public final double getTransitionTime() { return transitionTime; }
public final void setTransitionTime(double t) {
if (t < 0.0 || t > Double.MAX_VALUE) {
throw new IllegalArgumentException("transition time out of bounds.");
}
transitionTime = t;
}
public final DemographicFunction getFirstEpochDemography() {
return epoch1;
}
public final DemographicFunction getSecondEpochDemography() {
return epoch2;
}
// Implementation of abstract methods
public final double getDemographic(double t) {
if (t < transitionTime) {
return epoch1.getDemographic(t);
} else {
return epoch2.getDemographic(t-transitionTime);
}
}
public final double getIntensity(double t) {
if (t < transitionTime) {
return epoch1.getIntensity(t);
} else {
return epoch1.getIntensity(transitionTime) + epoch2.getIntensity(t-transitionTime);
}
}
/**
* By overriding this function we ensure that the integral can still be found when one of the sub-demographic models does not implement getIntensity.
* @param start
* @param finish
* @return the integral of the demographic function between start and finish
*/
public final double getIntegral(double start, double finish) {
if (start < transitionTime) {
if (finish < transitionTime) {
return epoch1.getIntegral(start, finish);
} else {
return epoch1.getIntegral(start, transitionTime) + epoch2.getIntegral(0, finish-transitionTime);
}
} else {
return epoch2.getIntegral(start-transitionTime, finish-transitionTime);
}
}
/**
* @param x a value of intensity
* @return the time in the past that corresponds to the given intensity.
*/
public final double getInverseIntensity(double x) {
double time = epoch1.getInverseIntensity(x);
if (time < transitionTime) {
return time;
}
x -= epoch1.getIntensity(transitionTime);
return transitionTime + epoch2.getInverseIntensity(x);
}
public int getNumArguments() {
return epoch1.getNumArguments() + epoch2.getNumArguments() + 1;
}
public final String getArgumentName(int n) {
if (n < epoch1.getNumArguments()) {
return epoch1.getArgumentName(n);
}
n -= epoch1.getNumArguments();
if (n < epoch2.getNumArguments()) {
return epoch2.getArgumentName(n);
}
n -= epoch2.getNumArguments();
if (n == 0) return "transitionTime";
throw new IllegalArgumentException();
}
public final double getArgument(int n) {
if (n < epoch1.getNumArguments()) {
return epoch1.getArgument(n);
}
n -= epoch1.getNumArguments();
if (n < epoch2.getNumArguments()) {
return epoch2.getArgument(n);
}
n -= epoch2.getNumArguments();
if (n == 0) return transitionTime;
throw new IllegalArgumentException();
}
public final void setArgument(int n, double value) {
if (n < epoch1.getNumArguments()) {
epoch1.setArgument(n, value);
}
n -= epoch1.getNumArguments();
if (n < epoch2.getNumArguments()) {
epoch2.setArgument(n, value);
}
n -= epoch2.getNumArguments();
if (n == 0) transitionTime = value;
throw new IllegalArgumentException();
}
/**
* @return the lower bound of the nth argument of this function.
*/
public final double getLowerBound(int n) {
if (n < epoch1.getNumArguments()) {
return epoch1.getLowerBound(n);
}
n -= epoch1.getNumArguments();
if (n < epoch2.getNumArguments()) {
return epoch2.getLowerBound(n);
}
n -= epoch2.getNumArguments();
if (n == 0) return 0.0;
throw new IllegalArgumentException();
}
/**
* @return the upper bound of the nth argument of this function.
*/
public final double getUpperBound(int n) {
if (n < epoch1.getNumArguments()) {
return epoch1.getUpperBound(n);
}
n -= epoch1.getNumArguments();
if (n < epoch2.getNumArguments()) {
return epoch2.getUpperBound(n);
}
n -= epoch2.getNumArguments();
if (n == 0) return Double.MAX_VALUE;
throw new IllegalArgumentException();
}
public final DemographicFunction getCopy() {
TwoEpochDemographic df = new TwoEpochDemographic(epoch1, epoch2, getUnits());
df.setTransitionTime(transitionTime);
return df;
}
}