// $Id: force.cpp,v 1.81 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 <algorithm>                    // for stl::remove
#include <cassert>
#include <cmath>
#include <numeric>                      // for stl::accumulate

#include "local_build.h"                // for definition of LAMARC_NEW_FEATURE_RELATIVE_SAMPLING

#include "chainpack.h"
#include "constants.h"
#include "datapack.h"
#include "datatype.h"
#include "defaults.h"
#include "event.h"
#include "force.h"
#include "forcesummary.h"
#include "mathx.h"
#include "plforces.h"
#include "region.h"
#include "registry.h"
#include "runreport.h"
#include "stringx.h"
#include "summary.h"
#include "ui_vars.h"
#include "ui_strings.h"
#include "userparam.h"
#include "xml_strings.h"                // for Force::ToXML() and PartitionForce::GetXMLStatusTag()

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

using namespace std;

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

Force::Force(       force_type          tag,
                    string              name,
                    string              fullname,
                    string              paramname,
                    string              fullparamname,
                    vector<Parameter>   parameters,
                    long                maxevents,
                    double              defvalue,
                    double              maxvalue,
                    double              minvalue,
                    double              maximizer_maxvalue,
                    double              maximizer_minvalue,
                    double              highval,
                    double              lowval,
                    double              highmult,
                    double              lowmult,
                    vector<ParamGroup>  identgroups,
                    vector<ParamGroup>  multgroups,
                    const DoubleVec1d&  paramgroupmults,
                    const UIVarsPrior&  prior)
    :   m_tag(tag),
        m_name(name),
        m_fullname(fullname),
        m_paramname(paramname),
        m_fullparamname(fullparamname),
        m_parameters(parameters),
        m_maxevents(maxevents),
        m_defvalue(defvalue),
        m_maxvalue(maxvalue),
        m_minvalue(minvalue),
        m_maximizer_maxvalue(maximizer_maxvalue),
        m_maximizer_minvalue(maximizer_minvalue),
        m_highval(highval),
        m_lowval(lowval),
        m_highmult(highmult),
        m_lowmult(lowmult),
        m_paramgroupmultipliers(paramgroupmults),
        m_plforceptr(NULL),
        m_identgroups(identgroups),
        m_multgroups(multgroups),
        m_defaultPrior(prior)
{
    // intentionally blank
}

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

DoubleVec1d Force::PopParameters(DoubleVec1d& valuelist)
{
    // chew off as many values from the front of "valuelist"
    // as this force has parameters, and return them.
    // The passed vector is reduced in size.
    DoubleVec1d tempvec;
    DoubleVec1d::iterator start = valuelist.begin();
    DoubleVec1d::iterator end = start + m_parameters.size();

    tempvec.insert(tempvec.end(), start, end);
    valuelist.erase(start, end);
    return tempvec;

} // PopParameters

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

vector<proftype> Force::GetProfileTypes() const
{
    vector<proftype> profiles;

    vector<Parameter>::const_iterator param = m_parameters.begin();
    for ( ; param != m_parameters.end(); ++param)
        profiles.push_back(param->GetProfileType());

    return profiles;

} // GetProfileTypes

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

vector<ParamStatus> Force::GetParamstatuses() const
{
    vector<ParamStatus> pstats;

    vector<Parameter>::const_iterator param = m_parameters.begin();
    for ( ; param != m_parameters.end(); ++param)
        pstats.push_back(param->GetStatus());

    return pstats;

} // GetProfileTypes

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

StringVec1d Force::MakeStartParamReport() const
{
    StringVec1d rpt;
    verbosity_type verbose = registry.GetUserParameters().GetVerbosity();

    if (verbose == NORMAL || verbose == VERBOSE)
    {
        string line = m_fullparamname;
        MethodTypeVec1d meth = registry.GetForceSummary().GetMethods(GetTag());
        DoubleVec1d start = registry.GetForceSummary().GetStartParameters().
            GetGlobalParametersByTag(GetTag());
        if (m_parameters.size() > 1UL)
        {
            line += " (USR = user, WAT = watterson, FST = FST)";
            rpt.push_back(line);
            line = "Population";
            unsigned long param;
            for(param = 0; param < m_parameters.size(); ++param)
            {
                line += " "+indexToKey(param)+" "+ToString(meth[param],false); // false => short version of name
                line += " "+Pretty(start[param],12);
                rpt.push_back(line);
                line.assign(10,' ');
            }
        }
        else
        {
            line += " (" + ToString(meth[0],false) + ")"; // ToString(method_type,false) gives short version of name
            line = MakeJustified(line,-25);
            line += MakeJustified(Pretty(start[0]),25);
            rpt.push_back(line);
        }
    }

    return(rpt);
} // Force::MakeStartParamReport

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

StringVec1d Force::MakeChainParamReport(const ChainOut& chout) const
{
    ForceParameters fparam = chout.GetEstimates();
    return(Tabulate(fparam.GetGlobalParametersByTag(GetTag()), 8));
} // Force::MakeChainParamReport

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

bool Force::HasNoVaryingParameters() const
{
    vector<Parameter>::const_iterator it;
    for (it = m_parameters.begin(); it != m_parameters.end(); ++it)
    {
        if (it->IsVariable()) return false;
    }
    return true;

} // Force::HasNoVaryingParameters

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

DoubleVec2d Force::GetMles() const
{
    assert(m_parameters.size() != 0);   // if there are no Parameters yet it's too early to call this!

    vector<Parameter>::const_iterator it;
    DoubleVec2d result;
    DoubleVec1d empty;

    for (it = m_parameters.begin(); it != m_parameters.end(); ++it)
    {
        if (it->IsValidParameter()) result.push_back(it->GetRegionMLEs());
        else result.push_back(empty);
    }
    return result;

} // GetMles

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

DoubleVec1d Force::GetPopmles() const
{
    assert(m_parameters.size() != 0);   // if there are no Parameters yet it's too early to call this!

    vector<Parameter>::const_iterator it;
    DoubleVec1d result;

    for (it = m_parameters.begin(); it != m_parameters.end(); ++it)
    {
        if (it->IsValidParameter()) result.push_back(it->GetOverallMLE());
        else result.push_back(0.0);
    }
    return result;

} // GetPopmles

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

MethodTypeVec1d Force::GetMethods() const
{
    assert(m_parameters.size() != 0);   // if there are no Parameters yet it's too early to call this!

    vector<Parameter>::const_iterator it;
    MethodTypeVec1d result;

    for (it = m_parameters.begin(); it != m_parameters.end(); ++it)
    {
        result.push_back(it->GetMethod());
    }
    return result;

} // GetMethods

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

StringVec1d Force::GetAllParamNames() const
{
    StringVec1d names;
    vector<Parameter>::const_iterator param;
    for(param = m_parameters.begin(); param != m_parameters.end(); ++param)
        if (param->IsValidParameter())
            names.push_back(param->GetName());
        else
        {
            string emptystring("");
            names.push_back(emptystring);
        }

    return names;

} // GetAllParamNames

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

DoubleVec1d Force::CreateVectorOfParametersWithValue(double val) const
{
    DoubleVec1d pvec(m_parameters.size(),val);

    return pvec;
} // CreateVectorOfParametersWithValue

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

proftype Force::SummarizeProfTypes() const
{
    vector<Parameter>::const_iterator param;
    for(param = m_parameters.begin(); param != m_parameters.end(); ++param)
        if (param->GetProfileType() != profile_NONE)
            return param->GetProfileType();

    return profile_NONE;

} // SummarizeProfTypes

//------------------------------------------------------------------------------------
// GetIdenticalGroupedParams is used in the Forcesummary constructor.

ULongVec2d Force::GetIdenticalGroupedParams() const
{
    ULongVec2d groups;
    for (unsigned long gnum = 0; gnum < m_identgroups.size(); ++gnum)
    {
        if (m_identgroups[gnum].first.Status() == pstat_identical_head)
        {
            ULongVec1d onegroup;
            for (unsigned long pnum = 0; pnum < m_identgroups[gnum].second.size(); ++pnum)
            {
                onegroup.push_back(m_parameters[m_identgroups[gnum].second[pnum]].GetParamVecIndex());
            }
            groups.push_back(onegroup);
        }
    }
    return groups;
}

//------------------------------------------------------------------------------------
// GetMultiplicativeGroupedParams is used in the Forcesummary constructor.

ULongVec2d Force::GetMultiplicativeGroupedParams() const
{
    ULongVec2d groups;
    for (unsigned long gnum = 0; gnum < m_multgroups.size(); ++gnum)
    {
        if (m_multgroups[gnum].first.Status() == pstat_multiplicative_head)
        {
            ULongVec1d onegroup;
            for (unsigned long pnum = 0; pnum < m_multgroups[gnum].second.size(); ++pnum)
            {
                onegroup.push_back(m_parameters [m_multgroups[gnum].second[pnum]].GetParamVecIndex());
            }
            groups.push_back(onegroup);
        }
    }
    return groups;
}

//------------------------------------------------------------------------------------
// GetParamGroupMultipliers is used in the Forcesummary constructor.

DoubleVec1d Force::GetParamGroupMultipliers() const
{
    return m_paramgroupmultipliers;
}

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

string Force::MakeOpeningTag(unsigned long nspaces) const
{
    return MakeIndent(MakeTag(GetXMLName()),nspaces);
}

StringVec1d Force::ToXML(unsigned long nspaces) const
{
    StringVec1d xmllines;
    string line = MakeOpeningTag(nspaces);
    xmllines.push_back(line);

    nspaces += INDENT_DEPTH;
    string mytag(MakeTag(xmlstr::XML_TAG_START_VALUES));
    const ForceParameters& fp = registry.GetForceSummary().GetStartParameters();
    DoubleVec1d params = fp.GetGlobalParametersByTag(GetTag());
    line = MakeIndent(mytag,nspaces) + ToString(params,7) + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_METHOD);
    line = MakeIndent(mytag,nspaces) + ToString(GetMethods()) + MakeCloseTag(mytag);
    xmllines.push_back(line);
    if (m_tag != force_GROW && m_tag != force_COAL)
    {
        mytag = MakeTag(xmlstr::XML_TAG_MAX_EVENTS);
        line = MakeIndent(mytag,nspaces) + ToString(GetMaxEvents()) + MakeCloseTag(mytag);
        xmllines.push_back(line);
    }
    mytag = MakeTag(xmlstr::XML_TAG_PROFILES);
    line = MakeIndent(mytag,nspaces) + " " + ToString(GetProfileTypes()) + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_CONSTRAINTS);
    line = MakeIndent(mytag,nspaces) + " " + ToString(GetParamstatuses()) + MakeCloseTag(mytag);
    xmllines.push_back(line);

    for (unsigned long gnum = 0; gnum < m_identgroups.size(); ++gnum)
    {
        mytag = MakeTagWithConstraint(xmlstr::XML_TAG_GROUP, ToString(m_identgroups[gnum].first.Status()));
        LongVec1d indexes = m_identgroups[gnum].second;
        for (unsigned long i=0; i<indexes.size(); i++)
            indexes[i]++;
        line = MakeIndent(mytag, nspaces) + ToString(indexes) + " " + MakeCloseTag(xmlstr::XML_TAG_GROUP);
        xmllines.push_back(line);
    }

    // MFIX  need a similar code block for multiplicative groups, once the UI format is settled

    //Write out the default prior
    mytag = MakeTagWithType(xmlstr::XML_TAG_PRIOR, ToString(m_defaultPrior.GetPriorType()));
    line = MakeIndent(mytag, nspaces);
    xmllines.push_back(line);
    nspaces += INDENT_DEPTH;

    mytag = MakeTag(xmlstr::XML_TAG_PARAMINDEX);
    line = MakeIndent(mytag, nspaces) + " " + ToString(uistr::allStr) + " " + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_PRIORLOWERBOUND);
    line = MakeIndent(mytag, nspaces) + " " + ToString(m_defaultPrior.GetLowerBound()) + " " + MakeCloseTag(mytag);
    xmllines.push_back(line);
    mytag = MakeTag(xmlstr::XML_TAG_PRIORUPPERBOUND);
    line = MakeIndent(mytag, nspaces) + " " + ToString(m_defaultPrior.GetUpperBound()) + " " + MakeCloseTag(mytag);
    xmllines.push_back(line);
#ifdef LAMARC_NEW_FEATURE_RELATIVE_SAMPLING
    mytag = MakeTag(xmlstr::XML_TAG_RELATIVE_SAMPLE_RATE);
    line = MakeIndent(mytag, nspaces) + " " + ToString(m_defaultPrior.GetSamplingRate()) + " " + MakeCloseTag(mytag);
    xmllines.push_back(line);
#endif

    nspaces -= INDENT_DEPTH;
    line = MakeIndent(MakeCloseTag(xmlstr::XML_TAG_PRIOR), nspaces);
    xmllines.push_back(line);

    //Write out any overridden priors
    for (unsigned long pnum = 0; pnum < m_parameters.size(); ++pnum)
    {
        if (m_parameters[pnum].IsValidParameter())
        {
            Prior thisPrior = m_parameters[pnum].GetPrior();
            if (!(thisPrior == m_defaultPrior))
            {
                mytag = MakeTagWithType(xmlstr::XML_TAG_PRIOR, ToString(thisPrior.GetPriorType()));
                line = MakeIndent(mytag, nspaces);
                xmllines.push_back(line);
                nspaces += INDENT_DEPTH;

                mytag = MakeTag(xmlstr::XML_TAG_PARAMINDEX);
                line = MakeIndent(mytag, nspaces) + " " + ToString(pnum + 1) + " " + MakeCloseTag(mytag);
                xmllines.push_back(line);
                mytag = MakeTag(xmlstr::XML_TAG_PRIORLOWERBOUND);
                line = MakeIndent(mytag, nspaces) + " " + ToString(thisPrior.GetLowerBound()) + " " + MakeCloseTag(mytag);
                xmllines.push_back(line);
                mytag = MakeTag(xmlstr::XML_TAG_PRIORUPPERBOUND);
                line = MakeIndent(mytag, nspaces) + " " + ToString(thisPrior.GetUpperBound()) + " " + MakeCloseTag(mytag);
                xmllines.push_back(line);
#ifdef LAMARC_NEW_FEATURE_RELATIVE_SAMPLING
                mytag = MakeTag(xmlstr::XML_TAG_RELATIVE_SAMPLE_RATE);
                line = MakeIndent(mytag, nspaces) + " " + ToString(thisPrior.GetSamplingRate()) + " " + MakeCloseTag(mytag);
                xmllines.push_back(line);
#endif

                nspaces -= INDENT_DEPTH;
                line = MakeIndent(MakeCloseTag(xmlstr::XML_TAG_PRIOR), nspaces);
                xmllines.push_back(line);

            }
        }
    }

    nspaces -= INDENT_DEPTH;
    line = MakeIndent(MakeCloseTag(GetXMLName()),nspaces);
    xmllines.push_back(line);
    return xmllines;
} // ToXML

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

bool Force::IsAMember(const LongVec1d& m1, const LongVec1d& m2) const
{
    return m1 == m2;
} // IsAMember

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

deque<bool> Force::UseCalculatedValues() const
{
    deque<bool> howtouse;

    vector<Parameter>::const_iterator it;
    for (it = m_parameters.begin(); it != m_parameters.end(); ++it)
    {
        howtouse.push_back(it->GetMethod() != method_USER && it->GetMethod() != method_PROGRAMDEFAULT);
    }

    return howtouse;
} // Force::UseCalculatedValues

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

double Force::Truncate(double target) const
{
    if (target > m_maxvalue)
        return m_maxvalue;
    if (target < m_minvalue)
        return m_minvalue;
    return target;

} // Force::Truncate

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

DoubleVec1d Force::RetrieveGlobalParameters(const ForceParameters& fp) const
{
    return fp.GetGlobalParametersByTag(GetTag());
} // Force::RetrieveParameters

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

DoubleVec1d Force::RetrieveRegionalParameters(const ForceParameters& fp) const
{
    return fp.GetRegionalParametersByTag(GetTag());
} // Force::RetrieveParameters

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

DoubleVec1d Force::RetrieveGlobalLogParameters(const ForceParameters& fp) const
{
    DoubleVec1d params(fp.GetGlobalParametersByTag(GetTag()));
    DoubleVec1d result(params.size(), 0.0);
    LogVec0(params, result);
    return result;
} // Force::RetrieveLogParameters

DoubleVec1d Force::RetrieveRegionalLogParameters(const ForceParameters& fp) const
{
    DoubleVec1d params(fp.GetRegionalParametersByTag(GetTag()));
    DoubleVec1d result(params.size(), 0.0);
    LogVec0(params, result);
    return result;
} // Force::RetrieveLogParameters

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

unsigned long Force::FindOrdinalPosition(long cannonicalpos) const
{
    assert(cannonicalpos >= m_plforceptr->GetStart());
    return cannonicalpos - m_plforceptr->GetStart();
} // Force::FindOrdinalPosition

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

CoalForce::CoalForce(vector<Parameter> parameters,
                     long maxevents,
                     bool withGrowth,
                     bool withLogisticSelection,
                     vector<ParamGroup> identgroups,
                     vector<ParamGroup> multgroups,
                     const DoubleVec1d& paramgroupmults,
                     const UIVarsPrior& prior)
    : Force(    force_COAL,
                "Coal",
                "Coalescence",
                "Theta",
                "Theta",
                parameters,
                maxevents,
                defaults::theta,
                defaults::maxTheta,
                defaults::minTheta,
                defaults::maximization_maxTheta,
                defaults::maximization_minTheta,
                defaults::highvalTheta,
                defaults::lowvalTheta,
                defaults::highmultTheta,
                defaults::lowmultTheta,
                identgroups,
                multgroups,
                paramgroupmults,
                prior)
{
    m_axisname.push_back(string("Population"));
    m_axisname.push_back(string("Region"));

    // Setting up the coalescePL object as a pointer that will be used later by the PostLike::GetPLfunction().
    if(withGrowth)
    {
        m_plforceptr = new CoalesceGrowPL(parameters.size());
    }
    else if (withLogisticSelection)
    {
        m_plforceptr = new CoalesceLogisticSelectionPL(parameters.size());
    }
    else
    {
        m_plforceptr = new CoalescePL (parameters.size());
    }
} // CoalForce constructor

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

vector<Event*> CoalForce::MakeEvents(const ForceSummary& fs) const
{
    vector<Event*> tempvec;
    tempvec.push_back(new ActiveCoal(fs));
    tempvec.push_back(new InactiveCoal(fs));
    return tempvec;
} // MakeEvents

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

Summary* CoalForce::CreateSummary(IntervalData& interval, bool shortness) const
{
    return new CoalSummary(interval, shortness);
} // CreateSummary

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

long CoalForce::ReportDimensionality() const
{
    if(m_parameters.size() == 1)
    {
        return 1L;
    }
    return 2L;
}

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

RegionGammaForce::RegionGammaForce(vector<Parameter> parameters,
                                   vector<ParamGroup> identgroups,
                                   vector<ParamGroup> multgroups,
                                   const DoubleVec1d& paramgroupmults,
                                   const UIVarsPrior& prior)
    : Force(    force_REGION_GAMMA,
                "RegionGamma",
                "Background mutation rate gamma-distributed over regions",
                "Alpha",
                "Scaled shape parameter (\"alpha\")",
                parameters,
                0,
                defaults::gammaOverRegions,
                defaults::maxGammaOverRegions,
                defaults::minGammaOverRegions,
                defaults::maximization_maxGammaOverRegions,
                defaults::maximization_minGammaOverRegions,
                defaults::highvalGammaOverRegions,
                defaults::lowvalGammaOverRegions,
                defaults::highmultGammaOverRegions,
                defaults::lowmultGammaOverRegions,
                identgroups,
                multgroups,
                paramgroupmults,
                prior)  // ignored
{
    // intentionally blank
}

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

vector<Event*> RegionGammaForce::MakeEvents(const ForceSummary&) const
{
    vector<Event*> tempvec;             // Yes this returns an empty vector.
    return tempvec;

} // RegionGammaForce::MakeEvents()

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

long RegionGammaForce::ReportDimensionality() const
{
    return 1L;
}

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

Summary* RegionGammaForce::CreateSummary(IntervalData&, bool) const
{
    return NULL;                        // Yes, we have no summary of our own.

} // RegionGammaForce::CreateSummary

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

MigForce::MigForce(vector<Parameter> parameters,
                   long maxevents,
                   long npop,
                   vector<ParamGroup> identgroups,
                   vector<ParamGroup> multgroups,
                   const DoubleVec1d& paramgroupmults,
                   const UIVarsPrior& prior)
    : PartitionForce(
        force_MIG,
        "Mig",
        "Migration",
        "Mig",
        "Migration Rate",
        parameters,
        maxevents,
        defaults::migration,
        defaults::maxMigRate,
        defaults::minMigRate,
        defaults::maximization_maxMigRate,
        defaults::maximization_minMigRate,
        defaults::highvalMig,
        defaults::lowvalMig,
        defaults::highmultMig,
        defaults::lowmultMig,
        npop,
        identgroups,
        multgroups,
        paramgroupmults,
        prior)
{
    m_axisname.push_back(string("Population"));
    m_axisname.push_back(string("Region"));

    // Setting up the coalescePL object as a pointer that will be used later by the
    // PostLike::GetPLfunction()
    m_plforceptr = new MigratePL (npop);

} // MigForce constructor

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

string MigForce::GetXMLStatusTag() const
{
    return string("");
} // GetXMLStatusTag

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

vector<Event*> MigForce::MakeEvents(const ForceSummary& fs) const
{
    vector<Event*> tempvec;
    tempvec.push_back(new MigEvent(fs));
    return tempvec;
} // MakeEvents

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

Summary* MigForce::CreateSummary(IntervalData& interval, bool shortness) const
{
    return new MigSummary(interval, shortness);
} // CreateSummary

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

DivMigForce::DivMigForce(vector<Parameter> parameters,
                         long maxevents,
                         long npop,
                         vector<ParamGroup> identgroups,
                         vector<ParamGroup> multgroups,
                         const DoubleVec1d& paramgroupmults,
                         const UIVarsPrior& prior)
    : PartitionForce(
        force_DIVMIG,

#if 0                                   // RSGNOTE: Was this.
        "DivMig",
        "DivergenceMigration",
        "DivMig",
        "Divergence Migration Rate",
#else                                   // RSGNOTE: Changed to this.
        "Mig",                          // Is this correct?  Seems odd in a force called "DivMigForce".
        "Migration",                    // These are the arguments to MigForce.
        "Mig",
        "Migration Rate",
#endif

        parameters,
        maxevents,
        defaults::migration,
        defaults::maxMigRate,
        defaults::minMigRate,
        defaults::maximization_maxMigRate,
        defaults::maximization_minMigRate,
        defaults::highvalMig,
        defaults::lowvalMig,
        defaults::highmultMig,
        defaults::lowmultMig,
        npop,
        identgroups,
        multgroups,
        paramgroupmults,
        prior)
{
    m_axisname.push_back(string("Population"));
    m_axisname.push_back(string("Region"));

    // Setting up the coalescePL object as a pointer that will be used later by the
    // PostLike::GetPLfunction()
    m_plforceptr = new DivMigPL (npop);

} // DivMigForce constructor

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

string DivMigForce::GetXMLStatusTag() const
{
    return string("");
} // GetXMLStatusTag

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

vector<Event*> DivMigForce::MakeEvents(const ForceSummary& fs) const
{
    vector<Event*> tempvec;
    tempvec.push_back(new DivMigEvent(fs));
    return tempvec;
} // MakeEvents

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

Summary* DivMigForce::CreateSummary(IntervalData& interval, bool shortness) const
{
    return new DivMigSummary(interval, shortness);
} // CreateSummary

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

RecForce::RecForce(vector<Parameter> parameters,
                   long maxevents,
                   vector<ParamGroup> identgroups,
                   vector<ParamGroup> multgroups,
                   const DoubleVec1d& paramgroupmults,
                   const UIVarsPrior& prior )
    : Force(    force_REC,
                "Rec",
                "Recombination",
                "Rec",
                "Recombination Rate",
                parameters,
                maxevents,
                defaults::recombinationRate,
                defaults::maxRecRate,
                defaults::minRecRate,
                defaults::maximization_maxRecRate,
                defaults::maximization_minRecRate,
                defaults::highvalRec,
                defaults::lowvalRec,
                defaults::highmultRec,
                defaults::lowmultRec,
                identgroups,
                multgroups,
                paramgroupmults,
                prior)
{
    m_axisname.push_back(string(""));
    m_axisname.push_back(string("Region"));

    // Setting up the recombinePL object as a pointer that will be used later by the
    // PostLike::GetPLfunction()
    m_plforceptr = new RecombinePL (0);

} // RecForce constructor

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

vector<Event*> RecForce::MakeEvents(const ForceSummary& fs) const
{
    vector<Event*> tempvec;
    tempvec.push_back(new ActiveRec(fs));
    tempvec.push_back(new InactiveRec(fs));
    return tempvec;
} // MakeEvents

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

Summary* RecForce::CreateSummary(IntervalData& interval, bool shortness) const
{
    // as far as we know, RecSummaries are always short.
    // NB: JDEBUG/MDEBUG? Not in the presence of growth/selection plus disease!
    return new RecSummary(interval, shortness);
} // CreateSummary

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

PartitionForce::PartitionForce(
    force_type          tag,
    string              name,
    string              fullname,
    string              paramname,
    string              fullparamname,
    vector<Parameter>   parameters,
    long                maxevents,
    double              defvalue,
    double              maxvalue,
    double              minvalue,
    double              maximizer_maxvalue,
    double              maximizer_minvalue,
    double              highval,
    double              lowval,
    double              highmult,
    double              lowmult,
    long                npartitions,
    vector<ParamGroup>  identgroups,
    vector<ParamGroup>  multgroups,
    const DoubleVec1d&  paramgroupmults,
    const UIVarsPrior&  prior)
    : Force(        tag,
                    name,
                    fullname,
                    paramname,
                    fullparamname,
                    parameters,
                    maxevents,
                    defvalue,
                    maxvalue,
                    minvalue,
                    maximizer_maxvalue,
                    maximizer_minvalue,
                    highval,
                    lowval,
                    highmult,
                    lowmult,
                    identgroups,
                    multgroups,
                    paramgroupmults,
                    prior),
      m_npartitions(npartitions)
{
    // intentionally blank
    // as a pure-virtual method class, the ctor just calls through
} // PartitionForce::ctor

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

long PartitionForce::ChoosePartition(long origpart, long, bool, long) const
{
    return origpart;
} // PartitionForce::ChoosePartition

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

void PartitionForce::ModifyEvents(const ForceSummary&, vector<Event*>& events) const
{
    vector<Event*>::iterator it;
    for (it = events.begin(); it != events.end(); ++it)
    {

        if ((*it)->Type() == activeRecEvent)
            dynamic_cast<ActiveRec*>(*it)->AddSizeForce(m_tag);

        if ((*it)->Type() == inactiveRecEvent)
            dynamic_cast<InactiveRec*>(*it)->AddSizeForce(m_tag);

    }

} // PartitionForce::ModifyEvents

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

bool PartitionForce::SetPartIndex(long value)
{
    m_partindex = value;
    return true;
} // PartitionForce::SetPartIndex

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

bool PartitionForce::IsAMember(const LongVec1d& m1, const LongVec1d& m2) const
{
    return m1[m_partindex] == m2[m_partindex];
} // PartitionForce::IsAMember

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

DoubleVec1d PartitionForce::CreateVectorOfParametersWithValue(double val) const
{
    DoubleVec1d pvec(m_parameters.size());
    DoubleVec1d::iterator part(pvec.begin());
    unsigned long part1, part2, nparts(GetNPartitions());

    assert(m_parameters.size() == nparts*nparts);

    for(part1 = 0; part1 < nparts && part != pvec.end(); ++part1)
        for(part2 = 0; part2 < nparts; ++part2, ++part)
            if (part1 == part2) *part = 0.0;
            else *part = val;

    return pvec;

} // PartitionForce::CreateVectorOfParametersWithValue

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

StringVec1d PartitionForce::MakeStartParamReport() const
{
    StringVec1d rpt;
    verbosity_type verbose = registry.GetUserParameters().GetVerbosity();

    if (verbose == NORMAL || verbose == VERBOSE)
    {
        string line = m_fullparamname+" (USR = user, FST = FST)";
        rpt.push_back(line);
        MethodTypeVec2d meth = registry.GetForceSummary().Get2DMethods(GetTag());
        DoubleVec2d start = registry.GetForceSummary().GetStartParameters().GetGlobal2dRates(GetTag());
        long nparts = registry.GetDataPack().GetNPartitionsByForceType(GetTag());
        long colwidth1 = 9, colwidth2 = 14;
        long totlength = nparts * colwidth2 + colwidth1;
        line = MakeCentered("from",totlength);
        rpt.push_back(line);
        line = MakeJustified("Pop",colwidth1);
        long part;
        for(part = 0; part < nparts; ++part)
            line += MakeCentered(indexToKey(part),colwidth2);
        rpt.push_back(line);
        line = MakeJustified("into 1",colwidth1);
        for(part = 0; part < nparts; ++part)
        {
            long ipart;
            for(ipart = 0; ipart < nparts; ++ipart)
            {
                string name = ToString(meth[part][ipart], false); // false to get short name
                if (part == ipart) name = "-";
                if (name == "-") line += MakeCentered(name,colwidth2);
                else line += MakeCentered(name + " " + Pretty(start[part][ipart], colwidth1), colwidth2);
            }
            rpt.push_back(line);
            line.erase();
            line = MakeJustified(ToString(part+2),colwidth1);
        }
    }

    return(rpt);
} // PartitionForce::MakeStartParamReport

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

StringVec1d PartitionForce::MakeChainParamReport(const ChainOut& chout) const
{
    return(Tabulate(chout.GetEstimates().GetGlobal2dRates(GetTag()), 8));
} // PartitionForce::MakeChainParamReport

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

DoubleVec1d PartitionForce::SumXPartsToParts(const DoubleVec1d& xparts) const
{
    DoubleVec1d parts(m_npartitions, 0.0);
    LongVec1d nparts(registry.GetDataPack().GetAllNPartitions());

    LongVec1d indicator(registry.GetDataPack().GetNPartitionForces(), 0L);

    DoubleVec1d::const_iterator xpart;
    for(xpart = xparts.begin(); xpart != xparts.end(); ++xpart)
    {
        parts[indicator[m_partindex]] += *xpart;

        long part;
        for(part = nparts.size() - 1; part >= 0; --part)
        {
            ++indicator[part];
            if (indicator[part] < nparts[part]) break;
            indicator[part] = 0;
        }
    }

    return parts;
} // PartitionForce::SumXPartsToParts

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

DoubleVec1d PartitionForce::SumXPartsToParts(const DoubleVec1d& xparts, const DoubleVec1d& growths, double etime) const
{
    DoubleVec1d parts(m_npartitions, 0.0);
    LongVec1d nparts(registry.GetDataPack().GetAllNPartitions());

    LongVec1d indicator(registry.GetDataPack().GetNPartitionForces(), 0L);

    long xpart, nxparts = xparts.size();
    for(xpart = 0; xpart < nxparts; ++xpart)
    {
        parts[indicator[m_partindex]] += xparts[xpart] * exp(-growths[xpart]*etime);

        long part;
        for(part = nparts.size() - 1; part >= 0; --part)
        {
            ++indicator[part];
            if (indicator[part] < nparts[part]) break;
            indicator[part] = 0;
        }
    }

    return parts;
} // PartitionForce::SumXPartsToParts

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

string PartitionForce::MakeStatusXML(const string& mystatus) const
{
    return(GetXMLStatusTag() + mystatus + MakeCloseTag(GetXMLStatusTag()));
} // PartitionForce::MakeStatusXML

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

LocalPartitionForce::LocalPartitionForce(
    force_type          tag,
    string              name,
    string              fullname,
    string              paramname,
    string              fullparamname,
    vector<Parameter>   parameters,
    long                maxevents,
    double              defvalue,
    double              maxvalue,
    double              minvalue,
    double              maximizer_maxvalue,
    double              maximizer_minvalue,
    double              highval,
    double              lowval,
    double              highmult,
    double              lowmult,
    long                npartitions,
    long                localsite,
    vector<ParamGroup>  identgroups,
    vector<ParamGroup>  multgroups,
    const DoubleVec1d&  paramgroupmults,
    const UIVarsPrior&  prior)
    : PartitionForce(
        tag,
        name,
        fullname,
        paramname,
        fullparamname,
        parameters,
        maxevents,
        defvalue,
        maxvalue,
        minvalue,
        maximizer_maxvalue,
        maximizer_minvalue,
        highval,
        lowval,
        highmult,
        lowmult,
        npartitions,
        identgroups,
        multgroups,
        paramgroupmults,
        prior),
      m_localsite(localsite)
{
    // deliberately blank
} // LocalPartitionForce ctor

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

StringVec1d LocalPartitionForce::ToXML(unsigned long nspaces) const
{
    StringVec1d xmllines(Force::ToXML(nspaces));

    string mytag(MakeTag(xmlstr::XML_TAG_DISEASELOCATION));
    nspaces += INDENT_DEPTH;
    string line = MakeIndent(mytag,nspaces) + ToString(GetLocalSite()) + MakeCloseTag(mytag);

    // insert location information just before close tag
    StringVec1d::iterator it = xmllines.end();
    --it;
    xmllines.insert(it,line);

    return xmllines;

} // LocalPartitionForce::ToXML

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

long LocalPartitionForce::ChoosePartition(long origpart, long chosenpart, bool islow, long midpoint) const
{
    // "midpoint" is a recombination Littlelink (the one at center of recombination Biglink, if Biglinks enabled).
    if (!((m_localsite <= midpoint && islow) || (m_localsite > midpoint && !islow)))
    {
        // If the disease marker is NOT present on our branch ...
        return chosenpart;
    }
    else
    {
        return origpart;
    }

} // LocalPartitionForce::ChoosePartition

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

GrowthForce::GrowthForce(vector<Parameter> parameters,
                         long maxevents,
                         vector<ParamGroup> identgroups,
                         vector<ParamGroup> multgroups,
                         const DoubleVec1d& paramgroupmults,
                         const UIVarsPrior& prior )
    : Force(    force_GROW,
                "Grow",
                "Growth",
                "Growth",
                "GrowthRate",
                parameters,
                maxevents,
                defaults::growth,
                defaults::maxGrowRate,
                defaults::minGrowRate,
                defaults::maximization_maxGrowRate,
                defaults::maximization_minGrowRate,
                defaults::highvalGrowth,
                defaults::lowvalGrowth,
                defaults::highmultGrowth,
                defaults::lowmultGrowth,
                identgroups,
                multgroups,
                paramgroupmults,
                prior)
{
    m_axisname.push_back(string("Population"));
    m_axisname.push_back(string("Region"));

    // setting up the growPL object
    // as a pointer that will be used later by the
    // PostLike::GetPLfunction()
    m_plforceptr = new GrowPL (parameters.size());

} // GrowthForce::ctor

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

vector<Event*> GrowthForce::MakeEvents(const ForceSummary&) const
{
    vector<Event*> tempvec;             // Yes this returns an empty vector.
    return tempvec;

} // GrowthForce::MakeEvents()

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

Summary* GrowthForce::CreateSummary(IntervalData&, bool) const
{
    return NULL;                        // Yes, we have no summary of our own.

} // CreateSummary

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

void GrowthForce::ModifyEvents(const ForceSummary&, vector<Event*>&) const
{
    // this is now a no-op
} // GrowthForce::ModifyEvents()

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

DoubleVec1d GrowthForce::RetrieveGlobalLogParameters(const ForceParameters& fp) const
{
    DoubleVec1d params(fp.GetGlobalParametersByTag(GetTag()));

    return params;

} // Force::RetrieveLogParameters

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

DoubleVec1d GrowthForce::RetrieveRegionalLogParameters(const ForceParameters& fp) const
{
    DoubleVec1d params(fp.GetRegionalParametersByTag(GetTag()));

    return params;

} // Force::RetrieveLogParameters

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

long GrowthForce::ReportDimensionality() const
{
    if(m_parameters.size() == 1)
    {
        return 1L;
    }
    return 2L;
}

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

string GrowthForce::MakeOpeningTag(unsigned long nspaces) const
{
    return MakeIndent(MakeTagWithType(GetXMLName(),ToString(growth_CURVE)), nspaces);
}

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

LogisticSelectionForce::LogisticSelectionForce(vector<Parameter> parameters,
                                               long maxevents,
                                               long paramvecindex,
                                               vector<ParamGroup> identgroups,
                                               vector<ParamGroup> multgroups,
                                               const DoubleVec1d& paramgroupmults,
                                               const UIVarsPrior& prior )
    : Force(    force_LOGISTICSELECTION,
                "LSelect",
                "Logistic Selection",
                "LSelectCoeff",
                "Logistic Selection Coefficient",
                parameters,
                maxevents,
                defaults::logisticSelection,
                defaults::maxLSelectCoeff,
                defaults::minLSelectCoeff,
                defaults::maximization_maxLSelectCoeff,
                defaults::maximization_minLSelectCoeff,
                defaults::highvalLSelect,
                defaults::lowvalLSelect,
                defaults::highmultLSelect,
                defaults::lowmultLSelect,
                identgroups,
                multgroups,
                paramgroupmults,
                prior)
{
    m_axisname.push_back(string("Population"));
    m_axisname.push_back(string("Region"));

    long numPartitionForces = registry.GetDataPack().GetNPartitionForces();

    if (1 != numPartitionForces)
    {
        string msg = "LogisticSelectionForce constructor, detected ";
        msg += ToString(numPartitionForces) + " partition forces; ";
        msg += "currently, only one such force type is allowed.";
        throw implementation_error(msg);
    }
    long numCrossPartitions = registry.GetDataPack().GetNCrossPartitions();
    if (2 != numCrossPartitions)
    {
        string msg = "LogisticSelectionForce constructor, detected ";
        msg += ToString(numCrossPartitions) + " populations; ";
        msg += "must have exactly 2, one for the favored allele, ";
        msg += "one for the disfavored allele.";
        throw implementation_error(msg);
    }
    // Setting up the LogisticSelectionPL object as a pointer that will be used later by the
    // PostLike::GetPLfunction()
    m_plforceptr = new LogisticSelectionPL(paramvecindex);

} // LogisticSelectionForce::ctor

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

vector<Event*> LogisticSelectionForce::MakeEvents(const ForceSummary&) const
{
    vector<Event*> tempvec;             // Yes this returns an empty vector.
    return tempvec;

} // LogisticSelectionForce::MakeEvents()

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

Summary* LogisticSelectionForce::CreateSummary(IntervalData&, bool) const
{
    return NULL;                        // Yes, we have no summary of our own.

} // CreateSummary

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

void LogisticSelectionForce::ModifyEvents(const ForceSummary&, vector<Event*>&) const
{
    // this is now a no-op
} // LogisticSelectionForce::ModifyEvents()

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

DoubleVec1d LogisticSelectionForce::RetrieveGlobalLogParameters(const ForceParameters& fp) const
{
    DoubleVec1d params(fp.GetGlobalParametersByTag(GetTag()));

    return params;

}

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

DoubleVec1d LogisticSelectionForce::RetrieveRegionalLogParameters(const ForceParameters& fp) const
{
    DoubleVec1d params(fp.GetRegionalParametersByTag(GetTag()));

    return params;

}

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

long LogisticSelectionForce::ReportDimensionality() const
{
    if(m_parameters.size() == 1)
    {
        return 1L;
    }
    return 2L;
}

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

string LogisticSelectionForce::MakeOpeningTag(unsigned long nspaces) const
{
    return MakeIndent(MakeTag(GetXMLName()), nspaces);
}

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

DiseaseForce::DiseaseForce(
    vector<Parameter> parameters,
    long maxevents,
    bool hasLogisticSelection,
    long nstates,
    long localsite,
    vector<ParamGroup> identgroups,
    vector<ParamGroup> multgroups,
    const DoubleVec1d& paramgroupmults,
    const UIVarsPrior& prior)
    : LocalPartitionForce(
        force_DISEASE,
        "Disease",
        "Disease Status",
        "Disease MuRate",
        "Disease Mutation Rate",
        parameters,
        maxevents,
        defaults::disease,
        defaults::maxDiseaseRate,
        defaults::minDiseaseRate,
        defaults::maximization_maxDiseaseRate,
        defaults::maximization_minDiseaseRate,
        defaults::highvalDisease,
        defaults::lowvalDisease,
        defaults::highmultDisease,
        defaults::lowmultDisease,
        nstates,
        localsite,
        identgroups,
        multgroups,
        paramgroupmults,
        prior)
{
    m_axisname.push_back(string("Population"));
    m_axisname.push_back(string("Region"));

    // Setting up the diseasePL object as a pointer that will be used later by the
    // PostLike::GetPLfunction()
    if (hasLogisticSelection)
        m_plforceptr = new DiseaseLogisticSelectionPL(nstates);
    else
        m_plforceptr = new DiseasePL(nstates);
    assert(parameters.size()==static_cast<DoubleVec1d::size_type>(nstates*nstates));

} // DiseaseForce::ctor

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

string DiseaseForce::GetXMLStatusTag() const
{
    return MakeTag(xmlstr::XML_TAG_DISEASESTATUS);
} // DiseaseForce::GetXMLStatusTag

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

vector<Event*> DiseaseForce::MakeEvents(const ForceSummary& fs) const
{
    vector<Event*> tempvec;
    tempvec.push_back(new DiseaseEvent(fs));
    return tempvec;
} // MakeEvents

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

Summary* DiseaseForce::CreateSummary(IntervalData& interval, bool shortness) const
{
    return new DiseaseSummary(interval, shortness);
} // DiseaseForce::CreateSummary

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

StickForce::StickForce(
    force_type         tag,
    string             name,
    string             fullname,
    string             paramname,
    string             fullparamname,
    vector<Parameter>  parameters,
    long               maxevents,
    double             defvalue,
    double             maxvalue,
    double             minvalue,
    double             maximizer_maxvalue,
    double             maximizer_minvalue,
    double             highval,
    double             lowval,
    double             highmult,
    double             lowmult,
    vector<ParamGroup> identgroups,
    vector<ParamGroup> multgroups,
    const DoubleVec1d& paramgroupmults,
    const UIVarsPrior& prior)
    : Force(tag,name,fullname,paramname,fullparamname,parameters,
            maxevents,defvalue,maxvalue,minvalue,maximizer_maxvalue,
            maximizer_minvalue,highval,lowval,highmult,
            lowmult,identgroups,multgroups,paramgroupmults,prior),
      m_percentchange(defaults::perThetaChange)
{
    // intentionally blank
    // as a pure-virtual method class, the ctor just calls through
} // StickForce::ctor

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

StickExpGrowForce::StickExpGrowForce(
    vector<Parameter> parameters,
    long maxevents ,
    vector<ParamGroup> identgroups,
    vector<ParamGroup> multgroups,
    const DoubleVec1d& paramgroupmults,
    const UIVarsPrior& prior)
    : StickForce(
        force_EXPGROWSTICK,
        "StickExpGrow",
        "StickExpGrow Status",
        "StickExpGrow MuRate",
        "StickExpGrow Mutation Rate",
        parameters,
        maxevents,
        defaults::growth,
        defaults::maxGrowRate,
        defaults::minGrowRate,
        defaults::maximization_maxGrowRate,
        defaults::maximization_minGrowRate,
        defaults::highvalGrowth,
        defaults::lowvalGrowth,
        defaults::highmultGrowth,
        defaults::lowmultGrowth,
        identgroups,
        multgroups,
        paramgroupmults,
        prior),
      m_negln(log(1.0+m_percentchange)),
      m_posln(log(1.0-m_percentchange))

{
    m_axisname.push_back(string("Population"));
    m_axisname.push_back(string("Region"));
    // setting up the normal growPL object
    // as a pointer that will be used later by the
    // PostLike::GetPLfunction()
    m_plforceptr = new GrowPL (parameters.size());

} // StickExpGrowForce::ctor

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

string StickExpGrowForce::MakeOpeningTag(unsigned long nspaces) const
{
    return MakeIndent(MakeTagWithType(GetXMLName(), xmlstr::XML_ATTRVALUE_STICKEXP),nspaces);
}

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

string StickExpGrowForce::GetXMLName() const
{
    return xmlstr::XML_TAG_GROWTH;
}

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

vector<Event*> StickExpGrowForce::MakeEvents(const ForceSummary&) const
{
    vector<Event*> tempvec;             // Yes this returns an empty vector.
    return tempvec;
}

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

void StickExpGrowForce::ModifyEvents(const ForceSummary&, vector<Event*>&) const
{
    // this is now a no-op
} // StickExpGrowForce::ModifyEvents()

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

Summary* StickExpGrowForce::CreateSummary(IntervalData&, bool) const
{
    return NULL;                        // Yes, we have no summary of our own.
}

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

DoubleVec1d StickExpGrowForce::RetrieveGlobalLogParameters
(const ForceParameters& fp) const
{
    DoubleVec1d params(fp.GetGlobalParametersByTag(GetTag()));
    return params;
}

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

DoubleVec1d StickExpGrowForce::RetrieveRegionalLogParameters
(const ForceParameters& fp) const
{
    DoubleVec1d params(fp.GetRegionalParametersByTag(GetTag()));
    return params;
}

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

long StickExpGrowForce::ReportDimensionality() const
{
    if (m_parameters.size() == 1)
    {
        return 1L;
    }
    return 2L;
}

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

StickSelectForce::StickSelectForce(
    vector<Parameter> parameters,
    long maxevents ,
    vector<ParamGroup> identgroups,
    vector<ParamGroup> multgroups,
    const DoubleVec1d& paramgroupmults,
    const UIVarsPrior& prior)
    : StickForce(
        force_LOGSELECTSTICK,
        "StickSelect",
        "StickSelect Status",
        "StickSelect MuRate",
        "StickSelect Mutation Rate",
        parameters,
        maxevents,
        defaults::logisticSelection,
        defaults::maxLSelectCoeff,
        defaults::minLSelectCoeff,
        defaults::maximization_maxLSelectCoeff,
        defaults::maximization_minLSelectCoeff,
        defaults::highvalLSelect,
        defaults::lowvalLSelect,
        defaults::highmultLSelect,
        defaults::lowmultLSelect,
        identgroups,
        multgroups,
        paramgroupmults,
        prior)

{
    m_axisname.push_back(string("Population"));
    m_axisname.push_back(string("Region"));
    const DataPack& dp(registry.GetDataPack());

    long numpforces(dp.GetNPartitionForces());
    if (numpforces != 1)
    {
        string msg = "StickLogisticSelectionForce constructor, detected ";
        msg += ToString(numpforces) + " partition forces; ";
        msg += "currently, only one such force type is allowed.";
        throw implementation_error(msg);
    }
    long numcpforces(dp.GetNCrossPartitions());
    if (numcpforces != 2)
    {
        string msg = "StickLogisticSelectionForce constructor, detected ";
        msg += ToString(numcpforces) + " populations; ";
        msg += "must have exactly 2, one for the favored allele, ";
        msg += "one for the disfavored allele.";
        throw implementation_error(msg);
    }

    // The ForceSummary() does not necessairly exist when we call this ctor in Registry::InstallForcesAllOverThePlace().
    // Also, we need special case code when putting PLForces into the PostLike objects.  So, we will defer construction
    // of the PLForces object until then.
    // m_plforceptr = new StickSelectPL (registry.GetForceSummary());

} // StickSelectForce::ctor

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

string StickSelectForce::GetXMLName() const
{
    return xmlstr::XML_TAG_STOCHASTICSELECTION;
}

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

vector<Event*> StickSelectForce::MakeEvents(const ForceSummary&) const
{
    vector<Event*> tempvec;             // Yes this returns an empty vector.
    return tempvec;
}

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

string StickSelectForce::MakeOpeningTag(unsigned long nspaces) const
{
    return MakeIndent(MakeTagWithType(GetXMLName(), xmlstr::XML_ATTRVALUE_STICK),nspaces);
}

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

Summary* StickSelectForce::CreateSummary(IntervalData&, bool) const
{
    return NULL;                        // Yes, we have no summary of our own.
}

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

DoubleVec1d StickSelectForce::RetrieveGlobalLogParameters(const ForceParameters& fp) const
{
    DoubleVec1d params(fp.GetRegionalParametersByTag(GetTag()));
    return params;
}

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

DoubleVec1d StickSelectForce::RetrieveRegionalLogParameters(const ForceParameters& fp) const
{
    DoubleVec1d params(fp.GetRegionalParametersByTag(GetTag()));
    return params;
}

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

long StickSelectForce::ReportDimensionality() const
{
    if(m_parameters.size() == 1) return 1L;
    else return 2L;
}

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

DivForce::DivForce(vector<Parameter> parameters, long int, //maxEvents unused.
                   vector<ParamGroup> identgroups,
                   vector<ParamGroup> multgroups,
                   const DoubleVec1d& paramgroupmults,
                   const UIVarsPrior& prior,
                   const vector<vector<string> >& newpops,
                   const vector<string>& ancestors,
                   const DataPack& dpack)
    : Force(force_DIVERGENCE,
            "Div",
            "Divergence",
            "Epoch",
            "EpochTime",
            parameters,
            defaults::epochEvents,
            defaults::epochtime,
            defaults::maxEpoch,
            defaults::minEpoch,
            defaults::maximization_maxEpoch,
            defaults::maximization_minEpoch,
            defaults::highvalEpoch,
            defaults::lowvalEpoch,
            defaults::highmultEpoch,
            defaults::lowmultEpoch,
            identgroups,
            multgroups,
            paramgroupmults,
            prior)
{
    // DO EPOCHS HERE

    // Create initial list of populations.
    LongVec1d pops_here;
    for (long pop = 0; pop < dpack.GetNumTipPopulations(); ++pop)
        pops_here.push_back(pop);

    // The first Epoch has no child or ancestor info, just pops_here.
    vector<long> fakeancestors;
    Epoch firstepoch(pops_here, fakeancestors, FLAGLONG);
    m_epochs.push_back(firstepoch);

    // The remaining Epochs
    for (StringVec2d::size_type ep = 0; ep < newpops.size(); ++ep)
    {
        LongVec1d children;
        for (StringVec1d::size_type pop = 0; pop < newpops[ep].size(); ++pop)
        {
            children.push_back(dpack.GetPartitionNumber(force_DIVMIG,newpops[ep][pop]));
        }
        long ancestornum(dpack.GetPartitionNumber(force_DIVMIG,ancestors[ep]));
        // fix up the current populations list for the boundary changes
        for (LongVec1d::const_iterator searchpop = children.begin();
             searchpop != children.end(); ++searchpop)
        {
            pops_here.erase(remove(pops_here.begin(),pops_here.end(),*searchpop), pops_here.end());
        }
        pops_here.push_back(ancestornum);

        // Make the epoch.
        Epoch epoch(pops_here,children,ancestornum);
        m_epochs.push_back(epoch);
    }

    m_axisname.push_back(string("Population"));
    m_axisname.push_back(string("Region"));

    // NB:  Even though these parameters don't factor into P(G|param), we make
    // a PLForce to keep the maximizer happy--it expects all parameters to
    // correspond to a PLForce.
    m_plforceptr = new DivPL(m_epochs.size() - 1);
}

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

long DivForce::ReportDimensionality() const
{
    if(m_parameters.size() == 1)
    {
        return 1L;
    }
    return 2L;
}

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

Summary* DivForce::CreateSummary(IntervalData& interval, bool shortness) const
{
    return new EpochSummary(interval, shortness); // Apparently we do have a Summary!.
    // It must be used to mark boundary lines in the tree....
} // CreateSummary

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

vector<Event*> DivForce::MakeEvents(const ForceSummary& fs) const
{
    vector<Event*> myevents;
    myevents.push_back(new EpochEvent(fs));
    return myevents;
} // MakeEvents

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

StringVec1d DivForce::ToXML(unsigned long nspaces) const
{
    StringVec1d xmllines(Force::ToXML(nspaces));
    StringVec1d epochblock;

    StringVec1d popsList = registry.GetDataPack().GetAllPartitionNames(force_DIVMIG);
    string poptree(MakeTag(xmlstr::XML_TAG_POPTREE));

    nspaces += INDENT_DEPTH;
    // population-tree
    string line = MakeIndent(poptree, nspaces);
    epochblock.push_back(line);
    unsigned long epoch;
    // we do not write XML for the first epoch
    for (epoch = 1; epoch < m_epochs.size(); ++epoch)
    {
        // epoch-boundary
        string boundary(MakeTag(xmlstr::XML_TAG_EPOCH_BOUNDARY));
        nspaces += INDENT_DEPTH;
        line = MakeIndent(boundary, nspaces);
        epochblock.push_back(line);

        // new-populations
        string newpop(MakeTag(xmlstr::XML_TAG_NEWPOP));
        nspaces += INDENT_DEPTH;
        line = MakeIndent(newpop,nspaces);

        unsigned long pop;
        for (pop = 0; pop < m_epochs[epoch].Departing().size(); ++pop)
        {
            long epochIndex = m_epochs[epoch].Departing()[pop];
            string popName = popsList[epochIndex];
            line += " " + popName;
        }

        line += " " + MakeCloseTag(newpop);
        epochblock.push_back(line);

        // ancestor
        string ancestor(MakeTag(xmlstr::XML_TAG_ANCESTOR));
        long ancestorIndex = m_epochs[epoch].Arriving();
        line = MakeIndent(ancestor,nspaces) + " " + popsList[ancestorIndex] + " " + MakeCloseTag(ancestor);
        epochblock.push_back(line);
        nspaces -= INDENT_DEPTH;

        // end epoch-boundary
        line = MakeIndent(MakeCloseTag(boundary),nspaces);
        epochblock.push_back(line);
    }

    //  end population-tree
    nspaces -= INDENT_DEPTH;
    line = MakeIndent(MakeCloseTag(poptree),nspaces);
    epochblock.push_back(line);

    // add to existing array just before end
    // very inefficient but I doubt this matters
    unsigned long i;
    for (i = 0; i < epochblock.size(); ++i)
    {
        StringVec1d::iterator it = xmllines.end();
        --it;
        xmllines.insert(it,epochblock[i]);
    }

    return xmllines;
} // DivForce::ToXML

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

StringVec1d Tabulate(double params, long width=7)
{
    StringVec1d str;
    str.push_back(Pretty(params,width));
    return(str);
} // Tabulate(double)

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

StringVec1d Tabulate(const DoubleVec1d& params, long width=7)
{
    StringVec1d str;
    long i;
    for (i = 0; i < (long)params.size(); ++i) str.push_back(Pretty(params[i],width));
    return(str);
} // Tabulate(DoubleVec1d)

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

StringVec1d Tabulate(const DoubleVec2d& params, long width=7)
{
    StringVec1d str;
    long i;
    long j;
    for (i = 0; i < static_cast<long>(params.size()); ++i)
    {
        string tempstr = "";
        for (j = 0; j < static_cast<long>(params[0].size()); ++j)
        {
            if (j != 0) tempstr += " ";
            if (j != i) tempstr += Pretty(params[i][j],width);
            else
            {
                long k;
                for (k = 0; k < width; ++k) tempstr += "-";
            }
            tempstr += " ";
        }
        str.push_back(tempstr);
    }
    return(str);
} // Tabulate(DoubleVec2d)

//____________________________________________________________________________________
