Skip to content
Snippets Groups Projects

pydtn agkmeans and version 1.0

Merged Hunter McConnell (rtm534) requested to merge summer2022 into develop
1 file
+ 129
99
Compare changes
  • Side-by-side
  • Inline
+ 129
99
@@ -4,10 +4,10 @@ __author__ = "Hunter McConnell <hunter.mcconnell@usask.ca>"
import sys
import tkinter as tk
from tkinter import DISABLED, W, filedialog as fd
import yaml
from yaml.loader import Loader
from tkinter import BOTH, DISABLED, NSEW, TRUE, W, X, filedialog as fd
from pydtnsim import Node, EpidemicNode, ProphetNode, ProphetNodeSingle
from pydtnsim.community import BubbleKCliqueNode, BubbleLouvainNode
@@ -16,17 +16,17 @@ from pydtnsim.community import HCBFAGKmeansNode, BubbleAGKmeansNode
# update here for options to appear in gui
NODES = [
Node, # direct delivery
EpidemicNode,
BubbleKCliqueNode,
HCBFKCliqueNode,
BubbleLouvainNode,
HCBFLouvainNode,
HCBFAGKmeansNode,
BubbleAGKmeansNode,
ProphetNode,
ProphetNodeSingle,
]
Node, # direct delivery
EpidemicNode,
BubbleKCliqueNode,
HCBFKCliqueNode,
BubbleLouvainNode,
HCBFLouvainNode,
HCBFAGKmeansNode,
BubbleAGKmeansNode,
ProphetNode,
ProphetNodeSingle,
]
BUFFER_TYPES = [
"FILO",
@@ -61,22 +61,23 @@ DEPENDANT = [
"latency-total-delay",
]
class SimOptions(tk.LabelFrame):
"""General options."""
def __init__(self, parent=None):
"""Create and format sim options."""
tk.LabelFrame.__init__(self, parent, text="SimOptions")
self.parent = parent
tk.Label(self, text="Config File:").grid(row=0, column=0)
self. config_var = tk.StringVar()
tk.Entry(self, textvariable=self. config_var).grid(row=0, column=1)
self.config_var = tk.StringVar()
tk.Entry(self, textvariable=self.config_var).grid(row=0, column=1)
tk.Label(self, text="Contact dir:").grid(row=1, column=0)
self.trace_var = tk.StringVar()
tk.Entry(self, textvariable=self.trace_var).grid(row=1, column=1)
# output file
# todo: file dialog?
# todo: validation?
tk.Label(self, text="Output dir:").grid(row=2, column=0)
self.out_var = tk.StringVar()
tk.Entry(self, textvariable=self.out_var).grid(row=2, column=1)
@@ -88,9 +89,9 @@ class SimOptions(tk.LabelFrame):
tk.Label(self, text="Batches:").grid(row=4, column=0)
self.batch_var = tk.IntVar(value=1)
tk.Entry(self, textvariable=self.batch_var).grid(row=4, column=1)
def getOptions(self):
"""Return a dictionary of sim options"""
def get_options(self):
"""Return a dictionary of sim options."""
param = {}
param["config"] = self.config_var.get()
param["contact_dir"] = self.trace_var.get()
@@ -105,19 +106,23 @@ class SimOptions(tk.LabelFrame):
return param
def setOptions(self, options):
def set_options(self, options):
"""Display current options."""
self.config_var.set(options["config"])
self.trace_var.set(options["contact_dir"])
self.out_var.set(options["output_dir"])
tmp = ", ".join(str(i) for i in options["seeds"])
self.seeds_var.set(tmp)
self.batch_var.set(options["batch"])
class NodeOptions(tk.LabelFrame):
"""Options that get passed for node creation."""
# pylint: disable=too-many-instance-attributes
def __init__(self, parent):
"""Create and format node options."""
tk.LabelFrame.__init__(self, parent, text="NodeOptions")
self.parent = parent
@@ -137,26 +142,26 @@ class NodeOptions(tk.LabelFrame):
self.cycle_var = tk.IntVar(value=300)
tk.Entry(self, textvariable=self.cycle_var).grid(row=3, column=1)
tk.Label(self, text="Buffer Capacity (??):").grid(row=4, column=0)
tk.Label(self, text="Buffer Capacity (Mb):").grid(row=4, column=0)
self.buffer_var = tk.StringVar(value="inf")
tk.Entry(self, textvariable=self.buffer_var).grid(row=4, column=1)
tk.Label(self, text="Bandwidth (??):").grid(row=5, column=0)
tk.Label(self, text="Bandwidth (Mb):").grid(row=5, column=0)
self.bandwidth_var = tk.StringVar(value="inf")
tk.Entry(self, textvariable=self.bandwidth_var).grid(row=5, column=1)
frame1 = tk.Frame(self)
frame1.grid(row=0, column=3, rowspan = 6)
frame1.grid(row=0, column=3, rowspan=6)
self.buffer_choice = tk.StringVar()
self.buffer_choice.set("filo")
for choice in BUFFER_TYPES:
tk.Radiobutton(frame1, text=choice, variable=self.buffer_choice, value=choice).pack(anchor=W, ipadx=15)
tk.Radiobutton(
frame1, text=choice, variable=self.buffer_choice, value=choice
).pack(anchor=W, ipadx=15)
def getOptions(self):
"""Return a dictionary of node options"""
def get_options(self):
"""Return a dictionary of node options."""
param = {}
param["epoch"] = self.epoch_var.get()
param["k"] = self.k_var.get()
@@ -168,7 +173,8 @@ class NodeOptions(tk.LabelFrame):
return param
def setOptions(self, options):
def set_options(self, options):
"""Display current options."""
self.epoch_var.set(options["epoch"])
self.k_var.set(options["k"])
self.agk_var.set(options["agk"])
@@ -176,32 +182,37 @@ class NodeOptions(tk.LabelFrame):
self.buffer_var.set(options["buffer_capacity"])
self.bandwidth_var.set(options["bandwidth"])
self.buffer_choice.set(options["buffer_type"])
class NodeChoices(tk.LabelFrame):
"""Choice of nodes to be used."""
def __init__(self, parent):
"""Create and format node choices."""
tk.LabelFrame.__init__(self, parent, text="NodeChoices")
self.parent = parent
self.node_vars = []
for (i, node) in zip(range(len(NODES)), NODES):
for node in NODES:
# pylint:disable=invalid-name
v = tk.IntVar()
self.node_vars.append(v)
tk.Checkbutton(self, text=node.__name__, variable=v).pack(anchor=W)
def getChoices(self):
"""Return a dictionary of node choices"""
def get_choices(self):
"""Return a dictionary of node choices."""
param = {}
param["Nodes"] = []
for (node, var) in zip(NODES, self.node_vars):
if var.get() == 1:
param["Nodes"].append(node)
return param
def setChoices(self, options):
# reset
def set_choices(self, options):
"""Display current options."""
# reset
for var in self.node_vars:
var.set(0)
@@ -211,15 +222,24 @@ class NodeChoices(tk.LabelFrame):
class TrafficOptions(tk.LabelFrame):
"""Options that get passed for traffic creation."""
def __init__(self, parent):
"""Create and format traffic options."""
tk.LabelFrame.__init__(self, parent, text="TrafficOptions")
self.parent = parent
tk.Label(self, text="Packet Generation Interval (s):").grid(row=0, column=0)
tk.Label(self, text="Packet Generation Interval (s):").grid(
row=0, column=0
)
self.packet_interval_var = tk.IntVar(value=300)
tk.Entry(self, textvariable=self.packet_interval_var).grid(row=0, column=1)
tk.Entry(self, textvariable=self.packet_interval_var).grid(
row=0, column=1
)
tk.Label(self, text="Packets Generated per Interval:").grid(row=1, column=0)
tk.Label(self, text="Packets Generated per Interval:").grid(
row=1, column=0
)
self.packet_gen_var = tk.IntVar(value=1)
tk.Entry(self, textvariable=self.packet_gen_var).grid(row=1, column=1)
@@ -227,12 +247,12 @@ class TrafficOptions(tk.LabelFrame):
self.ttl_var = tk.StringVar(value=0)
tk.Entry(self, textvariable=self.ttl_var).grid(row=2, column=1)
tk.Label(self, text="Packet Size (??):").grid(row=3, column=0)
tk.Label(self, text="Packet Size (Mb):").grid(row=3, column=0)
self.packet_size_var = tk.IntVar(value=0)
tk.Entry(self, textvariable=self.packet_size_var).grid(row=3, column=1)
def getOptions(self):
"""Return a dictionary of traffic options"""
def get_options(self):
"""Return a dictionary of traffic options."""
param = {}
param["step"] = self.packet_interval_var.get()
param["traffic_per_step"] = self.packet_gen_var.get()
@@ -241,7 +261,8 @@ class TrafficOptions(tk.LabelFrame):
return param
def setOptions(self, options):
def set_options(self, options):
"""Display current options."""
self.packet_interval_var.set(options["step"])
self.packet_gen_var.set(options["traffic_per_step"])
self.ttl_var.set(options["time_to_live"])
@@ -249,7 +270,10 @@ class TrafficOptions(tk.LabelFrame):
class GraphingOptions(tk.LabelFrame):
"""Options to be passed for graphing output."""
def __init__(self, parent):
"""Create and format graphing options."""
tk.LabelFrame.__init__(self, parent, text="GraphicsOptions")
self.parent = parent
@@ -264,21 +288,20 @@ class GraphingOptions(tk.LabelFrame):
self.ind_choice = tk.StringVar()
self.ind_choice.set("None")
for choice in INDEPENDANT:
tk.Radiobutton(frame1, text=choice, variable=self.ind_choice, value=choice).pack(anchor=W)
tk.Radiobutton(
frame1, text=choice, variable=self.ind_choice, value=choice
).pack(anchor=W)
self.dep_vars = []
for dep in DEPENDANT:
# pylint:disable=invalid-name
v = tk.IntVar()
self.dep_vars.append(v)
tk.Checkbutton(frame2, text=dep, variable=v).pack(anchor=W)
def getOptions(self):
"""Return a dictionary of graphing (output) options"""
def get_options(self):
"""Return a dictionary of graphing (output) options."""
param = {}
param["choice"] = self.ind_choice.get()
param["input"] = self.ind_input.get()
@@ -290,24 +313,18 @@ class GraphingOptions(tk.LabelFrame):
]
if param["choice"] not in ["contact_dir", "buffer_type"]:
if param["choice"] in ["bandwidth", "payload", "k", "agk"]:
param["input"] = [
int(input)
for input in param["input"]
]
param["input"] = [int(input) for input in param["input"]]
else:
param["input"] = [
float(input)
for input in param["input"]
]
param["input"] = [float(input) for input in param["input"]]
param["dependant"] = []
for (dep, var) in zip(DEPENDANT, self.dep_vars):
if var.get() == 1:
param["dependant"].append(dep)
return param
def setOptions(self, options):
def set_options(self, options):
"""Display current options."""
self.ind_choice.set(options["choice"])
if options["input"] is not None:
tmp = ", ".join(str(i) for i in options["input"])
@@ -322,80 +339,93 @@ class GraphingOptions(tk.LabelFrame):
class Gui(tk.Tk):
"""Simple GUI to modify config file."""
# pylint: disable=too-many-instance-attributes
def __init__(self, parent):
"""Create and format GUI."""
tk.Tk.__init__(self, parent)
self.parent = parent
self.param={}
self.param = {}
self.simOptions = SimOptions(self)
self.nodeChoices = NodeChoices(self)
self.nodeOptions = NodeOptions(self)
self.trafficOptions = TrafficOptions(self)
self.graphingOptions = GraphingOptions(self)
self.sim_options = SimOptions(self)
self.node_choices = NodeChoices(self)
self.node_options = NodeOptions(self)
self.traffic_options = TrafficOptions(self)
self.graphing_options = GraphingOptions(self)
self.simOptions.grid(row=0, column=0, sticky="NSEW")
self.nodeChoices.grid(row=0, column=1, sticky="NSEW")
self.nodeOptions.grid(row=1, column=1, sticky="NSEW")
self.trafficOptions.grid(row=1, column=0, sticky="NSEW")
self.graphingOptions.grid(row=0, column=2, rowspan=2, sticky="NSEW")
self.sim_options.grid(row=0, column=0, sticky="NSEW")
self.node_choices.grid(row=0, column=1, sticky="NSEW")
self.node_options.grid(row=1, column=1, sticky="NSEW")
self.traffic_options.grid(row=1, column=0, sticky="NSEW")
self.graphing_options.grid(row=0, column=2, rowspan=2, sticky="NSEW")
tk.Button(
self, text="Load config file", command=self.load_config
).grid(row=3, column=0, columnspan=3)
tk.Button(
self, text="Save sim parameters", command=self.submit
).grid(row=4, column=0, columnspan=3)
self.runButton = tk.Button(
self, text="Save and run sim", command=self.submitQuit
tk.Button(self, text="Save sim parameters", command=self.submit).grid(
row=4, column=0, columnspan=3
)
self.run_button = tk.Button(
self, text="Save and run sim", command=self.submit_quit
)
self.runButton.grid(row=5, column=0, columnspan=3)
self.run_button.grid(row=5, column=0, columnspan=3)
tk.Button(self, text="Quit", command=self.quit).grid(
row=6, column=0, columnspan=3
)
def read_config(self, file):
with open(file, "r", newline="") as f:
"""Display this config file in GUI."""
# pylint: disable=invalid-name
with open(file, "r", newline="", encoding="utf-8") as f:
param = yaml.load(f, Loader=Loader)
self.simOptions.setOptions(param["SimOptions"])
self.nodeOptions.setOptions(param["NodeOptions"])
self.nodeChoices.setChoices(param["NodeChoices"])
self.trafficOptions.setOptions(param["TrafficOptions"])
self.graphingOptions.setOptions(param["GraphingOptions"])
self.sim_options.set_options(param["SimOptions"])
self.node_options.set_options(param["NodeOptions"])
self.node_choices.set_choices(param["NodeChoices"])
self.traffic_options.set_options(param["TrafficOptions"])
self.graphing_options.set_options(param["GraphingOptions"])
def load_config(self):
"""Choose a config file to display."""
file = fd.askopenfilename()
self.read_config(file)
def submit(self):
"""Save to config file."""
param = {}
param["SimOptions"] = self.simOptions.getOptions()
param["NodeOptions"] = self.nodeOptions.getOptions()
param["NodeChoices"] = self.nodeChoices.getChoices()
param["TrafficOptions"] = self.trafficOptions.getOptions()
param["GraphingOptions"] = self.graphingOptions.getOptions()
param["SimOptions"] = self.simOptions.get_options()
param["NodeOptions"] = self.nodeOptions.get_options()
param["NodeChoices"] = self.nodeChoices.get_choices()
param["TrafficOptions"] = self.trafficOptions.get_options()
param["GraphingOget_cptions"] = self.graphingOptions.get_options()
self.param = param
with open(param["SimOptions"]["config"], "w", newline="") as f:
# pylint: disable=invalid-name
with open(
param["SimOptions"]["config"], "w", newline="", encoding="utf-8"
) as f:
yaml.dump(param, f)
def submitQuit(self):
def submit_quit(self):
"""Save to config file, then close GUI."""
self.submit()
self.quit()
def main():
"""Display GUI, allows editing of config files."""
gui = Gui(None)
gui.title("Pydtnsim Gui Test")
gui.runButton["state"] = DISABLED
gui.run_button["state"] = DISABLED
gui.mainloop()
print(gui.param)
if __name__ == "__main__":
sys.exit(main())
Loading