def execute(self):
        """Execute the experiment by showing all trials and collecting the responses."""

        # present start screen
        self.mouse.setVisible(True)
        self.window.flip()
        core.wait(0.1)

        self._execute_introduction()
        self._execute_warm_up_trials()
        self._execute_instructions_main()
        self._execute_main_trials()

        # read in experimental data of the main experiment
        experiment_data = pd.read_csv(
            os.path.join(self.data_path, "experiment_data.csv")
        )

        # create trial structure for the repeated trials
        self.control_trials_data = ut.create_repeated_trials(
            experiment_data, self.subject_data
        )
        self.control_trials_data.to_csv(
            os.path.join(self.data_path, "repeated_trials_experiment_structure.csv"),
            index=False,
        )

        # execute repeated trials
        self._execute_control_trials()

        trials.KeypressTrial(
            self.mouse,
            self.window,
            keys=["space"],
            text="This is the end\nof the first part\nof the experiment.\n\n\n(Press `space` to continue.)",
        ).run()

        trials.KeypressTrial(
            self.mouse,
            self.window,
            keys=["space"],
            text="The experimenter\nwill now follow up\nwith two questions.\n\n\n(Press `space` to continue.)",
        ).run()

        trials.KeypressTrial(
            self.mouse,
            self.window,
            keys=["space"],
            text="Thank you for now.\n\n\n(Press space to exit)",
        ).run()
    def _execute_instructions_main(self):
        """Execute the instructions for the main experiment."""

        trials.BatchedTrial(
            self.mouse,
            self.window,
            [
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text=
                    "From now on,\nyou will always see\nthe following layout of the screen.\n\n\n(Press `space` to"
                    " continue.)",
                ),
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text=
                    "On the sides of the screen,\nyou will either see\nnatural instruction images or\noptimized "
                    "instruction images.\n\nAt the center of the screen,\nyou will always see\nnatural images."
                    "\n\n\n(Press `space` to continue)",
                ),
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text=
                    "Please pay attention\nwhether you see\n\n*maximally*\n(= Lieblingsbilder)\nor\n*minimally*"
                    "\n(= Nicht-Lieblingsbilder)\n\nactivating images.\n\n\n(Press `space` to continue.)",
                ),
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text=
                    "The question is always\nthe following:\n\n\n(Press `space` to continue.)",
                ),
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text=
                    "Which of the two images\nat the center of the screen\nis also a\nmaximally activating image"
                    "\n(= Lieblingsbild)?\n\n\n(Press `space` to continue.)",
                ),
            ],
        ).run()
    def _execute_instructions_main(self):
        """Execute the instructions for the main experiment."""

        trials.BatchedTrial(
            self.mouse,
            self.window,
            [
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text="From now on,\nyou will always see\nthe following layout of the screen.\n\n\n"
                         "(Press `space` to continue.)",
                ),
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text="On the sides of the screen,\nyou will either see\nno instruction images,\nnatural instruction"
                         " images or\noptimized instruction images.\n\nAt the center of the screen,\nyou will always "
                         "see\nnatural images.\n\n\n(Press `space` to continue)",
                ),
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text="The question is always\nthe following:\n\n\n(Press `space` to continue.)",
                ),
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text="Which of the two images\nat the center of the screen\nis also a\nmaximally activating image?"
                         "\n\n\n(Press `space` to continue.)",
                ),
                
            ],
        ).run()
    def _execute_introduction(self):
        """Execute the trials which are part of the introduction."""

        trials.BatchedTrial(
            self.mouse,
            self.window,
            [
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text="Welcome to the experiment.\nIt will start soon.\n\n\n(Press `space` to continue.)",
                ),
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text="At first, we will ask you\nhow intuitive you find\nthe "
                    "interpretability method.\n\n\n(Press `space` to continue.)",
                ),
            ],
        ).run()

        event.clearEvents()
        def show_feedback(trial_nr):
            nonlocal cum_sum_previous_block_trials
            # display how many trials were correct in the last block
            n_last_block_trials = trial_nr - cum_sum_previous_block_trials
            n_last_block_correct_trials = sum(correct_list[-n_last_block_trials:])

            cum_sum_previous_block_trials = trial_nr

            trials.KeypressTrial(
                self.mouse,
                self.window,
                keys=["space"],
                text=f"You got {n_last_block_correct_trials} out of "
                     f"{n_last_block_trials} trials correct.\n\n\n(Press `space` to continue.)",
            ).run()
    def execute(self):
        """Execute the experiment by showing all trials and collecting the reponses."""

        # present start screen
        self.mouse.setVisible(True)
        self.window.flip()
        core.wait(0.1)

        self._execute_introduction()
        self._execute_warm_up_trials("beginning")
        self._execute_instructions_main()
        self._execute_main_trials()
        self._execute_warm_up_trials("end")

        trials.KeypressTrial(
            self.mouse,
            self.window,
            keys=["space"],
            text=
            "This is the end\nof the first part\nof the experiment.\n\n\n(Press `space` to continue.)",
        ).run()

        trials.KeypressTrial(
            self.mouse,
            self.window,
            keys=["space"],
            text=
            "The experimenter\nwill now follow up\nwith two questions.\n\n\n(Press `space` to continue.)",
        ).run()

        trials.KeypressTrial(
            self.mouse,
            self.window,
            keys=["space"],
            text="Thank you for now.\n\n\n(Press space to exit)",
        ).run()
    def _execute_introduction(self):
        """Execute the trials which are part of the introduction."""

        trials.BatchedTrial(
            self.mouse,
            self.window,
            [
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text=
                    "Welcome to the experiment.\nIt will start soon.\n\n\n(Press `space` to continue.)",
                )
            ],
        ).run()

        event.clearEvents()
    def _execute_main_type_trials(self, trials_data: pd.DataFrame):
        """Execute the given set of trials (which are either main or
        repeated main trials)."""

        initial_trial_nr = trials_data.iloc[0]["trial_nr"]

        previous_block = trials_data.iloc[0]["block_nr"]
        cum_sum_previous_block_trials = initial_trial_nr
        next_block = False

        correct_list = []

        def show_feedback(trial_nr):
            nonlocal cum_sum_previous_block_trials
            # display how many trials were correct in the last block
            n_last_block_trials = trial_nr - cum_sum_previous_block_trials
            n_last_block_correct_trials = sum(correct_list[-n_last_block_trials:])

            cum_sum_previous_block_trials = trial_nr

            trials.KeypressTrial(
                self.mouse,
                self.window,
                keys=["space"],
                text=f"You got {n_last_block_correct_trials} out of "
                     f"{n_last_block_trials} trials correct.\n\n\n(Press `space` to continue.)",
            ).run()

        for row in range(len(trials_data)):
            trial_info = trials_data.iloc[row]
            trial_nr = trial_info["trial_nr"]
            trial_type = trial_info["trial_type"]
            instr_type = trial_info["instr_type"]
            subject_id = trial_info["subject_id"]
            batch = trial_info["batch"]
            block = int(trial_info["block_nr"])
            catch_trial = trial_info["catch_trial"]

            trial_nr_in_block = trial_info["index"]
            n_trials_in_block = trials_data[trials_data["block_nr"] == block]["index"].max() + 1

            catch_trial = not np.isnan(catch_trial) and bool(catch_trial)

            if trial_type == "repeated":
                old_trial_nr = trial_info["old_trial_nr"]
                old_block_nr = trial_info["old_block_nr"]
            else:
                old_trial_nr = np.NaN
                old_block_nr = np.NaN

            # Check if a block was finished (which means it is time for
            # feedback about the last block and a break)
            if block != previous_block:
                show_feedback(trial_nr)

                while True:
                    keys = trials.KeypressTrial(
                        self.mouse,
                        self.window,
                        keys=["space", "escape"],
                        text="Short break.\n\n\n(Press `space` to continue.)",
                    ).run()

                    if len(keys) == 1 and "space" in keys:
                        break
                    elif len(keys) == 1 and "escape" in keys:
                        self.window.fullscr = not self.window.fullscr
                        self.window.flip()
                        print("Subject toggled fullscreen")

                next_block = True
                previous_block = block

            # If a new block was started, display info about instruction type
            # of the stimuli
            if next_block or trial_nr == initial_trial_nr:
                instruction_title = {
                    "none_pre": "No",
                    "none": "No",
                    "none_post": "No",
                    "optimized": "Optimized",
                    "natural": "Natural",
                }[instr_type]
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text=f"Now you will see the\nfollowing type of\ninstruction images:\n\n"
                         f"{instruction_title} images\n\n\n(Press `space` to start the trials.)",
                ).run()
                trials.KeypressTrial(
                    self.mouse,
                    self.window,
                    keys=["space"],
                    text="The question is still the same:\nWhich of the two images\nat the center of the screen\nis "
                         "also a\nmaximally activating image?\n\n\n(Press `space` to continue.)",
                ).run()

                next_block = False

            layer = trial_info["layer"]
            kernel_size = trial_info["kernel_size"]
            channel = trial_info["channel"]
            folder_name = os.path.join(
                cfg.stimuli_folder,
                "sampled_trials",
                f"{layer}",
                f"kernel_size_{kernel_size}",
                f"{channel}",
            )
            query_folder_name = os.path.join(folder_name, "natural_images",
                                             f"batch_{batch}")
            if instr_type in ("optimized", "natural"):
                if instr_type == "optimized":
                    instruction_folder_name = os.path.join(
                        folder_name, "optimized_images"
                    )
                elif instr_type == "natural":
                    instruction_folder_name = os.path.join(
                        folder_name, "natural_images", f"batch_{batch}"
                    )

                min_stimuli = [
                    os.path.join(instruction_folder_name, f"min_{i+1}.png")
                    for i in range(cfg.n_instruction_patches)
                ]
                max_stimuli = [
                    os.path.join(instruction_folder_name, f"max_{i}.png")
                    for i in range(cfg.n_instruction_patches)
                ]
                min_title = "Minimally activating"
                max_title = "Maximally activating"
            else:
                min_stimuli = []
                max_stimuli = []

                min_title = ""
                max_title = ""

            if catch_trial:
                query_image_a = np.random.choice(min_stimuli, 1).item()
                query_image_b = np.random.choice(max_stimuli, 1).item()
            else:
                query_image_a = os.path.join(query_folder_name, "min_0.png")
                query_image_b = os.path.join(query_folder_name, "max_9.png")

            # flip order of query images randomly
            if np.random.rand() < 0.5:
                query_order = "min_max"
                correct_response: Final = "b"
            else:
                query_order = "max_min"
                correct_response: Final = "a"
                query_image_a, query_image_b = query_image_b, query_image_a

            trial = ForcedChoiceTrial(
                self.mouse,
                self.window,
                min_stimuli,
                max_stimuli,
                min_title,
                max_title,
                query_image_a,
                query_image_b,
                # timeout=timeout_threshold,
                global_progress=(trial_nr_in_block + 1 ) / (n_trials_in_block + 1),
                correct=correct_response,
            )

            rt, response, confidence, timeout_reached = trial.run()
            correct = response == correct_response

            correct_list.append(correct)

            trial_data = {
                # data from experiment_structure.csv
                "subject_id": subject_id,
                "trial_nr": trial_nr,
                "block_nr": block,
                "instr_type": instr_type,
                "trial_type": trial_type,
                "catch_trial": catch_trial,
                "batch": batch,
                "layer": layer,
                "kernel_size": kernel_size,
                "channel": channel,
                # data from trial
                "query_order": query_order,
                "correct": correct,
                "conf_rating": confidence,
                "RT": rt,
                "timeout": timeout_reached,
                "response": response,
                "correct_response": correct_response,
                "query_image_a": query_image_a,
                "query_image_b": query_image_b,
                # in case of repeated trials
                "old_trial_nr": old_trial_nr,
                "old_block_nr": old_block_nr,
                "seed": cfg.seed,
            }

            trial_data_df = pd.DataFrame(trial_data, index=[0])
            trial_data_df.to_csv(
                os.path.join(self.data_path, "experiment_data.csv"),
                index=False,
                mode="a",
                header=False,
            )

        show_feedback(trial_nr + 1)
    def _execute_warm_up_trials(self):
        """Execute the warm-up (name in paper: intuitiveness) trials of the experiment."""

        trials.KeypressTrial(
            self.mouse,
            self.window,
            keys=["space"],
            text=f"Please move the slider\nto the left (not intuitive)\nor to the right (intuitive)\naccording to "
                 f"your impression.\n\n\n(Press `space` to continue.)",
        ).run()
        
        # Warm-up trials
        rating_list = []
        rt_list = []
        trial_nr_list_warm_up = []
        trial_name_list = []
        warm_up_trials = list(string.ascii_lowercase)[: cfg.n_warm_up_trials]
        
        # randomize the order of warm_up_trials
        random.shuffle(warm_up_trials)
        
        
        for trial_nr, trial_name in enumerate(warm_up_trials):
            folder_name = os.path.join(
                cfg.stimuli_folder,
                "warm_up_trials",
                f"layer_{trial_name}",
                f"kernel_size_{trial_name}",
                f"channel_{trial_name}"
            )
            optimized_stimuli = [
                os.path.join(folder_name, f"optimized_images", f"max_{i}.png")
                for i in range(cfg.n_instruction_patches)
            ]
            natural_stimuli = [
                os.path.join(folder_name, f"natural_images", f"max_{i}.png")
                for i in range(cfg.n_instruction_patches)
            ]

            trial = WarmUpTrial(
                self.mouse,
                self.window,
                optimized_stimuli,
                natural_stimuli,
                "Optimized Images",
                "Natural Images",
            )
            rating, rt = trial.run()
            rating_list.append(int(rating))
            rt_list.append(rt)
            trial_nr_list_warm_up.append(trial_nr)
            trial_name_list.append(trial_name)

        warm_up_data_dict = {
            "subject_id": self.subject_data.subject_id[0],
            "trial_name": trial_name_list,
            "trial_nr": trial_nr_list_warm_up,
            "rating": rating_list,
            "rt": rt_list,
        }

        # save warm-up data in csv-file
        warm_up_data = pd.DataFrame(warm_up_data_dict)
        warm_up_data.to_csv(
            os.path.join(self.data_path, "warm_up_experiment_data.csv"), index=False
        )
    def _execute_warm_up_trials(self, beginning_or_end_str: str):
        """Execute the warumup trials of the experiment."""

        if beginning_or_end_str == "beginning":
            trials.KeypressTrial(
                self.mouse,
                self.window,
                keys=["space"],
                text="At first, we will ask you\nhow intuitive you find\nthe "
                "interpretability method.\n\n\n(Press `space` to continue.)",
            )
        elif beginning_or_end_str == "end":
            trials.KeypressTrial(
                self.mouse,
                self.window,
                keys=["space"],
                text=
                "Finally, we will ask you\nonce again\nhow intuitive you find\nthe "
                "interpretability method.\n\n\n(Press `space` to continue.)",
            )

        trials.KeypressTrial(
            self.mouse,
            self.window,
            keys=["space"],
            text=
            f"Please move the slider\nto the left (not intuitive)\nor to the right (intuitive)\naccording to your"
            f" impression.\n\n\n(Press `space` to continue.)",
        ).run()

        # Warm-up trials
        rating_list = []
        rt_list = []
        trial_nr_list_warm_up = []
        trial_name_list = []
        warm_up_trials = list(string.ascii_lowercase)[:cfg.n_warm_up_trials]

        # randomize the order of warm_up_trials
        random.shuffle(warm_up_trials)

        for trial_nr, trial_name in enumerate(warm_up_trials):
            folder_name = os.path.join(cfg.stimuli_folder_10, "warm_up_trials",
                                       f"layer_{trial_name}",
                                       f"kernel_size_{trial_name}",
                                       f"channel_{trial_name}")
            optimized_stimuli = [
                os.path.join(folder_name, f"optimized_images", f"max_{i}.png")
                for i in range(cfg.n_instruction_patches_warm_up)
            ]
            natural_stimuli = [
                os.path.join(folder_name, f"natural_images", f"max_{i}.png")
                for i in range(cfg.n_instruction_patches_warm_up)
            ]

            trial = WarmUpTrial(
                self.mouse,
                self.window,
                optimized_stimuli,
                natural_stimuli,
                "Optimized Images",
                "Natural Images",
            )
            rating, rt = trial.run()
            rating_list.append(int(rating))
            rt_list.append(rt)
            trial_nr_list_warm_up.append(trial_nr)
            trial_name_list.append(trial_name)

        warm_up_data_dict = {
            "subject_id": self.subject_data.subject_id[0],
            "trial_name": trial_name_list,
            "trial_nr": trial_nr_list_warm_up,
            "rating": rating_list,
            "rt": rt_list,
        }

        # save warm-up data in csv-file
        warm_up_data = pd.DataFrame(warm_up_data_dict)
        filename = os.path.join(
            self.data_path,
            f"warm_up_experiment_data_{beginning_or_end_str}.csv")
        if os.path.exists(filename):
            # just append
            warm_up_data.to_csv(filename, index=False, header=False, mode="a")
        else:
            warm_up_data.to_csv(filename, index=False)