Commit 4a673030 authored by Ahmad Reza's avatar Ahmad Reza
Browse files

Again a lot of changes have been done:

- For the reading the data of the config the classe ConfigData is created
in a seperated file called config.py

- For the visualization a bug is fixed. The bug was that whenever
the vis.py goes into a sleep it is not possible to zoom or to create
tiles. !This bus has been fixed by Karol Actun!

- Three methods sim_to_coords, coords_to_sim, check_coords are moved
from the world.py to the header.py. Because those methods are
independent from the world.py. Based on these change some changes
have to been made on the other files.

- The particle counter has been removed from particle.py. The counting
of the particle and given the particle a number based on the counting
is happening now in world.py.

- Some unnecessary variables have been deleted from the matters.
parent 9eb54fc1
import configparser
from datetime import datetime
class ConfigData:
def __init__(self):
config = configparser.ConfigParser(allow_no_value=True)
config.read("config.ini")
self.seed_value = config.getint("Simulator", "seedvalue")
self.max_round = config.getint("Simulator", "max_round")
self.random_order = config.getboolean("Simulator", "random_order")
self.visualization = config.getint("Simulator", "visualization")
try:
self.scenario = config.get("File", "scenario")
except configparser.NoOptionError as noe:
self.scenario = "init_scenario.py"
try:
self.solution = config.get("File", "solution")
except configparser.NoOptionError as noe:
self.solution = "solution.py"
self.size_x = config.getfloat("Simulator", "size_x")
self.size_y = config.getfloat("Simulator", "size_y")
self.window_size_x = config.getint("Simulator", "window_size_x")
self.window_size_y = config.getint("Simulator", "window_size_y")
self.border = config.getfloat("Simulator", "border")
self.max_particles = config.getint("Simulator", "max_particles")
self.mm_limitation = config.getboolean("Matter", "mm_limitation")
self.particle_mm_size = config.getint("Matter", "particle_mm_size")
self.tile_mm_size = config.getint("Matter", "tile_mm_size")
self.marker_mm_size = config.getint("Matter", "marker_mm_size")
self.local_time = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')[:-1]
self.multiple_sim = 0
......@@ -109,27 +109,26 @@ class CsvParticleData:
class CsvRoundData:
def __init__(self, task=0, scenario=0, solution=0, seed=20, particle_num=0, tiles_num=0, markers_num=0,
steps=0, directory="outputs/"):
def __init__(self, task=0, scenario=0, solution=0, seed=20, directory="outputs/"):
self.task = task
self.scenario = scenario
self.solution = solution
self.actual_round= 1
self.seed = seed
self.steps = steps
self.steps_sum = steps
self.steps = 0
self.steps_sum = 0
self.particle_created=0
self.particle_deleted=0
self.particle_num = particle_num
self.particle_num = 0
self.particle_read = 0
self.particle_write = 0
self.tile_created = 0
self.tile_deleted = 0
self.tile_num = tiles_num
self.tile_num = 0
self.tile_read = 0
self.tile_write = 0
self.markers_num = markers_num
self.markers_num = 0
self.marker_read = 0
self.marker_write = 0
self.marker_created = 0
......
import math
from enum import Enum
......@@ -79,3 +80,32 @@ def get_the_invert(dir):
def dir_in_range(dir):
return dir % 6
def check_coords( coords_x, coords_y):
"""
Checks if the given coordinates are matching the
hexagon coordinates
:param coords_x: proposed x coordinate
:param coords_y: proposed y coordinate
:return: True: Correct x and y coordinates; False: Incorrect coordinates
"""
if (coords_x / 0.5) % 2 == 0:
if coords_y % 2 != 0:
return False
else:
return True
else:
if coords_y % 2 == 0:
return False
else:
return True
def coords_to_sim(coords):
return coords[0], coords[1] * math.sqrt(3 / 4)
def sim_to_coords(x, y):
return x, round(y / math.sqrt(3 / 4), 0)
\ No newline at end of file
......@@ -24,6 +24,7 @@ class Matter:
self.mm_limit = world.config_data.mm_limitation
self.mm_size = mm_size
self.modified = False
self.created = False
def set_alpha(self, alpha):
"""
......
......@@ -18,27 +18,17 @@ particle_counter=0
class Particle(matter.Matter):
"""In the classe marker all the methods for the characterstic of a marker is included"""
def __init__(self, world, x, y, color=black, alpha=1):
def __init__(self, world, x, y, color=black, alpha=1, particle_counter = particle_counter):
"""Initializing the marker constructor"""
super().__init__( world, (x, y), color, alpha, type="particle", mm_size=world.config_data.particle_mm_size)
global particle_counter
particle_counter+=1
self.number=particle_counter
super().__init__( world, (x, y), color, alpha,
type="particle", mm_size=world.config_data.particle_mm_size)
self.number = particle_counter
self.__isCarried = False
self.created = False
self.carried_tile = None
self.carried_particle = None
self.__isCarried = False
self.steps = 0
self.created = False
self.csv_particle_writer = csv_generator.CsvParticleData( self.get_id(), self.number)
def coords_to_sim(self, coords):
return coords[0], coords[1] * math.sqrt(3 / 4)
def sim_to_coords(self, x, y):
return x, round(y / math.sqrt(3 / 4), 0)
def has_tile(self):
if self.carried_tile == None:
return False
......@@ -51,7 +41,6 @@ class Particle(matter.Matter):
else:
return True
def get_carried_status(self):
"""
Get the status if it is taken or not
......@@ -71,7 +60,6 @@ class Particle(matter.Matter):
else:
return False
def check_on_particle(self):
"""
Checks if the particle is on a particle
......@@ -103,7 +91,7 @@ class Particle(matter.Matter):
"""
dir_coord = self.world.get_coords_in_dir(self.coords, dir)
dir, dir_coord = self.check_within_border(dir, dir_coord)
if self.world.check_coords(dir_coord[0], dir_coord[1]):
if check_coords(dir_coord[0], dir_coord[1]):
if self.coords in self.world.particle_map_coords:
del self.world.particle_map_coords[self.coords]
......@@ -142,7 +130,7 @@ class Particle(matter.Matter):
:return: True: Success Moving; False: Non moving
"""
dir_coord = self.world.get_coords_in_dir(self.coords, dir)
sim_coord = self.coords_to_sim(dir_coord)
sim_coord = coords_to_sim(dir_coord)
if self.world.get_sim_x_size() >= abs(sim_coord[0]) and \
self.world.get_sim_y_size() >= abs(sim_coord[1]):
return self.move_to(dir)
......@@ -799,7 +787,7 @@ class Particle(matter.Matter):
logging.info("particle with id %s is", self.get_id())
if x is not None and y is not None:
coords = (x, y)
if self.world.check_coords(x,y):
if check_coords(x,y):
logging.info("Going to create a tile on position \(%i , %i\)", x,y )
if self.world.add_tile(coords[0], coords[1], color, alpha) == True:
self.world.tile_map_coords[coords[0], coords[1]].created = True
......@@ -980,7 +968,7 @@ class Particle(matter.Matter):
:return: True: successful taken; False: unsuccessful taken
"""
if self.carried_particle is None and self.carried_tile is None:
if self.world.check_coords(x, y):
if check_coords(x, y):
coords = (x, y)
if coords in self.world.tile_map_coords:
self.carried_tile = self.world.tile_map_coords[coords]
......@@ -1060,7 +1048,7 @@ class Particle(matter.Matter):
:param y: y coordinate
"""
if self.carried_tile is not None:
if self.world.check_coords(x, y):
if check_coords(x, y):
coords = (x, y)
if coords not in self.world.get_tile_map_coords():
try: # cher: insert so to overcome the AttributeError
......@@ -1138,7 +1126,7 @@ class Particle(matter.Matter):
"""
coords = (0, 0)
if x is not None and y is not None:
if self.world.check_coords(x, y):
if check_coords(x, y):
coords = (x, y)
logging.info("Going to create a particle on position %s", str(coords))
new_particle = self.world.add_particle(coords[0], coords[1], color, alpha)
......@@ -1213,7 +1201,7 @@ class Particle(matter.Matter):
:return: True: Deleting successful; False: Deleting unsuccessful
"""
if x is not None and y is not None:
if self.world.check_coords(x, y):
if check_coords(x, y):
coords = (x, y)
if self.world.remove_particle_on(coords):
logging.info("Deleted particle with particle on coords %s", str(coords))
......@@ -1313,7 +1301,7 @@ class Particle(matter.Matter):
:return: True: Successful taken; False: Cannot be taken or wrong Coordinates
"""
if self.carried_particle is None and self.carried_tile is None:
if self.world.check_coords(x, y):
if check_coords(x, y):
coords = (x, y)
if coords in self.world.particle_map_coords:
self.carried_particle = self.world.particle_map_coords[coords]
......@@ -1394,7 +1382,7 @@ class Particle(matter.Matter):
"""
if self.carried_particle is not None:
if x is not None and y is not None:
if self.world.check_coords(x, y):
if check_coords(x, y):
coords = (x, y)
if coords not in self.world.particle_map_coords:
try: # cher: insert so to overcome the AttributeError
......@@ -1483,7 +1471,7 @@ class Particle(matter.Matter):
"""
coords = (0, 0)
if x is not None and y is not None:
if self.world.check_coords(x, y):
if check_coords(x, y):
coords = (x, y)
logging.info("Going to create a marker on position %s", str(coords))
new_marker = self.world.add_marker(coords[0], coords[1], color, alpha)
......@@ -1558,7 +1546,7 @@ class Particle(matter.Matter):
:return: True: Deleting successful; False: Deleting unsuccessful
"""
if x is not None and y is not None:
if self.world.check_coords(x, y):
if check_coords(x, y):
coords = (x, y)
if self.world.remove_marker_on(coords):
logging.info("Deleted marker oords %s", str(coords))
......
......@@ -10,7 +10,6 @@ class Tile(matter.Matter):
"""Initializing the marker constructor"""
super().__init__( world, (x, y), color, alpha, type="tile", mm_size=world.config_data.tile_mm_size)
self.__isCarried = False
self.created = False
def get_tile_status(self):
"""
......
......@@ -30,7 +30,7 @@ busy_waiting_time = 1
print_frame_stats = False
# simulation parameters
rounds_per_second = 1
rounds_per_second = 10
# tile_alpha = 0.6
particle_alpha = 1
......@@ -417,16 +417,25 @@ class VisWindow(pyglet.window.Window):
self.marker_vertex_list.colors[16 * i: 16 * i + 16] = (marker.color + [marker.get_alpha()]) * 4
def draw_world(self):
def draw_world(self, round_start_timestamp):
while not self.simulation_running:
self.dispatch_events()
self.draw()
if self.simulation_running or self.window_active is False:
return
self.dispatch_events()
#while actual simulation round is below max round
time.sleep(1/rounds_per_second)
self.draw()
# waiting until enough time passed to do the next simulation round.
time_elapsed = time.perf_counter() - round_start_timestamp
while time_elapsed < 1 / rounds_per_second:
# waiting for 1/100 of the round_time
waiting_time = (1 / rounds_per_second) / 100
time.sleep(waiting_time)
self.dispatch_events()
self.draw()
time_elapsed = time.perf_counter() - round_start_timestamp
return
def finished(self):
......
......@@ -17,11 +17,11 @@ class World:
"""
Initializing the world constructor
:param seed: seed number for new random numbers
:param max_round: the max round number for terminating the simulator
:param max_round: the max round number for terminating the worldulator
:param solution: The name of the solution that is going to be used
:param size_x: the maximal size of the x axes
:param size_y: the maximal size of the y axes
:param sim_name: the name of the world file that is used to build up the world
:param world_name: the name of the world file that is used to build up the world
:param solution_name: the name of the solution file that is only used for the csv file
:param seed: the seed number it is only used here for the csv file
:param max_particles: the maximal number of particles that are allowed to be or created in this world
......@@ -31,7 +31,7 @@ class World:
self.__end = False
self.init_particles=[]
self.particle_num=0
self.particle_id_counter = 0
self.particles = []
self.particles_created = []
self.particle_rm = []
......@@ -39,7 +39,6 @@ class World:
self.particle_map_id = {}
self.__particle_deleted=False
self.tiles_num = 0
self.tiles = []
self.tiles_created = []
self.tiles_rm = []
......@@ -48,7 +47,6 @@ class World:
self.__tile_deleted=False
self.new_tile = None
self.markers_num=0
self.markers = []
self.markers_created = []
self.marker_map_coords = {}
......@@ -56,14 +54,12 @@ class World:
self.markers_rm = []
self.__marker_deleted = False
self.directory = config_data.dir_name
self.config_data = config_data
self.csv_round = csv_generator.CsvRoundData(scenario=config_data.scenario,
solution=config_data.solution,
seed=config_data.seed_value,
tiles_num=0, particle_num=0,
steps=0, directory=config_data.dir_name)
directory=config_data.dir_name)
mod = importlib.import_module('scenario.' + self.config_data.scenario)
mod.scenario(self)
......@@ -76,7 +72,7 @@ class World:
def csv_aggregator(self):
self.csv_round.aggregate_metrics()
particle_csv = csv_generator.CsvParticleFile(self.directory)
particle_csv = csv_generator.CsvParticleFile(self.config_data.dir_name)
for particle in self.particles:
particle_csv.write_particle(particle)
particle_csv.csv_file.close()
......@@ -129,14 +125,13 @@ class World:
"""
return self.__solution
def get_particles_num(self):
def get_amount_of_particles(self):
"""
Returns the actual number of particles in the world
:return: The actual number of Particles
"""
return self.tiles_num
return len(self.particles)
def get_particle_list(self):
"""
......@@ -162,14 +157,13 @@ class World:
"""
return self.particle_map_id
def get_tiles_num(self):
def get_amount_of_tiles(self):
"""
Returns the actual number of particles in the world
:return: The actual number of Particles
"""
return self.tiles_num
return len(self.tiles)
def get_tiles_list(self):
"""
......@@ -195,13 +189,13 @@ class World:
"""
return self.tile_map_id
def get_marker_num(self):
def get_amount_of_markers(self):
"""
Returns the actual number of markers in the world
:return: The actual number of markers
"""
return self.markers_num
return len(self.markers)
def get_marker_list(self):
"""
......@@ -227,7 +221,6 @@ class World:
"""
return self.marker_map_id
def get_coords_in_dir(self, coords, dir):
"""
Returns the coordination data of the pointed directions
......@@ -238,14 +231,14 @@ class World:
"""
return coords[0] + x_offset[dir], coords[1] + y_offset[dir]
def get_sim_x_size(self):
def get_world_x_size(self):
"""
:return: Returns the maximal x size of the world
"""
return self.config_data.size_x
def get_sim_y_size(self):
def get_world_y_size(self):
"""
:return: Returns the maximal y size of the world
"""
......@@ -269,32 +262,6 @@ class World:
def set_marker_deleted(self):
self.__marker_deleted = False
def check_coords(self, coords_x, coords_y):
"""
Checks if the given coordinates are matching the
hexagon coordinates
:param coords_x: proposed x coordinate
:param coords_y: proposed y coordinate
:return: True: Correct x and y coordinates; False: Incorrect coordinates
"""
if (coords_x / 0.5) % 2 == 0:
if coords_y % 2 != 0:
return False
else:
return True
else:
if coords_y % 2 == 0:
return False
else:
return True
def coords_to_sim(self, coords):
return coords[0], coords[1] * math.sqrt(3 / 4)
def sim_to_coords(self, x, y):
return x, round(y / math.sqrt(3 / 4), 0)
def add_particle(self, x, y, color=black, alpha=1):
"""
Add a particle to the world database
......@@ -309,9 +276,11 @@ class World:
if alpha < 0 or alpha >1:
alpha = 1
if len(self.particles) < self.config_data.max_particles:
if self.check_coords(x,y) == True:
if check_coords(x,y) == True:
if (x,y) not in self.get_particle_map_coords():
new_particle= particle.Particle(self, x, y, color, alpha)
self.particle_id_counter += 1
new_particle = particle.Particle(self, x, y, color, alpha, self.particle_id_counter)
print(new_particle.number)
self.particles_created.append(new_particle)
self.particle_map_coords[new_particle.coords] = new_particle
self.particle_map_id[new_particle.get_id()] = new_particle
......@@ -391,7 +360,7 @@ class World:
"""
if alpha < 0 or alpha >1:
alpha = 1
if self.check_coords(x,y) == True:
if check_coords(x,y) == True:
if (x,y) not in self.tile_map_coords:
self.new_tile=tile.Tile(self, x, y, color, alpha)
print("Before adding ", len(self.tiles) )
......@@ -420,7 +389,7 @@ class World:
:param y: the y coordinates on which the tile should be added
:return: True: Successful added; False: Unsuccsessful
"""
if self.check_coords(x, y) == True:
if check_coords(x, y) == True:
if (x, y) not in self.tile_map_coords:
self.new_tile = tile.Tile(self, x, y, color, alpha)
self.tiles.append(self.new_tile)
......@@ -501,7 +470,7 @@ class World:
"""
if alpha < 0 or alpha >1:
alpha = 1
if self.check_coords(x, y) == True:
if check_coords(x, y) == True:
if (x, y) not in self.marker_map_coords:
self.new_marker = marker.Marker(self, x, y, color, alpha)
self.markers.append(self.new_marker)
......
"""This is the main module of the Opportunistic Robotics Network Simulator"""
import importlib
import configparser
import getopt
import logging
import os
import sys
from datetime import datetime
from lib import world
import time
from lib import world, config
from lib.gnuplot_generator import gnuplot_generator
class ConfigData:
def __init__(self, config):
self.seed_value = config.getint("Simulator", "seedvalue")
self.max_round = config.getint("Simulator", "max_round")
self.random_order = config.getboolean("Simulator", "random_order")
self.visualization = config.getint("Simulator", "visualization")
try:
self.scenario = config.get("File", "scenario")
except (configparser.NoOptionError) as noe:
self.scenario = "init_scenario.py"
try:
self.solution = config.get("File", "solution")
except (configparser.NoOptionError) as noe:
self.solution = "solution.py"
self.size_x = config.getfloat("Simulator", "size_x")
self.size_y = config.getfloat("Simulator", "size_y")
self.window_size_x = config.getint("Simulator", "window_size_x")
self.window_size_y = config.getint("Simulator", "window_size_y")
self.border = config.getfloat("Simulator", "border")
self.max_particles = config.getint("Simulator", "max_particles")
self.mm_limitation = config.getboolean("Matter", "mm_limitation")
self.particle_mm_size = config.getint("Matter", "particle_mm_size")
self.tile_mm_size = config.getint("Matter", "tile_mm_size")
self.marker_mm_size = config.getint("Matter", "marker_mm_size")
self.local_time = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')[:-1]
self.multiple_sim = 0
def swarm_sim( argv ):
def swarm_sim(argv):
"""In the main function first the config is getting parsed and than
the swarm_world and the swarm_world object is created. Afterwards the run method of the swarm_world
the swarm_sim_world and the swarm_sim_world object is created. Afterwards the run method of the swarm_sim_world
is called in which the simlator is going to start to run"""
logging.basicConfig(filename='system.log', filemode='w', level=logging.INFO, format='%(message)s')
logging.info('Started')
config_data = init_swarm_sim(argv)
swarm_world = world.World(config_data)
while swarm_world.get_actual_round() <= swarm_world.get_max_round() and swarm_world.get_end() is False:
solution(swarm_world)
if config_data.visualization and swarm_world.window.window_active is False:
break
swarm_world.csv_aggregator()
gnuplot_generator(config_data.dir_name)
logging.info('Finished')
def init_swarm_sim(argv):
config_data = read_config_file()
config_data = config.ConfigData()
read_cmd_args(argv, config_data)
create_dir(config_data)
return config_data
create_dir_for_data(config_data)
def read_config_file():
config = configparser.ConfigParser(allow_no_value=True)
config.read("config.ini")
config_data = ConfigData(config)
return config_data
swarm_sim_world = world.World(config_data)
while swarm_sim_world.get_actual_round() <= swarm_sim_world.get_max_round() and swarm_sim_world.get_end() is False:
round_start_timestamp = time.perf_counter()
run_solution(swarm_sim_world)
if config_data.visualization:
swarm_sim_world.window.draw_world(round_start_timestamp)
if swarm_sim_world.window.window_active is False:
break
def create_dir(config_data):
if config_data.multiple_sim == 1:
config_data.dir_name = config_data.local_time + "_" + config_data.scenario.rsplit('.', 1)[0] + \
"_" + config_data.solution.rsplit('.', 1)[0] + "/" + \
str(config_data.seed_value)
generate_data(config_data, swarm_sim_world)
config_data.dir_name = "./outputs/mulitple/" + config_data.dir_name
else: