blob: 170b428870445b97d5fe7a943069c7ec1d3035b2 [file] [log] [blame]
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2006, 2007 INRIA
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
*/
#include "spring-mobility-model.h"
#include "ns3/simulator.h"
#include "ns3/double.h"
#include "ns3/log.h"
#include "ns3/node-list.h"
#include "ns3/node.h"
#include <boost/foreach.hpp>
NS_LOG_COMPONENT_DEFINE ("SpringMobilityModel");
namespace ns3 {
NS_OBJECT_ENSURE_REGISTERED (SpringMobilityModel);
double SpringMobilityModel::m_totalKineticEnergy = 0.0;
bool SpringMobilityModel::m_stable = false;
EventId SpringMobilityModel::m_updateEvent;
double SpringMobilityModel::m_epsilon = 100.0;
const double COLOUMB_K = 200;
TypeId SpringMobilityModel::GetTypeId (void)
{
static TypeId tid = TypeId ("ns3::SpringMobilityModel")
.SetParent<MobilityModel> ()
.AddConstructor<SpringMobilityModel> ()
// .AddAttribute ("Epsilon", "Bound for kinetic energy when system is considered stable",
// DoubleValue (100.0),
// MakeDoubleAccessor (&SpringMobilityModel::m_epsilon),
// MakeDoubleChecker<double> ())
.AddAttribute ("NodeMass", "Node mass",
DoubleValue (10),
MakeDoubleAccessor (&SpringMobilityModel::m_nodeMass),
MakeDoubleChecker<double> ())
.AddAttribute ("NodeCharge", "Node charge",
DoubleValue (2),
MakeDoubleAccessor (&SpringMobilityModel::m_nodeCharge),
MakeDoubleChecker<double> ())
.AddAttribute ("SpringNormalLength", "Normal length of spring length",
DoubleValue (10),
MakeDoubleAccessor (&SpringMobilityModel::m_springNormalLength),
MakeDoubleChecker<double> ())
.AddAttribute ("SpringConstant", "Spring constant",
DoubleValue (0.2),
MakeDoubleAccessor (&SpringMobilityModel::m_springConstant),
MakeDoubleChecker<double> ())
.AddAttribute ("DampingFactor", "Dumping factor",
DoubleValue (0.8),
MakeDoubleAccessor (&SpringMobilityModel::m_dampingFactor),
MakeDoubleChecker<double> ())
;
return tid;
}
SpringMobilityModel::SpringMobilityModel ()
: m_position (0,0,0)
, m_velocity (0,0,0)
{
}
SpringMobilityModel::~SpringMobilityModel ()
{
}
void
SpringMobilityModel::AddSpring (Ptr<MobilityModel> node)
{
m_springs.push_back (node);
}
void
SpringMobilityModel::DoStart ()
{
if (!m_updateEvent.IsRunning ())
m_updateEvent = Simulator::Schedule (Seconds(0.05), SpringMobilityModel::UpdateAll);
}
void
SpringMobilityModel::UpdateAll ()
{
for (NodeList::Iterator node = NodeList::Begin ();
node != NodeList::End ();
node++)
{
Ptr<SpringMobilityModel> model = (*node)->GetObject<SpringMobilityModel> ();
if (model != 0)
model->Update ();
}
if (m_totalKineticEnergy < m_epsilon)
{
m_stable = true;
NS_LOG_INFO ("Stabilized with " << m_totalKineticEnergy);
}
else
m_updateEvent = Simulator::Schedule (Seconds(0.05), SpringMobilityModel::UpdateAll);
}
void
SpringMobilityModel::Update () const
{
NS_LOG_FUNCTION (this << m_stable << m_position << m_velocity);
if (m_stable) return;
Time now = Simulator::Now ();
if (now <= m_lastTime)
{
m_lastTime = now;
return;
}
double time_step_s = (now - m_lastTime).ToDouble (Time::S);
m_lastTime = now;
Vector force (0.0, 0.0, 0.0);
for (NodeList::Iterator node = NodeList::Begin ();
node != NodeList::End ();
node++)
{
if ((*node)->GetId () == GetObject<Node> ()->GetId ()) continue;
Ptr<SpringMobilityModel> model = (*node)->GetObject<SpringMobilityModel> ();
if (model == 0) continue;
if (model == this) continue;
double distance = GetDistanceFrom (model);
if (distance < 0.1) continue;
Vector direction = (GetPosition () - model->GetPosition ()) / distance; // direction vector of size 1, force trying to take nodes apart
force += direction * COLOUMB_K * m_nodeCharge * m_nodeCharge / distance / distance;
}
BOOST_FOREACH (Ptr<MobilityModel> model, m_springs)
{
double distance = GetDistanceFrom (model);
Vector direction = (model->GetPosition () - GetPosition ()) / distance; // direction vector of size 1, force trying to take nodes closer, if they are more than distance apart
force += direction * (- m_springNormalLength + distance) / m_springConstant;
}
// NS_LOG_DEBUG ("force: " << force);
// subtract previous value of kinetic energy for the node
double velocityValue = CalculateDistance (m_velocity, Vector(0,0,0));
m_totalKineticEnergy -= m_nodeMass * velocityValue * velocityValue;
// Correct velocity and position
m_velocity = (m_velocity + force * time_step_s) * m_dampingFactor;
m_position += m_velocity * time_step_s;
// Add new value for the kinetic energy
velocityValue = CalculateDistance (m_velocity, Vector(0,0,0));
m_totalKineticEnergy += m_nodeMass * velocityValue * velocityValue;
NotifyCourseChange ();
}
Vector
SpringMobilityModel::DoGetPosition (void) const
{
// NS_LOG_FUNCTION (this << m_position);
return m_position;
}
void
SpringMobilityModel::DoSetPosition (const Vector &position)
{
// NS_LOG_FUNCTION (this << position);
m_position = position;
NotifyCourseChange ();
m_stable = false;
for (NodeList::Iterator node = NodeList::Begin ();
node != NodeList::End ();
node++)
{
Ptr<SpringMobilityModel> model = (*node)->GetObject<SpringMobilityModel> ();
if (model != 0)
model->m_lastTime = Simulator::Now ();
}
if (!m_updateEvent.IsRunning ())
m_updateEvent = Simulator::Schedule (Seconds(0.05), SpringMobilityModel::UpdateAll);
}
Vector
SpringMobilityModel::DoGetVelocity (void) const
{
return m_velocity;
}
} // namespace ns3