np-workflows 1.6.89__py3-none-any.whl → 1.6.91__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. np_workflows/__init__.py +3 -5
  2. np_workflows/experiments/dynamic_routing/main.py +20 -41
  3. np_workflows/experiments/dynamic_routing/widgets.py +29 -24
  4. np_workflows/experiments/openscope_P3/P3_workflow_widget.py +11 -19
  5. np_workflows/experiments/openscope_P3/__init__.py +1 -1
  6. np_workflows/experiments/openscope_P3/main_P3_pilot.py +66 -68
  7. np_workflows/experiments/openscope_barcode/__init__.py +1 -1
  8. np_workflows/experiments/openscope_barcode/barcode_workflow_widget.py +14 -20
  9. np_workflows/experiments/openscope_barcode/camstim_scripts/barcode_mapping_script.py +8 -14
  10. np_workflows/experiments/openscope_barcode/camstim_scripts/barcode_opto_script.py +121 -68
  11. np_workflows/experiments/openscope_barcode/main_barcode_pilot.py +69 -69
  12. np_workflows/experiments/openscope_loop/__init__.py +1 -1
  13. np_workflows/experiments/openscope_loop/camstim_scripts/barcode_mapping_script.py +8 -14
  14. np_workflows/experiments/openscope_loop/camstim_scripts/barcode_opto_script.py +121 -68
  15. np_workflows/experiments/openscope_loop/loop_workflow_widget.py +11 -19
  16. np_workflows/experiments/openscope_loop/main_loop_pilot.py +66 -68
  17. np_workflows/experiments/openscope_psycode/__init__.py +1 -1
  18. np_workflows/experiments/openscope_psycode/main_psycode_pilot.py +69 -69
  19. np_workflows/experiments/openscope_psycode/psycode_workflow_widget.py +14 -20
  20. np_workflows/experiments/openscope_v2/__init__.py +1 -1
  21. np_workflows/experiments/openscope_v2/main_v2_pilot.py +66 -68
  22. np_workflows/experiments/openscope_v2/v2_workflow_widget.py +11 -19
  23. np_workflows/experiments/openscope_vippo/__init__.py +1 -1
  24. np_workflows/experiments/openscope_vippo/main_vippo_pilot.py +66 -68
  25. np_workflows/experiments/openscope_vippo/vippo_workflow_widget.py +14 -20
  26. np_workflows/experiments/task_trained_network/__init__.py +1 -1
  27. np_workflows/experiments/task_trained_network/camstim_scripts/make_tt_stims.py +24 -14
  28. np_workflows/experiments/task_trained_network/camstim_scripts/oct22_tt_stim_script.py +54 -41
  29. np_workflows/experiments/task_trained_network/camstim_scripts/ttn_main_script.py +19 -22
  30. np_workflows/experiments/task_trained_network/camstim_scripts/ttn_mapping_script.py +8 -14
  31. np_workflows/experiments/task_trained_network/camstim_scripts/ttn_opto_script.py +121 -68
  32. np_workflows/experiments/task_trained_network/main_ttn_pilot.py +73 -68
  33. np_workflows/experiments/task_trained_network/ttn_session_widget.py +11 -19
  34. np_workflows/experiments/task_trained_network/ttn_stim_config.py +23 -19
  35. np_workflows/experiments/templeton/main.py +18 -41
  36. np_workflows/experiments/templeton/widgets.py +26 -23
  37. np_workflows/shared/__init__.py +1 -1
  38. np_workflows/shared/base_experiments.py +430 -308
  39. np_workflows/shared/npxc.py +85 -53
  40. np_workflows/shared/widgets.py +374 -224
  41. {np_workflows-1.6.89.dist-info → np_workflows-1.6.91.dist-info}/METADATA +7 -21
  42. np_workflows-1.6.91.dist-info/RECORD +48 -0
  43. {np_workflows-1.6.89.dist-info → np_workflows-1.6.91.dist-info}/WHEEL +2 -1
  44. np_workflows-1.6.91.dist-info/entry_points.txt +2 -0
  45. np_workflows-1.6.91.dist-info/top_level.txt +1 -0
  46. np_workflows/assets/images/logo_np_hab.png +0 -0
  47. np_workflows/assets/images/logo_np_vis.png +0 -0
  48. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_00.stim +0 -5
  49. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_01.stim +0 -5
  50. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_02.stim +0 -5
  51. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_03.stim +0 -5
  52. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_04.stim +0 -5
  53. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_05.stim +0 -5
  54. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_06.stim +0 -5
  55. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_07.stim +0 -5
  56. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_08.stim +0 -5
  57. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_09.stim +0 -5
  58. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_10.stim +0 -5
  59. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_11.stim +0 -5
  60. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_12.stim +0 -5
  61. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_13.stim +0 -5
  62. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_14.stim +0 -5
  63. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_15.stim +0 -5
  64. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_16.stim +0 -5
  65. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_17.stim +0 -5
  66. np_workflows/experiments/task_trained_network/camstim_scripts/stims/densely_annotated_18.stim +0 -5
  67. np_workflows/experiments/task_trained_network/camstim_scripts/stims/flash_250ms.stim +0 -20
  68. np_workflows/experiments/task_trained_network/camstim_scripts/stims/gabor_20_deg_250ms.stim +0 -30
  69. np_workflows/experiments/task_trained_network/camstim_scripts/stims/old_stim.stim +0 -5
  70. np_workflows/experiments/task_trained_network/camstim_scripts/stims/shuffle_reversed.stim +0 -5
  71. np_workflows/experiments/task_trained_network/camstim_scripts/stims/shuffle_reversed_1st.stim +0 -5
  72. np_workflows/experiments/task_trained_network/camstim_scripts/stims/shuffle_reversed_2nd.stim +0 -5
  73. np_workflows/shared/camstim_scripts/flash_250ms.stim +0 -20
  74. np_workflows/shared/camstim_scripts/gabor_20_deg_250ms.stim +0 -30
  75. np_workflows-1.6.89.dist-info/RECORD +0 -76
  76. np_workflows-1.6.89.dist-info/entry_points.txt +0 -4
@@ -1,4 +1,3 @@
1
- # -*- coding: utf-8 -*-
2
1
  """
3
2
  optotagging.py
4
3
 
@@ -9,37 +8,30 @@ by joshs@alleninstitute.org
9
8
  (c) 2018 Allen Institute for Brain Science
10
9
 
11
10
  """
12
- import camstim # ensures "magic" gets setup properly by importing first
13
- import logging # must occur after camstim import for "magic"
14
- from camstim.zro import agent
15
-
16
- import numpy as np
17
- from toolbox.IO.nidaq import AnalogOutput
18
- from toolbox.IO.nidaq import DigitalOutput
19
11
 
20
12
  import datetime
21
- import numpy as np
22
- import time
13
+ import logging # must occur after camstim import for "magic"
23
14
  import pickle as pkl
15
+ import time
24
16
 
17
+ import numpy as np
18
+ from camstim.zro import agent
19
+ from toolbox.IO.nidaq import AnalogOutput, DigitalOutput
25
20
 
26
21
  # %%
27
22
 
28
23
 
29
- def run_optotagging(levels, conditions, waveforms, isis, sampleRate=10000.):
30
-
31
- from toolbox.IO.nidaq import AnalogOutput
32
- from toolbox.IO.nidaq import DigitalOutput
24
+ def run_optotagging(levels, conditions, waveforms, isis, sampleRate=10000.0):
33
25
 
34
26
  sweep_on = np.array([0, 0, 1, 0, 0, 0, 0, 0], dtype=np.uint8)
35
27
  stim_on = np.array([0, 0, 1, 1, 0, 0, 0, 0], dtype=np.uint8)
36
28
  stim_off = np.array([0, 0, 1, 0, 0, 0, 0, 0], dtype=np.uint8)
37
29
  sweep_off = np.array([0, 0, 0, 0, 0, 0, 0, 0], dtype=np.uint8)
38
30
 
39
- ao = AnalogOutput('Dev1', channels=[1])
31
+ ao = AnalogOutput("Dev1", channels=[1])
40
32
  ao.cfg_sample_clock(sampleRate)
41
33
 
42
- do = DigitalOutput('Dev1', 2)
34
+ do = DigitalOutput("Dev1", 2)
43
35
 
44
36
  do.start()
45
37
  ao.start()
@@ -62,71 +54,123 @@ def run_optotagging(levels, conditions, waveforms, isis, sampleRate=10000.):
62
54
  do.clear()
63
55
  ao.clear()
64
56
 
57
+
65
58
  # %%
66
59
 
67
60
 
68
- def generatePulseTrain(pulseWidth, pulseInterval, numRepeats, riseTime, sampleRate=10000.):
61
+ def generatePulseTrain(
62
+ pulseWidth, pulseInterval, numRepeats, riseTime, sampleRate=10000.0
63
+ ):
69
64
 
70
65
  data = np.zeros((int(sampleRate),), dtype=np.float64)
71
- # rise_samples =
66
+ # rise_samples =
72
67
 
73
68
  rise_and_fall = (
74
- ((1 - np.cos(np.arange(sampleRate*riseTime/1000., dtype=np.float64)*2*np.pi/10))+1)-1)/2
69
+ (
70
+ (
71
+ 1
72
+ - np.cos(
73
+ np.arange(sampleRate * riseTime / 1000.0, dtype=np.float64)
74
+ * 2
75
+ * np.pi
76
+ / 10
77
+ )
78
+ )
79
+ + 1
80
+ )
81
+ - 1
82
+ ) / 2
75
83
  half_length = rise_and_fall.size / 2
76
84
  rise = rise_and_fall[:half_length]
77
85
  fall = rise_and_fall[half_length:]
78
86
 
79
- peak_samples = int(sampleRate*(pulseWidth-riseTime*2)/1000)
87
+ peak_samples = int(sampleRate * (pulseWidth - riseTime * 2) / 1000)
80
88
  peak = np.ones((peak_samples,))
81
89
 
82
- pulse = np.concatenate((rise,
83
- peak,
84
- fall))
90
+ pulse = np.concatenate((rise, peak, fall))
85
91
 
86
- interval = int(pulseInterval*sampleRate/1000.)
92
+ interval = int(pulseInterval * sampleRate / 1000.0)
87
93
 
88
94
  for i in range(0, numRepeats):
89
- data[i*interval:i*interval+pulse.size] = pulse
95
+ data[i * interval : i * interval + pulse.size] = pulse
90
96
 
91
97
  return data
92
98
 
93
99
 
94
100
  # %% create waveforms
95
101
 
96
- def optotagging(mouseID, operation_mode='experiment', level_list=[1.15, 1.28, 1.345], genotype=None):
102
+
103
+ def optotagging(
104
+ mouseID, operation_mode="experiment", level_list=[1.15, 1.28, 1.345], genotype=None
105
+ ):
97
106
 
98
107
  sampleRate = 10000
99
108
 
100
109
  # 1 s cosine ramp:
101
- data_cosine = (((1 - np.cos(np.arange(sampleRate, dtype=np.float64)
102
- * 2*np.pi/sampleRate)) + 1) - 1)/2 # create raised cosine waveform
110
+ data_cosine = (
111
+ (
112
+ (
113
+ 1
114
+ - np.cos(
115
+ np.arange(sampleRate, dtype=np.float64) * 2 * np.pi / sampleRate
116
+ )
117
+ )
118
+ + 1
119
+ )
120
+ - 1
121
+ ) / 2 # create raised cosine waveform
103
122
 
104
123
  # 1 ms cosine ramp:
105
124
  rise_and_fall = (
106
- ((1 - np.cos(np.arange(sampleRate*0.001, dtype=np.float64)*2*np.pi/10))+1)-1)/2
125
+ (
126
+ (
127
+ 1
128
+ - np.cos(
129
+ np.arange(sampleRate * 0.001, dtype=np.float64) * 2 * np.pi / 10
130
+ )
131
+ )
132
+ + 1
133
+ )
134
+ - 1
135
+ ) / 2
107
136
  half_length = rise_and_fall.size / 2
108
137
 
109
138
  # pulses with cosine ramp:
110
- pulse_2ms = np.concatenate((rise_and_fall[:half_length], np.ones(
111
- (int(sampleRate*0.001),)), rise_and_fall[half_length:]))
112
- pulse_5ms = np.concatenate((rise_and_fall[:half_length], np.ones(
113
- (int(sampleRate*0.004),)), rise_and_fall[half_length:]))
114
- pulse_10ms = np.concatenate((rise_and_fall[:half_length], np.ones(
115
- (int(sampleRate*0.009),)), rise_and_fall[half_length:]))
139
+ pulse_2ms = np.concatenate(
140
+ (
141
+ rise_and_fall[:half_length],
142
+ np.ones((int(sampleRate * 0.001),)),
143
+ rise_and_fall[half_length:],
144
+ )
145
+ )
146
+ pulse_5ms = np.concatenate(
147
+ (
148
+ rise_and_fall[:half_length],
149
+ np.ones((int(sampleRate * 0.004),)),
150
+ rise_and_fall[half_length:],
151
+ )
152
+ )
153
+ pulse_10ms = np.concatenate(
154
+ (
155
+ rise_and_fall[:half_length],
156
+ np.ones((int(sampleRate * 0.009),)),
157
+ rise_and_fall[half_length:],
158
+ )
159
+ )
116
160
 
117
161
  data_2ms_10Hz = np.zeros((sampleRate,), dtype=np.float64)
118
162
 
119
163
  for i in range(0, 10):
120
164
  interval = sampleRate / 10
121
- data_2ms_10Hz[i*interval:i*interval+pulse_2ms.size] = pulse_2ms
165
+ data_2ms_10Hz[i * interval : i * interval + pulse_2ms.size] = pulse_2ms
122
166
 
123
167
  data_5ms = np.zeros((sampleRate,), dtype=np.float64)
124
- data_5ms[:pulse_5ms.size] = pulse_5ms
168
+ data_5ms[: pulse_5ms.size] = pulse_5ms
125
169
 
126
170
  data_10ms = np.zeros((sampleRate,), dtype=np.float64)
127
- data_10ms[:pulse_10ms.size] = pulse_10ms
171
+ data_10ms[: pulse_10ms.size] = pulse_10ms
128
172
 
129
- data_10s = np.zeros((sampleRate*10,), dtype=np.float64)
173
+ data_10s = np.zeros((sampleRate * 10,), dtype=np.float64)
130
174
  data_10s[:-2] = 1
131
175
 
132
176
  # %% for experiment
@@ -138,8 +182,8 @@ def optotagging(mouseID, operation_mode='experiment', level_list=[1.15, 1.28, 1.
138
182
  condition_list = [2, 3]
139
183
  waveforms = [data_2ms_10Hz, data_5ms, data_10ms, data_cosine]
140
184
 
141
- opto_levels = np.array(level_list*numRepeats*len(condition_list)) # BLUE
142
- opto_conditions = condition_list*numRepeats*len(level_list)
185
+ opto_levels = np.array(level_list * numRepeats * len(condition_list)) # BLUE
186
+ opto_conditions = condition_list * numRepeats * len(level_list)
143
187
  opto_conditions = np.sort(opto_conditions)
144
188
  opto_isis = np.random.random(opto_levels.shape) * isi_rand + isi
145
189
 
@@ -151,7 +195,7 @@ def optotagging(mouseID, operation_mode='experiment', level_list=[1.15, 1.28, 1.
151
195
 
152
196
  # %% for testing
153
197
 
154
- if operation_mode == 'test_levels':
198
+ if operation_mode == "test_levels":
155
199
  isi = 2.0
156
200
  isi_rand = 0.0
157
201
 
@@ -160,60 +204,69 @@ def optotagging(mouseID, operation_mode='experiment', level_list=[1.15, 1.28, 1.
160
204
  condition_list = [0]
161
205
  waveforms = [data_10s, data_10s]
162
206
 
163
- opto_levels = np.array(level_list*numRepeats *
164
- len(condition_list)) # BLUE
165
- opto_conditions = condition_list*numRepeats*len(level_list)
207
+ opto_levels = np.array(level_list * numRepeats * len(condition_list)) # BLUE
208
+ opto_conditions = condition_list * numRepeats * len(level_list)
166
209
  opto_conditions = np.sort(opto_conditions)
167
210
  opto_isis = np.random.random(opto_levels.shape) * isi_rand + isi
168
211
 
169
- elif operation_mode == 'pretest':
212
+ elif operation_mode == "pretest":
170
213
  numRepeats = 1
171
214
 
172
215
  condition_list = [0]
173
- data_2s = data_10s[-sampleRate*2:]
216
+ data_2s = data_10s[-sampleRate * 2 :]
174
217
  waveforms = [data_2s]
175
218
 
176
- opto_levels = np.array(level_list*numRepeats *
177
- len(condition_list)) # BLUE
178
- opto_conditions = condition_list*numRepeats*len(level_list)
219
+ opto_levels = np.array(level_list * numRepeats * len(condition_list)) # BLUE
220
+ opto_conditions = condition_list * numRepeats * len(level_list)
179
221
  opto_conditions = np.sort(opto_conditions)
180
- opto_isis = [1]*len(opto_conditions)
222
+ opto_isis = [1] * len(opto_conditions)
181
223
  # %%
182
224
 
183
225
  outputDirectory = agent.OUTPUT_DIR
184
- fileDate = str(datetime.datetime.now()).replace(':', '').replace(
185
- '.', '').replace('-', '').replace(' ', '')[2:14]
186
- fileName = outputDirectory + "/" + fileDate + '_'+mouseID + '.opto.pkl'
187
-
188
- print('saving info to: ' + fileName)
189
- fl = open(fileName, 'wb')
226
+ fileDate = (
227
+ str(datetime.datetime.now())
228
+ .replace(":", "")
229
+ .replace(".", "")
230
+ .replace("-", "")
231
+ .replace(" ", "")[2:14]
232
+ )
233
+ fileName = outputDirectory + "/" + fileDate + "_" + mouseID + ".opto.pkl"
234
+
235
+ print("saving info to: " + fileName)
236
+ fl = open(fileName, "wb")
190
237
  output = {}
191
238
 
192
- output['opto_levels'] = opto_levels
193
- output['opto_conditions'] = opto_conditions
194
- output['opto_ISIs'] = opto_isis
195
- output['opto_waveforms'] = waveforms
239
+ output["opto_levels"] = opto_levels
240
+ output["opto_conditions"] = opto_conditions
241
+ output["opto_ISIs"] = opto_isis
242
+ output["opto_waveforms"] = waveforms
196
243
 
197
244
  pkl.dump(output, fl)
198
245
  fl.close()
199
- print('saved.')
246
+ print("saved.")
200
247
 
201
248
  # %%
202
- run_optotagging(opto_levels, opto_conditions,
203
- waveforms, opto_isis, float(sampleRate))
249
+ run_optotagging(
250
+ opto_levels, opto_conditions, waveforms, opto_isis, float(sampleRate)
251
+ )
204
252
 
205
253
 
206
254
  # %%
207
255
  if __name__ == "__main__":
208
- import json
209
256
  import argparse
257
+ import json
210
258
 
211
259
  parser = argparse.ArgumentParser()
212
- parser.add_argument('json_params', type=str, )
260
+ parser.add_argument(
261
+ "json_params",
262
+ type=str,
263
+ )
213
264
  args, _ = parser.parse_known_args()
214
265
 
215
- with open(args.json_params, 'r', ) as f:
266
+ with open(
267
+ args.json_params,
268
+ ) as f:
216
269
  json_params = json.load(f)
217
270
 
218
- logging.info('Optotagging with params: %s' % json_params)
271
+ logging.info("Optotagging with params: %s" % json_params)
219
272
  optotagging(**json_params)
@@ -1,17 +1,6 @@
1
- import configparser
2
- import contextlib
3
- import copy
4
- import enum
5
- import functools
6
- from typing import ClassVar, Literal, NamedTuple, NoReturn, Optional, TypedDict
7
-
8
1
  import IPython.display
9
2
  import ipywidgets as ipw
10
- import np_config
11
- import np_logging
12
3
  import np_session
13
- import np_workflows
14
- from pyparsing import Any
15
4
 
16
5
  from np_workflows.experiments.openscope_loop.main_loop_pilot import LoopSession
17
6
 
@@ -20,6 +9,7 @@ global_state = {}
20
9
 
21
10
  # for widget, before creating a experiment --------------------------------------------- #
22
11
 
12
+
23
13
  class SelectedSession:
24
14
  def __init__(self, session: str | LoopSession, mouse: str | int | np_session.Mouse):
25
15
  if isinstance(session, str):
@@ -48,17 +38,19 @@ def loop_workflow_widget(
48
38
  options=tuple(_.value for _ in LoopSession),
49
39
  description="Session",
50
40
  )
51
-
41
+
52
42
  def update_selection():
53
43
  selection.__init__(str(session_dropdown.value), str(mouse))
54
-
55
- if (previously_selected_value := global_state.get('selected_session')):
44
+
45
+ if previously_selected_value := global_state.get("selected_session"):
56
46
  session_dropdown.value = previously_selected_value
57
47
  update_selection()
58
-
48
+
59
49
  console = ipw.Output()
60
50
  with console:
61
- if last_session := np_session.Mouse(selection.mouse).state.get('last_loop_session'):
51
+ if last_session := np_session.Mouse(selection.mouse).state.get(
52
+ "last_loop_session"
53
+ ):
62
54
  print(f"{mouse} last session: {last_session}")
63
55
  print(f"Selected: {selection.session}")
64
56
 
@@ -74,9 +66,9 @@ def loop_workflow_widget(
74
66
  update_selection()
75
67
  with console:
76
68
  print(f"Selected: {selection.session}")
77
- global_state['selected_session'] = selection.session.value
78
-
79
- session_dropdown.observe(update, names='value')
69
+ global_state["selected_session"] = selection.session.value
70
+
71
+ session_dropdown.observe(update, names="value")
80
72
 
81
73
  IPython.display.display(ipw.VBox([session_dropdown, console]))
82
74
 
@@ -1,41 +1,22 @@
1
- import configparser
2
1
  import contextlib
3
- import copy
4
- import dataclasses
5
- import datetime
6
2
  import enum
7
- import functools
8
- import pathlib
9
- import platform
10
- import shutil
11
- import threading
12
3
  import time
13
- import zlib
14
- from typing import ClassVar, Literal, NamedTuple, NoReturn, Optional, TypedDict
15
4
 
16
- import IPython
17
- import IPython.display
18
- import ipywidgets as ipw
19
- import np_config
20
5
  import np_logging
21
- import np_services
22
6
  import np_session
23
- import np_workflows
24
- import PIL.Image
25
- import pydantic
26
- from pyparsing import Any
27
7
  from np_services import (
28
- Service,
29
8
  Finalizable,
30
- ScriptCamstim, SessionCamstim,
31
- SessionCamstim,
9
+ MouseDirector,
10
+ NewScaleCoordinateRecorder,
32
11
  OpenEphys,
12
+ Service,
13
+ SessionCamstim,
33
14
  Sync,
34
15
  VideoMVR,
35
- NewScaleCoordinateRecorder,
36
- MouseDirector,
37
16
  )
38
17
 
18
+ import np_workflows
19
+
39
20
  logger = np_logging.getLogger(__name__)
40
21
 
41
22
 
@@ -49,16 +30,16 @@ class LoopSession(enum.Enum):
49
30
 
50
31
  class LoopMixin:
51
32
  """Provides project-specific methods and attributes, mainly related to camstim scripts."""
52
-
33
+
53
34
  workflow: LoopSession
54
35
  """Enum for particular workflow/session, e.g. PRETEST, HAB_60, HAB_90,
55
36
  EPHYS."""
56
-
37
+
57
38
  session: np_session.PipelineSession
58
39
  mouse: np_session.Mouse
59
40
  user: np_session.User
60
41
  platform_json: np_session.PlatformJson
61
-
42
+
62
43
  @property
63
44
  def recorders(self) -> tuple[Service, ...]:
64
45
  """Services to be started before stimuli run, and stopped after. Session-dependent."""
@@ -70,11 +51,11 @@ class LoopMixin:
70
51
 
71
52
  @property
72
53
  def stims(self) -> tuple[Service, ...]:
73
- return (SessionCamstim, )
74
-
54
+ return (SessionCamstim,)
55
+
75
56
  def initialize_and_test_services(self) -> None:
76
57
  """Configure, initialize (ie. reset), then test all services."""
77
-
58
+
78
59
  MouseDirector.user = self.user.id
79
60
  MouseDirector.mouse = self.mouse.id
80
61
 
@@ -92,79 +73,95 @@ class LoopMixin:
92
73
 
93
74
  def update_state(self) -> None:
94
75
  "Store useful but non-essential info."
95
- self.mouse.state['last_session'] = self.session.id
96
- self.mouse.state['last_Loop_session'] = str(self.workflow)
76
+ self.mouse.state["last_session"] = self.session.id
77
+ self.mouse.state["last_Loop_session"] = str(self.workflow)
97
78
  if self.mouse == 366122:
98
79
  return
99
80
  match self.workflow:
100
81
  case LoopSession.PRETEST:
101
82
  return
102
83
  case LoopSession.HAB:
103
- self.session.project.state['latest_hab'] = self.session.id
84
+ self.session.project.state["latest_hab"] = self.session.id
104
85
  case LoopSession.EPHYS:
105
- self.session.project.state['latest_ephys'] = self.session.id
106
- self.session.project.state['sessions'] = self.session.project.state.get('sessions', []) + [self.session.id]
107
-
86
+ self.session.project.state["latest_ephys"] = self.session.id
87
+ self.session.project.state["sessions"] = self.session.project.state.get(
88
+ "sessions", []
89
+ ) + [self.session.id]
90
+
108
91
  def run_stim(self) -> None:
109
92
 
110
93
  self.update_state()
111
-
94
+
112
95
  if not SessionCamstim.is_ready_to_start():
113
96
  raise RuntimeError("SessionCamstim is not ready to start.")
114
-
115
- np_logging.web(f'Loop_{self.workflow.name.lower()}').info(f"Started session {self.mouse.mtrain.stage['name']}")
97
+
98
+ np_logging.web(f"Loop_{self.workflow.name.lower()}").info(
99
+ f"Started session {self.mouse.mtrain.stage['name']}"
100
+ )
116
101
  SessionCamstim.start()
117
-
102
+
118
103
  with contextlib.suppress(Exception):
119
104
  while not SessionCamstim.is_ready_to_start():
120
105
  time.sleep(2.5)
121
-
106
+
122
107
  if isinstance(SessionCamstim, Finalizable):
123
108
  SessionCamstim.finalize()
124
109
 
125
110
  with contextlib.suppress(Exception):
126
- np_logging.web(f'Loop_{self.workflow.name.lower()}').info(f"Finished session {self.mouse.mtrain.stage['name']}")
127
-
128
-
129
- def copy_data_files(self) -> None:
111
+ np_logging.web(f"Loop_{self.workflow.name.lower()}").info(
112
+ f"Finished session {self.mouse.mtrain.stage['name']}"
113
+ )
114
+
115
+ def copy_data_files(self) -> None:
130
116
  super().copy_data_files()
131
-
117
+
132
118
  # When all processing completes, camstim Agent class passes data and uuid to
133
119
  # /camstim/lims BehaviorSession class, and write_behavior_data() writes a
134
120
  # final .pkl with default name YYYYMMDDSSSS_mouseID_foragingID.pkl
135
121
  # - if we have a foraging ID, we can search for that
136
- if None == (stim_pkl := next(self.session.npexp_path.glob(f'{self.session.date:%y%m%d}*_{self.session.mouse}_*.pkl'), None)):
137
- logger.warning('Did not find stim file on npexp matching the format `YYYYMMDDSSSS_mouseID_foragingID.pkl`')
122
+ if None == (
123
+ stim_pkl := next(
124
+ self.session.npexp_path.glob(
125
+ f"{self.session.date:%y%m%d}*_{self.session.mouse}_*.pkl"
126
+ ),
127
+ None,
128
+ )
129
+ ):
130
+ logger.warning(
131
+ "Did not find stim file on npexp matching the format `YYYYMMDDSSSS_mouseID_foragingID.pkl`"
132
+ )
138
133
  return
139
134
  assert stim_pkl
140
135
  if not self.session.platform_json.foraging_id:
141
- self.session.platform_json.foraging_id = stim_pkl.stem.split('_')[-1]
142
- new_stem = f'{self.session.folder}.stim'
143
- logger.debug(f'Renaming stim file copied to npexp: {stim_pkl} -> {new_stem}')
136
+ self.session.platform_json.foraging_id = stim_pkl.stem.split("_")[-1]
137
+ new_stem = f"{self.session.folder}.stim"
138
+ logger.debug(f"Renaming stim file copied to npexp: {stim_pkl} -> {new_stem}")
144
139
  stim_pkl = stim_pkl.rename(stim_pkl.with_stem(new_stem))
145
-
140
+
146
141
  # remove other stim pkl, which is nearly identical, if it was also copied
147
- for pkl in self.session.npexp_path.glob('*.pkl'):
142
+ for pkl in self.session.npexp_path.glob("*.pkl"):
148
143
  if (
149
144
  self.session.folder not in pkl.stem
150
- and
151
- abs(pkl.stat().st_size - stim_pkl.stat().st_size) < 1e6
145
+ and abs(pkl.stat().st_size - stim_pkl.stat().st_size) < 1e6
152
146
  ):
153
- logger.debug(f'Deleting extra stim pkl copied to npexp: {pkl.stem}')
147
+ logger.debug(f"Deleting extra stim pkl copied to npexp: {pkl.stem}")
154
148
  pkl.unlink()
155
-
156
-
149
+
150
+
157
151
  def validate_selected_workflow(session: LoopSession, mouse: np_session.Mouse) -> None:
158
- for workflow in ('hab', 'ephys'):
152
+ for workflow in ("hab", "ephys"):
159
153
  if (
160
154
  workflow in session.value.lower()
161
- and workflow not in mouse.mtrain.stage['name'].lower()
155
+ and workflow not in mouse.mtrain.stage["name"].lower()
162
156
  ) or (
163
- session.value.lower() == 'ephys' and 'hab' in mouse.mtrain.stage['name'].lower()
157
+ session.value.lower() == "ephys"
158
+ and "hab" in mouse.mtrain.stage["name"].lower()
164
159
  ):
165
- raise ValueError(f"Workflow selected ({session.value}) does not match MTrain stage ({mouse.mtrain.stage['name']}): please check cells above.")
160
+ raise ValueError(
161
+ f"Workflow selected ({session.value}) does not match MTrain stage ({mouse.mtrain.stage['name']}): please check cells above."
162
+ )
163
+
166
164
 
167
-
168
165
  class Hab(LoopMixin, np_workflows.PipelineHab):
169
166
  def __init__(self, *args, **kwargs):
170
167
  self.services = (
@@ -209,9 +206,10 @@ def new_experiment(
209
206
  case _:
210
207
  raise ValueError(f"Invalid workflow type: {workflow}")
211
208
  experiment.workflow = workflow
212
-
209
+
213
210
  with contextlib.suppress(Exception):
214
- np_logging.web(f'Loop_{experiment.workflow.name.lower()}').info(f"{experiment} created")
215
-
216
- return experiment
211
+ np_logging.web(f"Loop_{experiment.workflow.name.lower()}").info(
212
+ f"{experiment} created"
213
+ )
217
214
 
215
+ return experiment
@@ -1,2 +1,2 @@
1
- from .main_psycode_pilot import new_experiment, Hab, Ephys, validate_selected_workflow
1
+ from .main_psycode_pilot import Ephys, Hab, new_experiment, validate_selected_workflow
2
2
  from .psycode_workflow_widget import PsyCode_workflow_widget