Configurations

The use of bruker_control requires an experimental configuration file held inside a JSON format. These were created as a means of doing the following:

  • Create files that act as documentation which precisely describe the exact parameters used for an experiment for every subject

  • Have a reproducible experiment that can be executed using completed configuration files

  • Have a standard set of parameters for performing experiments with the system that is flexible for several use cases and simpler to modify and add to

  • Avoid generating copies of Arduino sketches at runtime as occured in the first iterations of running headfixed behavior experiments

  • Have a file format that can be programmatically accessed when running analysis scripts or searching for particular experiments

  • Have templates that can be easily called upon and updated programatically at runtime without requiring user input

Many of these fields were present in the initial Arduino and MATLAB code, but the Arduino scripts had these values hard coded into the sketch itself. Having a configuration file allows for there to be just one sketch for each team/project as needed that can stand ready for a session without needing to reupload a new sketch in between running individual animals.

Example Project Config: Behavior

Below is an example of what such a configuration looks like:

{"beh_metadata": {
    "totalNumberOfTrials": 60,
    "startingReward": 3,
    "maxSequentialReward": null,
    "maxSequentialPunish": 3,
    "punishTone": 2000,
    "rewardTone": 9000,
    "USDeliveryTime_Sucrose": 200,
    "USDeliveryTime_Air": 100,
    "USConsumptionTime_Sucrose": 3000,
    "vacuum" : true,
    "ITIJitter": true,
    "baseITI": null,
    "minITI": 15,
    "maxITI": 30,
    "toneJitter": false,
    "baseTone": 3,
    "minTone": null,
    "maxTone": null,
    "catchTrials": true,
    "numCatchReward": 3,
    "numCatchPunish": 2,
    "catchOffset" : 0.25,
    "percentPunish": 0.25,
    "stim": true,
    "shutterOnly": false,
    "stimFrequency": 20,
    "stimPulseTime": 5,
    "stimLambda": 590,
    "stimDeliveryTime_PreCS": 1000,
    "stimDeliveryTime_Total": 5000,
    "stimStartPosition": 20,
    "numStimReward": 5,
    "numStimPunish": 5,
    "numStimAlone": 3,
    "yoked": false,
    "trialArray": {},
    "ITIArray": {},
    "toneArray": {},
    "LEDArray": {},
    "dropped_frames": {}
  },
  "zstack_metadata": {
    "zstack": true,
    "stack_number": 3,
    "zdelta": 25.0,
    "zstep": 1.0
  },
  "weight_check": true
}

Config Values Key: Behavior Metadata

Many of the fields were written as to be self explanatory. Below you can find an explainer for each field:

  • totalNumberOfTrials: Total number of trials for an experiment

  • startingReward: Total number of sucrose trials to deliver in the beginnin

  • maxSequentialReward: Maximum number of reward trials to allow in a row

  • maxSequentialPunish: Maximum number of punishment trials to allow in a row

  • punishTone: Tone in Hertz (Hz) to play through a speaker for the subject

  • rewardTone: Tone in Hertz (Hz) to play through a speaker for the subject

  • USDeliveryTime_Sucrose: Time in milliseconds (ms) to open sucrose solenoid

  • USDeliveryTime_Air: Time in milliseconds (ms) to open the air solenoid

  • USConsumptionTime_Sucrose: Time in milliseconds (ms) to allow subject to consume sucrose droplet

  • vacuum: Whether or not a vacuum is enabled for use in the experiment. Either True or False

  • ITIJitter: Whether or not to have jitter in inter-trial-interval (ITI) timings

  • baseITI: Inter-trial-interval (ITI) to use if no ITIJitter is False

  • minITI: Minimum inter-trial-interval (ITI) value in seconds. Defines lower bound for sampling ITI values

  • maxITI: Maximum inter-trial-interval (ITI) value in seconds. Defines upper bound for sampling ITI values

  • toneJitter: Whether or not to have jitter in the duration of tones that are played for the subject. Either True or False

  • baseTone: Time to play tone in seconds (s) for subject if toneJitter is False.

  • minTone: Minimum time to play tone in seconds (s). Defines lower bound for sampling tone values

  • maxTone: Maximum time to play tone in seconds (s). Defines upper bound for sampling tone values

  • catchTrials: Whether or not to have catch trials occur during an experiment. Either True or False

  • numCatchReward: Number of reward catch trials to present to the subject

  • numCatchPunish: Number of punish catch trials to present to the subject

  • catchOffset: Where in the trialArray catch trials should be presented. This is defined as the proportion of remaining trials that should be eligible for delivering catch trials.

  • percentPunish: The proportion of trials that will be punishment trials.

  • stim: Whether or not to have stimulation trials occur during an experiment. Currently only valid for whole field LED stimulation.

  • shutterOnly: Whether or not the stimulation trials did not activate LED and only activated PMT shutters.

  • stimFrequency: Frequency of stimulation in Hertz (Hz) that the whole field LED will perform

  • stimLambda: Wavelength of stimulating LED in nanometers (nm). This is assumed to be constant for a given project and is for documentation purposes alone

  • stimDeliveryTime_PreCS: Time in milliseconds (ms) to start LED output before presentation of conditioned stimulus

  • stimDeliveryTime_Total: Total time in milliseconds (ms) that the LED ouptut will be delivered. This is assumed to be constant for a given project and is for documentation purposes alone.

  • stimStartPosition: 1-Indexed position where LED stimulation should begin. trial_utils.py will decrement this by 1 so it is 0-indexed for Python/Arduino iterations.

  • numStimReward: Number of trials to give LED stimulation with a reward

  • numStimPunish: Number of trials to give LED stimulation with a punishment

  • numStimAlone: Number of trials to give LED stimulation alone

  • yoked: (NEW) Whether or not to generate/check for yoked trial settings

  • trialArray: Array of integers for trials that the Arduino will iterate through. Valid numbers are 0-6

  • ITIArray: Array of inter-trial-intervals (ITIs) that the Arduino will iterate through

  • toneArray: Array of tone durations to deliver to the subject

  • LEDArray: Array of times for delivering LED stimulation. Calculated by trial_utils.py by taking the ITI for the appropriate trial and subtracting the stimDeliveryTime_PreCS value

  • dropped_frames: List of video frames that are dropped when transferring data from the Genie Nano to the computer during an experiment. Packet loss is rare, but has occured previously.

Config Values Key: Trial Types

Currently accessible trial types in bruker_control are entirely designed around one behavior paradigm: the delivery of sucrose or an airpuff to the headfixed subject. Perhaps in the future a library like Autopilot could be used to dynamically generate trials using the library’s powerful framework. We create base trial types around these and then have additional trial types we build off them:

  • LED optogenetic stimulation trials with airpuff and sucrose presented

  • LED only trials: Trials where no stimuli are presented but the LED is triggered to stimulate neurons

  • Catch trials: trials where only the tone (or conditioned stimulus) is presented and the associated airpuff or sucrose (unconditioned stimulus) is not

When building the trial arrays, each trial type is associated with a specific number. The key for these numbers is:

  • 0: Airpuff

  • 1: Sucrose

  • 2: Airpuff Catch

  • 3: Sucrose Catch

  • 4: Airpuff LED

  • 5: Sucrose LED

  • 6: LED Only

Config Values Key: Z-Stack Metadata

If users want to have a z-stack performed for their imaging session before the experiment, they can use this metadata to define parameters used for imaging.

  • zstack: Whether or not to perform a z-stack for a given recording

  • stack_number: Number of z-stacks to perform

  • zdelta: Distance in micrometers (um) to move above and below the selected imaging plane for the z-stack.

  • zstep: Distance in micrometeres (um) the scope will move between images.

Config Values Key: Miscellaneous

Some users need to make sure a weight has been recorded for the subject being imaged. To ensure that users remember to have weights recorded for their mice, there’s an option to perform a weight check. If the weight check fails, the experiment won’t go forward. It is likely that this will be removed in the near future.

Complete Configuration File

This is an example of what a completed configuration file looks like after an experiment is completed (from a real experiment!):

{
    "beh_metadata": {
        "totalNumberOfTrials": 60,
        "startingReward": 3,
        "maxSequentialReward": null,
        "maxSequentialPunish": 3,
        "punishTone": 2000,
        "rewardTone": 9000,
        "USDeliveryTime_Sucrose": 200,
        "USDeliveryTime_Air": 100,
        "USConsumptionTime_Sucrose": 1000,
        "USDelay": 2000,
        "vacuum": true,
        "ITIJitter": true,
        "baseITI": null,
        "minITI": 25,
        "maxITI": 30,
        "toneJitter": false,
        "baseTone": 3,
        "minTone": null,
        "maxTone": null,
        "catchTrials": true,
        "numCatchReward": 3,
        "numCatchPunish": 2,
        "catchOffset": 0.25,
        "percentPunish": 0.25,
        "stim": true,
        "shutter_only": false,
        "stimFrequency": 20,
        "stimPulseTime": 5,
        "stimLambda": 590,
        "stimDeliveryTime_PreCS": 6000,
        "stimDeliveryTime_Total": 5000,
        "stimStartPosition": 20,
        "numStimReward": 5,
        "numStimPunish": 5,
        "numStimAlone": 3,
        "yoked": false,
        "trialArray": [
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            0,
            1,
            1,
            1,
            0,
            0,
            1,
            1,
            1,
            1,
            0,
            0,
            0,
            6,
            6,
            4,
            5,
            4,
            5,
            5,
            4,
            4,
            4,
            5,
            5,
            6,
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            1,
            3,
            1,
            1,
            0,
            2,
            3,
            2,
            1,
            1,
            0,
            3,
            1,
            1,
            1,
            1
        ],
        "ITIArray": [
            29480,
            29582,
            25763,
            25851,
            25784,
            27231,
            27803,
            26458,
            28338,
            27721,
            29685,
            26766,
            27797,
            27750,
            26832,
            27437,
            27762,
            26503,
            29295,
            28137,
            28762,
            26795,
            25739,
            29311,
            27552,
            25838,
            28862,
            27459,
            28341,
            28575,
            26141,
            29665,
            27975,
            29316,
            25065,
            26304,
            25210,
            28299,
            25331,
            28878,
            26094,
            27875,
            28720,
            26682,
            29879,
            25739,
            25534,
            28427,
            29739,
            26514,
            26915,
            26121,
            26061,
            28227,
            29269,
            29778,
            28466,
            29169,
            25100,
            27282
        ],
        "toneArray": [
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000,
            3000
        ],
        "LEDArray": [
            22762,
            20795,
            19739,
            23311,
            21552,
            19838,
            22862,
            21459,
            22341,
            22575,
            20141,
            23665,
            21975
        ],
        "dropped_frames": []
    },
    "zstack_metadata": {
        "zstack": true,
        "stack_number": 1,
        "zdelta": 25.0,
        "zstep": 1.0
    },
    "weight_check": false
}

Example Subject Metadata

In an effort to make metadata about the subject programmatically available for use in generating Neurodata Without Borders compliant datasets as well as programmatically update laser power and wavelength for instances where z-stacks required multiple wavelengths for imaging different fluorophores. Below is an example of what the subject metdata looks like:

# Subject Metadata used for grabbing information 
# Jeremy Delahanty, Tye Lab Februrary 2022
# This was generated by taking all available fields labmembers had stored
# in their surgery logs and joining it with NWB metadata fields.
subject_id: "A000"
subject_alias: "best-mouse"
ear_tag:
  l_ear: true
  r_ear: false
ear_notch:
  l_ear: false
  r_ear: false
# Cage IDs MUST be the barcode for the cage
cage_id: 0123456
# Cage Alias is whatever the experimenter likes to refer the cage as
cage_alias: "cage-alias"
# Date of birth in YYYMMDD format
dob: "20220205"
# Descriptions
description: "Mouse Description"
genotype: "HET DAT Cre"
sex: "M"
species: "Mus Musculus"
strain: "C57BL/6J"
# Surgeries are organized by date
surgery:
  "20210924":
    surgeon: "Jeremy Delahanty"
    start_time: "10:00"
    end_time: "11:00"
    stereotax: "Delta"
    anesthetic: "Isoflurane"
    skull_position:
      bregma: -0.02
      lambda: -0.02
      level_left: -0.01
      level_right: -0.01
    headplate:
      num_screws: 1
      skull_hashing: true
    grin_implant:
      target: "mPFC"
      hemisphere: "R"
      type: "Proview"
      dims: [1, 4]
      supplier: "Inscopix"
      ap: 1.90
      ml: 0.45
      dv: -2.18
      angle: null
      notes: "None"
    brain_injections:
      gcamp:
        target: "mPFC"
        hemisphere: "R"
        virus: "AAV8"
        promoter: "promoter"
        opsin: null
        fluorophore: "jGCaMP7f"
        fluorophore_excitation_lambda: 482.5
        fluorophore_emission_lambda: 513.0
        supplier: "The Salk Institute for Biological Studies"
        description: "Calcium Sensitive Green Fluorescent Indicator"
        lot: null
        ap: 1.90
        ml: 0.45
        dv: -2.20
        angle: null
        # Volume in nL
        volume: 300
        # Rate in nL/min
        rate: 100.0
        # Bevel Direction: Away from you is 0 degrees
        bevel: 90
      chr:
        target: "VTA"
        hemisphere: "R"
        virus: "AAV8"
        promoter: "hSyn"
        cre: "FLEX"
        flp: null
        opsin: "chrimsonR"
        opsin_excitation_lambda: 100.0
        fluorophore: "tdTomato"
        fluorophore_excitation_lambda: 482.5
        fluorophore_emission_lambda: 581.0
        supplier: "Supplier"
        description: "description"
        lot: null
        ap: -3.30
        ml: 0.35
        dv: -4.05
        angle: null
        # Volume in nL
        volume: 700.0
        # Rate in nL/min
        rate: 100.0
        # Bevel Direction
        bevel: 180
    analgesics:
      buprinex:
        route: "IP"
        location: "abdomen"
        # Dosages are in mg/kg
        dose: 1.0
        # Volumes here in mL
        volume: 2.0
      lidocaine:
        route: "SQ"
        location: "scalp"
        dose: null
        volume: 0.5
      loxicam:
        route: "IP"
        location: "abdomen"
        # Dosages are in mg/kg
        dose: 5.0
        volume: 0.5
    fluids:
      ringers:
        route: "IP"
        location: "abdomen"
        percent: 20.0
        volume: 1.0

status:
  alive: true
  time_of_death: null
  death_notes: null

Not every project has this metadata available and no project is required to have it to use the system. Only some of these fields are used by bruker_control while a majority of them are used for NWB compliance. bruker_control does not currently implement NWB files at runtime as it did previously. The module nwb_utils.py may be reimplemented in the future.

There is currently only 1 field that is used by bruker_control:

  • fluorophore_excition_lambda: Wavelength in nanometers (nm) that the injected indicator uses for imaging. Value is multiplied by 2 at runtime to change the laser wavelength

The remaining fields are used for documentation of the subject and NWB compliance.

Example Subject Metadata: Weights

The NWB standard asks for weights to be recorded for a given recording. While they’re not required, users typically are weighing subjects before imaging sessions. In order to programatically add weights to the NWB File and access them later, a weights file was added to store subjects’ measurements. The files are very simple and consist of date/weight pairs. The date format is stored as YYYYMMDD as with all other dates stored in this system. Weights are stored in kilograms (kg) per the NWB standard’s documentation.

"20211104": 0.0268
"20211111": 0.0260
"20211118": 0.0273
"20211125": 0.0250
"20211202": 0.0279
"20211209": 0.0247
"20211214": 0.0279