Exemple #1
0
    def trial(
        self,
        btype: PhaseType,
        show_boxes: List[int],
        onset: TaskTime = 0,
        deval_idx: int = 1,
        dur: Optional[TaskDur] = 1
    ) -> Tuple[TaskTime, List[Keypress], Optional[TaskDur]]:
        """run a trial, flipping at onset
        @param btype - block type: what to show, how to score
        @param show_boxes - what box(es) to show
        @param deval_idx - for DD 0 to deval top, 1 to devalue bottom
        @return (fliptime, resp, rt) - key of response, how long til push could both be None
        """

        # check things make sense
        if (btype == PhaseType.OD and len(show_boxes) != 2) or \
           (btype != PhaseType.OD and len(show_boxes) != 1):
            raise Exception(
                'trail got wrong length (%d) of boxes for block (%s)' %
                (len(show_boxes), btype.name))

        # for most this is just drawing the box centered
        # but if we have two boxes to draw, align vert. (block = OD)
        for i, bn in enumerate(show_boxes):
            pos = i - (2 if len(show_boxes) > 1 else 0)  # 0 or -2, -1
            self.draw_box(box_states[btype], bn, pos, deval_idx == i)

        # show response arrows only if we have one centered box.
        # NB. feedback keeps arrows only on PhaseType.ID
        # SOA and DD both see arrows, but they are only indicators. never change color
        if len(show_boxes) == 1:
            self.show_arrows(Direction.No)

        if self.cheat:
            self.show_cheat()

        # START
        # NB. neg wait time treated like no wait
        wait_until(onset, verbose=True)
        fliptime = self.win.flip()
        # wait for response
        resp: List[Keypress] = []
        rt: Optional[TaskDur] = None
        if dur is None or dur > 0:
            print(f'  wait-for-response for {dur}sec')
            # NB. if two keys are held down, will report both!
            # make this None
            if dur:
                resp = event.waitKeys(maxWait=dur - .01,
                                      keyList=self.keys.keys())
            else:
                resp = event.waitKeys(keyList=self.keys.keys())
            rt = core.getTime() - fliptime

        return (fliptime, resp, rt)
Exemple #2
0
 def message(self, message: str, onset: TaskTime = 0) -> TaskTime:
     """show a message centered on the screen
     @param message
     @return fliptime
     """
     self.textBox.text = message
     self.textBox.pos = (0, 0)
     self.textBox.color = 'white'
     self.textBox.height = 0.1
     self.textBox.draw()
     wait_until(onset)
     return self.win.flip()
Exemple #3
0
def ID_blk(task, DURS, seed, fout=None):
    # mprage takes 6.5 minutes.
    # allow 6 seconds to end and display score
    show_boxes = shuffle_box_idx(task.info.boxes, seed)
    block_score = 0
    have_time = True
    bnum = 0
    starttime = wait_for_scanner(task.win)
    nextflip = starttime
    while have_time:
        for trl_num, box_idx in enumerate(show_boxes):
            box = task.info.boxes[box_idx]
            event = EventOut(PhaseType.ID, box)
            trl_info = task.trial(PhaseType.ID, [box_idx],
                                  onset=nextflip,
                                  dur=None)
            event.read_resp(trl_info)
            block_score += event.resp.score
            event.write(trl_num, block_score, bnum, starttime, fout,
                        'ID_mprage')

            # give feedback
            fliptime = task.fbk(box_idx,
                                event.resp.score,
                                side=event.resp.side)
            event = EventOut(PhaseType.ID, box, fliptime, TrialType.FBK)
            event.write(trl_num, block_score, bnum, starttime, fout,
                        'ID_mprage')
            nextflip = fliptime + DURS['fbk']
            if core.getTime() - starttime > DURS['mprage']:
                have_time = False
                break

        fliptime = task.message(
            f"In this block you scored {block_score} pnts!", nextflip)
        event = EventOut(PhaseType.ID, None, fliptime, TrialType.SCORE)
        event.write(0, block_score, bnum, starttime, fout, 'ID_mprage')

        # reset block for next go
        show_boxes = shuffle_box_idx(task.info.boxes, seed)
        block_score = 0
        bnum += 1
        nextflip = fliptime + DURS['score']

        # when mprage is just about over. we wont start a new block
        # so need to wait here so participant has time to read score
        if not have_time:
            wait_until(nextflip)

    fliptime = task.message(f"Finished ID!", nextflip)
    wait_until(fliptime + DURS['score'])
Exemple #4
0
 def iti(self, onset: TaskTime = 0) -> TaskTime:
     """ show iti screen.
     @param onset - when to flip. default now (0)
     @return fliptime - when screen was flipped
     """
     wait_until(onset)
     self.textBox.color = 'white'
     self.textBox.text = '+'
     # same hight as box that will replace it
     # but text hieght is a little different. still not centered
     self.textBox.height = self.box.size[1]
     self.textBox.pos = (0, 1 / 16)  # try to offset cross
     self.textBox.draw()
     fliptime = self.win.flip()
     return fliptime
Exemple #5
0
    def grid(self,
             phase: PhaseType,
             deval_idxs: List[int],
             onset: TaskTime = 0) -> TaskTime:
        """ show grid of boxes (always same order)
        @param ceval_idxs - which to cross out
        @param onset - when to flip. default now (0)
        @return fliptime - when screen was flipped
        """
        for bi in range(len(self.boxes)):
            # offset by one for showing teh grid
            boxis = 'open' if phase == PhaseType.SOA else 'closed'
            self.draw_box(boxis, bi, bi + 1, bi in deval_idxs)

        wait_until(onset, verbose=True)
        fliptime = self.win.flip()
        return fliptime
Exemple #6
0
    def fbk(self,
            show_box: Optional[int],
            score: int,
            onset: TaskTime = 0,
            side: Direction = Direction.No) -> TaskTime:
        """ give feedback - only for ID
        @param show_boxes - which box idx to show
        @param score - score to display (see Box.score())
        @param onset - when to flip (default to now (0))
        """

        if score <= 0:
            show_box = None
        self.draw_box("open", show_box, 0)

        self.textBox.pos = self.scoreBox.pos
        # yellow if correct
        # red if not
        if score >= 1:
            self.scoreBox.fillColor = 'yellow'
            self.textBox.color = 'black'
        else:
            self.scoreBox.fillColor = 'red'
            self.textBox.color = 'white'

        self.textBox.text = "%d" % score
        self.textBox.height = .1
        self.scoreBox.draw()
        self.textBox.draw()

        # show correct side
        self.show_arrows(side, score > 0)

        if self.cheat:
            self.show_cheat()

        wait_until(onset)
        return self.win.flip()
Exemple #7
0
def slips_blk(task, DURS, seed, phase=PhaseType.SOA, fout=None):
    """   
    @param task - FabFruitTask object with boxes
    @param DURS - dict with durations. keys: grid, score, iti, timeout, OFF
    @param phase - DD or SOA [default: SOA]
    @param fout - where to save file [default: None]
    
    @side-effect: execute ~10min run for given phase type

     blks: dv0 OFF 2dv2 OFF 2dv4 OFF 2dv2 OFF 2dv4 OFF
     time:  40  40   80  40   80  40   80  40   80  40 | 560 (9.33 min)
     trls:  12   0   24   0   24   0   24   0   24   0 | 108

    
     5 second grid
     2 second score
     12 x 
       1.3 seconds avg rt in 3 pilot MR is 
       1 second iti 
       + (extra .7 ontop of rt for correct no resonse
          for the 2 or 4 devalued (each box seen twice)
     blk total = 12 * (1+1.3) + 5 +2  # 35 seconds (+ .7*2*2 or .7*4*2)
     2 per 80 seconds => 2 ON for each 40s OFF 
    
     2 reps of: 1x dv0 , 2x dv2, 2x dv4. 5*80 + 3*40 == 520 == 8.67 min
    
     have 9 L/R matched pairs for each dv2 and dv4. using 8
      len(deval_2(task.info.boxes,seed)) == 9
      len(deval_4(task.info.boxes,seed)) == 9
    """

    all_deval_idxs = {
        0: [[]] * 9,
        2: deval_2(task.info.boxes, seed),
        4: deval_4(task.info.boxes, seed)
    }

    for k in all_deval_idxs:
        seed.shuffle(all_deval_idxs[k])

    draws = [0, 2, 2, 4, 4]
    seed.shuffle(draws)
    switch_blocks = []  # len == len(draws) == 5
    deval_idxs = []  # len == 9 (len(draws)*2 - 1)
    i = 0
    # draw twice from all but 0 devalued (only one dv0)
    for d in draws:
        deval_idxs.append(all_deval_idxs[d].pop())
        if d != 0:
            deval_idxs.append(all_deval_idxs[d].pop())
            i += 1
        switch_blocks.append(i)
        i += 1

    starttime = wait_for_scanner(task.win)
    next_flip = starttime
    for bnum, block_devaled_idxs in enumerate(deval_idxs):
        extra_col = f"{phase.name}_{len(block_devaled_idxs)}"
        # grid
        show_boxes = shuffle_box_idx(task.info.boxes, seed)
        block_score = 0
        fliptime = task.grid(phase, block_devaled_idxs, next_flip)
        event = EventOut(phase, None, fliptime, TrialType.GRID)
        event.write(0, block_score, bnum, starttime, fout, extra_col)
        next_flip = fliptime + DURS['grid']

        # trial
        for trl_num, box_idx in enumerate(show_boxes):
            box = task.boxes[box_idx]

            # 2 second timeout matches javascript
            event = EventOut(phase, box)
            trl_info = task.trial(phase, [box_idx],
                                  onset=next_flip,
                                  dur=DURS['timeout'])
            event.read_resp(trl_info, box_idx in block_devaled_idxs)
            block_score += event.resp.score
            event.write(trl_num, block_score, bnum, starttime, fout, extra_col)
            rt_fliptime = trl_info[0] + trl_info[2]

            # 1second iti matches javascript
            fliptime = task.iti(rt_fliptime)
            event = EventOut(phase, box, fliptime, TrialType.ITI)
            event.write(trl_num, block_score, bnum, starttime, fout, extra_col)
            next_flip = fliptime + DURS['iti']

        fliptime = task.message(
            f"You scored {block_score} pnts\n\n" +
            f"Block {bnum+1}/{len(deval_idxs)}!", next_flip)
        event = EventOut(phase, None, fliptime, TrialType.SCORE)
        event.write(trl_num, block_score, bnum, starttime, fout, extra_col)
        next_flip = fliptime + DURS['score']

        # moving to different number of devalued items. need OFF period
        # N.B. currently have wait block at very end
        if bnum in switch_blocks:
            fliptime = task.iti(next_flip)
            event = EventOut(phase, box, fliptime, TrialType.ITI)
            event.write(trl_num, block_score, bnum, starttime, fout)
            next_flip = fliptime + DURS['OFF']
            print(f"# OFF waiting {DURS['OFF']} seconds until {next_flip:.2f}")
            # default trial() intentionally errors if waiting more than 30seconds
            # get around that by waiting here for a bit
            wait_until(fliptime + DURS['OFF'] - .1, maxwait=DURS['OFF'])

    fliptime = task.message(f"Finished {phase.name}!", next_flip)
    wait_until(fliptime + DURS['score'])