Adding SpringMobilityModel to adjust positions of nodes in large
topologies
Inspired by http://en.wikipedia.org/wiki/Force-based_algorithms_%28graph_drawing%29
diff --git a/examples/abilene-topology.cc b/examples/abilene-topology.cc
index 75a4b99..a96daf7 100644
--- a/examples/abilene-topology.cc
+++ b/examples/abilene-topology.cc
@@ -30,6 +30,7 @@
#include <iostream>
#include <sstream>
#include "ns3/annotated-topology-reader.h"
+#include "../utils/spring-mobility-helper.h"
using namespace ns3;
using namespace std;
@@ -80,6 +81,7 @@
// --------------------------------------------
AnnotatedTopologyReader reader ("/abilene");
+ reader.SetMobilityModel ("ns3::SpringMobilityModel");
reader.SetFileName (input);
NodeContainer nodes = reader.Read ();
@@ -90,6 +92,8 @@
return -1;
}
+ SpringMobilityHelper::InstallSprings (reader.LinksBegin (), reader.LinksEnd ());
+
// InternetStackHelper stack;
// Ipv4GlobalRoutingHelper ipv4RoutingHelper ("ns3::Ipv4GlobalRoutingOrderedNexthops");
// stack.SetRoutingHelper (ipv4RoutingHelper);
diff --git a/examples/abilene-topology.txt b/examples/abilene-topology.txt
index 5eb607d..4672859 100644
--- a/examples/abilene-topology.txt
+++ b/examples/abilene-topology.txt
@@ -1,7 +1,7 @@
router
#name city latitude longitude
ATLA-M5 Atlanta_GA 33.750000 -84.383300
-ATLAng Atlanta_GA 33.750000 -84.383300
+ATLAng Atlanta_GA 33.850000 -84.483300
CHINng Chicago_IL 41.833300 -87.616700
DNVRng Denver_CO 40.750000 -105.000000
HSTNng Houston_TX 29.770031 -95.517364
diff --git a/examples/sprint-topology.cc b/examples/sprint-topology.cc
index 5efffeb..3a53c35 100644
--- a/examples/sprint-topology.cc
+++ b/examples/sprint-topology.cc
@@ -31,43 +31,81 @@
#include "ns3/rocketfuel-topology-reader.h"
using namespace ns3;
+using namespace std;
NS_LOG_COMPONENT_DEFINE ("CcnxSprintTopology");
int
main (int argc, char *argv[])
{
- Packet::EnableChecking();
- Packet::EnablePrinting();
- std::string weights ("./src/NDNabstraction/examples/sprint.weights");
- std::string latencies ("./src/NDNabstraction/examples/sprint.latencies");
+ // Packet::EnableChecking();
+ // Packet::EnablePrinting();
+ string weights ("./src/NDNabstraction/examples/sprint.weights");
+ string latencies ("./src/NDNabstraction/examples/sprint.latencies");
- // ------------------------------------------------------------
- // -- Read topology data.
- // --------------------------------------------
-
- RocketfuelWeightsReader reader;
+ Time finishTime = Seconds (2.0);
+ string animationFile;
+ string strategy = "ns3::CcnxFloodingStrategy";
+ CommandLine cmd;
+ cmd.AddValue ("finish", "Finish time", finishTime);
+ cmd.AddValue ("netanim", "NetAnim filename", animationFile);
+ cmd.AddValue ("strategy", "CCNx forwarding strategy", strategy);
+ cmd.AddValue ("weights", "Weights file", weights);
+ cmd.AddValue ("latencies", "Latencies file", latencies);
+ cmd.Parse (argc, argv);
- reader.SetFileName (weights);
- reader.SetFileType (RocketfuelWeightsReader::WEIGHTS);
- NodeContainer nodes = reader.Read ();
-
- reader.SetFileName (latencies);
- reader.SetFileType (RocketfuelWeightsReader::LATENCIES);
- reader.Read ();
+ // ------------------------------------------------------------
+ // -- Read topology data.
+ // --------------------------------------------
- if (reader.LinksSize () == 0)
+ RocketfuelWeightsReader reader ("/sprint");
+ reader.SetBoundingBox (0, 0, 400, 250);
+
+ reader.SetFileName (weights);
+ reader.SetFileType (RocketfuelWeightsReader::WEIGHTS);
+ NodeContainer nodes = reader.Read ();
+
+ reader.SetFileName (latencies);
+ reader.SetFileType (RocketfuelWeightsReader::LATENCIES);
+ reader.Read ();
+
+ reader.Commit ();
+ if (reader.LinksSize () == 0)
{
- NS_LOG_ERROR ("Problems reading the topology file. Failing.");
- return -1;
+ NS_LOG_ERROR ("Problems reading the topology file. Failing.");
+ return -1;
}
- NS_LOG_INFO("Nodes = " << nodes.GetN());
- NS_LOG_INFO("Links = " << reader.LinksSize ());
+ NS_LOG_INFO("Nodes = " << nodes.GetN());
+ NS_LOG_INFO("Links = " << reader.LinksSize ());
- NS_LOG_INFO ("Run Simulation.");
- Simulator::Run ();
- Simulator::Destroy ();
- NS_LOG_INFO ("Done.");
- return 0;
+ InternetStackHelper stack;
+ Ipv4GlobalRoutingHelper ipv4RoutingHelper ("ns3::Ipv4GlobalRoutingOrderedNexthops");
+ stack.SetRoutingHelper (ipv4RoutingHelper);
+ stack.Install (nodes);
+
+ reader.AssignIpv4Addresses (Ipv4Address ("10.0.0.0"));
+
+ // Install CCNx stack
+ NS_LOG_INFO ("Installing CCNx stack");
+ CcnxStackHelper ccnxHelper;
+ ccnxHelper.SetForwardingStrategy (strategy);
+ ccnxHelper.EnableLimits (false, Seconds(0.1));
+ ccnxHelper.SetDefaultRoutes (true);
+ ccnxHelper.InstallAll ();
+
+ // // Populate FIB based on IPv4 global routing controller
+ // ccnxHelper.InstallFakeGlobalRoutes ();
+ // ccnxHelper.InstallRouteTo (Names::Find<Node> ("/sprint", "San+Jose,+CA4062"));
+
+ // Simulator::Schedule (Seconds (1.0), PrintFIBs);
+ // PrintFIBs ();
+
+ Simulator::Stop (finishTime);
+
+ NS_LOG_INFO ("Run Simulation.");
+ Simulator::Run ();
+ Simulator::Destroy ();
+ NS_LOG_INFO ("Done.");
+ return 0;
}
diff --git a/model/annotated-topology-reader.cc b/model/annotated-topology-reader.cc
index eb56339..6553f86 100644
--- a/model/annotated-topology-reader.cc
+++ b/model/annotated-topology-reader.cc
@@ -58,6 +58,8 @@
, m_randY (0, 100.0)
{
NS_LOG_FUNCTION (this);
+
+ // SetMobilityModel ("ns3::ConstantPositionMobilityModel");
}
void
@@ -69,6 +71,13 @@
m_randY = UniformVariable (uly, lry);
}
+void
+AnnotatedTopologyReader::SetMobilityModel (const std::string &model)
+{
+ NS_LOG_FUNCTION (this << model);
+ m_mobilityFactory.SetTypeId (model);
+}
+
AnnotatedTopologyReader::~AnnotatedTopologyReader ()
{
NS_LOG_FUNCTION (this);
@@ -77,14 +86,15 @@
Ptr<Node>
AnnotatedTopologyReader::CreateNode (const std::string name)
{
- return CreateNode (name, m_randX.GetValue (), m_randX.GetValue ());
+ return CreateNode (name, m_randX.GetValue (), m_randY.GetValue ());
}
Ptr<Node>
AnnotatedTopologyReader::CreateNode (const std::string name, double posX, double posY)
{
+ NS_LOG_FUNCTION (this << name << posX << posY);
Ptr<Node> node = CreateObject<Node> ();
- Ptr<ConstantPositionMobilityModel> loc = CreateObject<ConstantPositionMobilityModel> ();
+ Ptr<MobilityModel> loc = DynamicCast<MobilityModel> (m_mobilityFactory.Create ());
node->AggregateObject (loc);
loc->SetPosition (Vector (posX, posY, 0));
@@ -144,9 +154,9 @@
// NS_LOG_DEBUG ("Input: [" << line << "]");
istringstream lineBuffer (line);
- string from, to, capacity, metric;
+ string from, to, capacity, metric, delay, queueSizeNode1, queueSizeNode2;
- lineBuffer >> from >> to >> capacity >> metric;
+ lineBuffer >> from >> to >> capacity >> metric >> delay >> queueSizeNode1 >> queueSizeNode2;
if (processedLinks[to].size () != 0 &&
processedLinks[to].find (from) != processedLinks[to].end ())
@@ -164,9 +174,13 @@
link.SetAttribute ("DataRate", capacity);
link.SetAttribute ("OSPF", metric);
- // link.SetAttribute ("Delay", delay);
- // link.SetAttribute ("QueueSizeNode1", queueSizeNode1);
- // link.SetAttribute ("QueueSizeNode2", queueSizeNode2);
+
+ if (!delay.empty ())
+ link.SetAttribute ("Delay", delay);
+ if (!queueSizeNode1.empty ())
+ link.SetAttribute ("QueueSizeNode1", queueSizeNode1);
+ if (!queueSizeNode2.empty ())
+ link.SetAttribute ("QueueSizeNode2", queueSizeNode2);
AddLink (link);
NS_LOG_DEBUG ("New link " << from << " <==> " << to << " / " << capacity << "Kbps with " << metric << " metric");
@@ -202,6 +216,7 @@
{
BOOST_FOREACH (const Link &link, m_linksList)
{
+ NS_LOG_DEBUG ("OSPF: " << link.GetAttribute ("OSPF"));
uint16_t metric = boost::lexical_cast<uint16_t> (link.GetAttribute ("OSPF"));
{
@@ -230,40 +245,33 @@
AnnotatedTopologyReader::ApplySettings ()
{
PointToPointHelper p2p;
-
- // temporary queue, will be changed later
- p2p.SetQueue ("ns3::DropTailQueue",
- "MaxPackets", StringValue("100"));
BOOST_FOREACH (Link &link, m_linksList)
{
string tmp;
- NS_LOG_INFO ("DataRate = " + link.GetAttribute("DataRate")+"Kbps");
- p2p.SetDeviceAttribute ("DataRate", StringValue(link.GetAttribute("DataRate")+"Kbps"));
+ if (link.GetAttributeFailSafe ("DataRate", tmp))
+ {
+ NS_LOG_INFO ("DataRate = " + link.GetAttribute("DataRate")+"Kbps");
+ p2p.SetDeviceAttribute ("DataRate", StringValue(link.GetAttribute("DataRate")+"Kbps"));
+ }
if (link.GetAttributeFailSafe("Delay", tmp))
{
NS_LOG_INFO ("Delay = " + link.GetAttribute("Delay")+"ms");
p2p.SetChannelAttribute ("Delay", StringValue(link.GetAttribute("Delay")+"ms"));
}
- else
- {
- NS_LOG_INFO ("Default delay 1ms");
- p2p.SetChannelAttribute ("Delay", StringValue("1ms"));
- }
NetDeviceContainer nd = p2p.Install(link.GetFromNode (), link.GetToNode ());
link.SetNetDevices (nd.Get (0), nd.Get (1));
- // NS_LOG_INFO ("Queue: " << link.GetAttribute("QueueSizeNode1") << " <==> " << link.GetAttribute("QueueSizeNode2"));
-
if (link.GetAttributeFailSafe("QueueSizeNode1", tmp))
{
PointerValue txQueueFrom;
link.GetFromNetDevice ()->GetAttribute ("TxQueue", txQueueFrom);
NS_ASSERT (txQueueFrom.Get<DropTailQueue> () != 0);
+ NS_LOG_INFO ("QueueFrom: " << link.GetAttribute("QueueSizeNode1"));
txQueueFrom.Get<DropTailQueue> ()->SetAttribute ("MaxPackets", StringValue (link.GetAttribute("QueueSizeNode1")));
}
@@ -273,6 +281,7 @@
link.GetToNetDevice ()->GetAttribute ("TxQueue", txQueueTo);
NS_ASSERT (txQueueTo.Get<DropTailQueue> () != 0);
+ NS_LOG_INFO ("QueueTo: " << link.GetAttribute("QueueSizeNode2"));
txQueueTo.Get<DropTailQueue> ()->SetAttribute ("MaxPackets", StringValue (link.GetAttribute("QueueSizeNode2")));
}
}
diff --git a/model/annotated-topology-reader.h b/model/annotated-topology-reader.h
index 06bbe2a..4bacd2a 100644
--- a/model/annotated-topology-reader.h
+++ b/model/annotated-topology-reader.h
@@ -23,6 +23,7 @@
#include "ns3/topology-reader.h"
#include "ns3/random-variable.h"
+#include "ns3/object-factory.h"
namespace ns3
{
@@ -69,6 +70,9 @@
void
SetBoundingBox (double ulx, double uly, double lrx, double lry);
+ void
+ SetMobilityModel (const std::string &model);
+
protected:
Ptr<Node>
CreateNode (const std::string name);
@@ -76,7 +80,7 @@
Ptr<Node>
CreateNode (const std::string name, double posX, double posY);
-private:
+protected:
/**
* \brief This method applies setting to corresponding nodes and links
* NetDeviceContainer must be allocated
@@ -94,6 +98,8 @@
UniformVariable m_randX;
UniformVariable m_randY;
+
+ ObjectFactory m_mobilityFactory;
};
}
diff --git a/model/rocketfuel-weights-reader.cc b/model/rocketfuel-weights-reader.cc
index ac7f6b1..448464e 100644
--- a/model/rocketfuel-weights-reader.cc
+++ b/model/rocketfuel-weights-reader.cc
@@ -46,6 +46,7 @@
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
+#include "../utils/spring-mobility-helper.h"
#include <iomanip>
#include <set>
@@ -56,9 +57,11 @@
namespace ns3 {
-RocketfuelWeightsReader::RocketfuelWeightsReader ()
+RocketfuelWeightsReader::RocketfuelWeightsReader (const std::string &path/*=""*/)
+ : AnnotatedTopologyReader (path)
{
NS_LOG_FUNCTION (this);
+ SetMobilityModel ("ns3::SpringMobilityModel");
}
RocketfuelWeightsReader::~RocketfuelWeightsReader ()
@@ -138,8 +141,11 @@
switch (m_inputType)
{
case WEIGHTS:
- link->SetAttribute ("OSPF", attribute);
- break;
+ {
+ double metric = boost::lexical_cast<double> (attribute);
+ link->SetAttribute ("OSPF", boost::lexical_cast<string> (metric*2));
+ break;
+ }
case LATENCIES:
link->SetAttribute ("Delay", attribute);
break;
@@ -156,8 +162,34 @@
}
topgen.close ();
- NS_LOG_INFO ("Rocketfuel topology created with " << nodes.GetN () << " nodes and " << LinksSize () << " links");
+
+ if (!repeatedRun)
+ {
+ NS_LOG_INFO ("Rocketfuel topology created with " << nodes.GetN () << " nodes and " << LinksSize () << " links");
+ }
return nodes;
}
-
+
+void
+RocketfuelWeightsReader::Commit ()
+{
+ ApplySettings ();
+
+ SpringMobilityHelper::InstallSprings (LinksBegin (), LinksEnd ());
+}
+
+
+// void
+// RocketfuelWeightsReader::Cheat (NodeContainer &nodes)
+// {
+// double epsilon = 1;
+
+// for (NodeContainer::Iterator i = nodes.Begin ();
+// i != nodes.End ();
+// i++)
+// {
+
+// }
+// }
+
} /* namespace ns3 */
diff --git a/model/rocketfuel-weights-reader.h b/model/rocketfuel-weights-reader.h
index 2b73c11..ecf4905 100644
--- a/model/rocketfuel-weights-reader.h
+++ b/model/rocketfuel-weights-reader.h
@@ -39,7 +39,7 @@
class RocketfuelWeightsReader : public AnnotatedTopologyReader
{
public:
- RocketfuelWeightsReader ();
+ RocketfuelWeightsReader (const std::string &path="");
virtual ~RocketfuelWeightsReader ();
void
@@ -55,7 +55,11 @@
*
* \return the container of the nodes created (or empty container if there was an error)
*/
- virtual NodeContainer Read (void);
+ virtual NodeContainer
+ Read (void);
+
+ void
+ Commit ();
enum
{
@@ -63,6 +67,9 @@
LATENCIES
};
+ // void
+ // Cheat (NodeContainer &nodes);
+
private:
RocketfuelWeightsReader (const RocketfuelWeightsReader&);
RocketfuelWeightsReader& operator= (const RocketfuelWeightsReader&);
diff --git a/utils/spring-mobility-helper.cc b/utils/spring-mobility-helper.cc
new file mode 100644
index 0000000..5e4b4f6
--- /dev/null
+++ b/utils/spring-mobility-helper.cc
@@ -0,0 +1,51 @@
+/* -*- 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-helper.h"
+#include "spring-mobility-model.h"
+
+namespace ns3 {
+
+void
+SpringMobilityHelper::InstallSprings (Ptr<Node> node1, Ptr<Node> node2)
+{
+ Ptr<SpringMobilityModel> model1, model2;
+ model1 = node1->GetObject<SpringMobilityModel> ();
+ model2 = node2->GetObject<SpringMobilityModel> ();
+
+ NS_ASSERT (model1 != 0 && model2 != 0);
+
+ model1->AddSpring (model2);
+ model2->AddSpring (model1);
+}
+
+void
+SpringMobilityHelper::InstallSprings (TopologyReader::ConstLinksIterator first,
+ TopologyReader::ConstLinksIterator end)
+{
+ for (; first != end; first++)
+ {
+ InstallSprings (first->GetFromNode (),
+ first->GetToNode ());
+ }
+}
+
+} // namespace ns3
+
diff --git a/utils/spring-mobility-helper.h b/utils/spring-mobility-helper.h
new file mode 100644
index 0000000..7285d25
--- /dev/null
+++ b/utils/spring-mobility-helper.h
@@ -0,0 +1,45 @@
+/* -*- 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>
+ */
+#ifndef SPRING_MOBILITY_HELPER_H
+#define SPRING_MOBILITY_HELPER_H
+
+#include "ns3/topology-reader.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup mobility
+ *
+ * \brief
+ */
+class SpringMobilityHelper
+{
+public:
+ static void
+ InstallSprings (Ptr<Node> node1, Ptr<Node> node2);
+
+ static void
+ InstallSprings (TopologyReader::ConstLinksIterator first,
+ TopologyReader::ConstLinksIterator end);
+};
+
+} // namespace ns3
+
+#endif // SPRING_MOBILITY_HELPER_H
diff --git a/utils/spring-mobility-model.cc b/utils/spring-mobility-model.cc
new file mode 100644
index 0000000..5fb968b
--- /dev/null
+++ b/utils/spring-mobility-model.cc
@@ -0,0 +1,188 @@
+/* -*- 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;
+
+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 (1000.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.6),
+ MakeDoubleAccessor (&SpringMobilityModel::m_dampingFactor),
+ MakeDoubleChecker<double> ())
+ ;
+
+ return tid;
+}
+
+SpringMobilityModel::SpringMobilityModel ()
+ : m_position (0,0,0)
+ , m_velocity (0,0,0)
+ , m_stable (false)
+{
+}
+
+SpringMobilityModel::~SpringMobilityModel ()
+{
+}
+
+void
+SpringMobilityModel::AddSpring (Ptr<MobilityModel> node)
+{
+ m_springs.push_back (node);
+}
+
+void
+SpringMobilityModel::DoStart ()
+{
+ // m_updateEvent = Simulator::Schedule (Seconds(0.05), &SpringMobilityModel::Update, this);
+
+ // Simulator::Schedule (Seconds(2.0), &SpringMobilityModel::Test, this);
+}
+
+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;
+
+ if (m_totalKineticEnergy < m_epsilon)
+ {
+ m_stable = true;
+ NS_LOG_INFO ("Stabilized with " << m_totalKineticEnergy);
+ }
+
+ NotifyCourseChange ();
+ // m_updateEvent = Simulator::Schedule (Seconds(0.05), &SpringMobilityModel::Update, this);
+}
+
+Vector
+SpringMobilityModel::DoGetPosition (void) const
+{
+ // NS_LOG_FUNCTION (this << m_position);
+ Update ();
+
+ return m_position;
+}
+void
+SpringMobilityModel::DoSetPosition (const Vector &position)
+{
+ // NS_LOG_FUNCTION (this << position);
+ m_position = position;
+
+ NotifyCourseChange ();
+ m_stable = false;
+}
+Vector
+SpringMobilityModel::DoGetVelocity (void) const
+{
+ return m_velocity;
+}
+
+} // namespace ns3
diff --git a/utils/spring-mobility-model.h b/utils/spring-mobility-model.h
new file mode 100644
index 0000000..553ab9d
--- /dev/null
+++ b/utils/spring-mobility-model.h
@@ -0,0 +1,94 @@
+/* -*- 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:
+ */
+#ifndef SPRING_MOBILITY_MODEL_H
+#define SPRING_MOBILITY_MODEL_H
+
+#include "ns3/mobility-model.h"
+#include "ns3/nstime.h"
+#include "ns3/event-id.h"
+
+namespace ns3 {
+
+/**
+ * \ingroup mobility
+ *
+ * \brief
+ */
+class SpringMobilityModel : public MobilityModel
+{
+public:
+ static TypeId GetTypeId (void);
+
+ /**
+ * Create a position located at coordinates (0,0,0) with velocity (0,0,0)
+ */
+ SpringMobilityModel ();
+ virtual ~SpringMobilityModel ();
+
+ /**
+ * \brief Attach node by a spring
+ * \param node MobilityModel layer of the attaching node
+ */
+ void
+ AddSpring (Ptr<MobilityModel> node);
+
+private:
+ // from Object
+ virtual void
+ DoStart ();
+
+ // from MobilityModel
+ virtual Vector
+ DoGetPosition (void) const;
+
+ virtual void
+ DoSetPosition (const Vector &position);
+
+ virtual Vector
+ DoGetVelocity (void) const;
+
+ // Updating positions
+ void
+ Update (void) const;
+
+private:
+ double m_epsilon;
+
+ double m_nodeMass;
+ double m_nodeCharge;
+ double m_springNormalLength;
+ double m_springConstant;
+ double m_dampingFactor;
+
+ static double m_totalKineticEnergy;
+
+ mutable Vector m_position;
+ mutable Vector m_velocity;
+ mutable bool m_stable;
+ mutable Time m_lastTime;
+
+ EventId m_updateEvent;
+
+ std::list<Ptr<MobilityModel> > m_springs;
+};
+
+} // namespace ns3
+
+#endif // SPRING_MOBILITY_MODEL_H