Skip to content
Merged
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
2 changes: 1 addition & 1 deletion lineflow/examples/carrier_magazin.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ def build(self):

if __name__ == '__main__':
line = SimplestLineWithReturnForPartCarriers()
line.run(simulation_end=200, visualize=True, capture_screen=True)
line.run(simulation_end=200, visualize=True)
2 changes: 1 addition & 1 deletion lineflow/examples/complex_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ def build(self):
get_max_reward=False
)

line.run(simulation_end=4000, agent=agent, capture_screen=False, show_status=True, visualize=False)
line.run(simulation_end=4000, agent=agent, show_status=True, visualize=False)
print("Produced: ", line.get_n_parts_produced())
print("Scrap: ", line.get_n_scrap_parts())
print("Reward: ", line.get_n_parts_produced() - line.get_n_scrap_parts()*scrap_factor)
4 changes: 2 additions & 2 deletions lineflow/examples/component_assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,5 +149,5 @@ def build(self):


if __name__ == '__main__':
line = ComponentAssembly(realtime=True, factor=0.01)
line.run(simulation_end=1000, visualize=True, capture_screen=True)
line = ComponentAssembly(realtime=True, factor=0.5)
line.run(simulation_end=10_000, visualize=True)
2 changes: 1 addition & 1 deletion lineflow/examples/multi_sink.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,5 +62,5 @@ def build(self):
if __name__ == '__main__':
line = MultiSink(realtime=False, n_sinks=5, alternate=False)
agent = make_greedy_policy(5)
line.run(simulation_end=200, agent=agent, visualize=True, capture_screen=False)
line.run(simulation_end=200, agent=agent, visualize=True)
print('Produced parts: ', line.get_n_parts_produced())
2 changes: 1 addition & 1 deletion lineflow/examples/showcase_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,4 +87,4 @@ def build(self):

if __name__ == '__main__':
line = ShowCase(realtime=True, factor=0.1)
line.run(simulation_end=150, visualize=True, capture_screen=True)
line.run(simulation_end=150, visualize=True)
2 changes: 1 addition & 1 deletion lineflow/examples/simple_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ def build(self):

if __name__ == '__main__':
line = SimpleLine()
line.run(simulation_end=3, visualize=True, capture_screen=True)
line.run(simulation_end=3_000, visualize=True)
4 changes: 2 additions & 2 deletions lineflow/examples/worker_assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ def build(self):


if __name__ == '__main__':
line = WorkerAssignment(with_rework=True, realtime=False, n_assemblies=7, step_size=2)
line = WorkerAssignment(with_rework=True, realtime=True, n_assemblies=7, step_size=2, factor=0.2)

agent = make_random_agent(7)
line.run(simulation_end=1000, agent=agent, visualize=True, capture_screen=False)
line.run(simulation_end=10_000, agent=agent, visualize=True)
38 changes: 17 additions & 21 deletions lineflow/simulation/connectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ def connect_to_output(self, station):
self._position_output = station.position
return self.get

def setup_positions(self):
raise NotImplementedError()


class Buffer(Connector):
"""
Expand Down Expand Up @@ -77,7 +80,7 @@ def init_state(self):
def n_carriers(self):
return len(self.carriers)

def setup_draw(self):
def setup_positions(self):

vec_direction = np.array(
[
Expand Down Expand Up @@ -113,28 +116,21 @@ def setup_draw(self):
)

self._positions_arrow[i] = arrowhead

def get_visualization_data(self):
data = [
dict(
type='connector',
start=self._position_input,
end=self._position_output,
n_slots=self.capacity,
)
]

def _draw(self, screen):

pygame.draw.line(
screen,
self.color,
self._position_input,
self._position_output,
width=10,
)

# Draw slots
for i, slot in enumerate(self._positions_slots):
pygame.draw.circle(screen, 'gray', slot, 10)

# Draw arrowheads
for i, arrow in enumerate(self._positions_arrow[:-1]):
pygame.draw.polygon(screen, 'black', arrow)

# Draw carriers
for carrier in self.carriers.values():
carrier.draw(screen)
data.append(carrier.get_visualization_data(with_text=True))

return data

def _sample_put_time(self):
return self.put_time + self.random.exponential(scale=self.put_std)
Expand Down
8 changes: 4 additions & 4 deletions lineflow/simulation/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ def reset(self, seed=None, options=None):
observation = self._get_observations_as_tensor(state)

if self.render_mode == "human":
self.line.setup_draw()
self.line._close_visualization()
self.line._init_visualization()
self.render()
return observation, self._get_info()

Expand All @@ -201,13 +202,12 @@ def features(self):
return self.line.state.observable_features

def render(self):
self.line._draw()
self.line._send_data_to_visualization()

def close(self):
if self.render_mode == 'human':
self.line.viewpoint.teardown()
self.line._close_visualization()

def _get_observations_as_tensor(self, state):

X = state.get_observations(lookback=1, include_time=False)
return np.array(X, dtype=np.float32)
141 changes: 51 additions & 90 deletions lineflow/simulation/line.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import numpy as np
import logging
from tqdm import tqdm
from multiprocessing import Process, Queue, Event

from lineflow.simulation.stationary_objects import StationaryObject
from lineflow.simulation.states import LineStates
Expand All @@ -12,7 +13,7 @@
Station,
Sink,
)
from lineflow.simulation.visualization import Viewpoint
from lineflow.simulation.visualization import start_visualization

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -48,6 +49,31 @@ def __init__(
self._info = info

self.reset(random_state=random_state)
self.data = []

def _init_visualization(self):
"""
Initializes the visualization process and the communication channels.
"""
self.stop_event = Event()
self.halt_event = Event()
self.connection = Queue()
self.visualization_process = Process(
target=start_visualization,
args=(self.connection, self.stop_event, self.halt_event)
)

for _, obj in self._objects.items():
if isinstance(obj, Connector):
obj.setup_positions()

self.visualization_process.start()

def _close_visualization(self):
if hasattr(self, 'visualization_process'):
self.stop_event.set()
self.visualization_process.join()


@property
def name(self):
Expand Down Expand Up @@ -175,86 +201,27 @@ def _register_objects_at_env(self):
for o in self._objects.values():
o.register(self.env)

def _draw(self, actions=None):

self.viewpoint.check_user_input()

self.viewpoint.clear()

# Draw objects, first connectors, then stations
self._draw_connectors()
self._draw_stations()

self.viewpoint._draw()

if actions is not None:
self._draw_actions(actions)

self._draw_info()

pygame.display.flip()

def _draw_info(self):

font = pygame.font.SysFont(None, 20)
def _send_data_to_visualization(self, actions=None):
if not self.stop_event.is_set():
data = []

time = font.render('T={:.2f}'.format(self.env.now), True, 'black')
n_parts = font.render(
f'#Parts={self.get_n_parts_produced()}', True, 'black'
)
self.viewpoint.screen.blit(time, time.get_rect(center=(30, 30)))
self.viewpoint.screen.blit(n_parts, n_parts.get_rect(center=(30, 50)))

def _draw_actions(self, actions):
font = pygame.font.SysFont(None, 20)
actions = font.render(f'{actions}', True, 'black')
self.viewpoint.screen.blit(actions, actions.get_rect(center=(500, 30)))

def _draw_stations(self):
self._draw_objects_of_type(Station)

def _draw_connectors(self):
self._draw_objects_of_type(Connector)
for _, obj in self._objects.items():
if isinstance(obj, Station):
data.append(obj.get_visualization_data())

def _draw_objects_of_type(self, object_type):
for _, obj in self._objects.items():
if isinstance(obj, object_type):
obj._draw(self.viewpoint.paper)

def _get_object_positions(self):
x = []
y = []
for o in self._objects.values():
if hasattr(o, "position"):
x.append(o.position[0])
y.append(o.position[1])
return x, y

def _adjust_positions(self):
x, y = self._get_object_positions()

if min(x) < 100:
delta_x = 100 - min(x)
for o in self._objects.values():
if hasattr(o, "position"):
o.position[0] += delta_x
if min(y) < 100:
delta_y = 100 - min(y)
for o in self._objects.values():
if hasattr(o, "position"):
o.position[1] += delta_y

x, y = self._get_object_positions()
return max(x), max(y)

def setup_draw(self):
pygame.init()

max_x, max_y = self._adjust_positions()
for o in self._objects.values():
o.setup_draw()
if isinstance(obj, Connector):
data.extend(obj.get_visualization_data())

self.viewpoint = Viewpoint(size=(max_x+100, max_y+100))
data.append(
dict(
type="info",
time=self.env.now,
n_parts=self.get_n_parts_produced()
)
)
if actions is not None:
data.append(dict(type="actions", actions=actions))
self.connection.put(data)

def apply(self, values):
for object_name in values.keys():
Expand Down Expand Up @@ -299,7 +266,6 @@ def run(
agent=None,
show_status=True,
visualize=False,
capture_screen=False,
):
"""
Args:
Expand All @@ -309,12 +275,9 @@ def run(
class.
show_status (bool): Show progress bar for each simulation episode
visualize (bool): If true, line visualization is opened
capture_screen (bool): Captures last Time frame when screen should be recorded
"""

if visualize:
self.setup_draw()

self._init_visualization()

# Register objects when simulation is initially started
if len(self.env._queue) == 0:
Expand All @@ -329,6 +292,9 @@ def run(
)

while self.env.now < simulation_end:
if visualize and self.halt_event.is_set():
break

pbar.update(self.env.now - now)
now = self.env.now
try:
Expand All @@ -342,17 +308,12 @@ def run(
self.apply(actions)

if visualize:
self._draw(actions)

if capture_screen and visualize:
pygame.image.save(self.viewpoint.screen, f"{self.name}.png")
self._send_data_to_visualization(actions)

if visualize:
self.viewpoint.teardown()
self._close_visualization()

def get_observations(self, object_name=None):
"""
"""

df = self.state.df()

Expand Down
Loading
Loading