// $Id: branch.cpp,v 1.110 2018/01/03 21:33:03 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>
#include <cassert>
#include <iostream>                     // for debug cerr
#include <numeric>                      // for std::accumulate

#ifdef DMALLOC_FUNC_CHECK
#include <dmalloc.h>
#endif

#include "local_build.h"

#include "branch.h"
#include "branchbuffer.h"
#include "datapack.h"
#include "range.h"                      // For Link-related typedefs and constants.
#include "summary.h"
#include "treesum.h"

#include "force.h"                      // for RBranch::RecCopyPartitionsFrom, Branch::IsAMember
#include "locus.h"                      // for TipData stuff used in constructor

#include "tinyxml.h"

// This turns on the detailed print out of the creation and analysis of each coalescence tree.
// JRM 4/10
//#define PRINT_TREE_DETAILS

// Print details of what was used in the summary scoring.
// JRM 4/10
//#define PRINT_SUMMARY_DETAILS

using namespace std;

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

// Initialization of static variable; needs to be in .cpp file.  It is being initialized to the result
// of calling the implicit default constructor for Branch_ptr (ie, boost::shared_ptr<Branch>).
Branch_ptr Branch::NONBRANCH;

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

string ToString(branch_type btype)
{
    switch(btype)
    {
        case btypeBase:   return "Base";
        case btypeTip:    return "Tip";
        case btypeCoal:   return "Coalescence";
        case btypeMig:    return "Migration";
        case btypeDivMig: return "DivMigration";
        case btypeDisease:return "Disease";
        case btypeRec:    return "Recombination";
        case btypeEpoch:  return "Epochboundary";
    }

    assert(false);
    return "";
}

//------------------------------------------------------------------------------------
// Initializes Branch's Range pointer object to pointer value of argument, not to pointer to copy of that object.
// Thus, be sure that caller of this constructor either constructs a new Range or constructs a new copy of one.
// THIS CTOR does a SHALLOW COPY of its RANGE-OBJECT POINTER.
//
// This constructor is the only one which behaves this way.  For all classes derived from Branch, constructors which
// take as a single argument or as one or more of several arguments a const Range * const value must be given a
// pointer to a freshly-allocated or copied (by a deep-copying constructor) object.  ALL OTHER CTORS (for classes
// derived from Branch) do a DEEP COPY of their RANGE-OBJECT POINTER-valued argument(s).  They usually do so by
// allocating (using CreateRange) or copying (using a deep-copying copy constructor) and passing the result
// to THIS constructor.

Branch::Branch(Range * newrangeptr)
    : boost::enable_shared_from_this<Branch>(),
      // Initialize m_rangePtr to pointer to original object (having been allocated by caller), not to pointer
      // to COPY of pointee.  Ie, this is a shallow copy.  All callers of this constructor must freshly-allocate
      // or deep-copy the Range object whose pointer they pass to this function.
      // "newrangeptr" may be NULL (if the BBranch ctor is called).  This is OK; do not ASSERT here.
      // Only ASSERT if somebody tries to DEREFERENCE that NULL pointer.
      m_rangePtr(newrangeptr),
      m_parents(NELEM, Branch::NONBRANCH),
      m_children(NELEM, Branch::NONBRANCH),
      m_ID(),
      m_equivBranch(Branch::NONBRANCH),
      m_partitions(registry.GetDataPack().GetNPartitionForces(), FLAGLONG)
{
    m_eventTime     = 0.0;
    m_updateDL      = false;
    m_marked        = false;
    m_wasCoalCalced = false;
    m_isSample      = 1;

} // Branch constructor

//------------------------------------------------------------------------------------
// Must delete the Range object held by pointer and always allocated on the heap.
// All classes derived from Branch have default (ie, empty) destructors, but the
// runtime systems calls this one for the base class (since all Branch classes
// derive from Branch), and this single destructor deallocates the Range object.

Branch::~Branch()
{
    // We need to delete the contained Range member, since we own it.
    delete m_rangePtr;

} // Branch destructor

//------------------------------------------------------------------------------------
// DEEP-COPYING copy constructor.

Branch::Branch(const Branch & src)
    : boost::enable_shared_from_this<Branch>(),
      m_parents(NELEM, Branch::NONBRANCH),
      m_children(NELEM, Branch::NONBRANCH),
      m_equivBranch(Branch::NONBRANCH)
{
    CopyAllMembers(src);                // Does a deep copy of objects (namely Range) held by pointer.
} // Branch copy constructor

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

void Branch::CopyAllMembers(const Branch & src)
{
    fill(m_parents.begin(), m_parents.end(), Branch::NONBRANCH);
    fill(m_children.begin(), m_children.end(), Branch::NONBRANCH);

    m_ID               = src.m_ID;
    m_eventTime        = src.m_eventTime;
    m_partitions       = src.m_partitions;
    m_updateDL         = src.m_updateDL;
    m_marked           = src.m_marked;
    // Here's the deep copy mentioned above.  OK to copy a NULL Range pointer here.
    m_rangePtr         = src.m_rangePtr->Clone();
    m_DLcells          = src.m_DLcells;
    m_movingDLcells    = src.m_movingDLcells;
    m_isSample         = src.m_isSample;
    m_wasCoalCalced    = src.m_wasCoalCalced;

} // Branch::CopyAllMembers

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

bool Branch::IsAMember(const Force & force, const LongVec1d & membership) const
{
    return force.IsAMember(m_partitions, membership);
} // Branch::IsAMember

//------------------------------------------------------------------------------------
// Checks if two branches are functionally the same.
// If you want full equivalency, use operator==().

bool Branch::IsEquivalentTo(const Branch_ptr twin)   const
{
    return m_ID == twin->m_ID;

#if 0  // Useful for debugging, perhaps.
    if (Event() != twin->Event())
    {
        // cerr << "Different Events." << endl;
        return false;
    }

    if (m_partitions != twin->m_partitions)
    {
        // cerr << "Different Partitions." << endl;
        return false;
    }

    if (GetRangePtr()->GetLiveSites() != twin->GetRangePtr()->GetLiveSites())
    {
        // cerr << "Different Active Sites." << endl;
        return false;
    }

    if (m_eventTime != twin->m_eventTime)
    {
        // cerr << "Different Event Times." << endl;
        return false;
    }

    bool my_sites_all_live(GetRangePtr()->LiveSitesOnly());
    bool his_sites_all_live(twin->GetRangePtr()->LiveSitesOnly());
    if (my_sites_all_live && his_sites_all_live) return true;  // Both branches NON-RECOMBINANT.
    if (my_sites_all_live != his_sites_all_live) return false; // One recombinant, other not.
    //
    // From here to end, we require that both branches be recombinant, containing RecRange objects
    // rather than Range objects.  That is guaranteed, because of LiveSitesOnly() test above.
    //
    RecRange * my_recrange_ptr(dynamic_cast<RecRange *>(GetRangePtr()));
    assert(my_recrange_ptr);

    RecRange * twin_recrange_ptr(dynamic_cast<RecRange *>(twin->GetRangePtr()));
    assert(twin_recrange_ptr);

    // RecRange::GetRecpoint() returns Littlelink (Biglink midpoint, if Biglinks enabled).
    if (my_recrange_ptr->GetRecpoint() != twin_recrange_ptr->GetRecpoint())
    {
        // cerr << "Different Recombination Point." << endl;
        return false;
    }

    return true;
#endif

} // Branch::IsEquivalentTo

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

bool Branch::HasSamePartitionsAs(const Branch_ptr twin)   const
{
    if (twin)
    {
        if (m_partitions != twin->m_partitions)
        {
            return false;
        }
    }

    return true;

} //HasSamePartitionsAs

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

bool Branch::PartitionsConsistentWith(const Branch_ptr child)   const
{
    assert(Event() == btypeRec);

    if (child)
    {
        const ForceSummary & fs = registry.GetForceSummary();
        if (fs.CheckForce(force_DISEASE))
        {
            if (GetRangePtr()->AreDiseaseSitesTransmitted())
            {
                long int diseaseIndex = fs.GetPartIndex(force_DISEASE);
                long int diseaseState = child->GetPartition(force_DISEASE);
                if (diseaseState != m_partitions[diseaseIndex])
                {
                    return false;
                }
            }
        }
    }

    return true;

} // PartitionsConsistentWith

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

void Branch::ResetBuffersForNextRearrangement()
{
    GetRangePtr()->SetOldInfoToCurrent();
    GetRangePtr()->ClearNewTargetLinks();

} // ResetBuffersForNextRearrangement

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

LongVec1d Branch::GetLocalPartitions() const
{
    LongVec1d lppartitions;
    LongVec1d lpindex(registry.GetForceSummary().GetLocalPartitionIndexes());
    LongVec1d::iterator lpforce;

    for (lpforce = lpindex.begin(); lpforce != lpindex.end(); ++lpforce)
    {
        lppartitions.push_back(m_partitions[*lpforce]);
    }

    return lppartitions;

} // GetLocalPartitions

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

long int Branch::GetID() const
{
    return m_ID.ID();
}

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

weakBranch_ptr Branch::GetEquivBranch() const
{
    return m_equivBranch;
} // Branch::GetEquivBranch

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

void Branch::SetEquivBranch(Branch_ptr twin)
{
    m_equivBranch = twin;
} // Branch::SetEquivBranch

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

long int Branch::GetPartition(force_type force) const
{
    return m_partitions[registry.GetForceSummary().GetPartIndex(force)];
} // Branch::GetPartition

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

void Branch::SetPartition(force_type force, long int val)
{
    m_partitions[registry.GetForceSummary().GetPartIndex(force)] = val;
} // Branch::SetPartition

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

void Branch::CopyPartitionsFrom(Branch_ptr src)
{
    m_partitions = src->m_partitions;
} // Branch::CopyPartitionsFrom

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

void Branch::MarkParentsForDLCalc()
{
    // Evil kludge necessary because we force parents/children to always have two spaces even when empty!
    if (!m_parents[0].expired())
    {
        Branch_ptr parent0(m_parents[0]);
        if (!parent0->m_updateDL)
        {
            parent0->SetUpdateDL();
            parent0->MarkParentsForDLCalc();
        }
    }

    if (!m_parents[1].expired())
    {
        Branch_ptr parent1(m_parents[1]);
        if (!parent1->m_updateDL)
        {
            parent1->SetUpdateDL();
            parent1->MarkParentsForDLCalc();
        }
    }

} // Branch::MarkParentsForDLCalc

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

void Branch::ReplaceChild(Branch_ptr, Branch_ptr newchild)
{
    // This version is used by MBranch and DBranch; there are overrides for other branches.
    newchild->m_parents[0] = shared_from_this();
    m_children[0]          = newchild;

} // Branch::ReplaceChild

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

bool Branch::HasSameActive(const Branch & br)
{
    return GetRangePtr()->SameLiveSites(br.GetRangePtr()->GetLiveSites());
} // Branch::HasSameActive

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

const Cell_ptr Branch::GetDLCell(long int loc, long int ind, bool moving) const
{
    if (moving)
    {
        assert(loc < static_cast<long int>(m_movingDLcells.size()));
        assert(ind < static_cast<long int>(m_movingDLcells[loc].size()));
        return m_movingDLcells[loc][ind];
    }
    else
    {
        assert(loc < static_cast<long int>(m_DLcells.size()));
        assert(ind < static_cast<long int>(m_DLcells[loc].size()));
        return m_DLcells[loc][ind];
    }
} // Branch::GetDLCell

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

Cell_ptr Branch::GetDLCell(long int loc, long int ind, bool moving)
{
    if (moving)
    {
        assert(loc < static_cast<long int>(m_movingDLcells.size()));
        assert(ind < static_cast<long int>(m_movingDLcells[loc].size()));
        return m_movingDLcells[loc][ind];
    }
    else
    {
        assert(loc < static_cast<long int>(m_DLcells.size()));
        assert(ind < static_cast<long int>(m_DLcells[loc].size()));
        return m_DLcells[loc][ind];
    }
} // Branch::GetDLCell

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

double Branch::HowFarTo(const Branch & br) const
{
    return fabs(br.m_eventTime - m_eventTime);
} // Branch::HowFarTo

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

Branch_ptr Branch::GetValidChild(Branch_ptr br, long int whichpos)
{
#ifdef PRINT_TREE_DETAILS
    cerr << " In GetValidChild whichpos: " << whichpos << "  br: " << br << endl;
#endif

    Branch_ptr pChild = br->GetActiveChild(whichpos);
    if (pChild)
        br = GetValidChild(pChild, whichpos);

#ifdef PRINT_TREE_DETAILS
    cerr << " return from GetValidChild br: " << br << endl;
#endif

    return br;

} // Branch::GetValidChild

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

Branch_ptr Branch::GetValidPanelChild(Branch_ptr br, long int whichpos)
{
#ifdef PRINT_TREE_DETAILS
    cerr << " In GetValidChild whichpos: " << whichpos << "  br: " << br << endl;
#endif

    Branch_ptr pChild = br->GetActivePanelChild(whichpos);
    if (pChild)
        br = GetValidPanelChild(pChild, whichpos);

#ifdef PRINT_TREE_DETAILS
    cerr << " return from GetValidChild br: " << br << endl;
#endif

    return br;

} // Branch::GetValidPanelChild

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

Branch_ptr Branch::GetValidParent(long int whichpos)
{
    // We are looking for an ancestor of our branch at which the site of interest coalesces.
    Branch_ptr pParent(Parent(0));
    if (Parent(1))
    {
        // This branch has two parents; which one is needed?
        if (Parent(1)->GetRangePtr()->IsSiteLive(whichpos)) pParent = Parent(1);
    }

    // If we have reached the bottom of the tree, we give up--there is no parent.
    if (pParent->Event() == btypeBase) return Branch::NONBRANCH;

    // Otherwise, check if this could be the parent we need.
    if (pParent->Event() == btypeCoal)
    {
        // This could be the coalescence we're looking for, but does our site actually coalesce here?
        if (pParent->Child(0)->GetRangePtr()->IsSiteLive(whichpos) &&
            pParent->Child(1)->GetRangePtr()->IsSiteLive(whichpos))
        {
            return pParent;
        }
    }

    // It's not a coalescence (or the right coalescence), so keep going downward.
    return pParent->GetValidParent(whichpos);

} // GetValidParent

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

bool Branch::DiffersInDLFrom(Branch_ptr branch, long int locus, long int marker) const
{
    return m_DLcells[locus].DiffersFrom(branch->m_DLcells[locus], marker);
} // Branch::DiffersInDLFrom

//------------------------------------------------------------------------------------
// Debugging function.

bool Branch::CheckInvariant() const
{
    // Check correct time relationships among parents and offspring.
    long int index;
    for (index = 0; index < NELEM; ++index)
    {
        // If the child exists it must be earlier.
        if (Child(index))
        {
            if (Child(index)->m_eventTime > m_eventTime)
            {
                return false;
            }
        }

        // If the parent exists it must be later.
        if (Parent(index))
        {
            if (Parent(index)->m_eventTime < m_eventTime)
            {
                return false;
            }
        }
    }

    return true;

} // CheckInvariant

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

bool Branch::operator==(const Branch & src) const
{
    if (Event() != src.Event()) return false;
    if (m_partitions != src.m_partitions) return false;
    if (m_eventTime != src.m_eventTime) return false;

    return true;

} // operator==

//------------------------------------------------------------------------------------
// Debugging function.

string Branch::DLCheck(const Branch & other) const
{
    unsigned long int locus;
    string problems;

    if (m_DLcells.size() != other.m_DLcells.size())
    {
        return string("   The DLCells are different sizes--error\n");
    }

    for (locus = 0; locus < m_DLcells.size(); ++locus)
    {
        unsigned long int ncells = m_DLcells[locus].size();
        if (ncells != other.m_DLcells[locus].size())
        {
            return string("   Bad branch comparison--error\n");
        }

        unsigned long int ind;
        for (ind = 0; ind < ncells; ++ind)
        {
            long int badmarker = m_DLcells[locus][ind]->DiffersFrom(other.m_DLcells[locus][ind]);
            if (badmarker == FLAGLONG) continue;

            problems += "   Branch " + ToString(m_ID.ID());
            problems += " differs from other branch " + ToString(other.m_ID.ID());
            problems += " at marker " + ToString(badmarker);
            problems += "\n";

            return problems;
        }
    }

    return problems;

} // Branch::DLCheck

//------------------------------------------------------------------------------------
// Debugging function.

void Branch::PrintInfo() const
{
    cerr << "Branch::PrintInfo ..." << endl << endl;
    cerr << "ID: " << m_ID.ID() << " (" << ToString(Event()) << ")" << endl;
    if (Event() == btypeCoal)
    {
        cerr << "Parent: " << Parent(0)->GetID() << endl;
        cerr << "Child(0): " << Child(0)->GetID() << " Child(1): " << Child(1)->GetID() << endl;
    }
    else if (Event() == btypeRec)
    {
        cerr << "Parent(0): " << Parent(0)->GetID() << " Parent(1): " << Parent(1)->GetID() << endl;
        cerr << "Child: " << Child(0)->GetID() << endl;
    }
    else if (Event() == btypeBase)
    {
        cerr << "Child: " << Child(0)->GetID() << endl;
    }
    else
    {
        cerr << "Parent: " << Parent(0)->GetID() << endl;
        cerr << "Child: " << Child(0)->GetID() << endl;
    }

    cerr << "Partitions:  ";
    for (unsigned long int i = 0; i < m_partitions.size(); ++i)
    {
        cerr << m_partitions[i] << " ";
    }

    cerr << endl << "Event time:  " << m_eventTime << endl << endl;
    GetRangePtr()->PrintInfo();

} // Branch::PrintInfo

//------------------------------------------------------------------------------------
// Debugging function.

vector<Branch_ptr> Branch::GetBranchChildren()
{
    vector<Branch_ptr> newkids;
    vector<weakBranch_ptr>::iterator kid;

    for (kid = m_children.begin(); kid != m_children.end(); ++kid)
    {
        newkids.push_back(kid->lock());
    }

    return newkids;
} // Branch::GetBranchChildren

//------------------------------------------------------------------------------------
// This function is non-const because we need boost::shared_from_this()!

bool Branch::ConnectedTo(const Branch_ptr family)
{
    if (Child(0) && Child(0) == family) return true;
    if (Child(1) && Child(1) == family) return true;
    if (Parent(0) && Parent(0) == family) return true;
    if (Parent(1) && Parent(1) == family) return true;

    cerr << endl << "Branch " << family->m_ID.ID();
    cerr << " is not connected to branch " << m_ID.ID() << " ";
    cerr << "even though it thinks it is via it's ";

    Branch_ptr me(shared_from_this());
    if (family->Child(0) && family->Child(0) == me) cerr << "child0";
    if (family->Child(1) && family->Child(1) == me) cerr << "child1";
    if (family->Parent(0) && family->Parent(0) == me) cerr << "parent0";
    if (family->Parent(1) && family->Parent(1) == me) cerr << "parent1";

    cerr << endl;
    return false;
} // Branch::ConnectedTo

//------------------------------------------------------------------------------------
// Debugging function.

bool Branch::IsSameExceptForTimes(const Branch_ptr other) const
{
    if (Event() != other->Event()) return false;
    if (m_partitions != other->m_partitions) return false;

    return true;
} // Branch::IsSameExceptForTimes

//------------------------------------------------------------------------------------
// Debugging function.

bool Branch::RevalidateRange(FC_Status &) const
{
    bool retval = GetRangePtr()->SameAsChild(Child(0)->GetRangePtr());
    if (!retval)
    {
        cerr << "Failed in Branch::RevalidateRange; ID: " << m_ID.ID() << endl;
    }

    return retval;
} // Branch::RevalidateRange

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

void Branch::AddGraphML(TiXmlElement * elem) const
{
    ////////////////////////////////////////////////////////////
    // node itself
    long int myID = GetID();
    long int canonicalID = GetCanonicalID();
    if (canonicalID == myID)
    {
        TiXmlElement * node = new TiXmlElement("node");
        node->SetAttribute("id", ToString(canonicalID));
        elem->LinkEndChild(node);

        // type of node
        TiXmlElement * typeInfo = new TiXmlElement("data");
        node->LinkEndChild(typeInfo);
        typeInfo->SetAttribute("key", "node_type");
        TiXmlText * nTypeText = new TiXmlText(GetGraphMLNodeType());
        typeInfo->LinkEndChild(nTypeText);

        // time of node
        TiXmlElement * timeInfo = new TiXmlElement("data");
        node->LinkEndChild(timeInfo);
        timeInfo->SetAttribute("key", "node_time");
        TiXmlText * nTimeText = new TiXmlText(ToString(m_eventTime));
        timeInfo->LinkEndChild(nTimeText);

        AddNodeInfo(node);
    }

    ////////////////////////////////////////////////////////////
    // branch(es) themselves
    TiXmlElement * branchElem = new TiXmlElement("edge");
    elem->LinkEndChild(branchElem);
    branchElem->SetAttribute("source", ToString(GetCanonicalParentID()));
    branchElem->SetAttribute("target", ToString(canonicalID));

    // partition forces
    TiXmlElement * partElem = new TiXmlElement("data");
    branchElem->LinkEndChild(partElem);
    partElem->SetAttribute("key","partitions");

    string partstr ="";
    if (registry.GetForceSummary().CheckForce(force_DISEASE))
    {
        partstr += ToString(force_DISEASE);
        partstr += ":";
        partstr += registry.GetDataPack().GetPartitionName(force_DISEASE, GetPartition(force_DISEASE));
    }

    if (registry.GetForceSummary().CheckForce(force_DIVMIG))
    {
        if (partstr.length() > 0)
        {
            partstr += ",";
        }
        partstr += ToString(force_DIVMIG);
        partstr += ":";
        partstr += registry.GetDataPack().GetPartitionName(force_DIVMIG, GetPartition(force_DIVMIG));
    }

    if (registry.GetForceSummary().CheckForce(force_MIG))
    {
        if (partstr.length() > 0)
        {
            partstr += ",";
        }
        partstr += ToString(force_MIG);
        partstr += ":";
        partstr += registry.GetDataPack().GetPartitionName(force_MIG, GetPartition(force_MIG));
    }

    TiXmlText * pTypeText = new TiXmlText(partstr);
    partElem->LinkEndChild(pTypeText);

    // range info
    TiXmlElement * lrangeElem = new TiXmlElement("data");
    branchElem->LinkEndChild(lrangeElem);
    lrangeElem->SetAttribute("key","live_sites");
    rangeset lset = GetRangePtr()->GetLiveSites();
    TiXmlText * lTypeText = new TiXmlText(ToGraphMLString(lset));
    lrangeElem->LinkEndChild(lTypeText);

    if (Event() == btypeRec)
    {
        TiXmlElement * trangeElem = new TiXmlElement("data");
        branchElem->LinkEndChild(trangeElem);
        trangeElem->SetAttribute("key","transmitted_sites");
        rangeset tset = GetRangePtr()->GetTransmittedSites();
        TiXmlText * tTypeText = new TiXmlText(ToGraphMLString(tset));
        trangeElem->LinkEndChild(tTypeText);
    }

    //AddBranchInfo(branchElem);
} // Branch::AddGraphML

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

string Branch::GetParentIDs() const
{
    string outstr = "";
    long int pCount = NParents();
    for (long int count = 0 ; count < pCount; count++)
    {
        const Branch_ptr p = Parent(count);
        if (p != Branch::NONBRANCH)
        {
            outstr = outstr + " " + ToString(p->GetID());
        }
    }
    return outstr;
} // Branch::GetParentIDs

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

string Branch::GetChildIDs() const
{
    string outstr = "";
    long int pCount = NChildren();
    for (long int count = 0 ; count < pCount; count++)
    {
        const Branch_ptr p = Child(count);
        if (p != Branch::NONBRANCH)
        {
            outstr = outstr + " " + ToString(p->GetID());
        }
    }
    return outstr;
} // Branch::GetChildIDs

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

long int Branch::GetCanonicalID() const
{
    long int myID = GetID();
    const Branch_ptr p = GetRecPartner();
    if (p != Branch::NONBRANCH)
    {
        long int otherID = p->GetID();
        if (otherID < myID)
        {
            return otherID;
        }
    }
    return myID;
} // Branch::GetCanonicalID

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

long int Branch::GetCanonicalParentID() const
{
    long int downID = -1;
    long int pCount = NParents();
    long int trueCount = 0;
    for (long int count = 0 ; count < pCount; count++)
    {
        const Branch_ptr p = Parent(count);
        if (p != Branch::NONBRANCH)
        {
            long int canonicalParent = p->GetCanonicalID();
            if (trueCount == 0)
            {
                downID = canonicalParent;
            }
            else
            {
                if (downID != canonicalParent)
                {
                    assert(false);
                    return -2;
                }
            }
        }
    }
    return downID;
} // Branch::GetCanonicalParentID

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// This constructor should only be called by the TimeList constructor.
// Passes a newly-allocated Range (by pointer) to the Branch constructor, which does a shallow copy.
// Actually, the Range object in a BBranch should never be accessed.  BBranch::CreateRange() returns
// a NULL pointer, which the accessor function GetRangePtr() tests (ASSERTs if it is NULL).

BBranch::BBranch()
    : Branch(CreateRange())
{
    // Deliberately blank.
} // BBranch constructor

//------------------------------------------------------------------------------------
// Returns a pointer to a newly-allocated Branch, which contains a deep-copied Range
// (thanks to the deep-copying copy constructor this class inherits from Branch).

Branch_ptr BBranch::Clone() const
{
    return Branch_ptr(new BBranch(*this));
} // BBranch::Clone

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

void BBranch::ScoreEvent(TreeSummary &, BranchBuffer &) const
{
    assert(false);                      // I don't think this should ever be called.
} // BBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Third arg is a reference for consistency with same function in other classes,
// which return a recombination weight therein.

void BBranch::ScoreEvent(TreeSummary &, BranchBuffer &, Linkweight &) const
{
    assert(false);                      // I don't think this should ever be called.
} // BBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Debugging function.

bool BBranch::CheckInvariant() const
{
    // Base branches have no parents...
    long int index;
    for (index = 0; index < NELEM; ++index)
    {
        if (Parent(index)) return false;
    }

    // ...and one child
    if (!Child(0)) return false;
    if (Child(1)) return false;

    if (!Branch::CheckInvariant()) return false;

    return true;

} // CheckInvariant

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

string BBranch::GetGraphMLNodeType() const
{
    assert(false);
    string outstr = "Error BBranch";
    return outstr;
}

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Creates a new TBranch object containing a newly-allocated Range object (held by pointer),
// which was allocated by CreateRange and shallow-copied by the Branch constructor.

TBranch::TBranch(const TipData & tipdata, long int nsites, const rangeset & diseasesites)
    : Branch(CreateRange(nsites, diseasesites))
{
    m_partitions = tipdata.GetBranchPartitions();
    m_label = tipdata.label;

    // This is used for SNP panel corrections.
    if (tipdata.m_source == dsource_panel)
    {
        m_isSample = 0;
    }

#if 0
    cerr << "Tip: " << tipdata.label;
    if (tipdata.m_source == dsource_panel)
        cerr << " is a panel member ";
    else
        cerr << " is a study member ";
    cerr << endl;
#endif

    // WARNING:  must be changed for sequential-sampling case
    m_eventTime = 0.0;

} // TBranch constructor

//------------------------------------------------------------------------------------
// Returns a pointer to a newly-heap-allocated Range or RecRange object.
// Please see note about different meaning of "GetAllLinks()" in Biglink versus Littlelink implementation.
// Note ("NOTA BENE") is in file "range.h", in definition of RecRange class.

Range * TBranch::CreateRange(long int nsites, const rangeset & diseasesites) const
{
    if (registry.GetForceSummary().CheckForce(force_REC)) // This force includes recombination.
    {
        // Called only when underlying data structures (trees, branches, ranges)
        // are potentially recombinant (ie, contain RecRanges, not Ranges).
        linkrangeset alllinks(RecRange::GetAllLinks());   // All Links were and are targetable.
        rangeset allsites(MakeRangeset(0, nsites));       // All Sites are both live and transmitted.
        return new RecRange(nsites, diseasesites, allsites, allsites, alllinks, alllinks, allsites, allsites);
    }
    else
    {
        return new Range(nsites);
    }

} // TBranch::CreateRange

//------------------------------------------------------------------------------------
// Returns a pointer to a newly-allocated Branch, which contains a deep-copied Range
// (thanks to the deep-copying copy constructor this class inherits from Branch).

Branch_ptr TBranch::Clone() const
{
    return Branch_ptr(new TBranch(*this));
} // TBranch::Clone

//------------------------------------------------------------------------------------
// Debugging function.

bool TBranch::CheckInvariant() const
{
    // Tip branches have no children...
    long int index;
    for (index = 0; index < NELEM; ++index)
    {
        if (Child(index)) return false;
    }

    // ...and at least one parent.
    if (!Parent(0)) return false;

    if (!Branch::CheckInvariant()) return false;

    return true;

} // CheckInvariant

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

bool TBranch::operator==(const Branch & src) const
{
    return ((Branch::operator==(src)) && (m_label == dynamic_cast<const TBranch &>(src).m_label));
} // operator==

//------------------------------------------------------------------------------------
// Debugging function.

bool TBranch::IsSameExceptForTimes(const Branch_ptr src) const
{
    return ((Branch::IsSameExceptForTimes(src)) && (m_label == boost::dynamic_pointer_cast<const TBranch>(src)->m_label));
} // IsSameExceptForTimes

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

void TBranch::ScoreEvent(TreeSummary &, BranchBuffer &) const
{
    assert(false);                      // I don't think this should ever be called.
} // TBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Third arg is a reference for consistency with same function in other classes,
// which return a recombination weight therein.

void TBranch::ScoreEvent(TreeSummary &, BranchBuffer &, Linkweight &) const
{
    assert(false);                      // I don't think this should ever be called.
} // TBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Debugging function.

bool TBranch::RevalidateRange(FC_Status &) const
{
    if (GetRangePtr()->LiveSitesOnly()) return true;
    //
    // From here to end, we require that this function is called only on recombinant branches,
    // which contain RecRange objects rather than Range objects.  That is guaranteed, because
    // LiveSitesOnly() returns TRUE for non-recombinant branches.  The issue is not what kind
    // of event we are processing; it is what kind of Range object the branch contains.
    //
    long int nsites(GetRangePtr()->GetNumRegionSites());
    rangeset diseasesites(GetRangePtr()->GetDiseaseSites());

    // MDEBUG following is not good form nor exception-safe; consider fixing.
    Range * newrangeptr(CreateRange(nsites, diseasesites));
    bool matches = (*newrangeptr == *GetRangePtr());
    delete newrangeptr;
    if (!matches)
    {
        cerr << "RevalidateRange failed in TBranch: " << m_ID.ID() << endl;
    }
    return matches;

} // TBranch::RevalidateRange

//------------------------------------------------------------------------------------
// Debugging function.

void TBranch::PrintInfo() const
{
    cerr << "TBranch::PrintInfo ..." << endl << endl;
    cerr << "Event type:  " << ToString(Event()) << endl;
    cerr << "Label: " << m_label << endl;
    cerr << "ID: " << m_ID.ID() << endl;
    cerr << "Partitions:  ";

    for (unsigned long int i = 0; i < m_partitions.size(); i++)
    {
        cerr << m_partitions[i] << " ";
    }

    cerr << endl << "Event time:  " << m_eventTime << endl << endl;
    GetRangePtr()->PrintInfo();

} // TBranch::PrintInfo

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

string TBranch::GetGraphMLNodeType() const
{
    return "Tip";
}

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

void TBranch::AddNodeInfo(TiXmlElement * nodeElem) const
{
    // type of node
    TiXmlElement * labelInfo = new TiXmlElement("data");
    nodeElem->LinkEndChild(labelInfo);
    labelInfo->SetAttribute("key", "node_label");
    TiXmlText * labelText = new TiXmlText(m_label);
    labelInfo->LinkEndChild(labelText);
}

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Creates a new CBranch object containing a newly-allocated Range object (held by pointer),
// which was allocated by CreateRange and shallow-copied by the Branch constructor.

CBranch::CBranch(const Range * const child1rangeptr, const Range * const child2rangeptr,
                 bool newbranchisinactive, const rangeset & fcsites)
    : Branch(CreateRange(child1rangeptr, child2rangeptr, newbranchisinactive, fcsites))
{
    // Deliberately blank.
} // CBranch constructor

//------------------------------------------------------------------------------------
// Returns a pointer to a newly-heap-allocated Range or RecRange object.

Range * CBranch::CreateRange(const Range * const child1rangeptr, const Range * const child2rangeptr,
                             bool newbranchisinactive, const rangeset & fcsites) const
{
    // These we can grab from either child as they should be identical in these fields.
    long int nsites(child1rangeptr->GetNumRegionSites());

    if (registry.GetForceSummary().CheckForce(force_REC)) // This force includes recombination.
    {
        // Called only when underlying data structures (trees, branches, ranges)
        // are potentially recombinant (ie, contain RecRanges, not Ranges).
        rangeset diseasesites(child1rangeptr->GetDiseaseSites());
        rangeset allsites(MakeRangeset(0, nsites)); // All Sites are transmitted.
        rangeset livesites(Union(child1rangeptr->GetLiveSites(), child2rangeptr->GetLiveSites()));
        rangeset targetsites = Union(diseasesites, RemoveRangeFromRange(fcsites, livesites));
        linkrangeset curtargetlinks(RecRange::LinksSpanningSites(targetsites));
        linkrangeset oldtargetlinks;
        rangeset oldtargetsites, oldlivesites;

        if (newbranchisinactive)        // Copy the inactive child oldtargetlinks and oldtargetsites.
        {
            oldtargetlinks = child1rangeptr->GetOldTargetLinks();
            oldtargetsites = child1rangeptr->GetOldTargetSites();
            oldlivesites = child1rangeptr->GetOldLiveSites();
        }
        else
        {
            oldtargetlinks = curtargetlinks;
            oldtargetsites = targetsites;
            oldlivesites = livesites;
        }

        return new RecRange(nsites, diseasesites, allsites, livesites, curtargetlinks,
                            oldtargetlinks, oldtargetsites, oldlivesites);
    }
    else
    {
        return new Range(nsites);
    }

} // CBranch::CreateRange

//------------------------------------------------------------------------------------
// Returns a pointer to a newly-allocated Branch, which contains a deep-copied Range
// (thanks to the deep-copying copy constructor this class inherits from Branch).

Branch_ptr CBranch::Clone() const
{
    return Branch_ptr(new CBranch(*this));
} // CBranch::Clone

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

bool CBranch::CanRemove(Branch_ptr checkchild)
{
    if (m_marked) return true;

    m_marked = true;
    if (Child(0) == checkchild) SetChild(0, Child(1));
    SetChild(1, Branch::NONBRANCH);

    return false;

} // CBranch::CanRemove

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

void CBranch::UpdateBranchRange(const rangeset & fcsites, bool dofc)
{
    if (m_marked)
    {
        GetRangePtr()->UpdateOneLeggedCRange(Child(0)->GetRangePtr());
    }
    else
    {
        GetRangePtr()->UpdateCRange(Child(0)->GetRangePtr(), Child(1)->GetRangePtr(), fcsites, dofc);
    }

} // CBranch::UpdateBranchRange

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

void CBranch::UpdateRootBranchRange(const rangeset & fcsites, bool dofc)
{
    if (m_marked)
    {
        GetRangePtr()->UpdateOneLeggedRootRange(Child(0)->GetRangePtr());
    }
    else
    {
        GetRangePtr()->UpdateRootRange(Child(0)->GetRangePtr(), Child(1)->GetRangePtr(), fcsites, dofc);
    }

} // CBranch::UpdateRootBranchRange

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

void CBranch::ReplaceChild(Branch_ptr pOldChild, Branch_ptr pNewChild)
{
    if (Child(0) == pOldChild)
        SetChild(0, pNewChild);
    else
        SetChild(1, pNewChild);

    pNewChild->SetParent(0, shared_from_this());

} // CBranch::ReplaceChild

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

Branch_ptr CBranch::OtherChild(Branch_ptr badchild)
{
    if (Child(0) == badchild) return Child(1);
    return Child(0);

} // CBranch::OtherChild

//------------------------------------------------------------------------------------
// Both children must be both active and included in the DLcalc for this to return true.

bool CBranch::CanCalcDL(long int site) const
{
    if ((Child(0)->GetRangePtr()->IsSiteLive(site)) && (Child(1)->GetRangePtr()->IsSiteLive(site)))
    {
        return true;
    }
    else
    {
        return false;
    }
}

//------------------------------------------------------------------------------------
// If both children are active return Branch::NONBRANCH to signal a stop; otherwise return the active child.

const Branch_ptr CBranch::GetActiveChild(long int site)  const
{
    if (Child(0)->GetRangePtr()->IsSiteLive(site))
    {
        if (Child(1)->GetRangePtr()->IsSiteLive(site)) return Branch::NONBRANCH;
        return Child(0);
    }
    else
    {
        return Child(1);
    }

} // CBranch::GetActiveChild

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

void CBranch::ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const
{
    long int i;
    Summary * csum = summary.GetSummary(force_COAL);

    // Forces have become inconsistent!
    assert(dynamic_cast<CoalSummary *>(csum));

    long int myxpart = registry.GetDataPack().GetCrossPartitionIndex(m_partitions);
    LongVec1d emptyvec;

    // Score the event.
    csum->AddInterval(m_eventTime, ks.GetBranchParts(), ks.GetBranchXParts(),
                      FLAGFAULTY, myxpart, FLAGLONG, FLAGLONG, emptyvec, force_COAL);

    // Adjust the branch counts.
    for (i = 0; i < NELEM; ++i)
        ks.UpdateBranchCounts(Child(i)->m_partitions, false);

    ks.UpdateBranchCounts(m_partitions);

} // CBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Third arg is a reference because this function returns a recombination weight therein.
// This version should be called on recombinant branches only (not necessarily that we are
// processing a recombination event, just that the branch contains a RecRange).

void CBranch::ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const
{
    // "recweight" is a Link recombination weight (Biglink weight or number of Littlelinks).

    long int i;
    Summary * csum = summary.GetSummary(force_COAL);

    // Forces have become inconsistent!
    assert(dynamic_cast<CoalSummary *>(csum));

    long int myxpart = registry.GetDataPack().GetCrossPartitionIndex(m_partitions);
    LongVec1d emptyvec;

    // Score the event.
    csum->AddInterval(m_eventTime, ks.GetBranchParts(), ks.GetBranchXParts(),
                      recweight, myxpart, FLAGLONG, FLAGLONG, emptyvec, force_COAL);

    // Adjust the branch and Link weight.
    // From here to end, we require that this function is called only on recombinant branches,
    // which contain RecRange objects rather than Range objects.
    for (i = 0; i < NELEM; ++i)
    {
        ks.UpdateBranchCounts(Child(i)->m_partitions, false);
        RecRange * child_recrange_ptr(dynamic_cast<RecRange *>(Child(i)->GetRangePtr()));
        assert(child_recrange_ptr);     // FIRE if fcn called on non-recombinant object.
        recweight -= child_recrange_ptr->GetCurTargetLinkweight();
    }

    ks.UpdateBranchCounts(m_partitions);

    RecRange * my_recrange_ptr(dynamic_cast<RecRange *>(GetRangePtr()));
    assert(my_recrange_ptr);
    recweight += my_recrange_ptr->GetCurTargetLinkweight();

} // CBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Debugging function.

bool CBranch::CheckInvariant() const
{
    // Coalescent branches have two children...
    if (!Child(0)) return false;
    if (!Child(1)) return false;

    //...and at least one parent.
    if (!Parent(0)) return false;

    if (!Branch::CheckInvariant()) return false;

    return true;

} // CheckInvariant

//------------------------------------------------------------------------------------
// Debugging function.

bool CBranch::RevalidateRange(FC_Status & fcstatus) const
{
    rangeset livesites;
    rangeset live0;
    rangeset live1;

    // Are we the same moeity and population as our children?
    if (Child(0)->m_partitions != m_partitions)
    {
        cerr << "Branch changed color in CBranch: " << m_ID.ID() << endl;
        return false;
    }

    if (Child(1) && Child(1)->m_partitions != m_partitions)
    {
        cerr << "Branch changed color in CBranch: " << m_ID.ID() << endl;
        return false;
    }

    if (!Child(1))                      // We're in a one-legger.
    {
        const Range * const childrangeptr(Child(0)->GetRangePtr());
        livesites = childrangeptr->GetLiveSites();
        if (!(GetRangePtr()->SameLiveSites(livesites)))
        {
            cerr << "RevalidateRange found one legger in CBranch: " << m_ID.ID() << endl;
            return false;
        }
        // We don't need to update fc stuff for a one-legger.
    }
    else
    {
        // We're in a normal coalescence.
        const Range * const child0rangeptr(Child(0)->GetRangePtr());
        const Range * const child1rangeptr(Child(1)->GetRangePtr());

        live0 = child0rangeptr->GetLiveSites();
        live1 = child1rangeptr->GetLiveSites();
        livesites = Union(child0rangeptr->GetLiveSites(), child1rangeptr->GetLiveSites());
        if (!(GetRangePtr()->SameLiveSites(livesites)))
        {
            cerr << "RevalidateRange found !SameLiveSites in CBranch: " << m_ID.ID() << endl;
            return false;
        }

#if FINAL_COALESCENCE_ON
        rangeset fcsites(Intersection(child0rangeptr->GetLiveSites(), child1rangeptr->GetLiveSites()));
        fcstatus.Decrement_FC_Counts(fcsites);
#endif
    }

    if (GetRangePtr()->LiveSitesOnly()) return true; // We're done checking.
    //
    // From here to end, we require that this function is called only on recombinant branches,
    // which contain RecRange objects rather than Range objects.  That is guaranteed, because
    // LiveSitesOnly() returns TRUE for non-recombinant branches.  The issue is not what kind
    // of event we are processing; it is what kind of Range object the branch contains.
    //
    RecRange * my_recrange_ptr(dynamic_cast<RecRange *>(GetRangePtr()));
    assert(my_recrange_ptr);

#if FINAL_COALESCENCE_ON
    linkrangeset curtargetlinks(RecRange::LinksSpanningSites
                                (Union(my_recrange_ptr->GetDiseaseSites(),
                                       RemoveRangeFromRange(fcstatus.Coalesced_Sites(), livesites))));
#else
    linkrangeset curtargetlinks(RecRange::LinksSpanningSites(Union(my_recrange_ptr->GetDiseaseSites(), livesites)));
#endif

    // Comparing Biglinks if in Biglink mode, Littlelinks if in Littlelink mode.
    if (my_recrange_ptr->DifferentCurTargetLinks(curtargetlinks))
    {
        cerr << "CBranch::RevalidateRange (invalid CurTargetLinks) call to RecRange::PrintInfo()" << endl << endl;
        my_recrange_ptr->PrintInfo();
        //
        cerr << "Disease Sites: " << ToString(my_recrange_ptr->GetDiseaseSites()) << endl;
        cerr << "Live Sites: " << ToString(livesites) << endl;
        cerr << "Live Sites Child 0: " << ToString(live0) << endl;
        cerr << "Live Sites Child 1: " << ToString(live1) << endl;
        cerr << "FCstatus: " << ToString(fcstatus.Coalesced_Sites()) << endl << endl;
        //
        cerr << "Target Links [my_recrange_ptr->GetCurTargetLinks()]:  ";
        RecRange::PrintLinks(my_recrange_ptr->GetCurTargetLinks());
        //
        cerr << endl << "Target Links [curtargetlinks]:  ";
        RecRange::PrintLinks(curtargetlinks);
        cerr << endl;
        //
        return false;
    }

    // Is this a rec-only branch?  Otherwise, we may not want GetOldTargetLinks() to ASSERT.
    if (my_recrange_ptr->DifferentNewTargetLinks(RemoveRangeFromRange(my_recrange_ptr->GetOldTargetLinks(), curtargetlinks)))
    {
        cerr << "RevalidateRange found DifferentNewTargetLinks(newtarget) in CBranch: " << m_ID.ID() << endl;
        cerr << "CBranch::RevalidateRange (invalid NewTargetLinks) call to RecRange::PrintInfo()" << endl << endl;
        //
        my_recrange_ptr->PrintInfo();
        //
        cerr << "Target Links [RemoveRangeFromRange(my_recrange_ptr->GetOldTargetLinks(), curtargetlinks)]:  ";
        RecRange::PrintLinks(RemoveRangeFromRange(my_recrange_ptr->GetOldTargetLinks(), curtargetlinks));
        //
        cerr << endl << "Target Links [curtargetlinks]:  ";
        RecRange::PrintLinks(curtargetlinks);
        cerr << endl;
        //
        return false;
    }

    return true;

} // CBranch::RevalidateRange

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

string CBranch::GetGraphMLNodeType() const
{
    return "Coal";
}

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Creates a new PartitionBranch object containing a newly-allocated Range object
// (held by pointer), which was allocated by CreateRange and shallow-copied by the Branch constructor.

PartitionBranch::PartitionBranch(const Range * const childrangeptr)
    : Branch(CreateRange(childrangeptr))
{
    // Deliberately blank.
} // PartitionBranch constructor

//------------------------------------------------------------------------------------
// Returns a pointer to a newly-heap-allocated Range or RecRange object.

Range * PartitionBranch::CreateRange(const Range * const childrangeptr) const
{
    // NOT copy-constructed from the child, because a PartitionBranch always transmits all sites, and the child might not.
    long int nsites(childrangeptr->GetNumRegionSites());

    if (registry.GetForceSummary().CheckForce(force_REC)) // This force includes recombination.
    {
        // Called only when underlying data structures (trees, branches, ranges)
        // are potentially recombinant (ie, contain RecRanges, not Ranges).
        rangeset diseasesites(childrangeptr->GetDiseaseSites());
        rangeset allsites(MakeRangeset(0, nsites)); // All Sites are transmitted.
        rangeset livesites(childrangeptr->GetLiveSites());
        linkrangeset curtargetlinks(childrangeptr->GetCurTargetLinks());
        linkrangeset oldtargetlinks(childrangeptr->GetOldTargetLinks());
        rangeset oldtargetsites(childrangeptr->GetOldTargetSites());
        rangeset oldlivesites(childrangeptr->GetOldLiveSites());

        return new RecRange(nsites, diseasesites, allsites, livesites, curtargetlinks,
                            oldtargetlinks, oldtargetsites, oldlivesites);
    }
    else
    {
        return new Range(nsites);
    }

} // PartitionBranch::CreateRange

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

void PartitionBranch::UpdateBranchRange(const rangeset &, bool)
{
    GetRangePtr()->UpdateMRange(Child(0)->GetRangePtr());
} // PartitionBranch::UpdateBranchRange

//------------------------------------------------------------------------------------
// Debugging function.

bool PartitionBranch::CheckInvariant() const
{
    // Partition branches have one child...
    if (!Child(0)) return false;
    if (Child(1)) return false;

    //...and at least one parent.
    if (!Parent(0)) return false;

    if (!Branch::CheckInvariant()) return false;

    return true;

} // CheckInvariant

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Creates a new MigLikeBranch object containing a newly-allocated Range object (held by pointer),
// which was allocated by CreateRange in the PartitionBranch constructor.

MigLikeBranch::MigLikeBranch(const Range * const protorangeptr)
    : PartitionBranch(protorangeptr)
{
    // Deliberately blank.
} // MigLikeBranch constructor

//------------------------------------------------------------------------------------
// Creates a new MigLikeBranch object containing a newly-allocated Range object (held by pointer), which
// was allocated by CreateRange and shallow-copied by the Branch constructor that PartitionBranch inherits.

MigLikeBranch::MigLikeBranch(const MigLikeBranch & src)
    : PartitionBranch(src)
{
    // Deliberately blank.
} // MigLikeBranch copy constructor

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Creates a new MBranch object containing a newly-allocated Range object (held by pointer), which
// was allocated by CreateRange and shallow-copied by the Branch constructor that MigLikeBranch inherits.

MBranch::MBranch(const Range * const protorangeptr)
    : MigLikeBranch(protorangeptr)
{
    // Deliberately blank.
} // MBranch constructor

//------------------------------------------------------------------------------------
// Creates a new MBranch object containing a newly-allocated Range object (held by pointer), which
// was allocated by CreateRange and shallow-copied by the Branch constructor that MigLikeBranch inherits.

MBranch::MBranch(const MBranch & src)
    : MigLikeBranch(src)
{
    // Deliberately blank.
} // MBranch copy constructor

//------------------------------------------------------------------------------------
// Creates a new MBranch object containing a newly-allocated Range object (held by pointer), which
// was deep-copied by the PartitionBranch copy constructor that MigLikeBranch inherits.

Branch_ptr MBranch::Clone() const
{
    return Branch_ptr(new MBranch(*this));
} // MBranch::Clone

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

void MBranch::ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const
{
    Summary * msum = summary.GetSummary(force_MIG);

    assert(dynamic_cast<MigSummary *>(msum));

    long int mypop = GetPartition(force_MIG);
    long int chpop = Child(0)->GetPartition(force_MIG);
    LongVec1d emptyvec;

    // Score the event.
    msum->AddInterval(m_eventTime, ks.GetBranchParts(), ks.GetBranchXParts(),
                      FLAGFAULTY, mypop, chpop, FLAGLONG, emptyvec, force_MIG);

    // Adjust the branch counts.
    assert(!Child(1));                  // too many children??
    ks.UpdateBranchCounts(m_partitions);
    ks.UpdateBranchCounts(Child(0)->m_partitions, false);

    // We do not adjust active sites; they cannot possibly change.

} // MBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Third arg is a reference for consistency with same function in other classes,
// which return a recombination weight therein.

void MBranch::ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const
{
    Summary * msum = summary.GetSummary(force_MIG);

    // Forces have become inconsistent!
    assert(dynamic_cast<MigSummary *>(msum));

    long int mypop = GetPartition(force_MIG);
    long int chpop = Child(0)->GetPartition(force_MIG);
    LongVec1d emptyvec;

    // Score the event.
    msum->AddInterval(m_eventTime, ks.GetBranchParts(), ks.GetBranchXParts(),
                      recweight, mypop, chpop, FLAGLONG, emptyvec, force_MIG);

    // Adjust the branch counts.
    assert(!Child(1));                  // too many children??
    ks.UpdateBranchCounts(m_partitions);
    ks.UpdateBranchCounts(Child(0)->m_partitions, false);

    // We do not adjust active sites; they cannot possibly change.

} // MBranch::ScoreEvent

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

string MBranch::GetGraphMLNodeType() const
{
    string outstr = "Mig";
    return outstr;
}

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Divergence migration branches.  Practically identical to MBranch.

DivMigBranch::DivMigBranch(const Range * const protorangeptr)
    : MigLikeBranch(protorangeptr)
{
    // Deliberately blank.
} // DivMigBranch constructor

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

DivMigBranch::DivMigBranch(const DivMigBranch & src)
    : MigLikeBranch(src)
{
    // Deliberately blank.
} // DivMigBranch copy constructor

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

Branch_ptr DivMigBranch::Clone() const
{
    return Branch_ptr(new DivMigBranch(*this));
} // DivMigBranch::Clone

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

void DivMigBranch::ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const
{
    Summary * msum = summary.GetSummary(force_DIVMIG);

    assert(dynamic_cast<DivMigSummary *>(msum));

    long int mypop = GetPartition(force_DIVMIG);
    long int chpop = Child(0)->GetPartition(force_DIVMIG);
    LongVec1d emptyvec;

    // Score the event.
    msum->AddInterval(m_eventTime, ks.GetBranchParts(), ks.GetBranchXParts(),
                      FLAGFAULTY, mypop, chpop, FLAGLONG, emptyvec, force_DIVMIG);

    // Adjust the branch counts.
    assert(!Child(1));                  // too many children??
    ks.UpdateBranchCounts(m_partitions);
    ks.UpdateBranchCounts(Child(0)->m_partitions, false);

    // We do not adjust active sites; they cannot possibly change.

} // DivMigBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Third arg is a reference for consistency with same function in other classes,
// which return a recombination weight therein.

void DivMigBranch::ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const
{
    Summary * msum = summary.GetSummary(force_DIVMIG);

    // Forces have become inconsistent!
    assert(dynamic_cast<DivMigSummary *>(msum));

    long int mypop = GetPartition(force_DIVMIG);
    long int chpop = Child(0)->GetPartition(force_DIVMIG);
    LongVec1d emptyvec;

    // Score the event.
    msum->AddInterval(m_eventTime, ks.GetBranchParts(), ks.GetBranchXParts(),
                      recweight, mypop, chpop, FLAGLONG, emptyvec, force_DIVMIG);

    // Adjust the branch counts.
    assert(!Child(1));                  // too many children??
    ks.UpdateBranchCounts(m_partitions);
    ks.UpdateBranchCounts(Child(0)->m_partitions, false);

    // We do not adjust active sites; they cannot possibly change.

} // DivMigBranch::ScoreEvent

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

string DivMigBranch::GetGraphMLNodeType() const
{
    string outstr = "Epoch";
    return outstr;
}

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Disease mutation branches.  NOT related to Divergence!

DBranch::DBranch(const Range * const protorangeptr)
    : PartitionBranch(protorangeptr)
{
    // Deliberately blank.
} // DBranch constructor

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

DBranch::DBranch(const DBranch & src)
    : PartitionBranch(src)
{
    // Deliberately blank.
} // DBranch copy constructor

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

Branch_ptr DBranch::Clone() const
{
    return Branch_ptr(new DBranch(*this));
} // DBranch::Clone

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

void DBranch::ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const
{
    Summary * dissum = summary.GetSummary(force_DISEASE);

    // Forces have become inconsistent!
    assert(dynamic_cast<DiseaseSummary *>(dissum));

    long int mydis = GetPartition(force_DISEASE);
    long int chdis = Child(0)->GetPartition(force_DISEASE);
    LongVec1d emptyvec;

    // Score the event.
    dissum->AddInterval(m_eventTime, ks.GetBranchParts(), ks.GetBranchXParts(),
                        FLAGFAULTY, mydis, chdis, FLAGLONG, emptyvec, force_DISEASE);

    // Adjust the branch counts.
    assert(!Child(1));                  // too many children??
    ks.UpdateBranchCounts(m_partitions);
    ks.UpdateBranchCounts(Child(0)->m_partitions, false);

    // We do not adjust active sites; they cannot possibly change.

} // DBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Third arg is a reference for consistency with same function in other classes,
// which return a recombination weight therein.

void DBranch::ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const
{
    Summary * dissum = summary.GetSummary(force_DISEASE);

    // Forces have become inconsistent!
    assert(dynamic_cast<DiseaseSummary *>(dissum));

    long int mydis = GetPartition(force_DISEASE);
    long int chdis = Child(0)->GetPartition(force_DISEASE);
    LongVec1d emptyvec;

    // Score the event.
    dissum->AddInterval(m_eventTime, ks.GetBranchParts(), ks.GetBranchXParts(),
                        recweight, mydis, chdis, FLAGLONG, emptyvec, force_DISEASE);

    // Adjust the branch counts.
    assert(!Child(1));                  // too many children??
    ks.UpdateBranchCounts(m_partitions);
    ks.UpdateBranchCounts(Child(0)->m_partitions, false);

    // We do not adjust active sites; they cannot possibly change.

} // DBranch::ScoreEvent

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

string DBranch::GetGraphMLNodeType() const
{
    string outstr = "Disease";
    return outstr;
}

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

Branch_ptr EBranch::Clone() const
{
    return Branch_ptr(new EBranch(*this));
} // EBranch::Clone

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

// NB: The code that calls this routine calls it ONLY on the
// FIRST of a group of EBranches representing the same epoch
// time.  It therefore does not record its child population, as
// that would vary among the various EBranches.  This facilitates
// handling in TreeSum->Summarize().
void EBranch::ScoreEvent(TreeSummary & summary, BranchBuffer & ks) const
{
    Summary * esum = summary.GetSummary(force_DIVERGENCE);

    // Forces have become inconsistent!
    assert(dynamic_cast<EpochSummary *>(esum));

    // NB While this is not a partition force, it cooperates with DIVMIG here.
    long int mypop = GetPartition(force_DIVMIG);
    long int chpop = Child(0)->GetPartition(force_DIVMIG);
    LongVec1d emptyvec;

    // Score the event.
    esum->AddInterval(m_eventTime, ks.GetBranchParts(), ks.GetBranchXParts(),
                      FLAGFAULTY, mypop, FLAGLONG, FLAGLONG, emptyvec, force_DIVERGENCE);

    // Adjust the branch counts.
    assert(!Child(1));                  // too many children??
    ks.UpdateBranchCounts(m_partitions);
    ks.UpdateBranchCounts(Child(0)->m_partitions, false);

    // We do not adjust active sites; they cannot possibly change.

} // EBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Third arg is a reference for consistency with same function in other classes,
// which return a recombination weight therein.

// NB: The code that calls this routine calls it ONLY on the
// FIRST of a group of EBranches representing the same epoch
// time.  It therefore does not record its child population, as
// that would vary among the various EBranches.  This facilitates
// handling in TreeSum->Summarize().
void EBranch::ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const
{
    Summary * esum = summary.GetSummary(force_DIVERGENCE);

    // Forces have become inconsistent!
    assert(dynamic_cast<EpochSummary *>(esum));

    // NB While this is not a partition force, it cooperates with DIVMIG here.
    long int mypop = GetPartition(force_DIVMIG);
    long int chpop = Child(0)->GetPartition(force_DIVMIG);
    LongVec1d emptyvec;

    // Score the event.
    esum->AddInterval(m_eventTime, ks.GetBranchParts(), ks.GetBranchXParts(),
                      recweight, mypop, FLAGLONG, FLAGLONG, emptyvec, force_DIVERGENCE);

    // Adjust the branch counts.
    assert(!Child(1));                  // too many children??
    ks.UpdateBranchCounts(m_partitions);
    ks.UpdateBranchCounts(Child(0)->m_partitions, false);

    // We do not adjust active sites; they cannot possibly change.

} // EBranch::ScoreEvent

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

string EBranch::GetGraphMLNodeType() const
{
    string outstr = "Epoch";
    return outstr;
}

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Creates a new RBranch object containing a newly-allocated Range object (held by pointer),
// which was allocated by CreateRange and shallow-copied by the Branch constructor.

RBranch::RBranch(const Range * const childrangeptr, bool newbranchisinactive,
                 const rangeset & transmittedsites, const rangeset & fcsites)
    : Branch(CreateRange(childrangeptr, newbranchisinactive, transmittedsites, fcsites))
{
    // Deliberately blank.
} // RBranch constructor

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

Branch_ptr RBranch::Clone() const
{
    return Branch_ptr(new RBranch(*this));
} // RBranch::Clone

//------------------------------------------------------------------------------------
// Returns a pointer to a newly-heap-allocated RecRange object.
// ASSERTs if attempt is made to create a Range object.

Range * RBranch::CreateRange(const Range * const childrangeptr, bool newbranchisinactive,
                             const rangeset & transmittedsites, const rangeset & fcsites) const
{
    if (registry.GetForceSummary().CheckForce(force_REC)) // This force includes recombination.
    {
        // Called only when underlying data structures (trees, branches, ranges)
        // are potentially recombinant (ie, contain RecRanges, not Ranges).
        // The following are identical with our child.
        long int nsites(childrangeptr->GetNumRegionSites());
        rangeset diseasesites(childrangeptr->GetDiseaseSites());
        rangeset livesites(Intersection(childrangeptr->GetLiveSites(), transmittedsites));

        // MNEWCODE I am still not positive the following lines are correct!
        // But I can't find the case that would prove them wrong.
        rangeset targetsites = Union(diseasesites, RemoveRangeFromRange(fcsites, livesites));
        linkrangeset curtargetlinks(RecRange::LinksSpanningSites(targetsites));
        linkrangeset oldtargetlinks;
        rangeset oldtargetsites, oldlivesites;

        if (newbranchisinactive)        // Copy the inactive child oldtargetlinks and oldtargetsites.
        {
            oldtargetlinks = childrangeptr->GetOldTargetLinks();
            oldtargetsites = childrangeptr->GetOldTargetSites();
            oldlivesites = childrangeptr->GetOldLiveSites();
        }
        else
        {
            oldtargetlinks = curtargetlinks;
            oldtargetsites = targetsites;
            oldlivesites = livesites;
        }

        return new RecRange(nsites, diseasesites, transmittedsites, livesites, curtargetlinks,
                            oldtargetlinks, oldtargetsites, oldlivesites);
    }
    else
    {
        assert(false);                  // An RBranch in a non-recombinant run??
        return NULL;                    // To silence compiler warning.
    }

} // RBranch::CreateRange

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

void RBranch::CopyPartitionsFrom(Branch_ptr src)
{
    m_partitions = src->m_partitions;
} // Branch::CopyPartitionsFrom

//------------------------------------------------------------------------------------
// Called only when underlying data structures (trees, branches, ranges)
// are potentially recombinant (ie, contain RecRanges, not Ranges).

void RBranch::RecCopyPartitionsFrom(Branch_ptr src, FPartMap fparts, bool islow)
{
    m_partitions = src->m_partitions; //fparts may override.

    ForceVec forces(registry.GetForceSummary().GetPartitionForces());

    for (unsigned long int force = 0; force < forces.size(); force++)
    {
        FPartMapiter thisforcepart = fparts.find(forces[force]->GetTag());
        if (thisforcepart != fparts.end())
        {
            long int chosenpart = thisforcepart->second;
            // RBranch::GetRecpoint() returns Littlelink (Biglink midpoint, if Biglinks enabled).
            long int partition = dynamic_cast<PartitionForce *>(forces[force])->
                ChoosePartition(src->m_partitions[force], chosenpart, islow, GetRecpoint());
            m_partitions[force] = partition;
        }
    }

} // RBranch::RecCopyPartitionsFrom

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

void RBranch::UpdateBranchRange(const rangeset & fcsites, bool dofc)
{
    GetRangePtr()->UpdateRRange(Child(0)->GetRangePtr(), fcsites, dofc);
} // RBranch::UpdateBranchRange

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

void RBranch::ReplaceChild(Branch_ptr oldchild, Branch_ptr newchild)
{
    SetChild(0, newchild);

    Branch_ptr myself = shared_from_this();

    if (oldchild->Parent(0) == myself)
    {
        newchild->SetParent(0, myself);
    }
    else
    {
        newchild->SetParent(1, myself);
    }

} // RBranch::ReplaceChild

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

bool RBranch::IsRemovableRecombinationLeg(const rangeset & fcsites) const
{
    return (!GetRangePtr()->AreChildTargetSitesTransmitted(Child(0)->GetRangePtr(), fcsites));
} // RBranch::IsRemovableRecombinationLeg

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

bool RBranch::operator==(const Branch & other) const
{
    return (Branch::operator==(other) && (*GetRangePtr() == *(other.GetRangePtr())));
}

//------------------------------------------------------------------------------------
// Debugging function.

bool RBranch::IsSameExceptForTimes(const Branch_ptr other) const
{
    return (Branch::IsSameExceptForTimes(other) && (*GetRangePtr() == *(other->GetRangePtr())));
}

//------------------------------------------------------------------------------------
// Recombinant branches only (returns Branch::NONBRANCH in non-recombinant case).

Branch_ptr RBranch::GetRecPartner() const
{
    Branch_ptr partner((Child(0)->Parent(0) == shared_from_this()) ?
                       Child(0)->Parent(1) : Child(0)->Parent(0));

    return partner;

} // GetRecPartner

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

void RBranch::ScoreEvent(TreeSummary &, BranchBuffer &) const
{
    assert(false);                      // This should never be called.
} // RBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Third arg is a reference because this function returns a recombination weight therein.
// Called only when underlying data structures (trees, branches, ranges)
// are potentially recombinant (ie, contain RecRanges, not Ranges).

void RBranch::ScoreEvent(TreeSummary & summary, BranchBuffer & ks, Linkweight & recweight) const
{
    // "recweight" is a Link recombination weight (Biglink weight or number of Littlelinks).

    // One interval with a recombination at the top involves *two* RBranches.  Only one
    // will be summarized into the TreeSummary.  Thus, this peculiar-looking code only calls
    // AddInterval() if the RBranch in question is its Child's *first* Parent, though
    // it does clean-up bookkeeping in any case.
    if (Child(0)->Parent(0) == shared_from_this())
    {
        RecSummary * rsum = dynamic_cast<RecSummary *>(summary.GetSummary(force_REC));
        RecTreeSummary & rtreesum = dynamic_cast<RecTreeSummary &>(summary);

        // Forces have become inconsistent!?
        assert(rsum);

        // Obtain the partnerpicks information for the branch which had it, which is not necessarily
        // this one.  MDEBUG:  This code assumes there is at most one local partition force and one
        // non-local partition force.  It will need to be more complex when multiples of either are allowed.

        // I assume that either both parents match the child, and it doesn't matter which we use,
        // or one parent does not match the child, in which case that parent must be used.

        LongVec1d childpartitions = Child(0)->m_partitions;
        LongVec1d otherpartitions = Child(0)->Parent(1)->m_partitions;  // other branch of recombination
        LongVec1d partnerpicks;
        LongVec1d lpindex(registry.GetForceSummary().GetLocalPartitionIndexes());
        LongVec1d::iterator lpforce;
        LongVec1d pickedmembership;

        // MDEBUG vestigal code assuming multiple lpforces are possible here.
        // This is not carried through correctly elsewhere in function!
        for (lpforce = lpindex.begin(); lpforce != lpindex.end(); ++lpforce)
        {
            if (m_partitions[*lpforce] == childpartitions[*lpforce])
            {
                pickedmembership = otherpartitions;
            }
            else
            {
                pickedmembership = m_partitions;
            }
            partnerpicks.push_back(pickedmembership[*lpforce]);
            rsum->AddToRecombinationCounts(pickedmembership);
        }

        // Score the event.  RBranch::GetRecpoint() returns Littlelink (Biglink midpoint, if Biglinks enabled).
        rsum->AddInterval(m_eventTime, ks.GetBranchParts(), ks.GetBranchXParts(), recweight,
                          FLAGLONG, FLAGLONG, GetRecpoint(), partnerpicks, force_REC);

        // Update list of recombinations by partition.
        rtreesum.AddRecToRecsByPart(pickedmembership, rsum->GetLastAdded());

        // Adjust the branch counts and Link weight for removal of the child.
        ks.UpdateBranchCounts(Child(0)->m_partitions, false);
        RecRange * child_recrange_ptr(dynamic_cast<RecRange *>(Child(0)->GetRangePtr()));
        assert(child_recrange_ptr);     // FIRE if fcn called on non-recombinant object.
        recweight -= child_recrange_ptr->GetCurTargetLinkweight();
    }

    // Adjust the branch and Link weight for addition of this branch.
    ks.UpdateBranchCounts(m_partitions);
    RecRange * my_recrange_ptr(dynamic_cast<RecRange *>(GetRangePtr()));
    assert(my_recrange_ptr);
    recweight += my_recrange_ptr->GetCurTargetLinkweight();

} // RBranch::ScoreEvent

//------------------------------------------------------------------------------------
// Debugging function.

bool RBranch::CheckInvariant() const
{
    // Recombinant branches have one child...
    if (!Child(0))
    {
        return false;
    }

    if (Child(1))
    {
        return false;
    }

    //...and at least one parent.
    if (!Parent(0))
    {
        return false;
    }

    if (!Branch::CheckInvariant()) return false;
    return true;

} // CheckInvariant

//------------------------------------------------------------------------------------
// Debugging function.
// Call only when underlying data structures (trees, branches, ranges)
// are potentially recombinant (ie, contain RecRanges, not Ranges).

bool RBranch::RevalidateRange(FC_Status & fcstatus) const
{
    RecRange * my_recrange_ptr(dynamic_cast<RecRange *>(GetRangePtr()));
    assert(my_recrange_ptr);            // FIRE if fcn called on non-recombinant object.

#if 0 // Include this branch if RevalidateRange is only being called after Prune().
    long int recpoint(my_recrange_ptr->GetRecpoint()); // Littlelink (Biglink midpoint, if Biglinks enabled).

    RecRange * child_recrange_ptr(dynamic_cast<RecRange *>(Child(0)->GetRangePtr()));
    assert(child_recrange_ptr);

    if (!(child_recrange_ptr->IsLinkTargetable(recpoint)))
    {
        cerr << "Non-targetable recombination site found in RBranch: " << m_ID.ID() << endl;
        return false;
    }
#endif

    rangeset livesites(Intersection(Child(0)->GetRangePtr()->GetLiveSites(), GetRangePtr()->GetTransmittedSites()));
    if (!(GetRangePtr()->SameLiveSites(livesites)))
    {
        cerr << "RevalidateRange found !SameLiveSites in RBranch: " << m_ID.ID() << endl;
        return false;
    }

    // Did we change color inappropriately?
    if (GetRangePtr()->AreDiseaseSitesTransmitted())
    {
        if (Child(0)->m_partitions != m_partitions)
        {
            cerr << "Branch changed color in RBranch: " << m_ID.ID() << endl;
            return false;
        }
    }

    if (GetRangePtr()->LiveSitesOnly()) return true; // We're done.
    //
    // From here to end, we require that this function is called only on recombinant branches,
    // which contain RecRange objects rather than Range objects.  That is guaranteed, because
    // LiveSitesOnly() returns TRUE for non-recombinant branches.  The issue is not what kind
    // of event we are processing; it is what kind of Range object the branch contains.
    //
#if FINAL_COALESCENCE_ON
    linkrangeset curtargetlinks(RecRange::LinksSpanningSites
                                (Union(my_recrange_ptr->GetDiseaseSites(),
                                       RemoveRangeFromRange(fcstatus.Coalesced_Sites(), livesites))));
#else
    linkrangeset curtargetlinks(RecRange::LinksSpanningSites(Union(my_recrange_ptr->GetDiseaseSites(), livesites)));
#endif

    if (my_recrange_ptr->DifferentCurTargetLinks(curtargetlinks))
    {
        cerr << "RevalidateRange found DifferentTargetLinks in RBranch: " << m_ID.ID() << endl;
        //
        cerr << "RBranch::RevalidateRange (invalid CurTargetLinks) call to RecRange::PrintInfo()" << endl << endl;
        my_recrange_ptr->PrintInfo();
        //
        cerr << "Target Links [my_recrange_ptr->GetCurTargetLinks()]:  ";
        RecRange::PrintLinks(my_recrange_ptr->GetCurTargetLinks());
        //
        cerr << endl << "Target Links [curtargetlinks]:  ";
        RecRange::PrintLinks(curtargetlinks);
        cerr << endl;
        //
        return false;
    }

    if (my_recrange_ptr->DifferentNewTargetLinks(RemoveRangeFromRange(my_recrange_ptr->GetOldTargetLinks(), curtargetlinks)))
    {
        cerr << "RevalidateRange found DifferentNewTargetLinks in RBranch: " << m_ID.ID() << endl;
        //
        cerr << "RBranch::RevalidateRange (invalid NewTargetLinks) call to RecRange::PrintInfo()" << endl << endl;
        my_recrange_ptr->PrintInfo();
        //
        cerr << "Target Links [RemoveRangeFromRange(my_recrange_ptr->GetOldTargetLinks(), curtargetlinks)]:  ";
        RecRange::PrintLinks(RemoveRangeFromRange(my_recrange_ptr->GetOldTargetLinks(), curtargetlinks));
        //
        cerr << endl << "Target Links [curtargetlinks]:  ";
        RecRange::PrintLinks(curtargetlinks);
        cerr << endl;
        //
        return false;
    }

    return true;

} // RBranch::RevalidateRange

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

string RBranch::GetGraphMLNodeType() const
{
    return "Rec";
}

//------------------------------------------------------------------------------------
// Called only when underlying data structures (trees, branches, ranges)
// are potentially recombinant (ie, contain RecRanges, not Ranges).

void RBranch::AddNodeInfo(TiXmlElement * nodeElem) const
{
    // Testing recombination location information.
    TiXmlElement * recElem = new TiXmlElement("data");
    nodeElem->LinkEndChild(recElem);
    recElem->SetAttribute("key", "rec_location");

    RecRange * my_recrange_ptr(dynamic_cast<RecRange *>(GetRangePtr()));
    assert(my_recrange_ptr);                            // FIRE if fcn called on non-recombinant object.
    long int recpoint = my_recrange_ptr->GetRecpoint(); // Littlelink (Biglink midpoint, if Biglinks enabled).

    recpoint += 2; // increment to make consistent with GraphML conventions
    TiXmlText * rlTypeText = new TiXmlText(ToString(recpoint));
    recElem->LinkEndChild(rlTypeText);
}

//____________________________________________________________________________________
