// $Id: timelist.cpp,v 1.61 2018/01/03 21:33:04 mkkuhner Exp $

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

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

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

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

*/

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


#include <cassert>
#include <functional>                   // for mem_fun
#include <iostream>                     // debugging
#include <fstream>                      // for WriteBestTree
#include <set>                          // for PrintTreeList()

#include <algorithm>                    // used only in debug code
#include <boost/algorithm/string.hpp>   // for trim function

#include "local_build.h"
#include "dynatracer.h"                 // Defines some debugging macros.

#include "force.h"                      // for SetStickParams() use of StickForce.
#include "timelist.h"
#include "stringx.h"                    // for access to Pretty() in PrintTimeList()
                                        //     also for ToString() in PrintTreeList()
#include "datapack.h"                   // for TipData class
#include "errhandling.h"                // for exceptions
#include "tinyxml.h"

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

using namespace std;

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

bool is_sorted(Branchconstiter begin, Branchconstiter end)
{
    if (begin == end) return true;
    Branchconstiter i = begin;
    Branchconstiter j = i;
    for (j++; j != end && i != end; i++, j++)
    {
        if ((*j)->m_eventTime < (*i)->m_eventTime) return false;
        if ((*j)->m_eventTime == (*i)->m_eventTime &&
            (*j)->GetID() < (*i)->GetID()) return false;
    }
    return true;
}

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

// TimeList constructor

TimeList::TimeList()
{
    m_base = Branch_ptr(new BBranch);
    m_base->m_eventTime = DBL_MAX;

    m_firsttip = m_branches.end();
    m_firstbody = m_branches.end();
    m_firstcoal = m_branches.end();

    m_ntips = m_ncuttable = 0;

} // TimeList::TimeList

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

TimeList::TimeList(const TimeList & src)
{
    m_base = Branch_ptr(new BBranch);
    CopyTips(src);
    CopyBody(src);

} // TimeList copy ctor

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

TimeList & TimeList::operator=(const TimeList & src)
{
    CopyTips(src);
    CopyBody(src);

    return *this;

} // TimeList::operator=

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

TimeList::~TimeList()
{
    // empty due to shared_ptr
} // TimeList::~TimeList

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

void TimeList::Clear()
{
    m_branches.clear();

    m_firsttip = m_branches.end();
    m_firstbody = m_branches.end();
    m_firstcoal = m_branches.end();

    m_ntips = m_ncuttable = 0;
    ClearBranchCount();

} // TimeList::Clear

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

void TimeList::ClearBody()
{
    ClearBranchCount();                 // clears all branches from counter

    Branchiter brit;
    for(brit = FirstTip(); brit != EndBranch(); brit = NextTip(brit))
    {
        (*brit)->SetParent(0, Branch::NONBRANCH);
        (*brit)->SetParent(1, Branch::NONBRANCH);
        CountBranch((*brit)->Event());  // re-introduces tips only
    }

    m_branches.remove_if(IsBodyGroup());
    m_ncuttable = GetNTips();

    // reset stored locations into body
    m_firstbody = m_branches.end();
    m_firstcoal = m_branches.end();

} // TimeList::ClearBody

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

void TimeList::ClearPartialBody(Branchiter firstinvalid)
{
    double cuttime = (*firstinvalid)->m_eventTime;

    Branchiter brit;
    for (brit = BeginBranch(); brit != firstinvalid; ++brit)
    {
        Branch_ptr branch = *brit;
        long pa(0L);
        for (pa = 0; pa < NELEM; ++pa)
        {
            // WARNING warning -- does this comparison fail for tied non-tip branches?
            if (branch->Parent(pa))
            {
                // I believe this assert checks for tie-related failure--Mary
                assert(!(branch->Parent(pa) == *firstinvalid && branch->Parent(pa)->m_eventTime != cuttime));
                if (branch->Parent(pa)->m_eventTime > cuttime)
                {
                    branch->SetParent(pa, Branch::NONBRANCH);
                }
            }
        }
    }

    // Uncount the dying branches.
    for (brit = firstinvalid; brit != m_branches.end(); brit = NextBody(brit))
    {
        m_ncuttable -= (*brit)->Cuttable();
        UncountBranch((*brit)->Event());
    }

    bool neednewbody(cuttime <= (*m_firstbody)->m_eventTime);
    bool neednewcoal(cuttime <= (*m_firstcoal)->m_eventTime);

    // Erase unwanted entries.
    m_branches.erase(remove_if(firstinvalid, EndBranch(), IsBodyGroup()), EndBranch());

    if (neednewbody)
        m_firstbody = find_if(m_branches.begin(), m_branches.end(), IsBodyGroup());
    if (neednewcoal)
        m_firstcoal = find_if(m_branches.begin(), m_branches.end(), IsCoalGroup());

} // ClearPartialBody

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

long TimeList::GetNBodyBranches() const
{
    return count_if(BeginBranch(), EndBranch(), IsBodyGroup());
} // TimeList::GetNBodyBranches

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

TBranch_ptr TimeList::CreateTip(const TipData & tipdata, const vector<LocusCell> & cells,
                                const vector<LocusCell> & movingcells, long nsites, rangeset diseasesites)
{
    // used in sample only case
    TBranch_ptr ptip = TBranch_ptr(new TBranch(tipdata, nsites, diseasesites));
    ptip->SetDLCells(cells);
    ptip->SetMovingDLCells(movingcells);

    // This way tips are added the same way everybody is, and it's ensured they'll be in the right order.
    Collate(ptip);

    ++m_ntips;

    return ptip;

} // TimeList::CreateTip

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

TBranch_ptr TimeList::CreateTip(const TipData & tipdata, const vector<LocusCell> & cells,
                                const vector<LocusCell> & movingcells, long nsites, rangeset diseasesites,
                                const vector<Locus> & loci)
{
    // used in panel case
    TBranch_ptr ptip = TBranch_ptr(new TBranch(tipdata, nsites, diseasesites));
    ptip->SetDLCells(cells);
    ptip->SetMovingDLCells(movingcells);

    // This way tips are added the same way everybody is, and it's ensured they'll be in the right order.
    Collate(ptip);

    ++m_ntips;

    // create invariant mask for samples
    DoubleVec1d unkmask(INVARIANTS,1);

    // loop over loci because different loci can have different models
    for (unsigned int i = 0; i<loci.size(); i++)
    {
        // fill the tip invariant cells
        Cell_ptr pdlcell = ptip->GetDLCell(loci[i].GetIndex(), invariantCell, false);

        if (ptip->m_isSample == 0)
        {
            // panel tip masks - use DatatoLikes to accommodate error
            // seems like this could all happen in the SetAllCategories calls, but I couldn't get the types to get along - JRMfix
            DoubleVec1d amask = loci[i].GetDataModel()->DataToLikes(SINGLEBASES[baseA]);
            DoubleVec1d cmask = loci[i].GetDataModel()->DataToLikes(SINGLEBASES[baseC]);
            DoubleVec1d gmask = loci[i].GetDataModel()->DataToLikes(SINGLEBASES[baseG]);
            DoubleVec1d tmask = loci[i].GetDataModel()->DataToLikes(SINGLEBASES[baseT]);

            pdlcell->SetAllCategoriesTo(amask, baseA);
            pdlcell->SetAllCategoriesTo(cmask, baseC);
            pdlcell->SetAllCategoriesTo(gmask, baseG);
            pdlcell->SetAllCategoriesTo(tmask, baseT);
        }
        else
        {
            // sample tip - set everything to unknown
            for (int i=0; i<INVARIANTS; i++)
            {
                pdlcell->SetAllCategoriesTo(unkmask, i);
            }
        }
    }
    return ptip;
} // TimeList::CreateTip

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

TBranch_ptr TimeList::GetTip(const string & tipname) const
{
    TBranch_ptr ptip;
    string loctipname = tipname;
    boost::trim(loctipname);

    Branchconstiter brit;
    for(brit = FirstTip(); brit != m_branches.end(); brit = NextTip(brit))
    {
        ptip = boost::dynamic_pointer_cast<TBranch>(*brit);
        assert(ptip);
        string label = ptip->m_label;
        boost::trim(label);
        if (label == loctipname) return ptip;
    }

    throw data_error("Unable to find tip:  " + tipname);

} // TimeList::GetTip

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

void TimeList::CopyTips(const TimeList & src)
{
    // Clear out a timelist, then copy in tips from another timelist.
    Clear();

    Branchconstiter brit;
    for (brit = src.FirstTip(); brit != src.EndBranch(); brit = src.NextTip(brit))
    {
        CollateAndSetCrossrefs((*brit)->Clone(), *brit);
        CountBranch((*brit)->Event());
    }

    m_ntips = src.m_ntips;
    m_firsttip = find_if(m_branches.begin(), m_branches.end(), IsTipGroup());

} // TimeList::CopyTips

//------------------------------------------------------------------------------------
// Assuming that by "equivalent" we mean, has the same event, partition info,
// eventtime, Link weight, recombination point, and label (if any).

Branchiter TimeList::FindEquivBranch(const Branch_ptr target)
{
    Branchiter myit;
    assert(target);

    for (myit = BeginBranch(); myit != EndBranch(); ++myit)
        if (target->IsEquivalentTo(*myit)) return myit;

    assert(false);

    return myit;

} // TimeList::FindEquivBranch

//------------------------------------------------------------------------------------
// CopyBody() assumes that the tips of src and *this are identical!  It also assumes
// that no internal *node* of the tree has both 2 parents and 2 children.

void TimeList::CopyBody(const TimeList & src)
{
    ClearBody();

    Branch_ptr newbranch;
    Branchconstiter brit = src.FirstBody();

    // If the src tree has no body, we will not attempt to copy it
    // nor to hook up the Base.  Given an incomplete tree, we return
    // an incomplete tree.  Mary August 2001
    if (brit != src.EndBranch())
    {
        for( ; brit != src.EndBranch(); brit = src.NextBody(brit))
        {
            newbranch = (*brit)->Clone();
            Branch_ptr srcchild = (*brit)->Child(0);
            Branch_ptr newchild = srcchild->GetEquivBranch().lock();
            assert(newchild);
            newbranch->SetChild(0, newchild);

            if (srcchild->Parent(0) == *brit)
            {
                newchild->SetParent(0, newbranch);
                srcchild = (*brit)->Child(1);
                if (srcchild)
                {
                    newchild = srcchild->GetEquivBranch().lock();
                    assert(newchild);
                    newbranch->SetChild(1, newchild);
                    newchild->SetParent(0, newbranch);
                }
            }
            else
            {
                newchild->SetParent(1, newbranch);
            }

            CollateAndSetCrossrefs(newbranch, *brit);
        }

        m_base->SetChild(0, newbranch);
        newbranch->SetParent(0, m_base);
    }

    m_ncuttable = src.m_ncuttable;
    m_branchmap = src.m_branchmap;

} // TimeList::CopyBody

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

void TimeList::CopyPartialBody(const TimeList & src, const Branchiter & srcstart, Branchiter & mystart)
{
    // This differs from CopyBody in that it only copies the part of the
    // TimeList that differs between this and src, as an optimization.

    // Possible speedup involving moving the functionality of
    // ClearPartialBody inside the loop over branches below!?
    ClearPartialBody(mystart);

    Branch_ptr newbranch;
    Branchconstiter brit = src.FirstBody();

    // If the src tree has no body, we will not attempt to copy it nor to hook up the Base.
    // Given an incomplete tree, we return an incomplete tree.  Mary August 2001
    if (brit != src.EndBranch())
    {
        for(brit = srcstart; brit != src.EndBranch(); brit = src.NextBody(brit))
        {
            newbranch = (*brit)->Clone();
            Branch_ptr srcchild = (*brit)->Child(0);
            Branch_ptr newchild = srcchild->GetEquivBranch().lock();
            assert(newchild);
            newbranch->SetChild(0, newchild);

            if (srcchild->Parent(0) == *brit)
            {
                newchild->SetParent(0, newbranch);
                srcchild = (*brit)->Child(1);
                if (srcchild)
                {
                    newchild = srcchild->GetEquivBranch().lock();
                    assert(newchild);
                    newbranch->SetChild(1, newchild);
                    newchild->SetParent(0, newbranch);
                }
            }
            else
            {
                newchild->SetParent(1, newbranch);
            }

            CollateAndSetCrossrefs(newbranch, *brit);
        }

        m_base->SetChild(0, newbranch);
        newbranch->SetParent(0, m_base);
    }
    assert(is_sorted(m_branches.begin(), m_branches.end()));

    m_ncuttable = src.m_ncuttable;
    m_branchmap = src.m_branchmap;

} // TimeList::CopyPartialBody

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

bool TimeIsLessThan(Branch_ptr b1, Branch_ptr b2)
{
    //This could also check IDs, but it was already too slow.  We would
    // use it for lower_bound, if we found a way to make that faster.
    return (b1->GetTime() < b2->GetTime());
}

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

Branchiter TimeList::Collate(Branch_ptr newbranch)
{
    Branchiter brit;

    // Degenerate collate into an empty list.  This might not be necessary at all,
    // except that it set 'm_ncuttable' to 0 and called 'ClearBranchCount'.
    // Do we need this?  At least it doesn't hurt anything.
    if (m_branches.empty())
    {
        m_branches.push_front(newbranch);
        brit = m_branches.begin();  // since we used push_front
        m_ncuttable = 0;
        ClearBranchCount();
        UpdateBookkeeping(brit);
        return brit;
    }

    //LS NOTE:  This is one way to find where to insert the new branch.  It ended
    // up being slightly slower and it's a bit more obscure, so below is the
    // slightly-faster, more-plodding version.  I've left it here as a template
    // if anyone wants to try using lower_bound or something like it later.
#if 0
    Branchiter lowerbound = lower_bound(m_branches.begin(), m_branches.end(), newbranch, &TimeIsLessThan);

    while (lowerbound != m_branches.end() &&
           (*lowerbound)->m_eventTime == newbranch->m_eventTime &&
           (*lowerbound)->GetID() < newbranch->GetID())
    {
        lowerbound++;
    }

    if (lowerbound != m_branches.begin())
    {
        Branchiter onelower = lowerbound;
        onelower--;
        while (onelower != m_branches.begin() &&
               (*onelower)->m_eventTime == newbranch->m_eventTime &&
               (*onelower)->GetID() > newbranch->GetID())
        {
            onelower--;
            lowerbound--;
        }
    }
#endif

    //LS NOTE:  This routine can take up 1/4 of the time spent in rearrangement,
    // (for particularly high values of recombination) so if you see a way to
    // speed it up, take it.  Do note that a version that used 'lower_bound'
    // ended up being a bit slower, sadly.
    Branchiter lowerbound = m_branches.begin();

    // Iterate to the first branch whose time is greater than or equal to the new branch's time.
    while (lowerbound != m_branches.end() &&
           (*lowerbound)->m_eventTime < newbranch->m_eventTime)
    {
        ++lowerbound;
    }

    // Iterate to the first branch whose ID is greater than the current branch's ID,
    // assuming we don't go beyond the current time.
    while (lowerbound != m_branches.end() &&
           (*lowerbound)->m_eventTime == newbranch->m_eventTime &&
           (*lowerbound)->GetID() < newbranch->GetID())
    {
        ++lowerbound;
    }

    brit = m_branches.insert(lowerbound, newbranch);
    UpdateBookkeeping(brit);

    return brit;

} // TimeList::Collate

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

Branchiter TimeList::Collate(Branch_ptr newbranch, Branch_ptr spouse)
{
    //Used only to add recombination events, which are tied for their times.
    // This is done purely as a time-saving measure for highly-recombinant trees.
    // Currently, the return value is discarded, but that could change--it
    // now points to the iter of where 'newbranch' went in (and not, say, the
    // earlier of the two possibilities).
    Branchiter spousepoint = Collate(spouse);

    if (newbranch->GetID() > spouse->GetID())
    {
        // We should add 'newbranch' after 'spouse', not before.
        ++spousepoint;
    }

    Branchiter brit = m_branches.insert(spousepoint, newbranch);
    UpdateBookkeeping(brit);

    return brit;
}

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

Branchiter TimeList::CollateAndSetCrossrefs(Branch_ptr newbranch, Branch_ptr oldbranch)
{
    assert (newbranch != Branch::NONBRANCH);
    assert (oldbranch != Branch::NONBRANCH);
    newbranch->SetEquivBranch(oldbranch);
    oldbranch->SetEquivBranch(newbranch);
    return Collate(newbranch);
}

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

void TimeList::UpdateBookkeeping(Branchiter newbranch)
{
    m_ncuttable += (*newbranch)->Cuttable();
    CountBranch((*newbranch)->Event());
    UpdateFirstsIfNecessary(newbranch);
}

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

void TimeList::Remove(Branch_ptr badbranch)
{
    switch(badbranch->BranchGroup())
    {
        case bgroupTip:
            if (badbranch == *m_firsttip) m_firsttip = NextTip(m_firsttip);
            break;
        case bgroupBody:
            if (badbranch == *m_firstbody) m_firstbody = NextBody(m_firstbody);
            if (badbranch == *m_firstcoal) m_firstcoal = NextCoal(m_firstcoal);
            break;
        default:
            throw implementation_error("TimeList::Unknown branch group.");
    }

    m_branches.remove(badbranch);
    m_ncuttable -= badbranch->Cuttable();
    UncountBranch(badbranch->Event());

} // TimeList::Remove

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

Branchiter TimeList::NextTip(Branchiter & it)
{
    Branchiter mit(it);
    ++mit;
    return ((mit == EndBranch()) ? EndBranch() : find_if(mit, EndBranch(), IsTipGroup()));

} // TimeList::NextTip

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

Branchconstiter TimeList::NextTip(Branchconstiter & it) const
{
    Branchconstiter mit(it);
    ++mit;
    return ((mit == EndBranch()) ? EndBranch() : find_if(mit, EndBranch(), IsTipGroup()));

} // TimeList::NextTip

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

Branchiter TimeList::NextBody(Branchiter & it)
{
    Branchiter mit(it);
    ++mit;
    return ((mit == EndBranch()) ? EndBranch() : find_if(mit, EndBranch(), IsBodyGroup()));

} // TimeList::NextBody

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

Branchconstiter TimeList::NextBody(Branchconstiter & it) const
{
    Branchconstiter mit(it);
    ++mit;
    return ((mit == EndBranch()) ? EndBranch() : find_if(mit, EndBranch(), IsBodyGroup()));

} // TimeList::NextBody

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

Branchiter TimeList::NextCoal(Branchiter & it)
{
    Branchiter mit(it);
    ++mit;
    return ((mit == EndBranch()) ? EndBranch() : find_if(mit, EndBranch(), IsCoalGroup()));

} // TimeList::NextCoal

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

Branchconstiter TimeList::NextCoal(Branchconstiter & it) const
{
    Branchconstiter mit(it);
    ++mit;
    return ((mit == EndBranch()) ? EndBranch() : find_if(mit, EndBranch(), IsCoalGroup()));

} // TimeList::NextCoal

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

Branchiter TimeList::PrevBodyOrTip(Branchiter & it)
{
    Branchiter mit(it);
    --mit;
    IsBodyGroup bodycheck;
    IsTipGroup tipcheck;
    while(!bodycheck(*mit) && !tipcheck(*mit)) --mit;
    return mit;

} // TimeList::PrevBody

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

Branchiter TimeList::NextNonTimeTiedBranch(Branchiter & it)
{
    Branchiter mit(it);
    ++mit;
    double badtyme((*it)->m_eventTime);
    while ((*mit)->m_eventTime == badtyme) ++mit;
    return mit;

} // TimeList::NextNonTimeTiedBranch

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

Branchiter TimeList::FindIter(Branch_ptr branch)
{
    return ((m_branches.empty()) ? EndBranch() : find(BeginBranch(), EndBranch(), branch));
} // TimeList::FindIter

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

Branchconstiter TimeList::FindIter(Branch_ptr branch) const
{
    Branchconstiter brit;

    for(brit = BeginBranch(); brit != EndBranch(); ++brit)
        if (*brit == branch) break;  // yes, we compare pointers!

    return brit;

} // TimeList::FindIter

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

void TimeList::Prune()
{
    // Excise marked branches.
    Branchiter brit;
    for(brit = FirstBody() ; brit != EndBranch() ; )
    {
        Branch_ptr pbranch = *brit;
        if (pbranch->m_marked)
        {
            Branch_ptr pparent = pbranch->Parent(0);
            pparent->ReplaceChild(pbranch, pbranch->Child(0));
            SetUpdateDLs(pparent);

            pparent = pbranch->Parent(1);
            if (pparent)
            {
                pparent->ReplaceChild(pbranch, pbranch->Child(0));
                SetUpdateDLs(pparent);
            }
            brit = NextBody(brit);
            Remove(pbranch);            // deletes what pbranch points to
            continue;
        }
        brit = NextBody(brit);
    }
    assert(IsValidTimeList());

    // Check for loops in the root.
    long nbranches = 2 * m_ntips;
    for(brit = FirstBody() ; ; brit = NextBody(brit))
    {
        nbranches += (*brit)->CountDown();
        if (nbranches <= 2) break;
    }

    if (*brit != Root())
    {
        m_base->SetChild(0, *brit);
        (*brit)->SetParent(0, m_base);
        (*brit)->SetParent(1, Branch::NONBRANCH);

        // We could use std::remove_if, but we'd still need to do this handloop
        // for stuff like Uncount, and updating of m_firstfoo pointers.
        for(brit = NextBody(brit) ; brit != m_branches.end() ; )
        {
            Branch_ptr pbranch = *brit;
            brit = NextBody(brit);
            Remove(pbranch);
        }
    }

    assert(IsValidTimeList());

} // TimeList::Prune

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

void TimeList::SetUpdateDLs(Branch_ptr pBranch)
{
    if (pBranch->Event() == btypeBase) return; // The base terminates recursion.

    if (!pBranch->GetUpdateDL())
    {
        pBranch->SetUpdateDL();
        SetUpdateDLs(pBranch->Parent(0));

        if (pBranch->Parent(1))
            SetUpdateDLs(pBranch->Parent(1));
    }

} // TimeList::SetUpdateDLs

//------------------------------------------------------------------------------------
// Marks the entire tree as needing updating--a debug function.

void TimeList::SetAllUpdateDLs()
{
    Branchiter brit;
    for (brit = m_branches.begin(); brit != m_branches.end(); ++brit)
        (*brit)->SetUpdateDL();
    --brit;
    (*brit)->SetUpdateDL();

} // SetAllUpdateDLs()

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

void TimeList::ClearUpdateDLs()
{
    Branchiter brit;
    for(brit = m_branches.begin(); brit != m_branches.end(); ++brit)
        (*brit)->ClearUpdateDL();

} // TimeList::ClearUpdateDLs

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

void TimeList::PrintTimeList() const
{
    PrintTimeList(cerr);
}

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

void TimeList::PrintTimeList(ostream& os) const
{
    os << endl;
    os << " New tree start " << endl;
    Branchconstiter branch;

    for(branch = BeginBranch(); branch != EndBranch(); ++branch)
    {
        os << "**Branch " << (*branch)->GetID() << endl;
        (*branch)->PrintInfo();
    }

    vector<Branch_ptr> endbranch;
    vector<Branch_ptr>::iterator br;
    //Branchiter branch;
    double tyme = 0.0;
    bool newinterval = true;
    for(branch = BeginBranch() ; branch != EndBranch() ; )
    {
        if (newinterval) os << Pretty(tyme) << ": branch(s) ";
        if ((*branch)->m_eventTime == tyme)
        {
            os << (*branch)->GetID();
            os << (*branch)->Event() << endl;
            (*branch)->GetRangePtr()->PrintLive();
            (*branch)->GetRangePtr()->PrintNewTargetLinks();
            os << (*branch)->GetUpdateDL();
            os << " ";
            long site;
            os << endl;
            if ((*branch)->Event() == btypeTip)
            {
                for(site = 0; site < 4; ++site)
                {
                    DNACell * pcell = dynamic_cast<DNACell *>((*branch)->GetDLCell(0, markerCell, false).get());
                    os << "   " << Pretty(pcell->GetSiteDLs(site)[0][baseA]);
                    os << "   " << Pretty(pcell->GetSiteDLs(site)[0][baseC]);
                    os << "   " << Pretty(pcell->GetSiteDLs(site)[0][baseG]);
                    os << "   " << Pretty(pcell->GetSiteDLs(site)[0][baseT]);
                    os << endl;
                }
            }
            newinterval = false;
        }
        else
        {
            os << "start" << endl;
            newinterval = true;
            if (!endbranch.empty())
            {
                os << "      branch(s) ";
                for(br = endbranch.begin(); br != endbranch.end(); ++br)
                {
                    if (*br != Branch::NONBRANCH)
                    {
                        os << (*br)->GetID();
                        os << (*br)->Event() << endl;
                        (*br)->GetRangePtr()->PrintLive();
                        (*br)->GetRangePtr()->PrintNewTargetLinks();
                        os << (*br)->GetUpdateDL();
                        os << " ";
                    }
                }
                os << " end" << endl;
            }
            endbranch = (*branch)->GetBranchChildren();
            tyme = (*branch)->m_eventTime;
            continue;
        }
        ++branch;
    }

    // Catch the branches that end at the root.
    os << endl << "      branch(s) ";
    for(br = endbranch.begin(); br != endbranch.end(); ++br)
    {
        if (*br != Branch::NONBRANCH)
        {
            os << (*br)->GetID();
            os << (*br)->Event();
            (*br)->GetRangePtr()->PrintLive();
            (*br)->GetRangePtr()->PrintNewTargetLinks();
            os << (*br)->GetUpdateDL();
            os << " ";
        }
    }

    os << " end at the root" << endl;

} // TimeList::PrintTimeList

//------------------------------------------------------------------------------------
// Debugging function.
// Prints in "internal" units, not "user" units.

void TimeList::PrintTreeList() const
{
    PrintTreeList(cerr);
}

//------------------------------------------------------------------------------------
// Debugging function.
// Prints in "internal" units, not "user" units.

void TimeList::PrintTreeList(ostream & of) const
{
    set<string> branches;

    Branchconstiter branch = FirstTip();
    of << endl;
    of << ToString((*branch)->GetID()) << " ";
    of << ToString((*branch)->Event()) << "/" << (*branch)->m_eventTime << ":";
    for( ; branch != EndBranch() ; branch = NextTip(branch))
    {
        string id = ToString((*branch)->GetID());
        branches.insert(id);
        of << " " << id;
    }
    of << endl;

    for(branch = FirstBody() ; branch != EndBranch() ; branch = NextBody(branch))
    {
        string id = ToString((*branch)->GetID());
        branch_type event = (*branch)->Event();
        //of << id << ToString(event) << "/" << (*branch)->m_eventTime;
        of << id << " " << ToString(event) << ":" << ToString((*branch)->GetUpdateDL())
           << "/" << (*branch)->m_eventTime;

        string chid = ToString((*branch)->Child(0)->GetID());
        branches.erase(chid);
        branches.insert(id);

        switch(event)
        {
            case btypeCoal:
                of << ":";
                if ((*branch)->Child(1) != NULL) // defends against 1-leg coal
                {
                    chid = ToString((*branch)->Child(1)->GetID());
                    branches.erase(chid);
                }
                break;
            case btypeRec:
                ++branch;
                id = ToString((*branch)->GetID());
                event = (*branch)->Event();
                of << "/" << id << event << ":";
                branches.insert(id);
                break;
            case btypeMig:
            case btypeDivMig:
            case btypeDisease:
            case btypeEpoch:
                of << ":";
                break;
            case btypeBase:
            case btypeTip:
                assert(false);          // unknown branch type
        }
        set<string>::iterator br;
        for(br = branches.begin(); br != branches.end(); ++br)
            of << " " << *br;
        if (!(*branch)->m_partitions.empty())
            of << " " << "status = " << (*branch)->m_partitions[0];
        of << endl;
    }

    of << "End of Tree" << endl;

} // TimeList::PrintTreeList()

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

TiXmlDocument * TimeList::AssembleGraphML() const
{

    TiXmlDocument * docP = new TiXmlDocument();

    TiXmlDeclaration * decl = new TiXmlDeclaration("1.0", "", "");
    docP->LinkEndChild( decl );

    TiXmlElement * graphml = new TiXmlElement("graphml");
    docP->LinkEndChild( graphml );

    /////////////////////////////////////////////////////////////////////////
    // stuff at the top of graphML; used to specify what in-house tags and
    // attributes we are using

    // partitions
    TiXmlElement * ptype = new TiXmlElement("key");
    ptype->SetAttribute("id", "partitions");
    ptype->SetAttribute("for", "edge");
    ptype->SetAttribute("attr.name", "ptype");
    ptype->SetAttribute("attr.type", "string");
    graphml->LinkEndChild(ptype);

    // recombination range for edge
    TiXmlElement * rtype = new TiXmlElement("key");
    rtype->SetAttribute("id", "live_sites");
    rtype->SetAttribute("for", "edge");
    rtype->SetAttribute("attr.name", "asites");
    rtype->SetAttribute("attr.type", "string");
    graphml->LinkEndChild(rtype);

    // location of recombination event
    TiXmlElement * rltype = new TiXmlElement("key");
    rltype->SetAttribute("id", "rec_location");
    rltype->SetAttribute("for", "node");
    rltype->SetAttribute("attr.name", "rloc");
    rltype->SetAttribute("attr.type", "long");
    graphml->LinkEndChild(rltype);

    // type of node (coal, rec, divmig, etc)
    TiXmlElement * ntype = new TiXmlElement("key");
    ntype->SetAttribute("id", "node_type");
    ntype->SetAttribute("for", "node");
    ntype->SetAttribute("attr.name", "ntype");
    ntype->SetAttribute("attr.type", "string");
    graphml->LinkEndChild(ntype);

    // integer ID for node
    TiXmlElement * ntime = new TiXmlElement("key");
    ntime->SetAttribute("id", "node_time");
    ntime->SetAttribute("for", "node");
    ntime->SetAttribute("attr.name", "ntime");
    ntime->SetAttribute("attr.type", "double");
    graphml->LinkEndChild(ntime);

    // node label -- should only be for tips
    TiXmlElement * nlabel = new TiXmlElement("key");
    nlabel->SetAttribute("id", "node_label");
    nlabel->SetAttribute("for", "node");
    nlabel->SetAttribute("attr.name", "nlabel");
    nlabel->SetAttribute("attr.type", "string");
    graphml->LinkEndChild(nlabel);

    /////////////////////////////////////////////////////////////////////////
    // now we start the actual graph

    TiXmlElement * graph = new TiXmlElement("graph");
    graph->SetAttribute("id", "myGraph");
    graph->SetAttribute("edgedefault", "directed");
    graphml->LinkEndChild( graph );

    for(Branchconstiter branch = BeginBranch(); branch != EndBranch(); ++branch)
    {
        (*branch)->AddGraphML(graph);
    }

    return docP;

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

void TimeList::PrintIDs() const
{
    for (Branchconstiter brit = m_branches.begin(); brit != m_branches.end(); brit++)
    {
        cerr << (*brit)->GetID() << "\t"
             << (*brit)->GetTime() << "\t"
             << ToString((*brit)->Event()) << endl;
    }
}

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

void TimeList::PrintTips()
{
    cerr << endl << " The tips are " << endl;
    Branchiter branch;

    for(branch = FirstTip(); branch != EndBranch(); branch = NextTip(branch))
    {
        TBranch_ptr tip = boost::dynamic_pointer_cast<TBranch>(*branch);
        assert(tip);
        cerr << "   " << tip->m_label << " with id#";
        cerr << tip->GetID();
        if (tip->m_partitions.size())
        {
            cerr << " " << tip->m_partitions[0];
        }
        cerr << endl;
    }

    cerr << "End tips" << endl;

} // TimeList::PrintTips

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

void TimeList::PrintDirectionalMutationEventCountsToFile(ofstream & of) const
{
    if (!registry.GetForceSummary().CheckForce(force_DISEASE)) return;

    LongVec1d::size_type nparts(registry.GetDataPack(). GetNPartitionsByForceType(force_DISEASE));

    LongVec1d footemp(nparts, 0L);
    LongVec2d nevents(nparts, footemp);
    Branchconstiter brit;
    for (brit = FirstBody(); brit != m_branches.end(); ++brit)
    {
        if ((*brit)->Event() == btypeDisease)
        {
            nevents[(*brit)->GetPartition(force_DISEASE)][(*brit)->Child(0)->GetPartition(force_DISEASE)]++;
        }
    }

    of << "DiseaseEventCounts: ";
    LongVec2d::size_type startdis;
    for(startdis = 0; startdis < nparts; ++startdis)
    {
        LongVec2d::size_type enddis;
        for(enddis = 0; enddis < nparts; ++enddis)
        {
            if (startdis == enddis) continue;
            of << startdis << "->" << enddis << "=";
            of << nevents[startdis][enddis] << "; ";
        }
    }
    of << endl;

} // PrintDirectionMutationEventCountsToFile

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

void TimeList::PrintTimeTilFirstEventToFile(ofstream & of) const
{
    of << "FirstEvent at " << (*FirstBody())->m_eventTime;
} // PrintTimeTilFirstEventToFile

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

void TimeList::PrintTraitPhenotypeAtLastCoalescence(ofstream & of) const
{
    // we assume the last branch will be a coalescence
    of << "Last coalescence in " << m_branches.back()->GetPartition(force_DISEASE);

} // PrintTraitPhenotypeAtLastCoalescence

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

void TimeList::MakeCoalescent(double theta)
{
    assert (HowMany(btypeMig) == 0 && HowMany(btypeRec) == 0);

    long nbranches = GetNTips();
    Branchiter branch;

    for(branch = FirstBody(); branch != EndBranch(); branch = NextBody(branch))
    {
        assert(nbranches > 0);

        (*branch)->m_eventTime = theta / (nbranches * (nbranches - 1));
        --nbranches;
    }

} // TimeList::MakeCoalescent

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

string TimeList::DLCheck(const TimeList & other) const
{
    // This code should be commented in if DLCheck is being used to test for strict identity,
    // and commented out if you know the trees are not in fact identical but want to find out where.

#if 1  // Conditional compilation based on comment above.
    long ncoals = HowMany(btypeCoal), otherncoals = other.HowMany(btypeCoal);
    if (ncoals != otherncoals)
    {
        return string("The trees differ in number of coalescences!\n");
    }
#endif

    string problems;
    Branchconstiter branch, otherbranch;

    for(branch = BeginBranch(), otherbranch = other.BeginBranch();
        branch != EndBranch() && otherbranch != other.EndBranch();
        ++branch, ++otherbranch)
    {
        problems += (*branch)->DLCheck(**otherbranch);
    }

    return problems;

} // TimeList::DLCheck

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

void TimeList::CloneCheck() const
{
    vector<Branch_ptr> newbranches;
    Branchconstiter branch;

    for(branch = BeginBranch() ; branch != EndBranch() ; ++branch)
    {
        Branch_ptr newbranch = Branch::NONBRANCH;
        newbranch = (*branch)->Clone();
        if (!newbranch)
        {
            cerr << "Failed to clone branch " << (*branch)->GetID() << endl;
        }
        newbranches.push_back(newbranch);
    }

} // TimeList::CloneCheck

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

bool TimeList::IsPresent(const Branchiter & branch) const
{
    bool foundequiv = false;
    Branchconstiter brit;

    for(brit = BeginBranch() ; brit != EndBranch() ; ++brit)
    {
        if (*brit == *branch)
            return true;
        foundequiv = (**brit == **branch);
    }

    if (foundequiv)
        cerr << "Found equivalent but not same pointer!" << endl;

    return false;

} // TimeList::IsPresent()

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

bool TimeList::IsSameExceptForTimes(const TimeList & other) const
{
    Branchconstiter brit, otherbrit;
    for(brit = BeginBranch(), otherbrit = other.BeginBranch(); brit != EndBranch();
        ++brit, ++otherbrit)
    {
        if (!(*brit)->IsSameExceptForTimes(*otherbrit)) return false;
    }

    return true;

} // TimeList::IsSameExceptForTimes

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

void TimeList::PrintIntervalLengthsToFile() const
{
    ofstream fs;
    fs.open("timeints.out", ios::app);

    long interval;
    Branchconstiter top, bottom;
    for(top = BeginBranch(), bottom = FirstBody(), interval = 0;
        bottom != EndBranch();
        top = bottom, bottom = NextBody(bottom), ++interval)
    {
        if ((*top)->Event() == btypeRec)
        {
            top = bottom;
            bottom = NextBody(bottom);
        }
        double length((*bottom)->m_eventTime - (*top)->m_eventTime);
        fs << "int" << interval << " " << length << endl;
    }

    fs.close();

} // TimeList::PrintIntervalLengthsToFile

//------------------------------------------------------------------------------------
// The following functions manage the counters for branches of each type.
//------------------------------------------------------------------------------------

void TimeList::CountBranch(const branch_type tag)
{
    BranchMap::iterator it = m_branchmap.find(tag);

    if (it == m_branchmap.end())
    {   // entry not found
        m_branchmap.insert(make_pair(tag, 1L));
    }
    else
    {
        it->second++;
    }

} // CountBranch

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

void TimeList::UncountBranch(const branch_type tag)
{
    BranchMap::iterator it = m_branchmap.find(tag);
    assert(it != m_branchmap.end());    // why are we trying to remove a branch type that isn't there?
    it->second--;
    assert(it->second >= 0);            // why are we trying to remove a branch that isn't there?

} // UncountBranch

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

void TimeList::ClearBranchCount()
{
    // We don't get rid of entries, since they may be useful later when the same kind of branch comes round again.

    BranchMap::iterator it = m_branchmap.begin();
    BranchMap::iterator end = m_branchmap.end();

    for ( ; it != end; ++it)
    {
        it->second = 0L;
    }

} // ClearBranchCount

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

void TimeList::UpdateFirstsIfNecessary(Branchiter & branch)
{
    switch((*branch)->BranchGroup())
    {
        case bgroupTip:
            m_firsttip = find_if(m_branches.begin(), m_branches.end(), IsTipGroup());
            return;
        case bgroupBody:
            if (m_firstbody == m_branches.end() ||
                (*m_firstbody)->m_eventTime > (*branch)->m_eventTime)
            {
                m_firstbody = branch;
            }
            else
            {
                if ((*m_firstbody)->m_eventTime == (*branch)->m_eventTime)
                {
                    m_firstbody = find_if(m_branches.begin(), m_branches.end(), IsBodyGroup());
                }
            }
            if ((*branch)->Event() == btypeCoal)
            {
                if (m_firstcoal == m_branches.end() || (*m_firstcoal)->m_eventTime > (*branch)->m_eventTime)
                {
                    m_firstcoal = branch;
                }
                else
                {
                    if ((*m_firstcoal)->m_eventTime == (*branch)->m_eventTime)
                    {
                        m_firstcoal = find_if(m_branches.begin(), m_branches.end(), IsCoalGroup());
                    }
                }
            }
            return;
    }

    throw implementation_error("TimeList::Unknown branch group.");

} // UpdateFirstsIfNecessary

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

long TimeList::HowMany(branch_type tag) const
{
    BranchMap::const_iterator it = m_branchmap.find(tag);
    if (it == m_branchmap.end())        // entry not found
        return 0L;
    else return it->second;

} // HowMany

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

bool TimeList::ContainsOnlyTipsAndCoals() const
{
    // Trees must always contain tips and coalescences...
    if (m_branchmap.size() > 2) return false;

    return true;

} // ContainsOnlyTipsAndCoals

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

bool TimeList::ContainsOnlyTipsCoalsAndRecombs() const
{
    // Trees must always contain tips and coalescences...
    // so if there are 3 types and one is btypeRec...
    if(m_branchmap.size() == 3 && m_branchmap.find(btypeRec) != m_branchmap.end())
        return true;

    return false;
} // ContainsOnlyTipsCoalsAndRecombs

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

bool TimeList::operator==(const TimeList & src) const
{
    // We do not check for equivalence of m_firstbody, m_firstcoal, and m_firsttip.

    if (m_branchmap != src.m_branchmap) return false;
    if (m_ntips != src.m_ntips) return false;
    if (m_ncuttable != src.m_ncuttable) return false;

    if (m_branches.size() != src.m_branches.size()) return false;

    Branchconstiter mybr = m_branches.begin();
    Branchconstiter srcbr = src.m_branches.begin();

    for ( ; mybr != m_branches.end(); ++mybr, ++srcbr)
    {
        if (**mybr != **srcbr) return false;
    }

    return true;

} // operator==

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

Branchiter TimeList::ResolveTiedTimes(Branchconstiter firstinvalid)
{
    // the general case
    double firsttime((*firstinvalid)->m_eventTime);
    Branchiter br;
    for(br = FirstBody(); br != EndBranch(); br = NextBody(br))
    {
        if ((*br)->m_eventTime == firsttime) return br;
    }

    assert(false);                      // ResolveTiedTimes asked for a time that's not here!

    return EndBranch();

} // ResolveTiedTimes

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

bool TimeList::IsValidTimeList() const
{
    Branchconstiter it;
    long i = 0;
    bool okay = true;

    for (it = BeginBranch(); it != EndBranch(); ++it, ++i)
    {
        if (*it == Branch::NONBRANCH)
        {
            okay = false;               // Are there any null branches in this tree?
        }
        else
        {
            if ((*it)->GetRangePtr()->NoLiveAndNoTransmittedDiseaseSites())
            {
                // JDEBUG -- there could be a more rigorous test involving FC here.
                //
                // This branch of the IF handles only recombinant branches, guaranteed because
                // NoLiveAndNoTransmittedDiseaseSites() returns FALSE for non-recombinant branches.
                // The issue is the type of Range objects the branch contains, not the current event type.
                //
                cerr << "A " << ToString((*it)->Event()) << " branch with ";
                (*it)->GetRangePtr()->PrintLive();
                if ((*it)->Event() == btypeRec)
                {
                    // RBranch::GetRecpoint() returns a Littlelink (Biglink midpoint).
                    cerr << "  and recombination point at " << (*it)->GetRecpoint();
                }
                cerr << endl;
                const Branch_ptr br((*it)->Child(0));
                cerr << "  Active Sites in child: ";
                br->GetRangePtr()->PrintLive();
                cerr << "  Current Target Link Weight in child: " << br->GetRangePtr()->GetCurTargetLinkweight() << endl << endl;
                okay = false;
                cerr << "  Branch printout before ASSERT:" << endl << endl;
                (*it)->PrintInfo();
                assert(false);
            }

            branch_type event = ((*it)->Event());
            switch (event)
            {
                case btypeTip:
                    if (i >= m_ntips) okay = false;
                    break;
                default:
                    if (i < m_ntips) okay = false;
            }
            assert(okay);

            Branch_ptr parent1 = (*it)->Parent(0);
            Branch_ptr parent2 = (*it)->Parent(1);
            if (parent2 && !parent1) okay = false;
            if (parent1 && !parent1->ConnectedTo(*it)) okay = false;
            if (parent2 && !parent2->ConnectedTo(*it)) okay = false;

            Branch_ptr child1 = (*it)->Child(0);
            Branch_ptr child2 = (*it)->Child(1);
            if (child2 && !child1) okay = false;
            if (child1 && !child1->ConnectedTo(*it)) okay = false;
            if (child2 && !child2->ConnectedTo(*it)) okay = false;
            switch (event)
            {
                case btypeCoal:
                    if ((!(*it)->HasSamePartitionsAs(child1)) || (!(*it)->HasSamePartitionsAs(child2)))
                    {
                        okay = false;
                        assert(false);
                    }
                    break;
                case btypeMig:
                case btypeDivMig:
                case btypeDisease:
                case btypeEpoch:
                    if ((*it)->HasSamePartitionsAs(child1))
                    {
                        okay = false;
                        assert(false);
                    }
                    break;
                case btypeRec:
                    // Value returned by Branch::GetRecpoint() (FLAGLONG) is actually a code for NO RECOMBINATION.
                    if ((*it)->GetRecpoint() == FLAGLONG) okay = false;
                    if (!((*it)->PartitionsConsistentWith(child1))) okay = false;
                    DebugAssert2(((*it)->GetRecpoint() != FLAGLONG) && (*it)->PartitionsConsistentWith(child1),
                                 (*it)->GetRecpoint(),
                                 (*it)->PartitionsConsistentWith(child1));
#if 0 // Equivalent to DebugAssert2 above, in case it is removed later.
                    assert(okay);
#endif
                    break;
                case btypeBase:
                case btypeTip:
                    //Check anything here?
                    break;
            }
        }
    }

    assert(m_firsttip == find_if(m_branches.begin(), m_branches.end(), IsTipGroup()));
    assert(m_firstbody == find_if(m_branches.begin(), m_branches.end(), IsBodyGroup()));
    assert(m_firstcoal == find_if(m_branches.begin(), m_branches.end(), IsCoalGroup()));
    assert(okay);

    return okay;

} // IsValidTimeList

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

void TimeList::PrintNodeInfo(long nodenumber) const
{
    Branchconstiter br;
    for (br = BeginBranch(); br != EndBranch(); ++br)
    {
        long id = (*br)->GetID();
        if (id == nodenumber)
        {
            //cerr << "Node " << id << endl;
            (*br)->PrintInfo();
            return;
        }
    }

} // PrintNodeInfo

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

bool TimeList::RevalidateAllRanges() const
{
    Branchconstiter br;
    FC_Status fcstatus;

#if FINAL_COALESCENCE_ON
    for(br = FirstTip(); br != EndBranch(); br = NextTip(br))
    {
        fcstatus.Increment_FC_Counts((*br)->GetLiveSites());
    }
#endif

    int nbr = 0;
    for (br = BeginBranch(); br != EndBranch(); ++br)
    {
        // cerr << endl << "in TimeList::RevalidateAllRanges checking branch: " << nbr << ", ID: " << (*br)->GetID() << endl;
        // (*br)->GetRangePtr()->PrintInfo();
        if (!(*br)->RevalidateRange(fcstatus)) return false;
        ++nbr;
    }

    return true;

} // RevalidateAllRanges

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

void TimeList::CorrectAllRanges()
{
    Branchiter br;
    bool usefc = false;;
    FC_Status fcstatus;

#if FINAL_COALESCENCE_ON
    usefc = true;

    for(br = FirstTip(); br != EndBranch(); br = NextTip(br))
    {
        fcstatus.Increment_FC_Counts((*br)->GetLiveSites());
    }
#endif

    for (br = BeginBranch(); br != EndBranch(); ++br)
    {
        // A hack, makes the fcstatus right, we ignore the return value.
        (*br)->RevalidateRange(fcstatus);
        (*br)->UpdateBranchRange(fcstatus.Coalesced_Sites(), usefc);
    }

} // CorrectAllRanges

//____________________________________________________________________________________
