Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

energy model #5

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pons/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from .mobility import generate_randomwaypoint_movement, OneMovement, OneMovementManager
from .node import generate_nodes, Node, NetworkSettings, Message, BROADCAST_ADDR
from .routing import Router, EpidemicRouter
from .energy import EnergyModel, DefaultEnergyModel, ESP32Wifi

import random

Expand Down
45 changes: 45 additions & 0 deletions pons/energy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class EnergyModel:
"""base class for energy models"""
def __init__(self, max_energy: float, idle: float, receive: float, forward: float, name: str):
"""
@param max_energy: max energy of the model
@param idle: amount of energy the model consumes in idle
@param receive: amount of energy the model consumes upon message receival
@param forward: amount of energy the model consumes upon forward of message
"""
self.max_energy: float = max_energy
self._idle: float = idle
self._receive: float = receive
self._forward: float = forward
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be sending or tx

self._name: str = name
self.energy: float = max_energy

def __str__(self) -> str:
return self._name

def __repr__(self) -> str:
return str(self)

def on_receive(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the function name should match the one in node.py from where it is called, e.g., on_recv

"""handling message receive"""
self.energy -= self._receive
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is the transmission time? sending costs a specific amount of energy per time. so a large chunk of data might need several minutes and thus should consume more power


def on_forward(self):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the function name should match the one in node.py from where it is called, e.g., on_send
forwarding is something from the routing side, on the lower levels its just a transmission that consumes energy

"""handling message forward"""
self.energy -= self._forward
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is the transmission time? sending costs a specific amount of energy per time. so a large chunk of data might need several minutes and thus should consume more power


def on_idle(self, interval: float = 1.0):
"""handling idle"""
self.energy -= self._idle * interval


class DefaultEnergyModel(EnergyModel):
"""unlimited energy model - equivalent to no energy model"""
def __init__(self):
super().__init__(100, 0, 0, 0, "DefaultEnergyModel")


class ESP32Wifi(EnergyModel):
"""energy model simulating the esp32 using wifi"""
def __init__(self, initial_energy: int = 100000):
super().__init__(initial_energy, 90, 100, 190, "ESP32 Wifi")
43 changes: 35 additions & 8 deletions pons/node.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
from __future__ import annotations

import math
from copy import deepcopy
import pons
import random

from copy import deepcopy
from typing import TYPE_CHECKING

import pons

if TYPE_CHECKING:
import pons.routing

Expand Down Expand Up @@ -71,7 +70,7 @@ class Node(object):
"""A The ONE movement scenario.
"""

def __init__(self, node_id: int, net: List[NetworkSettings] = None, router: pons.routing.Router = None):
def __init__(self, node_id: int, net: List[NetworkSettings] = None, router: pons.routing.Router = None, energy_model: pons.EnergyModel = None):
self.id = node_id
self.x = 0.0
self.y = 0.0
Expand All @@ -80,6 +79,9 @@ def __init__(self, node_id: int, net: List[NetworkSettings] = None, router: pons
for n in net:
self.net[n.name] = deepcopy(n)
self.router = router
self.energy_model = energy_model
if self.energy_model is None:
self.energy_model = pons.DefaultEnergyModel()
self.neighbors = {}
for net in self.net.values():
self.neighbors[net.name] = []
Expand Down Expand Up @@ -112,13 +114,15 @@ def send(self, netsim: pons.NetSim, to_nid: int, msg: Message):
for nid in self.neighbors[net.name]:
receiver = netsim.nodes[nid]
netsim.net_stats["tx"] += 1
self.energy_model.on_forward()
pons.delayed_execution(netsim.env, tx_time,
receiver.on_recv(netsim, self.id, msg))
else:
if to_nid in self.neighbors[net.name]:
# self.log("sending msg %s to %d" % (msg, to_nid))
receiver = netsim.nodes[to_nid]
netsim.net_stats["tx"] += 1
self.energy_model.on_forward()
pons.delayed_execution(netsim.env, tx_time,
receiver.on_recv(netsim, self.id, msg))
else:
Expand All @@ -136,6 +140,7 @@ def on_recv(self, netsim: pons.NetSim, from_nid: int, msg: Message):
if from_nid in self.neighbors[net.name]:
# print("Node %d received msg %s from %d" % (to_nid, msg, from_nid))
netsim.net_stats["rx"] += 1
self.energy_model.on_receive()
if self.router is not None:
if msg.id == "HELLO":
self.router.on_scan_received(deepcopy(msg), from_nid)
Expand All @@ -147,11 +152,33 @@ def on_recv(self, netsim: pons.NetSim, from_nid: int, msg: Message):
netsim.net_stats["drop"] += 1


def generate_nodes(num_nodes: int, offset: int = 0, net: List[NetworkSettings] = None, router: pons.routing.Router = None):
def generate_nodes(
num_nodes: int,
offset: int = 0,
net: List[NetworkSettings] = None,
router: pons.routing.Router = None,
energy_model: pons.EnergyModel or List[pons.EnergyModel] = None
):
"""
generates nodes
@param num_nodes: number of nodes
@param offset: offset for the node ids
@param net: a list of network settings
@param router: the router to use (optional)
@param energy_model: the energy model(s) (optional) -
Either one energy model or a list of models matching num_nodes.
If only one is given, it is used for every nodes.
"""
nodes = []
if net == None:
if net is None:
net = []
if energy_model is None:
energy_model = pons.DefaultEnergyModel()
if isinstance(energy_model, pons.EnergyModel):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe some errorhandling here would be nice with user feedback

energy_model = [deepcopy(energy_model) for i in range(0, num_nodes)]
if len(energy_model) != num_nodes:
raise ValueError("size of energy_model should match num_nodes")
for i in range(num_nodes):
nodes.append(Node(i + offset, net=deepcopy(net),
router=deepcopy(router)))
router=deepcopy(router), energy_model=energy_model[i]))
return nodes
10 changes: 5 additions & 5 deletions pons/routing/directdelivery.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .router import Router
import pons


class DirectDeliveryRouter(Router):
Expand Down Expand Up @@ -28,21 +29,20 @@ def on_peer_discovered(self, peer_id):
for msg in self.store:
self.forward(msg)

def on_msg_received(self, msg, remote_id):
# self.log("msg received: %s from %d" % (msg, remote_id))
def on_msg_received(self, msg: pons.Message, remote_id: int):
self.netsim.routing_stats['relayed'] += 1
if not self.is_msg_known(msg):
self.remember(remote_id, msg)
msg.hops += 1
self.store_add(msg)
if msg.dst == self.my_id:
# self.log("msg arrived", self.my_id)
# print("msg arrived", self.my_id)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did you replace the central logging with a print statement?

self.netsim.routing_stats['delivered'] += 1
self.netsim.routing_stats['hops'] += msg.hops
self.netsim.routing_stats['latency'] += self.env.now - msg.created
else:
# self.log("msg not arrived yet", self.my_id)
# print("msg not arrived yet", self.my_id)
self.forward(msg)
else:
# self.log("msg already known", self.history)
# print("msg already known", self.history)
self.netsim.routing_stats['dups'] += 1
12 changes: 6 additions & 6 deletions pons/routing/epidemic.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .router import Router
import pons


class EpidemicRouter(Router):
Expand Down Expand Up @@ -41,21 +42,20 @@ def on_peer_discovered(self, peer_id):
else:
self.forward(msg)

def on_msg_received(self, msg, remote_id):
# self.log("msg received: %s from %d" % (msg, remote_id))
def on_msg_received(self, msg: pons.Message, remote_id: int):
self.netsim.routing_stats['relayed'] += 1
if not self.is_msg_known(msg):
self.remember(remote_id, msg)
msg.hops += 1
self.store_add(msg)
if msg.dst == self.my_id:
# self.log("msg arrived %s" % msg)
# print("msg arrived", self.my_id)
self.netsim.routing_stats['delivered'] += 1
self.netsim.routing_stats['hops'] += msg.hops
self.netsim.routing_stats['latency'] += self.env.now - msg.created
else:
# self.log("msg not arrived yet", self.my_id)
# print("msg not arrived yet", self.my_id)
self.forward(msg)
else:
# self.log("msg already known", self.history)
self.netsim.routing_stats['dups'] += 1
# print("msg already known", self.history)
self.netsim.routing_stats['dups'] += 1
12 changes: 6 additions & 6 deletions pons/routing/firstcontact.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from .router import Router
import pons


class FirstContactRouter(Router):
Expand Down Expand Up @@ -41,21 +42,20 @@ def on_peer_discovered(self, peer_id):
for msg in self.store:
self.forward(msg)

def on_msg_received(self, msg, remote_id):
# self.log("msg received: %s from %d" % (msg, remote_id))
def on_msg_received(self, msg: pons.Message, remote_id: int):
self.netsim.routing_stats['relayed'] += 1
if not self.is_msg_known(msg):
self.remember(remote_id, msg)
msg.hops += 1
self.store_add(msg)
if msg.dst == self.my_id:
# self.log("msg arrived", self.my_id)
# print("msg arrived", self.my_id)
self.netsim.routing_stats['delivered'] += 1
self.netsim.routing_stats['hops'] += msg.hops
self.netsim.routing_stats['latency'] += self.env.now - msg.created
else:
# self.log("msg not arrived yet", self.my_id)
# print("msg not arrived yet", self.my_id)
self.forward(msg)
else:
# self.log("msg already known", self.history)
self.netsim.routing_stats['dups'] += 1
# print("msg already known", self.history)
self.netsim.routing_stats['dups'] += 1
9 changes: 5 additions & 4 deletions pons/routing/router.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@

from copy import copy
import pons

HELLO_MSG_SIZE = 42
Expand Down Expand Up @@ -68,7 +66,8 @@ def start(self, netsim: pons.NetSim, my_id: int):
self.env.process(self.scan())

def scan(self):
while True:
node = self.netsim.nodes[self.my_id]
while node.energy_model.energy > 0:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why have this check here? isn't it enough to have an energy check in the send and receive functions of node.py so the router or any other upper layers are not relevant any more? ofc the scan loop can also contain the check to avoid some CPU cycles but deactivating the node functions is the safe bet to ensure that no further communication happens

# print("[%s] scanning..." % self.my_id)

# assume some kind of peer discovery mechanism
Expand All @@ -88,14 +87,16 @@ def scan(self):
yield self.env.timeout(self.scan_interval)

def on_scan_received(self, msg: pons.Message, remote_id: int):
if self.netsim.nodes[self.my_id].energy_model.energy <= 0:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why have this check here? isn't it enough to have an energy check in the send and receive functions of node.py so the router or any other upper layers are not relevant any more? ofc the scan loop can also contain the check to avoid some CPU cycles but deactivating the node functions is the safe bet to ensure that no further communication happens

return
# self.log("[%s] scan received: %s from %d" %
# (self.my_id, msg, remote_id))
if msg.id == "HELLO" and remote_id not in self.peers:
self.peers.append(remote_id)
# self.log("NEW PEER: %d" % remote_id)
self.on_peer_discovered(remote_id)
# elif remote_id in self.peers:
# self.log("DUP PEER: %d" % remote_id)
# self.log("DUP PEER: %d" % remote_id)

def on_peer_discovered(self, peer_id):
self.log("peer discovered: %d" % peer_id)
Expand Down
6 changes: 3 additions & 3 deletions pons/routing/sprayandwait.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import copy
import math
import pons


class SprayAndWaitRouter(Router):
Expand Down Expand Up @@ -58,8 +59,7 @@ def on_peer_discovered(self, peer_id):
for msg in self.store:
self.forward(msg)

def on_msg_received(self, msg, remote_id):
# self.log("msg received: %s from %d" % (msg, remote_id))
def on_msg_received(self, msg: pons.Message, remote_id: int):
self.netsim.routing_stats['relayed'] += 1
if not self.is_msg_known(msg):
self.remember(remote_id, msg)
Expand All @@ -75,4 +75,4 @@ def on_msg_received(self, msg, remote_id):
self.forward(msg)
else:
# print("msg already known", self.history)
self.netsim.routing_stats['dups'] += 1
self.netsim.routing_stats['dups'] += 1
15 changes: 15 additions & 0 deletions pons/simulation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import simpy
import time
import pons
from multiprocessing import Process


class NetSim(object):
Expand Down Expand Up @@ -45,6 +46,17 @@ def start_peers_logger(self, interval=1.0):
for node in self.nodes:
print(node.neighbors)

def start_energy_manager(self, interval=1.0):
"""start an energy manager"""
while True:
yield self.env.timeout(interval)
for node in self.nodes:
node.energy_model.on_idle(interval)

def should_start_energy_manager(self) -> bool:
"""check if any node has another energy model than the default one"""
return not all(isinstance(node, pons.DefaultEnergyModel) for node in self.nodes)

def setup(self):
print("initialize simulation")

Expand All @@ -58,6 +70,9 @@ def setup(self):
if self.config is not None and self.config.get("peers_logger", True):
self.env.process(self.start_peers_logger())

if self.should_start_energy_manager():
self.env.process(self.start_energy_manager())

for n in self.nodes:
n.start(self)

Expand Down
3 changes: 1 addition & 2 deletions sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
net = pons.NetworkSettings("WIFI_50m", range=NET_RANGE)
epidemic = pons.routing.EpidemicRouter(capacity=CAPACITY)

nodes = pons.generate_nodes(
NUM_NODES, net=[net], router=epidemic)
nodes = pons.generate_nodes(NUM_NODES, net=[net], router=epidemic)
config = {"movement_logger": False, "peers_logger": False}

msggenconfig = {"type": "single", "interval": 30, "src": (
Expand Down
Loading