Esempio n. 1
0
  void
  GSOCells::runEvent(Particle& part, const double) const
  {
    Sim->dynamics->updateParticle(part);

    Vector CellOrigin;
    size_t ID(part.getID());

    for (size_t iDim(0); iDim < NDIM; ++iDim)
      {
	CellOrigin[iDim] = (ID % cuberootN) * cellDimension[iDim] - 0.5*Sim->primaryCellSize[iDim];
	ID /= cuberootN;
      }
  
    //Determine the cell transition direction, its saved
    int cellDirectionInt(Sim->dynamics->
			 getSquareCellCollision3
			 (part, CellOrigin, 
			  cellDimension));

    size_t cellDirection = abs(cellDirectionInt) - 1;

    GlobalEvent iEvent(getEvent(part));

#ifdef DYNAMO_DEBUG 
    if (std::isnan(iEvent.getdt()))
      M_throw() << "A NAN Interaction collision time has been found"
		<< iEvent.stringData(Sim);
  
    if (iEvent.getdt() == HUGE_VAL)
      M_throw() << "An infinite Interaction (not marked as NONE) collision time has been found\n"
		<< iEvent.stringData(Sim);
#endif

    Sim->systemTime += iEvent.getdt();
    
    Sim->ptrScheduler->stream(iEvent.getdt());
  
    Sim->stream(iEvent.getdt());

    Vector vNorm(0,0,0);

    Vector pos(part.getPosition()), vel(part.getVelocity());

    Sim->BCs->applyBC(pos, vel);

    vNorm[cellDirection] = (cellDirectionInt > 0) ? -1 : +1; 
    
    //Run the collision and catch the data
    NEventData EDat(Sim->dynamics->runPlaneEvent(part, vNorm, 1.0, 0.0));

    Sim->_sigParticleUpdate(EDat);

    //Now we're past the event update the scheduler and plugins
    Sim->ptrScheduler->fullUpdate(part);
  
    for (shared_ptr<OutputPlugin> & Ptr : Sim->outputPlugins)
      Ptr->eventUpdate(iEvent, EDat);

  }
Esempio n. 2
0
  void 
  GVolumetricPotential::runEvent(Particle& part, const double dt)  {
    //Despite the system not being streamed this must be done.  This is
    //because the scheduler and all interactions, locals and systems
    //expect the particle to be up to date.
    Sim->dynamics->updateParticle(part);

    const size_t oldCellIndex = _cellData.getCellID(part.getID());
    const int cellDirectionInt(Sim->dynamics->getSquareCellCollision3(part, calcPosition(oldCellIndex, part), _cellDimension));
    const size_t cellDirection = abs(cellDirectionInt) - 1;

    GlobalEvent iEvent(getEvent(part));

#ifdef DYNAMO_DEBUG 
    if (std::isnan(iEvent.getdt()))
      M_throw() << "A NAN Interaction collision time has been found when recalculating this global"
		<< iEvent.stringData(Sim);
#endif

    Sim->systemTime += iEvent.getdt();
    Sim->ptrScheduler->stream(iEvent.getdt());  
    Sim->stream(iEvent.getdt());

    //Calculate which cell the particle might end up in
    const auto oldCellCoord = _ordering.toCoord(oldCellIndex);
    auto newCellCoord = oldCellCoord;
    newCellCoord[cellDirection] += _ordering.getDimensions()[cellDirection] + ((cellDirectionInt > 0) ? 1 : -1);
    newCellCoord[cellDirection] %= _ordering.getDimensions()[cellDirection];
    const size_t newCellIndex = _ordering.toIndex(newCellCoord);


    Vector vNorm{0,0,0};
    vNorm[cellDirection] = (cellDirectionInt > 0) ? -1 : 1;

    NEventData EDat;

    //Run the collision and catch the data
    Sim->dynamics->updateParticle(part);    
    Vector pos(part.getPosition()), vel(part.getVelocity());
    Sim->BCs->applyBC(pos, vel);
    double potEnergyChange = 0.5 * (double(_volumeData[newCellIndex]) - double(_volumeData[oldCellIndex]));
    double arg =  vel[cellDirection] * vel[cellDirection] - 2 * potEnergyChange / Sim->species(part)->getMass(part);
    if (arg > 0)
      {
	EDat = ParticleEventData(part, *Sim->species(part), WALL);
	part.getVelocity()[cellDirection] *= std::sqrt(arg) / std::abs(part.getVelocity()[cellDirection]);
	_cellData.moveTo(oldCellIndex, newCellIndex, part.getID());
      }
    else
      EDat = Sim->dynamics->runPlaneEvent(part, vNorm, 1.0, 0.0);
    
    //Now we're past the event update the scheduler and plugins
    Sim->_sigParticleUpdate(EDat);
    Sim->ptrScheduler->fullUpdate(part);  
    for (shared_ptr<OutputPlugin> & Ptr : Sim->outputPlugins)
      Ptr->eventUpdate(iEvent, EDat);
  }
Esempio n. 3
0
void CContactRemoteViewNotifier::RunL()
    {
    // update iEvent to notify CContactRemoteViewBase that cnt server died 
    if (iStatus.Int() == KErrServerTerminated || iStatus.Int() == KErrDied)
        {
        iEvent().iEventType = TContactViewEvent::EServerError;
        iEvent().iInt = iStatus.Int();
        }
    
    // this will try to start server and create the view, if server died
    iCallBack.CallBack();
    
    // listen to view events if server is running
    if (iEvent().iInt != KErrServerTerminated && iEvent().iInt != KErrDied)
        {
        Start();
        }
    }
Esempio n. 4
0
  void 
  GParabolaSentinel::runEvent(const Particle& part, const double) const
  {
    Sim->dynamics.getLiouvillean().updateParticle(part);

    GlobalEvent iEvent(getEvent(part));

    if (iEvent.getdt() == HUGE_VAL)
      {
	//We've numerically drifted slightly passed the parabola, so
	//just reschedule the particles events, no need to enforce anything
	Sim->ptrScheduler->fullUpdate(part);
	return;
      }

#ifdef DYNAMO_DEBUG 
    if (boost::math::isnan(iEvent.getdt()))
      M_throw() << "A NAN Interaction collision time has been found when recalculating this global"
		<< iEvent.stringData(Sim);
#endif

    Sim->dSysTime += iEvent.getdt();
    
    Sim->ptrScheduler->stream(iEvent.getdt());
  
    Sim->dynamics.stream(iEvent.getdt());

    Sim->dynamics.getLiouvillean().enforceParabola(part);
  
#ifdef DYNAMO_DEBUG
    iEvent.addTime(Sim->freestreamAcc);
  
    Sim->freestreamAcc = 0;

    NEventData EDat(ParticleEventData(part, Sim->dynamics.getSpecies(part), VIRTUAL));

    Sim->signalParticleUpdate(EDat);

    BOOST_FOREACH(std::tr1::shared_ptr<OutputPlugin> & Ptr, Sim->outputPlugins)
      Ptr->eventUpdate(iEvent, EDat);
#else
    Sim->freestreamAcc += iEvent.getdt();
#endif

    Sim->ptrScheduler->fullUpdate(part);
  }
Esempio n. 5
0
  void 
  GPBCSentinel::runEvent(Particle& part, const double dt) const
  {
    GlobalEvent iEvent(part, dt, VIRTUAL, *this);

    Sim->systemTime += iEvent.getdt();
    
    Sim->ptrScheduler->stream(iEvent.getdt());
  
    Sim->stream(iEvent.getdt());

    NEventData EDat(ParticleEventData(part, *Sim->species[part], VIRTUAL));

    Sim->signalParticleUpdate(EDat);

    BOOST_FOREACH(shared_ptr<OutputPlugin> & Ptr, Sim->outputPlugins)
      Ptr->eventUpdate(iEvent, EDat);

    Sim->ptrScheduler->fullUpdate(part);
  }
Esempio n. 6
0
  void 
  GParabolaSentinel::runEvent(Particle& part, const double) const
  {
    Sim->dynamics->updateParticle(part);

    GlobalEvent iEvent(getEvent(part));

    iEvent.setType(VIRTUAL);

    if (iEvent.getdt() == HUGE_VAL)
      {
	//We've numerically drifted slightly passed the parabola, so
	//just reschedule the particles events, no need to enforce anything
	Sim->ptrScheduler->fullUpdate(part);
	return;
      }

#ifdef DYNAMO_DEBUG 
    if (std::isnan(iEvent.getdt()))
      M_throw() << "A NAN Interaction collision time has been found when recalculating this global"
		<< iEvent.stringData(Sim);
#endif

    Sim->systemTime += iEvent.getdt();
    
    Sim->ptrScheduler->stream(iEvent.getdt());
  
    Sim->stream(iEvent.getdt());

    NEventData EDat = Sim->dynamics->enforceParabola(part);
  
    Sim->_sigParticleUpdate(EDat);

    for (shared_ptr<OutputPlugin> & Ptr : Sim->outputPlugins)
      Ptr->eventUpdate(iEvent, EDat);

    Sim->ptrScheduler->fullUpdate(part);
  }
Esempio n. 7
0
  void 
  GFrancesco::runEvent(Particle& part, const double)
  {
    const double dt = _eventTimes[part] - Sim->systemTime;
    _eventTimes[part] = HUGE_VAL;
    Event iEvent(part, dt, GLOBAL, GAUSSIAN, ID);
    
    Sim->systemTime += dt;
    Sim->ptrScheduler->stream(dt);
    Sim->stream(dt);

    Sim->dynamics->updateParticle(part);
    NEventData EDat(ParticleEventData(part, *Sim->species(part), GAUSSIAN));
    
    //Kill the rotational motion
    Sim->dynamics->getRotData(part).angularVelocity = Vector{0,0,0};
    //Reassign the linear motion
    part.getVelocity() = _vel * (Sim->dynamics->getRotData(part).orientation * magnet::math::Quaternion::initialDirector());

    Sim->_sigParticleUpdate(EDat);
    for (shared_ptr<OutputPlugin> & Ptr : Sim->outputPlugins)
      Ptr->eventUpdate(iEvent, EDat);
    Sim->ptrScheduler->fullUpdate(part);
  }
Esempio n. 8
0
  void
  Scheduler::runNextEvent()
  {
    sorter->sort();

#ifdef DYNAMO_DEBUG
    if (sorter->nextPELEmpty())
      M_throw() << "Next particle list is empty but top of list!";
#endif

    lazyDeletionCleanup();

    if (boost::math::isnan(sorter->next_dt()))
      M_throw() << "Next event time is NaN"
		<< "\nTime to event "
		<< sorter->next_dt()
		<< "\nEvent Type = " 
		<< sorter->next_type()
		<< "\nOwner Particle = " << sorter->next_ID()
		<< "\nID2 = " << sorter->next_p2();
    
    if (sorter->next_dt() == HUGE_VAL)
      {
	derr << "Next event time is Inf! (Queue has run out of events!)\n"
	     << "Shutting simulation down..."
	     << "\nEvent details, Type = " 
	     << sorter->next_type()
	     << "\nOwner Particle = " << sorter->next_ID()
	     << "\nID2 = " << sorter->next_p2()
	     << std::endl;
	Sim->endEventCount = Sim->eventCount;
	return;
      }

    ////////////////////////////////////////////////////////////////////
    // We can't perform such strict testing as commented out
    // below. Sometimes negative event times occur, usually at the start
    // of a simulation when particles are initialized just on the edge
    // of a cell, or if we have a system event which is "triggered" and
    // sets its own event time to 0. These must be tolerated and we must
    // trust in the determinism of the dynamics and the precision of the
    // calculations to minimise any effects. Generally, systems
    // shouldn't crash because of negative event times that were not
    // caused by a physically incorrect initial configuration
    ////////////////////////////////////////////////////////////////////
    //  if (sorter->next_dt() < 0)
    //    M_throw() << "Next event time is less than 0"
    //	      << "\nTime to event "
    //	      << sorter->next_dt()
    //	      << "\nEvent Type = " 
    //	      << sorter->next_type()
    //      	      << "\nOwner Particle = " << sorter->next_ID()
    //	      << "\nID2 = " << sorter->next_p2();
  
    /*! This is our dimensionless parameter which we need to correct a
      edge case for the collision testing. If an event is scheduled to
      occur its collision time is always double checked before it is
      executed. If two events are close together in time, the earliest
      might be popped off the queue, retested and then appear to occur
      later than the next event. In this case the original event is
      discarded and the new version is reinserted into the event
      queue. However, a rounding error might then cause the new event to
      appear earlier than the second event and we're back where we
      started. Basically, if "rejectionLimit" rejections occur in a row we
      just accept the next event in the queue. This breaks these loops and
      allows the simulation to continue. 

      With this method the system is guarranteed to maintain the correct
      event sequence to within machine precision. The queue can even
      handle negative time events provided the dynamics allow it.
    */
    const size_t rejectionLimit = 10;

    switch (sorter->next_type())
      {
      case INTERACTION:
	{
	  const Particle& p1(Sim->particleList[sorter->next_ID()]);
	  const Particle& p2(Sim->particleList[sorter->next_p2()]);

	  //Ready the next event in the FEL
	  sorter->popNextEvent();
	  sorter->update(sorter->next_ID());
	  sorter->sort();	
	  lazyDeletionCleanup();

	  //Now recalculate the FEL event
	  Sim->dynamics.getLiouvillean().updateParticlePair(p1, p2);       
	  IntEvent Event(Sim->dynamics.getEvent(p1, p2));
	
#ifdef DYNAMO_DEBUG
	  if (sorter->nextPELEmpty())
	    M_throw() << "The next PEL is empty, cannot perform the comparison to see if this event is out of sequence";
#endif

	  if ((Event.getType() == NONE)
	      || ((Event.getdt() > sorter->next_dt()) 
		  && (++_interactionRejectionCounter < rejectionLimit)))
	    {
#ifdef DYNAMO_DEBUG
	      derr << "Event " << Sim->eventCount << ":" << Event.getType()
		   << ",dt=" << Event.getdt() << ">nextdt=" << sorter->next_dt()
		   << ",p1=" << p1.getID() << ",p2=" << p2.getID() << std::endl;
#endif		
	      this->fullUpdate(p1, p2);
	      return;
	    }
	
#ifdef DYNAMO_DEBUG
	  if (Event.getdt() < 0)
	    derr << "Negative time " << Event.getdt() << std::endl;
#endif

	  //Reset the rejection watchdog, we will run an interaction event now
	  _interactionRejectionCounter = 0;
		
#ifdef DYNAMO_DEBUG

	  if (boost::math::isnan(Event.getdt()))
	    M_throw() << "A NAN Interaction collision time has been found"
		      << Event.stringData(Sim);
	
	  if (Event.getdt() == HUGE_VAL)
	    M_throw() << "An infinite Interaction (not marked as NONE) collision time has been found\n"
		      << Event.stringData(Sim);
#endif
	
	  //Debug section
#ifdef DYNAMO_CollDebug
	  std::cerr << "\nsysdt " << (Event.getdt() + Sim->dSysTime) / Sim->dynamics.units().unitTime()
		    << "  ID1 " << ((p2.getID() < p2.getID()) ? p1.getID() : p2.getID())
		    << "  ID2 " << ((p2.getID() < p2.getID()) ? p2.getID() : p1.getID())
		    << "  dt " << Event.getdt()
		    << "  Type " << Event.getType();
#endif

	  Sim->dSysTime += Event.getdt();
	
	  stream(Event.getdt());
	
	  //dynamics must be updated first
	  Sim->dynamics.stream(Event.getdt());
	
	  Event.addTime(Sim->freestreamAcc);

	  Sim->freestreamAcc = 0;

	  Sim->dynamics.getInteractions()[Event.getInteractionID()]
	    ->runEvent(p1,p2,Event);

	  break;
	}
      case GLOBAL:
	{
	  //We don't stream the system for globals as neighbour lists
	  //optimise this (they dont need it).

	  //We also don't recheck Global events! (Check, some events might rely on this behavior)
	  Sim->dynamics.getGlobals()[sorter->next_p2()]
	    ->runEvent(Sim->particleList[sorter->next_ID()], sorter->next_dt());       	
	  break;	           
	}
      case LOCAL:
	{
	  const Particle& part(Sim->particleList[sorter->next_ID()]);

	  //Copy the FEL event
	  size_t localID = sorter->next_p2();

	  //Ready the next event in the FEL
	  sorter->popNextEvent();
	  sorter->update(sorter->next_ID());
	  sorter->sort();
	  lazyDeletionCleanup();

	  Sim->dynamics.getLiouvillean().updateParticle(part);
	  LocalEvent iEvent(Sim->dynamics.getLocals()[localID]->getEvent(part));

	  if (iEvent.getType() == NONE)
	    {
#ifdef DYNAMO_DEBUG
	      derr << "Local event found not to occur [" << part.getID()
		   << "] (possible glancing/tenuous event canceled due to numerical error)" << std::endl;
#endif		
	      this->fullUpdate(part);
	      return;
	    }
	
	  double next_dt = sorter->next_dt();

	  if ((iEvent.getdt() > next_dt) && (++_localRejectionCounter < rejectionLimit))
	    {
#ifdef DYNAMO_DEBUG 
	      derr << "Recalculated LOCAL event time is greater than the next event time, recalculating" << std::endl;
#endif
	      this->fullUpdate(part);
	      return;
	    }

	  _localRejectionCounter = 0;

#ifdef DYNAMO_DEBUG 
	  if (boost::math::isnan(iEvent.getdt()))
	    M_throw() << "A NAN Global collision time has been found\n"
		      << iEvent.stringData(Sim);
	
	  if (iEvent.getdt() == HUGE_VAL)
	    M_throw() << "An infinite (not marked as NONE) Global collision time has been found\n"
		      << iEvent.stringData(Sim);
#endif
	
	  Sim->dSysTime += iEvent.getdt();
	
	  stream(iEvent.getdt());
	
	  //dynamics must be updated first
	  Sim->dynamics.stream(iEvent.getdt());
	
	  iEvent.addTime(Sim->freestreamAcc);
	  Sim->freestreamAcc = 0;

	  Sim->dynamics.getLocals()[localID]->runEvent(part, iEvent);	  
	  break;
	}
      case SYSTEM:
	{
	  Sim->dynamics.getSystemEvents()[sorter->next_p2()]
	    ->runEvent();
	  //This saves the system events rebuilding themselves
	  rebuildSystemEvents();
	  break;
	}
      case VIRTUAL:
	{
	  //This is a special type which requires that the system is
	  //moved forward to the current time and the events for this
	  //particle recalculated.

	  double dt = sorter->next_dt();
	  size_t ID = sorter->next_ID();
	  Sim->dSysTime += dt;
	  Sim->ptrScheduler->stream(dt);
	  Sim->dynamics.stream(dt);
	  Sim->freestreamAcc += dt;
	  this->fullUpdate(Sim->particleList[ID]);
	  break;
	}
      case NONE:
	{
	  M_throw() << "A NONE event has reached the top of the queue."
	    "\nThe simulation has run out of events! Aborting!";
	}
      default:
	M_throw() << "Unhandled event type requested to be run\n"
		  << "Type is " << sorter->next_type();
      }
  }
Esempio n. 9
0
  void 
  GWaker::runEvent(const Particle& part, const double dt) const
  {
    GlobalEvent iEvent(getEvent(part));
    iEvent.setdt(dt); //We only trust the schedulers time, as we don't
    //track the motion of the system in Globals
  
#ifdef DYNAMO_DEBUG 
    if (boost::math::isnan(iEvent.getdt()))
      M_throw() << "A NAN Interaction collision time has been found"
		<< iEvent.stringData(Sim);
  
    if (iEvent.getdt() == HUGE_VAL)
      M_throw() << "An infinite Interaction (not marked as NONE) collision time has been found\n"
		<< iEvent.stringData(Sim);
#endif

    Sim->dSysTime += iEvent.getdt();
    
    Sim->ptrScheduler->stream(iEvent.getdt());
  
    Sim->dynamics.stream(iEvent.getdt());

    Sim->dynamics.getLiouvillean().updateParticle(part);

    //Here is where the particle goes to sleep or wakes
    ++Sim->eventCount;
  
    _neighbors = 0;

    //Add the interaction events
    Sim->ptrScheduler->getParticleNeighbourhood(part, magnet::function::MakeDelegate(this, &GWaker::nblistCallback));
  
    //  if (_neighbors < 10)
    //    {
    iEvent.addTime(Sim->freestreamAcc);      
    Sim->freestreamAcc = 0;

    ParticleEventData EDat(part, Sim->dynamics.getSpecies(part), iEvent.getType());
      
    Vector newVel(Sim->normal_sampler(),Sim->normal_sampler(),Sim->normal_sampler());
    newVel *= _wakeVelocity / newVel.nrm();
      
    const_cast<Particle&>(part).getVelocity() = newVel;
    const_cast<Particle&>(part).setState(Particle::DYNAMIC);
      
    EDat.setDeltaKE(0.5 * EDat.getSpecies().getMass(part.getID())
		    * (part.getVelocity().nrm2() 
		       - EDat.getOldVel().nrm2()));
      
    Sim->signalParticleUpdate(EDat);
      
    BOOST_FOREACH(shared_ptr<OutputPlugin> & Ptr, Sim->outputPlugins)
      Ptr->eventUpdate(iEvent, EDat);
    //    }
    //  else
    //    Sim->freestreamAcc += iEvent.getdt();

    //Now we're past the event, update the scheduler and plugins
    Sim->ptrScheduler->fullUpdate(part);
  }
Esempio n. 10
0
  void
  Scheduler::runNextEvent()
  {
#ifdef DYNAMO_DEBUG
    if (sorter->empty())
      M_throw() << "Next particle list is empty but top of list!";
#endif

    Event next_event = sorter->top();

    ////////////////////////////////////////////////////////////////////
    // We can't perform such strict testing as commented out
    // below. Sometimes negative event times occur, usually at the start
    // of a simulation when particles are initialized just on the edge
    // of a cell, or if we have a system event which is "triggered" and
    // sets its own event time to 0. These must be tolerated and we must
    // trust in the determinism of the dynamics and the precision of the
    // calculations to minimise any effects. Generally, systems
    // shouldn't crash because of negative event times that were not
    // caused by a physically incorrect initial configuration
    ////////////////////////////////////////////////////////////////////
    //  if (sorter->next_dt() < 0)
    //    M_throw() << "Next event time is less than 0"
    //	      << "\nTime to event "
    //	      << sorter->next_dt()
    //	      << "\nEvent Type = " 
    //	      << sorter->next_type()
    //      	      << "\nOwner Particle = " << sorter->next_ID()
    //	      << "\nID2 = " << sorter->next_p2();
  
    /*! This is our dimensionless parameter which we need to correct a
      edge case for the collision testing. If an event is scheduled to
      occur its collision time is always double checked before it is
      executed. If two events are close together in time, the earliest
      might be popped off the queue, retested and then appear to occur
      later than the next event. In this case the original event is
      discarded and the new version is reinserted into the event
      queue. However, a rounding error might then cause the new event to
      appear earlier than the second event and we're back where we
      started. Basically, if "rejectionLimit" rejections occur in a row we
      just accept the next event in the queue. This breaks these loops and
      allows the simulation to continue. 

      With this method the system is guarranteed to maintain the correct
      event sequence to within machine precision. The queue can even
      handle negative time events provided the dynamics allow it.
    */
    const size_t rejectionLimit = 10;
    const size_t systemParticleID = Sim->N();

    if (next_event._type == RECALCULATE)
      {
	if (next_event._particle1ID == systemParticleID)
	  rebuildSystemEvents();
	else
	  //This is a special event type which requires that the
	  // events for this particle recalculated.
	  this->fullUpdate(Sim->particles[next_event._particle1ID]);

	return;
      }
    
    if (next_event._type == NONE)
      M_throw() << "A type=NONE event with no source has reached the top of the queue."
	"\nThe simulation has run out of events! Aborting!";

    //-inf values are special values for instant event.
    if (next_event._dt == -std::numeric_limits<float>::infinity())
      next_event._dt = 0;

    switch (next_event._source)
      {
      case INTERACTION:
	{
#ifdef DYNAMO_DEBUG
	  if (next_event._particle1ID >= Sim->particles.size())
	    M_throw() << "Out of range particle access";
	  if (next_event._particle2ID >= Sim->particles.size())
	    M_throw() << "Out of range particle access";
#endif

	  Particle& p1(Sim->particles[next_event._particle1ID]);
	  Particle& p2(Sim->particles[next_event._particle2ID]);

	  if (!std::isfinite(next_event._dt))
	    M_throw() << "Next event time is not finite!"
		      << "\ndt = " << next_event._dt
		      << "\nEvent Type = " << next_event._type
		      << "\nParticle 1 ID = " << next_event._particle1ID
		      << "\nParticle 2 ID = " << next_event._particle2ID
		      << "\nInteraction = " << Sim->getInteraction(p1, p2)->getName()
	      ;

	  //Ready the next event in the FEL
	  sorter->pop();

	  //Now recalculate the current FEL event (to check if
	  //accumilation of numerical errors have caused the order of
	  //events to change). This also gives us more information on
	  //the event.
	  Sim->dynamics->updateParticlePair(p1, p2);
	  const Event Event = Sim->getEvent(p1, p2);
	
	  //Now check if the recalculated event is still the first
	  //event in the FEL. If not, force a recalculation of this
	  //particles events and return (so another event can be run).
#ifdef DYNAMO_DEBUG
	  if (sorter->empty())
	    M_throw() << "The next PEL is empty, cannot perform the comparison to see if this event is out of sequence";
#endif
	  next_event = sorter->top();
	  if (next_event._dt == -std::numeric_limits<float>::infinity())
	    next_event._dt = 0;
	  
	  //Here we see if the next FEL event is earlier than the one
	  //about to be processed, we also count the amount of
	  //rejections we perform (its a watchdog), as (in some minor
	  //edge cases) we can enter loops due to tiny precision
	  //differences in event times.
	  if ((Event._type == NONE) || ((Event._dt > next_event._dt) && (++_interactionRejectionCounter < rejectionLimit)))
	    {
	      this->fullUpdate(p1, p2);
	      return;
	    }

	  //Reset the rejection watchdog counter as we are about to
	  //run an interaction event now
	  _interactionRejectionCounter = 0;
		
	  if (!std::isfinite(next_event._dt))
	    M_throw() << "Next event time is not finite!"
		      << "\ndt = " << next_event._dt
		      << "\nEvent Type = " << next_event._type
		      << "\nParticle 1 ID = " << next_event._particle1ID
		      << "\nParticle 2 ID = " << next_event._particle2ID
		      << "\nInteraction = " << Sim->getInteraction(p1, p2)->getName();

#ifdef DYNAMO_DEBUG
	  if (Event._dt < 0)
	    derr << "Warning! Negative time event " << Event << std::endl;
	  
	  if (p1.getID() == p2.getID())
	    M_throw() << "Somehow processing a self Interaction";
#endif

	  //Move the simulation forward to the time of the event
	  Sim->systemTime += Event._dt;
	  stream(Event._dt);
	  //Allow everything to stream up to the current time before executing the event
	  Sim->stream(Event._dt);
	  
	  PairEventData eventdata = Sim->interactions[Event._sourceID]->runEvent(p1, p2, Event);
	  
	  Sim->_sigParticleUpdate(eventdata);
	  Sim->ptrScheduler->fullUpdate(p1, p2);
	  for (shared_ptr<OutputPlugin> & Ptr : Sim->outputPlugins)
	    Ptr->eventUpdate(Event, eventdata);
	  break;
	}
      case GLOBAL:
	{
	  if (!std::isfinite(next_event._dt))
	    M_throw() << "Next event time is not finite!"
		      << "\ndt = " << next_event._dt
		      << "\nEvent Type = " << next_event._type
		      << "\nParticle ID = " << next_event._particle1ID
		      << "\nGlobal (ID=" << next_event._sourceID << ")= " << Sim->globals[next_event._sourceID]->getName()
	      ;

	  //We don't stream the system for globals as neighbour lists
	  //optimise this (they dont need it).  We also don't recheck
	  //Global events! (Check, some events might rely on this
	  //behavior)
	  Sim->globals[next_event._sourceID]->runEvent(Sim->particles[next_event._particle1ID], next_event._dt);
	  break;
	}
      case LOCAL:
	{
	  Particle& part(Sim->particles[next_event._particle1ID]);
	  size_t localID = next_event._sourceID;

	  if (!std::isfinite(next_event._dt))
	    M_throw() << "Next event time is not finite!"
		      << "\ndt = " << next_event._dt
		      << "\nEvent Type = " << next_event._type
		      << "\nParticle ID = " << next_event._particle1ID
		      << "\nGlobal (ID=" << next_event._sourceID << ")= " 
		      << Sim->locals[next_event._sourceID]->getName()
	      ;

	  //Ready the next event in the FEL
	  sorter->pop();
	  Sim->dynamics->updateParticle(part);
	  Event iEvent(Sim->locals[localID]->getEvent(part));

	  next_event = sorter->top();
	  //Check the recalculated event is valid and not later than
	  //the next event in the queue
	  if ((iEvent._type == NONE) || ((iEvent._dt > next_event._dt) && (++_localRejectionCounter < rejectionLimit)))
	    {
	      this->fullUpdate(part);
	      return;
	    }

	  _localRejectionCounter = 0;

#ifdef DYNAMO_DEBUG 
	  if (!std::isfinite(next_event._dt))
	    M_throw() << "Recalculated event time is not finite!"
		      << next_event._particle1ID
		      << "\nGlobal = " << Sim->locals[next_event._sourceID]->getName();
#endif
	
	  Sim->systemTime += iEvent._dt;
	
	  stream(iEvent._dt);
	
	  //dynamics must be updated first
	  Sim->stream(iEvent._dt);
	
	  const ParticleEventData data = Sim->locals[localID]->runEvent(part, iEvent);
	  Sim->_sigParticleUpdate(data);	  
	  Sim->ptrScheduler->fullUpdate(part);
	  for (shared_ptr<OutputPlugin> & Ptr : Sim->outputPlugins)
	    Ptr->eventUpdate(iEvent, data);
	  break;
	}
      case SYSTEM:
	{
	  sorter->pop();
	  //System events can use the value -std::numeric_limits<float>::infinity() to request
	  //immediate processing, therefore, only NaN and +std::numeric_limits<float>::infinity()
	  //values are invalid
	  if (std::isnan(next_event._dt) || (next_event._dt == std::numeric_limits<float>::infinity()))
	    M_throw() << "Next event time is not finite!"
		      << "\ndt = " << next_event._dt
		      << "\nEvent Type = " << next_event._type
		      << "\nParticle ID = " << next_event._particle1ID
		      << "\nSystem (ID=" << next_event._sourceID << ")= " << Sim->systems[next_event._sourceID]->getName()
	      ;
	  
	  Sim->systemTime += next_event._dt;
	  stream(next_event._dt);
	  Sim->stream(next_event._dt);

	  const NEventData data = Sim->systems[next_event._sourceID]->runEvent();

	  if (!data.L1partChanges.empty() || !data.L2partChanges.empty()) {
	    Sim->_sigParticleUpdate(data);
	    for (const auto& d1 : data.L1partChanges)
	      this->fullUpdate(Sim->particles[d1.getParticleID()]);
	    for (const auto& d2 : data.L2partChanges)
	      this->fullUpdate(Sim->particles[d2.particle1_.getParticleID()], Sim->particles[d2.particle2_.getParticleID()]);
	    
	    for (shared_ptr<OutputPlugin>& Ptr : Sim->outputPlugins)
	      Ptr->eventUpdate(next_event, data);
	  }

	  const size_t systemParticleID = Sim->N();
	  Event event = Sim->systems[next_event._sourceID]->getEvent();
	  event._particle1ID = systemParticleID;
	  sorter->push(event);
	  break;
	}
      default:
	M_throw() << "Unhandled event type requested to be run\n"
		  << "Type is " << next_event._type;
      }
  }
Esempio n. 11
0
const TContactViewEvent& CContactRemoteViewNotifier::Event() const
    {
    return MUTABLE_CAST(CContactRemoteViewNotifier*,this)->iEvent();
    }