Эвакуационная симуляция дает сбой большому количеству агентов - PullRequest
0 голосов
/ 14 апреля 2020

Меня зовут Йоханнес, и в настоящее время я пытаюсь смоделировать эвакуацию в python с использованием известного пакета pygame. Я создал код, который принимает несколько агентов, а затем моделирует процесс эвакуации этих агентов в окне Pygame. Чтобы сделать код более реалистичным c Я включил циклы for для проверки столкновений людей и стен. Итак, мне действительно нужно проверить эти два условия. Теперь, когда я запускаю программу до 35 агентов (nr_agents - это переменная, с помощью которой вы можете настроить это число), все работает нормально. Но когда я увеличиваю количество людей, скажем до 70 или 100 или более, эвакуация запаздывает, и люди внезапно начинают прыгать по всему экрану. Сначала я думал, что речь идет о моем Chromebook (он не может обрабатывать много кадров в секунду), но теперь, когда у меня более мощный ноутбук, и код все еще отстает. Я сам думаю, что это как-то связано с увеличением количества вычислений, которые выполняет программа (мой код O (n ^ 2) из-за взаимодействия людей l oop). Но это было бы очень грустно, потому что мне действительно нужны циклы for в функциях взаимодействия людей и стены, чтобы мой код был реалистичным, я думаю.

Я попытался увеличить количество кадров в секунду, чтобы сделать код более приятным, и я постарался вынести как можно больше ненужных вычислений из циклов for. Кроме того, я купил новый ноутбук с более мощным процессором и большим количеством оперативной памяти, чтобы иметь возможность обрабатывать больше FPS. Также я попытался использовать профилировщик, чтобы найти, где мой код тратит много времени (но снова я продолжаю прибегать к циклам for, которые проверяют наличие коллизий).

Мой вопрос: есть ли способ, с помощью которого я мог бы сделать этот код более эффективным, чтобы ut мог обрабатывать больше агентов?

Советы или решения были бы очень благодарны. У меня действительно нет вариантов.

Код состоит из 2 частей. Основная часть показана ниже:

# Programming evacuation systems using Crowd Simulation
# Agent-Based Modelling
# Loading the pygame package
import pygame
# Importing locals
from pygame.locals import *
# Other packages
import sys
import numpy as np
import numpy.random as random
import math
import time
from additional_functions import *
# Initializing Pygame and font
pygame.init()
pygame.font.init() 
timefont = pygame.font.SysFont('Comic Sans MS', 30)

""" 

Creating a screen with a room that is smaller than then screen 

"""

# Size of the screen
width = 800
height = 800  
size = width, height # Do not adjust this

# Creating screen
roomscreen = pygame.display.set_mode(size)

# Making background white and creating colors
WHITE = (255,255,255)
RED = (255,0,0)
GREEN = (0,255,0)
BLACK = (0,0,0)
background_color = WHITE
roomscreen.fill(background_color)
pygame.display.update()

# Defining clock
clock = pygame.time.Clock()

# Creating evacuation object class
class Agent(object):
    def __init__(self):

        self.mass = 80 # random.uniform(40,90)
        self.radius = 12
        # random initialize a agent

        self.x = random.uniform(100 + self.radius, 600 - self.radius)
        self.y = random.uniform(100 + self.radius,700 - self.radius)
        self.pos = np.array([self.x, self.y])
        #self.pos = np.array([10.0, 10.0])

        self.aVelocityX = 0 #random.uniform(0,1.6)
        self.aVelocityY = 0 #random.uniform(0,1.6)
        self.aVelocity = np.array([self.aVelocityX, self.aVelocityY])
        #self.actualV = np.array([0.0, 0.0])

        self.dest = np.array([700,400])
        self.direction = normalize(self.dest - self.pos)
        #self.direction = np.array([0.0, 0.0])

        self.dSpeed = 12 
        self.dVelocity = self.dSpeed*self.direction

        self.acclTime = 0.5 #random.uniform(8,16) #10.0
        self.drivenAcc = (self.dVelocity - self.aVelocity)/self.acclTime


        self.bodyFactor = 120000
        self.F = 1
        self.delta = 0.8 #random.uniform(0.8,1.6) #0.8 #0.08

        self.Goal = 0
        self.time = 0.0

        print('X and Y Position:', self.pos)
        print('self.direction:', self.direction)

    def velocity_force(self): # function to adapt velocity
        deltaV = self.dVelocity - self.aVelocity
        if np.allclose(deltaV, np.zeros(2)):
            deltaV = np.zeros(2)
        return deltaV*self.mass/self.acclTime


    def f_ij(self, other): # interaction with people
        r_ij = self.radius + other.radius
        d_ij = np.linalg.norm(self.pos - other.pos)
        e_ij = (self.pos - other.pos)/d_ij
        value = self.F*np.exp((r_ij-d_ij)/(self.delta))*e_ij
        + self.bodyFactor*g(r_ij-d_ij)*e_ij
        return value

    def f_ik_wall(self, wall): # interaction with the wall in the room
        r_i = self.radius
        d_iw,e_iw = distance_agent_to_wall(self.pos,wall)
        value = -self.F*np.exp((r_i-d_iw)/self.delta)*e_iw # Assume wall and people give same force
        + self.bodyFactor*g(r_i-d_iw)*e_iw
        return value

    def update_dest(self):
            self.dest = np.array([700,400])

# Now to let multiple objects move to the door we define
nr_agents = 35
agent_color = GREEN
line_color = BLACK

# Making room
room_height = 600 # height of the room
room_width = 600 # width of the room
room_left = 100 # left pixels coordinate
room_top = 100 # top pixels coordeinate

""" 

Now we need to create the doors through which objects will leave in case of evacuation
This door's position can be determined using:

"""
# Door 1
door_ytop = 385
door_ybottom = 415

# This gives the following walls
walls = [[room_left, room_top, room_left + room_width, room_top], 
[room_left, room_top, room_left, room_top+room_height], 
[room_left, room_top+room_height, room_left + room_width, room_top+ room_height],
[room_left + room_width, room_top, room_left + room_width, door_ytop],
[room_left+room_width, room_top + room_height, room_left + room_width, door_ybottom]]



# initialize agents
agents = []
time_matrix = np.zeros((nr_agents, 1))
for n in range(nr_agents):
    agent = Agent()
    agents.append(agent)

run = True
count = 0
start_time = time.time()
while run:

    # Updating time
    if count < nr_agents:
        current_time = time.time()
        elapsed_time = current_time - start_time

    # Finding delta t for this frame
    dt = clock.tick(70)/1000

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        elif event.type == pygame.MOUSEBUTTONDOWN:
            (x, y) = pygame.mouse.get_pos()
            print(x, y)

    roomscreen.fill(background_color)

    # draw walls
    for wall in walls:
        start_posw = np.array([wall[0],wall[1]])
        end_posw = np.array([wall[2],wall[3]])
        start_posx = start_posw 
        end_posx = end_posw
        pygame.draw.line(roomscreen, line_color, start_posx, end_posx, 3)

    for agent_i in agents:
        agent_i.update_dest()
        agent_i.direction = normalize(agent_i.dest - agent_i.pos)
        agent_i.dVelocity = agent_i.dSpeed*agent_i.direction
        aVelocity_force = agent_i.velocity_force()
        people_interaction = 0.0
        wall_interaction = 0.0

        for agent_j in agents: 
            if agent_i == agent_j: continue
            people_interaction += agent_i.f_ij(agent_j)

        for wall in walls:
            wall_interaction += agent_i.f_ik_wall(wall)

        sumForce = aVelocity_force + people_interaction + wall_interaction
        dv_dt = sumForce/agent_i.mass
        agent_i.aVelocity = agent_i.aVelocity + dv_dt*dt 
        agent_i.pos = agent_i.pos + agent_i.aVelocity*dt


    for agent_i in agents:

        agent_i.time += clock.get_time()/1000 
        start_position = [0, 0]
        start_position[0] = int(agent_i.pos[0])
        start_position[1] = int(agent_i.pos[1])

        end_position = [0, 0]
        end_position[0] = int(agent_i.pos[0] + agent_i.aVelocity[0])
        end_position[1] = int(agent_i.pos[1] + agent_i.aVelocity[1])

        end_positionDV = [0, 0]
        end_positionDV[0] = int(agent_i.pos[0] + agent_i.dVelocity[0])
        end_positionDV[1] = int(agent_i.pos[1] + agent_i.dVelocity[1])

        if start_position[0] >= 700 or start_position[0] <= 100 and agent_i.Goal == 0:
            agent_i.Goal = 1
            time_matrix[count]  = agent_i.time
            # print('Time to Reach the Goal:', agent_i.time)

        if start_position[0] > 700 or start_position[0] < 100:
            count += 1
            agents.remove(agent_i)

        pygame.draw.circle(roomscreen, agent_color, start_position, 12, 3)
        pygame.draw.line(roomscreen, agent_color, start_position, end_positionDV, 2)
    pygame.draw.line(roomscreen, [255,60,0], start_position, end_positionDV, 2)

    # Present text on screen
    timestr = "Time: " +  str(elapsed_time)
    timesurface = timefont.render(timestr, False, (0, 0, 0))
    roomscreen.blit(timesurface,(0,0))
    # Update the screen
    pygame.display.flip()

pygame.quit()

Вторая часть - это часть, из которой я импортирую специальную функцию. Это называется Additional_functions. Но эти функции невелики и не занимают много времени с точки зрения вычислений. Если вам нужно что-то еще или что-то не так с моим постом, не стесняйтесь, сообщите мне.

Надеюсь, мы сможем куда-нибудь добраться.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...