// $Id: timesize.cpp,v 1.11 2018/01/03 21:32:58 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein */


#include <cassert>

#include "force.h"
#include "mathx.h"    // for SafeProductWithExp()
#include "timesize.h"

#ifdef DMALLOC_FUNC_CHECK
#include "/usr/local/include/dmalloc.h"
#endif

using namespace std;

//------------------------------------------------------------------------------------

DoubleVec1d GrowTimeSize::PartitionSizeAt(force_type partforce,
                                          const ForceParameters& fp, double etime) const
{
    DoubleVec1d thetas(fp.GetRegionalThetas()), growths(fp.GetGrowthRates());
    return dynamic_cast<PartitionForce*>(*registry.GetForceSummary().
                                         GetForceByTag(partforce))->SumXPartsToParts(thetas, growths, etime);
} // GrowTimeSize::PartitionSizeAt

//------------------------------------------------------------------------------------

DoubleVec1d GrowTimeSize::SizeAt(const ForceParameters& fp, double etime) const
{
    DoubleVec1d thetas(fp.GetRegionalThetas()), growths(fp.GetGrowthRates());
    assert(thetas.size() == growths.size());
    DoubleVec1d newthetas(thetas.size());
    unsigned long param;
    for(param = 0; param < thetas.size(); ++param)
    {
        newthetas[param] = SafeProductWithExp(thetas[param],-growths[param]*etime);
    }

    return newthetas;
} // GrowTimeSize::SizeAt

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

DoubleVec1d StaticTimeSize::PartitionSizeAt(force_type partforce,
                                            const ForceParameters& fp, double etime) const
{
    DoubleVec1d thetas(fp.GetRegionalThetas());
    return dynamic_cast<PartitionForce*>(*registry.GetForceSummary().
                                         GetForceByTag(partforce))->SumXPartsToParts(thetas);
} // StaticTimeSize::PartitionSizeAt

//------------------------------------------------------------------------------------

DoubleVec1d StaticTimeSize::SizeAt(const ForceParameters& fp, double etime)
    const
{
    DoubleVec1d thetas(fp.GetRegionalThetas());
    return thetas;
} // StaticTimeSize::SizeAt

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------

DoubleVec1d LogisticSelectionTimeSize::SizeAt(const ForceParameters& fp,
                                              double t) const
{
    DoubleVec1d thetas(fp.GetRegionalThetas()),
        selcoeffs(fp.GetLogisticSelectionCoefficient());

    if (2 != thetas.size())
    {
        string msg = "LogisticSelectionTimeSize::SizeAt(), needed to receive ";
        msg += "two thetas, one for each allele, but instead received ";
        msg += ToString(thetas.size());
        msg + " thetas.";
        throw implementation_error(msg);
    }

    if (1 != selcoeffs.size())
    {
        string msg = "LogisticSelectionTimeSize::SizeAt(), needed to receive ";
        msg += "1 selection coefficient, but instead received ";
        msg += ToString(selcoeffs.size());
        msg + " coefficients.";
        throw implementation_error(msg);
    }

    DoubleVec1d newthetas(2);
    double t_term = SafeProductWithExp(thetas[1], selcoeffs[0]*t);
    newthetas[0] = (thetas[0]+thetas[1])/(thetas[0] + t_term);
    newthetas[1] = newthetas[0] * t_term;
    newthetas[0] = newthetas[0] * thetas[0];

    return newthetas;
} // LogisticSelectionTimeSize::SizeAt

//------------------------------------------------------------------------------------

DoubleVec1d LogisticSelectionTimeSize::PartitionSizeAt(force_type partforce,
                                                       const ForceParameters& fp, double etime) const
{
    DoubleVec1d emptyvec;
    throw implementation_error("LogisticSelectionTimeSize::PartitionSizeAt() was called; shouldn\'t be?");
    return emptyvec;
} // LogisticSelectionTimeSize::PartitionSizeAt

//____________________________________________________________________________________
