Skip to content

Commit

Permalink
Merge pull request #248 from AllenNeuralDynamics/production_testing
Browse files Browse the repository at this point in the history
[production merge] 02/13/2024
  • Loading branch information
alexpiet authored Feb 13, 2024
2 parents 87d1fc8 + 25dd86d commit ccd974c
Show file tree
Hide file tree
Showing 19 changed files with 463 additions and 349 deletions.
66 changes: 37 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,46 +280,54 @@ To configure automatic updates consistent with the [update protocol](https://git
- **Double dipping**: Double dipping statistics in different behavior epochs and conditions.

### Automatic training
1. In the main dialog, press `Auto Train` button <img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/9ef26192-044b-4c22-928f-b328b7ab36ab" width="90"> or `Ctrl + Alt + A` to open the Automatic Training dialog
1. In the main dialog, press `Auto Train` button <img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/836a4432-b1b2-4f92-9c66-2441a9d77a82" width="150"> or `Ctrl + Alt + A` to open the Automatic Training dialog
> [!IMPORTANT]
> If the dialog fails to open, check AWS credentials at `~/.aws/credentials`. See [instructions](#for-initial-installation)
2. For the first session of a new mouse:
- Confirm that this is a new mouse<br>
<img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/bcaafe89-3330-4704-81f9-ab30c259512b" width="400"><br>
- On the right side, select a desired curriculum for the new mouse. Double-check `curriculum_name`, `curriculum_version`, and the diagrams<br>.
<img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/2e3c030f-f91e-4917-9fa9-7e27af115171" width="700"><br>
- Click buttons to see interative diagrams in browser <br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/bb845129-a12b-445a-8639-0e981a60deb9" height="30">
- Click `Set curriculum` button <img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/f1fac3e0-1c84-42e9-9f12-ba11896845b8" width="60"> to confirm
- Now a new entry with `session = 0` is added in `Training history`, and `STAGE_1` of the selected curriculum is suggested by default. <br>
<img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/90a054ab-71c1-4fa2-b13b-ab06f7895080" width="700"><br>
1. ‼️ So far, the automatic training system cannot handle our previous Stage 1.1 --> Stage 1.2.<br>
For a new mouse, please still use `Coupled Baiting - Stage 1.1` in the "Parameters" page to warm up the mouse as before.<br>
Note we always start with `Coupled Baiting - Stage 1.1` even if `curriculum_name == "Uncoupled ..."` (see [this issue](https://github.com/AllenNeuralDynamics/aind-behavior-blog/issues/241))<br>
![image](https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/13c34f43-ceeb-4a79-927e-242f03608602)<br>
Once you think the mouse is ready for Stage 1.2, please follow the steps below to start using automatic training. <br>(`Stage 1` in `Auto Train`= `Stage 1.2` in the `Parameters` tab.)<br><br>

2. Confirm that this is a new mouse in the automatic training system<br>
<img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/684d4aac-f9a9-4ce7-9536-61aace828c76" width="400"><br>
3. In "Curriculum Manager", select a desired curriculum for the new mouse. Double-check `curriculum_name` and `curriculum_version`<br>.
<img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/da03961e-71ef-4c6b-a0c0-37475edd1c66" width="700"><br><br>
4. (Optional) Click buttons to see interative diagrams in browser <br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/99038b93-aef7-48bb-b756-a387bf435a6e" height="30">
5. Click `Set curriculum` button <img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/2e3f9abd-afda-4a8c-8475-dfb4f2d8065d" width="300"> to confirm
6. Now a new entry with `session = 0` is added in `Training history`, and `STAGE_1` of the selected curriculum is suggested by default. <br>
<img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/dac71e11-ed71-4fbc-9c3b-85695aa8ef5c" width="700"><br><br>
3. For a mouse that already started training
- Its training history and curriculum is automatically loaded
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/58a9e583-09a4-4295-84eb-db5ef873df5d" width="900">
- Uncheck `show this mouse only` to see training history from all mice
1. Its training history and curriculum is automatically loaded
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/1dc6e13a-a563-425e-81df-28c0e71a8037" width="900">
2. (Optional) Uncheck `show this mouse only` to see training history from all mice
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/97c05425-7dac-426b-9ba2-aadcfc1868ed" height="30">
- Press `Show all training history` <img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/ff1354b6-4b78-4740-a317-b5ec1b83686e" height="30"> to open an interactive plotly chart that visualize all training history in browser
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/af541948-94ab-4f13-b599-ca188be77324" width="700">
3. (Optional) Press `Show auto-training history in Streamlit` <img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/c5dc9f2f-8485-47c3-a7e7-ed23947cc4a1" height="30"> to open the Streamlit app showing all training history in browser
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/194ee69c-14ec-466d-93b7-3b3e26b4ece8" width="1200">
4. Apply and lock training parameters
- Check the curriculum name and stage name shown on the huge green button<br>
<img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/c46cd82e-76e7-4d7c-914e-41752937fee8" width="200"><br>
- Press the button to apply and lock all curriculum-controlled training parameters in the main GUI (including the "Task").
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/27e72b0d-5317-47ba-ac16-7b22e7374cd7" width="900">
- Note that you can still modify some items in `Training parameters`, such as `Valve open time`, `Give left/right`, and `Next block`.
- You could now close the Auto Training dialog.
- Start the training as usual.
1. Check the curriculum name and stage name shown on the huge green button<br>
<img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/b4bcfd2e-dc68-4349-9208-b06f429c993f" width="200"><br>
2. Press the button to apply and lock all curriculum-controlled training parameters in the main GUI (including the "Task").
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/fabbf0c2-3f9f-4fa3-8945-030105248851" width="1200">
3. Note that you can still modify some items in `Training parameters`, such as `Valve open time`, `Give left/right`, and `Next block`.
4. You could now close the Auto Training dialog.
5. Start the training as usual.

5. Override parameters (not recommended)
- Once `Apply and lock` is pressed, you can press it again to unlock the parameters and override any of them. But in this case, the automatic training mode is disengaged, and this session is considered "off-curriculum".

1. Once `Apply and lock` is pressed, you can press it again to unlock the parameters and override any of them. But in this case, the automatic training mode is disengaged, and this session is considered "off-curriculum". <br>
![image](https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/08b7997c-bdce-421b-8c90-3a7e4dfc5ba7)

6. Override stage (not recommended)
- Check `Override stage` to override the suggested stage. In the example below, `STAGE_FINAL` is suggested, but `STAGE_3` will be actually used (see the green button).
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/92fb9df7-3e54-4bf2-a86a-02c3808c554e" width="700">
1. Check `Override stage` to override the suggested stage. In the example below, `STAGE_FINAL` is suggested, but `STAGE_3` will be actually used (see the green button).
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/3a25ed5c-e92f-4ba4-8fc5-38bd4c498499" width="700">

7. Override curriculum (not recommended)
- If you somehow decide to change the curriculum during training, press `Override curriculum` and set a new curriculum.
- In this case, since all stages from the old curriculum now become "irrelevant", you should always manually select a stage in the ***new*** curriculum to override.
1. If you somehow decide to change the curriculum during training, press `Override curriculum` and set a new curriculum.
2. In this case, since all stages from the old curriculum now become "irrelevant", you should always manually select a stage in the ***new*** curriculum to override.
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/802e5208-dc5f-45f5-8ece-b9241157bf88" width="300">
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/fba62a4b-acdb-49e9-a401-3a382607b0f3" width="700">
<br><img src="https://github.com/AllenNeuralDynamics/dynamic-foraging-task/assets/24734299/9f0f0853-8033-46ff-82a6-38b6c01ec136" width="700">

### Water Calibration

Expand Down
5 changes: 5 additions & 0 deletions src/desktop_shortcuts/BoxA no console.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cd /d C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\src\foraging_gui
call conda activate Foraging
start "" C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\src\desktop_shortcuts\start_popup.bat
start "" pythonw Foraging.py 1

5 changes: 5 additions & 0 deletions src/desktop_shortcuts/BoxB no console.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cd /d C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\src\foraging_gui
call conda activate Foraging
start "" C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\src\desktop_shortcuts\start_popup.bat
start "" pythonw Foraging.py 2

5 changes: 5 additions & 0 deletions src/desktop_shortcuts/BoxC no console.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cd /d C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\src\foraging_gui
call conda activate Foraging
start "" C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\src\desktop_shortcuts\start_popup.bat
start "" pythonw Foraging.py 3

5 changes: 5 additions & 0 deletions src/desktop_shortcuts/BoxD no console.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cd /d C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\src\foraging_gui
call conda activate Foraging
start "" C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\src\desktop_shortcuts\start_popup.bat
start "" pythonw Foraging.py 4

12 changes: 10 additions & 2 deletions src/desktop_shortcuts/CameraA.bat
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
cd /d C:\Users\svc_aind_behavior\Documents\camera_workflows
start /min C:\Users\svc_aind_behavior\Documents\GitHub\dynamic-foraging-task\bonsai\bonsai Camera_boxA.bonsai --no-editor
cd /d C:\Users\%USERNAME%\Documents\camera_workflows
echo off
mode 50,10
cls
start /B C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\bonsai\bonsai Camera_boxA.bonsai --no-editor
powershell -window minimized -command ""
timeout 5 > NUL
title CAMERA A
echo This window controls camera A
echo Close this window if camera A is whited out

12 changes: 10 additions & 2 deletions src/desktop_shortcuts/CameraB.bat
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
cd /d C:\Users\svc_aind_behavior\Documents\camera_workflows
start /min C:\Users\svc_aind_behavior\Documents\GitHub\dynamic-foraging-task\bonsai\bonsai Camera_boxB.bonsai --no-editor
cd /d C:\Users\%USERNAME%\Documents\camera_workflows
echo off
mode 50,10
cls
start /B C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\bonsai\bonsai Camera_boxB.bonsai --no-editor
powershell -window minimized -command ""
timeout 5 > NUL
title CAMERA B
echo This window controls camera B
echo Close this window if camera B is whited out

12 changes: 10 additions & 2 deletions src/desktop_shortcuts/CameraC.bat
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
cd /d C:\Users\svc_aind_behavior\Documents\camera_workflows
start /min C:\Users\svc_aind_behavior\Documents\GitHub\dynamic-foraging-task\bonsai\bonsai Camera_boxC.bonsai --no-editor
cd /d C:\Users\%USERNAME%\Documents\camera_workflows
echo off
mode 50,10
cls
start /B C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\bonsai\bonsai Camera_boxC.bonsai --no-editor
powershell -window minimized -command ""
timeout 5 > NUL
title CAMERA C
echo This window controls camera C
echo Close this window if camera C is whited out

12 changes: 10 additions & 2 deletions src/desktop_shortcuts/CameraD.bat
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
cd /d C:\Users\svc_aind_behavior\Documents\camera_workflows
start /min C:\Users\svc_aind_behavior\Documents\GitHub\dynamic-foraging-task\bonsai\bonsai Camera_boxD.bonsai --no-editor
cd /d C:\Users\%USERNAME%\Documents\camera_workflows
echo off
mode 50,10
cls
start /B C:\Users\%USERNAME%\Documents\GitHub\dynamic-foraging-task\bonsai\bonsai Camera_boxD.bonsai --no-editor
powershell -window minimized -command ""
timeout 5 > NUL
title CAMERA D
echo This window controls camera D
echo Close this window if camera D is whited out

46 changes: 24 additions & 22 deletions src/foraging_gui/Dialogs.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,8 @@ def _Laser(self,Numb):
ItemsRight=sorted(ItemsRight)
eval('self.LaserPowerLeft_'+str(Numb)+'.clear()')
eval('self.LaserPowerLeft_'+str(Numb)+'.addItems(ItemsLeft)')
eval('self.LaserPowerLeft_'+str(Numb)+'.clear()')
eval('self.LaserPowerLeft_'+str(Numb)+'.addItems(ItemsRight)')
eval('self.LaserPowerRight_'+str(Numb)+'.clear()')
eval('self.LaserPowerRight_'+str(Numb)+'.addItems(ItemsRight)')
self.MainWindow.WarningLabel.setText('')
self.MainWindow.WarningLabel.setStyleSheet("color: gray;")
else:
Expand Down Expand Up @@ -334,7 +334,7 @@ def __init__(self, MainWindow,parent=None):
self.MainWindow=MainWindow
self.FinishLeftValve=0
if not hasattr(self.MainWindow,'WaterCalibrationResults'):
self.MainWindow.LaserCalibrationResults={}
self.MainWindow.WaterCalibrationResults={}
self.WaterCalibrationResults={}
else:
self.WaterCalibrationResults=self.MainWindow.WaterCalibrationResults
Expand Down Expand Up @@ -1153,17 +1153,17 @@ def is_file_in_use(file_path):
except OSError as e:
return True

class ManipulatorDialog(QDialog):
def __init__(self, MainWindow, parent=None):
super().__init__(parent)
uic.loadUi('Manipulator.ui', self)
#class ManipulatorDialog(QDialog):
# def __init__(self, MainWindow, parent=None):
# super().__init__(parent)
# uic.loadUi('Manipulator.ui', self)

class MotorStageDialog(QDialog):
def __init__(self, MainWindow, parent=None):
super().__init__(parent)
uic.loadUi('MotorStage.ui', self)

self.MainWindow=MainWindow
#class MotorStageDialog(QDialog):
# def __init__(self, MainWindow, parent=None):
# super().__init__(parent)
# uic.loadUi('MotorStage.ui', self)
#
# self.MainWindow=MainWindow

class LaserCalibrationDialog(QDialog):
def __init__(self, MainWindow, parent=None):
Expand Down Expand Up @@ -1288,6 +1288,8 @@ def _GetLaserWaveForm(self):
self.CLP_InputVoltage=float(self.voltage.text())
# generate the waveform based on self.CLP_CurrentDuration and Protocol, Frequency, RampingDown, PulseDur
self._GetLaserAmplitude()
# send the trigger source. It's '/Dev1/PFI0' ( P2.0 of NIdaq USB6002) by default
self.MainWindow.Channel.TriggerSource('/Dev1/PFI0')
# dimension of self.CurrentLaserAmplitude indicates how many locations do we have
for i in range(len(self.CurrentLaserAmplitude)):
# in some cases the other paramters except the amplitude could also be different
Expand Down Expand Up @@ -1397,10 +1399,9 @@ def _GetTrainingParameters(self,win):
setattr(self, Prefix+'_'+child.objectName(), child.isChecked())
def _InitiateATrial(self):
'''Initiate calibration in bonsai'''
# send the trigger source. It's '/Dev1/PFI0' ( P2.0 of NIdaq USB6002) by default
self.MainWindow.Channel.TriggerSource('/Dev1/PFI0')
# start generating waveform in bonsai
self.MainWindow.Channel.OptogeneticsCalibration(int(1))
self.MainWindow.Channel.receive()
def _CopyFromOpto(self):
'''Copy the optogenetics parameters'''
N=[]
Expand Down Expand Up @@ -1696,7 +1697,6 @@ def _Open(self):
# change button color and disable the open button
self.Open.setEnabled(False)
self.Open.setStyleSheet("background-color : green;")
QApplication.processEvents()
self._GetTrainingParameters(self.MainWindow)
self._GetLaserWaveForm()
self.worker2 = Worker(self._Sleep,float(self.LC_Duration_1)+1)
Expand Down Expand Up @@ -1935,7 +1935,7 @@ def _connect_auto_training_manager(self):
except:
logger.error("AWS connection failed!")
QMessageBox.critical(self,
'Error',
'Box {}, Error'.format(self.MainWindow.box_letter),
f'AWS connection failed!\n'
f'Please check your AWS credentials at ~\.aws\credentials!')
return False
Expand Down Expand Up @@ -2009,7 +2009,8 @@ def _connect_curriculum_manager(self):
bucket='aind-behavior-data',
root='foraging_auto_training/saved_curriculums/'
),
saved_curriculums_local=self.MainWindow.default_saveFolder + '/curriculum_manager/',
# saved to tmp folder under user's home directory
saved_curriculums_local=os.path.expanduser('~/.aind_auto_train/curriculum_manager/')
)

def _show_available_curriculums(self):
Expand Down Expand Up @@ -2128,7 +2129,7 @@ def _update_stage_to_apply(self):
def _apply_curriculum(self):
# Check if a curriculum is selected
if not hasattr(self, 'selected_curriculum') or self.selected_curriculum is None:
QMessageBox.critical(self, "Error", "Please select a curriculum!")
QMessageBox.critical(self, "Box {}, Error".format(self.MainWindow.box_letter), "Please select a curriculum!")
return

# Always enable override stage
Expand Down Expand Up @@ -2174,11 +2175,11 @@ def _apply_curriculum(self):
if self.selected_curriculum['curriculum'] == self.curriculum_in_use:
# The selected curriculum is the same as the one in use
logger.info(f"Selected curriculum is the same as the one in use. No change is made.")
QMessageBox.information(self, "Info", "Selected curriculum is the same as the one in use. No change is made.")
QMessageBox.information(self, "Box {}, Info".format(self.MainWindow.box_letter), "Selected curriculum is the same as the one in use. No change is made.")
return
else:
# Confirm with the user about overriding the curriculum
reply = QMessageBox.question(self, "Confirm",
reply = QMessageBox.question(self, "Box {}, Confirm".format(self.MainWindow.box_letter),
f"Are you sure you want to override the curriculum?\n"
f"If yes, please also manually select a training stage.",
QMessageBox.Yes | QMessageBox.No,
Expand Down Expand Up @@ -2284,7 +2285,8 @@ def _set_training_parameters(self, paras_dict, if_press_enter=False):
task_ind = widget_task.findText(paras_dict['task'])
if task_ind < 0:
logger.error(f"Task {paras_dict['task']} not found!")
QMessageBox.critical(self, "Error", f'''Task "{paras_dict['task']}" not found. Check the curriculum!''')
QMessageBox.critical(self, "Box {}, Error".format(self.MainWindow.box_letter),
f'''Task "{paras_dict['task']}" not found. Check the curriculum!''')
return [] # Return an empty list without setting anything
else:
widget_task.setCurrentIndex(task_ind)
Expand Down
Loading

0 comments on commit ccd974c

Please sign in to comment.