Kitaya lab

User-defined task #2




Find the codes of task 90 by searching for “def Task90()” in the OperantHouse program.

def Task90():   # Test task
   global Phase
   Phase0_Init = 0
   Phase1_Init = 0
   Phase2_Init = 0
   while EndFlag == 0:
       OperantHouseUpdate()    # Run house keeping function (This must be executed once per frame)

       if GetBackButtonStat()==1:    # If "Back" button is clicked
           break   # Back to the task select phase
       if Phase == 0:  # Parameter inputs
           if Phase0_Init == 0:    # Make GUI for the setting of the parameters for this task
               RemoveMainRightWidget() # Remove task buttons
               PutStartBackButton()    # Put "start" and "back" buttons

               ColumnWidth = 14    # Width of input columns
               
               mMaxCorrectNum = ttk.Label(MainWindowRightFrame, text='MaxCorrectNum', width=ColumnWidth).grid(row=0, column=0, sticky=W)    # Put label
               MaxCorrectNumVar = IntVar(MainWindowRoot)  # Declare a variable for input column
               iMaxCorrectNum = ttk.Entry(MainWindowRightFrame, textvariable=MaxCorrectNumVar, width=ColumnWidth).grid(row=1, column=0)  # Create inputcolumn and link it with the variable
               
               mTimeLimit = ttk.Label(MainWindowRightFrame, text='TimeLimit(min)', width=ColumnWidth).grid(row=0, column=1, sticky=W)
               TimeLimitVar = IntVar(MainWindowRoot)
               iTimeLimit = ttk.Entry(MainWindowRightFrame, textvariable=TimeLimitVar, width=ColumnWidth).grid(row=1, column=1)
               
               mLickDur = ttk.Label(MainWindowRightFrame, text='LickDur(s)', width=ColumnWidth).grid(row=0, column=2, sticky=W)
               LickDurVar = IntVar(MainWindowRoot)
               iLickDur = ttk.Entry(MainWindowRightFrame, textvariable=LickDurVar, width=ColumnWidth).grid(row=1, column=2)


               Str = "ParametersForTask" + str(GetTaskID())
               if os.path.exists(Str + '/MaxCorrectNum.dat') == True:  # If save file named "MaxCorrectNum.dat" exist:
                   with open(Str + '/MaxCorrectNum.dat', 'rb') as PickleInst[GetTaskID()]:
                       MaxCorrectNumVar.set(pickle.load(PickleInst[GetTaskID()]))  # Assign loaded data into the variable of this program
               else:  # If save file doesn't exist
                   MaxCorrectNumVar.set(80)  # Assign 80 into the variable

               if os.path.exists(Str + '/TimeLimit.dat') == True:
                   with open(Str + '/TimeLimit.dat', 'rb') as PickleInst[GetTaskID()]:
                       TimeLimitVar.set(pickle.load(PickleInst[GetTaskID()]))
               else:
                   TimeLimitVar.set(600)

               if os.path.exists(Str + '/LickDur.dat') == True:
                   with open(Str + '/LickDur.dat', 'rb') as PickleInst[GetTaskID()]:
                       LickDurVar.set(pickle.load(PickleInst[GetTaskID()]))
               else:
                   LickDurVar.set(2)


               PutRoiGui(0, 1, 1, 0)  # Put setting GUI of the indicated ROI on ROI window (ROI number, Detection mode, Threshold direction, ShowSymbol or not)
               PutRoiGui(19, 0, 0, 1)

               RemoveAllDigitalOutGui()    # Remove all GUIs on the Digital out window
               PutDigitalOutGui(10)    # Put the digital output GUI for channel 10 on Digital ouput window
               PutDigitalOutGui(12)
               PutDigitalOutGui(13)

               RemoveAllServoGui() # Remove all GUI on the Servo GUI
               PutServoGui(3)  # Put a servo GUI for channel 3 on the Servo GUI

               Phase0_Init = 1 # Set a flag which indicating phase0 initialization has done

       if GetSaveTrgStat() == 1:    # If save trigger is activated
           # Parameters will be saved into a folder named "ParametersForTask90"
           Str="ParametersForTask"+str(GetTaskID())   # Assign save folder path
           if os.path.exists(Str) == False:    # If save folder doesn't exist
               os.mkdir(Str)   # Create the folder
           with open(Str+'/MaxCorrectNum.dat', 'wb') as PickleInst[GetTaskID()]:
               pickle.dump(MaxCorrectNumVar.get(),PickleInst[GetTaskID()])     # Save a value of "MaxCorrectNumVar" as "MaxCorrectNum.dat" file

           with open(Str+'/TimeLimit.dat', 'wb') as PickleInst[GetTaskID()]:
               pickle.dump(TimeLimitVar.get(),PickleInst[GetTaskID()])

           with open(Str+'/LickDur.dat', 'wb') as PickleInst[GetTaskID()]:
               pickle.dump(LickDurVar.get(), PickleInst[GetTaskID()])


       if Phase == 1:  # Waiting phase (Task will start when the set time arrives)
           if Phase1_Init == 0: # If the initialization for phase1 has not done
               PutPreTaskButton()  # Put "StartNow" and "Back" button on Main window
               mStatusVar = StringVar(MainWindowRoot)  # Create a variable for status display
               mStatus = ttk.Label(MainWindowRightFrame, textvariable=mStatusVar)  # Create label object and link it with Main window
               mStatus.place(x=10, y=0)    # Place label object on the Main window
               mOngoingResultVar = StringVar(MainWindowRoot)   # Create a variable for progress display
               Phase1_Init = 1 # Flat that phase1 has done
           mStatusVar.set('Test task (' + str(GetTaskID()) + ')    Waiting...')    # Show current status of the Operant House
           if IsStartTime() == 1:  # Check whether task start time arrives
               StartNow()  # Start task (Phase number will be "2")

       if Phase == 2:  # If it is during task
           if Phase2_Init == 0: # Initialization of the task
               PutEndTaskNowButton()   # Put "TaskEnd" button on Main window
               mStatusVar.set('Test task (' + str(GetTaskID()) + ')    Start time ' + str(TaskStartedMonth) + '/' + str(TaskStartedDay) + ' ' + str(TaskStartedHour)+ ':' + str(TaskStartedMinute) + '    Running')    # Assign latest information about current task into "mStatusVar"
               mOngoingResult = ttk.Label(MainWindowRightFrame, textvariable=mOngoingResultVar)
               mOngoingResult.place(x=10, y=18)

               # Assign task parameter values in StringVars into integer or string variable (to make the cord easeir to read)
               MaxCorrectNum=int(MaxCorrectNumVar.get())   # Get the value of "MaxCorrectNumVar" and convert it from string to integer and assign intovariable named "MaxCorrectNum"
               TimeLimit = int(TimeLimitVar.get())
               LickDur = int(LickDurVar.get())

               # Declar local variables for this task
               CorrectNum = 0
               TaskDur = 0  # This will keep the elapsed time during of task
               NowDrinking = 0

               StartRecording()  # Start camera capture / TTL signal output
               StartLickRecording()  # Start an entry of lick log
               LightCycleControlOff()  # Deactivate automatic Light/Dark cycle illumination
               RoofLightOff()  # Turn off the lights on roof (Digital output Ch13)
               InfraredLightOn()   # Turn on the infrared LED illumination (Digital output Ch12)
               DigitalOutOn(10)        # Turn on cue LED connected to Ch10
               ServoPosInside(3)   # Change the angle of water arm servo connected to Ch3 to inside position
               CreateNormalPanel(0)  # Create a white-filled square panel as panel #0

               Writer_TouchEventTxt = open(Path + "/" + str(TimeNow.year) + "_" + str(TimeNow.month) + "_" + str(TimeNow.day) + " " + str(TimeNow.hour) + "h" + str(TimeNow.minute) + "m Task" + str(GetTaskID()) + " Touch.txt", 'w')  # Initialize the text exporter for a result file
               Writer_TouchEventTxt.write('TrialNum\tResult\t\t\tyyyy/mm/dd\th:m\ts\n')  # Write item name on the result file
               Writer_TouchEventCsv = open(Path + "/" + str(TimeNow.year) + "_" + str(TimeNow.month) + "_" + str(TimeNow.day) + " " + str(TimeNow.hour) + "h" + str(TimeNow.minute) + "m Task" + str(GetTaskID()) + " Touch.csv", 'w')
               print("Task #" + str(GetTaskID()) + " is started at " + str(GetTaskStartedMonth()) + '/' + str(GetTaskStartedDay()) + ' ' + str(GetTaskStartedHour()) + ':' + str(GetTaskStartedMinute()) + ':' + str(GetTaskStartedSecond()))  # Enter the start time in the console window of Pycharm

               Timer_Start(5)  # Start a timer #5 to measure the duration of the task
               Phase2 = 2  # Start task from the reward phase
               Phase2_Init = 1 # Flag indicating that initialization of Phase2 has done

           if Phase2 == 0:   # Initiation of new trial
               TaskDur = Timer_GetSec(5)
               ShowPanel(0)    # Display panel #0
               Phase2 = 1

           if Phase2 == 1:   # Panel presentation
               TouchedPanelID = DetectRoiNosepoke()  # Examine which panel is touched (return panel ID. If none of the panels touched, return -1)
               if TouchedPanelID == 0: # If mouse touches the panel
                   ServoPosInside(3)    # Move the water nozzle into inside position
                   DigitalOutOn(10)    # Onset cue light
                   HidePanel(0)
                   NowDrinking = 0
                   CorrectNum += 1     # Increase the number of correct response
                   mOngoingResultVar.set('CorrectNum:' + str(CorrectNum))
                   Writer_TouchEventTxt.write(str(CorrectNum)+'\tPanelTouched(Correct)\t'+ str(TimeNow.year)+"/"+str(TimeNow.month)+"/"+str(TimeNow.day)+"\t"+str(TimeNow.hour)+":"+str(TimeNow.minute)+"\t"+str(TimeNow.second)+"."+str(TimeNow.microsecond//1000)+"\n") # Write the response on thetext file
                   Writer_TouchEventCsv.write(str(CorrectNum) + ',1,' + str(TimeNow.year) + "," + str(TimeNow.month) + "," + str(TimeNow.day) + "," + str(TimeNow.hour) + "," + str(TimeNow.minute) + "," + str(TimeNow.second) + "." + str(TimeNow.microsecond//1000)+"\n")  # Write the response on the csvfile
                   Phase2 = 2  # Start reward phase

               if Timer_GetSec(5) >= TimeLimit * 60:   # If time limit of the task comes
                   TaskDur = Timer_GetSec(5)
                   print("Time limit elapsed")
                   Timer_End(5)    # Stop the timer
                   Phase2 = -1

           if Phase2 == 2:  # Reward phase
               if DetectRoiNosepoke() == 19 and NowDrinking == 0:    # If the mouse initiates nose poking
                   NowDrinking = 1
                   Timer_Start(0)  # Start lick timer
               if NowDrinking == 1:    # If the nose poke has begun
                   if Timer_GetSec(0) >= LickDur:   # If the nosepoke duration exceeds the lick duration
                       Timer_End(0) # End timer for measuring lick duration
                       ServoPosMiddle(3)   # Move water nozzle back to the middle position
                       DigitalOutOff(10)   # Turn off the cue LED
                       NowDrinking = 0
                       if CorrectNum < MaxCorrectNum:  # If the touch number doesn't exceed the maximum number
                           Phase2 = 0
                       if CorrectNum >= MaxCorrectNum:   # If the touch number exceeds the maximum number
                           TaskDur = Timer_GetSec(5)  # Keep the task time
                           Phase2 = -1 # Go to the task finalizing phase

           if Phase2 == -1 or GetEndTaskNowButtonStat() == 1:  # If the flag is set to finish the task
               LightCycleControlOn()   # Activate automatic light/dark cycle
               ServoPosMiddle(3)   # Moze servo nozzle into middle position
               DeleteAllPanel()    # Remove a panel on touch screen
               InfraredLightOff()  # Turn off the infrared LED
               if GetRecordingStat() == 1: # If camera is capturing
                   SetEndRecordingTimer(60)    # Onset a timer to finish video recording after 60 frames (correspond about 2sec) from now
               # Add summary of results into the result file
               Writer_TouchEventTxt.write('CorrectNum:'+str(CorrectNum)+"\n")
               Writer_TouchEventTxt.write('SessionStartTime: ' + str(GetTaskStartedMonth()) + '/' + str(GetTaskStartedDay()) + ' ' + str(GetTaskStartedHour()) +':' + str(GetTaskStartedMinute()) + ':' + str(GetTaskStartedSecond()) + "\n")
               Writer_TouchEventTxt.write('SessionEndTime: ' + str(TimeNow.month) + '/' + str(TimeNow.day) + ' ' + str(TimeNow.hour) + ':' + str(TimeNow.minute) + ':' + str(TimeNow.second + (TimeNow.microsecond // 1000) / 1000) + "\n")
               Writer_TouchEventTxt.write('TaskDuration(sec): ' + str(TaskDur) + "\n")
               # Add experimental conditions into the result file
               Writer_TouchEventTxt.write('MaxCorrectNum: '+str(MaxCorrectNum)+"\n")
               Writer_TouchEventTxt.write('TimeLimit: ' + str(TimeLimit) + "\n")
               Writer_TouchEventTxt.write('LickDur: ' + str(LickDur)+"\n")
               Writer_TouchEventTxt.write('RecordFPS: ' + str(GetRecordFps()) + "\n")  # Recorded frame number per second
               Writer_TouchEventTxt.write(GetRoiSensitivity() + "\n")  # Settings of each ROI
               Writer_TouchEventTxt.write(GetServoAngle() + "\n")  # Set angles of each servo

               Writer_TouchEventTxt.close()    # Close the text exporter for the result file
               Writer_TouchEventCsv.close()
               EndLickRecording()  # End lick log recording

               SendMail(DeviceNameVar.get()+' finished task '+str(GetTaskID())+'. Correct:'+str(CorrectNum)+' Dur:'+str(round(Timer_GetSec(5) / 60,1))+' min','The task is finished.') # Send a email (correct number and task duration are added to email title)

               Phase = 1  # Go back to the task-waiting phase
               Phase2 = 0
               Phase2_Init = 0

           SetDispVariable(0, 'Phase2', str(Phase2))  # Display "Phase2" value on the bottom of main window
   return




When the task button in the main window is clicked, the task 90 code is called as a function and it starts the loop from line 6 as while syntax.

while EndFlag == 0:

Therefore, the code below line 6 will be a main loop of this program after choosing the task. However, this loop doesn’t contain commands to control basic functions of OperantHouse such as the camera, Arduino, GUI and timers.

To execute these functions, the following function is executed. This function must be executed once per frame.

OperantHouseUpdate()    # Run house keeping function (This must be executed once per frame)


The next code is to exit the loop and return to the task select phase when the “Back” button on the left side of the main window is clicked.

if GetBackButtonStat()==1:    # If "Back" button is clicked
   break   # Back to the task select phase

During the task selection, the program loop at the following code located at the end of this program.

while EndFlag<=4: # Main roop of non-task period 3
   OperantHouseUpdate()

   if OHCnt==30:    # If it takes a while after running (Serial connection doesn't establish at the 1st frame)
       RoofLightOn()    #Turn on roof illumination
       InfraredLightOn()    # Turn on IR illumination
       ServoPosMiddle(3)  # Move water nozzle to the intermediate position
   if ButtonAWS_On==1: # If button activated AWS is turned on
       if AWS_Stat==1:
           ServoPosMiddle(3)
           DigitalOutOff(10)
           RoofLightOn()
           IsWaterCueBlink = 0
           ButtonAWS_On=0
   if EndFlag==3:  # If LEDs are turned off and water nozzle move to neutral position, turn off the switch of servo
       Angle = 127  # Means make servo is turned off (ValueRange=0-127(0-180 degree))
       ServoOutputBook = 1


Now let's move on. This task comprises 3 phases. In phase 0, it shows task parameters setting. In phase 1, it waits until the task starts. In phase 2, it performs the task. The Phase is a global variable and its value is manipulated by clicking the buttons on the main window.
In the next chapter, I’ll explain the code in phase 0 which is executed after clicking the task button.