Beispiel #1
0
  void 
  Dynamics::outputParticleXMLData(magnet::xml::XmlStream& XML, bool applyBC) const
  {
    XML << magnet::xml::tag("ParticleData");
  
    if (hasOrientationData())
      XML << magnet::xml::attr("OrientationData") << "Y";

    for (size_t i = 0; i < Sim->N; ++i)
      {
	Particle tmp(Sim->particles[i]);
	if (applyBC) 
	  Sim->BCs->applyBC(tmp.getPosition(), tmp.getVelocity());
      
	tmp.getVelocity() *= (1.0 / Sim->units.unitVelocity());
	tmp.getPosition() *= (1.0 / Sim->units.unitLength());
      
	XML << magnet::xml::tag("Pt");
	Sim->_properties.outputParticleXMLData(XML, i);
	XML << tmp;

	if (hasOrientationData())
	  XML << magnet::xml::tag("O")
	      << orientationData[i].angularVelocity
	      << magnet::xml::endtag("O")
	      << magnet::xml::tag("U")
	      << orientationData[i].orientation
	      << magnet::xml::endtag("U") ;

	XML << magnet::xml::endtag("Pt");
      }
  
    XML << magnet::xml::endtag("ParticleData");
  }
Beispiel #2
0
  void 
  Dynamics::initialise()
  {
    streamFreq = 10 * Sim->N;
    
    if (hasOrientationData())
      {
	double sumEnergy(0.0);
	for (const Particle& part : Sim->particles)
	  sumEnergy += Sim->species[part]->getScalarMomentOfInertia(part.getID())
	  * orientationData[part.getID()].angularVelocity.nrm2();
      
	//Check if any of the species are overridden
	bool hasInertia(false);
	for (const shared_ptr<Species>& spec : Sim->species)
	  if (std::dynamic_pointer_cast<SpInertia>(spec))
	    hasInertia = true;

	if (!hasInertia)
	  M_throw() << "No species have inertia, yet the particles have orientational degrees of freedom set!";

	sumEnergy *= 0.5 / Sim->units.unitEnergy();
  
	dout << "System Rotational Energy " << sumEnergy
	     << "\nRotational kT " << sumEnergy / Sim->N << std::endl;
      }
  }
Beispiel #3
0
  void
  Dynamics::rescaleSystemKineticEnergy(const double& scale)
  {
    double scalefactor(sqrt(scale));

    if (std::dynamic_pointer_cast<BCLeesEdwards>(Sim->BCs))
      {
	const BCLeesEdwards& bc = static_cast<const BCLeesEdwards&>(*Sim->BCs);
	for (Particle& part : Sim->particles)
	  {
	    const double mass = Sim->species[part]->getMass(part.getID());
	    if (!std::isinf(mass))
	      part.getVelocity() = Vector(bc.getPeculiarVelocity(part) * scalefactor + bc.getStreamVelocity(part));
	  }
      }
    else
      for (Particle& part : Sim->particles)
	{
	  const double mass = Sim->species[part]->getMass(part.getID());
	  if (!std::isinf(mass))
	    part.getVelocity() *= scalefactor;
	}

    if (hasOrientationData())
      for (Particle& part : Sim->particles)
	{
	  const double I = Sim->species[part]->getScalarMomentOfInertia(part.getID());
	  if (!std::isinf(I))
	    orientationData[part.getID()].angularVelocity *= scalefactor;
	}
  }
Beispiel #4
0
ParticleEventData
DynNewtonian::runAndersenWallCollision(Particle& part, const Vector & vNorm, const double& sqrtT, const double) const
{
    updateParticle(part);

    if (hasOrientationData())
        M_throw() << "Need to implement thermostating of the rotational degrees"
                  " of freedom";

    //This gives a completely new random unit vector with a properly
    //distributed Normal component. See Granular Simulation Book
    ParticleEventData tmpDat(part, *Sim->species[part], WALL);

    double mass = Sim->species[tmpDat.getSpeciesID()]->getMass(part.getID());

    for (size_t iDim = 0; iDim < NDIM; iDim++)
        part.getVelocity()[iDim] = Sim->normal_sampler() * sqrtT / std::sqrt(mass);

    part.getVelocity()
    //This first line adds a component in the direction of the normal
    += vNorm * (sqrtT * sqrt(-2.0*log(1.0-Sim->uniform_sampler()) / mass)
                //This removes the original normal component
                -(part.getVelocity() | vNorm));

    tmpDat.setDeltaKE(0.5 * mass * (part.getVelocity().nrm2() - tmpDat.getOldVel().nrm2()));

    return tmpDat;
}
Beispiel #5
0
ParticleEventData
DynNewtonian::randomGaussianEvent(Particle& part, const double& sqrtT,
                                  const size_t dimensions) const
{
#ifdef DYNAMO_DEBUG
    if (dimensions > NDIM)
        M_throw() << "Number of dimensions passed larger than NDIM!";
#endif

    //See http://mathworld.wolfram.com/SpherePointPicking.html

    if (hasOrientationData())
        M_throw() << "Need to implement thermostating of the rotational degrees"
                  " of freedom";

    //Ensure the particle is free streamed first
    updateParticle(part);

    //Collect the precoll data
    ParticleEventData tmpDat(part, *Sim->species[part], GAUSSIAN);

    double mass = Sim->species[tmpDat.getSpeciesID()]->getMass(part.getID());
    double factor = sqrtT / std::sqrt(mass);

    //Assign the new velocities
    for (size_t iDim = 0; iDim < dimensions; iDim++)
        part.getVelocity()[iDim] = Sim->normal_sampler() * factor;

    tmpDat.setDeltaKE(0.5 * mass * (part.getVelocity().nrm2() - tmpDat.getOldVel().nrm2()));

    return tmpDat;
}
Beispiel #6
0
  std::pair<bool, double> 
  DynCompression::getOffcentreSpheresCollision(const double offset1, const double diameter1, const double offset2, const double diameter2, const Particle& p1, const Particle& p2, double t_max, double maxdist) const
  {  
#ifdef DYNAMO_DEBUG
    if (!hasOrientationData())
      M_throw() << "Cannot use this function without orientational data";

    if (!isUpToDate(p1))
      M_throw() << "Particle1 " << p1.getID() << " is not up to date";

    if (!isUpToDate(p2))
      M_throw() << "Particle2 " << p2.getID() << " is not up to date";
#endif

    Vector r12 = p1.getPosition() - p2.getPosition();
    Vector v12 = p1.getVelocity() - p2.getVelocity();
    Sim->BCs->applyBC(r12, v12);
    
    const double limit_time_window = 1 / growthRate;

    std::pair<bool, double> retval = magnet::intersection::offcentre_growing_spheres(r12, v12, orientationData[p1.getID()].angularVelocity, orientationData[p2.getID()].angularVelocity, orientationData[p1.getID()].orientation * Quaternion::initialDirector() * offset1, orientationData[p2.getID()].orientation * Quaternion::initialDirector() * offset2, diameter1, diameter2, maxdist, std::min(limit_time_window, t_max), Sim->systemTime, growthRate);
    
    //Check if there's no collision reported but we've limited the interval
    if ((retval.second == HUGE_VAL) && (t_max > limit_time_window))
      return std::pair<bool, double>(false, limit_time_window);
    
    //Otherwise return what was calculated
    return retval;
  }
Beispiel #7
0
  ParticleEventData 
  DynCompression::runAndersenWallCollision(Particle& part, const Vector & vNorm, const double& sqrtT, const double d) const
  {  
    updateParticle(part);

    if (hasOrientationData())
      M_throw() << "Need to implement thermostating of the rotational degrees"
	" of freedom";

    //This gives a completely new random unit vector with a properly
    //distributed Normal component. See Granular Simulation Book
    ParticleEventData tmpDat(part, *Sim->species[part], WALL);
 
    double mass = Sim->species[tmpDat.getSpeciesID()]->getMass(part.getID());

    std::normal_distribution<> normal_dist;
    std::uniform_real_distribution<> uniform_dist;

    for (size_t iDim = 0; iDim < NDIM; iDim++)
      part.getVelocity()[iDim] = normal_dist(Sim->ranGenerator) * sqrtT / std::sqrt(mass);
  
    part.getVelocity()
      //This first line adds a component in the direction of the normal
      += vNorm * (sqrtT * sqrt(-2.0*log(1.0 - uniform_dist(Sim->ranGenerator)) / mass)
		  //This removes the original normal component
		  -(part.getVelocity() | vNorm)
		  //This adds on the velocity of the wall
		  + d * growthRate)
      ;

    return tmpDat; 
  }
Beispiel #8
0
void
DynNewtonian::streamParticle(Particle &particle, const double &dt) const
{
    particle.getPosition() += particle.getVelocity() * dt;

    //The Vector copy is required to make sure that the cached
    //orientation doesn't change during calculation
    if (hasOrientationData())
        orientationData[particle.getID()].orientation
            = Rodrigues(orientationData[particle.getID()].angularVelocity * dt)
              * Vector(orientationData[particle.getID()].orientation);
}
Beispiel #9
0
  void
  DynGravity::streamParticle(Particle &particle, const double &dt) const
  {
    bool isDynamic = particle.testState(Particle::DYNAMIC);
    particle.getPosition() += dt * (particle.getVelocity() + 0.5 * dt * g * isDynamic);
    particle.getVelocity() += dt * g * isDynamic;

    if (hasOrientationData())
      {
	orientationData[particle.getID()].orientation = Quaternion::fromRotationAxis(orientationData[particle.getID()].angularVelocity * dt)
	  * orientationData[particle.getID()].orientation ;
	orientationData[particle.getID()].orientation.normalise();
      }
  }
Beispiel #10
0
  double 
  Liouvillean::getParticleKineticEnergy(const Particle& part) const
  {
    double energy(0);
    if (Sim->dynamics.BCTypeTest<BCLeesEdwards>())
      {
	const BCLeesEdwards& bc = static_cast<const BCLeesEdwards&>(Sim->dynamics.BCs());

	energy += bc.getPeculiarVelocity(part).nrm2()
	  * Sim->dynamics.getSpecies(part).getMass(part.getID());
      }
    else
      energy += part.getVelocity().nrm2()
	* Sim->dynamics.getSpecies(part).getMass(part.getID());
  
    if (hasOrientationData())
      energy += orientationData[part.getID()].angularVelocity.nrm2()
	* Sim->dynamics.getSpecies(part).getScalarMomentOfInertia(part.getID());

    return 0.5 * energy;
  }
Beispiel #11
0
  double 
  Dynamics::getParticleKineticEnergy(const Particle& part) const
  {
    double energy(0);
    if (std::tr1::dynamic_pointer_cast<BCLeesEdwards>(Sim->BCs))
      {
	const BCLeesEdwards& bc = static_cast<const BCLeesEdwards&>(*Sim->BCs);

	energy += bc.getPeculiarVelocity(part).nrm2()
	  * Sim->species[part]->getMass(part.getID());
      }
    else
      energy += part.getVelocity().nrm2()
	* Sim->species[part]->getMass(part.getID());
  
    if (hasOrientationData())
      energy += orientationData[part.getID()].angularVelocity.nrm2()
	* Sim->species[part]->getScalarMomentOfInertia(part.getID());

    return 0.5 * energy;
  }
Beispiel #12
0
  double 
  Dynamics::getParticleKineticEnergy(const Particle& part) const
  {
    const double mass = Sim->species[part]->getMass(part.getID());

    double energy(0);
    if (!std::isinf(mass))
      {
	if (std::dynamic_pointer_cast<BCLeesEdwards>(Sim->BCs))
	  energy += static_cast<const BCLeesEdwards&>(*Sim->BCs).getPeculiarVelocity(part).nrm2() * mass;
	else
	  energy += part.getVelocity().nrm2() * mass;
      }

    if (hasOrientationData())
      {
	const double I = Sim->species[part]->getScalarMomentOfInertia(part.getID());
	if (!std::isinf(I))
	  energy += I * orientationData[part.getID()].angularVelocity.nrm2();
      }

    return 0.5 * energy;
  }
Beispiel #13
0
 /*! \brief Returns the degrees of freedom per particle.
  */
 inline size_t getParticleDOF() const { return NDIM + 2 * hasOrientationData(); }