def __run(self) -> None: """ Triggers the event for the next step as long as the simulaiton has not finished. Author: Beil Benedikt, Benjamin Eder :return: Nothing """ while not self.__event_stop.is_set() and ( self.state.infected_count() > 0 or self.state.get_total_count() < self.state.get_beginning_total_count()): start = time.time_ns() active_provider.get_scheduler().trigger_gui_event( controller.scheduler.Events.NEXT_STEP, {"state": self.state}) took = (time.time_ns() - start) // 1000000 speed = self.state.speed() if speed > 0: to_wait = speed - took if to_wait < 0: print( 'WARNING: Simulation is too busy, consider slowing down the speed!' ) else: QtCore.QThread.msleep( to_wait) # Wait for the calculated time if not self.__paused: self.__pause_simulation()
def on_size_slider_released() -> None: self.state.set_size(np.uint(size_slider.value())) self.state.reset() active_provider.get_scheduler().trigger_gui_event( controller.events.Events.RESET, kw={"state": self.state}) self.state_viz.reset()
def reset_clicked() -> None: if not self.__paused: pause_simulation() self.state.set_size(cfg.DEFAULT_SIZE) size_slider.setValue(cfg.DEFAULT_SIZE) self.state.set_infected_share( 0) # Prevent errors due to shares being more than 1.0 in sum self.state.set_susceptible_share(cfg.DEFAULT_SUSCEPTIBLE_SHARE) susceptible_share_slider.setValue( round(self.state.susceptible_share() * 100)) self.state.set_infected_share(cfg.DEFAULT_INFECTED_SHARE) infected_share_slider.setValue( round(self.state.infected_share() * 100)) self.state.set_infection_prob(cfg.DEFAULT_INFECTION_PROB) infection_prob_slider.setValue( round(self.state.infection_prob() * 100)) self.state.set_remove_prob(cfg.DEFAULT_REMOVE_PROB) remove_prob_slider.setValue(round(self.state.remove_prob() * 100)) self.state.reset() active_provider.get_scheduler().trigger_gui_event( controller.events.Events.RESET, kw={"state": self.state}) self.state_viz.reset()
def restart_clicked() -> None: if not self.__paused: pause_simulation() play_pause_btn.setIcon(play_icon) next_btn.setEnabled(True) self.state.reset() active_provider.get_scheduler().trigger_gui_event( controller.events.Events.RESET, kw={"state": self.state}) self.state_viz.reset()
def on_infected_slider_released() -> None: new_share = infected_share_slider.value() / 100 current_susceptible_share = self.state.susceptible_share() if new_share + current_susceptible_share > 1.0: self.state.set_susceptible_share(1.0 - new_share) susceptible_share_slider_supplier().setValue( round(self.state.susceptible_share() * 100)) self.state.set_infected_share(new_share) self.state.reset() active_provider.get_scheduler().trigger_gui_event( controller.events.Events.RESET, kw={"state": self.state}) self.state_viz.reset()
def __init__(self, state: SimState): super().__init__() self.state = state self.__paused = True self.__numOfInfected = 10000 self.threadpool = QThreadPool() self.__event_stop = threading.Event() self.__event_ready = threading.Event() self.app = QtWidgets.QApplication([]) app_icon = QtGui.QIcon() app_icon.addFile('res/icon.ico') self.app.setWindowIcon(app_icon) win = QtWidgets.QMainWindow(flags=QtCore.Qt.WindowFlags()) QtGui.QFontDatabase.addApplicationFont('res/Manrope.ttf') win.setStyleSheet(cfg.styleSheet) self.root_widget = QtWidgets.QWidget() self.root_layout = QtWidgets.QHBoxLayout() self.root_layout.setContentsMargins(0, 0, 0, 0) self.root_widget.setLayout(self.root_layout) win.setCentralWidget(self.root_widget) win.setWindowTitle('Epidemic Simulator') win.resize(1200, 800) self.win = win # PyQtGraph configuration pg.setConfigOptions( imageAxisOrder= 'row-major', # Interpret image data as row-major instead of col-major foreground=cfg.FOREGROUND_COLOR, background=cfg.BACKGROUND_COLOR, antialias=True) self.__build_controls() self.__build_visualizations() self.__build_settings() active_provider.get_scheduler().register_gui_handler( controller.events.Events.REPAINT, self.__after_step_completion) self.__repaint_signal.connect(self.__repaint_viz) active_provider.get_scheduler().register_gui_handler( controller.events.Events.AGENT_CHANGE_GUI, self.state.agent_update) active_provider.get_scheduler().trigger_gui_event( controller.events.Events.RESET, kw={"state": self.state})
def __delete__(self, instance): from controller.provider import active_provider active_provider.get_scheduler().get_observable().off(Events.RESET.value, self.__reset)
def play() -> None: play_pause_btn.setIcon(pause_icon) next_btn.setEnabled(False) size_slider.setEnabled(False) infected_share_slider.setEnabled(False) susceptible_share_slider.setEnabled(False) self.__paused = False if cfg.BATCH_RUN_ENABLED: # Prepare results file try: os.remove(cfg.BATCH_RESULT_FILE) except OSError: pass with open(cfg.BATCH_RESULT_FILE, 'a+') as results_file: results_file.write(f"""{{ \t\"config\": {{ \t\t\"size\": {self.state.size()}, \t\t\"susceptible_share\": {self.state.susceptible_share()}, \t\t\"infected_share\": {self.state.infected_share()}, \t\t\"infection_probability\": {self.state.infection_prob()}, \t\t\"remove_probability\": {self.state.remove_prob()}, \t\t\"movement_mixing\": {self.state.get_mixing_value_m()}, \t\t\"infection_env_radius\": {self.state.infection_env_radius()}, \t\t\"infection_env_metric\": \"{self.state.infection_env_metric().value}\", \t\t\"calc_real_effective_reproduction_rate\": {str(self.state.calculate_real_effective_reproduction_number()).lower()}, \t\t\"breakdown_dead_immune_enabled\": {str(self.state.lethality_toggle()).lower()}, \t\t\"lethality\": {self.state.lethality()}, \t\t\"vaccine_enabled\": {str(self.state.vaccine_toggle()).lower()}, \t\t\"vaccine_time\": {self.state.vaccine_time()}, \t\t\"vaccine_share\": {self.state.vaccine_share()}, \t\t\"movement_limit_enabled\": {str(self.state.movement_limit_enabled()).lower()}, \t\t\"movement_limit_radius\": {self.state.movement_limit_radius()}, \t\t\"movement_limit_metric\": \"{self.state.movement_limit_metric().value}\", \t\t\"movement_limit_high_distances_are_uncommon\": {str(self.state.movement_limit_high_distances_are_uncommon()).lower()}, \t\t\"incubation_period_enabled\": {str(self.state.incubation_period_enabled()).lower()}, \t\t\"incubation_period\": {self.state.incubation_period()}, \t\t\"quarantine_enabled\": {str(self.state.quarantine_enabled()).lower()}, \t\t\"quarantine_share\": {self.state.quarantine_share()} \t}}, \t\"runs\": [ """) # Run a batch of simulations for i in range(cfg.BATCH_RUN_ITERATIONS): print( f'Running batch job {i + 1} of {cfg.BATCH_RUN_ITERATIONS}...' ) while self.state.infected_count( ) > 0 or self.state.get_total_count( ) < self.state.get_beginning_total_count(): active_provider.get_scheduler().trigger_gui_event( controller.scheduler.Events.NEXT_STEP, {"state": self.state}) results_file.write(f"""\t\t{{ \t\t\t\"iteration\": {i + 1}, \t\t\t\"seed\": {self.state.get_seed()}, \t\t\t\"elapsed_days\": {self.state_viz.elapsed_days()}, \t\t\t\"effective_reproduction_rates\": {json.dumps(self.state_viz.r_values())}, \t\t\t\"estimated_effective_reproduction_rates\": {json.dumps(self.state_viz.r_estimate_values())}, \t\t\t\"susceptible_counts\": {json.dumps(self.state_viz.sus_counts())}, \t\t\t\"infected_counts\": {json.dumps(self.state_viz.inf_counts())}, \t\t\t\"removed_counts\": {json.dumps(self.state_viz.rem_counts())}, \t\t\t\"dead_counts\": {json.dumps(self.state_viz.ded_counts())}, \t\t\t\"immune_counts\": {json.dumps(self.state_viz.imm_counts())}, \t\t\t\"incubated_counts\": {json.dumps(self.state_viz.inc_counts())} \t\t}}{',' if i < cfg.BATCH_RUN_ITERATIONS - 1 else ''} """) self.state.seed() # Reseed simulation self.state.reset() active_provider.get_scheduler().trigger_gui_event( controller.events.Events.RESET, kw={"state": self.state}) self.state_viz.reset() results_file.write(f"""\t] }} """) else: self.__event_stop.clear() worker = Worker(self.__run) self.threadpool.start(worker)
def next_clicked() -> None: active_provider.get_scheduler().trigger_gui_event( controller.scheduler.Events.NEXT_STEP, {"state": self.state})