Modifying SpringMobilityModel to make all nodes readjust after even one
node changes its position (previously only this node was adjusting itself)

SpringMobilityModel now updates positions based on internal (static) timer
diff --git a/examples/sprint-pops.latencies b/examples/sprint-pops.latencies
new file mode 100644
index 0000000..7c3fd07
--- /dev/null
+++ b/examples/sprint-pops.latencies
@@ -0,0 +1,84 @@
+0 1 0.312
+2 3 10.786
+1 4 0.222
+1 5 1.035
+1 6 1.414
+1 7 1.24
+1 8 0.814
+1 9 19.532
+1 10 0.352
+1 11 4.593
+12 13 2.622
+14 15 0.207
+14 16 12.098
+14 17 13.941
+15 18 7.791
+15 19 38.946
+20 21 19.775
+20 22 0.345
+23 24 5.337
+25 26 0.276
+27 28 0.645
+8 20 19.787
+8 16 8.352
+8 28 1.578
+8 24 10.459
+8 26 5.005
+21 31 20.741
+13 32 4.737
+13 33 1.424
+17 35 2.091
+17 20 14.409
+17 18 7.13
+17 28 6.214
+17 24 6.437
+17 25 1.315
+17 26 1.176
+17 29 3.282
+17 36 2.478
+11 24 5.751
+11 38 3.235
+11 17 4.718
+33 39 1.817
+33 40 2.035
+6 7 0.327
+6 28 0.97
+6 25 5.176
+6 8 0.612
+6 17 5.725
+6 34 0.802
+6 11 6.007
+39 42 0.699
+16 24 3.655
+16 29 0.135
+16 17 3.286
+31 45 0.268
+31 46 0.268
+31 37 3.375
+31 47 2.708
+32 48 1.712
+32 44 2.329
+32 42 1.595
+48 49 3.201
+7 13 31.13
+38 43 1.643
+9 15 5.513
+9 20 0.437
+9 31 2.648
+9 30 0.124
+9 17 14.774
+9 19 42.03
+5 32 28.338
+5 8 0.359
+5 7 0.316
+18 23 0.779
+40 48 2.34
+40 49 2.529
+24 38 7.706
+24 31 9.827
+24 45 10.045
+24 50 0.092
+3 9 59.812
+19 41 26.19
+19 20 42.057
+19 51 14.125
diff --git a/examples/sprint-pops.weights b/examples/sprint-pops.weights
new file mode 100644
index 0000000..387a37f
--- /dev/null
+++ b/examples/sprint-pops.weights
@@ -0,0 +1,84 @@
+0 1 312
+2 3 10786
+1 4 222
+1 5 2500
+1 6 4000
+1 7 2500
+1 8 3860
+1 9 11769
+1 10 352
+1 11 3500
+12 13 2622
+14 15 500
+14 16 14192
+14 17 8909
+15 18 11747
+15 19 44530
+20 21 19775
+20 22 345
+23 24 5337
+25 26 2184
+27 28 645
+8 20 11409
+8 16 8282
+8 28 3000
+8 24 7735
+8 26 5500
+21 31 20741
+13 32 7552
+13 33 1500
+17 35 2091
+17 20 14409
+17 18 4337
+17 28 4000
+17 24 5735
+17 25 1315
+17 26 2500
+17 29 3282
+17 36 2478
+11 24 5096
+11 38 3235
+11 17 4360
+33 39 2000
+33 40 3000
+6 7 2500
+6 28 6860
+6 25 5176
+6 8 5860
+6 17 3860
+6 34 802
+6 11 5500
+39 42 699
+16 24 1547
+16 29 3000
+16 17 5282
+31 45 500
+31 46 268
+31 37 3375
+31 47 2708
+32 48 1712
+32 44 2329
+32 42 3352
+48 49 3201
+7 13 30890
+38 43 1643
+9 15 5500
+9 20 2500
+9 31 4735
+9 30 124
+9 17 13909
+9 19 42030
+5 32 28338
+5 8 2360
+5 7 2000
+18 23 5735
+40 48 2340
+40 49 2529
+24 38 2860
+24 31 9909
+24 45 10409
+24 50 92
+3 9 59812
+19 41 26190
+19 20 39530
+19 51 14125
diff --git a/examples/sprint-topology.cc b/examples/sprint-topology.cc
index 3a53c35..b3baa7c 100644
--- a/examples/sprint-topology.cc
+++ b/examples/sprint-topology.cc
@@ -35,6 +35,13 @@
 
 NS_LOG_COMPONENT_DEFINE ("CcnxSprintTopology");
 
+void PrintTime ()
+{
+  NS_LOG_INFO (Simulator::Now ());
+
+  Simulator::Schedule (Seconds (1.0), PrintTime);
+}
+
 int 
 main (int argc, char *argv[])
 {
@@ -42,16 +49,20 @@
   // Packet::EnablePrinting();
   string weights ("./src/NDNabstraction/examples/sprint.weights");
   string latencies ("./src/NDNabstraction/examples/sprint.latencies");
+  string positions;
     
   Time finishTime = Seconds (2.0);
   string animationFile;
   string strategy = "ns3::CcnxFloodingStrategy";
+  string save;
   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.AddValue ("positions", "Positions files", positions);
+  cmd.AddValue ("save", "Save positions to a file", save);
   cmd.Parse (argc, argv);
 
   // ------------------------------------------------------------
@@ -61,9 +72,16 @@
   RocketfuelWeightsReader reader ("/sprint");
   reader.SetBoundingBox (0, 0, 400, 250);
 
+  if (!positions.empty())
+    {
+      reader.SetFileName (positions);
+      reader.SetFileType (RocketfuelWeightsReader::POSITIONS);
+      reader.Read ();
+    }
+  
   reader.SetFileName (weights);
   reader.SetFileType (RocketfuelWeightsReader::WEIGHTS);    
-  NodeContainer nodes = reader.Read ();
+  reader.Read ();
 
   reader.SetFileName (latencies);
   reader.SetFileType (RocketfuelWeightsReader::LATENCIES);    
@@ -76,13 +94,13 @@
       return -1;
     }
     
-  NS_LOG_INFO("Nodes = " << nodes.GetN());
+  NS_LOG_INFO("Nodes = " << reader.GetNodes ().GetN());
   NS_LOG_INFO("Links = " << reader.LinksSize ());
     
   InternetStackHelper stack;
   Ipv4GlobalRoutingHelper ipv4RoutingHelper ("ns3::Ipv4GlobalRoutingOrderedNexthops");
   stack.SetRoutingHelper (ipv4RoutingHelper);
-  stack.Install (nodes);
+  stack.Install (reader.GetNodes ());
 
   reader.AssignIpv4Addresses (Ipv4Address ("10.0.0.0"));
 
@@ -98,14 +116,21 @@
   // ccnxHelper.InstallFakeGlobalRoutes ();
   // ccnxHelper.InstallRouteTo (Names::Find<Node> ("/sprint", "San+Jose,+CA4062"));
 
-  // Simulator::Schedule (Seconds (1.0), PrintFIBs);
-  // PrintFIBs ();
-
   Simulator::Stop (finishTime);
+  Simulator::Schedule (Seconds (1.0), PrintTime);
+
+  // reader.SavePositions (save+".debug");
 
   NS_LOG_INFO ("Run Simulation.");
   Simulator::Run ();
   Simulator::Destroy ();
   NS_LOG_INFO ("Done.");
+
+  if (!save.empty ())
+    {
+      NS_LOG_INFO ("Saving positions.");
+      reader.SavePositions (save);
+    }
+  
   return 0;
 }
diff --git a/model/annotated-topology-reader.cc b/model/annotated-topology-reader.cc
index 2ca17eb..194a90c 100644
--- a/model/annotated-topology-reader.cc
+++ b/model/annotated-topology-reader.cc
@@ -101,21 +101,28 @@
   loc->SetPosition (Vector (posX, posY, 0));
 
   Names::Add (m_path, name, node);
+  m_nodes.Add (node);
 
   return node;
 }
 
 NodeContainer
+AnnotatedTopologyReader::GetNodes () const
+{
+  return m_nodes;
+}
+
+
+NodeContainer
 AnnotatedTopologyReader::Read (void)
 {
   ifstream topgen;
   topgen.open (GetFileName ().c_str ());
-  NodeContainer nodes;
         
   if ( !topgen.is_open () )
     {
       NS_LOG_ERROR ("Cannot open file " << GetFileName () << " for reading");
-      return nodes;
+      return m_nodes;
     }
 
   while (!topgen.eof ())
@@ -138,8 +145,9 @@
       double latitude, longitude;
 
       lineBuffer >> name >> city >> latitude >> longitude;
+      if (name.empty ()) continue;
+
       Ptr<Node> node = CreateNode (name, m_scale*longitude, -m_scale*latitude);
-      nodes.Add (node);
     }
 
   map<string, set<string> > processedLinks; // to eliminate duplications
@@ -185,12 +193,12 @@
       NS_LOG_DEBUG ("New link " << from << " <==> " << to << " / " << capacity << " with " << metric << " metric (" << delay << ", " << maxPackets << ")");
     }
         
-  NS_LOG_INFO ("Annotated topology created with " << nodes.GetN () << " nodes and " << LinksSize () << " links");
+  NS_LOG_INFO ("Annotated topology created with " << m_nodes.GetN () << " nodes and " << LinksSize () << " links");
   topgen.close ();
         
   ApplySettings ();
   
-  return nodes;
+  return m_nodes;
 }
     
 void
diff --git a/model/annotated-topology-reader.h b/model/annotated-topology-reader.h
index cbcd890..b9268b8 100644
--- a/model/annotated-topology-reader.h
+++ b/model/annotated-topology-reader.h
@@ -53,8 +53,14 @@
    *
    * \return the container of the nodes created (or empty container if there was an error)
    */
-  virtual
-  NodeContainer Read (void);
+  virtual NodeContainer
+  Read ();
+
+  /**
+   * \brief Get nodes read by the reader
+   */
+  NodeContainer
+  GetNodes () const;
     
   /**
    * \brief Assign IPv4 addresses to all links
@@ -92,6 +98,7 @@
     
 protected:
   std::string m_path;
+  NodeContainer m_nodes;
 
 private:
   AnnotatedTopologyReader (const AnnotatedTopologyReader&);
diff --git a/model/rocketfuel-weights-reader.cc b/model/rocketfuel-weights-reader.cc
index 448464e..f6895fa 100644
--- a/model/rocketfuel-weights-reader.cc
+++ b/model/rocketfuel-weights-reader.cc
@@ -39,8 +39,7 @@
 #include "ns3/uinteger.h"
 #include "ns3/ipv4-address.h"
 
-#include "ns3/constant-position-mobility-model.h"
-#include "ns3/random-variable.h"
+#include "ns3/mobility-model.h"
 
 #include <regex.h>
 
@@ -78,14 +77,16 @@
 NodeContainer
 RocketfuelWeightsReader::Read ()
 {
+  if (m_inputType == POSITIONS)
+    return AnnotatedTopologyReader::Read ();
+  
   ifstream topgen;
   topgen.open (GetFileName ().c_str ());
-  NodeContainer nodes;
         
   if ( !topgen.is_open () )
     {
       NS_LOG_ERROR ("Cannot open file " << GetFileName () << " for reading");
-      return nodes;
+      return m_nodes;
     }
 
   map<string, set<string> > processedLinks; // to eliminate duplications
@@ -117,14 +118,12 @@
       if (fromNode == 0)
         {
           fromNode = CreateNode (from);
-          nodes.Add (fromNode);
         }
 
       Ptr<Node> toNode   = Names::Find<Node> (m_path, to);
       if (toNode == 0)
         {
           toNode = CreateNode (to);
-          nodes.Add (toNode);
         }
 
       Link *link;
@@ -142,8 +141,8 @@
         {
         case WEIGHTS:
           {
-            double metric = boost::lexical_cast<double> (attribute);
-            link->SetAttribute ("OSPF", boost::lexical_cast<string> (metric*2));
+            uint16_t metric = boost::lexical_cast<uint16_t> (attribute);
+            link->SetAttribute ("OSPF", boost::lexical_cast<string> (metric));
             break;
           }
         case LATENCIES:
@@ -165,9 +164,9 @@
 
   if (!repeatedRun)
     {
-      NS_LOG_INFO ("Rocketfuel topology created with " << nodes.GetN () << " nodes and " << LinksSize () << " links");
+      NS_LOG_INFO ("Rocketfuel topology created with " << m_nodes.GetN () << " nodes and " << LinksSize () << " links");
     }
-  return nodes;
+  return m_nodes;
 }
 
 void
@@ -178,6 +177,23 @@
   SpringMobilityHelper::InstallSprings (LinksBegin (), LinksEnd ());
 }
 
+void
+RocketfuelWeightsReader::SavePositions (const std::string &file) const
+{
+  ofstream os (file.c_str (), ios::trunc);
+  os << "router\n";
+  
+  for (NodeContainer::Iterator node = m_nodes.Begin ();
+       node != m_nodes.End ();
+       node++)
+    {
+      std::string name = Names::FindName (*node);
+      Ptr<MobilityModel> mobility = (*node)->GetObject<MobilityModel> ();
+      Vector position = mobility->GetPosition ();
+
+      os << name << "\t" << "unknown" << "\t" << -position.y << "\t" << position.x << "\n";
+    }
+}
 
 // void
 // RocketfuelWeightsReader::Cheat (NodeContainer &nodes)
diff --git a/model/rocketfuel-weights-reader.h b/model/rocketfuel-weights-reader.h
index ecf4905..cf6a784 100644
--- a/model/rocketfuel-weights-reader.h
+++ b/model/rocketfuel-weights-reader.h
@@ -64,12 +64,13 @@
   enum
     {
       WEIGHTS,
-      LATENCIES
+      LATENCIES,
+      POSITIONS
     };
 
-  // void
-  // Cheat (NodeContainer &nodes);
-
+  void
+  SavePositions (const std::string &file) const;
+  
 private:
   RocketfuelWeightsReader (const RocketfuelWeightsReader&);
   RocketfuelWeightsReader& operator= (const RocketfuelWeightsReader&);
diff --git a/utils/spring-mobility-model.cc b/utils/spring-mobility-model.cc
index 5fb968b..170b428 100644
--- a/utils/spring-mobility-model.cc
+++ b/utils/spring-mobility-model.cc
@@ -33,6 +33,9 @@
 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; 
 
@@ -41,10 +44,10 @@
   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 ("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),
@@ -62,7 +65,7 @@
                    MakeDoubleAccessor (&SpringMobilityModel::m_springConstant),
                    MakeDoubleChecker<double> ())
     .AddAttribute ("DampingFactor", "Dumping factor",
-                   DoubleValue (0.6),
+                   DoubleValue (0.8),
                    MakeDoubleAccessor (&SpringMobilityModel::m_dampingFactor),
                    MakeDoubleChecker<double> ())
     ;
@@ -73,7 +76,6 @@
 SpringMobilityModel::SpringMobilityModel ()
   : m_position (0,0,0)
   , m_velocity (0,0,0)
-  , m_stable (false)
 {
 }
 
@@ -90,15 +92,35 @@
 void
 SpringMobilityModel::DoStart ()
 {
-  // m_updateEvent = Simulator::Schedule (Seconds(0.05), &SpringMobilityModel::Update, this);
+  if (!m_updateEvent.IsRunning ())
+    m_updateEvent = Simulator::Schedule (Seconds(0.05), SpringMobilityModel::UpdateAll);
+}
 
-  // Simulator::Schedule (Seconds(2.0), &SpringMobilityModel::Test, this);
+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);
+  NS_LOG_FUNCTION (this << m_stable << m_position << m_velocity);
   if (m_stable) return;
   Time now = Simulator::Now ();
 
@@ -152,22 +174,13 @@
   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 
@@ -178,6 +191,19 @@
 
   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
diff --git a/utils/spring-mobility-model.h b/utils/spring-mobility-model.h
index 553ab9d..700c994 100644
--- a/utils/spring-mobility-model.h
+++ b/utils/spring-mobility-model.h
@@ -68,8 +68,11 @@
   void 
   Update (void) const;
 
+  static void
+  UpdateAll ();
+
 private:
-  double m_epsilon;
+  static double m_epsilon;
 
   double m_nodeMass;
   double m_nodeCharge;
@@ -78,14 +81,13 @@
   double m_dampingFactor;
 
   static double m_totalKineticEnergy;  
+  static bool m_stable;
+  static EventId m_updateEvent;
   
   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;
 };