//
// ********************************************************************
// * License and Disclaimer                                           *
// *                                                                  *
// * The  Geant4 software  is  copyright of the Copyright Holders  of *
// * the Geant4 Collaboration.  It is provided  under  the terms  and *
// * conditions of the Geant4 Software License,  included in the file *
// * LICENSE and available at  http://cern.ch/geant4/license .  These *
// * include a list of copyright holders.                             *
// *                                                                  *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work  make  any representation or  warranty, express or implied, *
// * regarding  this  software system or assume any liability for its *
// * use.  Please see the license in the file  LICENSE  and URL above *
// * for the full disclaimer and the limitation of liability.         *
// *                                                                  *
// * This  code  implementation is the result of  the  scientific and *
// * technical work of the GEANT4 collaboration.                      *
// * By using,  copying,  modifying or  distributing the software (or *
// * any work based  on the software)  you  agree  to acknowledge its *
// * use  in  resulting  scientific  publications,  and indicate your *
// * acceptance of all terms of the Geant4 Software license.          *
// ********************************************************************
//

#include "globals.hh"
#include "G4PhysicalConstants.hh"
#include "G4SystemOfUnits.hh"
#include "G4Proton.hh"
#include "G4Neutron.hh"
#include "G4LorentzRotation.hh"
#include "G4BinaryCascade.hh"
#include "G4KineticTrackVector.hh"
#include "G4DecayKineticTracks.hh"
#include "G4ReactionProductVector.hh"
#include "G4Track.hh"
#include "G4V3DNucleus.hh"
#include "G4Fancy3DNucleus.hh"
#include "G4Scatterer.hh"
#include "G4MesonAbsorption.hh"
#include "G4ping.hh"
#include "G4Delete.hh"

#include "G4CollisionManager.hh"
#include "G4Absorber.hh"

#include "G4CollisionInitialState.hh"
#include "G4ListOfCollisions.hh"
#include "G4Fragment.hh"
#include "G4RKPropagation.hh"

#include "G4NuclearShellModelDensity.hh"
#include "G4NuclearFermiDensity.hh"
#include "G4FermiMomentum.hh"

#include "G4PreCompoundModel.hh"
#include "G4ExcitationHandler.hh"
#include "G4HadronicInteractionRegistry.hh"

#include "G4FermiPhaseSpaceDecay.hh"

#include "G4PreCompoundModel.hh"
#include "G4HadronicParameters.hh"

#include <algorithm>
#include "G4ShortLivedConstructor.hh"
#include <typeinfo>

#include "G4PhysicsModelCatalog.hh"

//   turn on general debugging info, and consistency checks

//#define debug_G4BinaryCascade 1

//  more detailed debugging -- deprecated
//#define debug_H1_BinaryCascade 1

//  specific debugging info per method or functionality
//#define debug_BIC_ApplyCollision 1
//#define debug_BIC_CheckPauli 1
//#define debug_BIC_CorrectFinalPandE 1
//#define debug_BIC_Propagate 1
//#define debug_BIC_Propagate_Excitation 1
//#define debug_BIC_Propagate_Collisions 1
//#define debug_BIC_Propagate_finals 1
//#define debug_BIC_DoTimeStep 1
//#define debug_BIC_CorrectBarionsOnBoundary 1
//#define debug_BIC_GetExcitationEnergy 1
//#define debug_BIC_DeexcitationProducts 1
//#define debug_BIC_FinalNucleusMomentum 1
//#define debug_BIC_Final4Momentum 1
//#define debug_BIC_FillVoidnucleus 1
//#define debug_BIC_FindFragments 1
//#define debug_BIC_BuildTargetList 1
//#define debug_BIC_FindCollision 1
//#define debug_BIC_return 1

//-------
//#if defined(debug_G4BinaryCascade)
#if 0
  #define _CheckChargeAndBaryonNumber_(val) CheckChargeAndBaryonNumber(val)
  //#define debugCheckChargeAndBaryonNumberverbose 1
#else
  #define _CheckChargeAndBaryonNumber_(val)
#endif
//#if defined(debug_G4BinaryCascade)
#if 0
  #define _DebugEpConservation(val)  DebugEpConservation(val)
  //#define debugCheckChargeAndBaryonNumberverbose 1
#else
  #define _DebugEpConservation(val)
#endif

G4int G4BinaryCascade::theBIC_ID = -1;

//
//  C O N S T R U C T O R S   A N D   D E S T R U C T O R S
//
G4BinaryCascade::G4BinaryCascade(G4VPreCompoundModel* ptr) :
G4VIntraNuclearTransportModel("Binary Cascade", ptr)
{
    // initialise the resonance sector
    G4ShortLivedConstructor ShortLived;
    ShortLived.ConstructParticle();

    theCollisionMgr = new G4CollisionManager;
    theDecay=new G4BCDecay;
    theImR.push_back(theDecay);
    theLateParticle= new G4BCLateParticle;
    G4MesonAbsorption * aAb=new G4MesonAbsorption;
    theImR.push_back(aAb);
    G4Scatterer * aSc=new G4Scatterer;
    theH1Scatterer = new G4Scatterer;
    theImR.push_back(aSc);

    thePropagator = new G4RKPropagation;
    theCurrentTime = 0.;
    theBCminP = 45*MeV;
    theCutOnP = 90*MeV;
    theCutOnPAbsorb= 0*MeV;   // No Absorption of slow Mesons, other than above G4MesonAbsorption

    // reuse existing pre-compound model
    if(!ptr) {
      G4HadronicInteraction* p =
	G4HadronicInteractionRegistry::Instance()->FindModel("PRECO");
      G4VPreCompoundModel* pre = static_cast<G4VPreCompoundModel*>(p);
      if(!pre) { pre = new G4PreCompoundModel(); }
      SetDeExcitation(pre);
    }
    theExcitationHandler = GetDeExcitation()->GetExcitationHandler();
    SetMinEnergy(0.0*GeV);
    SetMaxEnergy(10.1*GeV);
    //PrintWelcomeMessage();
    thePrimaryEscape = true;
    thePrimaryType = 0;

    SetEnergyMomentumCheckLevels(1.0*perCent, 1.0*MeV);

    // init data members
    currentA=currentZ=0;
    lateA=lateZ=0;
    initialA=initialZ=0;
    projectileA=projectileZ=0;
    currentInitialEnergy=initial_nuclear_mass=0.;
    massInNucleus=0.;
    theOuterRadius=0.;
    theBIC_ID = G4PhysicsModelCatalog::GetModelID("model_G4BinaryCascade");
    fBCDEBUG = G4HadronicParameters::Instance()->GetBinaryDebug();
}

G4BinaryCascade::~G4BinaryCascade()
{
    ClearAndDestroy(&theTargetList);
    ClearAndDestroy(&theSecondaryList);
    ClearAndDestroy(&theCapturedList);
    delete thePropagator;
    delete theCollisionMgr;
    for(auto & ptr : theImR) { delete ptr; }
    theImR.clear();
    delete theLateParticle;
    delete theH1Scatterer;
}

void G4BinaryCascade::ModelDescription(std::ostream& outFile) const
{
    outFile << "G4BinaryCascade is an intra-nuclear cascade model in which\n"
            << "an incident hadron collides with a nucleon, forming two\n"
            << "final-state particles, one or both of which may be resonances.\n"
            << "The resonances then decay hadronically and the decay products\n"
            << "are then propagated through the nuclear potential along curved\n"
            << "trajectories until they re-interact or leave the nucleus.\n"
            << "This model is valid for incident pions up to 1.5 GeV and\n"
            << "nucleons up to 10 GeV.\n"
            << "The remaining excited nucleus is handed on to ";
            if (theDeExcitation)                // pre-compound
            {
              outFile << theDeExcitation->GetModelName() << " : \n ";
              theDeExcitation->DeExciteModelDescription(outFile);
            }
            else if (theExcitationHandler)    // de-excitation
            {
               outFile << "G4ExcitationHandler";    //theExcitationHandler->GetModelName();
               theExcitationHandler->ModelDescription(outFile);
            }
            else
            {
               outFile << "void.\n";
            }
    outFile<< " \n";
}
void G4BinaryCascade::PropagateModelDescription(std::ostream& outFile) const
{
    outFile << "G4BinaryCascade propagtes secondaries produced by a high\n"
            << "energy model through the wounded nucleus.\n"
            << "Secondaries are followed after the formation time and if\n"
            << "within the nucleus are propagated through the nuclear\n"
            << "potential along curved trajectories until they interact\n"
            << "with a nucleon, decay, or leave the nucleus.\n"
            << "An interaction of a secondary with a nucleon produces two\n"
            << "final-state particles, one or both of which may be resonances.\n"
            << "Resonances decay hadronically and the decay products\n"
            << "are in turn propagated through the nuclear potential along curved\n"
            << "trajectories until they re-interact or leave the nucleus.\n"
            << "This model is valid for pions up to 1.5 GeV and\n"
            << "nucleons up to about 3.5 GeV.\n"
            << "The remaining excited nucleus is handed on to ";
    if (theDeExcitation)                // pre-compound
    {
      outFile << theDeExcitation->GetModelName() << " : \n ";
      theDeExcitation->DeExciteModelDescription(outFile);
    }
    else if (theExcitationHandler)    // de-excitation
    {
       outFile << "G4ExcitationHandler";    //theExcitationHandler->GetModelName();
       theExcitationHandler->ModelDescription(outFile);
    }
    else
    {
       outFile << "void.\n";
    }
outFile<< " \n";
}

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

//
//      I M P L E M E N T A T I O N
//


//----------------------------------------------------------------------------
G4HadFinalState * G4BinaryCascade::ApplyYourself(const G4HadProjectile & aTrack,
        G4Nucleus & aNucleus)
//----------------------------------------------------------------------------
{
    if(fBCDEBUG) G4cerr << " ######### Binary Cascade Reaction starts ######### "<< G4endl;

    G4LorentzVector initial4Momentum = aTrack.Get4Momentum();
    const G4ParticleDefinition * definition = aTrack.GetDefinition();

    if(initial4Momentum.e()-initial4Momentum.m()<theBCminP &&
            ( definition==G4Neutron::NeutronDefinition() || definition==G4Proton::ProtonDefinition() ) )
    {
        return theDeExcitation->ApplyYourself(aTrack, aNucleus);
    }

    theParticleChange.Clear();
    // initialize the G4V3DNucleus from G4Nucleus
    the3DNucleus = new G4Fancy3DNucleus;

    // Build a KineticTrackVector with the G4Track
    G4KineticTrackVector * secondaries;// = new G4KineticTrackVector;
    G4ThreeVector initialPosition(0., 0., 0.); // will be set later

    if(!fBCDEBUG)
    {
        if(definition!=G4Neutron::NeutronDefinition() &&
                definition!=G4Proton::ProtonDefinition() &&
                definition!=G4PionPlus::PionPlusDefinition() &&
                definition!=G4PionMinus::PionMinusDefinition() )
        {
            G4cerr << "You are trying to use G4BinaryCascade with " <<definition->GetParticleName()<<" as projectile."<<G4endl;
            G4cerr << "G4BinaryCascade should not be used for projectiles other than nucleons or pions."<<G4endl;
            G4cerr << "If you want to continue, please switch on the developer environment: "<<G4endl;
            G4cerr << "setenv I_Am_G4BinaryCascade_Developer 1 "<<G4endl<<G4endl;
            throw G4HadronicException(__FILE__, __LINE__, "G4BinaryCascade - used for unvalid particle type - Fatal");
        }
    }

    // keep primary
    thePrimaryType = definition;
    thePrimaryEscape = false;

    G4double timePrimary=aTrack.GetGlobalTime();

    // try until an interaction will happen
    G4ReactionProductVector * products = nullptr;
    G4int interactionCounter = 0,collisionLoopMaxCount;
    do
    {
        // reset status that could be changed in previous loop event
        theCollisionMgr->ClearAndDestroy();

        if(products != nullptr)
        {  // free memory from previous loop event
            ClearAndDestroy(products);
            delete products;
        }

        G4int massNumber=aNucleus.GetA_asInt();
        the3DNucleus->Init(massNumber, aNucleus.GetZ_asInt());
        thePropagator->Init(the3DNucleus);
        G4KineticTrack * kt;
		  collisionLoopMaxCount = 200;
        do                  // sample impact parameter until collisions are found
        {
            theCurrentTime=0;
            G4double radius = the3DNucleus->GetOuterRadius()+3*fermi;
            initialPosition=GetSpherePoint(1.1*radius, initial4Momentum);  // get random position
            kt = new G4KineticTrack(definition, 0., initialPosition, initial4Momentum);
            kt->SetState(G4KineticTrack::outside);
            // secondaries has been cleared by Propagate() in the previous loop event
            secondaries= new G4KineticTrackVector;
            secondaries->push_back(kt);
            if(massNumber > 1) // 1H1 is special case
            {
                products = Propagate(secondaries, the3DNucleus);
            } else {
                products = Propagate1H1(secondaries,the3DNucleus);
            }
				    // until we FIND a collision ... or give up
        } while(! products && --collisionLoopMaxCount>0);   /* Loop checking, 31.08.2015, G.Folger */

        if(++interactionCounter>99) break;
		    // ...until we find an ALLOWED collision ... or give up
    } while(products && products->size() == 0);   /* Loop checking, 31.08.2015, G.Folger */

    if(products && products->size()>0)
    {
        //  G4cout << "BIC Applyyourself: number of products " << products->size() << G4endl;

        // Fill the G4ParticleChange * with products
        theParticleChange.SetStatusChange(stopAndKill);
        G4ReactionProductVector::iterator iter;

        for(iter = products->begin(); iter != products->end(); ++iter)
        {
        	G4DynamicParticle * aNewDP =
                    new G4DynamicParticle((*iter)->GetDefinition(),
                            (*iter)->GetTotalEnergy(),
                            (*iter)->GetMomentum());
        	G4HadSecondary aNew = G4HadSecondary(aNewDP);
            G4double time=(*iter)->GetFormationTime();
            if(time < 0.0) { time = 0.0; }
            aNew.SetTime(timePrimary + time);
            aNew.SetCreatorModelID((*iter)->GetCreatorModelID());
            aNew.SetParentResonanceDef((*iter)->GetParentResonanceDef());
            aNew.SetParentResonanceID((*iter)->GetParentResonanceID());	    
            theParticleChange.AddSecondary(aNew);
        }

         //DebugFinalEpConservation(aTrack, products);


    } else {  // no interaction, return primary
        if(fBCDEBUG) G4cerr << " ######### Binary Cascade Reaction void, return initial state ######### "<< G4endl;
        theParticleChange.SetStatusChange(isAlive);
        theParticleChange.SetEnergyChange(aTrack.GetKineticEnergy());
        theParticleChange.SetMomentumChange(aTrack.Get4Momentum().vect().unit());
    }

    if ( products ) 
	 {
	    ClearAndDestroy(products);
       delete products;
    }
	 
    delete the3DNucleus;
    the3DNucleus = nullptr;

    if(fBCDEBUG) G4cerr << " ######### Binary Cascade Reaction ends ######### "<< G4endl;

    return &theParticleChange;
}
//----------------------------------------------------------------------------
G4ReactionProductVector * G4BinaryCascade::Propagate(
        G4KineticTrackVector * secondaries, G4V3DNucleus * aNucleus)
//----------------------------------------------------------------------------
{
    G4ping debug("debug_G4BinaryCascade");
#ifdef debug_BIC_Propagate
    G4cout << "G4BinaryCascade Propagate starting -------------------------------------------------------" <<G4endl;
#endif

    the3DNucleus=aNucleus;
    G4ReactionProductVector * products = new G4ReactionProductVector;
    theOuterRadius = the3DNucleus->GetOuterRadius();
    theCurrentTime=0;
    theProjectile4Momentum=G4LorentzVector(0,0,0,0);
    theMomentumTransfer=G4ThreeVector(0,0,0);
    // build theSecondaryList, theProjectileList and theCapturedList
    ClearAndDestroy(&theCapturedList);
    ClearAndDestroy(&theSecondaryList);
    theSecondaryList.clear();
    ClearAndDestroy(&theFinalState);
    std::vector<G4KineticTrack *>::iterator iter;
    theCollisionMgr->ClearAndDestroy();

    theCutOnP=90*MeV;
    if(the3DNucleus->GetMass()>30) theCutOnP = 70*MeV;
    if(the3DNucleus->GetMass()>60) theCutOnP = 50*MeV;
    if(the3DNucleus->GetMass()>120) theCutOnP = 45*MeV;


    BuildTargetList();

#ifdef debug_BIC_GetExcitationEnergy
    G4cout << "ExcitationEnergy0 " << GetExcitationEnergy() << G4endl;
#endif

    thePropagator->Init(the3DNucleus);

    G4bool success = BuildLateParticleCollisions(secondaries);
    if (! success )   // fails if no excitation energy left....
    {
       products=HighEnergyModelFSProducts(products, secondaries);
       ClearAndDestroy(secondaries);
       delete secondaries;

#ifdef debug_G4BinaryCascade
       G4cout << "G4BinaryCascade::Propagate: warning - high energy model failed energy conservation, returning unchanged high energy final state" << G4endl;
#endif

       return products;
    }
    // check baryon and charge ...

    _CheckChargeAndBaryonNumber_("lateparticles");
    _DebugEpConservation(" be4 findcollisions");

    // if called stand alone find first collisions
    FindCollisions(&theSecondaryList);


    if(theCollisionMgr->Entries() == 0 )      //late particles ALWAYS create Entries
    {
        //G4cout << " no collsions -> return 0" << G4endl;
        delete products;
#ifdef debug_BIC_return
        G4cout << "return @ begin2,  no collisions "<< G4endl;
#endif
        return nullptr;
    }

    // end of initialization: do the job now
    // loop until there are no more collisions


    G4bool haveProducts = false;
#ifdef debug_BIC_Propagate_Collisions
    G4int collisionCount=0;
#endif
    G4int collisionLoopMaxCount=1000000;
    while(theCollisionMgr->Entries() > 0 && currentZ && --collisionLoopMaxCount>0)  /* Loop checking, 31.08.2015, G.Folger */  
    {
      if(Absorb()) {  // absorb secondaries, pions only
            haveProducts = true;
      }
      if(Capture()) { // capture secondaries, nucleons only
            haveProducts = true;
        }

        // propagate to the next collision if any (collisions could have been deleted
        // by previous absorption or capture)
        if(theCollisionMgr->Entries() > 0)
        {
            G4CollisionInitialState *
            nextCollision = theCollisionMgr->GetNextCollision();
#ifdef debug_BIC_Propagate_Collisions
            G4cout << " NextCollision  * , Time, curtime = " << nextCollision << " "
                    <<nextCollision->GetCollisionTime()<< " " <<
                    theCurrentTime<< G4endl;
#endif
            if (!DoTimeStep(nextCollision->GetCollisionTime()-theCurrentTime) )
            {
                // Check if nextCollision is still valid, ie. particle did not leave nucleus
                if (theCollisionMgr->GetNextCollision() != nextCollision )
                {
                    nextCollision = nullptr;
                }
            }
           //_DebugEpConservation("Stepped");

            if( nextCollision )
            {
                if (ApplyCollision(nextCollision))
                {
                    //G4cerr << "ApplyCollision success " << G4endl;
                    haveProducts = true;
#ifdef debug_BIC_Propagate_Collisions
                    collisionCount++;
#endif

                } else {
                    //G4cerr << "ApplyCollision failure " << G4endl;
                    theCollisionMgr->RemoveCollision(nextCollision);
                }
            }
        }
    }

    //--------- end of on Collisions
    //G4cout << "currentZ @ end loop " << currentZ << G4endl;
    G4int nProtons(0);
    for(iter = theTargetList.begin(); iter != theTargetList.end(); ++iter)
    {
    	if ( (*iter)->GetDefinition() == G4Proton::Proton() ) ++nProtons;
    }
    if ( ! theTargetList.size() || ! nProtons ){
        // nucleus completely destroyed, fill in ReactionProductVector
       products = FillVoidNucleusProducts(products);
#ifdef debug_BIC_return
        G4cout << "return @ Z=0 after collision loop "<< G4endl;
        PrintKTVector(&theSecondaryList,std::string(" theSecondaryList"));
        G4cout << "theTargetList size: " << theTargetList.size() << G4endl;
        PrintKTVector(&theTargetList,std::string(" theTargetList"));
        PrintKTVector(&theCapturedList,std::string(" theCapturedList"));

        G4cout << " ExcitE be4 Correct : " <<GetExcitationEnergy() << G4endl;
        G4cout << " Mom Transfered to nucleus : " << theMomentumTransfer << " " << theMomentumTransfer.mag() << G4endl;
        PrintKTVector(&theFinalState,std::string(" FinalState uncorrected"));
        G4cout << "returned products: " << products->size() << G4endl;
        _CheckChargeAndBaryonNumber_("destroyed Nucleus");
        _DebugEpConservation("destroyed Nucleus");
#endif

        return products;
    }

    // No more collisions: absorb, capture and propagate the secondaries out of the nucleus
    if(Absorb()) {
        haveProducts = true;
        // G4cout << "Absorb sucess " << G4endl;
    }

    if(Capture()) {
        haveProducts = true;
        // G4cout << "Capture sucess " << G4endl;
    }

    if(!haveProducts)  // no collisions happened. Return an empty vector.
    {
#ifdef debug_BIC_return
        G4cout << "return 3, no products "<< G4endl;
#endif
        return products;
    }


#ifdef debug_BIC_Propagate
    G4cout << " Momentum transfer to Nucleus " << theMomentumTransfer << " " << theMomentumTransfer.mag() << G4endl;
    G4cout << "  Stepping particles out...... " << G4endl;
#endif

    StepParticlesOut();
    _DebugEpConservation("stepped out");


    if ( theSecondaryList.size() > 0 )
    {
#ifdef debug_G4BinaryCascade
        G4cerr << "G4BinaryCascade: Warning, have active particles at end" << G4endl;
        PrintKTVector(&theSecondaryList, "active particles @ end  added to theFinalState");
#endif
        //  add left secondaries to FinalSate
        for ( iter =theSecondaryList.begin(); iter != theSecondaryList.end(); ++iter)
        {
            theFinalState.push_back(*iter);
        }
        theSecondaryList.clear();

    }
    while ( theCollisionMgr->Entries() > 0 )                /* Loop checking, 31.08.2015, G.Folger */
    {
#ifdef debug_G4BinaryCascade
        G4cerr << " Warning: remove left over collision(s) " << G4endl;
#endif
        theCollisionMgr->RemoveCollision(theCollisionMgr->GetNextCollision());
    }

#ifdef debug_BIC_Propagate_Excitation

    PrintKTVector(&theSecondaryList,std::string(" theSecondaryList"));
    G4cout << "theTargetList size: " << theTargetList.size() << G4endl;
    //  PrintKTVector(&theTargetList,std::string(" theTargetList"));
    PrintKTVector(&theCapturedList,std::string(" theCapturedList"));

    G4cout << " ExcitE be4 Correct : " <<GetExcitationEnergy() << G4endl;
    G4cout << " Mom Transfered to nucleus : " << theMomentumTransfer << " " << theMomentumTransfer.mag() << G4endl;
    PrintKTVector(&theFinalState,std::string(" FinalState uncorrected"));
#endif

    //


    G4double ExcitationEnergy=GetExcitationEnergy();

#ifdef debug_BIC_Propagate_finals
    PrintKTVector(&theFinalState,std::string(" FinalState be4 corr"));
    G4cout << " Excitation Energy prefinal,  #collisions:, out, captured  "
            << ExcitationEnergy << " "
            << collisionCount << " "
            << theFinalState.size() << " "
            << theCapturedList.size()<<G4endl;
#endif

    if (ExcitationEnergy < 0 )
    {
        G4int maxtry=5, ntry=0;
        do {
            CorrectFinalPandE();
            ExcitationEnergy=GetExcitationEnergy();
        } while ( ++ntry < maxtry && ExcitationEnergy < 0 );       /* Loop checking, 31.08.2015, G.Folger */
    }
    _DebugEpConservation("corrected");

#ifdef debug_BIC_Propagate_finals
    PrintKTVector(&theFinalState,std::string(" FinalState corrected"));
    G4cout << " Excitation Energy final,  #collisions:, out, captured  "
            << ExcitationEnergy << " "
            << collisionCount << " "
            << theFinalState.size() << " "
            << theCapturedList.size()<<G4endl;
#endif


    if ( ExcitationEnergy < 0. )
    {
            #ifdef debug_G4BinaryCascade
              	  G4cerr << "G4BinaryCascade-Warning: negative excitation energy ";
              	  G4cerr <<ExcitationEnergy<<G4endl;
             	   PrintKTVector(&theFinalState,std::string("FinalState"));
             	   PrintKTVector(&theCapturedList,std::string("captured"));
             	  G4cout << "negative ExE:Final 4Momentum .mag: " << GetFinal4Momentum()
             	          << " "<< GetFinal4Momentum().mag()<< G4endl
             	          << "negative ExE:FinalNucleusMom  .mag: " << GetFinalNucleusMomentum()
             		  << " "<< GetFinalNucleusMomentum().mag()<< G4endl;
            #endif
            #ifdef debug_BIC_return
                    G4cout << "  negative Excitation E return empty products " << products << G4endl;
                    G4cout << "return 4, excit < 0 "<< G4endl;
            #endif

        ClearAndDestroy(products);
        return products;   // return empty products- FixMe
    }

    G4ReactionProductVector * precompoundProducts=DeExcite();


    G4DecayKineticTracks decay(&theFinalState);
    _DebugEpConservation("decayed");

    products= ProductsAddFinalState(products, theFinalState);

    products= ProductsAddPrecompound(products, precompoundProducts);

//    products=ProductsAddFakeGamma(products);


    thePrimaryEscape = true;

    #ifdef debug_BIC_return
    G4cout << "BIC: return @end, all ok "<< G4endl;
    //G4cout << "  return products " << products << G4endl;
    #endif

    return products;
}

//----------------------------------------------------------------------------
G4double G4BinaryCascade::GetExcitationEnergy()
//----------------------------------------------------------------------------
{

    // get A and Z for the residual nucleus
#if defined(debug_G4BinaryCascade) || defined(debug_BIC_GetExcitationEnergy)
    G4int finalA = theTargetList.size()+theCapturedList.size();
    G4int finalZ = GetTotalCharge(theTargetList)+GetTotalCharge(theCapturedList);
    if ( (currentA - finalA) != 0 || (currentZ - finalZ) != 0 )
    {
        G4cerr << "G4BIC:GetExcitationEnergy(): Nucleon counting error current/final{A,Z} "
                << "("<< currentA << "," << finalA << ") ("<< currentZ << "," << finalZ << ")" << G4endl;
    }

#endif

    G4double excitationE(0);
    G4double nucleusMass(0);
    if(currentZ>.5)
    {
        nucleusMass = GetIonMass(currentZ,currentA);
    }
    else if (currentZ==0 )
    {
        if(currentA == 1) {nucleusMass = G4Neutron::Neutron()->GetPDGMass();}
        else              {nucleusMass = GetFinalNucleusMomentum().mag() - 3.*MeV*currentA;}
    }
    else
    {
#ifdef debug_G4BinaryCascade
        G4cout << "G4BinaryCascade::GetExcitationEnergy(): Warning - invalid nucleus (A,Z)=("
                << currentA << "," << currentZ << ")" << G4endl;
#endif
        return 0;
    }

#ifdef debug_BIC_GetExcitationEnergy
    G4ping debug("debug_ExcitationEnergy");
    debug.push_back("====> current A, Z");
    debug.push_back(currentZ);
    debug.push_back(currentA);
    debug.push_back("====> final A, Z");
    debug.push_back(finalZ);
    debug.push_back(finalA);
    debug.push_back(nucleusMass);
    debug.push_back(GetFinalNucleusMomentum().mag());
    debug.dump();
    //  PrintKTVector(&theTargetList, std::string(" current target list info"));
    //PrintKTVector(&theCapturedList, std::string(" current captured list info"));
#endif

    excitationE = GetFinalNucleusMomentum().mag() - nucleusMass;

    //G4double exE2 = GetFinal4Momentum().mag() - nucleusMass;

    //G4cout << "old/new excitE " << excitationE << " / "<< exE2 << G4endl;

#ifdef debug_BIC_GetExcitationEnergy
    // ------ debug
    if ( excitationE < 0 )
    {
        G4cout << "negative ExE final Ion mass " <<nucleusMass<< G4endl;
        G4LorentzVector Nucl_mom=GetFinalNucleusMomentum();
        if(finalZ>.5) G4cout << " Final nuclmom/mass " << Nucl_mom << " " << Nucl_mom.mag()
		    		           << " (A,Z)=("<< finalA <<","<<finalZ <<")"
		    		           << " mass " << nucleusMass << " "
		    		           << " excitE " << excitationE << G4endl;


        G4int A = the3DNucleus->GetMassNumber();
        G4int Z = the3DNucleus->GetCharge();
        G4double initialExc(0);
        if(Z>.5)
        {
            initialExc = theInitial4Mom.mag()- GetIonMass(Z, A);
            G4cout << "GetExcitationEnergy: Initial nucleus A Z " << A << " " << Z << " " << initialExc << G4endl;
        }
    }

#endif

    return excitationE;
}


//----------------------------------------------------------------------------
//
//       P R I V A T E   M E M B E R   F U N C T I O N S
//
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
void G4BinaryCascade::BuildTargetList()
//----------------------------------------------------------------------------
{

    if(!the3DNucleus->StartLoop())
    {
        //    G4cerr << "G4BinaryCascade::BuildTargetList(): StartLoop() error!"
        //	   << G4endl;
        return;
    }

    ClearAndDestroy(&theTargetList);  // clear theTargetList before rebuilding

    G4Nucleon * nucleon;
    const G4ParticleDefinition * definition;
    G4ThreeVector pos;
    G4LorentzVector mom;
    // if there are nucleon hit by higher energy models, then SUM(momenta) != 0
    initialZ=the3DNucleus->GetCharge();
    initialA=the3DNucleus->GetMassNumber();
    initial_nuclear_mass=GetIonMass(initialZ,initialA);
    theInitial4Mom = G4LorentzVector(0,0,0,initial_nuclear_mass);
    currentA=0;
    currentZ=0;
    while((nucleon = the3DNucleus->GetNextNucleon()) != nullptr)       /* Loop checking, 31.08.2015, G.Folger */
    {
        // check if nucleon is hit by higher energy model.
        if ( ! nucleon->AreYouHit() )
        {
            definition = nucleon->GetDefinition();
            pos = nucleon->GetPosition();
            mom = nucleon->GetMomentum();
            //    G4cout << "Nucleus " << pos.mag()/fermi << " " << mom.e() << G4endl;
            //theInitial4Mom += mom;
            //        the potential inside the nucleus is taken into account, and nucleons are on mass shell.
            mom.setE( std::sqrt( mom.vect().mag2() + sqr(definition->GetPDGMass()) ) );
            G4KineticTrack * kt = new G4KineticTrack(definition, 0., pos, mom);
            kt->SetState(G4KineticTrack::inside);
            kt->SetNucleon(nucleon);
            theTargetList.push_back(kt);
            ++currentA;
            if (definition->GetPDGCharge() > .5 ) ++currentZ;
        }

#ifdef debug_BIC_BuildTargetList
        else { G4cout << "nucleon is hit" << nucleon << G4endl;}
#endif
    }
    massInNucleus = 0;
    if(currentZ>.5)
    {
        massInNucleus = GetIonMass(currentZ,currentA);
    } else if (currentZ==0 && currentA>=1 )
    {
        massInNucleus = currentA * G4Neutron::Neutron()->GetPDGMass();
    } else
    {
        G4cerr << "G4BinaryCascade::BuildTargetList(): Fatal Error - invalid nucleus (A,Z)=("
                << currentA << "," << currentZ << ")" << G4endl;
        throw G4HadronicException(__FILE__, __LINE__, "G4BinaryCasacde::BuildTargetList()");
    }
    currentInitialEnergy=	theInitial4Mom.e() + theProjectile4Momentum.e();

#ifdef debug_BIC_BuildTargetList
    G4cout << "G4BinaryCascade::BuildTargetList():  nucleus (A,Z)=("
            << currentA << "," << currentZ << ") mass: " << massInNucleus <<
            ", theInitial4Mom " << theInitial4Mom <<
            ", currentInitialEnergy " << currentInitialEnergy << G4endl;
#endif

}

//----------------------------------------------------------------------------
G4bool  G4BinaryCascade::BuildLateParticleCollisions(G4KineticTrackVector * secondaries)
//----------------------------------------------------------------------------
{
   G4bool success(false);
   std::vector<G4KineticTrack *>::iterator iter;

   lateA=lateZ=0;
   projectileA=projectileZ=0;

   G4double StartingTime=DBL_MAX;        // Search for minimal formation time
   for(iter = secondaries->begin(); iter != secondaries->end(); ++iter)
   {
      if((*iter)->GetFormationTime() < StartingTime)
         StartingTime = (*iter)->GetFormationTime();
   }

   //PrintKTVector(secondaries, "initial late particles ");
   G4LorentzVector lateParticles4Momentum(0,0,0,0);
   for(iter = secondaries->begin(); iter != secondaries->end(); ++iter)
   {
      //  G4cout << " Formation time : " << (*iter)->GetDefinition()->GetParticleName() << " "
      //   << (*iter)->GetFormationTime() << G4endl;
      G4double FormTime = (*iter)->GetFormationTime() - StartingTime;
      (*iter)->SetFormationTime(FormTime);
      if( (*iter)->GetState() == G4KineticTrack::undefined  )   // particles from high energy generator
      {
         FindLateParticleCollision(*iter);
         lateParticles4Momentum += (*iter)->GetTrackingMomentum();
         lateA += (*iter)->GetDefinition()->GetBaryonNumber();
         lateZ += G4lrint((*iter)->GetDefinition()->GetPDGCharge()/eplus);
         //PrintKTVector(*iter, "late particle ");
      } else
      {
         theSecondaryList.push_back(*iter);
         //PrintKTVector(*iter, "incoming particle ");
         theProjectile4Momentum += (*iter)->GetTrackingMomentum();
         projectileA += (*iter)->GetDefinition()->GetBaryonNumber();
         projectileZ += G4lrint((*iter)->GetDefinition()->GetPDGCharge()/eplus);
#ifdef debug_BIC_Propagate
         G4cout << " Adding initial secondary " << *iter
               << " time" << (*iter)->GetFormationTime()
               << ", state " << (*iter)->GetState() << G4endl;
#endif
      }
   }
   //theCollisionMgr->Print();
   const G4HadProjectile * primary = GetPrimaryProjectile();  // check for primary from TheoHE model

   if (primary){
      G4LorentzVector mom=primary->Get4Momentum();
      theProjectile4Momentum += mom;
      projectileA = primary->GetDefinition()->GetBaryonNumber();
      projectileZ = G4lrint(primary->GetDefinition()->GetPDGCharge()/eplus);
      // now check if "excitation" energy left by TheoHE model
      G4double excitation= theProjectile4Momentum.e() + initial_nuclear_mass - lateParticles4Momentum.e() - massInNucleus;
#ifdef debug_BIC_GetExcitationEnergy
      G4cout << "BIC: Proj.e, nucl initial, nucl final, lateParticles"
            << theProjectile4Momentum << ",  "
            << initial_nuclear_mass<< ",  " << massInNucleus << ",  "
            << lateParticles4Momentum << G4endl;
      G4cout << "BIC: Proj.e / initial excitation: " << theProjectile4Momentum.e() << " / " << excitation << G4endl;
#endif
      success = excitation > 0;
#ifdef debug_G4BinaryCascade
      if ( ! success ) {
         G4cout << "G4BinaryCascade::BuildLateParticleCollisions(): Proj.e / initial excitation: " << theProjectile4Momentum.e() << " / " << excitation << G4endl;
         //PrintKTVector(secondaries);
      }
#endif
   } else {
      // no primary from HE model -> cascade
      success=true;
   }

   if (success) {
      secondaries->clear(); // Don't leave "G4KineticTrack *"s in two vectors
      delete secondaries;
   }
   return success;
}

//----------------------------------------------------------------------------
G4ReactionProductVector *  G4BinaryCascade::DeExcite()
//----------------------------------------------------------------------------
{
   // find a fragment and call the precompound model.
   G4Fragment * fragment = nullptr;
   G4ReactionProductVector * precompoundProducts = nullptr;

   G4LorentzVector pFragment(0);
   // G4cout << " final4mon " << GetFinal4Momentum() /MeV << G4endl;

   fragment = FindFragments();

   if(fragment)
   {
      if(fragment->GetA_asInt() >1)
      {
         pFragment=fragment->GetMomentum();
         // G4cout << " going to preco with fragment 4 mom " << pFragment << G4endl;
         if (theDeExcitation)                // pre-compound
         {
            precompoundProducts= theDeExcitation->DeExcite(*fragment);
         }
         else if (theExcitationHandler)    // de-excitation
         {
            precompoundProducts=theExcitationHandler->BreakItUp(*fragment);
         }

      } else
      {                                   // fragment->GetA_asInt() <= 1, so a single proton, as a fragment must have Z>0
         if (theTargetList.size() + theCapturedList.size() > 1 ) {
            throw G4HadronicException(__FILE__, __LINE__, "G4BinaryCasacde:: Invalid Fragment");
         }

         std::vector<G4KineticTrack *>::iterator i;
         if ( theTargetList.size() == 1 )  {i=theTargetList.begin();}
         if ( theCapturedList.size() == 1 ) {i=theCapturedList.begin();}
         G4ReactionProduct * aNew = new G4ReactionProduct((*i)->GetDefinition());
         aNew->SetTotalEnergy((*i)->GetDefinition()->GetPDGMass());
         aNew->SetCreatorModelID(theBIC_ID);
	 aNew->SetParentResonanceDef((*i)->GetParentResonanceDef());
	 aNew->SetParentResonanceID((*i)->GetParentResonanceID());	 
         aNew->SetMomentum(G4ThreeVector(0));// see boost for preCompoundProducts below..
         precompoundProducts = new G4ReactionProductVector();
         precompoundProducts->push_back(aNew);
      }                            // End of fragment->GetA() < 1.5
      delete fragment;
      fragment=nullptr;

   } else                            // End of if(fragment)
   {                                 // No fragment, can be neutrons only

      precompoundProducts = DecayVoidNucleus();
   }
   #ifdef debug_BIC_DeexcitationProducts

       G4LorentzVector fragment_momentum=GetFinalNucleusMomentum();
       G4LorentzVector Preco_momentum;
       if ( precompoundProducts )
       {
          std::vector<G4ReactionProduct *>::iterator j;
          for(j = precompoundProducts->begin(); j != precompoundProducts->end(); ++j)
          {
             G4LorentzVector pProduct((*j)->GetMomentum(),(*j)->GetTotalEnergy());
             Preco_momentum += pProduct;
           }
       }
       G4cout << "finalNuclMom / sum preco products" << fragment_momentum << "  / " << Preco_momentum
    		   << " delta E "<< fragment_momentum.e() - Preco_momentum.e() <<  G4endl;

   #endif

   return precompoundProducts;
}

//----------------------------------------------------------------------------
G4ReactionProductVector *  G4BinaryCascade::DecayVoidNucleus()
//----------------------------------------------------------------------------
{
   G4ReactionProductVector * result = nullptr;
   if ( (theTargetList.size()+theCapturedList.size()) > 0 )
   {
      result = new G4ReactionProductVector;
      std::vector<G4KineticTrack *>::iterator aNuc;
      G4LorentzVector aVec;
      std::vector<G4double> masses;
      G4double sumMass(0);

      if ( theTargetList.size() != 0)
      {
         for ( aNuc=theTargetList.begin(); aNuc != theTargetList.end(); aNuc++)
         {
            G4double mass=(*aNuc)->GetDefinition()->GetPDGMass();
            masses.push_back(mass);
            sumMass += mass;
         }
      }

      if ( theCapturedList.size() != 0)
      {
         for(aNuc = theCapturedList.begin(); aNuc != theCapturedList.end(); aNuc++)
         {
            G4double mass=(*aNuc)->GetDefinition()->GetPDGMass();
            masses.push_back(mass);
            sumMass += mass;
         }
      }

      G4LorentzVector finalP=GetFinal4Momentum();
      G4FermiPhaseSpaceDecay decay;
      // G4cout << " some neutrons? " << masses.size() <<" " ;
      // G4cout<< theTargetList.size()<<" "<<finalP <<" " << finalP.mag()<<G4endl;

      G4double eCMS=finalP.mag();
      if ( eCMS < sumMass )                    // @@GF --- Cheat!!
      {
         eCMS=sumMass + 2*MeV*masses.size();
         finalP.setE(std::sqrt(finalP.vect().mag2() + sqr(eCMS)));
      }

      precompoundLorentzboost.set(finalP.boostVector());
      std::vector<G4LorentzVector*> * momenta=decay.Decay(eCMS,masses);
      std::vector<G4LorentzVector*>::iterator aMom=momenta->begin();


      if ( theTargetList.size() != 0)
      {
         for ( aNuc=theTargetList.begin();
               (aNuc != theTargetList.end()) && (aMom!=momenta->end());
               aNuc++, aMom++ )
         {
            G4ReactionProduct * aNew = new G4ReactionProduct((*aNuc)->GetDefinition());
            aNew->SetTotalEnergy((*aMom)->e());
            aNew->SetMomentum((*aMom)->vect());
            aNew->SetCreatorModelID(theBIC_ID);
	    aNew->SetParentResonanceDef((*aNuc)->GetParentResonanceDef());
	    aNew->SetParentResonanceID((*aNuc)->GetParentResonanceID());
            result->push_back(aNew);
            delete *aMom;
         }
      }

      if ( theCapturedList.size() != 0)
      {
         for ( aNuc=theCapturedList.begin();
               (aNuc != theCapturedList.end()) && (aMom!=momenta->end());
               aNuc++, aMom++ )
         {
            G4ReactionProduct * aNew = new G4ReactionProduct((*aNuc)->GetDefinition());
            aNew->SetTotalEnergy((*aMom)->e());
            aNew->SetMomentum((*aMom)->vect());
            aNew->SetCreatorModelID(theBIC_ID);
            aNew->SetParentResonanceDef((*aNuc)->GetParentResonanceDef());
            aNew->SetParentResonanceID((*aNuc)->GetParentResonanceID());	    
            result->push_back(aNew);
            delete *aMom;
         }
      }

      delete momenta;
   }
   return result;
}                   // End if(!fragment)

//----------------------------------------------------------------------------
G4ReactionProductVector * G4BinaryCascade::ProductsAddFinalState(G4ReactionProductVector * products, G4KineticTrackVector & fs)
//----------------------------------------------------------------------------
{
// fill in products the outgoing particles
    std::size_t i(0);
#ifdef debug_BIC_Propagate_finals
    G4LorentzVector mom_fs;
#endif
    for(i = 0; i< fs.size(); i++)
    {
        G4KineticTrack * kt = fs[i];
        G4ReactionProduct * aNew = new G4ReactionProduct(kt->GetDefinition());
        aNew->SetMomentum(kt->Get4Momentum().vect());
        aNew->SetTotalEnergy(kt->Get4Momentum().e());
        aNew->SetNewlyAdded(kt->IsParticipant());
        aNew->SetCreatorModelID(theBIC_ID);
        aNew->SetParentResonanceDef(kt->GetParentResonanceDef());
        aNew->SetParentResonanceID(kt->GetParentResonanceID());	
        products->push_back(aNew);

#ifdef debug_BIC_Propagate_finals
        mom_fs += kt->Get4Momentum();
        G4cout <<kt->GetDefinition()->GetParticleName();
        G4cout << " Particle Ekin " << aNew->GetKineticEnergy();
        G4cout << ", is " << (kt->GetDefinition()->GetPDGStable() ? "stable" :
                (kt->GetDefinition()->IsShortLived() ? "short lived " : "non stable"))  ;
        G4cout << G4endl;
#endif

    }
#ifdef debug_BIC_Propagate_finals
    G4cout << " Final state momentum " << mom_fs << G4endl;
#endif

    return products;
}
//----------------------------------------------------------------------------
G4ReactionProductVector * G4BinaryCascade::ProductsAddPrecompound(G4ReactionProductVector * products, G4ReactionProductVector * precompoundProducts)
//----------------------------------------------------------------------------
{
   G4LorentzVector pSumPreco(0), pPreco(0);

   if ( precompoundProducts )
   {
      for(auto j = precompoundProducts->cbegin(); j != precompoundProducts->cend(); ++j)
      {
         // boost back to system of moving nucleus
         G4LorentzVector pProduct((*j)->GetMomentum(),(*j)->GetTotalEnergy());
         pPreco+= pProduct;
#ifdef debug_BIC_Propagate_finals
         G4cout << "BIC: pProduct be4 boost " <<pProduct << G4endl;
#endif
         pProduct *= precompoundLorentzboost;
#ifdef debug_BIC_Propagate_finals
         G4cout << "BIC: pProduct aft boost " <<pProduct << G4endl;
#endif
         pSumPreco += pProduct;
         (*j)->SetTotalEnergy(pProduct.e());
         (*j)->SetMomentum(pProduct.vect());
         (*j)->SetNewlyAdded(true);
         products->push_back(*j);
      }
      // G4cout << " unboosted preco result mom " << pPreco / MeV << "  ..- fragmentMom " << (pPreco - pFragment)/MeV<< G4endl;
      // G4cout << " preco result mom " << pSumPreco / MeV << "  ..-file4Mom " << (pSumPreco - GetFinal4Momentum())/MeV<< G4endl;
      precompoundProducts->clear();
      delete precompoundProducts;
   }
   return products;
}
//----------------------------------------------------------------------------
void  G4BinaryCascade::FindCollisions(G4KineticTrackVector * secondaries)
//----------------------------------------------------------------------------
{
    for(auto i=secondaries->cbegin(); i!=secondaries->cend(); ++i)
    {
        for(auto j=theImR.cbegin(); j!=theImR.cend(); ++j)
        {
            //      G4cout << "G4BinaryCascade::FindCollisions: at action " << *j << G4endl;
            const std::vector<G4CollisionInitialState *> & aCandList
            = (*j)->GetCollisions(*i, theTargetList, theCurrentTime);
            for(std::size_t count=0; count<aCandList.size(); ++count)
            {
                theCollisionMgr->AddCollision(aCandList[count]);
                //4cout << "====================== New Collision ================="<<G4endl;
                //theCollisionMgr->Print();
            }
        }
    }
}


//----------------------------------------------------------------------------
void  G4BinaryCascade::FindDecayCollision(G4KineticTrack * secondary)
//----------------------------------------------------------------------------
{
    const auto& aCandList = theDecay->GetCollisions(secondary, theTargetList, theCurrentTime);
    for(std::size_t count=0; count<aCandList.size(); ++count)
    {
        theCollisionMgr->AddCollision(aCandList[count]);
    }
}

//----------------------------------------------------------------------------
void  G4BinaryCascade::FindLateParticleCollision(G4KineticTrack * secondary)
//----------------------------------------------------------------------------
{

    G4double tin=0., tout=0.;
    if (((G4RKPropagation*)thePropagator)->GetSphereIntersectionTimes(secondary,tin,tout))
    {
        if ( tin > 0 )
        {
            secondary->SetState(G4KineticTrack::outside);
        } else if ( tout > 0 )
        {
            secondary->SetState(G4KineticTrack::inside);
        } else {
            //G4cout << "G4BC set miss , tin, tout " << tin << " , " << tout <<G4endl;
            secondary->SetState(G4KineticTrack::miss_nucleus);
        }
    } else {
        secondary->SetState(G4KineticTrack::miss_nucleus);
        //G4cout << "G4BC set miss ,no intersect tin, tout " << tin << " , " << tout <<G4endl;
    }


#ifdef debug_BIC_FindCollision
    G4cout << "FindLateP Particle, 4-mom, times newState "
            << secondary->GetDefinition()->GetParticleName() << " "
            << secondary->Get4Momentum()
            << " times " <<  tin << " " << tout << " "
            << secondary->GetState() << G4endl;
#endif

    const auto& aCandList = theLateParticle->GetCollisions(secondary, theTargetList, theCurrentTime);
    for(std::size_t count=0; count<aCandList.size(); ++count)
    {
#ifdef debug_BIC_FindCollision
        G4cout << " Adding a late Col : " << aCandList[count] << G4endl;
#endif
        theCollisionMgr->AddCollision(aCandList[count]);
    }
}


//----------------------------------------------------------------------------
G4bool G4BinaryCascade::ApplyCollision(G4CollisionInitialState * collision)
//----------------------------------------------------------------------------
{
    G4KineticTrack * primary = collision->GetPrimary();

#ifdef debug_BIC_ApplyCollision
    G4cerr << "G4BinaryCascade::ApplyCollision start"<<G4endl;
    theCollisionMgr->Print();
    G4cout << "ApplyCollisions : projte 4mom " << primary->GetTrackingMomentum()<< G4endl;
#endif

    G4KineticTrackVector target_collection=collision->GetTargetCollection();
    G4bool haveTarget=target_collection.size()>0;
    if( haveTarget && (primary->GetState() != G4KineticTrack::inside) )
    {
#ifdef debug_G4BinaryCascade
        G4cout << "G4BinaryCasacde::ApplyCollision(): StateError " << primary << G4endl;
        PrintKTVector(primary,std::string("primay- ..."));
        PrintKTVector(&target_collection,std::string("... targets"));
        collision->Print();
        G4cout << G4endl;
        theCollisionMgr->Print();
        //*GF*     throw G4HadronicException(__FILE__, __LINE__, "G4BinaryCasacde::ApplyCollision()");
#endif
        return false;
//    } else {
//       G4cout << "G4BinaryCasacde::ApplyCollision(): decay " << G4endl;
//       PrintKTVector(primary,std::string("primay- ..."));
//       G4double tin=0., tout=0.;
//       if (((G4RKPropagation*)thePropagator)->GetSphereIntersectionTimes(primary,tin,tout))
//       {
//           G4cout << "tin tout: " << tin << " " << tout << G4endl;
//       }

    }

    G4LorentzVector mom4Primary=primary->Get4Momentum();

    G4int initialBaryon(0);
    G4int initialCharge(0);
    if (primary->GetState() == G4KineticTrack::inside)
    {
        initialBaryon = primary->GetDefinition()->GetBaryonNumber();
        initialCharge = G4lrint(primary->GetDefinition()->GetPDGCharge()/eplus);
    }

    // for primary resonances, subtract neutron ( = proton) field ( ie. add std::abs(field))
    G4double initial_Efermi=CorrectShortlivedPrimaryForFermi(primary,std::move(target_collection));
    //****************************************


    G4KineticTrackVector * products = collision->GetFinalState();

#ifdef debug_BIC_ApplyCollision
    DebugApplyCollisionFail(collision, products);
#endif

    // reset primary to initial state, in case there is a veto...
    primary->Set4Momentum(mom4Primary);

    G4bool lateParticleCollision= (!haveTarget) && products && products->size() == 1;
    G4bool decayCollision= (!haveTarget) && products && products->size() > 1;
    G4bool Success(true);


#ifdef debug_G4BinaryCascade
    G4int lateBaryon(0), lateCharge(0);
#endif

    if ( lateParticleCollision )
    {  // for late particles, reset charges
        //G4cout << "lateP, initial B C state " << initialBaryon << " "
        //        << initialCharge<< " " << primary->GetState() << " "<< primary->GetDefinition()->GetParticleName()<< G4endl;
#ifdef debug_G4BinaryCascade
        lateBaryon = initialBaryon;
        lateCharge = initialCharge;
#endif
        initialBaryon=initialCharge=0;
        lateA -= primary->GetDefinition()->GetBaryonNumber();
        lateZ -= G4lrint(primary->GetDefinition()->GetPDGCharge()/eplus);
    }

    initialBaryon += collision->GetTargetBaryonNumber();
    initialCharge += G4lrint(collision->GetTargetCharge());
    if (!lateParticleCollision)
    {
       if( !products || products->size()==0 || !CheckPauliPrinciple(products) )
       {
#ifdef debug_BIC_ApplyCollision
          if (products) G4cout << " ======Failed Pauli =====" << G4endl;
          G4cerr << "G4BinaryCascade::ApplyCollision blocked"<<G4endl;
#endif
          Success=false;
       }



       if (Success && primary->GetState() == G4KineticTrack::inside ) {   // if the primary was outside, nothing to correct
          if (! CorrectShortlivedFinalsForFermi(products, initial_Efermi)){
             Success=false;
          }
       }
    }

#ifdef debug_BIC_ApplyCollision
    DebugApplyCollision(collision, products);
#endif

    if ( ! Success ){
        if (products) ClearAndDestroy(products);
        if ( decayCollision ) FindDecayCollision(primary);  // for decay, sample new decay
        delete products;
        products=nullptr;
        return false;
    }

    G4int finalBaryon(0);
    G4int finalCharge(0);
    G4KineticTrackVector toFinalState;
    for(auto i=products->cbegin(); i!=products->cend(); ++i)
    {
        if ( ! lateParticleCollision )
        {
            (*i)->SetState(primary->GetState());  // decay may be anywhere!
            if ( (*i)->GetState() == G4KineticTrack::inside ){
                finalBaryon+=(*i)->GetDefinition()->GetBaryonNumber();
                finalCharge+=G4lrint((*i)->GetDefinition()->GetPDGCharge()/eplus);
            } else {
               G4double tin=0., tout=0.;
               if (((G4RKPropagation*)thePropagator)->GetSphereIntersectionTimes((*i),tin,tout) &&
                     tin < 0 && tout > 0 )
               {
                  PrintKTVector((*i),"particle inside marked not-inside");
                   G4cout << "tin tout: " << tin << " " << tout << G4endl;
               }
            }
        } else {
            G4double tin=0., tout=0.;
            if (((G4RKPropagation*)thePropagator)->GetSphereIntersectionTimes((*i),tin,tout))
            {
                //G4cout << "tin tout: " << tin << " " << tout << G4endl;
                if ( tin > 0 )
                {
                    (*i)->SetState(G4KineticTrack::outside);
                }
                else if ( tout > 0 )
                {
                    (*i)->SetState(G4KineticTrack::inside);
                    finalBaryon+=(*i)->GetDefinition()->GetBaryonNumber();
                    finalCharge+=G4lrint((*i)->GetDefinition()->GetPDGCharge()/eplus);
                }
                else
                {
                    (*i)->SetState(G4KineticTrack::gone_out);
                    toFinalState.push_back((*i));
                }
            } else
            {
                (*i)->SetState(G4KineticTrack::miss_nucleus);
                //G4cout << " G4BC - miss -late Part- no intersection found " << G4endl;
                toFinalState.push_back((*i));
            }

        }
    }
    if(!toFinalState.empty())
    {
        theFinalState.insert(theFinalState.cend(),
                toFinalState.cbegin(),toFinalState.cend());
        std::vector<G4KineticTrack *>::iterator iter2;
        for(auto iter1=toFinalState.cbegin(); iter1!=toFinalState.cend(); ++iter1)
        {
            iter2 = std::find(products->begin(), products->end(), *iter1);
            if ( iter2 != products->cend() ) products->erase(iter2);
        }
        theCollisionMgr->RemoveTracksCollisions(&toFinalState);
    }

    //G4cout << " currentA, Z be4: " << currentA << " " << currentZ << G4endl;
    currentA += finalBaryon-initialBaryon;
    currentZ += finalCharge-initialCharge;
    //G4cout << " ApplyCollision currentA, Z aft: " << currentA << " " << currentZ << G4endl;

    G4KineticTrackVector oldSecondaries;
    oldSecondaries.push_back(primary);
    primary->Hit();

#ifdef debug_G4BinaryCascade
    if ( (finalBaryon-initialBaryon-lateBaryon) != 0 || (finalCharge-initialCharge-lateCharge) != 0 )
    {
        G4cout << "G4BinaryCascade: Error in Balancing: " << G4endl;
        G4cout << "initial/final baryon number, initial/final Charge "
                << initialBaryon <<" "<< finalBaryon <<" "
                << initialCharge <<" "<< finalCharge <<" "
                << " in Collision type: "<< typeid(*collision->GetGenerator()).name()
                << ", with number of products: "<< products->size() <<G4endl;
        G4cout << G4endl<<"Initial condition are these:"<<G4endl;
        G4cout << "proj: "<<collision->GetPrimary()->GetDefinition()->GetParticleName()<<G4endl;
        for(std::size_t it=0; it<collision->GetTargetCollection().size(); ++it)
        {
            G4cout << "targ: "
                    <<collision->GetTargetCollection()[it]->GetDefinition()->GetParticleName()<<G4endl;
        }
        PrintKTVector(&collision->GetTargetCollection(),std::string(" Target particles"));
        G4cout << G4endl<<G4endl;
    }
#endif

    G4KineticTrackVector oldTarget = collision->GetTargetCollection();
    for(std::size_t ii=0; ii< oldTarget.size(); ++ii)
    {
        oldTarget[ii]->Hit();
    }

    UpdateTracksAndCollisions(&oldSecondaries, &oldTarget, products);
    std::for_each(oldSecondaries.cbegin(), oldSecondaries.cend(), Delete<G4KineticTrack>());
    std::for_each(oldTarget.cbegin(), oldTarget.cend(), Delete<G4KineticTrack>());

    delete products;
    return true;
}


//----------------------------------------------------------------------------
G4bool G4BinaryCascade::Absorb()
//----------------------------------------------------------------------------
{
    // Do it in two step: cannot change theSecondaryList inside the first loop.
    G4Absorber absorber(theCutOnPAbsorb);

    // Build the vector of G4KineticTracks that must be absorbed
    G4KineticTrackVector absorbList;
    std::vector<G4KineticTrack *>::const_iterator iter;
    //  PrintKTVector(&theSecondaryList, " testing for Absorb" );
    for(iter = theSecondaryList.cbegin();
            iter != theSecondaryList.cend(); ++iter)
    {
        G4KineticTrack * kt = *iter;
        if(kt->GetState() == G4KineticTrack::inside)// absorption happens only inside the nucleus
        {
            if(absorber.WillBeAbsorbed(*kt))
            {
                absorbList.push_back(kt);
            }
        }
    }

    if(absorbList.empty())
        return false;

    G4KineticTrackVector toDelete;
    for(iter = absorbList.cbegin(); iter != absorbList.cend(); ++iter)
    {
        G4KineticTrack * kt = *iter;
        if(!absorber.FindAbsorbers(*kt, theTargetList))
            throw G4HadronicException(__FILE__, __LINE__, "G4BinaryCascade::Absorb(): Cannot absorb a particle.");

        if(!absorber.FindProducts(*kt))
            throw G4HadronicException(__FILE__, __LINE__, "G4BinaryCascade::Absorb(): Cannot absorb a particle.");

        G4KineticTrackVector * products = absorber.GetProducts();
        G4int maxLoopCount = 1000;
        while(!CheckPauliPrinciple(products) && --maxLoopCount>0)   /* Loop checking, 31.08.2015, G.Folger */
        {
            ClearAndDestroy(products);
            if(!absorber.FindProducts(*kt))
                throw G4HadronicException(__FILE__, __LINE__,
                        "G4BinaryCascade::Absorb(): Cannot absorb a particle.");
        }
		  if ( --maxLoopCount < 0 ) throw G4HadronicException(__FILE__, __LINE__, "G4BinaryCascade::Absorb(): Cannot absorb a particle."); 
        // ------ debug
        //    G4cerr << "Absorb CheckPauliPrinciple count= " <<  maxLoopCount << G4endl;
        // ------ end debug
        G4KineticTrackVector toRemove;  // build a vector for UpdateTrack...
        toRemove.push_back(kt);
        toDelete.push_back(kt);  // delete the track later
        G4KineticTrackVector * absorbers = absorber.GetAbsorbers();
        UpdateTracksAndCollisions(&toRemove, absorbers, products);
        ClearAndDestroy(absorbers);
    }
    ClearAndDestroy(&toDelete);
    return true;
}



// Capture all p and n with Energy < theCutOnP
//----------------------------------------------------------------------------
G4bool G4BinaryCascade::Capture(G4bool verbose)
//----------------------------------------------------------------------------
{
    G4KineticTrackVector captured;
    G4bool capture = false;
    std::vector<G4KineticTrack *>::const_iterator i;

    G4RKPropagation * RKprop=(G4RKPropagation *)thePropagator;

    G4double capturedEnergy = 0;
    G4int particlesAboveCut=0;
    G4int particlesBelowCut=0;
    if ( verbose ) G4cout << " Capture: secondaries " << theSecondaryList.size() << G4endl;
    for(i = theSecondaryList.cbegin(); i != theSecondaryList.cend(); ++i)
    {
        G4KineticTrack * kt = *i;
        if (verbose) G4cout << "Capture position, radius, state " <<kt->GetPosition().mag()<<" "<<theOuterRadius<<" "<<kt->GetState()<<G4endl;
        if(kt->GetState() == G4KineticTrack::inside) // capture happens only inside the nucleus
        {
            if((kt->GetDefinition() == G4Proton::Proton()) ||
                    (kt->GetDefinition() == G4Neutron::Neutron()))
            {
                //GF cut on kinetic energy    if(kt->Get4Momentum().vect().mag() >= theCutOnP)
                G4double field=RKprop->GetField(kt->GetDefinition()->GetPDGEncoding(),kt->GetPosition())
	            		           -RKprop->GetBarrier(kt->GetDefinition()->GetPDGEncoding());
                G4double energy= kt->Get4Momentum().e() - kt->GetActualMass() + field;
                if (verbose ) G4cout << "Capture: .e(), mass, field, energy" << kt->Get4Momentum().e() <<" "<<kt->GetActualMass()<<" "<<field<<" "<<energy<< G4endl;
                //	 if( energy < theCutOnP )
                //	 {
                capturedEnergy+=energy;
                ++particlesBelowCut;
                //	 } else
                //	 {
                //	    ++particlesAboveCut;
                //	 }
            }
        }
    }
    if (verbose) G4cout << "Capture particlesAboveCut,particlesBelowCut, capturedEnergy,capturedEnergy/particlesBelowCut <? 0.2*theCutOnP "
            << particlesAboveCut << " " << particlesBelowCut << " " << capturedEnergy
            << " "  << G4endl;
//    << " " << (particlesBelowCut>0) ? (capturedEnergy/particlesBelowCut) : (capturedEnergy) << " " << 0.2*theCutOnP << G4endl;
    //  if(particlesAboveCut==0 && particlesBelowCut>0 && capturedEnergy/particlesBelowCut<0.2*theCutOnP)
    if(particlesBelowCut>0 && capturedEnergy/particlesBelowCut<0.2*theCutOnP)
    {
        capture=true;
        for(i = theSecondaryList.cbegin(); i != theSecondaryList.cend(); ++i)
        {
            G4KineticTrack * kt = *i;
            if(kt->GetState() == G4KineticTrack::inside) // capture happens only inside the nucleus
            {
                if((kt->GetDefinition() == G4Proton::Proton()) ||
                        (kt->GetDefinition() == G4Neutron::Neutron()))
                {
                    captured.push_back(kt);
                    kt->Hit();				//
                    theCapturedList.push_back(kt);
                }
            }
        }
        UpdateTracksAndCollisions(&captured, nullptr, nullptr);
    }

    return capture;
}


//----------------------------------------------------------------------------
G4bool G4BinaryCascade::CheckPauliPrinciple(G4KineticTrackVector * products)
//----------------------------------------------------------------------------
{
    G4int A = the3DNucleus->GetMassNumber();
    G4int Z = the3DNucleus->GetCharge();

    G4FermiMomentum fermiMom;
    fermiMom.Init(A, Z);

    const G4VNuclearDensity * density=the3DNucleus->GetNuclearDensity();

    G4KineticTrackVector::const_iterator i;
    const G4ParticleDefinition * definition;

    // ------ debug
    G4bool myflag = true;
    // ------ end debug
    //  G4ThreeVector xpos(0);
    for(i = products->cbegin(); i != products->cend(); ++i)
    {
        definition = (*i)->GetDefinition();
        if((definition == G4Proton::Proton()) ||
                (definition == G4Neutron::Neutron()))
        {
            G4ThreeVector pos = (*i)->GetPosition();
            G4double d = density->GetDensity(pos);
            // energy correspondiing to fermi momentum
            G4double eFermi = std::sqrt( sqr(fermiMom.GetFermiMomentum(d)) + (*i)->Get4Momentum().mag2() );
            if( definition == G4Proton::Proton() )
            {
                eFermi -= the3DNucleus->CoulombBarrier();
            }
            G4LorentzVector mom = (*i)->Get4Momentum();
            // ------ debug
            /*
             *        G4cout << "p:[" << (1/MeV)*mom.x() << " " << (1/MeV)*mom.y() << " "
             *            << (1/MeV)*mom.z() << "] |p3|:"
             *            << (1/MeV)*mom.vect().mag() << " E:" << (1/MeV)*mom.t() << " ] m: "
             *            << (1/MeV)*mom.mag() << "  pos["
             *            << (1/fermi)*pos.x() << " "<< (1/fermi)*pos.y() << " "
             *            << (1/fermi)*pos.z() << "] |Dpos|: "
             *            << (1/fermi)*(pos-xpos).mag() << " Pfermi:"
             *            << (1/MeV)*p << G4endl;
             *         xpos=pos;
             */
            // ------ end debug
            if(mom.e() < eFermi )
            {
                // ------ debug
                myflag = false;
                // ------ end debug
                //      return false;
            }
        }
    }
#ifdef debug_BIC_CheckPauli
    if ( myflag  )
    {
        for(i = products->cbegin(); i != products->cend(); ++i)
        {
            definition = (*i)->GetDefinition();
            if((definition == G4Proton::Proton()) ||
                    (definition == G4Neutron::Neutron()))
            {
                G4ThreeVector pos = (*i)->GetPosition();
                G4double d = density->GetDensity(pos);
                G4double pFermi = fermiMom.GetFermiMomentum(d);
                G4LorentzVector mom = (*i)->Get4Momentum();
                G4double field =((G4RKPropagation*)thePropagator)->GetField(definition->GetPDGEncoding(),pos);
                if ( mom.e()-mom.mag()+field > 160*MeV )
                {
                    G4cout << "momentum problem pFermi=" <<  pFermi
                            << " mom, mom.m " << mom << " " << mom.mag()
                            << " field " << field << G4endl;
                }
            }
        }
    }
#endif

    return myflag;
}

//----------------------------------------------------------------------------
void G4BinaryCascade::StepParticlesOut()
//----------------------------------------------------------------------------
{
    G4int counter=0;
    G4int countreset=0;
    //G4cout << " nucl. Radius " << radius << G4endl;
    // G4cerr <<"pre-while- theSecondaryList "<<G4endl;
    while( theSecondaryList.size() > 0 )               /* Loop checking, 31.08.2015, G.Folger */
	                                                    // if countreset reaches limit, there is a break from while, see below.
    {
        G4double minTimeStep = 1.e-12*ns;   // about 30*fermi/(0.1*c_light);1.e-12*ns
                                            // i.e. a big step
        for(auto i = theSecondaryList.cbegin(); i != theSecondaryList.cend(); ++i)
        {
            G4KineticTrack * kt = *i;
            if( kt->GetState() == G4KineticTrack::inside )
            {
                G4double tStep(0), tdummy(0);
                G4bool intersect =
                        ((G4RKPropagation*)thePropagator)->GetSphereIntersectionTimes(kt,tdummy,tStep);
#ifdef debug_BIC_StepParticlesOut
                G4cout << " minTimeStep, tStep Particle " <<minTimeStep << " " <<tStep
                        << " " <<kt->GetDefinition()->GetParticleName()
                        << " 4mom " << kt->GetTrackingMomentum()<<G4endl;
                if ( ! intersect );
                {
                    PrintKTVector(&theSecondaryList, std::string(" state ERROR....."));
                    throw G4HadronicException(__FILE__, __LINE__, "G4BinaryCascade::StepParticlesOut() particle not in nucleus");
                }
#endif
                if(intersect && tStep<minTimeStep && tStep> 0 )
                {
                    minTimeStep = tStep;
                }
            } else if ( kt->GetState() != G4KineticTrack::outside ){
                PrintKTVector(&theSecondaryList, std::string(" state ERROR....."));
                throw G4HadronicException(__FILE__, __LINE__, "G4BinaryCascade::StepParticlesOut() particle not in nucleus");
            }
        }
        minTimeStep *= 1.2;
        G4double timeToCollision=DBL_MAX;
        G4CollisionInitialState * nextCollision=nullptr;
        if(theCollisionMgr->Entries() > 0)
        {
            nextCollision = theCollisionMgr->GetNextCollision();
            timeToCollision = nextCollision->GetCollisionTime()-theCurrentTime;
            //  G4cout << " NextCollision  * , Time= " << nextCollision << " " <<timeToCollision<< G4endl;
        }
        if ( timeToCollision > minTimeStep )
        {
            DoTimeStep(minTimeStep);
            ++counter;
        } else
        {
            if (!DoTimeStep(timeToCollision) )
            {
                // Check if nextCollision is still valid, ie. partcile did not leave nucleus
                if (theCollisionMgr->GetNextCollision() != nextCollision )
                {
                    nextCollision = nullptr;
                }
            }
            // G4cerr <<"post- DoTimeStep 3"<<G4endl;

            if(nextCollision)
            {
                if  ( ApplyCollision(nextCollision))
                {
                    // G4cout << "ApplyCollision sucess " << G4endl;
                } else
                {
                    theCollisionMgr->RemoveCollision(nextCollision);
                }
            }
        }

        if(countreset>100)
        {
#ifdef debug_G4BinaryCascade
            G4cerr << "G4BinaryCascade.cc: Warning - aborting looping particle(s)" << G4endl;
            PrintKTVector(&theSecondaryList," looping particles added to theFinalState");
#endif

            //  add left secondaries to FinalSate
            for (auto iter=theSecondaryList.cbegin(); iter!=theSecondaryList.cend(); ++iter)
            {
                theFinalState.push_back(*iter);
            }
            theSecondaryList.clear();

            break;
        }

        if(Absorb())
        {
            //       haveProducts = true;
            // G4cout << "Absorb sucess " << G4endl;
        }

        if(Capture(false))
        {
            //       haveProducts = true;
#ifdef debug_BIC_StepParticlesOut
            G4cout << "Capture sucess " << G4endl;
#endif
        }
        if ( counter > 100 && theCollisionMgr->Entries() == 0)   // no collision, and stepping for some time....
        {
#ifdef debug_BIC_StepParticlesOut
            PrintKTVector(&theSecondaryList,std::string("stepping 100 steps"));
#endif
            FindCollisions(&theSecondaryList);
            counter=0;
            ++countreset;
        }
        //G4cout << "currentZ @ end loop " << currentZ << G4endl;
        if ( ! currentZ ){
            // nucleus completely destroyed, fill in ReactionProductVector
           // products = FillVoidNucleusProducts(products);
    #ifdef debug_BIC_return
            G4cout << "return @ Z=0 after collision loop "<< G4endl;
            PrintKTVector(&theSecondaryList,std::string(" theSecondaryList"));
            G4cout << "theTargetList size: " << theTargetList.size() << G4endl;
            PrintKTVector(&theTargetList,std::string(" theTargetList"));
            PrintKTVector(&theCapturedList,std::string(" theCapturedList"));

            G4cout << " ExcitE be4 Correct : " <<GetExcitationEnergy() << G4endl;
            G4cout << " Mom Transfered to nucleus : " << theMomentumTransfer << " " << theMomentumTransfer.mag() << G4endl;
            PrintKTVector(&theFinalState,std::string(" FinalState uncorrected"));
          //  G4cout << "returned products: " << products->size() << G4endl;
    #endif
        }

    }
    //  G4cerr <<"Finished capture loop "<<G4endl;

    //G4cerr <<"pre- DoTimeStep 4"<<G4endl;
    DoTimeStep(DBL_MAX);
    //G4cerr <<"post- DoTimeStep 4"<<G4endl;
}

//----------------------------------------------------------------------------
G4double G4BinaryCascade::CorrectShortlivedPrimaryForFermi(
        G4KineticTrack* primary,G4KineticTrackVector target_collection)
//----------------------------------------------------------------------------
{
    G4double Efermi(0);
    if (primary->GetState() == G4KineticTrack::inside ) {
        G4int PDGcode=primary->GetDefinition()->GetPDGEncoding();
        Efermi=((G4RKPropagation *)thePropagator)->GetField(PDGcode,primary->GetPosition());

        if ( std::abs(PDGcode) > 1000 && PDGcode != 2112 && PDGcode != 2212 )
        {
            Efermi = ((G4RKPropagation *)thePropagator)->GetField(G4Neutron::Neutron()->GetPDGEncoding(),primary->GetPosition());
            G4LorentzVector mom4Primary=primary->Get4Momentum();
            primary->Update4Momentum(mom4Primary.e() - Efermi);
        }

        for (auto titer=target_collection.cbegin() ; titer!=target_collection.cend(); ++titer)
        {
            const G4ParticleDefinition * aDef=(*titer)->GetDefinition();
            G4int aCode=aDef->GetPDGEncoding();
            G4ThreeVector aPos=(*titer)->GetPosition();
            Efermi+= ((G4RKPropagation *)thePropagator)->GetField(aCode, aPos);
        }
    }
    return Efermi;
}

//----------------------------------------------------------------------------
G4bool G4BinaryCascade::CorrectShortlivedFinalsForFermi(G4KineticTrackVector * products,
        G4double initial_Efermi)
//----------------------------------------------------------------------------
{
    G4double final_Efermi(0);
    G4KineticTrackVector resonances;
    for (auto i =products->cbegin(); i != products->cend(); ++i)
    {
        G4int PDGcode=(*i)->GetDefinition()->GetPDGEncoding();
        //       G4cout << " PDGcode, state " << PDGcode << " " << (*i)->GetState()<<G4endl;
        final_Efermi+=((G4RKPropagation *)thePropagator)->GetField(PDGcode,(*i)->GetPosition());
        if ( std::abs(PDGcode) > 1000 && PDGcode != 2112 && PDGcode != 2212 )
        {
            resonances.push_back(*i);
        }
    }
    if ( resonances.size() > 0 )
    {
        G4double delta_Fermi= (initial_Efermi-final_Efermi)/resonances.size();
        for (auto res=resonances.cbegin(); res != resonances.cend(); ++res)
        {
            G4LorentzVector mom=(*res)->Get4Momentum();
            G4double mass2=mom.mag2();
            G4double newEnergy=mom.e() + delta_Fermi;
            G4double newEnergy2= newEnergy*newEnergy;
            //G4cout << "mom = " << mom <<" newE " << newEnergy<< G4endl;
            if ( newEnergy2 < mass2 )
            {
                return false;
            }
            G4ThreeVector mom3=std::sqrt(newEnergy2 - mass2) * mom.vect().unit();
            (*res)->Set4Momentum(G4LorentzVector(mom3,newEnergy));
            	  //G4cout << " correct resonance from /to " << mom.e() << " / " << newEnergy<<
            	  //		    " 3mom from/to " << mom.vect() << " / " << mom3 << G4endl;
        }
    }
    return true;
}

//----------------------------------------------------------------------------
void G4BinaryCascade::CorrectFinalPandE()
//----------------------------------------------------------------------------
//
//  Modify momenta of outgoing particles.
//   Assume two body decay, nucleus(@nominal mass) + sum of final state particles(SFSP).
//   momentum of SFSP shall be less than momentum for two body decay.
//
{
#ifdef debug_BIC_CorrectFinalPandE
    G4cerr << "BIC: -CorrectFinalPandE called" << G4endl;
#endif

    if ( theFinalState.size() == 0 ) return;

    G4KineticTrackVector::const_iterator i;
    G4LorentzVector pNucleus=GetFinal4Momentum();
    if ( pNucleus.e() == 0 ) return;    // check against explicit 0 from GetNucleus4Momentum()
#ifdef debug_BIC_CorrectFinalPandE
    G4cerr << " -CorrectFinalPandE 3" << G4endl;
#endif
    G4LorentzVector pFinals(0);
    for(i = theFinalState.cbegin(); i != theFinalState.cend(); ++i)
    {
        pFinals += (*i)->Get4Momentum();
#ifdef debug_BIC_CorrectFinalPandE
        G4cout <<"CorrectFinalPandE a final " << (*i)->GetDefinition()->GetParticleName()
        		           << " 4mom " << (*i)->Get4Momentum()<< G4endl;
#endif
    }
#ifdef debug_BIC_CorrectFinalPandE
    G4cout << "CorrectFinalPandE pN pF: " <<pNucleus << " " <<pFinals << G4endl;
#endif
    G4LorentzVector pCM=pNucleus + pFinals;

    G4LorentzRotation toCMS(-pCM.boostVector());
    pFinals *=toCMS;
#ifdef debug_BIC_CorrectFinalPandE
    G4cout << "CorrectFinalPandE pCM, CMS pCM " << pCM << " " <<toCMS*pCM<< G4endl;
    G4cout << "CorrectFinal CMS pN pF " <<toCMS*pNucleus << " "
            <<pFinals << G4endl
            << " nucleus initial mass : " <<GetFinal4Momentum().mag()
            <<" massInNucleus m(nucleus) m(finals) std::sqrt(s): " << massInNucleus << " " <<pNucleus.mag()<< " "
            << pFinals.mag() << " " << pCM.mag() << G4endl;
#endif

    G4LorentzRotation toLab = toCMS.inverse();

    G4double s0 = pCM.mag2();
    G4double m10 = GetIonMass(currentZ,currentA);
    G4double m20 = pFinals.mag();
    if( s0-(m10+m20)*(m10+m20) < 0 )
    {
#ifdef debug_BIC_CorrectFinalPandE
        G4cout << "G4BinaryCascade::CorrectFinalPandE() : error! " << G4endl;

        G4cout << "not enough mass to correct: mass^2, A,Z, mass(nucl), mass(finals) "
                << (s0-(m10+m20)*(m10+m20)) << " "
                << currentA << " " << currentZ << " "
                << m10 << " " << m20
                << G4endl;
        G4cerr << " -CorrectFinalPandE 4" << G4endl;

        PrintKTVector(&theFinalState," mass problem");
#endif
        return;
    }

    // Three momentum in cm system
    G4double pInCM = std::sqrt((s0-(m10+m20)*(m10+m20))*(s0-(m10-m20)*(m10-m20))/(4.*s0));
#ifdef debug_BIC_CorrectFinalPandE
    G4cout <<" CorrectFinalPandE pInCM  new, CURRENT, ratio : " << pInCM
            << " " << (pFinals).vect().mag()<< " " <<  pInCM/(pFinals).vect().mag() << G4endl;
#endif
    if ( pFinals.vect().mag() > pInCM )
    {
        G4ThreeVector p3finals=pInCM*pFinals.vect().unit();

        G4double factor=std::max(0.98,pInCM/pFinals.vect().mag());   // small correction
        G4LorentzVector qFinals(0);
        for(i = theFinalState.cbegin(); i != theFinalState.cend(); ++i)
        {
            //      G4ThreeVector p3((toCMS*(*i)->Get4Momentum()).vect() + deltap);
            G4ThreeVector p3(factor*(toCMS*(*i)->Get4Momentum()).vect());
            G4LorentzVector p(p3,std::sqrt((*i)->Get4Momentum().mag2() + p3.mag2()));
            qFinals += p;
            p *= toLab;
#ifdef debug_BIC_CorrectFinalPandE
            G4cout << " final p corrected: " << p << G4endl;
#endif
            (*i)->Set4Momentum(p);
        }
#ifdef debug_BIC_CorrectFinalPandE
        G4cout << "CorrectFinalPandE nucleus corrected mass : " << GetFinal4Momentum() << " "
                <<GetFinal4Momentum().mag() << G4endl
                << " CMS pFinals , mag, 3.mag : " << qFinals << " " << qFinals.mag() << " " << qFinals.vect().mag()<< G4endl;
        G4cerr << " -CorrectFinalPandE 5 " << factor <<  G4endl;
#endif
    }
#ifdef debug_BIC_CorrectFinalPandE
    else { G4cerr << " -CorrectFinalPandE 6 - no correction done" << G4endl; }
#endif

}

//----------------------------------------------------------------------------
void G4BinaryCascade::UpdateTracksAndCollisions(
        //----------------------------------------------------------------------------
        G4KineticTrackVector * oldSecondaries,
        G4KineticTrackVector * oldTarget,
        G4KineticTrackVector * newSecondaries)
{
    std::vector<G4KineticTrack *>::const_iterator iter2;

    // remove old secondaries from the secondary list
    if(oldSecondaries)
    {
        if(!oldSecondaries->empty())
        {
            for(auto iter1=oldSecondaries->cbegin(); iter1!=oldSecondaries->cend(); ++iter1)
            {
                iter2 = std::find(theSecondaryList.begin(), theSecondaryList.end(), *iter1);
                if ( iter2 != theSecondaryList.cend() ) theSecondaryList.erase(iter2);
            }
            theCollisionMgr->RemoveTracksCollisions(oldSecondaries);
        }
    }

    // remove old target from the target list
    if(oldTarget)
    {
        // G4cout << "################## Debugging 0 "<<G4endl;
        if(oldTarget->size()!=0)
        {

            // G4cout << "################## Debugging 1 "<<oldTarget->size()<<G4endl;
            for(auto iter1 = oldTarget->cbegin(); iter1 != oldTarget->cend(); ++iter1)
            {
                iter2 = std::find(theTargetList.begin(), theTargetList.end(), *iter1);
                theTargetList.erase(iter2);
            }
            theCollisionMgr->RemoveTracksCollisions(oldTarget);
        }
    }

    if(newSecondaries)
    {
        if(!newSecondaries->empty())
        {
            // insert new secondaries in the secondary list
            for(auto iter1 = newSecondaries->cbegin(); iter1 != newSecondaries->cend(); ++iter1)
            {
                theSecondaryList.push_back(*iter1);
                if ((*iter1)->GetState() == G4KineticTrack::undefined)
                {
                   PrintKTVector(*iter1, "undefined in FindCollisions");
                }


            }
            // look for collisions of new secondaries
            FindCollisions(newSecondaries);
        }
    }
    // G4cout << "Exiting ... "<<oldTarget<<G4endl;
}


class SelectFromKTV
{
private:
    G4KineticTrackVector * ktv;
    G4KineticTrack::CascadeState wanted_state;
public:
    SelectFromKTV(G4KineticTrackVector * out, G4KineticTrack::CascadeState astate)
    :
        ktv(out), wanted_state(astate)
    {};
    void operator() (G4KineticTrack *& kt) const
    {
        if ( (kt)->GetState() == wanted_state ) ktv->push_back(kt);
    };
};



//----------------------------------------------------------------------------
G4bool G4BinaryCascade::DoTimeStep(G4double theTimeStep)
//----------------------------------------------------------------------------
{

#ifdef debug_BIC_DoTimeStep
    G4ping debug("debug_G4BinaryCascade");
    debug.push_back("======> DoTimeStep 1"); debug.dump();
    G4cerr <<"G4BinaryCascade::DoTimeStep: enter step="<< theTimeStep
            << " , time="<<theCurrentTime << G4endl;
    PrintKTVector(&theSecondaryList, std::string("DoTimeStep - theSecondaryList"));
    //PrintKTVector(&theTargetList, std::string("DoTimeStep - theTargetList"));
#endif

    G4bool success=true;
    std::vector<G4KineticTrack *>::const_iterator iter;

    G4KineticTrackVector * kt_outside = new G4KineticTrackVector;
    std::for_each( theSecondaryList.begin(),theSecondaryList.end(),
            SelectFromKTV(kt_outside,G4KineticTrack::outside));
    //PrintKTVector(kt_outside, std::string("DoTimeStep - found outside"));

    G4KineticTrackVector * kt_inside = new G4KineticTrackVector;
    std::for_each( theSecondaryList.begin(),theSecondaryList.end(),
            SelectFromKTV(kt_inside, G4KineticTrack::inside));
    //  PrintKTVector(kt_inside, std::string("DoTimeStep - found inside"));
    //-----
    G4KineticTrackVector dummy;   // needed for re-usability
#ifdef debug_BIC_DoTimeStep
    G4cout << "NOW WE ARE ENTERING THE TRANSPORT"<<G4endl;
#endif

    // =================== Here we move the particles  ===================

    thePropagator->Transport(theSecondaryList, dummy, theTimeStep);

    // =================== Here we move the particles  ===================

    //------

    theMomentumTransfer += thePropagator->GetMomentumTransfer();
#ifdef debug_BIC_DoTimeStep
    G4cout << "DoTimeStep : theMomentumTransfer = " << theMomentumTransfer << G4endl;
    PrintKTVector(&theSecondaryList, std::string("DoTimeStep - secondaries aft trsprt"));
#endif

    //_DebugEpConservation(" after stepping");

    // Partclies which went INTO nucleus

    G4KineticTrackVector * kt_gone_in = new G4KineticTrackVector;
    std::for_each( kt_outside->begin(),kt_outside->end(),
            SelectFromKTV(kt_gone_in,G4KineticTrack::inside));
    //  PrintKTVector(kt_gone_in, std::string("DoTimeStep - gone in"));


    // Partclies which  went OUT OF nucleus
    G4KineticTrackVector * kt_gone_out = new G4KineticTrackVector;
    std::for_each( kt_inside->begin(),kt_inside->end(),
            SelectFromKTV(kt_gone_out, G4KineticTrack::gone_out));

    //  PrintKTVector(kt_gone_out, std::string("DoTimeStep - gone out"));

    G4KineticTrackVector *fail=CorrectBarionsOnBoundary(kt_gone_in,kt_gone_out);

    if ( fail )
    {
        // some particle(s) supposed to enter/leave were miss_nucleus/captured by the correction
        kt_gone_in->clear();
        std::for_each( kt_outside->begin(),kt_outside->end(),
                SelectFromKTV(kt_gone_in,G4KineticTrack::inside));

        kt_gone_out->clear();
        std::for_each( kt_inside->begin(),kt_inside->end(),
                SelectFromKTV(kt_gone_out, G4KineticTrack::gone_out));

#ifdef debug_BIC_DoTimeStep
        PrintKTVector(fail,std::string(" Failed to go in/out -> miss_nucleus/captured"));
        PrintKTVector(kt_gone_in, std::string("recreated kt_gone_in"));
        PrintKTVector(kt_gone_out, std::string("recreated kt_gone_out"));
#endif
        delete fail;
    }

    // Add tracks missing nucleus and tracks going straight though  to addFinals
    std::for_each( kt_outside->begin(),kt_outside->end(),
            SelectFromKTV(kt_gone_out,G4KineticTrack::miss_nucleus));
    //PrintKTVector(kt_gone_out, std::string("miss to append to final state.."));
    std::for_each( kt_outside->begin(),kt_outside->end(),
            SelectFromKTV(kt_gone_out,G4KineticTrack::gone_out));

#ifdef debug_BIC_DoTimeStep
    PrintKTVector(kt_gone_out, std::string("append gone_outs to final state.. theFinalState"));
#endif

    theFinalState.insert(theFinalState.end(),
            kt_gone_out->begin(),kt_gone_out->end());

    // Partclies which could not leave nucleus,  captured...
    G4KineticTrackVector * kt_captured = new G4KineticTrackVector;
    std::for_each( theSecondaryList.begin(),theSecondaryList.end(),
            SelectFromKTV(kt_captured, G4KineticTrack::captured));

    // Check no track is part in next collision, ie.
    //  this step was to far, and collisions should not occur any more

    if ( theCollisionMgr->Entries()> 0 )
    {
        if (kt_gone_out->size() )
        {
            G4KineticTrack * nextPrimary = theCollisionMgr->GetNextCollision()->GetPrimary();
            iter = std::find(kt_gone_out->begin(),kt_gone_out->end(),nextPrimary);
            if ( iter !=  kt_gone_out->cend() )
            {
                success=false;
#ifdef debug_BIC_DoTimeStep
                G4cout << " DoTimeStep - WARNING: deleting current collision!" << G4endl;
#endif
            }
        }
        if ( kt_captured->size() )
        {
            G4KineticTrack * nextPrimary = theCollisionMgr->GetNextCollision()->GetPrimary();
            iter = std::find(kt_captured->begin(),kt_captured->end(),nextPrimary);
            if ( iter !=  kt_captured->cend() )
            {
                success=false;
#ifdef debug_BIC_DoTimeStep
                G4cout << " DoTimeStep - WARNING: deleting current collision!" << G4endl;
#endif
            }
        }

    }
    // PrintKTVector(kt_gone_out," kt_gone_out be4 updatetrack...");
    UpdateTracksAndCollisions(kt_gone_out,0 ,0);


    if ( kt_captured->size() )
    {
        theCapturedList.insert(theCapturedList.end(),
                kt_captured->begin(),kt_captured->end());
        //should be      std::for_each(kt_captured->begin(),kt_captured->end(),
        //              std::mem_fun(&G4KineticTrack::Hit));
        // but VC 6 requires:
        for(auto i_captured=kt_captured->cbegin();i_captured!=kt_captured->cend(); ++i_captured)
        {
            (*i_captured)->Hit();
        }
        //     PrintKTVector(kt_captured," kt_captured be4 updatetrack...");
        UpdateTracksAndCollisions(kt_captured, nullptr, nullptr);
    }

#ifdef debug_G4BinaryCascade
    delete kt_inside;
    kt_inside = new G4KineticTrackVector;
    std::for_each( theSecondaryList.begin(),theSecondaryList.end(),
            SelectFromKTV(kt_inside, G4KineticTrack::inside));
    if ( currentZ != (GetTotalCharge(theTargetList)
            + GetTotalCharge(theCapturedList)
            + GetTotalCharge(*kt_inside)) )
    {
        G4cout << " error-DoTimeStep aft, A, Z: " << currentA << " " << currentZ
                << " sum(tgt,capt,active) "
                << GetTotalCharge(theTargetList) + GetTotalCharge(theCapturedList) + GetTotalCharge(*kt_inside)
                << " targets: "  << GetTotalCharge(theTargetList)
                << " captured: " << GetTotalCharge(theCapturedList)
                << " active: "   << GetTotalCharge(*kt_inside)
                << G4endl;
    }
#endif

    delete kt_inside;
    delete kt_outside;
    delete kt_captured;
    delete kt_gone_in;
    delete kt_gone_out;

    //  G4cerr <<"G4BinaryCascade::DoTimeStep: exit "<<G4endl;
    theCurrentTime += theTimeStep;

    //debug.push_back("======> DoTimeStep 2"); debug.dump();
    return success;

}

//----------------------------------------------------------------------------
G4KineticTrackVector* G4BinaryCascade::CorrectBarionsOnBoundary(
        G4KineticTrackVector *in,
        G4KineticTrackVector *out)
//----------------------------------------------------------------------------
{
    G4KineticTrackVector * kt_fail(nullptr);
    std::vector<G4KineticTrack *>::const_iterator iter;
    //  G4cout << "CorrectBarionsOnBoundary,currentZ,currentA,"
    //         << currentZ << " "<< currentA << G4endl;
    if (in->size())
    {
        G4int secondaries_in(0);
        G4int secondaryBarions_in(0);
        G4int secondaryCharge_in(0);
        G4double secondaryMass_in(0);

        for ( iter =in->cbegin(); iter != in->cend(); ++iter)
        {
            ++secondaries_in;
            secondaryCharge_in += G4lrint((*iter)->GetDefinition()->GetPDGCharge()/eplus);
            if ((*iter)->GetDefinition()->GetBaryonNumber()!=0 )
            {
                secondaryBarions_in += (*iter)->GetDefinition()->GetBaryonNumber();
                if((*iter)->GetDefinition() == G4Neutron::Neutron() ||
                        (*iter)->GetDefinition() == G4Proton::Proton()  )
                {
                    secondaryMass_in += (*iter)->GetDefinition()->GetPDGMass();
                } else 	  {
                    secondaryMass_in += G4Proton::Proton()->GetPDGMass();
                }
            }
        }
        G4double mass_initial= GetIonMass(currentZ,currentA);

        currentZ += secondaryCharge_in;
        currentA += secondaryBarions_in;

        //  G4cout << "CorrectBarionsOnBoundary,secondaryCharge_in, secondaryBarions_in "
        //         <<    secondaryCharge_in << " "<<  secondaryBarions_in << G4endl;

        G4double mass_final= GetIonMass(currentZ,currentA);

        G4double correction= secondaryMass_in + mass_initial - mass_final;
        if (secondaries_in>1)
        {correction /= secondaries_in;}

#ifdef debug_BIC_CorrectBarionsOnBoundary
        G4cout << "CorrectBarionsOnBoundary,currentZ,currentA,"
                << "secondaryCharge_in,secondaryBarions_in,"
                << "energy correction,m_secondry,m_nucl_init,m_nucl_final "
                << currentZ << " "<< currentA <<" "
                << secondaryCharge_in<<" "<<secondaryBarions_in<<" "
                << correction << " "
                << secondaryMass_in << " "
                << mass_initial << " "
                << mass_final << " "
                << G4endl;
        PrintKTVector(in,std::string("in be4 correction"));
#endif
        for ( iter = in->cbegin(); iter != in->cend(); ++iter)
        {
            if ((*iter)->GetTrackingMomentum().e()+correction > (*iter)->GetActualMass())
            {
                (*iter)->UpdateTrackingMomentum((*iter)->GetTrackingMomentum().e() + correction);
            } else {
                //particle cannot go in, put to miss_nucleus
                G4RKPropagation * RKprop=(G4RKPropagation *)thePropagator;
                (*iter)->SetState(G4KineticTrack::miss_nucleus);
                // Undo correction for Colomb Barrier
                G4double barrier=RKprop->GetBarrier((*iter)->GetDefinition()->GetPDGEncoding());
                (*iter)->UpdateTrackingMomentum((*iter)->GetTrackingMomentum().e() + barrier);
                if ( ! kt_fail ) kt_fail=new G4KineticTrackVector;
                kt_fail->push_back(*iter);
                currentZ -= G4lrint((*iter)->GetDefinition()->GetPDGCharge()/eplus);
                currentA -= (*iter)->GetDefinition()->GetBaryonNumber();

            }

        }
#ifdef debug_BIC_CorrectBarionsOnBoundary
        G4cout << " CorrectBarionsOnBoundary, aft, Z, A, sec-Z,A,m,m_in_nucleus "
                << currentZ << " " << currentA << " "
                << secondaryCharge_in << " " << secondaryBarions_in << " "
                << secondaryMass_in  << " "
                << G4endl;
        PrintKTVector(in,std::string("in AFT correction"));
#endif

    }
    //----------------------------------------------
    if (out->size())
    {
        G4int secondaries_out(0);
        G4int secondaryBarions_out(0);
        G4int secondaryCharge_out(0);
        G4double secondaryMass_out(0);

        for ( iter = out->cbegin(); iter != out->cend(); ++iter)
        {
            ++secondaries_out;
            secondaryCharge_out += G4lrint((*iter)->GetDefinition()->GetPDGCharge()/eplus);
            if ((*iter)->GetDefinition()->GetBaryonNumber() !=0 )
            {
                secondaryBarions_out += (*iter)->GetDefinition()->GetBaryonNumber();
                if((*iter)->GetDefinition() == G4Neutron::Neutron() ||
                        (*iter)->GetDefinition() == G4Proton::Proton()  )
                {
                    secondaryMass_out += (*iter)->GetDefinition()->GetPDGMass();
                } else {
                    secondaryMass_out += G4Neutron::Neutron()->GetPDGMass();
                }
            }
        }

        G4double mass_initial=  GetIonMass(currentZ,currentA);
        currentA -=secondaryBarions_out;
        currentZ -=secondaryCharge_out;

        //  G4cout << "CorrectBarionsOnBoundary,secondaryCharge_out, secondaryBarions_out "
        //         <<    secondaryCharge_out << " "<<  secondaryBarions_out << G4endl;

        //                        a delta minus will do currentZ < 0 in light nuclei
        //     if (currentA < 0 || currentZ < 0 )
        if (currentA < 0 )
        {
            G4cerr << "G4BinaryCascade - secondaryBarions_out,secondaryCharge_out " <<
                    secondaryBarions_out << " " << secondaryCharge_out << G4endl;
            PrintKTVector(&theTargetList,"CorrectBarionsOnBoundary Target");
            PrintKTVector(&theCapturedList,"CorrectBarionsOnBoundary Captured");
            PrintKTVector(&theSecondaryList,"CorrectBarionsOnBoundary Secondaries");
            G4cerr << "G4BinaryCascade - currentA, currentZ " << currentA << " " << currentZ << G4endl;
            throw G4HadronicException(__FILE__, __LINE__, "G4BinaryCascade::CorrectBarionsOnBoundary() - fatal error");
        }
        G4double mass_final=GetIonMass(currentZ,currentA);
        G4double correction= mass_initial - mass_final - secondaryMass_out;
        // G4cout << "G4BinaryCascade::CorrectBarionsOnBoundary() total out correction: " << correction << G4endl;

        if (secondaries_out>1) correction /= secondaries_out;
#ifdef debug_BIC_CorrectBarionsOnBoundary
        G4cout << "DoTimeStep,(current Z,A),"
                << "(secondaries out,Charge,Barions),"
                <<"* energy correction,(m_secondry,m_nucl_init,m_nucl_final) "
                << "("<< currentZ << ","<< currentA <<") ("
                << secondaries_out << ","
                << secondaryCharge_out<<","<<secondaryBarions_out<<") * "
                << correction << " ("
                << secondaryMass_out << ", "
                << mass_initial << ", "
                << mass_final << ")"
                << G4endl;
        PrintKTVector(out,std::string("out be4 correction"));
#endif

        for ( iter = out->cbegin(); iter != out->cend(); ++iter)
        {
            if ((*iter)->GetTrackingMomentum().e()+correction > (*iter)->GetActualMass())
            {
                (*iter)->UpdateTrackingMomentum((*iter)->GetTrackingMomentum().e() + correction);
            } else
            {
                // particle cannot go out due to change of nuclear potential!
                //  capture protons and neutrons;
                if(((*iter)->GetDefinition() == G4Proton::Proton()) ||
                        ((*iter)->GetDefinition() == G4Neutron::Neutron()))
                {
                    (*iter)->SetState(G4KineticTrack::captured);
                    // Undo correction for Colomb Barrier
                    G4double barrier=((G4RKPropagation *)thePropagator)->GetBarrier((*iter)->GetDefinition()->GetPDGEncoding());
                    (*iter)->UpdateTrackingMomentum((*iter)->GetTrackingMomentum().e() - barrier);
                    if ( kt_fail == 0 ) kt_fail=new G4KineticTrackVector;
                    kt_fail->push_back(*iter);
                    currentZ += G4lrint((*iter)->GetDefinition()->GetPDGCharge()/eplus);
                    currentA += (*iter)->GetDefinition()->GetBaryonNumber();
                }
#ifdef debug_BIC_CorrectBarionsOnBoundary
                else
                {
                    G4cout << "Not correcting outgoing " << *iter << " "
                            << (*iter)->GetDefinition()->GetPDGEncoding() << " "
                            << (*iter)->GetDefinition()->GetParticleName() << G4endl;
                    PrintKTVector(out,std::string("outgoing, one not corrected"));
                }
#endif
            }
        }

#ifdef debug_BIC_CorrectBarionsOnBoundary
        PrintKTVector(out,std::string("out AFTER correction"));
        G4cout << " DoTimeStep, nucl-update, A, Z, sec-Z,A,m,m_in_nucleus, table-mass, delta "
                << currentA << " "<< currentZ << " "
                << secondaryCharge_out << " "<< secondaryBarions_out << " "<<
                secondaryMass_out << " "
                << massInNucleus << " "
                << GetIonMass(currentZ,currentA)
                << " " << massInNucleus - GetIonMass(currentZ,currentA)
                << G4endl;
#endif
    }

    return kt_fail;
}


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

G4Fragment * G4BinaryCascade::FindFragments()
//----------------------------------------------------------------------------
{

#ifdef debug_BIC_FindFragments
    G4cout << "target, captured, secondary: "
            << theTargetList.size() << " "
            << theCapturedList.size()<< " "
            << theSecondaryList.size()
            << G4endl;
#endif

    G4int a = G4int(theTargetList.size()+theCapturedList.size());
    G4int zTarget = 0;
    for(auto i = theTargetList.cbegin(); i != theTargetList.cend(); ++i)
    {
        if(G4lrint((*i)->GetDefinition()->GetPDGCharge()/eplus) == 1 )
        {
            zTarget++;
        }
    }

    G4int zCaptured = 0;
    G4LorentzVector CapturedMomentum(0.,0.,0.,0.);
    for(auto i = theCapturedList.cbegin(); i != theCapturedList.cend(); ++i)
    {
        CapturedMomentum += (*i)->Get4Momentum();
        if(G4lrint((*i)->GetDefinition()->GetPDGCharge()/eplus) == 1 )
        {
            zCaptured++;
        }
    }

    G4int z = zTarget+zCaptured;

#ifdef debug_G4BinaryCascade
    if ( z != (GetTotalCharge(theTargetList) + GetTotalCharge(theCapturedList)) )
    {
        G4cout << " FindFragment Counting error z a " << z << " " <<a << " "
                << GetTotalCharge(theTargetList) << " " <<  GetTotalCharge(theCapturedList)<<
                G4endl;
        PrintKTVector(&theTargetList, std::string("theTargetList"));
        PrintKTVector(&theCapturedList, std::string("theCapturedList"));
    }
#endif
    //debug
    /*
     *   G4cout << " Fragment mass table / real "
     *          << GetIonMass(z, a)
     * 	 << " / " << GetFinal4Momentum().mag()
     * 	 << " difference "
     * 	 <<  GetFinal4Momentum().mag() - GetIonMass(z, a)
     * 	 << G4endl;
     */
    //
    //  if(fBCDEBUG) G4cerr << "Fragment A, Z "<< a <<" "<< z<<G4endl;
    if ( z < 1 ) return 0;

    G4int holes = G4int(the3DNucleus->GetMassNumber() - theTargetList.size());
    G4int excitons = (G4int)theCapturedList.size();
#ifdef debug_BIC_FindFragments
    G4cout << "Fragment: a= " << a << " z= " << z << " particles= " <<  excitons
            << " Charged= " << zCaptured << " holes= " << holes
            << " excitE= " <<GetExcitationEnergy()
            << " Final4Momentum= " << GetFinalNucleusMomentum() << " capturMomentum= " << CapturedMomentum
            << G4endl;
#endif

    G4Fragment * fragment = new G4Fragment(a,z,GetFinalNucleusMomentum());
    fragment->SetNumberOfHoles(holes);

    //GF  fragment->SetNumberOfParticles(excitons-holes);
    fragment->SetNumberOfParticles(excitons);
    fragment->SetNumberOfCharged(zCaptured);
    fragment->SetCreatorModelID(theBIC_ID);

    return fragment;
}

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

G4LorentzVector G4BinaryCascade::GetFinal4Momentum()
//----------------------------------------------------------------------------
// Return momentum of reminder nulceus;
//  ie. difference of (initial state(primaries+nucleus) - final state) particles, ignoring remnant nucleus
{
    G4LorentzVector final4Momentum = theInitial4Mom + theProjectile4Momentum;
    G4LorentzVector finals(0,0,0,0);
    for(auto i = theFinalState.cbegin(); i != theFinalState.cend(); ++i)
    {
        final4Momentum -= (*i)->Get4Momentum();
        finals		   += (*i)->Get4Momentum();
    }

    if(final4Momentum.e()> 0 && (final4Momentum.vect()/final4Momentum.e()).mag()>1.0 && currentA > 0)
    {
#ifdef debug_BIC_Final4Momentum
        G4cerr << G4endl;
        G4cerr << "G4BinaryCascade::GetFinal4Momentum - Fatal"<<G4endl;
        G4KineticTrackVector::iterator i;
        G4cerr <<"Total initial 4-momentum " << theProjectile4Momentum << G4endl;
        G4cerr <<" GetFinal4Momentum: Initial nucleus "<<theInitial4Mom<<G4endl;
        for(i = theFinalState.begin(); i != theFinalState.end(); ++i)
        {
            G4cerr <<" Final state: "<<(*i)->Get4Momentum()<<(*i)->GetDefinition()->GetParticleName()<<G4endl;
        }
        G4cerr << "Sum( 4-mom ) finals " << finals << G4endl;
        G4cerr<< " Final4Momentum = "<<final4Momentum <<" "<<final4Momentum.m()<<G4endl;
        G4cerr <<" current A, Z = "<< currentA<<", "<<currentZ<<G4endl;
        G4cerr << G4endl;
#endif

        final4Momentum=G4LorentzVector(0,0,0,0);
    }
    return final4Momentum;
}

//----------------------------------------------------------------------------
G4LorentzVector G4BinaryCascade::GetFinalNucleusMomentum()
//----------------------------------------------------------------------------
{
    // return momentum of nucleus for use with precompound model; also keep transformation to
    //   apply to precompoud products.

    G4LorentzVector CapturedMomentum(0,0,0,0);
    //  G4cout << "GetFinalNucleusMomentum Captured size: " <<theCapturedList.size() << G4endl;
    for(auto i = theCapturedList.cbegin(); i != theCapturedList.cend(); ++i)
    {
        CapturedMomentum += (*i)->Get4Momentum();
    }
    //G4cout << "GetFinalNucleusMomentum CapturedMomentum= " <<CapturedMomentum << G4endl;
    //  G4cerr << "it 9"<<G4endl;

    G4LorentzVector NucleusMomentum = GetFinal4Momentum();
    if ( NucleusMomentum.e() > 0 )
    {
        // G4cout << "GetFinalNucleusMomentum GetFinal4Momentum= " <<NucleusMomentum <<" "<<NucleusMomentum.mag()<<G4endl;
        // boost nucleus to a frame such that the momentum of nucleus == momentum of Captured
        G4ThreeVector boost= (NucleusMomentum.vect() -CapturedMomentum.vect())/NucleusMomentum.e();
        if(boost.mag2()>1.0)
        {
#     ifdef debug_BIC_FinalNucleusMomentum
            G4cerr << "G4BinaryCascade::GetFinalNucleusMomentum - Fatal"<<G4endl;
            G4cerr << "it 0"<<boost <<G4endl;
            G4cerr << "it 01"<<NucleusMomentum<<" "<<CapturedMomentum<<" "<<G4endl;
            G4cout <<" testing boost "<<boost<<" "<<boost.mag()<<G4endl;
#      endif
            boost=G4ThreeVector(0,0,0);
            NucleusMomentum=G4LorentzVector(0,0,0,0);
        }
        G4LorentzRotation  nucleusBoost( -boost );
        precompoundLorentzboost.set( boost );
#ifdef debug_debug_BIC_FinalNucleusMomentum
        G4cout << "GetFinalNucleusMomentum be4 boostNucleusMomentum, CapturedMomentum"<<NucleusMomentum<<" "<<CapturedMomentum<<" "<<G4endl;
#endif
        NucleusMomentum *= nucleusBoost;
#ifdef debug_BIC_FinalNucleusMomentum
        G4cout << "GetFinalNucleusMomentum aft boost GetFinal4Momentum= " <<NucleusMomentum <<G4endl;
#endif
    }
    return NucleusMomentum;
}

//----------------------------------------------------------------------------
G4ReactionProductVector * G4BinaryCascade::Propagate1H1(
        //----------------------------------------------------------------------------
        G4KineticTrackVector * secondaries, G4V3DNucleus * nucleus)
{
    G4ReactionProductVector * products = new G4ReactionProductVector;
    const G4ParticleDefinition * aHTarg = G4Proton::ProtonDefinition();
    if (nucleus->GetCharge() == 0) aHTarg = G4Neutron::NeutronDefinition();
    G4double mass = aHTarg->GetPDGMass();
    G4KineticTrackVector * secs = nullptr;
    G4ThreeVector pos(0,0,0);
    G4LorentzVector mom(mass);
    G4KineticTrack aTarget(aHTarg, 0., pos, mom);
    G4bool done(false);
    // data member    static G4Scatterer theH1Scatterer;
    //G4cout << " start 1H1 for " << (*secondaries).front()->GetDefinition()->GetParticleName()
    //       << " on " << aHTarg->GetParticleName() << G4endl;
    G4int tryCount(0);
    while(!done && tryCount++ <200)                                 /* Loop checking, 31.08.2015, G.Folger */
    {
        if(secs)
        {
            std::for_each(secs->begin(), secs->end(), DeleteKineticTrack());
            delete secs;
        }
        secs = theH1Scatterer->Scatter(*(*secondaries).front(), aTarget);
#ifdef debug_H1_BinaryCascade
        PrintKTVector(secs," From Scatter");
#endif
        for(std::size_t ss=0; secs && ss<secs->size(); ++ss)
        {
            // must have one resonance in final state, or it was elastic, not allowed here.
            if((*secs)[ss]->GetDefinition()->IsShortLived()) done = true;
        }
    }

    ClearAndDestroy(&theFinalState);
    ClearAndDestroy(secondaries);
    delete secondaries;

    for(std::size_t current=0; secs && current<secs->size(); ++current)
    {
        if((*secs)[current]->GetDefinition()->IsShortLived())
        {
            done = true; 	// must have one resonance in final state, elastic not allowed here!
            G4KineticTrackVector * dec = (*secs)[current]->Decay();
            for(auto jter=dec->cbegin(); jter != dec->cend(); ++jter)
            {
                //G4cout << "Decay"<<G4endl;
                secs->push_back(*jter);
                //G4cout << "decay "<<(*jter)->GetDefinition()->GetParticleName()<<G4endl;
            }
            delete (*secs)[current];
            delete dec;
        }
        else
        {
            //G4cout << "FS "<<G4endl;
            //G4cout << "FS "<<(*secs)[current]->GetDefinition()->GetParticleName()<<G4endl;
            theFinalState.push_back((*secs)[current]);
        }
    }

    delete secs;
#ifdef debug_H1_BinaryCascade
    PrintKTVector(&theFinalState," FinalState");
#endif
    for(auto iter = theFinalState.cbegin(); iter != theFinalState.cend(); ++iter)
    {
        G4KineticTrack * kt = *iter;
        G4ReactionProduct * aNew = new G4ReactionProduct(kt->GetDefinition());
        aNew->SetMomentum(kt->Get4Momentum().vect());
        aNew->SetTotalEnergy(kt->Get4Momentum().e());
        aNew->SetCreatorModelID(theBIC_ID);
        aNew->SetParentResonanceDef(kt->GetParentResonanceDef());
        aNew->SetParentResonanceID(kt->GetParentResonanceID());	
        products->push_back(aNew);
#ifdef debug_H1_BinaryCascade
        if (! kt->GetDefinition()->GetPDGStable() )
        {
            if (kt->GetDefinition()->IsShortLived())
            {
                G4cout << "final shortlived : ";
            } else
            {
                G4cout << "final un stable : ";
            }
            G4cout <<kt->GetDefinition()->GetParticleName()<< G4endl;
        }
#endif
        delete kt;
    }
    theFinalState.clear();
    return products;

}

//----------------------------------------------------------------------------
G4ThreeVector G4BinaryCascade::GetSpherePoint(
        G4double r, const G4LorentzVector & mom4)
//----------------------------------------------------------------------------
{
    //  Get a point outside radius.
    //     point is random in plane (circle of radius r) orthogonal to mom,
    //      plus -1*r*mom->vect()->unit();
    G4ThreeVector o1, o2;
    G4ThreeVector mom = mom4.vect();

    o1= mom.orthogonal();  // we simply need any vector non parallel
    o2= mom.cross(o1);     //  o2 is now orthogonal to mom and o1, ie. o1 and o2  define plane.

    G4double x2, x1;

    do
    {
        x1=(G4UniformRand()-.5)*2;
        x2=(G4UniformRand()-.5)*2;
    } while (sqr(x1) +sqr(x2) > 1.);                      /* Loop checking, 31.08.2015, G.Folger */ // or random is badly broken.....

    return G4ThreeVector(r*(x1*o1.unit() + x2*o2.unit() - 1.5* mom.unit()));



    /*
     * // Get a point uniformly distributed on the surface of a sphere,
     * // with z < 0.
     *   G4double b = r*G4UniformRand();  // impact parameter
     *   G4double phi = G4UniformRand()*2*pi;
     *   G4double x = b*std::cos(phi);
     *   G4double y = b*std::sin(phi);
     *   G4double z = -std::sqrt(r*r-b*b);
     *   z *= 1.001; // Get position a little bit out of the sphere...
     *   point.setX(x);
     *   point.setY(y);
     *   point.setZ(z);
     */
}

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

void G4BinaryCascade::ClearAndDestroy(G4KineticTrackVector * ktv)
//----------------------------------------------------------------------------
{
    for(auto i = ktv->cbegin(); i != ktv->cend(); ++i)
        delete (*i);
    ktv->clear();
}

//----------------------------------------------------------------------------
void G4BinaryCascade::ClearAndDestroy(G4ReactionProductVector * rpv)
//----------------------------------------------------------------------------
{
    for(auto i = rpv->cbegin(); i != rpv->cend(); ++i)
        delete (*i);
    rpv->clear();
}

//----------------------------------------------------------------------------
void G4BinaryCascade::PrintKTVector(G4KineticTrackVector * ktv, const G4String& comment)
//----------------------------------------------------------------------------
{
    if (comment.size() > 0 ) G4cout << "G4BinaryCascade::PrintKTVector() " << comment << G4endl;
    if (ktv) {
        G4cout << "  vector: " << ktv << ", number of tracks: " << ktv->size()
			         << G4endl;
        std::vector<G4KineticTrack *>::const_iterator i;
        G4int count;

        for(count = 0, i = ktv->cbegin(); i != ktv->cend(); ++i, ++count)
        {
            G4KineticTrack * kt = *i;
            G4cout << "  track n. " << count;
            PrintKTVector(kt);
        }
    } else {
        G4cout << "G4BinaryCascade::PrintKTVector():No KineticTrackVector given " << G4endl;
    }
}
//----------------------------------------------------------------------------
void G4BinaryCascade::PrintKTVector(G4KineticTrack * kt, const G4String& comment)
//----------------------------------------------------------------------------
{
    if (comment.size() > 0 ) G4cout << "G4BinaryCascade::PrintKTVector() "<< comment << G4endl;
    if ( kt ){
        G4cout << ", id: " << kt << G4endl;
        G4ThreeVector pos = kt->GetPosition();
        G4LorentzVector mom = kt->Get4Momentum();
        G4LorentzVector tmom = kt->GetTrackingMomentum();
        const G4ParticleDefinition * definition = kt->GetDefinition();
        G4cout << "    definition: " << definition->GetPDGEncoding() << " pos: "
                << 1/fermi*pos << " R: " << 1/fermi*pos.mag() << " 4mom: "
                << 1/MeV*mom <<"Tr_mom" <<  1/MeV*tmom << " P: " << 1/MeV*mom.vect().mag()
                << " M: " << 1/MeV*mom.mag() << G4endl;
        G4cout <<"    trackstatus: "<<kt->GetState() << " isParticipant " << (kt->IsParticipant()?"T":"F")   <<G4endl;
    } else {
        G4cout << "G4BinaryCascade::PrintKTVector(): No Kinetictrack given" << G4endl;
    }
}


//----------------------------------------------------------------------------
G4double G4BinaryCascade::GetIonMass(G4int Z, G4int A)
//----------------------------------------------------------------------------
{
    G4double mass(0);
    if ( Z > 0 && A >= Z )
    {
        mass = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIonMass(Z,A);

    } else if ( A > 0 && Z>0 )
    {
        // charge Z > A; will happen for light nuclei with pions involved.
        mass = G4ParticleTable::GetParticleTable()->GetIonTable()->GetIonMass(A,A);

    } else if ( A >= 0 && Z<=0 )
    {
        // all neutral, or empty nucleus
        mass = A * G4Neutron::Neutron()->GetPDGMass();

    } else if ( A == 0  )
    {
        // empty nucleus, except maybe pions
        mass = 0;

    } else
    {
        G4cerr << "G4BinaryCascade::GetIonMass() - invalid (A,Z) = ("
                << A << "," << Z << ")" <<G4endl;
        throw G4HadronicException(__FILE__, __LINE__, "G4BinaryCascade::GetIonMass() - giving up");

    }
	 //  G4cout << "G4BinaryCascade::GetIonMass() Z, A, mass " << Z << " " << A << " " << mass << G4endl;
    return mass;
}
G4ReactionProductVector * G4BinaryCascade::FillVoidNucleusProducts(G4ReactionProductVector * products)
{
    // return product when nucleus is destroyed, i.e. charge=0, or theTargetList.size()=0
    G4double Esecondaries(0.);
    G4LorentzVector psecondaries;
    std::vector<G4KineticTrack *>::const_iterator iter;
    std::vector<G4ReactionProduct *>::const_iterator rpiter;
    decayKTV.Decay(&theFinalState);

    for(iter = theFinalState.cbegin(); iter != theFinalState.cend(); ++iter)
    {
        G4ReactionProduct * aNew = new G4ReactionProduct((*iter)->GetDefinition());
        aNew->SetMomentum((*iter)->Get4Momentum().vect());
        aNew->SetTotalEnergy((*iter)->Get4Momentum().e());
        aNew->SetCreatorModelID(theBIC_ID);
	aNew->SetParentResonanceDef((*iter)->GetParentResonanceDef());
	aNew->SetParentResonanceID((*iter)->GetParentResonanceID());	
        Esecondaries +=(*iter)->Get4Momentum().e();
        psecondaries +=(*iter)->Get4Momentum();
        aNew->SetNewlyAdded(true);
        //G4cout << " Particle Ekin " << aNew->GetKineticEnergy() << G4endl;
        products->push_back(aNew);
    }

    // pull out late particles from collisions
    //theCollisionMgr->Print();
    while(theCollisionMgr->Entries() > 0)        /* Loop checking, 31.08.2015, G.Folger */
    {
        G4CollisionInitialState *
        collision = theCollisionMgr->GetNextCollision();

        if ( ! collision->GetTargetCollection().size() ){
            G4KineticTrackVector * lates = collision->GetFinalState();
            if ( lates->size() == 1 ) {
                G4KineticTrack * atrack=*(lates->begin());
                //PrintKTVector(atrack, " late particle @ void Nucl ");

                G4ReactionProduct * aNew = new G4ReactionProduct(atrack->GetDefinition());
                aNew->SetMomentum(atrack->Get4Momentum().vect());
                aNew->SetTotalEnergy(atrack->Get4Momentum().e());
                aNew->SetCreatorModelID(atrack->GetCreatorModelID());
		aNew->SetParentResonanceDef(atrack->GetParentResonanceDef());
		aNew->SetParentResonanceID(atrack->GetParentResonanceID());		
                Esecondaries +=atrack->Get4Momentum().e();
                psecondaries +=atrack->Get4Momentum();
                aNew->SetNewlyAdded(true);
                products->push_back(aNew);

            }
        }
        theCollisionMgr->RemoveCollision(collision);

    }

    // decay must be after loop on Collisions, and Decay() will delete entries in theSecondaryList, refered
    //   to by Collisions.
    decayKTV.Decay(&theSecondaryList);

    // Correct for momentum transfered to Nucleus
    G4ThreeVector transferCorrection(0);
    if ( (theSecondaryList.size() + theCapturedList.size()) > 0)
    {
    	transferCorrection= theMomentumTransfer /(theSecondaryList.size() + theCapturedList.size());
    }

    for(iter = theSecondaryList.cbegin(); iter != theSecondaryList.cend(); ++iter)
    {
        G4ReactionProduct * aNew = new G4ReactionProduct((*iter)->GetDefinition());
        (*iter)->Update4Momentum((*iter)->Get4Momentum().vect()+transferCorrection);
        aNew->SetMomentum((*iter)->Get4Momentum().vect());
        aNew->SetTotalEnergy((*iter)->Get4Momentum().e());
        aNew->SetCreatorModelID(theBIC_ID);
	aNew->SetParentResonanceDef((*iter)->GetParentResonanceDef());
	aNew->SetParentResonanceID((*iter)->GetParentResonanceID());	
        Esecondaries +=(*iter)->Get4Momentum().e();
        psecondaries +=(*iter)->Get4Momentum();
        if ( (*iter)->IsParticipant() ) aNew->SetNewlyAdded(true);
        products->push_back(aNew);
    }

    for(iter = theCapturedList.cbegin(); iter != theCapturedList.cend(); ++iter)
    {
        G4ReactionProduct * aNew = new G4ReactionProduct((*iter)->GetDefinition());
        (*iter)->Update4Momentum((*iter)->Get4Momentum().vect()+transferCorrection);
        aNew->SetMomentum((*iter)->Get4Momentum().vect());
        aNew->SetTotalEnergy((*iter)->Get4Momentum().e());
        aNew->SetCreatorModelID(theBIC_ID);
	aNew->SetParentResonanceDef((*iter)->GetParentResonanceDef());
	aNew->SetParentResonanceID((*iter)->GetParentResonanceID());	
        Esecondaries +=(*iter)->Get4Momentum().e();
        psecondaries +=(*iter)->Get4Momentum();
        aNew->SetNewlyAdded(true);
        products->push_back(aNew);
    }

    G4double SumMassNucleons(0.);
    G4LorentzVector pNucleons(0.);
    for(iter = theTargetList.cbegin(); iter != theTargetList.cend(); ++iter)
    {
        SumMassNucleons += (*iter)->GetDefinition()->GetPDGMass();
        pNucleons += (*iter)->Get4Momentum();
    }

    G4double Ekinetic=theProjectile4Momentum.e() + initial_nuclear_mass - Esecondaries - SumMassNucleons;
     #ifdef debug_BIC_FillVoidnucleus
        G4LorentzVector deltaP=theProjectile4Momentum + G4LorentzVector(initial_nuclear_mass) -
    		                psecondaries - pNucleons;
        //G4cout << "BIC::FillVoidNucleus() nucleons : "<<theTargetList.size() << " ,  T: " << Ekinetic <<
    	//	     ", deltaP " <<  deltaP << " deltaPNoNucl " << deltaP + pNucleons << G4endl;
     #endif
    if (Ekinetic > 0. && theTargetList.size()){
        Ekinetic /= theTargetList.size();
    } else {
        G4double Ekineticrdm(0);
        if (theTargetList.size()) Ekineticrdm = ( 0.1 + G4UniformRand()*5.) * MeV;	// leave some  Energy for Nucleons
      	G4double TotalEkin(Ekineticrdm);
        for (rpiter=products->cbegin(); rpiter!=products->cend(); ++rpiter){
        	TotalEkin+=(*rpiter)->GetKineticEnergy();
        }
        G4double correction(1.);
        if ( std::abs(Ekinetic) < 20*perCent * TotalEkin ){
        	correction=1. + (Ekinetic-Ekineticrdm)/TotalEkin;   // Ekinetic < 0 == IS < FS, need to reduce energies
        }
        #ifdef debug_G4BinaryCascade
			else {
				G4cout << "BLIC::FillVoidNucleus() fail correction, Ekinetic, TotalEkin " << Ekinetic << ""<< TotalEkin << G4endl;
			}
        #endif

        for (rpiter=products->cbegin(); rpiter!=products->cend(); ++rpiter){
	    	(*rpiter)->SetKineticEnergy((*rpiter)->GetKineticEnergy()*correction);  // this sets kinetic & total energy
        	(*rpiter)->SetMomentum((*rpiter)->GetTotalMomentum() * (*rpiter)->GetMomentum().unit());

        }

        Ekinetic=Ekineticrdm*correction;
        if (theTargetList.size())Ekinetic /= theTargetList.size();

	}

    for(iter = theTargetList.cbegin(); iter != theTargetList.cend(); ++iter) {
    	// set Nucleon it to be hit - as it is in fact
    	(*iter)->Hit();
        G4ReactionProduct * aNew = new G4ReactionProduct((*iter)->GetDefinition());
        aNew->SetKineticEnergy(Ekinetic);
        aNew->SetMomentum(aNew->GetTotalMomentum() * ((*iter)->Get4Momentum().vect().unit()));
        aNew->SetNewlyAdded(true);
        aNew->SetCreatorModelID(theBIC_ID);
	aNew->SetParentResonanceDef((*iter)->GetParentResonanceDef());
	aNew->SetParentResonanceID((*iter)->GetParentResonanceID());	
        products->push_back(aNew);
        Esecondaries += aNew->GetTotalEnergy();
        psecondaries += G4LorentzVector(aNew->GetMomentum(),aNew->GetTotalEnergy() );
    }
    psecondaries=G4LorentzVector(0);
    for (rpiter=products->cbegin(); rpiter!=products->cend(); ++rpiter){
    	psecondaries += G4LorentzVector((*rpiter)->GetMomentum(),(*rpiter)->GetTotalEnergy() );
    }

    G4LorentzVector initial4Mom=theProjectile4Momentum + G4LorentzVector(initial_nuclear_mass);

    //G4cout << "::FillVoidNucleus()final e/p conservation initial" <<initial4Mom
    //	<< " final " << psecondaries << " delta " << initial4Mom-psecondaries << G4endl;

    G4ThreeVector SumMom=psecondaries.vect();

    SumMom=initial4Mom.vect()-SumMom;
    G4int loopcount(0);

    // reverse_iterator reverse - start to correct last added first
    while ( SumMom.mag() > 0.1*MeV && loopcount++ < 10)           /* Loop checking, 31.08.2015, G.Folger */
    {
      G4int index=(G4int)products->size();
      for (auto reverse=products->crbegin(); reverse!=products->crend(); ++reverse, --index){
        SumMom=initial4Mom.vect();
        for (rpiter=products->cbegin(); rpiter!=products->cend(); ++rpiter){
          SumMom-=(*rpiter)->GetMomentum();
        }
        G4double p=((*reverse)->GetMomentum()).mag();
        (*reverse)->SetMomentum(  p*(((*reverse)->GetMomentum()+SumMom).unit()));
      }
    }
    return products;
}

G4ReactionProductVector * G4BinaryCascade::HighEnergyModelFSProducts(G4ReactionProductVector * products,
        G4KineticTrackVector * secondaries)
{
    for(auto iter = secondaries->cbegin(); iter != secondaries->cend(); ++iter)
    {
        G4ReactionProduct * aNew = new G4ReactionProduct((*iter)->GetDefinition());
        aNew->SetMomentum((*iter)->Get4Momentum().vect());
        aNew->SetTotalEnergy((*iter)->Get4Momentum().e());
        aNew->SetNewlyAdded(true);
        aNew->SetCreatorModelID((*iter)->GetCreatorModelID());
        aNew->SetParentResonanceDef((*iter)->GetParentResonanceDef());
        aNew->SetParentResonanceID((*iter)->GetParentResonanceID());
        //G4cout << " Particle Ekin " << aNew->GetKineticEnergy() << G4endl;
        products->push_back(aNew);
    }
    const G4ParticleDefinition* fragment = 0;
    if (currentA == 1 && currentZ == 0) {
        fragment = G4Neutron::NeutronDefinition();
    } else if (currentA == 1 && currentZ == 1) {
        fragment = G4Proton::ProtonDefinition();
    } else if (currentA == 2 && currentZ == 1) {
        fragment = G4Deuteron::DeuteronDefinition();
    } else if (currentA == 3 && currentZ == 1) {
        fragment = G4Triton::TritonDefinition();
    } else if (currentA == 3 && currentZ == 2) {
        fragment = G4He3::He3Definition();
    } else if (currentA == 4 && currentZ == 2) {
        fragment = G4Alpha::AlphaDefinition();;
    } else {
        fragment =
                G4ParticleTable::GetParticleTable()->GetIonTable()->GetIon(currentZ,currentA,0.0);
    }
    if (fragment != 0) {
        G4ReactionProduct * theNew = new G4ReactionProduct(fragment);
        theNew->SetMomentum(G4ThreeVector(0,0,0));
        theNew->SetTotalEnergy(massInNucleus);
        theNew->SetCreatorModelID(theBIC_ID);
        //theNew->SetFormationTime(??0.??);
        //G4cout << " Nucleus (" << currentZ << ","<< currentA << "), mass "<< massInNucleus << G4endl;
        products->push_back(theNew);
    }
    return products;
}

void G4BinaryCascade::PrintWelcomeMessage()
{
    G4cout <<"Thank you for using G4BinaryCascade. "<<G4endl;
}

//----------------------------------------------------------------------------
void G4BinaryCascade::DebugApplyCollisionFail(G4CollisionInitialState * collision,
      G4KineticTrackVector * products)
{
   G4bool havePion=false;
   if (products)
   {
      for ( auto i =products->cbegin(); i != products->cend(); ++i)
      {
         G4int PDGcode=std::abs((*i)->GetDefinition()->GetPDGEncoding());
         if (std::abs(PDGcode)==211 || PDGcode==111 ) havePion=true;
      }
   }
   if ( !products  || havePion)
   {
      const G4BCAction &action= *collision->GetGenerator();
      G4cout << " Collision " << collision << ", type: "<< typeid(action).name()
							                    << ", with NO products! " <<G4endl;
      G4cout << G4endl<<"Initial condition are these:"<<G4endl;
      G4cout << "proj: "<<collision->GetPrimary()->GetDefinition()->GetParticleName()<<G4endl;
      PrintKTVector(collision->GetPrimary());
      for(std::size_t it=0; it<collision->GetTargetCollection().size(); ++it)
      {
         G4cout << "targ: "
               <<collision->GetTargetCollection()[it]->GetDefinition()->GetParticleName()<<G4endl;
      }
      PrintKTVector(&collision->GetTargetCollection(),std::string(" Target particles"));
   }
   //  if ( lateParticleCollision ) G4cout << " Added late particle--------------------------"<<G4endl;
   //  if ( lateParticleCollision && products ) PrintKTVector(products, " reaction products");
}

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

G4bool G4BinaryCascade::CheckChargeAndBaryonNumber(const G4String& where)
{
   static G4int lastdA(0), lastdZ(0);
   G4int iStateA = the3DNucleus->GetMassNumber() + projectileA;
   G4int iStateZ = the3DNucleus->GetCharge()  + projectileZ;

   G4int fStateA(0);
   G4int fStateZ(0);

   G4int CapturedA(0), CapturedZ(0);
   G4int secsA(0), secsZ(0);
   for (auto i=theCapturedList.cbegin(); i!=theCapturedList.cend(); ++i) {
      CapturedA += (*i)->GetDefinition()->GetBaryonNumber();
      CapturedZ += G4lrint((*i)->GetDefinition()->GetPDGCharge()/eplus);
   }

   for (auto i=theSecondaryList.cbegin(); i!=theSecondaryList.cend(); ++i) {
      if ( (*i)->GetState() != G4KineticTrack::inside ) {
         secsA += (*i)->GetDefinition()->GetBaryonNumber();
         secsZ += G4lrint((*i)->GetDefinition()->GetPDGCharge()/eplus);
      }
   }

   for (auto i=theFinalState.cbegin(); i!=theFinalState.cend(); ++i) {
      fStateA += (*i)->GetDefinition()->GetBaryonNumber();
      fStateZ += G4lrint((*i)->GetDefinition()->GetPDGCharge()/eplus);
   }

   G4int deltaA= iStateA -  secsA - fStateA -currentA - lateA;
   G4int deltaZ= iStateZ -  secsZ - fStateZ -currentZ - lateZ;

#ifdef debugCheckChargeAndBaryonNumberverbose	
	G4cout << where <<" A: iState= "<< iStateA<<", secs= "<< secsA<< ", fState= "<< fStateA<< ", current= "<<currentA<< ", late= " <<lateA << G4endl;   
	G4cout << where <<" Z: iState= "<< iStateZ<<", secs= "<< secsZ<< ", fState= "<< fStateZ<< ", current= "<<currentZ<< ", late= " <<lateZ << G4endl;   
#endif

   if (deltaA != 0  || deltaZ!=0 ) {
      if (deltaA != lastdA || deltaZ != lastdZ ) {
         G4cout << "baryon/charge imbalance - " << where << G4endl
               << "deltaA " <<deltaA<<", iStateA "<<iStateA<< ",  CapturedA "<<CapturedA <<",  secsA "<<secsA
               << ", fStateA "<<fStateA << ", currentA "<<currentA << ", lateA "<<lateA << G4endl
               << "deltaZ "<<deltaZ<<", iStateZ "<<iStateZ<< ",  CapturedZ "<<CapturedZ <<",  secsZ "<<secsZ
               << ", fStateZ "<<fStateZ << ", currentZ "<<currentZ << ", lateZ "<<lateZ << G4endl<< G4endl;
         lastdA=deltaA;
         lastdZ=deltaZ;
      }
   } else { lastdA=lastdZ=0;}

   return true;
}
//----------------------------------------------------------------------------
void G4BinaryCascade::DebugApplyCollision(G4CollisionInitialState * collision,
        G4KineticTrackVector * products)
{

    PrintKTVector(collision->GetPrimary(),std::string(" Primary particle"));
    PrintKTVector(&collision->GetTargetCollection(),std::string(" Target particles"));
    PrintKTVector(products,std::string(" Scatterer products"));

#ifdef dontUse
    G4double thisExcitation(0);
    //  excitation energy from this collision
    //  initial state:
    G4double initial(0);
    G4KineticTrack * kt=collision->GetPrimary();
    initial +=  kt->Get4Momentum().e();

    G4RKPropagation * RKprop=(G4RKPropagation *)thePropagator;

    initial +=  RKprop->GetField(kt->GetDefinition()->GetPDGEncoding(),kt->GetPosition());
    initial -=  RKprop->GetBarrier(kt->GetDefinition()->GetPDGEncoding());
    G4cout << "prim. E/field/Barr/Sum " << kt->Get4Momentum().e()
        		          << " " << RKprop->GetField(kt->GetDefinition()->GetPDGEncoding(),kt->GetPosition())
        		          << " " << RKprop->GetBarrier(kt->GetDefinition()->GetPDGEncoding())
        		          << " " << initial << G4endl;;

    G4KineticTrackVector ktv=collision->GetTargetCollection();
    for ( unsigned int it=0; it < ktv.size(); ++it)
    {
        kt=ktv[it];
        initial +=  kt->Get4Momentum().e();
        thisExcitation += kt->GetDefinition()->GetPDGMass()
     		    		         - kt->Get4Momentum().e()
     		    		         - RKprop->GetField(kt->GetDefinition()->GetPDGEncoding(),kt->GetPosition());
        //     initial +=  RKprop->GetField(kt->GetDefinition()->GetPDGEncoding(),kt->GetPosition());
        //     initial -=  RKprop->GetBarrier(kt->GetDefinition()->GetPDGEncoding());
        G4cout << "Targ. def/E/field/Barr/Sum " <<  kt->GetDefinition()->GetPDGEncoding()
  			          << " " << kt->Get4Momentum().e()
  			          << " " << RKprop->GetField(kt->GetDefinition()->GetPDGEncoding(),kt->GetPosition())
  			          << " " << RKprop->GetBarrier(kt->GetDefinition()->GetPDGEncoding())
  			          << " " << initial <<" Excit " << thisExcitation << G4endl;;
    }

    G4double fin(0);
    G4double mass_out(0);
    G4int product_barions(0);
    if ( products )
    {
        for ( unsigned int it=0; it < products->size(); ++it)
        {
            kt=(*products)[it];
            fin +=  kt->Get4Momentum().e();
            fin +=  RKprop->GetField(kt->GetDefinition()->GetPDGEncoding(),kt->GetPosition());
            fin +=  RKprop->GetBarrier(kt->GetDefinition()->GetPDGEncoding());
            if ( kt->GetDefinition()->GetBaryonNumber()==1 ) product_barions++;
            mass_out += kt->GetDefinition()->GetPDGMass();
            G4cout << "sec. def/E/field/Barr/Sum " << kt->GetDefinition()->GetPDGEncoding()
  	    		         << " " << kt->Get4Momentum().e()
  	    		         << " " << RKprop->GetField(kt->GetDefinition()->GetPDGEncoding(),kt->GetPosition())
  	    		         << " " << RKprop->GetBarrier(kt->GetDefinition()->GetPDGEncoding())
  	    		         << " " << fin << G4endl;;
        }
    }


    G4int finalA = currentA;
    G4int finalZ = currentZ;
    if ( products )
    {
        finalA -= product_barions;
        finalZ -= GetTotalCharge(*products);
    }
    G4double delta = GetIonMass(currentZ,currentA) - (GetIonMass(finalZ,finalA) + mass_out);
    G4cout << " current/final a,z " << currentA << " " << currentZ << " "<< finalA<< " "<< finalZ
            <<  " delta-mass " << delta<<G4endl;
    fin+=delta;
    mass_out  = GetIonMass(finalZ,finalA);
    G4cout << " initE/ E_out/ Mfinal/ Excit " << currentInitialEnergy
            << " " <<   fin << " "
            <<  mass_out<<" "
            <<  currentInitialEnergy - fin - mass_out
            << G4endl;
    currentInitialEnergy-=fin;
#endif
}

//----------------------------------------------------------------------------
G4bool G4BinaryCascade::DebugFinalEpConservation(const G4HadProjectile & aTrack,
        G4ReactionProductVector* products)
//----------------------------------------------------------------------------
{
    G4double Efinal(0);
    G4ThreeVector pFinal(0);
    if (std::abs(theParticleChange.GetWeightChange() -1 ) > 1e-5 )
    {
        G4cout <<" BIC-weight change " << theParticleChange.GetWeightChange()<< G4endl;
    }

    for(auto iter = products->cbegin(); iter != products->cend(); ++iter)
    {

        G4cout << " Secondary E - Ekin / p " <<
              (*iter)->GetDefinition()->GetParticleName() << " " <<
              (*iter)->GetTotalEnergy() << " - " <<
              (*iter)->GetKineticEnergy()<< " / " <<
              (*iter)->GetMomentum().x() << " " <<
              (*iter)->GetMomentum().y() << " " <<
              (*iter)->GetMomentum().z() << G4endl;
        Efinal += (*iter)->GetTotalEnergy();
        pFinal += (*iter)->GetMomentum();
    }

      G4cout << "e outgoing/ total : " << Efinal << " " << Efinal+GetFinal4Momentum().e()<< G4endl;
      G4cout << "BIC E/p delta " <<
            (aTrack.Get4Momentum().e()+theInitial4Mom.e() - Efinal)/MeV <<
            " MeV / mom " << (aTrack.Get4Momentum()  - pFinal ) /MeV << G4endl;

    return (aTrack.Get4Momentum().e() + theInitial4Mom.e() - Efinal)/aTrack.Get4Momentum().e() < perCent;

}
//----------------------------------------------------------------------------
G4bool G4BinaryCascade::DebugEpConservation(const G4String& where)
//----------------------------------------------------------------------------
{
    G4cout << where << G4endl;
    G4LorentzVector psecs,    ptgts,    pcpts,    pfins;
    if (std::abs(theParticleChange.GetWeightChange() -1 ) > 1e-5 )
    {
        G4cout <<" BIC-weight change " << theParticleChange.GetWeightChange()<< G4endl;
    }

    std::vector<G4KineticTrack *>::const_iterator ktiter;
    for(ktiter = theSecondaryList.cbegin(); ktiter != theSecondaryList.cend(); ++ktiter)
       {

              G4cout << " Secondary E - Ekin / p " <<
                 (*ktiter)->GetDefinition()->GetParticleName() << " " <<
                 (*ktiter)->Get4Momentum().e() << " - " <<
                 (*ktiter)->Get4Momentum().e() - (*ktiter)->Get4Momentum().mag() << " / " <<
                 (*ktiter)->Get4Momentum().vect() << G4endl;
           psecs += (*ktiter)->Get4Momentum();
       }

    for(ktiter = theTargetList.cbegin(); ktiter != theTargetList.cend(); ++ktiter)
       {

              G4cout << " Target E - Ekin / p " <<
                 (*ktiter)->GetDefinition()->GetParticleName() << " " <<
                 (*ktiter)->Get4Momentum().e() << " - " <<
                 (*ktiter)->Get4Momentum().e() - (*ktiter)->Get4Momentum().mag() << " / " <<
                 (*ktiter)->Get4Momentum().vect() << G4endl;
           ptgts += (*ktiter)->Get4Momentum();
       }

    for(ktiter = theCapturedList.cbegin(); ktiter != theCapturedList.cend(); ++ktiter)
        {

               G4cout << " Captured E - Ekin / p " <<
                  (*ktiter)->GetDefinition()->GetParticleName() << " " <<
                  (*ktiter)->Get4Momentum().e() << " - " <<
                  (*ktiter)->Get4Momentum().e() - (*ktiter)->Get4Momentum().mag() << " / " <<
                  (*ktiter)->Get4Momentum().vect() << G4endl;
            pcpts += (*ktiter)->Get4Momentum();
        }

    for(ktiter = theFinalState.cbegin(); ktiter != theFinalState.cend(); ++ktiter)
        {

               G4cout << " Finals E - Ekin / p " <<
                  (*ktiter)->GetDefinition()->GetParticleName() << " " <<
                  (*ktiter)->Get4Momentum().e() << " - " <<
                  (*ktiter)->Get4Momentum().e() - (*ktiter)->Get4Momentum().mag() << " / " <<
                  (*ktiter)->Get4Momentum().vect() << G4endl;
            pfins += (*ktiter)->Get4Momentum();
        }

      G4cout << " Secondaries " << psecs << ", Targets " << ptgts << G4endl
    		  <<" Captured    " << pcpts << ", Finals  " << pfins << G4endl
    		  <<" Sum " << psecs + ptgts + pcpts + pfins << " PTransfer " << theMomentumTransfer
    		  <<" Sum+PTransfer " << psecs + ptgts + pcpts + pfins + theMomentumTransfer
    		  << G4endl<< G4endl;


    return true;

}

//----------------------------------------------------------------------------
G4ReactionProductVector * G4BinaryCascade::ProductsAddFakeGamma(G4ReactionProductVector *products )
//----------------------------------------------------------------------------
{
   //    else
//    {
//        G4ReactionProduct * aNew=0;
//        // return nucleus e and p
//        if  (fragment != 0 ) {
//            aNew = new G4ReactionProduct(G4Gamma::GammaDefinition());   // we only want to pass e/p
//            aNew->SetMomentum(fragment->GetMomentum().vect());
//            aNew->SetTotalEnergy(fragment->GetMomentum().e());
//            delete fragment;
//            fragment=0;
//        } else if (products->size() == 0) {
//            // FixMe GF: for testing without precompound, return 1 gamma of 0.01 MeV in +x
//#include "G4Gamma.hh"
//            aNew = new G4ReactionProduct(G4Gamma::GammaDefinition());
//            aNew->SetMomentum(G4ThreeVector(0.01*MeV,0,0));
//            aNew->SetTotalEnergy(0.01*MeV);
//        }
//        if ( aNew != 0 ) products->push_back(aNew);
//    }
   return products;
}

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