Skip to content

Commit

Permalink
Refactor task (#162)
Browse files Browse the repository at this point in the history
  • Loading branch information
tab-cmd authored Aug 4, 2021
1 parent cce7146 commit f8054da
Show file tree
Hide file tree
Showing 37 changed files with 547 additions and 541 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ This a list of the major modules and their functionality. Each module will conta
- `language_model`: gives probabilities of next letters during typing.
- `parameters`: location of json parameters.
- `static`: image and sound stimuli, misc manuals, and readable texts for gui.
- `tasks`: bcipy implemented user tasks. Main collection of bci modules for use during various experimentation. Ex. RSVPCalibration.
- `task`: bcipy implemented user tasks. Main collection of bci modules for use during various experimentation. Ex. RSVP Calibration.
- `feedback`: feedback mechanisms for sound and visual stimuli.
- `main`: executor of experiments. Main entry point into the application

Expand Down
2 changes: 1 addition & 1 deletion bcipy/demo/bci_main_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

def main():
from bcipy.main import bcipy_main
from bcipy.tasks.task_registry import TaskType
from bcipy.task import TaskType
from bcipy.helpers.parameters import DEFAULT_PARAMETERS_PATH

# Load a parameters file
Expand Down
2 changes: 1 addition & 1 deletion bcipy/gui/BCInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
)
from bcipy.helpers.load import load_json_parameters, load_experiments, copy_parameters, load_users
from bcipy.helpers.parameters import DEFAULT_PARAMETERS_PATH
from bcipy.tasks.task_registry import TaskType
from bcipy.task import TaskType


class BCInterface(BCIGui):
Expand Down
8 changes: 4 additions & 4 deletions bcipy/helpers/copy_phrase_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
from bcipy.helpers.task import BACKSPACE_CHAR
from bcipy.signal.model import SignalModel
from bcipy.signal.process import get_default_transform
from bcipy.tasks.rsvp.main_frame import DecisionMaker, EvidenceFusion
from bcipy.tasks.rsvp.query_mechanisms import NBestStimuliAgent
from bcipy.tasks.rsvp.stopping_criteria import (
from bcipy.task.control.handler import DecisionMaker, EvidenceFusion
from bcipy.task.control.query import NBestStimuliAgent
from bcipy.task.control.criteria import (
CriteriaEvaluator,
MaxIterationsCriteria,
MinIterationsCriteria,
ProbThresholdCriteria,
)
from bcipy.tasks.session_data import EvidenceType
from bcipy.task.data import EvidenceType


log = logging.getLogger(__name__)
Expand Down
2 changes: 1 addition & 1 deletion bcipy/helpers/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from bcipy.helpers.load import load_json_parameters, load_experiment_fields, load_experiments
from bcipy.helpers.task import alphabet
from bcipy.helpers.validate import validate_field_data_written
from bcipy.tasks.session_data import Session, Inquiry
from bcipy.task.data import Session, Inquiry


def session_data(data_dir: str, alp=None):
Expand Down
2 changes: 1 addition & 1 deletion bcipy/helpers/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from typing import Any, List, Optional, Set, Tuple, Union

import numpy as np
from bcipy.tasks.exceptions import InsufficientDataException
from bcipy.task.exceptions import InsufficientDataException
from psychopy import core, event, visual

log = logging.getLogger(__name__)
Expand Down
2 changes: 1 addition & 1 deletion bcipy/helpers/tests/test_copy_phrase_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from bcipy.helpers.load import load_json_parameters
from bcipy.helpers.task import alphabet
from bcipy.signal.model import PcaRdaKdeModel
from bcipy.tasks.session_data import EvidenceType
from bcipy.task.data import EvidenceType


class TestCopyPhraseWrapper(unittest.TestCase):
Expand Down
6 changes: 3 additions & 3 deletions bcipy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
from bcipy.helpers.validate import validate_experiment
from bcipy.helpers.parameters import DEFAULT_PARAMETERS_PATH
from bcipy.helpers.save import init_save_data_structure
from bcipy.tasks.start_task import start_task
from bcipy.tasks.task_registry import TaskType
from bcipy.task import TaskType
from bcipy.task.start_task import start_task
from bcipy.signal.model import PcaRdaKdeModel


Expand Down Expand Up @@ -128,7 +128,7 @@ def execute_task(task: TaskType, parameters: dict, save_folder: str) -> bool:
start_task(
display, daq, task, parameters, save_folder,
language_model=language_model,
signal_model=signal_model, fake=fake, auc_filename=filename)
signal_model=signal_model, fake=fake)

# If exception, close all display and acquisition objects
except Exception as e:
Expand Down
50 changes: 50 additions & 0 deletions bcipy/task/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# BCI TASKS
-----------

These are the tasks that can be run to collect experimental data.

## Paradigms
------------
Within `task/` there are folders for each of the supported paradigms, and within them, the supported modes. To add new paradigms, create a folder for it and place the tasks in files within it. Be sure to add it to the `start_task` file at the root to be able execute it! An entry must also be added to the task_registry TaskType
enum. This updates the GUI (BCInterface.py) and makes the task available to `start_task`.

Currently, these are the supported paradigms and modes:

### *Paradigm: RSVP*

##### Mode: Calibration

> Calibration
> Alert Tone Calibration
> Inter-Inquiry Feedback Calibration
> Timing Verification Calibration
##### Mode: Copy Phrase

> Copy Phrase

## Start Task
-------------

Start Task takes in Display [object], parameters [dict], file save [str-path] and task type [dict]. Using the
task type, start_task() will route to the correct paradigm (RSVP, SSVEP, MATRIX) and mode (Calibration, Copy Phrase, etc.)

It is called in the following way:


```
from bcipy.task.start_task import start_task
start_task(
display_window,
data_acquisition_client,
parameters,
file_save)
```

It will throw an error if the task isn't implemented.
10 changes: 10 additions & 0 deletions bcipy/task/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"""
This import statement allows users to import submodules from Task
"""
from .main import Task
from .task_registry import TaskType

__all__ = [
'Task',
'TaskType',
]
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

from bcipy.helpers.stimuli import InquirySchedule, rsvp_inq_generator, StimuliOrder
from bcipy.helpers.task import SPACE_CHAR, BACKSPACE_CHAR
from bcipy.tasks.rsvp.query_mechanisms import RandomStimuliAgent
from bcipy.tasks.rsvp.stopping_criteria import CriteriaEvaluator
from bcipy.task.control.query import RandomStimuliAgent
from bcipy.task.control.criteria import CriteriaEvaluator

log = logging.getLogger(__name__)

Expand Down Expand Up @@ -58,9 +58,10 @@ def reset_history(self):
del value[:]
self.likelihood = np.ones(len(self.likelihood)) / len(self.likelihood)

def save_history(self):
def save_history(self) -> None:
""" Saves the current likelihood history """
return 0
log.warning('save_history not implemented')
return

@property
def latest_evidence(self) -> Dict[str, List[float]]:
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from bcipy.tasks.rsvp.main_frame import EvidenceFusion, DecisionMaker
from bcipy.task.control.handler import EvidenceFusion, DecisionMaker
import numpy as np


Expand Down
File renamed without changes.
12 changes: 8 additions & 4 deletions bcipy/tasks/task.py → bcipy/task/main.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import logging

from abc import ABC, abstractmethod

class Task(object):

class Task(ABC):
"""Task.
Base class for BciPy tasks.
Expand All @@ -12,10 +14,12 @@ def __init__(self):
self.logger = logging.getLogger(__name__)

def configure(self):
pass
...

@abstractmethod
def execute(self):
raise NotImplementedError()
...

@abstractmethod
def name(self):
raise NotImplementedError()
...
File renamed without changes.
File renamed without changes.
Empty file.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from bcipy.helpers.stimuli import play_sound, soundfiles
from bcipy.tasks.task import Task
from bcipy.tasks.rsvp.calibration.calibration import RSVPCalibrationTask
from bcipy.task import Task
from bcipy.task.paradigm.rsvp.calibration.calibration import RSVPCalibrationTask


class RSVPAlertToneCalibrationTask(Task):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from bcipy.display.rsvp.mode.calibration import CalibrationDisplay
from bcipy.display.rsvp import StimuliProperties, TaskDisplayProperties, InformationProperties

from bcipy.tasks.task import Task
from bcipy.task import Task

from bcipy.helpers.triggers import _write_triggers_from_inquiry_calibration
from bcipy.helpers.stimuli import calibration_inquiry_generator, get_task_info, StimuliOrder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
from typing import List, Tuple

from bcipy.feedback.visual.level_feedback import LevelFeedback
from bcipy.tasks.task import Task
from bcipy.tasks.exceptions import InsufficientDataException
from bcipy.tasks.rsvp.calibration.calibration import RSVPCalibrationTask
from bcipy.task import Task
from bcipy.task.exceptions import InsufficientDataException
from bcipy.task.paradigm.rsvp.calibration.calibration import RSVPCalibrationTask
from bcipy.helpers.triggers import _write_triggers_from_inquiry_calibration
from bcipy.helpers.stimuli import calibration_inquiry_generator, get_task_info
from bcipy.helpers.task import (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from itertools import cycle
from bcipy.tasks.task import Task
from bcipy.tasks.rsvp.calibration.calibration import RSVPCalibrationTask
from bcipy.task import Task
from bcipy.task.paradigm.rsvp.calibration.calibration import RSVPCalibrationTask


class RSVPTimingVerificationCalibration(Task):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
trial_complete_message)
from bcipy.helpers.triggers import _write_triggers_from_inquiry_copy_phrase
from bcipy.signal.model.inquiry_preview import compute_probs_after_preview
from bcipy.tasks.session_data import Inquiry, Session, EvidenceType
from bcipy.tasks.task import Task
from bcipy.task.data import Inquiry, Session, EvidenceType
from bcipy.task import Task


class Decision(NamedTuple):
Expand Down
24 changes: 11 additions & 13 deletions bcipy/tasks/start_task.py → bcipy/task/start_task.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
"""Code for constructing and executing Tasks"""
from bcipy.tasks.rsvp.calibration.alert_tone_calibration import RSVPAlertToneCalibrationTask
from bcipy.tasks.rsvp.calibration.inter_inquiry_feedback_calibration import (
from bcipy.task.paradigm.rsvp.calibration.alert_tone_calibration import RSVPAlertToneCalibrationTask
from bcipy.task.paradigm.rsvp.calibration.inter_inquiry_feedback_calibration import (
RSVPInterInquiryFeedbackCalibration
)
from bcipy.tasks.rsvp.calibration.calibration import RSVPCalibrationTask
from bcipy.tasks.rsvp.copy_phrase import RSVPCopyPhraseTask
from bcipy.tasks.rsvp.calibration.timing_verification import RSVPTimingVerificationCalibration
from bcipy.task.paradigm.rsvp.calibration.calibration import RSVPCalibrationTask
from bcipy.task.paradigm.rsvp.copy_phrase import RSVPCopyPhraseTask
from bcipy.task.paradigm.rsvp.calibration.timing_verification import RSVPTimingVerificationCalibration

from bcipy.tasks.task import Task
from bcipy.tasks.exceptions import TaskRegistryException
from bcipy.tasks.task_registry import TaskType
from bcipy.task import Task
from bcipy.task.exceptions import TaskRegistryException
from bcipy.task.task_registry import TaskType


def make_task(display_window, daq, task, parameters, file_save,
signal_model=None, language_model=None, fake=True,
auc_filename=None) -> Task:
signal_model=None, language_model=None, fake=True) -> Task:
"""Creates a Task based on the provided parameters.
Parameters:
Expand All @@ -27,7 +26,6 @@ def make_task(display_window, daq, task, parameters, file_save,
signal_model
language_model - language model
fake: boolean - true if eeg stream is randomly generated
auc_filename: str
Returns:
--------
Task instance
Expand Down Expand Up @@ -60,8 +58,8 @@ def make_task(display_window, daq, task, parameters, file_save,


def start_task(display_window, daq, task, parameters, file_save,
signal_model=None, language_model=None, fake=True, auc_filename=None):
signal_model=None, language_model=None, fake=True):
"""Creates a Task and starts execution."""
task = make_task(display_window, daq, task, parameters, file_save,
signal_model, language_model, fake, auc_filename)
signal_model, language_model, fake)
task.execute()
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Tests for session-related functionality."""

import unittest
from bcipy.tasks.session_data import Session, Inquiry, EvidenceType
from bcipy.task.data import Session, Inquiry, EvidenceType


def sample_stim_seq(include_evidence: bool = False):
Expand Down Expand Up @@ -205,3 +205,7 @@ def test_session_deserialization(self):
self.assertEqual(
first_stim_seq.stimuli,
["+", "I", "D", "H", "G", "F", "<", "E", "B", "C", "A"])


if __name__ == '__main__':
unittest.main()
Loading

0 comments on commit f8054da

Please sign in to comment.