Command Line Interfaces

This module provides click-based Command-Line Interface (CLI) scripts that allow accessing all user-facing features from this library through the terminal.

sl-crc

Calculates the CRC32-XFER checksum for the input string.

sl-crc [OPTIONS]

Options

-i, --string <string>

The string to calculate the CRC checksum for.

sl-devices

Displays information about all Zaber devices available through USB ports of the host-system.

sl-devices [OPTIONS]

Options

-e, --errors

Determines whether to display errors encountered when connecting to all evaluated serial ports.

Default:

False

sl-maintain-vr

Exposes a terminal interface to interact with the water delivery solenoid valve and the running wheel break.

This CLI command is primarily designed to fill, empty, check, and, if necessary, recalibrate the solenoid valve used to deliver water to animals during training and experiment runtimes. Also, it is capable of locking or unlocking the wheel breaks, which is helpful when cleaning the wheel (after each session) and maintaining the wrap around the wheel surface (weekly to monthly).

The interface also contains Zaber motors (HeadBar and LickPort) bindings to facilitate testing the quality of implanted cranial windows before running training sessions for new animals.

sl-maintain-vr [OPTIONS]

Options

-p, --project <project>

Required The name of the project whose configuration data should be used during VR maintenance. If the maintenance runtime is used to save Zaber snapshots for new animals, the project also determines where the snapshots are saved.

sl-lick-train

Runs the lick training session for the specified animal and project combination.

Lick training is the first phase of preparing the animal to run experiment runtimes in the lab, and is usually carried out over the first two days of head-fixed training. Primarily, this training is designed to teach the animal to operate the lick-port and associate licking at the port with water delivery.

sl-lick-train [OPTIONS]

Options

-u, --user <user>

Required The ID of the user supervising the training session.

-p, --project <project>

Required The name of the project to which the trained animal belongs.

-a, --animal <animal>

Required The ID of the animal undergoing the lick training session.

-w, --animal_weight <animal_weight>

Required The weight of the animal, in grams, at the beginning of the training session.

-min, --minimum_delay <minimum_delay>

The minimum number of seconds that has to pass between two consecutive reward deliveries during training.

Default:

6

-max, --maximum_delay <maximum_delay>

The maximum number of seconds that can pass between two consecutive reward deliveries during training.

Default:

18

-v, --maximum_volume <maximum_volume>

The maximum volume of water, in milliliters, that can be delivered during training.

Default:

1.0

-t, --maximum_time <maximum_time>

The maximum time to run the training, in minutes.

Default:

20

sl-run-train

Runs the run training session for the specified animal and project combination.

Run training is the second phase of preparing the animal to run experiment runtimes in the lab, and is usually carried out over the five days following the lick training sessions. Primarily, this training is designed to teach the anima how to run the wheel treadmill while being head-fixed and associate getting water rewards with running on the treadmill. Over the course of training, the task requirements are adjusted to ensure the animal performs as many laps as possible during experiment sessions lasting ~60 minutes.

sl-run-train [OPTIONS]

Options

-u, --user <user>

Required The ID of the user supervising the training session.

-p, --project <project>

Required The name of the project to which the trained animal belongs.

-a, --animal <animal>

Required The name of the animal undergoing the run training session.

-w, --animal_weight <animal_weight>

Required The weight of the animal, in grams, at the beginning of the training session.

-is, --initial_speed <initial_speed>

The initial speed, in centimeters per second, the animal must maintain to obtain water rewards.

Default:

0.4

-id, --initial_duration <initial_duration>

The initial duration, in seconds, the animal must maintain above-threshold running speed to obtain water rewards.

Default:

0.4

-it, --increase_threshold <increase_threshold>

The volume of water delivered to the animal, in milliliters, after which the speed and duration thresholds are increased by the specified step-sizes. This is used to make the training progressively harder for the animal over the course of the training session.

Default:

0.1

-ss, --speed_step <speed_step>

The amount, in centimeters per second, to increase the speed threshold each time the animal receives the volume of water specified by the ‘increase-threshold’ parameter.

Default:

0.05

-ds, --duration_step <duration_step>

The amount, in seconds, to increase the duration threshold each time the animal receives the volume of water specified by the ‘increase-threshold’ parameter.

Default:

0.05

-v, --maximum_volume <maximum_volume>

The maximum volume of water, in milliliters, that can be delivered during training.

Default:

1.0

-t, --maximum_time <maximum_time>

The maximum time to run the training, in minutes.

Default:

20

sl-experiment

Runs the requested experiment session for the specified animal and project combination.

Experiment runtimes are carried out after the lick and run training sessions. Unlike training runtimes, experiment runtimes use the Virtual Reality (VR) system and rely on Unity game engine to resolve the experiment task logic during runtime. Also, experiments use the Mesoscope to acquire the brain activity data, which is mostly handled by the ScanImage software.

Unlike training CLIs, this CLI can be used to run a variety of experiments. Each experiment is configured via the user-written configuration .yaml file, which should be stored inside the ‘configuration’ folder of the target project. The experiments are discovered by name, allowing a single project to have multiple different experiments.

sl-experiment [OPTIONS]

Options

-u, --user <user>

Required The ID of the user supervising the experiment session.

-p, --project <project>

Required The name of the project to which the trained animal belongs.

-e, --experiment <experiment>

Required The name of the experiment to carry out during runtime.

-a, --animal <animal>

Required The name of the animal undergoing the experiment session.

-w, --animal_weight <animal_weight>

Required The weight of the animal, in grams, at the beginning of the experiment session.

sl-experiment

Preprocesses the target session’s data.

This command aggregates all session data on the VRPC, compresses the data to optimize it for network transmission and storage, and transfers the data to the NAS and the BioHPC cluster. It automatically skips already completed processing stages as necessary to optimize runtime performance.

Primarily, this command is intended to retry or resume failed or interrupted preprocessing runtimes. Preprocessing should be carried out immediately after data acquisition to optimize the acquired data for long-term storage and distribute it to the NAS and the BioHPC cluster for further processing and storage.

sl-experiment [OPTIONS]

Options

-s, --session-path <session_path>

Required The path to the session directory to preprocess.

sl-experiment

Depending on configuration, removes all redundant data directories for ALL projects from the ScanImagePC, VRPC, or both.

This command should be used at least weekly to remove no longer necessary data from the PCs used during data acquisition. Unless this function is called, our preprocessing pipelines will NOT remove the data, eventually leading to both PCs running out of storage space. Note, despite the command taking in a project name, it removes redundant data for all projects stored in the same root folder as the target project.

sl-experiment [OPTIONS]

Options

-p, --project <project>

Required The name of the project for which to purge the redundant data.

-u, --remove_ubiquitin

Determines whether to remove ubiquitin-marked mesoscope_frames directories from the ScanImagePC.

Default:

False

-t, --remove_telomere

Determines whether to remove raw_data directories from the VRPC if their counterparts on the BioHPC server contain telomere markers.

Default:

False

sl-experiment

Replaces the current local project root directory with the specified directory.

To ensure all projects are saved in the same location, this library statically resolves and saves the path to the root directory in default user directory. Since this directory is typically hidden, this CLI can be used to conveniently replace the local directory path, if necessary.

sl-experiment [OPTIONS]

Options

-p, --path <path>

Required The path to the new local directory where to store all project subdirectories.

Experiment Interfaces

This module provides classes that abstract working with Sun lab’s Mesoscope-VR system to acquire training or experiment data. Primarily, this includes the runtime management classes (highest level of internal data acquisition and processing API) and specialized runtime logic functions (user-facing external API functions).

class sl_experiment.experiment._BehaviorTraining(project_configuration, session_data, session_descriptor)

Bases: object

The base class for all behavior training runtimes.

This class provides methods for running the lick and run training sessions using a subset of the Mesoscope-VR system. It abstracts most low-level interactions with the VR system and the mesoscope via a simple high-level state API.

Notes

Calling this initializer does not start the Mesoscope-VR components. Use the start() method before issuing other commands to properly initialize all remote processes.

Parameters:
  • project_configuration (ProjectConfiguration) – An initialized ProjectConfiguration instance that specifies the runtime parameters to use for this experiment session. This is used internally to initialize all other Mesoscope-VR assets.

  • session_data (SessionData) – An initialized SessionData instance used to control the flow of data during acquisition and preprocessing. Each instance is initialized for the specific project, animal, and session combination for which the data is acquired.

  • session_descriptor (LickTrainingDescriptor | RunTrainingDescriptor) – A partially configured LickTrainingDescriptor or RunTrainingDescriptor instance. This instance is used to store session-specific information in a human-readable format.

_started

Tracks whether the VR system and training runtime are currently running.

_lick_training

Tracks the training state used by the instance, which is required for log parsing.

descriptor

Stores the session descriptor instance.

_session_data

Stores the SessionData instance.

_logger

A DataLogger instance that collects behavior log data from all sources: microcontrollers and video cameras.

_microcontrollers

Stores the MicroControllerInterfaces instance that interfaces with all MicroController devices used during runtime.

_cameras

Stores the VideoSystems instance that interfaces with video systems (cameras) used during runtime.

HeadBar

Stores the HeadBar class instance that interfaces with all HeadBar manipulator motors.

LickPort

Stores the LickPort class instance that interfaces with all LickPort manipulator motors.

deliver_reward(reward_size=5.0)

Uses the solenoid valve to deliver the requested volume of water in microliters.

This method is used by the training runtimes to reward the animal with water as part of the training process.

Return type:

None

lick_train_state()

Configures the VR system for running the lick training.

In the rest state, the break is engaged to prevent the mouse from moving the wheel. The encoder module is disabled, and the torque sensor is enabled. The VR screens are switched off, cutting off light emission. The lick sensor monitoring is on to record animal licking data.

Return type:

None

run_train_state()

Configures the VR system for running the run training.

In the rest state, the break is disengaged, allowing the mouse to run on the wheel. The encoder module is enabled, and the torque sensor is disabled. The VR screens are switched off, cutting off light emission. The lick sensor monitoring is on to record animal licking data.

Return type:

None

start()

Sets up all assets used during the training.

This internal method establishes the communication with the microcontrollers, data logger cores, and video system processes.

Return type:

None

Notes

This method will not run unless the host PC has access to the necessary number of logical CPU cores and other required hardware resources (GPU for video encoding, etc.). This prevents using the class on machines that are unlikely to sustain the runtime requirements.

As part of its runtime, this method will attempt to set Zaber motors for the HeadBar and LickPort to the positions that would typically be used during the mesoscope experiment runtime. Exercise caution and always monitor the system when it is running this method, as unexpected motor behavior can damage the mesoscope or harm the animal.

Unlike the experiment class start(), this method does not preset the hardware module states during runtime. Call the desired training state method to configure the hardware modules appropriately for the chosen runtime mode.

Raises:

RuntimeError – If the host PC does not have enough logical CPU cores available.

stop()

Stops and terminates the BehaviorTraining runtime.

This method achieves two main purposes. First, releases the hardware resources used during the training runtime by various system components. Second, it runs the preprocessing pipeline on the data to prepare it for long-term storage and further processing.

Return type:

None

property trackers: tuple[SharedMemoryArray, SharedMemoryArray, SharedMemoryArray]

Returns the tracker SharedMemoryArrays for (in this order) the LickInterface, ValveInterface, and EncoderInterface.

These arrays should be passed to the BehaviorVisualizer class to monitor the lick, valve and running speed data in real time during training.

class sl_experiment.experiment._KeyboardListener

Bases: object

Monitors the keyboard input for various runtime control signals and changes internal flags to communicate detected signals.

This class is used during all training runtimes to allow the user to manually control various aspects of the Mesoscope-VR system and runtime. For example, it is used to abort the runtime early by gracefully stopping all runtime assets and running data preprocessing.

Notes

This monitor may pick up keyboard strokes directed at other applications during runtime. While our unique key combinations are likely not used elsewhere, exercise caution when using other applications alongside the runtime code.

The monitor runs in a separate process (on a separate core) and sends the data to the main process via shared memory arrays. This prevents the listener from competing for resources with the runtime logic and the visualizer class.

_data_array

A SharedMemoryArray used to store the data recorded by the remote listener process.

_currently_pressed

Stores the keys that are currently being pressed.

_keyboard_process

The Listener instance used to monitor keyboard strokes. The listener runs in a remote process.

_started

A static flag used to prevent the __del__ method from shutting down an already terminated instance.

__del__()

Ensures all class resources are released before the instance is destroyed.

This is a fallback method, using shutdown() should be standard.

Return type:

None

_on_press(key)

Adds newly pressed keys to the storage set and determines whether the pressed key combination matches the shutdown combination.

This method is used as the ‘on_press’ callback for the Listener instance.

Return type:

None

_on_release(key)

Removes no longer pressed keys from the storage set.

This method is used as the ‘on_release’ callback for the Listener instance.

Return type:

None

_run_keyboard_listener()

The main function that runs in the parallel process to monitor keyboard inputs.

Return type:

None

property duration_modifier: int

Returns the current user-defined modifier to apply to the running epoch duration threshold.

This is used during run training to manually update the running epoch duration threshold.

property exit_signal: bool

Returns True if the listener has detected the runtime abort keys combination (ESC + q) being pressed.

This indicates that the user has requested the runtime to gracefully abort.

property reward_signal: bool

Returns True if the listener has detected the water reward delivery keys combination (ESC + r) being pressed.

This indicates that the user has requested the system to deliver 5uL water reward.

Notes

Each time this property is accessed, the flag is reset to 0.

shutdown()

This method should be called at the end of runtime to properly release all resources and terminate the remote process.

Return type:

None

property speed_modifier: int

Returns the current user-defined modifier to apply to the running speed threshold.

This is used during run training to manually update the running speed threshold.

class sl_experiment.experiment._MesoscopeExperiment(project_configuration, experiment_configuration, session_data, session_descriptor)

Bases: object

The base class for all mesoscope experiment runtimes.

This class provides methods for conducting experiments using the Mesoscope-VR system. It abstracts most low-level interactions with the VR system and the mesoscope via a simple high-level state API.

Notes

Calling this initializer does not initialize all Mesoscope-VR assets. Use the start() method before issuing other commands to properly initialize all remote processes.

This class statically reserves the id code ‘1’ to label its log entries. Make sure no other Ataraxis class, such as MicroControllerInterface or VideoSystem, uses this id code.

Parameters:
  • project_configuration (ProjectConfiguration) – An initialized ProjectConfiguration instance that specifies the runtime parameters to use for this experiment session. This is used internally to initialize all other Mesoscope-VR assets.

  • experiment_configuration (ExperimentConfiguration) – An initialized ExperimentConfiguration instance that specifies experiment-related parameters used during this session’s runtime. Primarily, this instance is used to extract the VR cue to distance map and to save the experiment configuration to the output directory at runtime initialization.

  • session_data (SessionData) – An initialized SessionData instance used to control the flow of data during acquisition and preprocessing. Each instance is initialized for the specific project, animal, and session combination for which the data is acquired.

  • session_descriptor (MesoscopeExperimentDescriptor) – A partially configured MesoscopeExperimentDescriptor instance. This instance is used to store session-specific information in a human-readable format.

_started

Tracks whether the VR system and experiment runtime are currently running.

descriptor

Stores the session descriptor instance.

_session_data

Stores the SessionData instance.

_experiment_configuration

Stores the ExperimentConfiguration instance.

_logger

A DataLogger instance that collects behavior log data from all sources: microcontrollers, video cameras, and the MesoscopeExperiment instance.

_microcontrollers

Stores the MicroControllerInterfaces instance that interfaces with all MicroController devices used during runtime.

_cameras

Stores the VideoSystems instance that interfaces with video systems (cameras) used during runtime.

HeadBar

Stores the HeadBar class instance that interfaces with all HeadBar manipulator motors.

LickPort

Stores the LickPort class instance that interfaces with all LickPort manipulator motors.

_vr_state

Stores the current state of the VR system. The MesoscopeExperiment updates this value whenever it is instructed to change the VR system state.

_state_map

Maps the integer state-codes used to represent VR system states to human-readable string-names.

_experiment_state

Stores the user-defined experiment state. Experiment states are defined by the user and are expected to be unique for each project and, potentially, experiment. Different experiment states can reuse the same VR state.

_timestamp_timer

A PrecisionTimer instance used to timestamp log entries generated by the class instance.

_source_id

Stores the unique identifier code for this class instance. The identifier is used to mark log entries made by this class instance and has to be unique across all sources that log data at the same time, such as MicroControllerInterfaces and VideoSystems.

_change_vr_state(new_state)

Updates and logs the new VR state.

This method is used internally to timestamp and log VR state (stage) changes, such as transitioning between rest and run VR states.

Parameters:

new_state (int) – The byte-code for the newly activated VR state.

Return type:

None

_get_cue_sequence()

Requests Unity game engine to transmit the sequence of virtual reality track wall cues for the current task.

This method is used as part of the experimental runtime startup process to both get the sequence of cues and verify that the Unity game engine is running and configured correctly.

Return type:

ndarray[Any, dtype[uint8]]

Returns:

The NumPy array that stores the sequence of virtual reality segments as byte (uint8) values.

Raises:

RuntimeError – If no response from Unity is received within 2 seconds or if Unity sends a message to an unexpected (different) topic other than “CueSequence/” while this method is running.

_start_mesoscope()

Sends the frame acquisition start TTL pulse to the mesoscope and waits for the frame acquisition to begin.

This method is used internally to start the mesoscope frame acquisition as part of the experiment startup process. It is also used to verify that the mesoscope is available and properly configured to acquire frames based on the input triggers.

Raises:

RuntimeError – If the mesoscope does not confirm frame acquisition within 2 seconds after the acquisition trigger is sent.

Return type:

None

change_experiment_state(new_state)

Updates and logs the new experiment state.

Use this method to timestamp and log experiment state (stage) changes, such as transitioning between different task goals.

Parameters:

new_state (int) – The integer byte-code for the new experiment state. The code will be serialized as an uint8 value, so only values between 0 and 255 inclusive are supported.

Return type:

None

start()

Sets up all assets used during the experiment.

This internal method establishes the communication with the microcontrollers, data logger cores, and video system processes. It also requests the cue sequence from Unity game engine and starts mesoscope frame acquisition process.

Return type:

None

Notes

This method will not run unless the host PC has access to the necessary number of logical CPU cores and other required hardware resources (GPU for video encoding, etc.). This prevents using the class on machines that are unlikely to sustain the runtime requirements.

As part of its runtime, this method will attempt to set Zaber motors for the HeadBar and LickPort to the positions optimal for mesoscope frame acquisition. Exercise caution and always monitor the system when it is running this method, as unexpected motor behavior can damage the mesoscope or harm the animal.

Raises:

RuntimeError – If the host PC does not have enough logical CPU cores available.

stop()

Stops and terminates the MesoscopeExperiment runtime.

This method achieves two main purposes. First, releases the hardware resources used during the experiment runtime by various system components. Second, it pulls all collected data to the VRPC and runs the preprocessing pipeline on the data to prepare it for long-term storage and further processing.

Return type:

None

property trackers: tuple[SharedMemoryArray, SharedMemoryArray, SharedMemoryArray]

Returns the tracker SharedMemoryArrays for (in this order) the LickInterface, ValveInterface, and EncoderInterface.

These arrays should be passed to the BehaviorVisualizer class to monitor the lick, valve and running speed data in real time during the experiment session.

vr_rest()

Switches the VR system to the rest state.

In the rest state, the break is engaged to prevent the mouse from moving the wheel. The encoder module is disabled, and instead the torque sensor is enabled. The VR screens are switched off, cutting off light emission. By default, the VR system starts all experimental runtimes using the REST state.

Return type:

None

vr_run()

Switches the VR system to the run state.

In the run state, the break is disengaged to allow the mouse to freely move the wheel. The encoder module is enabled to record and share live running data with Unity, and the torque sensor is disabled. The VR screens are switched on to render the VR environment.

Return type:

None

sl_experiment.experiment.lick_training_logic(experimenter, project_name, animal_id, animal_weight, minimum_reward_delay=6, maximum_reward_delay=18, maximum_water_volume=1.0, maximum_training_time=20)

Encapsulates the logic used to train animals to operate the lick port.

The lick training consists of delivering randomly spaced 5 uL water rewards via the solenoid valve to teach the animal that water comes out of the lick port. Each reward is delivered after a pseudorandom delay. Reward delay sequence is generated before training runtime by sampling a uniform distribution that ranges from ‘minimum_reward_delay’ to ‘maximum_reward_delay’. The training continues either until the valve delivers the ‘maximum_water_volume’ in milliliters or until the ‘maximum_training_time’ in minutes is reached, whichever comes first.

Parameters:
  • experimenter (str) – The ID (net-ID) of the experimenter conducting the training.

  • project_name (str) – The name of the project to which the trained animal belongs.

  • animal_id (str) – The numeric ID of the animal being trained.

  • animal_weight (float) – The weight of the animal, in grams, at the beginning of the training session.

  • minimum_reward_delay (int, default: 6) – The minimum time, in seconds, that has to pass between delivering two consecutive rewards.

  • maximum_reward_delay (int, default: 18) – The maximum time, in seconds, that can pass between delivering two consecutive rewards.

  • maximum_water_volume (float, default: 1.0) – The maximum volume of water, in milliliters, that can be delivered during this runtime.

  • maximum_training_time (int, default: 20) – The maximum time, in minutes, to run the training.

Return type:

None

sl_experiment.experiment.run_experiment_logic(experimenter, project_name, experiment_name, animal_id, animal_weight)

Encapsulates the logic used to run experiments via the Mesoscope-VR system.

This function can be used to execute any valid experiment using the Mesoscope-VR system. Each experiment should be broken into one or more experiment states (phases), such as ‘baseline’, ‘task’ and ‘cooldown’. Furthermore, each experiment state can use one or more VR system states. Currently, the VR system has two states: rest (1) and run (2). The states are used to broadly configure the Mesoscope-VR system, and they determine which systems are active and what data is collected (see library ReadMe for more details on VR states).

Primarily, this function is concerned with iterating over the states stored inside the experiment_state_sequence tuple. Each experiment and VR state combination is maintained for the requested duration of seconds. Once all states have been executed, the experiment runtime ends. Under this design pattern, each experiment is conceptualized as a sequence of states.

Notes

During experiment runtimes, the task logic and the Virtual Reality world are resolved via the Unity game engine. This function itself does not resolve the task logic, it is only concerned with iterating over experiment states, controlling the VR system, and monitoring user command issued via keyboard.

Similar to all other runtime functions, this function contains all necessary bindings to set up, execute, and terminate an experiment runtime. Custom projects should implement a cli that calls this function with project-specific parameters.

Parameters:
  • experimenter (str) – The id of the experimenter conducting the experiment.

  • project_name (str) – The name of the project for which the experiment is conducted.

  • experiment_name (str) – The name or ID of the experiment to be conducted.

  • animal_id (str) – The numeric ID of the animal participating in the experiment.

  • animal_weight (float) – The weight of the animal, in grams, at the beginning of the experiment session.

Return type:

None

sl_experiment.experiment.run_train_logic(experimenter, project_name, animal_id, animal_weight, initial_speed_threshold=0.4, initial_duration_threshold=0.4, speed_increase_step=0.05, duration_increase_step=0.01, increase_threshold=0.1, maximum_water_volume=1.0, maximum_training_time=20)

Encapsulates the logic used to train animals to run on the wheel treadmill while being head-fixed.

The run training consists of making the animal run on the wheel with a desired speed, in centimeters per second, maintained for the desired duration of time, in seconds. Each time the animal satisfies the speed and duration thresholds, it receives 5 uL of water reward, and the speed and durations trackers reset for the next training ‘epoch’. Each time the animal receives ‘increase_threshold’ of water, the speed and duration thresholds increase to make the task progressively more challenging. The training continues either until the training time exceeds the ‘maximum_training_time’, or the animal receives the ‘maximum_water_volume’ of water, whichever happens earlier.

Notes

During runtime, it is possible to manually increase or decrease both thresholds via ‘ESC’ and arrow keys. The speed and duration thresholds are limited to a minimum of 0.1 cm/s and 0.05 s and a maximum of 20 cm/s and 20 s.

Parameters:
  • experimenter (str) – The id of the experimenter conducting the training.

  • project_name (str) – The name of the project to which the trained animal belongs.

  • animal_id (str) – The numeric ID of the animal being trained.

  • animal_weight (float) – The weight of the animal, in grams, at the beginning of the training session.

  • initial_speed_threshold (float, default: 0.4) – The initial running speed threshold, in centimeters per second, that the animal must maintain to receive water rewards.

  • initial_duration_threshold (float, default: 0.4) – The initial duration threshold, in seconds, that the animal must maintain above-threshold running speed to receive water rewards.

  • speed_increase_step (float, default: 0.05) – The step size, in centimeters per second, by which to increase the speed threshold each time the animal receives ‘increase_threshold’ milliliters of water.

  • duration_increase_step (float, default: 0.01) – The step size, in seconds, by which to increase the duration threshold each time the animal receives ‘increase_threshold’ milliliters of water.

  • increase_threshold (float, default: 0.1) – The volume of water received by the animal, in milliliters, after which the speed and duration thresholds are increased by one step. Note, the animal will at most get ‘maximum_water_volume’ of water, so this parameter effectively controls how many increases will be made during runtime, assuming the maximum training time is not reached.

  • maximum_water_volume (float, default: 1.0) – The maximum volume of water, in milliliters, that can be delivered during this runtime.

  • maximum_training_time (int, default: 20) – The maximum time, in minutes, to run the training.

Return type:

None

sl_experiment.experiment.vr_maintenance_logic(project_name)

Encapsulates the logic used to maintain the solenoid valve and the running wheel.

This runtime allows interfacing with the water valve and the wheel break outside training and experiment runtime contexts. Usually, at the beginning of each experiment or training day the valve is filled with water and ‘referenced’ to verify it functions as expected. At the end of each day, the valve is emptied. Similarly, the wheel is cleaned after each session and the wheel surface wrap is replaced on a weekly or monthly basis (depending on the used wrap).

Notes

This runtime is also co-opted to check animal windows after the recovery period. This is mostly handled via the ScanImage software running on the mesoscope PC, while this runtime generates a snapshot of HeadBar and LickPort positions used during the verification.

Parameters:

project_name (str) – The name of the project whose configuration data should be used when interfacing with the solenoid valve. Primarily, this is used to extract valve calibration data to perform valve ‘referencing’ (testing) procedure. When testing cranial windows, this is also used to determine where to save the Zaber position snapshot.

Return type:

None

Ataraxis Binding Classes

This module binds Ataraxis classes for all Mesoscope-VR components (cameras, microcontrollers, Zaber motors). These bindings streamline the API used to interface with these components during experiment and training runtimes. Critically, these classes statically define optimal runtime configuration parameters for all managed components. Source code refactoring and a new library release are required each time these settings need to be updated.

class sl_experiment.binding_classes.HeadBar(headbar_port, zaber_positions_path)

Bases: object

Interfaces with Zaber motors that control the position of the HeadBar manipulator arm.

This class abstracts working with Zaber motors that move the HeadBar in Z, Pitch, and Roll axes. It is used by the major runtime classes, such as MesoscopeExperiment, to interface with HeadBar motors. The class is designed to transition the HeadBar between a set of predefined states and should not be used directly by the user.

Notes

This class does not contain the guards that notify users about risks associated with moving the motors. Do not use any methods from this class unless you know what you are doing. It is very easy to damage the motors, the mesoscope, or harm the animal.

To fine-tune the position of any HeadBar motors in real time, use the main Zaber Launcher interface (https://software.zaber.com/zaber-launcher/download) installed on the VRPC.

Unless you know that the motors are homed and not parked, always call the prepare_motors() method before calling any other methods. Otherwise, Zaber controllers will likely ignore the issued commands.

Parameters:
  • headbar_port (str) – The USB port used by the HeadBar Zaber motor controllers (devices).

  • zaber_positions_path (Path) – The path to the zaber_positions.yaml file that stores the motor positions saved during previous runtime.

_headbar

Stores the Connection class instance that manages the USB connection to a daisy-chain of Zaber devices (controllers) that allow repositioning the headbar holder.

_headbar_z

The ZaberAxis class instance for the HeadBar z-axis motor.

_headbar_pitch

The ZaberAxis class instance for the HeadBar pitch-axis motor.

_headbar_roll

The ZaberAxis class instance for the HeadBar roll-axis motor.

_previous_positions

An instance of _ZaberPositions class that stores the positions of HeadBar motors during a previous runtime. If this data is not available, this attribute is set to None to indicate there are no previous positions to use.

calibrate_position(wait_until_idle=True)

Moves all HeadBar motors to the water valve calibration position.

This position is stored in the non-volatile memory of each motor controller. This position is used during the water valve calibration to provide experimenters with easier access to the LickPort tube.

Notes

This method moves all HeadBar axes in-parallel to optimize runtime speed.

Parameters:

wait_until_idle (bool, default: True) – Determines whether to block in-place until all motors finish moving or to return without waiting for the motors to stop moving. This is primarily used to move multiple motor groups at the same time.

Return type:

None

disconnect()

Disconnects from the access port of the motor group.

This method should be called after the motors are parked (moved to their final parking position) to release the connection resources. If this method is not called, the runtime will NOT be able to terminate.

Return type:

None

Notes

Calling this method will execute the motor parking sequence, which involves moving the motors to their parking position. Make sure there are no animals mounted on the rig and that the mesoscope objective is removed from the rig before executing this command.

get_positions()

Returns the current position of all HeadBar motors in native motor units.

The positions are returned in the order of : Z, Pitch, and Roll. These positions can be saves as a zaber_positions.yaml file to be used during the following runtimes.

Return type:

tuple[int, int, int]

mount_position(wait_until_idle=True)

Moves all HeadBar motors to the animal mounting position.

This position is stored in the non-volatile memory of each motor controller. This position is used when the animal is mounted into the VR rig to provide the experimenter with easy access to the HeadBar holder.

Notes

This method moves all HeadBar axes in-parallel to optimize runtime speed.

Parameters:

wait_until_idle (bool, default: True) – Determines whether to block in-place until all motors finish moving or to return without waiting for the motors to stop moving. This is primarily used to move multiple motor groups at the same time.

Return type:

None

park_position(wait_until_idle=True)

Moves all HeadBar motors to their parking positions and parks (locks) them preventing future movements.

This method should be used at the end of each runtime (experiment, training, etc.) to ensure all HeadBar motors are positioned in a way that guarantees that they can be homed during the next runtime.

Notes

The motors are moved to the parking positions stored in the non-volatile memory of each motor controller. If this class is used together with the LickPort class, this method should always be called before the similar method from the LickPort class.

This method moves all HeadBar axes in-parallel to optimize runtime speed.

Parameters:

wait_until_idle (bool, default: True) – Determines whether to block in-place until all motors finish moving or to return without waiting for the motors to stop moving. This is primarily used to move multiple motor groups at the same time.

Return type:

None

prepare_motors(wait_until_idle=True)

Unparks and homes all HeadBar motors.

This method should be used at the beginning of each runtime (experiment, training, etc.) to ensure all HeadBar motors can be moved (are not parked) and have a stable point of reference. The motors are left at their respective homing positions at the end of this method’s runtime, and it is assumed that a different class method is called after this method to set the motors into the desired position.

Notes

This method moves all HeadBar axes in-parallel to optimize runtime speed.

Parameters:

wait_until_idle (bool, default: True) – Determines whether to block in-place until all motors finish moving or to return without waiting for the motors to stop moving. This is primarily used to move multiple motor groups at the same time.

Return type:

None

restore_position(wait_until_idle=True)

Restores the HeadBar motor positions to the states recorded at the end of the previous runtime.

For most runtimes, this method is used to restore the HeadBar to the state used during a previous experiment or training session for each animal. Since all animals are slightly different, the optimal HeadBar positions will vary slightly for each animal.

Notes

If previous positions are not available, the method falls back to moving the HeadBar motors to the general ‘mounting’ positions saved in the non-volatile memory of each motor controller. These positions are designed to work for most animals and provide an initial HeadBar position for the animal to be mounted into the VR rig.

When used together with the LickPort class, this method should always be called before the similar method from the LickPort class.

This method moves all HeadBar axes in-parallel to optimize runtime speed.

Parameters:

wait_until_idle (bool, default: True) – Determines whether to block in-place until all motors finish moving or to return without waiting for the motors to stop moving. This is primarily used to move multiple motor groups at the same time.

Return type:

None

wait_until_idle()

This method blocks in-place while at least one motor in the managed motor group is moving.

Primarily, this method is used to issue commands to multiple motor groups and then block until all motors in all groups finish moving. This optimizes the overall time taken to move the motors.

Return type:

None

class sl_experiment.binding_classes.LickPort(lickport_port, zaber_positions_path)

Bases: object

Interfaces with Zaber motors that control the position of the LickPort manipulator arm.

This class abstracts working with Zaber motors that move the LickPort in Z, X, and Y axes. It is used by the major runtime classes, such as MesoscopeExperiment, to interface with LickPort motors. The class is designed to transition the LickPort between a set of predefined states and should not be used directly by the user.

Notes

This class does not contain the guards that notify users about risks associated with moving the motors. Do not use any methods from this class unless you know what you are doing. It is very easy to damage the motors, the mesoscope, or harm the animal.

To fine-tune the position of any HeadBar motors in real time, use the main Zaber Launcher interface (https://software.zaber.com/zaber-launcher/download) installed on the VRPC.

Unless you know that the motors are homed and not parked, always call the prepare_motors() method before calling any other methods. Otherwise, Zaber controllers will likely ignore the issued commands.

Parameters:
  • lickport_port (str) – The USB port used by the LickPort Zaber motor controllers (devices).

  • zaber_positions_path (Path) – The path to the zaber_positions.yaml file that stores the motor positions saved during previous runtime.

_lickport

Stores the Connection class instance that manages the USB connection to a daisy-chain of Zaber devices (controllers) that allow repositioning the lick tube.

_lickport_z

Stores the Axis (motor) class that controls the position of the lickport along the Z axis.

_lickport_x

Stores the Axis (motor) class that controls the position of the lickport along the X axis.

_lickport_y

Stores the Axis (motor) class that controls the position of the lickport along the Y axis.

_previous_positions

An instance of _ZaberPositions class that stores the positions of LickPort motors during a previous runtime. If this data is not available, this attribute is set to None to indicate there are no previous positions to use.

calibrate_position(wait_until_idle=True)

Moves all LickPort motors to the water valve calibration position.

This position is stored in the non-volatile memory of each motor controller. This position is used during the water valve calibration to provide experimenters with easier access to the LickPort tube.

Notes

This method moves all LickPort axes in-parallel to optimize runtime speed.

Parameters:

wait_until_idle (bool, default: True) – Determines whether to block in-place until all motors finish moving or to return without waiting for the motors to stop moving. This is primarily used to move multiple motor groups at the same time.

Return type:

None

disconnect()

Disconnects from the access port of the motor group.

This method should be called after the motors are parked (moved to their final parking position) to release the connection resources. If this method is not called, the runtime will NOT be able to terminate.

Return type:

None

Notes

Calling this method will execute the motor parking sequence, which involves moving the motors to their parking position. Make sure there are no animals mounted on the rig and that the mesoscope objective is removed from the rig before executing this command.

get_positions()

Returns the current position of all LickPort motors in native motor units.

The positions are returned in the order of : Z, X, and Y. These positions can be saves as a zaber_positions.yaml file to be used during the following runtimes.

Return type:

tuple[int, int, int]

mount_position(wait_until_idle=True)

Moves all LickPort motors to the animal mounting position.

This position is stored in the non-volatile memory of each motor controller. This position is used when the animal is mounted into the VR rig to provide the experimenter with easy access to the HeadBar holder.

Notes

This method moves all LickPort axes in-parallel to optimize runtime speed.

Parameters:

wait_until_idle (bool, default: True) – Determines whether to block in-place until all motors finish moving or to return without waiting for the motors to stop moving. This is primarily used to move multiple motor groups at the same time.

Return type:

None

park_position(wait_until_idle=True)

Moves all LickPort motors to their parking positions and parks (locks) them preventing future movements.

This method should be used at the end of each runtime (experiment, training, etc.) to ensure all LickPort motors are positioned in a way that guarantees that they can be homed during the next runtime.

Notes

The motors are moved to the parking positions stored in the non-volatile memory of each motor controller. If this class is used together with the HeadBar class, this method should always be called after the similar method from the HeadBar class.

This method moves all LickPort axes in-parallel to optimize runtime speed.

Parameters:

wait_until_idle (bool, default: True) – Determines whether to block in-place until all motors finish moving or to return without waiting for the motors to stop moving. This is primarily used to move multiple motor groups at the same time.

Return type:

None

prepare_motors(wait_until_idle=True)

Unparks and homes all LickPort motors.

This method should be used at the beginning of each runtime (experiment, training, etc.) to ensure all LickPort motors can be moved (are not parked) and have a stable point of reference. The motors are left at their respective homing positions at the end of this method’s runtime, and it is assumed that a different class method is called after this method to set the motors into the desired position.

Notes

This method moves all LickPort axes in-parallel to optimize runtime speed.

Parameters:

wait_until_idle (bool, default: True) – Determines whether to block in-place until all motors finish moving or to return without waiting for the motors to stop moving. This is primarily used to move multiple motor groups at the same time.

Return type:

None

restore_position(wait_until_idle=True)

Restores the LickPort motor positions to the states recorded at the end of the previous runtime.

For most runtimes, this method is used to restore the LickPort to the state used during a previous experiment or training session for each animal. Since all animals are slightly different, the optimal LickPort positions will vary slightly for each animal.

Notes

If previous positions are not available, the method falls back to moving the LickPort motors to the general ‘parking’ positions saved in the non-volatile memory of each motor controller. Note, this is in contrast to the HeadBar, which falls back to using the ‘mounting’ positions. The mounting position for the LickPort aligns it to the top left corner of the running wheel, to provide experimenter with easier access to the HeadBar. The parking position, on the other hand, positions the lick tube roughly next to the animal’s head.

When used together with the HeadBar class, this method should always be called after the similar method from the HeadBar class.

This method moves all LickPort axes in-parallel to optimize runtime speed.

Parameters:

wait_until_idle (bool, default: True) – Determines whether to block in-place until all motors finish moving or to return without waiting for the motors to stop moving. This is primarily used to move multiple motor groups at the same time.

Return type:

None

wait_until_idle()

This method blocks in-place while at least one motor in the managed motor group is moving.

Primarily, this method is used to issue commands to multiple motor groups and then block until all motors in all groups finish moving. This optimizes the overall time taken to move the motors.

Return type:

None

class sl_experiment.binding_classes.MicroControllerInterfaces(data_logger, actor_port, sensor_port, encoder_port, valve_calibration_data, debug=False)

Bases: object

Interfaces with all Ataraxis Micro Controller (AMC) devices that control and record non-video behavioral data from the Mesoscope-VR system.

This class interfaces with the three AMC controllers used during various runtimes: Actor, Sensor, and Encoder. The class exposes methods to send commands to the hardware modules managed by these microcontrollers. In turn, these modules control specific components of the Mesoscope-Vr system, such as rotary encoders, solenoid valves, and conductive lick sensors.

Notes

This class is primarily intended to be used internally by the MesoscopeExperiment and BehavioralTraining classes. Our vr-maintenance CLI (sl-maintain-vr) uses this class directly to calibrate the water valve, but this is a unique use scenario. Do not initialize this class directly unless you know what you are doing.

Calling the initializer does not start the underlying processes. Use the start() method before issuing other commands to properly initialize all remote processes. This design is intentional and is used during experiment and training runtimes to parallelize data preprocessing and starting the next animal’s session.

Parameters:
  • data_logger (DataLogger) – The initialized DataLogger instance used to log the data generated by the managed microcontrollers. For most runtimes, this argument is resolved by the MesoscopeExperiment or BehavioralTraining classes that initialize this class.

  • actor_port (str) – The USB port used by the Actor Microcontroller.

  • sensor_port (str) – The USB port used by the Sensor Microcontroller.

  • encoder_port (str) – The USB port used by the Encoder Microcontroller.

  • valve_calibration_data (tuple[tuple[int | float, int | float], ...]) – A tuple of tuples, with each inner tuple storing a pair of values. The first value is the duration, in microseconds, the valve was open. The second value is the volume of dispensed water, in microliters. This data is used by the ValveInterface to calculate pulse times necessary to deliver requested volumes of water.

  • debug (bool, default: False) – Determines whether to run the managed interfaces in debug mode. Generally, this mode should be disabled for most runtimes. It is used during the initial system calibration to interactively debug and adjust the hardware module and interface configurations.

_started

Tracks whether the VR system and experiment runtime are currently running.

_previous_volume

Tracks the volume of water dispensed during previous deliver_reward() calls.

_screen_state

Tracks the current VR screen state.

mesoscope_start

The interface that starts mesoscope frame acquisition via TTL pulse.

mesoscope_stop

The interface that stops mesoscope frame acquisition via TTL pulse.

wheel_break

The interface that controls the electromagnetic break attached to the running wheel.

valve

The interface that controls the solenoid water valve that delivers water to the animal.

screens

The interface that controls the power state of the VR display screens.

_actor

The main interface for the ‘Actor’ Ataraxis Micro Controller (AMC) device.

mesoscope_frame

The interface that monitors frame acquisition timestamp signals sent by the mesoscope.

lick

The interface that monitors animal’s interactions with the lick sensor (detects licks).

torque

The interface that monitors the torque applied by the animal to the running wheel.

_sensor

The main interface for the ‘Sensor’ Ataraxis Micro Controller (AMC) device.

wheel_encoder

The interface that monitors the rotation of the running wheel and converts it into the distance traveled by the animal.

_encoder

The main interface for the ‘Encoder’ Ataraxis Micro Controller (AMC) device.

Raises:

TypeError – If the provided valve_calibration_data argument is not a tuple or does not contain valid elements.

calibrate_valve(pulse_duration=15)

Cycles solenoid valve opening and closing 500 times to determine the amount of water dispensed by the input pulse_duration.

The valve is kept open for the specified number of milliseconds. Between pulses, the valve is kept closed for 200 ms. Due to our valve design, keeping the valve closed for less than 200 ms generates a large pressure at the third (Normally Open) port, which puts unnecessary strain on the port plug.

During runtime, the valve will be pulsed 500 times to provide a large sample size. During calibration, the water should be collected in a pre-weighted conical tube. After the calibration is over, the tube with dispensed water has to be weighted to determine the dispensed volume by weight.

Notes

The calibration should be run with the following durations: 15 ms, 30 ms, 45 ms, and 60 ms. During testing, we found that these values roughly cover the range from 2 uL to 10 uL, which is enough to cover most training and experiment runtimes.

Make sure that the water line is primed, deaerated, and the holding (‘tank’) syringe filled exactly to the 5 mL mark at the beginning of each calibration cycle. Depending on the calibrated pulse_duration, you may need to refill the syringe during the calibration runtime. The calibration durations mentioned above should not need manual tank refills.

Parameters:

pulse_duration (int, default: 15) – The duration, in milliseconds, the valve is kept open at each calibration cycle

Return type:

None

close_valve()

Closes the water reward solenoid valve.

Return type:

None

deliver_reward(volume=5.0)

Pulses the water reward solenoid valve for the duration of time necessary to deliver the provided volume of water.

This method assumes that the valve has been calibrated before calling this method. It uses the calibration data provided at class instantiation to determine the period of time the valve should be kept open to deliver the requested volume of water.

Parameters:

volume (float, default: 5.0) – The volume of water to deliver, in microliters.

Return type:

None

disable_break()

Disengages the wheel break, enabling the animal to run on the wheel.

Return type:

None

disable_encoder_monitoring()

Stops monitoring the wheel encoder.

Return type:

None

disable_lick_monitoring()

Stops monitoring the conductive lick sensor.

Return type:

None

disable_mesoscope_frame_monitoring()

Stops monitoring the TTL pulses sent by the mesoscope to communicate when it is scanning a frame.

Return type:

None

disable_torque_monitoring()

Stops monitoring the torque sensor.

Return type:

None

disable_vr_screens()

Sets the VR screens to be OFF.

Return type:

None

property distance_tracker: SharedMemoryArray

Returns the SharedMemoryArray used to communicate the total distance traveled by the animal since runtime onset.

This array should be passed to a Visualizer class so that it can sample the shared data to generate real-time running speed plots. It is also used by the run training logic to evaluate animal’s performance during training.

enable_break()

Engages the wheel break at maximum strength, preventing the animal from running on the wheel.

Return type:

None

enable_encoder_monitoring()

Enables wheel encoder monitoring at 2 kHz rate.

This means that, at most, the Encoder will send the data to the PC at the 2 kHz rate. The Encoder collects data at the native rate supported by the microcontroller hardware, which likely exceeds the reporting rate.

Return type:

None

enable_lick_monitoring()

Enables monitoring the state of the conductive lick sensor at ~ 1 kHZ rate.

The lick sensor measures the voltage across the lick sensor and reports surges in voltage to the PC as a reliable proxy for tongue-to-sensor contact. Most lick events span at least 100 ms of time and, therefore, the rate of 1 kHZ is adequate for resolving all expected single-lick events.

Return type:

None

enable_mesoscope_frame_monitoring()

Enables monitoring the TTL pulses sent by the mesoscope to communicate when it is scanning a frame at ~ 1 kHZ rate.

The mesoscope sends the HIGH phase of the TTL pulse while it is scanning the frame, which produces a pulse of ~100ms. This is followed by ~5ms LOW phase during which the Galvos are executing the flyback procedure. This command checks the state of the TTL pin at the 1 kHZ rate, which is enough to accurately report both phases.

Return type:

None

enable_torque_monitoring()

Enables monitoring the torque sensor at ~ 1 kHZ rate.

The torque sensor detects CW and CCW torques applied by the animal to the wheel. Currently, we do not have a way of reliably calibrating the sensor, so detected torque magnitudes are only approximate. However, the sensor reliably distinguishes large torques from small torques and accurately tracks animal motion activity when the wheel break is engaged.

Return type:

None

enable_vr_screens()

Sets the VR screens to be ON.

Return type:

None

property lick_tracker: SharedMemoryArray

Returns the SharedMemoryArray used to communicate the lick sensor status.

This array should be passed to a Visualizer class so that it can sample the shared data to generate real-time lick detection plots.

property mesoscope_frame_count: int

Returns the total number of mesoscope frame acquisition pulses recorded since runtime onset.

open_valve()

Opens the water reward solenoid valve.

This method is primarily used to prime the water line with water before the first experiment or training session of the day.

Return type:

None

reference_valve()

Runs the reference valve calibration procedure.

Reference calibration is functionally similar to the calibrate_valve() method runtime. It is, however, optimized to deliver the overall volume of water recognizable for the human eye looking at the syringe holding the water (water ‘tank’ used in our system). Additionally, this uses the 5 uL volume as the reference volume, which matches the volume we use during experiments and training sessions.

The reference calibration HAS to be run with the water line being primed, deaerated, and the holding (‘tank’) syringe filled exactly to the 5 mL mark. This procedure is designed to dispense 5 uL of water 200 times, which should overall dispense ~ 1 ml of water.

Return type:

None

Notes

Use one of the conical tubes stored next to the Mesoscope cage to collect the dispensed water. It is highly encouraged to use both the visual confirmation (looking at the syringe water level drop) and the weight confirmation (weighing the water dispensed into the collection tube). This provides the most accurate referencing result.

If the referencing procedure fails to deliver 5 +- 0.5 uL of water measured with either method, the valve needs to be recalibrated using the calibrate_valve() method. Also, if valve referencing result stability over multiple days fluctuates significantly, it is advised to recalibrate the valve using the calibrate_valve() method.

start()

Starts MicroController communication processes and configures all hardware modules to use predetermined runtime parameters.

This method sets up the necessary assets that enable MicroController-PC communication. Until this method is called, all other class methods will not function correctly.

Return type:

None

Notes

After calling this method, most hardware modules will be initialized to an idle state. The only exception to this rule is the wheel break, which initializes to the ‘engaged’ state. Use other class methods to switch individual hardware modules into the desired state.

Since most modules initialize to an idle state, they will not be generating data. Therefore, it is safe to call this method before enabling the DataLogger class. However, it is strongly advised to enable the DataLogger as soon as possible to avoid data piling up in the buffer.

This method uses Console to notify the user about the initialization progress, but it does not enable the Console class itself. Make sure the console is enabled before calling this method.

start_mesoscope()

Sends the acquisition start TTL pulse to the mesoscope.

Return type:

None

stop()

Stops all MicroController communication processes and releases all resources.

This method needs to be called at the end of each runtime to release the resources reserved by the start() method. Until the stop() method is called, the DataLogger instance may receive data from running MicroControllers, so calling this method also guarantees no MicroController data will be lost if the DataLogger process is terminated.

Return type:

None

stop_mesoscope()

Sends the acquisition stop TTL pulse to the mesoscope.

Return type:

None

property total_delivered_volume: float

Returns the total volume of water, in microliters, dispensed by the valve since runtime onset.

property valve_tracker: SharedMemoryArray

Returns the SharedMemoryArray used to communicate the water reward valve state.

This array should be passed to a Visualizer class so that it can sample the shared data to generate real-time reward delivery plots.

class sl_experiment.binding_classes.VideoSystems(data_logger, output_directory, face_camera_index, left_camera_index, right_camera_index, harvesters_cti_path)

Bases: object

Interfaces with all cameras managed by Ataraxis Video System (AVS) classes that acquire and save camera frames as .mp4 video files.

This class interfaces with the three AVS cameras used during various runtimes to record animal behavior: the face camera and the two body cameras (the left camera and the right camera). The face camera is a high-grade scientific camera that records the animal’s face and pupil. The left and right cameras are lower-end security cameras recording the animal’s body from the left and right sides.

Notes

This class is primarily intended to be used internally by the MesoscopeExperiment and BehavioralTraining classes. Do not initialize this class directly unless you know what you are doing.

Calling the initializer does not start the underlying processes. Call the appropriate start() method to start acquiring and displaying face and body camera frames (there is a separate method for these two groups). Call the appropriate save() method to start saving the acquired frames to video files. Note that there is a single ‘global’ stop() method that works for all cameras at the same time.

The class is designed to be ‘lock-in’. Once a camera is enabled, the only way to disable frame acquisition is to call the main stop() method. Similarly, once frame saving is started, there is no way to disable it without stopping the whole class. This is an intentional design decision optimized to the specific class use-pattern in our lab.

Parameters:
  • data_logger (DataLogger) – The initialized DataLogger instance used to log the data generated by the managed cameras. For most runtimes, this argument is resolved by the MesoscopeExperiment or BehavioralTraining classes that initialize this class.

  • output_directory (Path) – The path to the directory where to output the generated .mp4 video files. Each managed camera generates a separate video file saved in the provided directory. For most runtimes, this argument is resolved by the MesoscopeExperiment or BehavioralTraining classes that initialize this class.

  • face_camera_index (int) – The index of the face camera in the list of all available Harvester-managed cameras.

  • left_camera_index (int) – The index of the left camera in the list of all available OpenCV-managed cameras.

  • right_camera_index (int) – The index of the right camera in the list of all available OpenCV-managed cameras.

  • harvesters_cti_path (Path) – The path to the GeniCam CTI file used to connect to Harvesters-managed cameras.

_face_camera_started

Tracks whether the face camera frame acquisition is running.

_body_cameras_started

Tracks whether the body cameras frame acquisition is running.

_face-camera

The interface that captures and saves the frames acquired by the 9MP scientific camera aimed at the animal’s face and eye from the left side (via a hot mirror).

_left_camera

The interface that captures and saves the frames acquired by the 1080P security camera aimed on the left side of the animal and the right and center VR screens.

_right_camera

The interface that captures and saves the frames acquired by the 1080P security camera aimed on the right side of the animal and the left VR screen.

property face_camera_log_path: Path

Returns the path to the compressed .npz archive that stores the data logged by the face camera during runtime.

property left_camera_log_path: Path

Returns the path to the compressed .npz archive that stores the data logged by the left body camera during runtime.

property right_camera_log_path: Path

Returns the path to the compressed .npz archive that stores the data logged by the right body camera during runtime.

save_body_camera_frames()

Starts saving the frames acquired by the left and right body cameras as a video file.

Return type:

None

save_face_camera_frames()

Starts saving the frames acquired by the face camera as a video file.

Return type:

None

start_body_cameras()

Starts left and right (body) camera frame acquisition.

This method sets up both the frame acquisition (producer) process and the frame saver (consumer) process for both cameras. However, the consumer processes will not save any frames until save_body_camera_frames() method is called.

Return type:

None

start_face_camera()

Starts face camera frame acquisition.

This method sets up both the frame acquisition (producer) process and the frame saver (consumer) process. However, the consumer process will not save any frames until save_face_camera_frames() method is called.

Return type:

None

stop()

Stops saving all camera frames and terminates the managed VideoSystems.

This method needs to be called at the end of each runtime to release the resources reserved by the start() methods. Until the stop() method is called, the DataLogger instance may receive data from running VideoSystems, so calling this method also guarantees no VideoSystem data will be lost if the DataLogger process is terminated. Similarly, this guarantees the integrity of the generated video files.

Return type:

None

Runtime Data Visualizers

This module provides the Visualizer class, a major training and experiment runtime UI element used to provide real-time feedback on the animal’s task performance and task parameters.

class sl_experiment.visualizers.BehaviorVisualizer(lick_tracker, valve_tracker, distance_tracker)

Bases: object

Visualizes lick, valve, and running speed data in real time.

This class is used to visualize the key behavioral metrics collected from animals performing experiment or training sessions in the Mesoscope-VR system. Note, the class is statically configured to generate the plots for all supported metrics, even if some of them are not used during a particular session.

Notes

This class is designed to run in the main thread of the runtime context. To update the visualized data, ensure that the ‘update’ class method is called repeatedly during runtime.

Parameters:
  • lick_tracker (SharedMemoryArray) – The SharedMemoryArray instance exposed by the LickInterface class that communicates the number of licks recorded by the class since runtime onset.

  • valve_tracker (SharedMemoryArray) – The SharedMemoryArray instance exposed by the ValveInterface class that communicates the number of times the valve has been opened since runtime onset.

  • distance_tracker (SharedMemoryArray) – The SharedMemoryArray instance exposed by the EncoderInterface class that communicates the total distance traveled by the animal since runtime onset, in centimeters.

_time_window

Specifies the time window, in seconds, to visualize during runtime. Currently, this is statically set to 12 seconds.

_time_step

Specifies the interval, in milliseconds, at which to update the visualization plots. Currently, this is statically set to 30 milliseconds, which gives a good balance between update smoothness and rendering time.

_update_timer

The PrecisionTimer instance used to ensure that the figure is updated once every _time_step milliseconds.

_lick_tracker

Stores the lick_tracker SharedMemoryArray.

_valve_tracker

Stores the valve_tracker SharedMemoryArray.

_distance_tracker

Stores the distance_tracker SharedMemoryArray.

_timestamps

A numpy array that stores the timestamps of the displayed data during visualization runtime. The timestamps are generated at class initialization and are kept constant during runtime.

_lick_data

A numpy array that stores the data used to generate the lick sensor state plot.

_valve_data

A numpy array that stores the data used to generate the solenoid valve state plot.

_speed_data

A numpy array that stores the data used to generate the running speed plot.

_previous_valve_count

Stores the total number of valve pulses sampled during the previous update cycle.

_previous_lick_count

Stores the total number of licks sampled during the previous update cycle.

_previous_distance

Stores the total distance traveled by the animal sampled during the previous update cycle.

_speed_timer

Stores the PrecisionTimer instance used to convert traveled distance into running speed.

_lick_line

Stores the line class used to plot the lick sensor data.

_valve_line

Stores the line class used to plot the solenoid valve data.

_speed_line

Stores the line class used to plot the average running speed data.

_figure

Stores the matplotlib figure instance used to display the plots.

_lick_axis

The axis object used to plot the lick sensor data during visualization runtime.

_valve_axis

The axis object used to plot the solenoid valve data during visualization runtime.

_speed_axis

The axis object used to plot the average running speed data during visualization runtime.

_speed_threshold_line

Stores the horizontal line class used to plot the running speed threshold used during training sessions.

_duration_threshold_line

Stores the horizontal line class used to plot the running epoch duration used during training sessions.

_running_speed

Stores the current running speed of the animal. Somewhat confusingly, since we already compute the average running speed of the animal via the visualizer, it is easier to retrieve and use it from the main training runtime. This value is used to share the current running speed with the training runtime.

_once

This flag is sued to limit certain visualizer operations to only be called once during runtime.

_speed_threshold_text

Stores the text object used to display the speed threshold value to the user.

_duration_threshold_text

Stores the text object used to display the running epoch duration value to the user.

__del__()

Ensures all resources are released when the figure object is garbage-collected.

Return type:

None

_sample_data()

Samples new data from tracker SharedMemoryArray instances and update the class memory.

Return type:

None

close()

Closes the visualized figure and cleans up the resources used by the class during runtime.

Return type:

None

property running_speed: float64

Returns the current running speed of the animal, calculated over the window of the last 100 milliseconds.

update()

Updates the figure managed by the class to display new data.

This method discards the oldest datapoint in the plot memory and instead samples a new datapoint. It also shifts all datapoints one timestamp to the left. When the method is called repeatedly, this makes the plot lines naturally flow from the right (now) to the left (12 seconds in the past), accurately displaying the visualized data history.

Return type:

None

Notes

The method has an internal update frequency limiter. Therefore, to achieve optimal performance, call this method as frequently as possible and rely on the internal limiter to force the specific update frequency.

update_speed_thresholds(speed_threshold, duration_threshold)

Updates the running speed and duration threshold lines to use the input anchor values.

This positions the threshold lines in the running speed plot to indicate the cut-offs for the running speed and running epoch duration that elicit water rewards. This is used during run training to visualize the thresholds the animal needs to meet to receive water rewards.

Parameters:
  • speed_threshold (float | float64) – The speed, in centimeter per second, the animal needs to maintain to get water rewards.

  • duration_threshold (float | float64) – The duration, in milliseconds, the animal has to maintain the above-threshold speed to get water rewards.

Return type:

None

sl_experiment.visualizers._plt_line_styles(line_style)

Converts colloquial line style names to pyplot’s ‘lifestyle’ string-codes.

Parameters:

line_style (str) – Colloquial name for the line style to be used. Options are ‘solid’, ‘dashed’, ‘dotdashed’ and ‘dotted’.

Return type:

str

Returns:

The string-code for the requested line style.

Raises:

KeyError – If the provided line style is not recognized.

sl_experiment.visualizers._plt_palette(color)

Converts colloquial color names to pyplot RGB color codes.

The provided colors are not perfectly colorblind-friendly. They should be used with different ‘line style’ formats to improve readability in monochrome spectrum. The codes generated by this function should be passed to ‘color’ argument of the pyplot module.

Parameters:

color (str) – Colloquial name of the color to be retrieved. Available options are: ‘green’, ‘blue’, ‘red’, ‘yellow’, ‘purple’, ‘orange’, ‘pink’, ‘black’, ‘white’, ‘gray’.

Return type:

tuple[float, float, float]

Returns:

A list of R, G, and B values for the requested color.

Raises:

KeyError – If the provided color is not recognized.

Zaber Interfaces

This module provides interfaces for Zaber controllers and motors used in the Mesoscope-VR system. Primarily, the module builds on top of the bindings exposed by ZaberMotion library to specialize them for the specific requirements of the Mesoscope-VR system.

class sl_experiment.zaber_bindings.CRCCalculator

Bases: object

A CRC32-XFER checksum calculator that works with raw bytes or pythonic strings.

This utility class exposes methods that generate CRC checksum labels and bytes objects, which are primarily used by Zaber binding classes to verify that Zaber devices have been configured to work with the binding interface exposed by this library.

_calculator

Stores the configured Calculator class object used to calculate the checksums.

bytes_checksum(data)

Calculates the CRC32-XFER checksum for the input bytes.

While the class is primarily designed for generating CRC-checksums for strings, this method can be used to checksum any bytes-converted object.

Parameters:

data (bytes) – The bytes-converted data to calculate the CRC checksum for.

Return type:

int

Returns:

The integer CRC32-XFER checksum.

string_checksum(string)

Calculates the CRC32-XFER checksum for the input string.

The input strings are first converted to bytes using ASCII protocol. The checksum is then calculated on the resultant bytes-object.

Parameters:

string (str) – The string for which to calculate the CRC checksum.

Return type:

int

Returns:

The integer CRC32-XFER checksum.

class sl_experiment.zaber_bindings.ZaberAxis(motor)

Bases: object

Interfaces with a Zaber axis (motor).

This class is the lowest member of the tri-class hierarchy used to control Zaber motors during runtime.

Notes

This class uses ‘millimeters’ for linear motors and ‘degrees’ for rotary motors. These units were chosen due to achieving the best balance between precision and ease of use for the experimenters in the lab.

Parameters:

motor (Axis) – Axis class instance that controls the hardware of the motor. This class should be instantiated automatically by the ZaberDevice class that manages this ZaberAxis instance.

_motor

Stores the Axis class instance that physically controls the motor hardware through Zaber ASCII protocol.

_name

Stores the user-defined label (name) of the axis.

_units

stores a ZaberUnits instance used to convert from colloquial unit names used in binding code to Zaber-specific Unit classes used during communication with the axis.

_linear

The boolean flag that determines if the managed motor is driving a linear or a rotary axis. This flag determines the units used by the motor (millimeters or degrees).

_park_position

The absolute position relative to the home sensor position, in native motor units, the motor should be parked at before shutting the axis down. This is used to position the motor in a way that is guaranteed to successfully home without colliding with surrounding objects after powering-up. This is especially relevant for rotary than linear axes.

_valve_position

The absolute position relative to the home sensor position, in native motor units, the motor should be moved to before water reward valve calibration. Since the space inside the Mesoscope-VR rig is constrained, it is helpful to orient the headbar and lickport motors in a way that provides easy access to the lickport tube. These positions are stored in the non-volatile memory and are used similar to how the park position is used.

_mount_position

The absolute position relative to the home sensor position, in native motor units, the motor should be moved to before mounting a naive animal onto the VR rig. This position is used to provide experimenters with more working room around the rig and ensure animal’s comfort as it is mounted onto the rig. This position is a fallback used when the animal does nto have a better, custom-calibrated position available. Usually, this would only be the case when the animal is mounted onto the rig for the very first time.

_max_limit

The maximum absolute position relative to the home sensor position, in native motor units, the motor hardware can reach.

_min_limit

Same as the _hardware_max_limit, but specifies the minimum absolute position relative to home sensor position, in native motor units, the motor hardware can reach.

_shutdown_flag

Tracks whether the axis has been shut down. Primarily, this is used to prevent the __del__() method from shutting down an already shut axis.

_timer

A PrecisionTimer class instance that is used to ensure that communication with the motor is carried out at a pace that does not overwhelm the connection interface with too many successive calls.

Raises:
  • TypeError – If motor is not an Axis class instance.

  • ValueError – If any motor parameter is read from the non-volatile memory is outside the expected range of values.

__del__()

Ensures the managed motor is stopped and parked before the class instance is garbage-collected.

This is a safety feature designed to de-power and lock the motor if the class encounters a runtime error. The feature is aimed at preserving the life and health of the animals and preventing mesoscope objective damage.

Return type:

None

__repr__()

Constructs and returns a string that represents the class instance.

Return type:

str

_ensure_call_padding()

This method should be used before each call to motor hardware to ensure it is sufficiently separated from other calls to prevent overwhelming the serial connection.

This method is statically configured to prevent further commands from being issued for the following 10 milliseconds, which is appropriate for the default Zaber communication baudrate of 115,200.

Return type:

None

_reset_pad_timer()

Resets the PrecisionTimer instance used to enforce a static delay between motor hardware calls.

This method should be used after each motor hardware call command to reset the timer in preparation for the next call (to exclude the time spent on the request-response sequence of the call from the padding calculation). It is designed to work together with the _ensure_call_padding method.

Return type:

None

get_position(native=False)

Returns the current absolute position of the motor relative to the home position.

Parameters:
  • native (bool, default: False) – Determines if the returned value should use native motor units (true) or metric units (false). For

  • axes (the metric units are millimeters. For rotary)

  • axes

  • degrees. (the metric units are)

Return type:

float

home()

Homes the motor by moving it towards the home sensor position until it triggers the sensor.

This method establishes a stable reference point used to execute all further motion commands.

Return type:

None

Notes

This class as a whole makes a considerable effort to avoid having to re-home the device by parking it before expected power shutdowns. That said, it is usually a good practice to home all devices after they had been idle for a prolonged period of time.

The method initializes the homing procedure but does not block until it is over. As such, it is likely that the motor would still be moving when this method returns. This feature is designed to support homing multiple axes in parallel.

property inversion: bool

Returns the current value of the motor hardware inversion flag.

Generally, this determines which direction of movement brings the motor towards its home sensor position.

property is_busy: bool

Returns True if the motor is currently executing a motor command (is moving).

property is_homed: bool

Returns True if the motor has a motion reference point (has been homed).

property is_parked: bool

Returns True if the motor is parked.

property maximum_limit: float

Returns the maximum absolute position, relative to the home sensor position, the motor can be moved to.

It is assumed that the home sensor position is always defined as 0. The returned position is in millimeters for linear axes and degrees for rotary axes.

property minimum_limit: float

Returns the minimum absolute position relative to the home sensor position the motor can be moved to.

It is assumed that the home sensor position is always defined as 0. The returned position is in millimeters for linear axes and degrees for rotary axes.

property mount_position: int

Returns the absolute position, in native motor units, where the motor needs to be moved before mounting the animal onto the VR rig.

Applying this position to the motor orients the headbar and lickport system in a way that makes it easier to mount the animal, while also providing animal with comfortable position inside the VR rig.

move(amount, absolute, native=False)

Moves the motor to the requested position.

Depending on the type of the motor and the native flag, the motion is either performed in millimeters (for linear axes), degrees (for rotary axes), or native units (for both types). Relative values are first converted to absolute values before being issued to the motor. The method contains internal mechanisms that prevent movement outside the hardware-defined motion range.

Notes

This method executes movement in a non-blocking fashion. As such, the method will most likely return before the motor finishes the move command. This behavior is designed to enable partially overlapping concurrent operation of multiple motors.

Parameters:
  • amount (float) – The amount to move the motor by. Depending on the value of the ‘absolute’ argument, this can either be the exact position to move the motor to or the number of displacement units to move the motor by.

  • absolute (bool) – A boolean flag that determines whether the input displacement amount is the absolute position to move the motor to (relative to home sensor position) or a displacement value to move the motor by (relative to its current absolute position).

  • native (bool, default: False) – A boolean flag that determines whether the input amount is given in metric displacement units of the motor or in native motor units.

Return type:

None

property name: str

‘Pitch_Axis’.

Type:

Returns the user-defined string-name of the motor axis, e.g.

park()

Parks the motor, which makes it unresponsive to motor commands and stores current absolute motor position in non-volatile memory.

This method is mostly used to avoid re-homing the device after power cycling, as parking ensures the reference point for the motor is maintained in non-volatile memory. Additionally, parking is used to lock the motor in place as an additional safety measure.

Return type:

None

property park_position: int

Returns the absolute position, in native motor units, where the motor needs to be moved before it is parked.

This position is applied to the motor before parking to promote a safe homing procedure once the motor is unparked. Parking the motor in a predetermined position avoids colliding with other objects in the environment during homing and provides a starting point for calibrating the motor’s position for new animals.

shutdown()

Prepares the motor for shutting down by moving the motor to a hardware-defined shutdown parking position.

This method has to be called at the end of each class runtime to ensure the class can be reused without manual intervention later.

Return type:

None

Notes

This method contains the guards that prevent it from being executed if the motor has already been shut down.

stop()

Decelerates and stops the motor.

Unlike most other motion commands, this command can be executed to interrupt any other already running motor command. This method is especially relevant during emergencies, as it has the potential to immediately stop the motor.

Return type:

None

Notes

Calling this method once instructs the motor to decelerate and stop. Calling this method twice in a row instructs the motor to stop immediately (without deceleration). Using this method for immediate shutdowns can have negative consequences for the motor and / or the load of the motor and other motors (axes) of the device.

This command does not block until the motor stops to allow stopping multiple motors (axes) in rapid succession.

unpark()

Unparks a parked motor, which allows the motor to accept and execute motion commands.

Return type:

None

property valve_position: int

Returns the absolute position, in native motor units, where the motor needs to be moved before calibrating the water reward valve of the Mesoscope-VR system.

Applying this position to the motor orients the headbar and lickport system in a way that provides easy access to the components of the water delivery system. In turn, this simplifies calibrating, flushing, and filling the system with water.

class sl_experiment.zaber_bindings.ZaberConnection(port)

Bases: object

Interfaces with a serial USB port and all Zaber devices (controllers) and axes (motors) available through that port.

This class exposes methods for connecting to and disconnecting from all Zaber peripherals that use a given USB port. Additionally, the class automates certain procedures, such as setting up and shutting down all associated peripherals as part of its connection or disconnection runtimes.

Notes

This class functions as the highest level of the tri-class Zaber binding hierarchy. A single serial connection can be used to access multiple Zaber devices (motor controllers), with each device managing a single axis (motor).

This class does not automatically initialize the connection with the port. Use the connect() method to connect to the port managed by this class.

Parameters:

port (str) – The name of the USB port used by this connection instance (eg: COM1, USB0, etc.). Use discover_zaber_devices() to determine the USB pots used by Zaber devices.

_port

Stores the name of the serial port used by the connection.

_connection

The Connection class instance is used to physically manage the connection. Initializes to a None placeholder until the connection is established via the connect() method.

_devices

The tuple of ZaberDevice class instances used to interface with Zaber devices available through the connected port. Initializes to an empty tuple placeholder.

_is_connected

The boolean flag that communicates the current connection state.

Raises:

TypeError – If the provided ‘port’ argument type is not a string.

__del__()

Ensures that the connection is shut down gracefully whenever the class instance is deleted.

Return type:

None

__repr__()

Constructs and returns a string that represents the class.

Return type:

str

connect()

Opens the serial port and automatically detects and connects to any available Zaber devices (controllers).

Depending on the input arguments, the method may also raise or print exception messages to inform the user of the cause of the runtime failure.

Raises:

NoDeviceFoundException – If no compatible Zaber devices are discovered using the target serial port.

Return type:

None

property device_count: int

Returns the number of Zaber devices using this connection.

property device_information: dict[int, Any]

Returns a dictionary that provides the basic ID information about all Zaber devices using this connection.

disconnect()

Shuts down all controlled Zaber devices and closes the connection.

Return type:

None

Notes

Make sure it is safe to park the motor before this method is called. Calling it will move the motor which may damage the environment or motors.

Specifically, loops over each connected device and triggers its shutdown() method to execute the necessary pre-disconnection procedures. Then, disconnects from the serial port and clears the device list.

get_device(index=0)

Returns the ZaberDevice class reference for the device under the requested index.

Parameters:

index (int, default: 0) – The index of the device class to retrieve. Use the device_information property to find the indices of the devices available through this connection. Valid indices start with 0 for the first device and cannot exceed the value of the device_count property. Defaults to 0.

Return type:

ZaberDevice

Returns:

A ZaberDevice class object used to control the requested device.

Raises:
  • TypeError – If the index argument is not of the correct type.

  • ValueError – If the input index is outside the valid range of indices, or if this method is called for a connection that does not have any associated ZaberDevice class instances.

property is_connected: bool

Returns True if the class has established connection with the managed serial port.

property port: str

Returns the name of the serial port used by the connection.

class sl_experiment.zaber_bindings.ZaberDevice(device)

Bases: object

Manages a single Zaber device (controller) and all of its axes (motors).

This class represents a single Zaber controller device, which contains independent CPU and volatile / non-volatile addressable memory. Depending on the model, a single device can control between one and four axes (motor drivers). Each device has a fairly high degree of closed-loop autonomy and, as such, is treated as a standalone external system.

Notes

This class is explicitly designed to work with devices that manage a single axis (motor). It will raise errors if it is initialized for a controller with more than a single axis.

Parameters:

device (Device) – The Device class instance that manages the controller. This should be automatically instantiated by the ZaberConnection class that discovers and binds the device.

_device

The Device class instance that handles all low-level manipulations necessary to control the device.

_id

The unique numeric ID of the device. Typically, this is hardcoded by the manufacturer.

_name

The name of the device, typically written to hardware non-volatile memory by the manufacturer (e.g.: ‘CTX102’).

_label

The user-defined name of the device. This name is assigned during initial configuration, and for any well-configured controller (device) the USER_DATA_0 non-volatile variable should always store the CRC32-XFER checksum of this label (using ASCII protocol to convert the label to bytes).

_crc_calculator

An instance of the CRCCalculator() class used to verify the device_code against the checksum of the device label.

_axis

Stores the ZaberAxis class instance used to interface with the motor managed by this Device instance.

_shutdown_flag

A boolean flag that locally tracks the shutdown status of the device.

Raises:
  • RuntimeError – If the device_code stored in the device’s non-volatile memory does not match the CRC32-XFER checksum of the device label. Also, if the device shutdown tracker is not set to 1 (if the device has not been properly shut down during the previous runtime).

  • ValueError – If the device manages more than a single axis (motor).

  • TypeError – If any of the initialization argument types do not match the expected types.

__repr__()

Constructs and returns a string that represents the class.

Return type:

str

property axis: ZaberAxis

Returns the ZaberAxis class reference for the axis (motor) managed by the ZaberDevice instance.

property axis_information: dict[str, str]

Returns a dictionary that provides the basic ID information about the axis controlled by this device.

property id: int

Returns the unique numeric ID of the device.

property label: str

Returns the label (user-assigned descriptive name) of the device.

property name: str

Returns the name (manufacturer-assigned hardware name) of the device.

shutdown()

Shuts down the axis (motor) managed by the device and changes the shutdown tracker non-volatile variable of the device to 1.

Return type:

None

Notes

This method is intended to be called by the parent ZaberConnection class as part of the disconnect() method runtime.

class sl_experiment.zaber_bindings._ZaberSettings(device_temperature='system.temperature', axis_maximum_speed='maxspeed', axis_acceleration='accel', axis_maximum_limit='limit.max', axis_minimum_limit='limit.min', axis_temperature='driver.temperature', axis_inversion='driver.dir', axis_position='pos', device_code='user.data.0', device_shutdown_flag='user.data.1', axis_linear_flag='user.data.10', axis_park_position='user.data.11', axis_calibration_position='user.data.12', axis_mount_position='user.data.13')

Bases: object

Maps Zaber setting codes to descriptive names.

This class functions as an additional abstraction layer that simplifies working with Zaber device and axis setting interface.

Notes

This class only lists the settings used by the classes of this module and does not cover all available Zaber settings.

axis_acceleration: str = 'accel'

The maximum rate at which the motor increases or decreases its speed during motion. This rate is used to transition between maximum speed and idleness.

axis_calibration_position: str = 'user.data.12'

The absolute position, in native motor units, where the motor should be moved for the water valve calibration procedure. This position is optimized for collecting a large volume of water that will be dispensed through the valve during calibration. Uses USER_DATA 12 variable.

axis_inversion: str = 'driver.dir'

A boolean flag that determines whether the motor is inverted (True) or not (False). From the perspective of the motor, this determines whether moving towards home constitutes ‘negative’ displacement (default) or ‘positive’ displacement.

axis_linear_flag: str = 'user.data.10'

The boolean flag that specifies if axis 1 motor is linear or rotary. This indirectly controls how this library interfaces with the motor. Uses USER_DATA 10 variable.

axis_maximum_limit: str = 'limit.max'

The maximum absolute position the motor is allowed to reach, relative to the home position.

axis_maximum_speed: str = 'maxspeed'

The maximum speed (velocity) of the motor. During motion, the motor accelerates until it reaches the speed defined by this parameter.

axis_minimum_limit: str = 'limit.min'

The minimum absolute position the motor is allowed to reach, relative to the home position.

axis_mount_position: str = 'user.data.13'

The absolute position, in native motor units, where the motor should be moved before mounting the animal onto the VR rig. This is a fallback position used for animals that do not have a calibrated HeadBar and LickPort position to restore between sessions. For most animals, this set of positions will only be used once, during the first training session.

axis_park_position: str = 'user.data.11'

The absolute position, in native motor units, where the motor should be moved to before parking and shutting down. This is used to ensure the motor will not collide with any physical boundaries when it is homed after re-connection. Uses USER_DATA 11 variable.

axis_position: str = 'pos'

The current absolute position of the motor relative to its home position.

axis_temperature: str = 'driver.temperature'

The temperature of the motor (driver) in degrees Celsius.

device_code: str = 'user.data.0'

The CRC32 checksum that should match the checksum of the device’s label. This value is used to confirm that the device has been configured to work with the bindings exposed from this library. Uses USER_DATA 0 variable.

device_shutdown_flag: str = 'user.data.1'

The boolean flag that tracks whether the device has been properly shut down during the previous runtime. This acts as a secondary verification mechanism to ensure that the device has been set to the correct parking position before connection cycles. Uses USER_DATA 1 variable.

device_temperature: str = 'system.temperature'

The temperature of the controller device CPU in degrees Celsius.

class sl_experiment.zaber_bindings._ZaberUnits(zaber_units_conversion=<factory>, unit_type='millimeters')

Bases: object

Exposes methods for selecting appropriate Zaber units used when communicating with the motor, based on the selected motor type and colloquial unit family.

This class is primarily designed to de-couple colloquial unit names used by our API from the Zaber-defined unit names, which is critical for reading and writing hardware settings and when issuing certain commands. To do so, after the initial configuration, use class properties to retrieve the necessary units (e.g: for displacement, velocity, or acceleration).

property acceleration_units: Units

Returns the Units class instance used to work with acceleration data.

Note, all acceleration units are given in units / seconds^2.

property displacement_units: Units

Returns the Units class instance used to work with displacement (length) data.

unit_type: str = 'millimeters'

millimeters) being used. Currently, this class only supports two families of units: millimeters and degrees.

Type:

Tracks the ‘family’ of the units (e.g

property velocity_units: Units

Returns the Units class instance used to work with velocity (speed) data.

Note, all velocity units are given in units / seconds.

zaber_units_conversion: dict[str, Any]

The dictionary that maps colloquial unit names to Zaber unit classes.

sl_experiment.zaber_bindings._attempt_connection(port)

Checks the input USB port for Zaber devices (controllers) and parses ID information for any discovered device.

Parameters:

port (str) – The name of the USB port to scan for Zaber devices (eg: COM1, USB0, etc.).

Return type:

dict[int, Any] | str

Returns:

The dictionary with the ID information of the discovered device(s), if zaber devices were discovered. If zaber devices were not found, returns the error message

sl_experiment.zaber_bindings._format_device_info(device_info)
Formats the device and axis ID information discovered during port scanning as a table before displaying it to

the user.

Parameters:

device_info (dict[str, Any]) – The dictionary containing the device and axis ID information for each scanned port.

Return type:

str

Returns:

A string containing the formatted device and axis ID information as a table.

sl_experiment.zaber_bindings._scan_active_ports()

Scans all available Serial (USB) ports and, for each port, returns the ID data for each connected Zaber device.

This method is intended to be used during the initial device configuration and testing to quickly discover what Zaber devices are available on the host-system. Additionally, it returns device configuration information, which is helpful during debugging and calibration.

Return type:

tuple[dict[str, Any], tuple[str, ...]]

Returns:

A tuple with two elements. The first element contains the dictionary that uses port names as keys and either lists all discovered zaber devices alongside their ID information or ‘None’ if any given port does not have discoverable Zaber devices. The second element is a tuple of error messages encountered during the scan.

sl_experiment.zaber_bindings.discover_zaber_devices(silence_errors=True)

Scans all available serial ports and displays information about connected Zaber devices.

Parameters:

silence_errors (bool, default: True) – Determines whether to display encountered errors. By default, when the discovery process runs into an error, it labels the error port as having no devices and suppresses the error. Enabling this flag will also print encountered error messages, which may be desirable for debugging purposes.

Return type:

None

AXMC Module Interfaces

This module provides the interfaces (ModuleInterface implementations) for the hardware used by the Mesoscope-VR system. These interfaces are designed to work with the hardware modules assembled and configured according to the instructions from our microcontrollers’ library: https://github.com/Sun-Lab-NBB/sl-micro-controllers.

class sl_experiment.module_interfaces.BreakInterface(minimum_break_strength=43.2047, maximum_break_strength=1152.1246, object_diameter=15.0333, debug=False)

Bases: ModuleInterface

Interfaces with BreakModule instances running on Ataraxis MicroControllers.

BreakModule allows interfacing with a break to dynamically control the motion of break-coupled objects. The module is designed to send PWM signals that trigger Field-Effect-Transistor (FET) gated relay hardware to deliver voltage that variably engages the break. The module can be used to either fully engage or disengage the breaks or to output a PWM signal to engage the break with the desired strength.

Notes

The break will notify the PC about its initial state (Engaged or Disengaged) after setup.

This class is explicitly designed to work with an 8-bit Pulse Width Modulation (PWM) resolution. Specifically, it assumes that there are a total of 255 intervals covered by the whole PWM range when it calculates conversion factors to go from PWM levels to torque and force.

Parameters:
  • minimum_break_strength (float, default: 43.2047) – The minimum torque applied by the break in gram centimeter. This is the torque the break delivers at minimum voltage (break is disabled).

  • maximum_break_strength (float, default: 1152.1246) – The maximum torque applied by the break in gram centimeter. This is the torque the break delivers at maximum voltage (break is fully engaged).

  • object_diameter (float, default: 15.0333) – The diameter of the rotating object connected to the break, in centimeters. This is used to calculate the force at the end of the object associated with each torque level of the break.

  • debug (bool, default: False) – A boolean flag that configures the interface to dump certain data received from the microcontroller into the terminal. This is used during debugging and system calibration and should be disabled for most runtimes.

_newton_per_gram_centimeter

Conversion factor from torque force in g cm to torque force in N cm.

_minimum_break_strength

The minimum torque the break delivers at minimum voltage (break is disabled) in N cm.

_maximum_break_strength

The maximum torque the break delivers at maximum voltage (break is fully engaged) in N cm.

_torque_per_pwm

Conversion factor from break pwm levels to breaking torque in N cm.

_force_per_pwm

Conversion factor from break pwm levels to breaking force in N at the edge of the object.

_debug

Stores the debug flag.

property force_per_pwm: float64

Returns the conversion factor to translate break pwm levels into breaking force in Newtons.

get_pwm_from_torque(target_torque_n_cm)

Converts the desired breaking torque in Newtons centimeter to the required PWM value (0-255) to be delivered to the break hardware by the BreakModule.

Use this method to convert the desired breaking torque into the PWM value that can be submitted to the BreakModule via the set_parameters() class method.

Parameters:

target_torque_n_cm (float) – Desired torque in Newtons centimeter at the edge of the object.

Return type:

uint8

Returns:

The byte PWM value that would generate the desired amount of torque.

Raises:

ValueError – If the input force is not within the valid range for the BreakModule.

initialize_remote_assets()

Not used.

Return type:

None

property maximum_break_strength: float64

Returns the maximum torque of the break in Newton centimeters.

property minimum_break_strength: float64

Returns the minimum torque of the break in Newton centimeters.

parse_mqtt_command(topic, payload)

Not used.

Return type:

None

process_received_data(message)

During debug runtime, dumps the data received from the module into the terminal.

Currently, this method only works with codes 52 (Engaged) and 53 (Disengaged).

Return type:

None

Notes

The method is not used during non-debug runtimes. If the interface runs in debug mode, make sure the console is enabled, as it is used to print received data into the terminal.

set_breaking_power()

Triggers the BreakModule to engage with the strength (torque) defined by the breaking_strength runtime parameter.

Unlike the toggle() method, this method allows precisely controlling the torque applied by the break. This is achieved by pulsing the break control pin at the PWM level specified by breaking_strength runtime parameter stored in BreakModule’s memory (on the microcontroller).

Return type:

None

Notes

This command switches the break to run in the variable strength mode and applies the current value of the breaking_strength parameter to the break, but it does not determine the breaking power. To adjust the power, use the set_parameters() class method to issue an updated breaking_strength value. By default, the break power is set to 50% (PWM value 128).

set_parameters(breaking_strength=np.uint8(255))

Changes the PC-addressable runtime parameters of the BreakModule instance.

Use this method to package and apply new PC-addressable parameters to the BreakModule instance managed by this Interface class.

Notes

Use set_breaking_power() command to apply the breaking-strength transmitted in this parameter message to the break. Until the command is called, the new breaking_strength will not be applied to the break hardware.

Parameters:

breaking_strength (uint8, default: np.uint8(255)) – The Pulse-Width-Modulation (PWM) value to use when the BreakModule delivers adjustable breaking power. Depending on this value, the breaking power can be adjusted from none (0) to maximum (255). Use get_pwm_from_force() to translate the desired breaking torque into the required PWM value.

Return type:

None

terminate_remote_assets()

Not used.

Return type:

None

toggle(state)

Triggers the BreakModule to be permanently engaged at maximum strength or permanently disengaged.

This command locks the BreakModule managed by this Interface into the desired state.

Notes

This command does NOT use the breaking_strength parameter and always uses either maximum or minimum breaking power. To set the break to a specific torque level, set the level via the set_parameters() method and then switch the break into the variable torque mode by using the set_breaking_power() method.

Parameters:

state (bool) – The desired state of the break. True means the break is engaged; False means the break is disengaged.

Return type:

None

property torque_per_pwm: float64

Returns the conversion factor to translate break pwm levels into breaking torque in Newton centimeters.

class sl_experiment.module_interfaces.EncoderInterface(encoder_ppr=8192, object_diameter=15.0333, cm_per_unity_unit=10.0, debug=False)

Bases: ModuleInterface

Interfaces with EncoderModule instances running on Ataraxis MicroControllers.

EncoderModule allows interfacing with quadrature encoders used to monitor the direction and magnitude of a connected object’s rotation. To achieve the highest resolution, the module relies on hardware interrupt pins to detect and handle the pulses sent by the two encoder channels.

Notes

This interface sends CW and CCW motion data to Unity via ‘LinearTreadmill/Data’ MQTT topic.

The default initial encoder readout is zero (no CW or CCW motion). The class instance is zeroed at communication initialization.

Parameters:
  • encoder_ppr (int, default: 8192) – The resolution of the managed quadrature encoder, in Pulses Per Revolution (PPR). This is the number of quadrature pulses the encoder emits per full 360-degree rotation. If this number is not known, provide a placeholder value and use the get_ppr () command to estimate the PPR using the index channel of the encoder.

  • object_diameter (float, default: 15.0333) – The diameter of the rotating object connected to the encoder, in centimeters. This is used to convert encoder pulses into rotated distance in cm.

  • cm_per_unity_unit (float, default: 10.0) – The length of each Unity ‘unit’ in centimeters. This is used to translate raw encoder pulses into Unity ‘units’ before sending the data to Unity.

  • debug (bool, default: False) – A boolean flag that configures the interface to dump certain data received from the microcontroller into the terminal. This is used during debugging and system calibration and should be disabled for most runtimes.

_motion_topic

Stores the MQTT motion topic.

_ppr

Stores the resolution of the managed quadrature encoder.

_object_diameter

Stores the diameter of the object connected to the encoder.

_cm_per_pulse

Stores the conversion factor that translates encoder pulses into centimeters.

_unity_unit_per_pulse

Stores the conversion factor to translate encoder pulses into Unity units.

_communication

Stores the communication class used to send data to Unity over MQTT.

_debug

Stores the debug flag.

_distance_tracker

Stores the SharedMemoryArray that stores the absolute distance traveled by the animal since class initialization, in centimeters. Note, the distance does NOT account for the direction of travel. It is a monotonically incrementing count of traversed centimeters.

__del__()

Ensures the speed_tracker is properly cleaned up when the class is garbage-collected.

Return type:

None

check_state(repetition_delay=np.uint32(200))

Returns the number of pulses accumulated by the EncoderModule since the last check or reset.

If there has been a significant change in the absolute count of pulses, reports the change and direction to the PC. It is highly advised to issue this command to repeat (recur) at a desired interval to continuously monitor the encoder state, rather than repeatedly calling it as a one-off command for best runtime efficiency.

This command allows continuously monitoring the rotation of the object connected to the encoder. It is designed to return the absolute raw count of pulses emitted by the encoder in response to the object ration. This allows avoiding floating-point arithmetic on the microcontroller and relies on the PC to convert pulses to standard units, such as centimeters. The specific conversion algorithm depends on the encoder and motion diameter.

Parameters:

repetition_delay (uint32, default: np.uint32(200)) – The time, in microseconds, to delay before repeating the command. If set to 0, the command will only run once.

Return type:

None

property cm_per_pulse: float64

Returns the conversion factor to translate raw encoder pulse count to distance moved in centimeters.

property distance_tracker: SharedMemoryArray

Returns the SharedMemoryArray that stores the total distance, in centimeters, traveled by the animal since runtime onset.

The distance is stored under index 0 of the tracker and uses the float64 datatype. Note, the distance does NOT account for the direction of travel. It is a monotonically incrementing count of traversed centimeters.

get_ppr()

Uses the index channel of the EncoderModule to estimate its Pulse-per-Revolution (PPR).

The PPR allows converting raw pulse counts the EncoderModule sends to the PC to accurate displacement in standard distance units, such as centimeters. This is a service command not intended to be used during most runtimes if the PPR is already known. It relies on the object tracked by the encoder completing up to 11 full revolutions and uses the index channel of the encoder to measure the number of pulses per each revolution.

Return type:

None

Notes

Make sure the evaluated encoder rotates at a slow and stead speed until this command completes. Similar to other service commands, it is designed to deadlock the controller until the command completes. Note, the EncoderModule does not provide the rotation, this needs to be done manually.

The direction of the rotation is not relevant for this command, as long as the object makes the full 360-degree revolution.

The command is optimized for the object to be rotated with a human hand at a steady rate, so it delays further index pin polling for 100 milliseconds each time the index pin is triggered. Therefore, if the object is moving too fast (or too slow), the command will not work as intended.

initialize_remote_assets()

Initializes the MQTTCommunication class and connects to the MQTT broker.

Also connects to the speed_tracker SharedMemoryArray and initializes the PrecisionTimer used in running speed calculation.

Return type:

None

property mqtt_topic: str

Returns the MQTT topic used to transfer motion data from the interface to Unity.

parse_mqtt_command(topic, payload)

Not used.

Return type:

None

process_received_data(message)

Processes incoming data in real time.

Motion data (codes 51 and 52) is converted into CW / CCW vectors, translated from pulses to Unity units, and is sent to Unity via MQTT. Encoder PPR data (code 53) is printed via console.

Also, keeps track of the total distance traveled by the animal since class initialization, relative to the initial position at runtime onset and updates the distance_tracker SharedMemoryArray.

Return type:

None

Notes

If debug mode is enabled, motion data is also converted to centimeters and printed via console.

reset_pulse_count()

Resets the EncoderModule pulse tracker to 0.

This command allows resetting the encoder without evaluating its current pulse count. Currently, this command is designed to only run once.

Return type:

None

set_parameters(report_ccw=np.True_, report_cw=np.True_, delta_threshold=np.uint32(10))

Changes the PC-addressable runtime parameters of the EncoderModule instance.

Use this method to package and apply new PC-addressable parameters to the EncoderModule instance managed by this Interface class.

Parameters:
  • report_ccw (bool | bool, default: np.True_) – Determines whether to report rotation in the CCW (positive) direction.

  • report_cw (bool | bool, default: np.True_) – Determines whether to report rotation in the CW (negative) direction.

  • delta_threshold (uint32 | int, default: np.uint32(10)) – The minimum number of pulses required for the motion to be reported. Depending on encoder resolution, this allows setting the ‘minimum rotation distance’ threshold for reporting. Note, if the change is 0 (the encoder readout did not change), it will not be reported, regardless of the value of this parameter. Sub-threshold motion will be aggregated (summed) across readouts until a significant overall change in position is reached to justify reporting it to the PC.

Return type:

None

terminate_remote_assets()

Destroys the MQTTCommunication class and disconnects from the speed_tracker SharedMemoryArray.

Return type:

None

class sl_experiment.module_interfaces.LickInterface(lick_threshold=1000, debug=False)

Bases: ModuleInterface

Interfaces with LickModule instances running on Ataraxis MicroControllers.

LickModule allows interfacing with conductive lick sensors used in the Sun Lab to detect mouse interaction with water dispensing tubes. The sensor works by sending a small direct current through the mouse, which is picked up by the sensor connected to the metal lick tube. When the mouse completes the circuit by making the contact with the tube, the sensor determines whether the resultant voltage matches the threshold expected for a tongue contact and, if so, notifies the PC about the contact.

Notes

The sensor is calibrated to work with very small currents that are not detectable by the animal, so it does not interfere with behavior during experiments. The sensor will, however, interfere with electrophysiological recordings.

The resolution of the sensor is high enough to distinguish licks from paw touches. By default, the microcontroller is configured in a way that will likely send both licks and non-lick interactions to the PC. Use the lick_threshold argument to provide a more exclusive lick threshold.

The interface automatically sends significant lick triggers to Unity via the “LickPort/” MQTT topic. This only includes the ‘onset’ triggers, the interface does not report voltage level reductions (associated with the end of the tongue-to-tube contact).

Parameters:
  • lick_threshold (int, default: 1000) – The threshold voltage, in raw analog units recorded by a 12-bit ADC, for detecting the tongue contact. Note, 12-bit ADC only supports values between 0 and 4095, so setting the threshold above 4095 will result in no licks being reported to Unity.

  • debug (bool, default: False) – A boolean flag that configures the interface to dump certain data received from the microcontroller into the terminal. This is used during debugging and system calibration and should be disabled for most runtimes.

_sensor_topic

Stores the output MQTT topic.

_lick_threshold

The threshold voltage for detecting a tongue contact.

_volt_per_adc_unit

The conversion factor to translate the raw analog values recorded by the 12-bit ADC into voltage in Volts.

_communication

Stores the communication class used to send data to Unity over MQTT.

_debug

Stores the debug flag.

_lick_tracker

Stores the SharedMemoryArray that stores the current lick detection status and the total number of licks detected since class initialization.

__del__()

Ensures the lick_tracker is properly cleaned up when the class is garbage-collected.

Return type:

None

check_state(repetition_delay=np.uint32(0))

Returns the voltage signal detected by the analog pin monitored by the LickModule.

If there has been a significant change in the detected voltage level and the level is within the reporting thresholds, reports the change to the PC. It is highly advised to issue this command to repeat (recur) at a desired interval to continuously monitor the lick sensor state, rather than repeatedly calling it as a one-off command for best runtime efficiency.

This command allows continuously monitoring the mouse interaction with the lickport tube. It is designed to return the raw analog units, measured by a 3.3V ADC with 12-bit resolution. To avoid floating-point math, the value is returned as an unsigned 16-bit integer.

Parameters:
  • repetition_delay (uint32, default: np.uint32(0)) – The time, in microseconds, to delay before repeating the command. If set to 0, the

  • once. (command will only run)

Return type:

None

get_adc_units_from_volts(voltage)

Converts the input voltage to raw analog units of 12-bit Analog-to-Digital-Converter (ADC).

Use this method to determine the appropriate raw analog units for the threshold arguments of the set_parameters() method, based on the desired voltage thresholds.

Notes

This method assumes a 3.3V ADC with 12-bit resolution.

Parameters:

voltage (float) – The voltage to convert to raw analog units, in Volts.

Return type:

uint16

Returns:

The raw analog units of 12-bit ADC for the input voltage.

initialize_remote_assets()

Initializes the MQTTCommunication class, connects to the MQTT broker, and connects to the SharedMemoryArray used to communicate lick status to other processes.

Return type:

None

property lick_threshold: uint16

Returns the voltage threshold, in raw ADC units of a 12-bit Analog-to-Digital voltage converter that is interpreted as the mouse licking the sensor.

property lick_tracker: SharedMemoryArray

Returns the SharedMemoryArray that stores the total number of licks detected by the module since class initialization.

The count is stored under index 0 of the array as an uint64 value.

property mqtt_topic: str

Returns the MQTT topic used to transfer lick events from the interface to Unity.

parse_mqtt_command(topic, payload)

Not used.

Return type:

None

process_received_data(message)

Processes incoming data.

Lick data (code 51) comes in as a change in the voltage level detected by the sensor pin. This value is then evaluated against the _lick_threshold and if the value exceeds the threshold, a binary lick trigger is sent to Unity via MQTT. Additionally, the method increments the total lick count stored in the _lick_tracker each time an above-threshold voltage readout is received from the module.

Return type:

None

Notes

If the class runs in debug mode, this method sends all received lick sensor voltages to the terminal via console. Make sure the console is enabled before calling this method.

set_parameters(signal_threshold=np.uint16(200), delta_threshold=np.uint16(180), averaging_pool_size=np.uint8(30))

Changes the PC-addressable runtime parameters of the LickModule instance.

Use this method to package and apply new PC-addressable parameters to the LickModule instance managed by this Interface class.

Notes

All threshold parameters are inclusive! If you need help determining appropriate threshold levels for specific targeted voltages, use the get_adc_units_from_volts() method of the interface instance.

Parameters:
  • signal_threshold (uint16, default: np.uint16(200)) – The minimum voltage level, in raw analog units of 12-bit Analog-to-Digital-Converter (ADC), that needs to be reported to the PC. Setting this threshold to a number above zero allows high-pass filtering the incoming signals. Note, Signals below the threshold will be pulled to 0.

  • delta_threshold (uint16, default: np.uint16(180)) – The minimum value by which the signal has to change, relative to the previous check, for the change to be reported to the PC. Note, if the change is 0, the signal will not be reported to the PC, regardless of this parameter value.

  • averaging_pool_size (uint8, default: np.uint8(30)) – The number of analog pin readouts to average together when checking pin state. This is used to smooth the recorded values to avoid communication line noise. Teensy microcontrollers have built-in analog pin averaging, but we disable it by default and use this averaging method instead. It is recommended to set this value between 15 and 30 readouts.

Return type:

None

terminate_remote_assets()

Destroys the MQTTCommunication class and disconnects from the lick-tracker SharedMemoryArray.

Return type:

None

property volts_per_adc_unit: float64

Returns the conversion factor to translate the raw analog values recorded by the 12-bit ADC into voltage in Volts.

class sl_experiment.module_interfaces.ScreenInterface(initially_on, debug=False)

Bases: ModuleInterface

Interfaces with ScreenModule instances running on Ataraxis MicroControllers.

ScreenModule is specifically designed to interface with the HDMI converter boards used in Sun lab’s Virtual Reality setup. The ScreenModule communicates with the boards to toggle the screen displays on and off, without interfering with their setup on the host PC.

Notes

Since the current VR setup uses three screens, this implementation of ScreenModule is designed to interface with all three screens at the same time. In the future, the module may be refactored to allow addressing individual screens.

The physical wiring of the module also allows manual screen manipulation via the buttons on the control panel if the ScreenModule is not actively delivering a toggle pulse. However, changing the state of the screen manually is strongly discouraged, as it interferes with tracking the state of the screen via software.

Parameters:
  • initially_on (bool) – A boolean flag that communicates the initial state of the screen. This is used during log parsing to deduce the state of the screen after each toggle pulse and assumes the screens are only manipulated via this interface.

  • debug (bool, default: False) – A boolean flag that configures the interface to dump certain data received from the microcontroller into the terminal. This is used during debugging and system calibration and should be disabled for most runtimes.

_initially_on

Stores the initial state of the screens.

_debug

Stores the debug flag.

initialize_remote_assets()

Not used.

Return type:

None

property initially_on: bool

Returns True if the screens were initially ON when the module interface was initialized, False otherwise.

parse_mqtt_command(topic, payload)

Not used.

Return type:

None

process_received_data(message)

If the class runs in the debug mode, dumps the received data into the terminal via console class.

This method is only used in the debug mode to print Screen toggle signal HIGH (On) and LOW (Off) phases.

Return type:

None

Notes

This method uses the console to print the data to the terminal. Make sure it is enabled before calling this method.

set_parameters(pulse_duration=np.uint32(1000000))

Changes the PC-addressable runtime parameters of the ScreenModule instance.

Use this method to package and apply new PC-addressable parameters to the ScreenModule instance managed by this Interface class.

Parameters:

pulse_duration (uint32, default: np.uint32(1000000)) – The duration, in microseconds, of each emitted screen toggle pulse HIGH phase. This is equivalent to the duration of the control panel POWER button press. The main criterion for this parameter is to be long enough for the converter board to register the press.

Return type:

None

terminate_remote_assets()

Not used.

Return type:

None

toggle()

Triggers the ScreenModule to briefly simulate pressing the POWER button of the scree control board.

This command is used to turn the connected display on or off. The new state of the display depends on the current state of the display when the command is issued. Since the displays can also be controlled manually (via the physical control board buttons), the state of the display can also be changed outside this interface, although it is highly advised to NOT change screen states manually.

Return type:

None

Notes

It is highly recommended to use this command to manipulate display states, as it ensures that display state changes are logged for further data analysis.

class sl_experiment.module_interfaces.TTLInterface(module_id, report_pulses=False, debug=False)

Bases: ModuleInterface

Interfaces with TTLModule instances running on Ataraxis MicroControllers.

TTLModule facilitates exchanging Transistor-to-Transistor Logic (TTL) signals between various hardware systems, such as microcontrollers, cameras and recording devices. The module contains methods for both sending and receiving TTL pulses, but each TTLModule instance can only perform one of these functions at a time.

Notes

When the TTLModule is configured to output a signal, it will notify the PC about the initial signal state (HIGH or LOW) after setup.

Parameters:
  • module_id (uint8) – The unique byte-code identifier of the TTLModule instance. Since the mesoscope data acquisition pipeline uses multiple TTL modules on some microcontrollers, each instance running on the same microcontroller must have a unique identifier. The ID codes are not shared between AMC and other module types.

  • report_pulses (bool, default: False) – A boolean flag that determines whether the class should report detecting HIGH signals to other processes. This is intended exclusively for the mesoscope frame acquisition recorder to notify the central process whether the mesoscope start trigger has been successfully received and processed by ScanImage software.

  • debug (bool, default: False) – A boolean flag that configures the interface to dump certain data received from the microcontroller into the terminal. This is used during debugging and system calibration and should be disabled for most runtimes.

_report_pulses

Stores the report pulses flag.

_debug

Stores the debug flag.

_pulse_tracker

When the class is initialized with the report_pulses flag, stores the SharedMemoryArray used to track how many pulses the class has recorded since initialization.

__del__()

Destroys the _pulse_tracker memory buffer and releases the resources reserved by the array during class runtime.

Return type:

None

check_state(repetition_delay=np.uint32(0))

Checks the state of the TTL signal received by the TTLModule.

This command evaluates the state of the TTLModule’s input pin and, if it is different from the previous state, reports it to the PC. This approach ensures that the module only reports signal level shifts (edges), preserving communication bandwidth.

Parameters:

repetition_delay (uint32, default: np.uint32(0)) – The time, in microseconds, to delay before repeating the command. If set to 0, the command will only run once.

Return type:

None

initialize_remote_assets()

If the class is instructed to report detected HIGH incoming pulses, connects to the _pulse_tracker SharedMemoryArray.

Return type:

None

parse_mqtt_command(topic, payload)

Not used.

Return type:

None

process_received_data(message)

Processes incoming data when the class operates in debug or pulse reporting mode.

During debug runtimes, this method dumps all received data into the terminal via the console class. During pulse reporting runtimes, the class increments the _pulse_tracker array each time it encounters a HIGH TTL signal edge sent by the mesoscope to timestamp acquiring (scanning) a new frame.

Return type:

None

Notes

If the interface runs in debug mode, make sure the console is enabled, as it is used to print received data into the terminal.

property pulse_count: int

Returns the total number of received TTL pulses recorded by the class since initialization.

send_pulse(repetition_delay=np.uint32(0), noblock=True)

Triggers TTLModule to deliver a one-off or recurrent (repeating) digital TTL pulse.

This command is well-suited to carry out most forms of TTL communication, but it is adapted for comparatively low-frequency communication at 10-200 Hz. This is in contrast to PWM outputs capable of mHz or even Khz pulse oscillation frequencies.

Parameters:
  • repetition_delay (uint32, default: np.uint32(0)) – The time, in microseconds, to delay before repeating the command. If set to 0, the command will only run once. The exact repetition delay will be further affected by other modules managed by the same microcontroller and may not be perfectly accurate.

  • noblock (bool, default: True) – Determines whether the command should block the microcontroller while emitting the high phase of the pulse or not. Blocking ensures precise pulse duration, non-blocking allows the microcontroller to perform other operations while waiting, increasing its throughput.

Return type:

None

set_parameters(pulse_duration=np.uint32(10000), averaging_pool_size=np.uint8(0))

Changes the PC-addressable runtime parameters of the TTLModule instance.

Use this method to package and apply new PC-addressable parameters to the TTLModule instance managed by this Interface class.

Parameters:
  • pulse_duration (uint32, default: np.uint32(10000)) – The duration, in microseconds, of each emitted TTL pulse HIGH phase. This determines how long the TTL pin stays ON when emitting a pulse.

  • averaging_pool_size (uint8, default: np.uint8(0)) – The number of digital pin readouts to average together when checking pin state. This is used during the execution of the check_state () command to debounce the pin readout and acts in addition to any built-in debouncing.

Return type:

None

terminate_remote_assets()

If the class is instructed to report detected HIGH incoming pulses, disconnects from the _pulse_tracker SharedMemoryArray.

Return type:

None

toggle(state)

Triggers the TTLModule to continuously deliver a digital HIGH or LOW signal.

This command locks the TTLModule managed by this Interface into delivering the desired logical signal.

Parameters:

state (bool) – The signal to output. Set to True for HIGH and False for LOW.

Return type:

None

class sl_experiment.module_interfaces.TorqueInterface(baseline_voltage=2046, maximum_voltage=2750, sensor_capacity=720.0779, object_diameter=15.0333, debug=False)

Bases: ModuleInterface

Interfaces with TorqueModule instances running on Ataraxis MicroControllers.

TorqueModule interfaces with a differential torque sensor. The sensor uses differential coding in the millivolt range to communicate torque in the CW and the CCW direction. To convert and amplify the output of the torque sensor, it is wired to an AD620 microvolt amplifier instrument that converts the output signal into a single positive vector and amplifies its strength to Volts range.

The TorqueModule further refines the sensor data by ensuring that CCW and CW torque signals behave identically. Specifically, it adjusts the signal to scale from 0 to baseline proportionally to the detected torque, regardless of torque direction.

Notes

This interface receives torque as a positive uint16_t value from zero to at most 2046 raw analog units of 3.3v 12-bit ADC converter. The direction of the torque is reported by the event-code of the received message.

Parameters:
  • baseline_voltage (int, default: 2046) – The voltage level, in raw analog units measured by 3.3v ADC at 12-bit resolution after the AD620 amplifier, that corresponds to no (0) torque readout. Usually, for a 3.3v ADC, this would be around 2046 (the midpoint, ~1.65 V).

  • maximum_voltage (int, default: 2750) – The voltage level, in raw analog units measured by 3.3v ADC at 12-bit resolution after the AD620 amplifier, that corresponds to the absolute maximum torque detectable by the sensor. The best way to get this value is to measure the positive voltage level after applying the maximum CW (positive) torque. At most, this value can be 4095 (~3.3 V).

  • sensor_capacity (float, default: 720.0779) – The maximum torque detectable by the sensor, in grams centimeter (g cm).

  • object_diameter (float, default: 15.0333) – The diameter of the rotating object connected to the torque sensor, in centimeters. This is used to calculate the force at the edge of the object associated with the measured torque at the sensor.

  • debug (bool, default: False) – A boolean flag that configures the interface to dump certain data received from the microcontroller into the terminal. This is used during debugging and system calibration and should be disabled for most runtimes.

_newton_per_gram_centimeter

Stores the hardcoded conversion factor from gram centimeter to Newton centimeter.

_capacity_in_newtons_cm

The maximum torque detectable by the sensor in Newtons centimeter.

_torque_per_adc_unit

The conversion factor to translate raw analog 3.3v 12-bit ADC values to torque in Newtons centimeter.

_force_per_adc_unit

The conversion factor to translate raw analog 3.3v 12-bit ADC values to force in Newtons.

_debug

Stores the debug flag.

check_state(repetition_delay=np.uint32(0))

Returns the torque signal detected by the analog pin monitored by the TorqueModule.

If there has been a significant change in the detected signal (voltage) level and the level is within the reporting thresholds, reports the change to the PC. It is highly advised to issue this command to repeat (recur) at a desired interval to continuously monitor the lick sensor state, rather than repeatedly calling it as a one-off command for best runtime efficiency.

This command allows continuously monitoring the CW and CCW torque experienced by the object connected to the torque sensor. It is designed to return the raw analog units, measured by a 3.3V ADC with 12-bit resolution. To avoid floating-point math, the value is returned as an unsigned 16-bit integer.

Notes

Due to how the torque signal is measured and processed, the returned value will always be between 0 and the baseline ADC value. For a 3.3V 12-bit ADC, this is between 0 and ~1.65 Volts.

Parameters:
  • repetition_delay (uint32, default: np.uint32(0)) – The time, in microseconds, to delay before repeating the command. If set to 0, the

  • once. (command will only run)

Return type:

None

property force_per_adc_unit: float64

Returns the conversion factor to translate the raw analog values recorded by the 12-bit ADC into force in Newtons.

get_adc_units_from_torque(target_torque)

Converts the input torque to raw analog units of 12-bit Analog-to-Digital-Converter (ADC).

Use this method to determine the appropriate raw analog units for the threshold arguments of the set_parameters() method.

Notes

This method assumes a 3.3V ADC with 12-bit resolution.

Parameters:

target_torque (float) – The target torque in Newton centimeter, to convert to an ADC threshold.

Return type:

uint16

Returns:

The raw analog units of 12-bit ADC for the input torque.

initialize_remote_assets()

Not used.

Return type:

None

parse_mqtt_command(topic, payload)

Not used.

Return type:

None

process_received_data(message)

If the class is initialized in debug mode, prints the received torque data to the terminal via console.

Return type:

None

In debug mode, this method parses incoming code 51 (CW torque) and code 52 (CCW torque) data and dumps it into

the terminal via console. If the class is not initialized in debug mode, this method does nothing.

Notes

Make sure the console is enabled before calling this method.

set_parameters(report_ccw=np.True_, report_cw=np.True_, signal_threshold=np.uint16(100), delta_threshold=np.uint16(70), averaging_pool_size=np.uint8(10))

Changes the PC-addressable runtime parameters of the TorqueModule instance.

Use this method to package and apply new PC-addressable parameters to the TorqueModule instance managed by this Interface class.

Notes

All threshold parameters are inclusive! If you need help determining appropriate threshold levels for specific targeted torque levels, use the get_adc_units_from_torque() method of the interface instance.

Parameters:
  • report_ccw (bool, default: np.True_) – Determines whether the sensor should report torque in the CounterClockwise (CCW) direction.

  • report_cw (bool, default: np.True_) – Determines whether the sensor should report torque in the Clockwise (CW) direction.

  • signal_threshold (uint16, default: np.uint16(100)) – The minimum torque level, in raw analog units of 12-bit Analog-to-Digital-Converter (ADC), that needs to be reported to the PC. Setting this threshold to a number above zero allows high-pass filtering the incoming signals. Note, Signals below the threshold will be pulled to 0.

  • delta_threshold (uint16, default: np.uint16(70)) – The minimum value by which the signal has to change, relative to the previous check, for the change to be reported to the PC. Note, if the change is 0, the signal will not be reported to the PC, regardless of this parameter value.

  • averaging_pool_size (uint8, default: np.uint8(10)) – The number of analog pin readouts to average together when checking pin state. This is used to smooth the recorded values to avoid communication line noise. Teensy microcontrollers have built-in analog pin averaging, but we disable it by default and use this averaging method instead. It is recommended to set this value between 15 and 30 readouts.

Return type:

None

terminate_remote_assets()

Not used.

Return type:

None

property torque_per_adc_unit: float64

Returns the conversion factor to translate the raw analog values recorded by the 12-bit ADC into torque in Newton centimeter.

class sl_experiment.module_interfaces.ValveInterface(valve_calibration_data, debug=False)

Bases: ModuleInterface

Interfaces with ValveModule instances running on Ataraxis MicroControllers.

ValveModule allows interfacing with a solenoid valve to controllably dispense precise volumes of fluid. The module is designed to send digital signals that trigger Field-Effect-Transistor (FET) gated relay hardware to deliver voltage that opens or closes the controlled valve. The module can be used to either permanently open or close the valve or to cycle opening and closing in a way that ensures a specific amount of fluid passes through the valve.

Notes

This interface comes pre-configured to receive valve pulse triggers from Unity via the “Gimbl/Reward/” topic.

The valve will notify the PC about its initial state (Open or Closed) after setup.

Our valve is statically configured to deliver audible tones when it is pulsed. This is used exclusively by the Pulse command, so the tone will not sound when the valve is activated during Calibration or Open commands. The default pulse duration is 100 ms, and this is primarily used to provide the animal with an auditory cue for the water reward.

Parameters:
  • valve_calibration_data (tuple[tuple[int | float, int | float], ...]) – A tuple of tuples that contains the data required to map pulse duration to delivered fluid volume. Each sub-tuple should contain the integer that specifies the pulse duration in microseconds and a float that specifies the delivered fluid volume in microliters. If you do not know this data, initialize the class using a placeholder calibration tuple and use the calibration() class method to collect this data using the ValveModule.

  • debug (bool, default: False) – A boolean flag that configures the interface to dump certain data received from the microcontroller into the terminal. This is used during debugging and system calibration and should be disabled for most runtimes.

_scale_coefficient

Stores the scale coefficient derived from the calibration data. We use the power law to fit the data, which results in better overall fit than using the linera equation.

_nonlinearity_exponent

The intercept of the valve calibration curve. This is used to account for the fact that some valves may have a minimum open time or dispensed fluid volume, which is captured by the intercept. This improves the precision of fluid-volume-to-valve-open-time conversions.

_calibration_cov

Stores the covariance matrix that describes the quality of fitting the calibration data using the power law. This is used to determine how well the valve performance is approximated by the power law.

_reward_topic

Stores the topic used by Unity to issue reward commands to the module.

_debug

Stores the debug flag.

_valve_tracker

Stores the SharedMemoryArray that tracks how many times the valve was opened and the total volume of water dispensed by the valve during runtime.

_previous_state

Tracks the previous valve state as Open (True) or Closed (False). This is used to accurately track delivered water volumes each time the valve opens and closes.

_cycle_timer

A PrecisionTimer instance initialized in the Communication process to track how long the valve stays open during cycling. This used together with the _previous_state to determine the volume of water delivered by the valve during runtime.

__del__()

Ensures the reward_tracker is properly cleaned up when the class is garbage-collected.

Return type:

None

calibrate()

Triggers ValveModule to repeatedly pulse the valve using the duration defined by the pulse_duration runtime parameter.

This command is used to build the calibration map of the valve that matches pulse_duration to the volume of fluid dispensed during the time the valve is open. To do so, the command repeatedly pulses the valve to dispense a large volume of fluid which can be measured and averaged to get the volume of fluid delivered during each pulse. The number of pulses carried out during this command is specified by the calibration_count parameter, and the delay between pulses is specified by the calibration_delay parameter.

Return type:

None

Notes

When activated, this command will block in-place until the calibration cycle is completed. Currently, there is no way to interrupt the command, and it may take a prolonged period of time (minutes) to complete.

This command does not set any of the parameters involved in the calibration process. Make sure the parameters are submitted to the ValveModule’s hardware memory via the set_parameters() class method before running the calibration() command.

property calibration_covariance: ndarray[Any, dtype[float64]]

Returns the 2x2 covariance matrix associated with the power‐law calibration fit.

The covariance matrix contains the estimated variances of the calibration parameters on its diagonal (i.e., variance of the scale coefficient and the nonlinearity exponent) and the covariances between these parameters in its off-diagonal elements.

This information can be used to assess the uncertainty in the calibration.

Returns:

A NumPy array (2x2) representing the covariance matrix.

property delivered_volume: float

Returns the total volume of water, in microliters, delivered by the valve during the current runtime.

get_duration_from_volume(target_volume)

Converts the desired fluid volume in microliters to the valve pulse duration in microseconds that ValveModule will use to deliver that fluid volume.

Use this method to convert the desired fluid volume into the pulse_duration value that can be submitted to the ValveModule via the set_parameters() class method.

Parameters:

target_volume (float) – Desired fluid volume in microliters.

Raises:

ValueError – If the desired fluid volume is too small to be reliably dispensed by the valve, based on its calibration data.

Return type:

uint32

Returns:

The microsecond pulse duration that would be used to deliver the specified volume.

initialize_remote_assets()

Connects to the reward tracker SharedMemoryArray and initializes the cycle PrecisionTimer from the Communication process.

Return type:

None

property mqtt_topic: str

Returns the MQTT topic monitored by the module to receive reward commands from Unity.

property nonlinearity_exponent: float64

Returns the nonlinearity exponent (B) from the power‐law calibration.

In the calibration model, fluid_volume = A * (pulse_duration)^B, this exponent indicates the degree of nonlinearity in how the dispensed volume scales with the valve’s pulse duration. For example, an exponent of 1 would indicate a linear relationship.

parse_mqtt_command(topic, payload)

When called, this method statically sends a reward delivery command to the ValveModule instance.

Notes

The method does NOT evaluate the input message or topic. It is written to always send reward trigger commands when called. If future Sun lab pipelines need this method to evaluate the input message, the logic of the method needs to be rewritten.

Returning the command message is more efficient than using the input_queue interface in this particular case.

Return type:

OneOffModuleCommand

Returns:

The command message to be sent to the microcontroller.

process_received_data(message)

Processes incoming data.

Valve calibration events (code 54) are sent to the terminal via console regardless of the debug flag. If the class was initialized in the debug mode, Valve opening (code 52) and closing (code 53) codes are also sent to the terminal. Also, stores the total number of times the valve was opened under _reward_tracker index 0 and the total volume of water delivered during runtime under _reward_tracker index 1. :rtype: None

Note

Make sure the console is enabled before calling this method.

property scale_coefficient: float64

Returns the scaling coefficient (A) from the power‐law calibration.

In the calibration model, fluid_volume = A * (pulse_duration)^B, this coefficient converts pulse duration (in microseconds) into the appropriate fluid volume (in microliters) when used together with the nonlinearity exponent.

send_pulse(repetition_delay=np.uint32(0), noblock=False)

Triggers ValveModule to deliver a precise amount of fluid by cycling opening and closing the valve once or repetitively (recurrently).

After calibration, this command allows delivering precise amounts of fluid with, depending on the used valve and relay hardware microliter or nanoliter precision. This command is optimized to change valve states at a comparatively low frequency in the 10-200 Hz range.

Notes

To ensure the accuracy of fluid delivery, it is recommended to run the valve in the blocking mode and, if possible, isolate it to a controller that is not busy with running other tasks.

Parameters:
  • repetition_delay (uint32, default: np.uint32(0)) – The time, in microseconds, to delay before repeating the command. If set to 0, the command will only run once. The exact repetition delay will be further affected by other modules managed by the same microcontroller and may not be perfectly accurate.

  • noblock (bool, default: False) – Determines whether the command should block the microcontroller while the valve is kept open or not. Blocking ensures precise pulse duration and dispensed fluid volume. Non-blocking allows the microcontroller to perform other operations while waiting, increasing its throughput.

Return type:

None

set_parameters(pulse_duration=np.uint32(35590), calibration_delay=np.uint32(200000), calibration_count=np.uint16(200), tone_duration=np.uint32(300000))

Changes the PC-addressable runtime parameters of the ValveModule instance.

Use this method to package and apply new PC-addressable parameters to the ValveModule instance managed by this Interface class.

Note

Default parameters are configured to support ‘reference’ calibration run. When calibrate() is called with these default parameters, the Valve should deliver ~5 uL of water, which is the value used during Sun lab experiments. If the reference calibration fails, you have to fully recalibrate the valve!

Parameters:
  • pulse_duration (uint32, default: np.uint32(35590)) – The time, in microseconds, the valve stays open when it is pulsed (opened and closed). This is used during the execution of the send_pulse() command to control the amount of dispensed fluid. Use the get_duration_from_volume() method to convert the desired fluid volume into the pulse_duration value.

  • calibration_delay (uint32, default: np.uint32(200000)) – The time, in microseconds, to wait between consecutive pulses during calibration. Calibration works by repeatedly pulsing the valve the requested number of times. Delaying after closing the valve (ending the pulse) ensures the valve hardware has enough time to respond to the inactivation phase before starting the next calibration cycle.

  • calibration_count (uint16, default: np.uint16(200)) – The number of times to pulse the valve during calibration. A number between 10 and 100 is enough for most use cases.

  • tone_duration (uint32, default: np.uint32(300000)) – The time, in microseconds, to sound the audible tone when the valve is pulsed. This is only used if the hardware ValveModule instance was provided with the TonePin argument at instantiation. If your use case involves emitting tones, make sure this value is higher than the pulse_duration value.

Return type:

None

terminate_remote_assets()

Disconnects from the reward tracker SharedMemoryArray.

Return type:

None

toggle(state)

Triggers the ValveModule to be permanently open or closed.

This command locks the ValveModule managed by this Interface into the desired state.

Parameters:

state (bool) – The desired state of the valve. True means the valve is open; False means the valve is closed.

Return type:

None

property valve_tracker: SharedMemoryArray

Returns the SharedMemoryArray that stores the total number of valve pulses and the total volume of water delivered during the current runtime.

The number of valve pulses is stored under index 0, while the total delivered volume is stored under index 1. Both values are stored as a float64 datatype. The total delivered volume is given in microliters.

Google Sheet Tools

This module provides classes and methods used to interface with Google Sheet files to extract the stored data or write new data. Primarily, these tools are used to synchronize the data acquired and stored during training and experiment runtimes with the data inside the lab’s Google Sheets.

class sl_experiment.google_sheet_tools.SurgerySheet(project_name, credentials_path, sheet_id)

Bases: object

Encapsulates the access to the target Google Sheet that contains lab surgery logs.

This class uses Google Sheets API to connect to and extract the data stored in the surgery log Google Sheet file. It functions as the central access point used to extract surgery data for each animal and project combination and save it as a .yaml file alongside other recorded training or experiment data.

Notes

This class is purpose-built to work with the specific surgery log format used in the Sun lab. If the target sheet or project tab layout does not conform to expectations, this class will likely not behave as intended.

Parameters:
  • project_name (str) – The name of the project whose data should be parsed by the class instance. It is expected that the target sheet stores all Sun Lab projects as individual tabs.

  • credentials_path (Path) – The path to the JSON file containing the service account credentials for accessing the Google Sheet.

  • sheet_id (str) – The ID of the Google Sheet containing the surgery data.

_project_name

Stores the target project name.

_sheet_id

Stores the ID of the target Google Sheet.

_service

The Google Sheets API service instance used to fetch data from the target Google Sheet.

_headers

A dictionary that uses headers (column names) as keys and Google Sheet column names (A, B, etc.) as values. This dictionary stores all user-defined headers used by the target Google Sheet tab.

_animals

Stores all animal IDs (names) whose data is stored in the target Google Sheet tab.

__del__()

Terminates the Google Sheets API service when the class is garbage-collected.

Return type:

None

_get_column_id(column_name)

Returns the Google Sheet column ID (letter) for the given column name.

This method assumes that the header name comes from the data extracted from the header row of the processed sheet. The method is used during animal-specific data parsing to retrieve data from specific columns.

Parameters:

column_name (str) – The name of the column as it appears in the header row.

Return type:

str | None

Returns:

The column ID (e.g., “A”, “B”, “C”) corresponding to the column name. If the target column header does not exist, returns None to indicate the header is not available.

property animals: tuple[str, ...]

Returns a tuple of animal IDs whose data is stored inside the managed project tab of the target Google Sheet.

extract_animal_data(animal_id)

Extracts the surgery data for the target animal and returns it as a SurgeryData object.

Primarily, this method is used by the SessionData class to extract and store the surgery data for each animal in its persistent ‘metadata’ folder. This ensures that all data relevant for analysis is kept in the same place.

Parameters:

animal_id (int) – The numeric ID of the animal whose data should be parsed by this method. It is expected that all animals use numeric IDs (either project-specific or unique across all projects) as ‘names’.

Return type:

SurgeryData

Returns:

A fully configured SurgeryData instance that stores the extracted data. Use the ‘to_yaml’ method of the returned instance to save the data to disk as a .yaml file.

property headers: tuple[str, ...]

Returns a tuple of headers (column names) used by the managed project tab of the target Google Sheet.

class sl_experiment.google_sheet_tools.WaterSheetData(animal_id, credentials_path, sheet_id)

Bases: object

Encapsulates and provides access to the target Google Sheet that contains project water-restriction data.

This class uses Google Sheets API to connect to and update the data stored in the water restriction log Google Sheet file. It functions as the central access point used to update the water restriction data for each animal after training and experiment sessions. Primarily, this is used as a convenience and data synchronization feature that allows experimenters to synchronize runtime data with the Google Sheet tracker, instead of entering it manually.

Notes

This class is purpose-built to work with the specific water restriction log format used in the Sun lab. If the target sheet layout does not conform to expectations, this class will likely not perform as intended.

In contrast to the surgery log, the water restriction log does not store project-specific information. While the general assumption is that each project uses a unique water restriction log file, the system also supports experimenters that use unique IDs for all mice, across all projects.

Parameters:
  • animal_id (int) – The ID of the animal whose data will be written by this class instance.

  • credentials_path (Path) – The path to the JSON file containing the service account credentials for accessing the Google Sheet.

  • sheet_id (str) – The ID of the Google Sheet containing the water restriction data for the target project.

_sheet_id

Stores the ID of the target Google Sheet.

_service

The Google Sheets API service instance used to write data to the target Google Sheet.

_animals

Stores all animal IDs (names) whose data is stored in the target Google Sheet.

_headers

A dictionary that uses headers (column names) as keys and Google Sheet column names (A, B, etc.) as values. This dictionary stores all user-defined headers used by the target Google Sheet tab (animal tab).

_sheet_id_numeric

The numeric ID of the tab that stores the data for the managed animal. This is used to write the data to the target animal’s tab.

__del__()

Terminates the Google Sheets API service when the class is garbage-collected.

Return type:

None

_find_date_row(target_date)

Finds the row index inside the manged water restriction log file containing the target date.

This is used when updating the log with new data to determine which row to write the data to.

Parameters:

target_date (str) – The date to find in ‘mm/dd/yyyy’ format.

Return type:

int

Returns:

The row index (1-based), containing the target date.

Raises:

ValueError – If the target data is not found inside the managed Google Sheet file.

_write_value(column_name, row_index, value)

Writes the input value to the specific cell based on column name and row index.

This is the primary method used to write new values to the managed water restriction log Google Sheet.

Parameters:
  • column_name (str) – The name of the column to write to.

  • row_index (int) – The row index (1-based) to write to.

  • value (int | float | str) – The value to write.

Return type:

None

property animals: tuple[str, ...]

Returns a tuple of animal IDs whose data is stored inside the target Google Sheet.

property headers: tuple[str, ...]

Returns a tuple of headers (column names) used by the managed animal tab of the target Google Sheet.

update_water_log(mouse_weight, water_ml, experimenter_id, session_name)

Updates the water restriction log for the managed animal with today’s training or experiment data.

This method is used at the end of each BehaviorTraining or MesoscopeExperiment runtime to update the water restriction log with the runtime data. Primarily, this is used to keep a record of behavior interventions and to streamline experimenter experience by automatically synchronizing the Google Sheet log with the data logged during runtime.

Notes

For this method to work as intended, the target water restriction log tab must be pre-filled with dates at least up to today’s data. The method searches the ‘date’ column for today’s date and uses it to determine which row of the table to update with data.

Parameters:
  • mouse_weight (float) – The weight of the mouse, in grams, at the beginning of the training or experiment session.

  • water_ml (float) – The combined volume of water, in milliliters, given to the animal automatically (during runtime) and manually (by the experimenter, after runtime).

  • experimenter_id (str) – The ID of the experimenter running the training or experiment session.

  • session_name (str) – The name (type) of the training or experiment session. This is written to the ‘behavior’ column to describe the type of activity performed by the animal during runtime.

Return type:

None

sl_experiment.google_sheet_tools._convert_date_time_to_timestamp(date, time)

Converts the input date and time strings into the UTC timestamp.

This function is used to convert date and time strings parsed from the Google Sheet into the microseconds since UTC epoch onset, which is the primary time format used by all other library components.

Parameters:
  • date (str) – The date string in the format “%m-%d-%y” or “%m-%d-%Y”.

  • time (str) – The time string in the format “%H:%M”.

Return type:

int

Returns:

The number of microseconds elapsed since UTC epoch onset as an integer.

Raises:

ValueError – If date or time are not non-empty strings. If the date or time format does not match any of the supported formats.

sl_experiment.google_sheet_tools._convert_index_to_column_letter(index)

Converts a 0-based column index to an Excel-style (Google Sheet) column letter (A, B, C, … Z, AA, AB, …).

This is used when parsing the available headers from the Google Sheet to generate the initial column-to-header mapping dictionary.

Args:

index: The 0-based column index to be converted.

Return type:

str

Returns:

The Excel-style column letter corresponding to the input index.

sl_experiment.google_sheet_tools._extract_coordinate_value(substring)

Extracts the numeric value from the input stereotactic coordinate substring.

This worker function is used to extract the numeric value for each implant and injection coordinate parsed from the Google Sheet data.

Parameters:

substring (str) – The stereotactic coordinate substring that contains the numeric value to be extracted.

Return type:

float

Returns:

The extracted numeric value, formatted as a float.

Raises:

ValueError – If the input substring does not contain a numerical value for the anatomical coordinate.

sl_experiment.google_sheet_tools._parse_stereotactic_coordinates(coordinate_string)

Parses the AP, ML, and DV stereotactic coordinates from the input coordinate string, extracted from the Google Sheet data.

This method is used when generating ImplantData and InjectionData classes to process the coordinates for each implant and injection.

Notes

This method expects the coordinates to be stored as a string formatted as: “-1.8 AP, 2 ML, .25 DV”.

Parameters:

coordinate_string (str) – The input string containing the stereotactic coordinates, formatted as described above.

Returns:

AP, ML, DV.

Return type:

The tuple of 3 floats, each storing the numeric value of the coordinates in the following order

sl_experiment.google_sheet_tools._replace_empty_values(row_data)

Replaces empty cells and cells containing ‘n/a’, ‘–’ or ‘—’ inside the input row_data list with None.

This is used when retrieving animal data to filter out empty cells and values.

Parameters:

row_data (list[str]) – The list of cell values from a single Google Sheet row.

Return type:

list[str | None]

Returns:

The filtered version of the input list.

Packaging Tools

This module provides methods for packaging session runtime data for transmission over the network. The methods from this module work in tandem with methods offered by transfer_tools.py to ensure the integrity of the transferred data.

sl_experiment.packaging_tools._calculate_file_checksum(base_directory, file_path)

Calculates xxHash3-128 checksum for a single file and its path relative to the base directory.

This function is passed to parallel workers used by the calculate_directory_hash() method that iteratively calculates the checksum for all files inside a directory. Each call to this function returns the checksum for the target file, which includes both the contents of the file and its path relative to the base directory.

Parameters:
  • base_directory (Path) – The path to the base (root) directory for which.

  • file_path (Path) – Absolute path to the target file.

Return type:

tuple[str, bytes]

Returns:

A tuple with two elements. The first element is the path to the file relative to the base directory. The second element is the xxhash3-128 checksum that covers the relative path and the contents of the file.

sl_experiment.packaging_tools.calculate_directory_checksum(directory, num_processes=None, batch=False, save_checksum=True)

Calculates xxHash3-128 checksum for the input directory, which includes the data of all contained files and the directory structure information.

This function is used to generate a checksum for each experimental session directory. Checksums are used to verify the session data integrity during transmission between the PC that acquired the data and longer term storage locations, such as the NAS or the lab processing server. The function can be configured to write the generated checksum as a hexadecimal string to the ax_checksum.txt file stored at the highest level of the input directory.

Note

All data transfer methods from this library automatically verify data integrity when it is uploaded to or downloaded from long-term storage. We assume that long-term storage comes with the necessary parity and data integrity verification methods to minimize data corruption risks.

This method uses multiprocessing to efficiently parallelize checksum calculation for multiple files. In combination with xxHash3, this achieves a significant speedup over more common checksums, such as MD5 and SHA256. Note that xxHash3 is not suitable for security purposes and is only used to ensure data integrity.

The method notifies the user about the checksum calculation process via the terminal.

The returned checksum accounts for both the contents of each file and the layout of the input directory structure.

Parameters:
  • directory (Path) – The Path to the directory to be checksummed.

  • num_processes (int | None, default: None) – The number of CPU processes to use for parallelizing checksum calculation. If set to None, the function defaults to using (logical CPU count - 4).

  • batch (bool, default: False) – Determines whether the function is called as part of batch-processing multiple directories. This is used to optimize progress reporting to avoid cluttering the terminal.

  • save_checksum (bool, default: True) – Determines whether the checksum should be saved (written to) a .txt file.

Return type:

str

Returns:

The xxHash3-128 checksum for the input directory as a hexadecimal string.

Transfer Tools

This module provides methods for moving data between the local machine, the ScanImage (Mesoscope) PC, the Synology NAS drive, and the lab BioHPC cluster. All methods in this module expect that the destinations and sources are mounted on the host file-system and use the os tools for moving the data.

sl_experiment.transfer_tools._transfer_file(src_file, source_directory, dest_directory)

Copies the input file from the source directory to the destination directory while preserving the file metadata.

This is a worker method used by the transfer_directory() method to move multiple files in parallel.

Notes

If the file is found under a hierarchy of subdirectories inside the input source_directory, that hierarchy will be preserved in the destination directory.

Parameters:
  • src_file (Path) – The file to be copied.

  • source_directory (Path) – The root directory where the file is located.

  • dest_directory (Path) – The destination directory where to move the file.

Return type:

None

sl_experiment.transfer_tools.transfer_directory(source, destination, num_threads=1, verify_integrity=True)

Copies the contents of the input directory tree from source to destination while preserving the folder structure.

This function is used to assemble the experimental data from all remote machines used in the acquisition process. It is also used to transfer the preprocessed raw data from the local machine to the NAS and the Sun lab BioHPC cluster.

Notes

This method recreates the moved directory hierarchy on the destination if the hierarchy does not exist. This is done before copying the files.

The method executes a multithreading copy operation. It does not clean up the source files. That job is handed to the SessionData class, which also executes the copy operation simultaneously for multiple destinations.

If the method is configured to verify transferred file integrity, it reruns the xxHash3-128 checksum calculation and compares the returned checksum to the one stored in the source directory. The method assumes that all input directories contain the ‘ax_checksum.txt’ file that stores the ‘source’ directory checksum at the highest level of the input directory tree.

Parameters:
  • source (Path) – The path to the directory that needs to be moved.

  • destination (Path) – The path to the destination directory where to move the contents of the source directory.

  • num_threads (int, default: 1) – The number of threads to use for parallel file transfer. This number should be set depending on the type of transfer (local or remote) and is not guaranteed to provide improved transfer performance. For local transfers, setting this number above 1 will likely provide a performance boost. For remote transfers using a single TCP / IP socket (such as non-multichannel SMB protocol), the number should be set to 1.

  • verify_integrity (bool, default: True) – Determines whether to perform integrity verification for the transferred files. Note, integrity verification is a time-consuming process and generally would not be a concern for most runtimes. Therefore, it is often fine to disable this option to optimize method runtime speed.

Raises:

RuntimeError – If the transferred files do not pass the xxHas3-128 checksum integrity verification.

Return type:

None

Data Preprocessing Tools

This module provides the methods used to preprocess experimental data after acquisition. The primary purpose of this procedure is to prepare the data for storage and further processing in the Sun lab data cluster.

This module also provides some of the dataclasses used to store runtime information on disk (session descriptors, hardware configuration) and the main SessionData class used to manage the data of each session.

sl_experiment.data_preprocessing._check_stack_size(file)

Reads the header of the input TIFF file, and if the file is a stack, extracts its size.

This function is used to both determine the stack size of the processed TIFF files and to exclude non-mesoscope TIFFs from processing.

Notes

This function only works with monochrome TIFF stacks generated by the mesoscope. It expects each TIFF file to be a stack of 2D frames.

Parameters:

file (Path) – The path to the TIFF file to evaluate.

Return type:

int

Returns:

If the file is a stack, returns the number of frames (pages) in the stack. Otherwise, returns 0 to indicate that the file is not a stack.

sl_experiment.data_preprocessing._delete_directory(directory_path)

Removes the input directory and all its subdirectories using parallel processing.

This function outperforms default approaches like subprocess call with rm -rf and shutil rmtree for directories with a comparably small number of large files. For example, this is the case for the mesoscope frame directories, which are deleted ~6 times faster with this method over sh.rmtree. Potentially, it may also outperform these approaches for all comparatively shallow directories.

Parameters:

directory_path (Path) – The path to the directory to delete.

Return type:

None

sl_experiment.data_preprocessing._generate_ops(metadata, frame_data, ops_path)

Uses frame-invariant ScanImage metadata and static default values to create an ops.json file in the directory specified by data_path.

This function is an implementation of the mesoscope data extraction helper from the suite2p library. The helper function has been reworked to use the metadata parsed by tifffile and reimplemented in Python. Primarily, this function generates the ‘fs’, ‘dx’, ‘dy’, ‘lines’, ‘nroi’, ‘nplanes’ and ‘mesoscan’ fields of the ‘ops’ configuration file.

Notes

The generated ops.json file will be saved at the location and filename specified by the ops_path.

Parameters:
  • metadata (dict[str, Any]) – The dictionary containing ScanImage metadata extracted from a mesoscope tiff stack file.

  • frame_data (ndarray[Any, dtype[int16]]) – A numpy array containing the extracted pixel data for the first frame of the stack.

  • ops_path (Path) – The path to the output ops.json file. This is generated by the ProjectData class and passed down to this method via the main directory processing function.

Return type:

None

sl_experiment.data_preprocessing._get_stack_number(tiff_path)

A helper function that determines the number of mesoscope-acquired tiff stacks using its file name.

This is used to sort all TIFF stacks in a directory before recompressing them with LERC scheme. Like other helpers, this helper is also used to identify and remove non-mesoscope TIFFs from the dataset.

Parameters:

tiff_path (Path) – The path to the TIFF file to evaluate.

Return type:

int | None

Returns:

The number of frames contained in the TIFF stack file or None to indicate that the input file is not a valid mesoscope TIFF stack.

sl_experiment.data_preprocessing._preprocess_google_sheet_data(session_data)

Updates the water restriction log and the surgery_data.yaml file.

This internal method is called as part of preprocessing. Primarily, it is used to ensure that the surgery data extracted and stored in the ‘metadata’ folder of each processed animal is actual. It also updates the water restriction log for the managed animal to reflect the water received before and after runtime. This step improves user experience by ensuring all relevant data is always kept together on the NAS and BioHPC server while preventing the experimenter from manually updating the log after data preprocessing.

Raises:

ValueError – If the session_type attribute of the input SessionData instance is not one of the supported options.

Parameters:

session_data (SessionData) – The SessionData instance for the processed session.

Return type:

None

sl_experiment.data_preprocessing._preprocess_log_directory(session_data, num_processes, remove_sources=True, verify_integrity=False)

Compresses all .npy (uncompressed) log entries stored in the behavior log directory into one or more .npz archives.

This service function is used during data preprocessing to optimize the size and format used to store all log entries. Primarily, this is necessary to facilitate data transfer over the network and log processing on the BioHPC server.

Parameters:
  • session_data (SessionData) – The SessionData instance for the processed session.

  • num_processes (int) – The maximum number of processes to use while processing the directory.

  • remove_sources (bool, default: True) – Determines whether to remove the original .npy files after they are compressed into .npz archives. It is recommended to have this option enabled.

  • verify_integrity (bool, default: False) – Determines whether to verify the integrity of compressed data against the source data. It is advised to have this disabled for most runtimes, as data corruption is highly unlikely, but enabling this option adds a significant overhead to the processing time.

Raises:

RuntimeError – If the target log directory contains both compressed and uncompressed log entries.

Return type:

None

sl_experiment.data_preprocessing._preprocess_mesoscope_directory(session_data, num_processes, remove_sources=True, batch=False, verify_integrity=False, batch_size=250)

Loops over all multi-frame Mesoscope TIFF stacks in the mesoscope_frames, recompresses them using Limited Error Raster Compression (LERC) scheme, and extracts ScanImage metadata.

This function is used as a preprocessing step for mesoscope-acquired data that optimizes the size of raw images for long-term storage and streaming over the network. To do so, all stacks are re-encoded using LERC scheme, which achieves ~70% compression ratio, compared to the original frame stacks obtained from the mesoscope. Additionally, this function also extracts frame-variant and frame-invariant ScanImage metadata from raw stacks and saves it as efficiently encoded JSON (.json) and compressed numpy archive (.npz) files to minimize disk space usage.

Notes

This function is specifically calibrated to work with TIFF stacks produced by the ScanImage matlab software. Critically, these stacks are named using ‘_’ to separate acquisition and stack number from the rest of the file name, and the stack number is always found last, e.g.: ‘Tyche-A7_2022_01_25_1__00001_00067.tif’. If the input TIFF files do not follow this naming convention, the function will not process them. Similarly, if the stacks do not contain ScanImage metadata, they will be excluded from processing.

To optimize runtime efficiency, this function employs multiple processes to work with multiple TIFFs at the same time. Given the overall size of each image dataset, this function can run out of RAM if it is allowed to operate on the entire folder at the same time. To prevent this, disable verification, use fewer processes, or change the batch_size to load fewer frames in memory at the same time.

In addition to frame compression and data extraction, this function also generates the ops.json configuration file. This file is used during suite2p cell registration, performed as part of our standard data processing pipeline.

Parameters:
  • session_data (SessionData) – The SessionData instance for the processed session.

  • num_processes (int) – The maximum number of processes to use while processing the directory. Each process is used to compress a stack of TIFF files in parallel.

  • remove_sources (bool, default: True) – Determines whether to remove the original TIFF files after they have been processed.

  • batch (bool, default: False) – Determines whether the function is called as part of batch-processing multiple directories. This is used to optimize progress reporting to avoid cluttering the terminal window.

  • verify_integrity (bool, default: False) – Determines whether to verify the integrity of compressed data against the source data. The conversion does not alter the source data, so it is usually safe to disable this option, as the chance of compromising the data is negligible. Note, enabling this function doubles the RAM used by each parallel worker spawned by this function.

  • batch_size (int, default: 250) – Determines how many frames are loaded into memory at the same time during processing. Note, the same number of frames will be loaded from each stack processed in parallel.

Return type:

None

sl_experiment.data_preprocessing._preprocess_video_names(session_data)

Renames the video (camera) files generated during runtime to use human-friendly camera names, rather than ID-codes.

This is a minor preprocessing function primarily designed to make further data processing steps more human-friendly.

Notes

This function assumes that the runtime uses 3 cameras with IDs 51 (face camera), 62 (left camera), and 73 (right camera).

Parameters:

session_data (SessionData) – The SessionData instance for the processed session.

Return type:

None

sl_experiment.data_preprocessing._process_invariant_metadata(file, ops_path, metadata_path)

Extracts frame-invariant ScanImage metadata from the target tiff file and uses it to generate metadata.json and ops.json files.

This function only needs to be called for one raw ScanImage TIFF stack acquired as part of the same experimental session. It extracts the ScanImage metadata that is common for all frames across all stacks and outputs it as a metadata.json file. This function also calls the _generate_ops() function that generates a suite2p ops.json file from the parsed metadata.

Notes

This function is primarily designed to preserve the metadata before compressing raw TIFF stacks with the Limited Error Raster Compression (LERC) scheme.

Parameters:
  • file (Path) – The path to the mesoscope TIFF stack file. This can be any file in the directory as the frame-invariant metadata is the same for all stacks.

  • ops_path (Path) – The path to the ops.json file that should be created by this function. This is resolved by the ProjectData class to match the processed project, animal, and session combination.

  • metadata_path (Path) – The path to the metadata.json file that should be created by this function. This is resolved by the ProjectData class to match the processed project, animal, and session combination.

Return type:

None

sl_experiment.data_preprocessing._process_stack(tiff_path, first_frame_number, output_dir, verify_integrity, batch_size=250)

Reads a TIFF stack, extracts its frame-variant ScanImage data, and saves it as a LERC-compressed stacked TIFF file.

This is a worker function called by the process_mesoscope_directory in-parallel for each stack inside each processed directory. It re-compresses the input TIFF stack using LERC-compression and extracts the frame-variant ScanImage metadata for each frame inside the stack. Optionally, the function can be configured to verify data integrity after compression.

Notes

This function can reserve up to double the processed stack size of RAM bytes to hold the data in memory. If the host-computer does not have enough RAM, reduce the number of concurrent processes, reduce the batch size, or disable verification.

Raises:
  • RuntimeError – If any extracted frame does not match the original frame stored inside the TIFF stack.

  • NotImplementedError – If extracted frame-variant metadata contains unexpected keys or expected keys for which we do not have a custom extraction implementation.

Parameters:
  • tiff_path (Path) – The path to the TIFF stack to process.

  • first_frame_number (int) – The position (number) of the first frame stored in the stack, relative to the overall sequence of frames acquired during the experiment. This is used to configure the output file name to include the range of frames stored in the stack.

  • output_dir (Path) – The path to the directory where to save the processed stacks.

  • verify_integrity (bool) – Determines whether to verify the integrity of compressed data against the source data. The conversion does not alter the source data, so it is usually safe to disable this option, as the chance of compromising the data is negligible. Note, enabling this function doubles the RAM usage for each worker process.

  • batch_size (int, default: 250) – The number of frames to process at the same time. This directly determines the RAM footprint of this function, as frames are kept in RAM during compression. Note, verification doubles the RAM footprint, as it requires both compressed and uncompressed data to be kept in RAM for comparison.

Return type:

dict[str, Any]

Returns:

A dictionary containing the extracted frame-variant ScanImage metadata for the processed stack.

sl_experiment.data_preprocessing._pull_mesoscope_data(session_data, num_threads=30, remove_sources=True, verify_transfer_integrity=True)

Pulls the data acquired by the Mesoscope from the ScanImagePC to the VRPC.

This function should be called after the data acquisition runtime to aggregate all recorded data on the VRPC before running the preprocessing pipeline. The function expects that the mesoscope frames source directory contains only the frames acquired during the current session runtime, the MotionEstimator.me and zstack.mat used for motion registration.

Notes

It is safe to call this function for sessions that did not acquire mesoscope frames. It is designed to abort early if it cannot discover the cached mesoscope frames data for the target session on the ScanImagePC.

This function expects that the data acquisition runtime has renamed the mesoscope_frames source directory for the session to include the session name. Manual intervention may be necessary if the runtime fails before the mesoscope_frames source directory is renamed.

This function is configured to parallelize data transfer and verification to optimize runtime speeds where possible.

When the function is called for the first time for a particular project and animal combination, it also ‘persists’ the MotionEstimator.me file before moving all mesoscope data to the VRPC. This creates the reference for all further motion estimation procedures carried out during future sessions.

Parameters:
  • session_data (SessionData) – The SessionData instance for the processed session.

  • remove_sources (bool, default: True) – Determines whether to remove the transferred mesoscope frame data from the ScanImagePC. Generally, it is recommended to remove source data to keep ScanImagePC disk usage low. Note, setting this to True will only mark the data for removal. The data will not be removed until ‘purge-data’ command is used from the terminal.

  • verify_transfer_integrity (bool, default: True) – Determines whether to verify the integrity of the transferred data. This is performed before source folder is marked for removal from the ScanImagePC if remove_sources is True.

Return type:

None

sl_experiment.data_preprocessing._push_data(session_data, parallel=True, num_threads=15)

Copies the raw_data directory from the VRPC to the NAS and the BioHPC server.

This internal method is called as part of preprocessing to move the preprocessed data to the NAS and the server. This method generates the xxHash3-128 checksum for the source folder that the server processing pipeline uses to verify the integrity of the transferred data.

Notes

The method also replaces the persisted zaber_positions.yaml file with the file generated during the managed session runtime. This ensures that the persisted file is always up to date with the current zaber motor positions.

Parameters:
  • session_data (SessionData) – The SessionData instance for the processed session.

  • parallel (bool, default: True) – Determines whether to parallelize the data transfer. When enabled, the method will transfer the data to all destinations at the same time (in-parallel). Note, this argument does not affect the number of parallel threads used by each transfer process or the number of threads used to compute the xxHash3-128 checksum. This is determined by the ‘num_threads’ argument (see below).

  • num_threads (int, default: 15) – Determines the number of threads used by each transfer process to copy the files and calculate the xxHash3-128 checksums. Since each process uses the same number of threads, it is highly advised to set this value so that num_threads * 2 (number of destinations) does not exceed the total number of CPU cores - 4.

Return type:

None

sl_experiment.data_preprocessing._resolve_telomere_markers(server_root_path, local_root_path)

Checks the data stored on Sun lab BioHPC server for the presence of telomere.bin markers and removes all matching directories on the VRPC.

Specifically, this function iterates through all raw_data directories on the VRPC, checks if the corresponding directory on the BioHPC server contains a telomere.bin marker, and removes the local raw_data directory if a marker is found.

Parameters:
  • server_root_path (Path) – The path to the root directory used to store all experiment and training data on the Sun lab BioHPC server.

  • local_root_path (Path) – The path to the root directory used to store all experiment and training data on the VRPC.

Return type:

None

sl_experiment.data_preprocessing._resolve_ubiquitin_markers(mesoscope_root_path)

Checks the data stored on the ScanImage PC for the presence of ubiquitin.bin markers and removes all directories that contain the marker.

This function is used to clear out cached mesoscope frame directories on the ScanImage PC once they have been safely copied and processed on the VRPC.

Parameters:

mesoscope_root_path (Path) – The path to the root directory used to store all mesoscope-acquired data on the ScanImage (Mesoscope) PC.

Return type:

None

sl_experiment.data_preprocessing.preprocess_session_data(session_data)

Aggregates all data on VRPC, compresses it for efficient network transmission, and transfers the data to the BioHPC server and the Synology NAS for long-term storage.

This method should be called at the end of each training and experiment runtime to compress and safely transfer the data to its long-term storage destinations.

Notes

The method will NOT delete the data from the VRPC or ScanImagePC. To safely remove the data, use the ‘purge-redundant-data’ CLI command. The data will only be removed if it has been marked for removal by our data management algorithms, which ensure we have enough spare copies of the data elsewhere.

Parameters:

session_data (SessionData) – The SessionData instance for the processed session. This argument is provided by the runtime management function or the CLI function that calls this function.

Return type:

None

sl_experiment.data_preprocessing.purge_redundant_data(remove_ubiquitin, remove_telomere, local_root_path, server_root_path, mesoscope_root_path)

Loops over ScanImagePC and VRPC directories that store training and experiment data and removes no longer necessary data caches.

This function searches the ScanImagePC and VRPC for no longer necessary directories and removes them from the respective systems. ScanImagePC directories are marked for deletion once they are safely copied to the VRPC (and the integrity of the copied data is verified using xxHash-128 checksum). VRPC directories are marked for deletion once the data is safely copied to the BioHPC server and the server verifies the integrity of the copied data using xxHash-128 checksum.

Notes

This is a service function intended to maintain the ScanImagePC and VRPC disk space. To ensure data integrity and redundancy at all processing stages, we do not remove the raw data from these PCs even if it has been preprocessed and moved to long-term storage destinations. However, once the data is moved to the BioHPC server and the NAS, it is generally safe to remove the copies stored on the ScanImagePC and VRPC.

While the NAS is currently not verified for transferred data integrity, it is highly unlikely that the transfer process leads to data corruption. Overall, the way this process is structured ensures that at all stages of data processing there are at least two copies of the data stored on two different machines.

Currently, this function does not discriminate between projects or animals. It will remove all data marked for deletion via the ubiquitin.bin marker or the telomere.bin marker.

Parameters:
  • remove_ubiquitin (bool) – Determines whether to remove ScanImagePC mesoscope_frames directories marked for deletion with ubiquitin.bin markers. Specifically, this allows removing directories that have been safely moved to the VRPC.

  • remove_telomere (bool) – Determines whether to remove VRPC directories whose corresponding BioHPC-server directories are marked with telomere.bin markers. Specifically, this allows removing directories that have been safely moved to and processed by the BioHPC server.

  • local_root_path (Path) – The path to the root directory of the VRPC used to store all experiment and training data.

  • server_root_path (Path) – The path to the root directory of the BioHPC server used to store all experiment and training data.

  • mesoscope_root_path (Path) – The path to the root directory of the ScanImagePC used to store all mesoscope-acquired frame data.

Return type:

None

Configuration and Data Storage Classes

This module provides classes that manage, save, and load varius library-generated data. Primarily, this data can be categorized as configuration data, session runtime data, or general non-session data. Configuration data is typically user-addressable (via editing the corresponding .yaml file) and is used to configure the runtime managed by the library. This includes data managed by the ProjectConfiguration and ExperimentConfiguration classes, for example. Session runtime data is generated during runtime and specifically excludes animal-generated behavior data (which is managed by the DataLogger and other Ataraxis classes). Examples of this data can be found in the ZaberPositions or MesoscopePosition classes. General non-runtime data currently includes animal surgery data (and, in the future, other ‘metadata’). This data is stored in SurgeryData class instance. Regardless of data-type, all classes and methods from this module are not intended to be called by users directly.

class sl_experiment.data_classes.DrugData(lactated_ringers_solution_volume_ml, lactated_ringers_solution_code, ketoprofen_volume_ml, ketoprofen_code, buprenorphine_volume_ml, buprenorphine_code, dexamethasone_volume_ml, dexamethasone_code)

Bases: object

Stores the information about all drugs administered to the subject before, during, and immediately after the surgical procedure.

buprenorphine_code: int

Stores the manufacturer code or internal reference code for buprenorphine. This code is used to identify the buprenorphine batch in additional datasheets and lab ordering documents.

buprenorphine_volume_ml: float

Stores the volume of buprenorphine administered during surgery, in ml.

dexamethasone_code: int

Stores the manufacturer code or internal reference code for dexamethasone. This code is used to identify the dexamethasone batch in additional datasheets and lab ordering documents.

dexamethasone_volume_ml: float

Stores the volume of dexamethasone administered during surgery, in ml.

ketoprofen_code: int

Stores the manufacturer code or internal reference code for ketoprofen. This code is used to identify the ketoprofen batch in additional datasheets and lab ordering documents.

ketoprofen_volume_ml: float

Stores the volume of ketoprofen administered during surgery, in ml.

lactated_ringers_solution_code: int

Stores the manufacturer code or internal reference code for Lactated Ringer’s Solution (LRS). This code is used to identify the LRS batch in additional datasheets and lab ordering documents.

lactated_ringers_solution_volume_ml: float

Stores the volume of Lactated Ringer’s Solution (LRS) administered during surgery, in ml.

class sl_experiment.data_classes.ExperimentConfiguration(cue_map=<factory>, experiment_states=<factory>)

Bases: YamlConfig

Stores the configuration of a single experiment runtime.

Primarily, this includes the sequence of experiment and Virtual Reality (Mesoscope-VR) states that define the flow of the experiment runtime. During runtime, the main control function traverses the sequence of states stored in this class instance start-to-end in the exact order specified by the user. Together with custom Unity projects, this class allows flexibly implementing a wide range of experiments.

Each project should define one or more experiment configurations and save them as .yaml files inside the project ‘configuration’ folder. The name for each configuration file is defined by the user and is used to identify and load the experiment configuration when ‘sl-run-experiment’ CLI command is executed.

cue_map: dict[int, float]

A dictionary that maps each integer-code associated with a wall cue used in the Virtual Reality experiment environment to its length in real-world centimeters. It is used to map each VR cue to the distance the animal needs to travel to fully traverse the wall cue region from start to end.

experiment_states: dict[str, ExperimentState]

A dictionary that uses human-readable state-names as keys and ExperimentState instances as values. Each ExperimentState instance represents a phase of the experiment.

class sl_experiment.data_classes.ExperimentState(experiment_state_code, vr_state_code, state_duration_s)

Bases: object

Encapsulates the information used to set and maintain the desired Mesoscope-VR and experiment state.

Primarily, experiment runtime logic (experiment task logic) is resolved by the Unity game engine. However, the Mesoscope-VR system configuration may also need to change throughout the experiment to optimize the runtime by disabling or reconfiguring specific hardware modules. For example, some experiment stages may require the running wheel to be locked to prevent the animal from running, but others may require it to be unlocked, to facilitate running behavior.

Overall, the Mesoscope-VR system functions like a state-machine, with multiple statically configured states that can be activated and maintained throughout the experiment. During runtime, the runtime control function expects a sequence of ExperimentState instances that will be traversed, start-to-end, to determine the flow of the experiment runtime.

Notes

Do not instantiate this class directly. It is managed by the ExperimentConfiguration wrapper class.

experiment_state_code: int

The integer code of the experiment state. Experiment states do not have a predefined meaning, Instead, each project is expected to define and follow its own experiment state code mapping. Typically, the experiment state code is used to denote major experiment stages, such as ‘baseline’, ‘task’, ‘cooldown’, etc. Note, the same experiment state code can be used by multiple sequential ExperimentState instances to change the VR system states while maintaining the same experiment state.

state_duration_s: float

The time, in seconds, to maintain the current combination of the experiment and VR states.

vr_state_code: int

One of the supported VR system state-codes. Currently, the Mesoscope-VR system supports two state codes. State code ‘1’ denotes ‘REST’ state and code ‘2’ denotes ‘RUN’ state. Note, multiple consecutive ExperimentState instances with different experiment state codes can reuse the same VR state code.

class sl_experiment.data_classes.HardwareConfiguration(cue_map=None, cm_per_pulse=None, maximum_break_strength=None, minimum_break_strength=None, lick_threshold=None, valve_scale_coefficient=None, valve_nonlinearity_exponent=None, torque_per_adc_unit=None, screens_initially_on=None, recorded_mesoscope_ttl=None)

Bases: YamlConfig

This class is used to save the runtime hardware configuration parameters as a .yaml file.

This information is used to read and decode the data saved to the .npz log files during runtime as part of data processing.

Notes

All fields in this dataclass initialize to None. During log processing, any log associated with a hardware module that provides the data stored in a field will be processed, unless that field is None. Therefore, setting any field in this dataclass to None also functions as a flag for whether to parse the log associated with the module that provides this field’s information.

This class is automatically configured by MesoscopeExperiment and BehaviorTraining classes to facilitate log parsing.

cm_per_pulse: float | None = None

EncoderInterface instance property.

cue_map: dict[int, float] | None = None

MesoscopeExperiment instance property.

lick_threshold: int | None = None

BreakInterface instance property.

maximum_break_strength: float | None = None

BreakInterface instance property.

minimum_break_strength: float | None = None

BreakInterface instance property.

recorded_mesoscope_ttl: bool | None = None

TTLInterface instance property.

screens_initially_on: bool | None = None

ScreenInterface instance property.

torque_per_adc_unit: float | None = None

TorqueInterface instance property.

valve_nonlinearity_exponent: float | None = None

ValveInterface instance property.

valve_scale_coefficient: float | None = None

ValveInterface instance property.

class sl_experiment.data_classes.ImplantData(implant, implant_target, implant_code, implant_ap_coordinate_mm, implant_ml_coordinate_mm, implant_dv_coordinate_mm)

Bases: object

Stores the information about a single implantation performed during surgery.

Multiple ImplantData instances are used at the same time if the surgery involved multiple implants.

implant: str

The descriptive name of the implant.

implant_ap_coordinate_mm: float

Stores implant’s antero-posterior stereotactic coordinate, in millimeters, relative to bregma.

implant_code: int

The manufacturer code or internal reference code for the implant. This code is used to identify the implant in additional datasheets and lab ordering documents.

implant_dv_coordinate_mm: float

Stores implant’s dorsal-ventral stereotactic coordinate, in millimeters, relative to bregma.

implant_ml_coordinate_mm: float

Stores implant’s medial-lateral stereotactic coordinate, in millimeters, relative to bregma.

implant_target: str

The name of the brain region or cranium section targeted by the implant.

class sl_experiment.data_classes.InjectionData(injection, injection_target, injection_volume_nl, injection_code, injection_ap_coordinate_mm, injection_ml_coordinate_mm, injection_dv_coordinate_mm)

Bases: object

Stores the information about a single injection performed during surgery.

Multiple InjectionData instances are used at the same time if the surgery involved multiple injections.

injection: str

The descriptive name of the injection.

injection_ap_coordinate_mm: float

Stores injection’s antero-posterior stereotactic coordinate, in millimeters, relative to bregma.

injection_code: int

The manufacturer code or internal reference code for the injected substance. This code is used to identify the substance in additional datasheets and lab ordering documents.

injection_dv_coordinate_mm: float

Stores injection’s dorsal-ventral stereotactic coordinate, in millimeters, relative to bregma.

injection_ml_coordinate_mm: float

Stores injection’s medial-lateral stereotactic coordinate, in millimeters, relative to bregma.

injection_target: str

The name of the brain region targeted by the injection.

injection_volume_nl: float

The volume of substance, in nanoliters, delivered during the injection.

class sl_experiment.data_classes.LickTrainingDescriptor(experimenter, mouse_weight_g, dispensed_water_volume_ml, minimum_reward_delay, maximum_reward_delay_s, maximum_water_volume_ml, maximum_training_time_m, experimenter_notes='Replace this with your notes.', experimenter_given_water_volume_ml=0.0)

Bases: YamlConfig

This class is used to save the description information specific to lick training sessions as a .yaml file.

The information stored in this class instance is filled in two steps. The main runtime function fills most fields of the class, before it is saved as a .yaml file. After runtime, the experimenter manually fills leftover fields, such as ‘experimenter_notes,’ before the class instance is transferred to the long-term storage destination.

The fully filled instance data is also used during preprocessing to write the water restriction log entry for the trained animal.

dispensed_water_volume_ml: float

Stores the total water volume, in milliliters, dispensed during runtime.

experimenter: str

The ID of the experimenter running the session.

experimenter_given_water_volume_ml: float = 0.0

The additional volume of water, in milliliters, administered by the experimenter to the animal after the session.

experimenter_notes: str = 'Replace this with your notes.'

This field is not set during runtime. It is expected that each experimenter replaces this field with their notes made during runtime.

maximum_reward_delay_s: int

Stores the maximum delay, in seconds, that can separate the delivery of two consecutive water rewards.

maximum_training_time_m: int

Stores the maximum time, in minutes, the system is allowed to run the training for.

maximum_water_volume_ml: float

Stores the maximum volume of water the system is allowed to dispense during training.

minimum_reward_delay: int

Stores the minimum delay, in seconds, that can separate the delivery of two consecutive water rewards.

mouse_weight_g: float

The weight of the animal, in grams, at the beginning of the session.

class sl_experiment.data_classes.MesoscopeExperimentDescriptor(experimenter, mouse_weight_g, dispensed_water_volume_ml, experimenter_notes='Replace this with your notes.', experimenter_given_water_volume_ml=0.0, mesoscope_x_position=0.0, mesoscope_y_position=0.0, mesoscope_roll_position=0.0, mesoscope_z_position=0.0, mesoscope_fast_z_position=0.0, mesoscope_tip_position=0.0, mesoscope_tilt_position=0.0)

Bases: YamlConfig

This class is used to save the description information specific to experiment sessions as a .yaml file.

The information stored in this class instance is filled in two steps. The main runtime function fills most fields of the class, before it is saved as a .yaml file. After runtime, the experimenter manually fills leftover fields, such as ‘experimenter_notes,’ before the class instance is transferred to the long-term storage destination.

The fully filled instance data is also used during preprocessing to write the water restriction log entry for the animal participating in the experiment runtime.

Notes

Critically, this class is used to save the mesoscope objective coordinates in the ‘persistent’ directory of an animal after each experiment session. This information is used during the following experiment runtimes to help the experimenter to restore the Mesoscope to the same position used during the previous session. This has to be done manually, as ThorLabs does not provide an API to work with the Mesoscope motors directly at this time.

dispensed_water_volume_ml: float

Stores the total water volume, in milliliters, dispensed during runtime.

experimenter: str

The ID of the experimenter running the session.

experimenter_given_water_volume_ml: float = 0.0

The additional volume of water, in milliliters, administered by the experimenter to the animal after the session.

experimenter_notes: str = 'Replace this with your notes.'

This field is not set during runtime. It is expected that each experimenter will replace this field with their notes made during runtime.

mesoscope_fast_z_position: float = 0.0

The Fast-Z-axis position, in micrometers, of the Mesoscope objective used during session runtime.

mesoscope_roll_position: float = 0.0

The Roll-axis position, in degrees, of the Mesoscope objective used during session runtime.

mesoscope_tilt_position: float = 0.0

The Tip-axis position, in degrees, of the Mesoscope objective used during session runtime.

mesoscope_tip_position: float = 0.0

The Tilt-axis position, in degrees, of the Mesoscope objective used during session runtime.

mesoscope_x_position: float = 0.0

The X-axis position, in centimeters, of the Mesoscope objective used during session runtime.

mesoscope_y_position: float = 0.0

The Y-axis position, in centimeters, of the Mesoscope objective used during session runtime.

mesoscope_z_position: float = 0.0

The Z-axis position, in centimeters, of the Mesoscope objective used during session runtime.

mouse_weight_g: float

The weight of the animal, in grams, at the beginning of the session.

class sl_experiment.data_classes.MesoscopePositions(mesoscope_x_position=0.0, mesoscope_y_position=0.0, mesoscope_roll_position=0.0, mesoscope_z_position=0.0, mesoscope_fast_z_position=0.0, mesoscope_tip_position=0.0, mesoscope_tilt_position=0.0)

Bases: YamlConfig

This class is used to save the Mesoscope position as a .yaml file to reuse it between experiment sessions.

Primarily, the class is used to help the experimenter to position the Mesoscope at the same position across multiple imaging sessions.

Notes

The same information as in this class is stored in the MesoscopeExperimentDescriptor class. The key difference is that the data from this class is kept in the ‘persistent’ VRPC directory and updated with each session, while each descriptor is permanently stored in each session raw_data directory.

mesoscope_fast_z_position: float = 0.0

The Fast-Z-axis position, in micrometers, of the Mesoscope objective used during session runtime.

mesoscope_roll_position: float = 0.0

The Roll-axis position, in degrees, of the Mesoscope objective used during session runtime.

mesoscope_tilt_position: float = 0.0

The Tip-axis position, in degrees, of the Mesoscope objective used during session runtime.

mesoscope_tip_position: float = 0.0

The Tilt-axis position, in degrees, of the Mesoscope objective used during session runtime.

mesoscope_x_position: float = 0.0

The X-axis position, in centimeters, of the Mesoscope objective used during session runtime.

mesoscope_y_position: float = 0.0

The Y-axis position, in centimeters, of the Mesoscope objective used during session runtime.

mesoscope_z_position: float = 0.0

The Z-axis position, in centimeters, of the Mesoscope objective used during session runtime.

class sl_experiment.data_classes.ProcedureData(surgery_start_us, surgery_end_us, surgeon, protocol, surgery_notes, post_op_notes)

Bases: object

Stores the general information about the surgical procedure.

post_op_notes: str

Stores surgeon’s notes taken during the post-surgery recovery period.

protocol: str

Stores the experiment protocol number (ID) used during the surgery.

surgeon: str

Stores the name or ID of the surgeon. If the intervention was carrie out by multiple surgeon, all participating surgeon names and IDs are stored as part of the same string.

surgery_end_us: int

Stores the date and time when the surgery has ended as microseconds elapsed since UTC epoch onset.

surgery_notes: str

Stores surgeon’s notes taken during the surgery.

surgery_start_us: int

Stores the date and time when the surgery was started as microseconds elapsed since UTC epoch onset.

class sl_experiment.data_classes.ProjectConfiguration(surgery_sheet_id='', water_log_sheet_id='', credentials_path=PosixPath('/media/Data/Experiments/sl-surgery-log-0f651e492767.json'), local_root_directory=PosixPath('/media/Data/Experiments'), server_root_directory=PosixPath('/media/cbsuwsun/storage/sun_data'), nas_root_directory=PosixPath('/home/cybermouse/nas/rawdata'), mesoscope_root_directory=PosixPath('/home/cybermouse/scanimage/mesodata'), face_camera_index=0, left_camera_index=0, right_camera_index=2, harvesters_cti_path=PosixPath('/opt/mvIMPACT_Acquire/lib/x86_64/mvGenTLProducer.cti'), actor_port='/dev/ttyACM0', sensor_port='/dev/ttyACM1', encoder_port='/dev/ttyACM2', headbar_port='/dev/ttyUSB0', lickport_port='/dev/ttyUSB1', unity_ip='127.0.0.1', unity_port=1883, valve_calibration_data=((15000, 1.8556), (30000, 3.4844), (45000, 7.1846), (60000, 10.0854)))

Bases: YamlConfig

Stores the project-specific configuration parameters that do not change between different animals and runtime sessions.

An instance of this class is generated and saved as a .yaml file in the ‘configuration’ directory of the project when it is created. After that, the stored data is reused for each training or experiment session executed for each animal of the project.

Notes

This class allows configuring this library to work for every project in the Sun lab while sharing (and hiding) the internal APIs and runtime control functions. This achieves a streamlined user experience, as users do not see nor care about inner workings of this library, while supporting project-specific customization.

The class is primarily designed to specify the ‘surgery_sheet_id’ and the ‘water_log_sheet_id’ values, which likely differ between projects. However, the class also allows configuring the hardware interfaces and directory paths used during data acquisition. While this information should not change between projects, having the ability to adjust it on a per-project basis may be helpful in the future.

_to_path(path)

Saves the instance data to disk as a .yaml file.

This method is automatically called when the project is created. All future runtimes use the from_path() method to load and reuse the configuration data saved to the .yaml file.

Parameters:

path (Path) – The path to the .yaml file to save the data to.

Return type:

None

_verify_data()

Verifies the data loaded from a .yaml file to ensure its validity.

Since this class is explicitly designed to be modified by the user, this verification step is carried out to ensure that the loaded data matches expectations. This reduces the potential for user errors to impact the runtime behavior of the library. This internal method is automatically called by the from_path() method.

Return type:

None

Notes

The method does not verify all fields loaded from the configuration file and instead focuses on paths and Google Sheet IDs. The binding classes verify uSB ports and camera indices during instantiation.

Raises:

ValueError – If the loaded data does not match expected formats or values.

actor_port: str = '/dev/ttyACM0'

The USB port used by the Actor Microcontroller.

credentials_path: str | Path = PosixPath('/media/Data/Experiments/sl-surgery-log-0f651e492767.json')

The path to the locally stored .JSON file that contains the service account credentials used to read and write Google Sheet data. This is used to access and work with the surgery log and the water restriction log. Usually, the same service account is used across all projects.

encoder_port: str = '/dev/ttyACM2'

The USB port used by the Encoder Microcontroller.

face_camera_index: int = 0

The index of the face camera in the list of all available Harvester-managed cameras.

harvesters_cti_path: str | Path = PosixPath('/opt/mvIMPACT_Acquire/lib/x86_64/mvGenTLProducer.cti')

The path to the GeniCam CTI file used to connect to Harvesters-managed cameras. Currently, this is only used by the face camera.

headbar_port: str = '/dev/ttyUSB0'

The USB port used by the HeadBar Zaber motor controllers (devices).

left_camera_index: int = 0

The index of the left body camera in the list of all available OpenCV-managed cameras.

lickport_port: str = '/dev/ttyUSB1'

The USB port used by the LickPort Zaber motor controllers (devices).

classmethod load(project_name)

Loads the project configuration parameters from a .yaml file and uses the loaded data to initialize a ProjectConfiguration instance.

This method is called for each project runtime to reuse the configuration parameters generated at project creation. When it is called for the first time (during new project creation), the method generates a default configuration file and prompts the user to update the configuration before proceeding with the runtime.

Notes

As part of its runtime, the method may prompt the user to provide the path to the local root directory. This directory stores all project subdirectories and acts as the top level of the local data hierarchy. The path to the directory will be saved in the static library-specific configuration file inside user’s default data directory, so that it can be reused for all future runtimes. Use ‘replace_root_path’ function to replace the path that is saved in this way.

Parameters:

project_name (str) – the name of the project whose configuration file needs to be discovered and loaded.

Return type:

ProjectConfiguration

Returns:

An initialized ProjectConfiguration instance.

local_root_directory: str | Path = PosixPath('/media/Data/Experiments')

The path to the root directory where all projects are stored on the host-machine (VRPC). Note, this is always written automatically when the class is saved to disk or loaded from disk, so manually writing this value is pointless.

mesoscope_root_directory: str | Path = PosixPath('/home/cybermouse/scanimage/mesodata')

The path to the root directory used to store all mesoscope-acquired data on the PC that manages the mesoscope (ScanImagePC).

nas_root_directory: str | Path = PosixPath('/home/cybermouse/nas/rawdata')

The path to the root directory where all projects are stored on the Synology NAS.

right_camera_index: int = 2

The index of the right body camera in the list of all available OpenCV-managed cameras.

sensor_port: str = '/dev/ttyACM1'

The USB port used by the Sensor Microcontroller.

server_root_directory: str | Path = PosixPath('/media/cbsuwsun/storage/sun_data')

The path to the root directory where all projects are stored on the BioHPC server machine.

surgery_sheet_id: str = ''

The ID for the Google Sheet file that stores surgery information for the animal whose data is managed by this instance. This is used to parse and write the surgery data for each managed animal into its ‘metadata’ folder, so that the surgery data is always kept together with the rest of the training and experiment data.

unity_ip: str = '127.0.0.1'

The IP address of the MQTT broker used to communicate with the Unity game engine. Note, this is only used during experiment runtimes. Training runtimes ignore this parameter.

unity_port: int = 1883

The port number of the MQTT broker used to communicate with the Unity game engine. Note, this is only used during experiment runtimes. Training runtimes ignore this parameter.

valve_calibration_data: dict[int | float, int | float] | tuple[tuple[int | float, int | float], ...] = ((15000, 1.8556), (30000, 3.4844), (45000, 7.1846), (60000, 10.0854))

A dictionary or tuple of tuples that maps valve open times, in microseconds, to the dispensed volume of water, in microliters. During runtime, this data is used by the ValveModule to translate the requested reward volumes into times the valve needs to be open to deliver the desired volume.

water_log_sheet_id: str = ''

The ID for the Google Sheet file that stores water restriction information for the animal whose data is managed by this instance. This is used to synchronize the information inside the water restriction log with the state of the animal at the end of each training or experiment runtime.

class sl_experiment.data_classes.RunTrainingDescriptor(experimenter, mouse_weight_g, dispensed_water_volume_ml, final_run_speed_threshold_cm_s, final_run_duration_threshold_s, initial_run_speed_threshold_cm_s, initial_run_duration_threshold_s, increase_threshold_ml, run_speed_increase_step_cm_s, run_duration_increase_step_s, maximum_water_volume_ml, maximum_training_time_m, experimenter_notes='Replace this with your notes.', experimenter_given_water_volume_ml=0.0)

Bases: YamlConfig

This class is used to save the description information specific to run training sessions as a .yaml file.

The information stored in this class instance is filled in two steps. The main runtime function fills most fields of the class, before it is saved as a .yaml file. After runtime, the experimenter manually fills leftover fields, such as ‘experimenter_notes,’ before the class instance is transferred to the long-term storage destination.

The fully filled instance data is also used during preprocessing to write the water restriction log entry for the trained animal.

dispensed_water_volume_ml: float

Stores the total water volume, in milliliters, dispensed during runtime.

experimenter: str

The ID of the experimenter running the session.

experimenter_given_water_volume_ml: float = 0.0

The additional volume of water, in milliliters, administered by the experimenter to the animal after the session.

experimenter_notes: str = 'Replace this with your notes.'

This field is not set during runtime. It is expected that each experimenter will replace this field with their notes made during runtime.

final_run_duration_threshold_s: float

Stores the final running duration threshold, in seconds, that was active at the end of training.

final_run_speed_threshold_cm_s: float

Stores the final running speed threshold, in centimeters per second, that was active at the end of training.

increase_threshold_ml: float

Stores the volume of water delivered to the animal, in milliliters, that triggerred the increase in the running speed and duration thresholds.

initial_run_duration_threshold_s: float

Stores the initial above-threshold running duration, in seconds, used during training.

initial_run_speed_threshold_cm_s: float

Stores the initial running speed threshold, in centimeters per second, used during training.

maximum_training_time_m: int

Stores the maximum time, in minutes, the system is allowed to run the training for.

maximum_water_volume_ml: float

Stores the maximum volume of water the system is allowed to dispensed during training.

mouse_weight_g: float

The weight of the animal, in grams, at the beginning of the session.

run_duration_increase_step_s: float

Stores the value, in seconds, used by the system to increment the duration threshold each time the animal receives ‘increase_threshold’ volume of water.

run_speed_increase_step_cm_s: float

Stores the value, in centimeters per second, used by the system to increment the running speed threshold each time the animal receives ‘increase_threshold’ volume of water.

class sl_experiment.data_classes.SessionData(project_name, animal_id, surgery_sheet_id, water_log_sheet_id, session_type, credentials_path, local_root_directory, server_root_directory, nas_root_directory, mesoscope_root_directory, session_name='None', experiment_name=None)

Bases: YamlConfig

Provides methods for managing the data acquired during one experiment or training session.

The primary purpose of this class is to maintain the session data structure across all supported destinations. It generates the paths used by all other classes from this library to determine where to save and load various session data during runtime.

As part of its initialization, the class generates the session directory for the input animal and project combination. Session directories use the current UTC timestamp, down to microseconds, as the directory name. This ensures that each session name is unique and preserves the overall session order.

Notes

It is expected that the server, NAS, and mesoscope data directories are mounted on the host-machine via the SMB or equivalent protocol. All manipulations with these destinations are carried out with the assumption that the OS has full access to these directories and filesystems.

This class is specifically designed for working with raw data from a single animal participating in a single experimental project session. Processed data is managed by the processing library methods and classes.

__post_init__()

Generates the session name and creates the session directory structure on all involved PCs.

Return type:

None

animal_id: str

The ID code of the animal for which the data is acquired.

property camera_frames_path: Path

Returns the path to the ‘camera_frames’ directory of the managed session.

This subdirectory is stored under the ‘raw_data’ directory and aggregates all video camera data.

credentials_path: str | Path

The path to the locally stored .JSON file that stores the service account credentials used to read and write Google Sheet data. This is used to access and work with the surgery log and the water restriction log.

property experiment_configuration_path: Path

Returns the path to the .yaml file that stores the configuration of the experiment runtime for the managed session.

This information is used during experiment runtimes to determine how to run the experiment.

experiment_name: str | None = None

Stores the name of the experiment configuration file. If the session_name attribute is ‘experiment’, this filed is used to communicate the specific experiment configuration used by the session. During runtime, this is used to load the experiment configuration (to run the experiment) and to save the experiment configuration to the session raw_data folder. If the session is not an experiment session, this is statically set to None.

classmethod from_path(path)

Initializes a SessionData instance to represent the data of an already existing session.

Typically, this initialization mode is used to preprocess an interrupted session. This method uses the cached data stored in the ‘session_data.yaml’ file in the ‘raw_data’ subdirectory of the provided session directory.

Parameters:

path (Path) – The path to the session directory on the local (VRPC) machine.

Return type:

SessionData

Returns:

An initialized SessionData instance for the session whose data is stored at the provided path.

Raises:

FileNotFoundError – If the ‘session_data.yaml’ file is not found after resolving the provided path.

property hardware_configuration_path: Path

Returns the path to the ‘hardware_configuration.yaml’ file of the managed session.

This file stores hardware module parameters used to read and parse .npz log files during data processing.

property local_experiment_configuration_path: Path

Returns the path to the .yaml file used to save the managed session’s experiment configuration.

This is used to preserve the experiment configuration inside the raw_data directory of the managed session.

property local_metadata_path: Path

Returns the path to the ‘metadata’ directory of the managed animal on the VRPC.

local_root_directory: str | Path

The path to the root directory where all projects are stored on the host-machine (VRPC).

property mesoscope_persistent_path: Path

Returns the path to the ‘persistent_data’ directory of the Mesoscope pc (ScanImagePC).

This directory is primarily used to store the reference MotionEstimator.me files for each animal.

mesoscope_root_directory: str | Path

The path to the root directory used to store all mesoscope-acquired data on the ScanImagePC.

property mesoscope_root_path: Path

Returns the path to the root directory of the Mesoscope pc (ScanImagePC) used to store all mesoscope-acquired data.

property nas_metadata_path: Path

Returns the path to the ‘metadata’ directory of the managed animal on the Synology NAS.

nas_root_directory: str | Path

The path to the root directory where all projects are stored on the Synology NAS.

property nas_root_path: Path

Returns the path to the root directory of the Synology NAS (Network Attached Storage) used to store all training and experiment data after preprocessing (backup cold long-term storage).

property previous_mesoscope_positions_path: Path

Returns the path to the ‘mesoscope_positions.yaml’ file of the previous session.

The file is stored inside the ‘persistent_data’ directory of the managed animal and is used to help restore the Mesoscope to the same position during following session(s).

property previous_zaber_positions_path: Path

Returns the path to the ‘zaber_positions.yaml’ file of the previous session.

The file is stored inside the ‘persistent_data’ directory of the managed animal.

project_name: str

The name of the project for which the data is acquired.

property raw_data_path: Path

Returns the path to the ‘raw_data’ directory of the managed session on the VRPC.

This directory functions as the root directory that stores all raw data acquired during training or experiment runtime for a given session.

property server_metadata_path: Path

Returns the path to the ‘metadata’ directory of the managed animal on the BioHPC server.

server_root_directory: str | Path

The path to the root directory where all projects are stored on the BioHPC server machine.

property server_root_path: Path

Returns the path to the root directory of the BioHPC server used to process and store all training and e experiment data (main long-term storage).

property session_descriptor_path: Path

Returns the path to the ‘session_descriptor.yaml’ file of the managed session.

This path is used to save important session information to be viewed by experimenters post-runtime and to use for further processing.

session_name: str = 'None'

Stores the name of the session for which the data is acquired. This name is generated at class initialization based on the current microsecond-accurate timestamp. Do NOT manually provide this name at class initialization. Use ‘from_path’ class method to initialize a SessionData instance for an already existing session data directory.

session_type: str

Stores the type of the session. Primarily, this determines how to read the session_descriptor.yaml file. Has to be set to one of the three supported types: ‘Lick training’, ‘Run training’ or ‘Experiment’.

surgery_sheet_id: str

The ID for the Google Sheet file that stores surgery information for the animal whose data is managed by this instance.

to_path()

Saves the data of the instance to the ‘raw_data’ directory of the managed session as a ‘session_data.yaml’ file.

This is used to save the data stored in the instance to disk, so that it can be reused during preprocessing or data processing. This also serves as the repository for the identification information about the project, animal, and session that generated the data.

Return type:

None

water_log_sheet_id: str

The ID for the Google Sheet file that stores water restriction information for the animal whose data is managed by this instance.

property zaber_positions_path: Path

Returns the path to the ‘zaber_positions.yaml’ file of the managed session.

This path is used to save the positions for all Zaber motors of the HeadBar and LickPort controllers at the end of the experimental session.

class sl_experiment.data_classes.SubjectData(id, ear_punch, sex, genotype, date_of_birth_us, weight_g, cage, location_housed, status)

Bases: object

Stores the surgical procedure subject (mouse) ID information.

cage: int

Stores the number of the latest cage used to house the subject.

date_of_birth_us: int

Stores the date of birth of the subject as the number of microseconds elapsed since UTC epoch onset.

ear_punch: str

Stores the ear tag location of the subject.

genotype: str

Stores the genotype of the subject.

id: int

Stores the unique ID (name) of the subject. Assumes all mice are given a numeric ID, rather than a string name.

location_housed: str

Stores the latest location used to house the subject after the surgery.

sex: str

Stores the gender of the subject.

status: str

Stores the latest status of the subject (alive / deceased).

weight_g: float

Stores the weight of the subject pre-surgery, in grams.

class sl_experiment.data_classes.SurgeryData(subject, procedure, drugs, implants, injections)

Bases: YamlConfig

Aggregates all data for a single mouse surgery procedure.

This class aggregates other dataclass instances that store specific data about the surgical procedure. Primarily, it is used to save the data as a .yaml file to the metadata directory of each animal used in every lab project. This way, the surgery data is always stored alongside the behavior and brain activity data collected during training and experiment runtimes.

drugs: DrugData

Stores the data about the substances subcutaneously injected into the subject before, during and immediately after the surgical intervention.

implants: list[ImplantData]

Stores the data for all cranial and transcranial implants introduced to the subject during the procedure.

injections: list[InjectionData]

Stores the data about all substances infused into the brain of the subject during the surgery.

procedure: ProcedureData

Stores general data about the surgical procedure.

subject: SubjectData

Stores the ID information about the subject (mouse).

class sl_experiment.data_classes.ZaberPositions(headbar_z=0, headbar_pitch=0, headbar_roll=0, lickport_z=0, lickport_x=0, lickport_y=0)

Bases: YamlConfig

This class is used to save Zaber motor positions as a .yaml file to reuse them between sessions.

The class is specifically designed to store, save, and load the positions of the LickPort and HeadBar motors (axes). It is used to both store Zaber motor positions for each session for future analysis and to restore the same Zaber motor positions across consecutive runtimes for the same project and animal combination.

Notes

All positions are saved using native motor units. All class fields initialize to default placeholders that are likely NOT safe to apply to the VR system. Do not apply the positions loaded from the file unless you are certain they are safe to use.

Exercise caution when working with Zaber motors. The motors are powerful enough to damage the surrounding equipment and manipulated objects. Do not modify the data stored inside the .yaml file unless you know what you are doing.

headbar_pitch: int = 0

The absolute position, in native motor units, of the HeadBar pitch-axis motor.

headbar_roll: int = 0

The absolute position, in native motor units, of the HeadBar roll-axis motor.

headbar_z: int = 0

The absolute position, in native motor units, of the HeadBar z-axis motor.

lickport_x: int = 0

The absolute position, in native motor units, of the LickPort x-axis motor.

lickport_y: int = 0

The absolute position, in native motor units, of the LickPort y-axis motor.

lickport_z: int = 0

The absolute position, in native motor units, of the LickPort z-axis motor.

sl_experiment.data_classes.replace_root_path(path)

Replaces the path to the local root directory saved in the library’s static configuration file with the provided path.

When the library is used for the first time, it asks the user to provide the path to the local directory where to save all projects managed by the library. This path is stored in the default user directory file, and it is reused for all future projects. To support replacing this path without searching for the default user directory (usually hidden), this function finds and updates the contents of the file that stores the local root path.

Parameters:

path (Path) – The path to the new local root directory.

Return type:

None