diff --git a/bonsai/Bonsai.config b/bonsai/Bonsai.config index fd9f98e..b982f6f 100644 --- a/bonsai/Bonsai.config +++ b/bonsai/Bonsai.config @@ -3,7 +3,7 @@ - + @@ -16,13 +16,13 @@ - - + + - + @@ -30,10 +30,10 @@ - - - - + + + + @@ -44,7 +44,7 @@ - + @@ -122,7 +122,7 @@ - + @@ -135,13 +135,13 @@ - - + + - + @@ -149,10 +149,10 @@ - - - - + + + + @@ -161,7 +161,7 @@ - + diff --git a/schema/aind_behavior_dynamic_foraging.json b/schema/aind_behavior_dynamic_foraging.json index 43be2c9..0af0aa5 100644 --- a/schema/aind_behavior_dynamic_foraging.json +++ b/schema/aind_behavior_dynamic_foraging.json @@ -876,7 +876,7 @@ "type": "string" }, "quiescent_duration": { - "$ref": "#/$defs/Distribution", + "$ref": "#/$defs/aind_behavior_services__task__distributions__Distribution__1", "default": { "family": "Exponential", "distribution_parameters": { @@ -907,7 +907,7 @@ "type": "number" }, "inter_trial_interval_duration": { - "$ref": "#/$defs/Distribution", + "$ref": "#/$defs/aind_behavior_services__task__distributions__Distribution__1", "default": { "family": "Exponential", "distribution_parameters": { @@ -924,7 +924,7 @@ "description": "Distribution describing the inter-trial interval (in seconds)." }, "block_len": { - "$ref": "#/$defs/Distribution", + "$ref": "#/$defs/aind_behavior_services__task__distributions__Distribution__1", "default": { "family": "Exponential", "distribution_parameters": { @@ -1008,58 +1008,6 @@ "title": "CoupledTrialGeneratorSpec", "type": "object" }, - "Distribution": { - "description": "Available distributions", - "discriminator": { - "mapping": { - "Beta": "#/$defs/BetaDistribution", - "Binomial": "#/$defs/BinomialDistribution", - "Exponential": "#/$defs/ExponentialDistribution", - "Gamma": "#/$defs/GammaDistribution", - "LogNormal": "#/$defs/LogNormalDistribution", - "Normal": "#/$defs/NormalDistribution", - "Pdf": "#/$defs/PdfDistribution", - "Poisson": "#/$defs/PoissonDistribution", - "Scalar": "#/$defs/Scalar", - "Uniform": "#/$defs/UniformDistribution" - }, - "propertyName": "family" - }, - "oneOf": [ - { - "$ref": "#/$defs/Scalar" - }, - { - "$ref": "#/$defs/NormalDistribution" - }, - { - "$ref": "#/$defs/LogNormalDistribution" - }, - { - "$ref": "#/$defs/ExponentialDistribution" - }, - { - "$ref": "#/$defs/UniformDistribution" - }, - { - "$ref": "#/$defs/PoissonDistribution" - }, - { - "$ref": "#/$defs/BinomialDistribution" - }, - { - "$ref": "#/$defs/BetaDistribution" - }, - { - "$ref": "#/$defs/GammaDistribution" - }, - { - "$ref": "#/$defs/PdfDistribution" - } - ], - "title": "Distribution", - "x-sgen-typename": "AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution" - }, "DynamicForagingSoundCard": { "description": "A calibrated sound card for the dynamic foraging rig. This is a subclass of the HarpSoundCard that includes the sound card calibration.", "properties": { @@ -1946,6 +1894,32 @@ "type": "object", "x-sgen-typename": "AllenNeuralDynamics.AindBehaviorServices.Distributions.PoissonDistributionParameters" }, + "QuickRetractSettings": { + "description": "Settings for the quick retract feature.", + "properties": { + "enable_during_quiescence": { + "default": false, + "description": "If true, the quick retract feature is enabled during the quiescence period.", + "title": "Enable During Quiescence", + "type": "boolean" + }, + "time_to_reset_during_quiescence": { + "$ref": "#/$defs/aind_behavior_services__task__distributions__Distribution__2", + "default": 1.0, + "description": "If enable_during_quiescence is true, this is the time the spout will take to reset. If the quiescence period is shorter than this time, the spout will retract at the end of the period.", + "ge": 0, + "x-sgen-typename": "AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution" + }, + "enable_on_response": { + "default": false, + "description": "If true, the quick retract feature is enabled immediately after a response is registered.", + "title": "Enable On Response", + "type": "boolean" + } + }, + "title": "QuickRetractSettings", + "type": "object" + }, "Rect": { "description": "Represents a rectangle defined by its top-left corner, width, and height.", "properties": { @@ -2778,11 +2752,17 @@ "title": "Response Deadline Duration", "type": "number" }, - "enable_fast_retract": { - "default": false, - "description": "If true, the opposite lickspout retracts quickly after a response is made.", - "title": "Enable Fast Retract", - "type": "boolean" + "fast_retract_settings": { + "default": null, + "description": "Settings for the quick retract feature. If null, the feature will be disabled for this trial.", + "oneOf": [ + { + "$ref": "#/$defs/QuickRetractSettings" + }, + { + "type": "null" + } + ] }, "quiescence_period_duration": { "default": 0.5, @@ -3150,7 +3130,7 @@ "type": "string" }, "quiescent_duration": { - "$ref": "#/$defs/Distribution", + "$ref": "#/$defs/aind_behavior_services__task__distributions__Distribution__1", "default": { "family": "Exponential", "distribution_parameters": { @@ -3181,7 +3161,7 @@ "type": "number" }, "inter_trial_interval_duration": { - "$ref": "#/$defs/Distribution", + "$ref": "#/$defs/aind_behavior_services__task__distributions__Distribution__1", "default": { "family": "Exponential", "distribution_parameters": { @@ -3198,7 +3178,7 @@ "description": "Distribution describing the inter-trial interval (in seconds)." }, "block_len": { - "$ref": "#/$defs/Distribution", + "$ref": "#/$defs/aind_behavior_services__task__distributions__Distribution__1", "default": { "family": "Scalar", "distribution_parameters": { @@ -3440,6 +3420,109 @@ }, "title": "WebCamera", "type": "object" + }, + "aind_behavior_services__task__distributions__Distribution__1": { + "description": "Available distributions", + "discriminator": { + "mapping": { + "Beta": "#/$defs/BetaDistribution", + "Binomial": "#/$defs/BinomialDistribution", + "Exponential": "#/$defs/ExponentialDistribution", + "Gamma": "#/$defs/GammaDistribution", + "LogNormal": "#/$defs/LogNormalDistribution", + "Normal": "#/$defs/NormalDistribution", + "Pdf": "#/$defs/PdfDistribution", + "Poisson": "#/$defs/PoissonDistribution", + "Scalar": "#/$defs/Scalar", + "Uniform": "#/$defs/UniformDistribution" + }, + "propertyName": "family" + }, + "oneOf": [ + { + "$ref": "#/$defs/Scalar" + }, + { + "$ref": "#/$defs/NormalDistribution" + }, + { + "$ref": "#/$defs/LogNormalDistribution" + }, + { + "$ref": "#/$defs/ExponentialDistribution" + }, + { + "$ref": "#/$defs/UniformDistribution" + }, + { + "$ref": "#/$defs/PoissonDistribution" + }, + { + "$ref": "#/$defs/BinomialDistribution" + }, + { + "$ref": "#/$defs/BetaDistribution" + }, + { + "$ref": "#/$defs/GammaDistribution" + }, + { + "$ref": "#/$defs/PdfDistribution" + } + ], + "title": "Distribution", + "x-sgen-typename": "AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution" + }, + "aind_behavior_services__task__distributions__Distribution__2": { + "description": "Available distributions", + "discriminator": { + "mapping": { + "Beta": "#/$defs/BetaDistribution", + "Binomial": "#/$defs/BinomialDistribution", + "Exponential": "#/$defs/ExponentialDistribution", + "Gamma": "#/$defs/GammaDistribution", + "LogNormal": "#/$defs/LogNormalDistribution", + "Normal": "#/$defs/NormalDistribution", + "Pdf": "#/$defs/PdfDistribution", + "Poisson": "#/$defs/PoissonDistribution", + "Scalar": "#/$defs/Scalar", + "Uniform": "#/$defs/UniformDistribution" + }, + "propertyName": "family" + }, + "oneOf": [ + { + "$ref": "#/$defs/Scalar" + }, + { + "$ref": "#/$defs/NormalDistribution" + }, + { + "$ref": "#/$defs/LogNormalDistribution" + }, + { + "$ref": "#/$defs/ExponentialDistribution" + }, + { + "$ref": "#/$defs/UniformDistribution" + }, + { + "$ref": "#/$defs/PoissonDistribution" + }, + { + "$ref": "#/$defs/BinomialDistribution" + }, + { + "$ref": "#/$defs/BetaDistribution" + }, + { + "$ref": "#/$defs/GammaDistribution" + }, + { + "$ref": "#/$defs/PdfDistribution" + } + ], + "title": "Distribution" } } } \ No newline at end of file diff --git a/src/Extensions.csproj b/src/Extensions.csproj index 667d0a4..fa0f74c 100644 --- a/src/Extensions.csproj +++ b/src/Extensions.csproj @@ -17,6 +17,7 @@ + - + \ No newline at end of file diff --git a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs index c3dfd91..43ed004 100644 --- a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs +++ b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs @@ -2797,6 +2797,123 @@ public override string ToString() } + /// + /// Settings for the quick retract feature. + /// + [System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.9.0.0 (Newtonsoft.Json v13.0.0.0)")] + [System.ComponentModel.DescriptionAttribute("Settings for the quick retract feature.")] + [Bonsai.WorkflowElementCategoryAttribute(Bonsai.ElementCategory.Source)] + [Bonsai.CombinatorAttribute(MethodName="Generate")] + public partial class QuickRetractSettings + { + + private bool _enableDuringQuiescence; + + private AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution _timeToResetDuringQuiescence; + + private bool _enableOnResponse; + + public QuickRetractSettings() + { + _enableDuringQuiescence = false; + _enableOnResponse = false; + } + + protected QuickRetractSettings(QuickRetractSettings other) + { + _enableDuringQuiescence = other._enableDuringQuiescence; + _timeToResetDuringQuiescence = other._timeToResetDuringQuiescence; + _enableOnResponse = other._enableOnResponse; + } + + /// + /// If true, the quick retract feature is enabled during the quiescence period. + /// + [Newtonsoft.Json.JsonPropertyAttribute("enable_during_quiescence")] + [System.ComponentModel.DescriptionAttribute("If true, the quick retract feature is enabled during the quiescence period.")] + public bool EnableDuringQuiescence + { + get + { + return _enableDuringQuiescence; + } + set + { + _enableDuringQuiescence = value; + } + } + + /// + /// If enable_during_quiescence is true, this is the time the spout will take to reset. If the quiescence period is shorter than this time, the spout will retract at the end of the period. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + [Newtonsoft.Json.JsonPropertyAttribute("time_to_reset_during_quiescence")] + [System.ComponentModel.DescriptionAttribute("If enable_during_quiescence is true, this is the time the spout will take to rese" + + "t. If the quiescence period is shorter than this time, the spout will retract at" + + " the end of the period.")] + public AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution TimeToResetDuringQuiescence + { + get + { + return _timeToResetDuringQuiescence; + } + set + { + _timeToResetDuringQuiescence = value; + } + } + + /// + /// If true, the quick retract feature is enabled immediately after a response is registered. + /// + [Newtonsoft.Json.JsonPropertyAttribute("enable_on_response")] + [System.ComponentModel.DescriptionAttribute("If true, the quick retract feature is enabled immediately after a response is reg" + + "istered.")] + public bool EnableOnResponse + { + get + { + return _enableOnResponse; + } + set + { + _enableOnResponse = value; + } + } + + public System.IObservable Generate() + { + return System.Reactive.Linq.Observable.Defer(() => System.Reactive.Linq.Observable.Return(new QuickRetractSettings(this))); + } + + public System.IObservable Generate(System.IObservable source) + { + return System.Reactive.Linq.Observable.Select(source, _ => new QuickRetractSettings(this)); + } + + protected virtual bool PrintMembers(System.Text.StringBuilder stringBuilder) + { + stringBuilder.Append("EnableDuringQuiescence = " + _enableDuringQuiescence + ", "); + stringBuilder.Append("TimeToResetDuringQuiescence = " + _timeToResetDuringQuiescence + ", "); + stringBuilder.Append("EnableOnResponse = " + _enableOnResponse); + return true; + } + + public override string ToString() + { + System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder(); + stringBuilder.Append(GetType().Name); + stringBuilder.Append(" { "); + if (PrintMembers(stringBuilder)) + { + stringBuilder.Append(" "); + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + } + + /// /// Represents a rectangle defined by its top-left corner, width, and height. /// @@ -4414,7 +4531,7 @@ public partial class Trial private double _responseDeadlineDuration; - private bool _enableFastRetract; + private QuickRetractSettings _fastRetractSettings; private double _quiescencePeriodDuration; @@ -4433,7 +4550,6 @@ public Trial() _rewardConsumptionDuration = 5D; _rewardDelayDuration = 0D; _responseDeadlineDuration = 5D; - _enableFastRetract = false; _quiescencePeriodDuration = 0.5D; _interTrialIntervalDuration = 5D; _lickspoutOffsetDelta = 0D; @@ -4447,7 +4563,7 @@ protected Trial(Trial other) _rewardDelayDuration = other._rewardDelayDuration; _secondaryReinforcer = other._secondaryReinforcer; _responseDeadlineDuration = other._responseDeadlineDuration; - _enableFastRetract = other._enableFastRetract; + _fastRetractSettings = other._fastRetractSettings; _quiescencePeriodDuration = other._quiescencePeriodDuration; _interTrialIntervalDuration = other._interTrialIntervalDuration; _isAutoResponseRight = other._isAutoResponseRight; @@ -4559,19 +4675,21 @@ public double ResponseDeadlineDuration } /// - /// If true, the opposite lickspout retracts quickly after a response is made. + /// Settings for the quick retract feature. If null, the feature will be disabled for this trial. /// - [Newtonsoft.Json.JsonPropertyAttribute("enable_fast_retract")] - [System.ComponentModel.DescriptionAttribute("If true, the opposite lickspout retracts quickly after a response is made.")] - public bool EnableFastRetract + [System.Xml.Serialization.XmlIgnoreAttribute()] + [Newtonsoft.Json.JsonPropertyAttribute("fast_retract_settings")] + [System.ComponentModel.DescriptionAttribute("Settings for the quick retract feature. If null, the feature will be disabled for" + + " this trial.")] + public QuickRetractSettings FastRetractSettings { get { - return _enableFastRetract; + return _fastRetractSettings; } set { - _enableFastRetract = value; + _fastRetractSettings = value; } } @@ -4683,7 +4801,7 @@ protected virtual bool PrintMembers(System.Text.StringBuilder stringBuilder) stringBuilder.Append("RewardDelayDuration = " + _rewardDelayDuration + ", "); stringBuilder.Append("SecondaryReinforcer = " + _secondaryReinforcer + ", "); stringBuilder.Append("ResponseDeadlineDuration = " + _responseDeadlineDuration + ", "); - stringBuilder.Append("EnableFastRetract = " + _enableFastRetract + ", "); + stringBuilder.Append("FastRetractSettings = " + _fastRetractSettings + ", "); stringBuilder.Append("QuiescencePeriodDuration = " + _quiescencePeriodDuration + ", "); stringBuilder.Append("InterTrialIntervalDuration = " + _interTrialIntervalDuration + ", "); stringBuilder.Append("IsAutoResponseRight = " + _isAutoResponseRight + ", "); @@ -6116,6 +6234,51 @@ public override string ToString() } + [System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.9.0.0 (Newtonsoft.Json v13.0.0.0)")] + [Newtonsoft.Json.JsonConverter(typeof(JsonInheritanceConverter), "family")] + [Bonsai.WorkflowElementCategoryAttribute(Bonsai.ElementCategory.Source)] + [Bonsai.CombinatorAttribute(MethodName="Generate")] + public partial class TimeToResetDuringQuiescence + { + + public TimeToResetDuringQuiescence() + { + } + + protected TimeToResetDuringQuiescence(TimeToResetDuringQuiescence other) + { + } + + public System.IObservable Generate() + { + return System.Reactive.Linq.Observable.Defer(() => System.Reactive.Linq.Observable.Return(new TimeToResetDuringQuiescence(this))); + } + + public System.IObservable Generate(System.IObservable source) + { + return System.Reactive.Linq.Observable.Select(source, _ => new TimeToResetDuringQuiescence(this)); + } + + protected virtual bool PrintMembers(System.Text.StringBuilder stringBuilder) + { + return false; + } + + public override string ToString() + { + System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder(); + stringBuilder.Append(GetType().Name); + stringBuilder.Append(" { "); + if (PrintMembers(stringBuilder)) + { + stringBuilder.Append(" "); + } + stringBuilder.Append("}"); + return stringBuilder.ToString(); + } + } + + [System.CodeDom.Compiler.GeneratedCodeAttribute("Bonsai.Sgen", "0.9.0.0 (Newtonsoft.Json v13.0.0.0)")] [Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))] public enum BehaviorStabilityParametersBehaviorEvaluationMode @@ -6415,6 +6578,45 @@ private static System.IObservable Process(System.IObservable arguments) + { + var typeMapping = Type; + var returnType = typeMapping != null ? typeMapping.GetType().GetGenericArguments()[0] : typeof(TimeToResetDuringQuiescence); + return System.Linq.Expressions.Expression.Call( + typeof(MatchTimeToResetDuringQuiescence), + "Process", + new System.Type[] { returnType }, + System.Linq.Enumerable.Single(arguments)); + } + + + private static System.IObservable Process(System.IObservable source) + where TResult : TimeToResetDuringQuiescence + { + return System.Reactive.Linq.Observable.Create(observer => + { + var sourceObserver = System.Reactive.Observer.Create( + value => + { + var match = value as TResult; + if (match != null) observer.OnNext(match); + }, + observer.OnError, + observer.OnCompleted); + return System.ObservableExtensions.SubscribeSafe(source, sourceObserver); + }); + } + } + + /// /// Serializes a sequence of data model objects into JSON strings. /// @@ -6528,6 +6730,11 @@ public System.IObservable Process(System.IObservable source return Process(source); } + public System.IObservable Process(System.IObservable source) + { + return Process(source); + } + public System.IObservable Process(System.IObservable source) { return Process(source); @@ -6627,6 +6834,11 @@ public System.IObservable Process(System.IObservable source) { return Process(source); } + + public System.IObservable Process(System.IObservable source) + { + return Process(source); + } } @@ -6656,6 +6868,7 @@ public System.IObservable Process(System.IObservable source) [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))] @@ -6676,6 +6889,7 @@ public System.IObservable Process(System.IObservable source) [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))] [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))] + [System.Xml.Serialization.XmlIncludeAttribute(typeof(Bonsai.Expressions.TypeMapping))] public partial class DeserializeFromJson : Bonsai.Expressions.SingleArgumentExpressionBuilder { diff --git a/src/Extensions/AindManipulator.bonsai b/src/Extensions/AindManipulator.bonsai index fdac889..5b0b47c 100644 --- a/src/Extensions/AindManipulator.bonsai +++ b/src/Extensions/AindManipulator.bonsai @@ -2,6 +2,8 @@ @@ -38,6 +40,80 @@ StepperDriverCommands + + Write + + 4 + + + + Write + + 90 + + + + Write + + 1 + + + + Write + + 2.5 + + + + + + + Write + + 4 + + + + Write + + 90 + + + + Write + + 1 + + + + Write + + 2.5 + + + + + + + + + + + 8 + + + + StepperDriverEvents + + + + + + Item1 + + + StepperDriverCommands + @@ -45,6 +121,21 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Extensions/CalculateSpoutPositions.cs b/src/Extensions/CalculateSpoutPositions.cs new file mode 100644 index 0000000..9fbeb3c --- /dev/null +++ b/src/Extensions/CalculateSpoutPositions.cs @@ -0,0 +1,46 @@ +using Bonsai; +using System; +using System.ComponentModel; +using System.Linq; +using System.Reactive.Linq; +using AllenNeuralDynamics.AindManipulator; + +[Combinator] +[Description("Calculates the retracted and extended positions of the spouts based on the manipulator position and a specified distance.")] +[WorkflowElementCategory(ElementCategory.Transform)] +public class CalculateSpoutPositions +{ + public double SpoutDistance { get; set; } + + public IObservable Process(IObservable> source) + { + return source.Select(value => + { + var initialPosition = value.Item1; + var currentPosition = value.Item2; + return new SpoutPositions + { + Retracted = new ManipulatorPosition() + { + X = currentPosition.X, + Y1 = initialPosition.Y1 - SpoutDistance, + Y2 = initialPosition.Y2 - SpoutDistance, + Z = currentPosition.Z + }, + Extended = new ManipulatorPosition() + { + X = currentPosition.X, + Y1 = initialPosition.Y1, + Y2 = initialPosition.Y2, + Z = currentPosition.Z + }, + }; + }); + } +} + +public class SpoutPositions +{ + public ManipulatorPosition Retracted { get; set; } + public ManipulatorPosition Extended { get; set; } +} diff --git a/src/Extensions/OperationControl.bonsai b/src/Extensions/OperationControl.bonsai index 8fd5b21..f00cfa5 100644 --- a/src/Extensions/OperationControl.bonsai +++ b/src/Extensions/OperationControl.bonsai @@ -7,13 +7,14 @@ xmlns:beh="clr-namespace:Harp.Behavior;assembly=Harp.Behavior" xmlns:scr="clr-namespace:Bonsai.Scripting.Expressions;assembly=Bonsai.Scripting.Expressions" xmlns:sys="clr-namespace:System;assembly=mscorlib" - xmlns:p2="clr-namespace:System.Reactive;assembly=System.Reactive.Core" - xmlns:p3="clr-namespace:AllenNeuralDynamics.AindManipulator;assembly=AllenNeuralDynamics.AindManipulator" - xmlns:p4="clr-namespace:AllenNeuralDynamics.Core;assembly=AllenNeuralDynamics.Core" - xmlns:p5="clr-namespace:Harp.SoundCard;assembly=Harp.SoundCard" - xmlns:p6="clr-namespace:AindDynamicForagingDataSchema;assembly=Extensions" + xmlns:p2="clr-namespace:Harp.StepperDriver;assembly=Harp.StepperDriver" + xmlns:p3="clr-namespace:AllenNeuralDynamics.Core;assembly=AllenNeuralDynamics.Core" + xmlns:p4="clr-namespace:;assembly=Extensions" + xmlns:p5="clr-namespace:AllenNeuralDynamics.AindManipulator;assembly=AllenNeuralDynamics.AindManipulator" + xmlns:p6="clr-namespace:Harp.SoundCard;assembly=Harp.SoundCard" + xmlns:p7="clr-namespace:AindDynamicForagingDataSchema;assembly=Extensions" xmlns:dsp="clr-namespace:Bonsai.Dsp;assembly=Bonsai.Dsp" - xmlns:p7="clr-namespace:Bonsai.Numerics.Distributions;assembly=Bonsai.Numerics" + xmlns:p8="clr-namespace:Bonsai.Numerics.Distributions;assembly=Bonsai.Numerics" xmlns="https://bonsai-rx.org/2018/workflow"> @@ -637,8 +638,97 @@ IsRightTriggerQuickRetract - - ResetQuickRetract + + it ? 2 : 4 + + + Write + + + + StepperDriverCommands + + + SpoutAvailableState + + + StartExperiment + + + ManipulatorPosition + + + + + + + 1 + + + + Item2 + + + InitialManipulatorPosition + + + + InitialManipulatorPosition + + + + SoftwareEvent + + + SpoutAvailableState + + + CalculatePositions + + + + InitialManipulatorPosition + + + ManipulatorPosition + + + + + + + + + + 5 + + + + + 1 + + + + + + + + + + + + + + + + + + + DetermineDirection + it.Item1 ? it.Item2.Extended : it.Item2.Retracted + + + MoveTo @@ -735,11 +825,11 @@ - - 0 - 0 - 0 - 0 + + 0 + 0 + 0 + 0 @@ -749,8 +839,8 @@ ManipulatorBiasTracker - - ManipulatorBiasTracker + + ManipulatorBiasTracker @@ -758,23 +848,38 @@ + + - - - + - - + - + + - + + + + + + + + + + + + + + + + @@ -975,10 +1080,10 @@ - + Write - - 0 + + 0 @@ -1046,7 +1151,7 @@ WaveformType - + Sine @@ -1154,11 +1259,11 @@ - - - 4 - 13000 - SampleRate96000Hz + + + 4 + 13000 + SampleRate96000Hz @@ -1201,7 +1306,7 @@ WaveformType - + WhiteNoise @@ -1232,9 +1337,9 @@ waveformSpec - - -2147483646 - 2147483646 + + -2147483646 + 2147483646 @@ -1264,8 +1369,8 @@ - - 9600 + + 9600 @@ -1310,11 +1415,11 @@ - - - 4 - 13000 - SampleRate96000Hz + + + 4 + 13000 + SampleRate96000Hz diff --git a/src/Extensions/TaskEngine.bonsai b/src/Extensions/TaskEngine.bonsai index 5157a6f..1f249ef 100644 --- a/src/Extensions/TaskEngine.bonsai +++ b/src/Extensions/TaskEngine.bonsai @@ -7,6 +7,7 @@ xmlns:p2="clr-namespace:;assembly=Extensions" xmlns:scr="clr-namespace:Bonsai.Scripting.Expressions;assembly=Bonsai.Scripting.Expressions" xmlns:p3="clr-namespace:AllenNeuralDynamics.Core;assembly=AllenNeuralDynamics.Core" + xmlns:p4="clr-namespace:AllenNeuralDynamics.AindBehaviorServices.Distributions;assembly=AllenNeuralDynamics.AindBehaviorServices.Distributions" xmlns:harp="clr-namespace:Bonsai.Harp;assembly=Bonsai.Harp" xmlns="https://bonsai-rx.org/2018/workflow"> @@ -179,11 +180,14 @@ IsRightLickEvent + + lickReset + - CeateTimer + CreateTimer @@ -230,6 +234,59 @@ 1 + + + + + Source1 + + + + true + + + + ThisTrial + + + FastRetractSettings + + + (it != null) & it.EnableDuringQuiescence + + + + + + it.Item2 + + + Item1 + + + SpoutAvailableState + + + + 1 + + + + + + + + + + + + + + + + + + @@ -240,17 +297,113 @@ SoftwareEvent + + lickReset + + + Retraction&Reset + + + + Source1 + + + + false + + + + SpoutAvailableState + + + ThisTrial + + + FastRetractSettings + + + TimeToResetDuringQuiescence + + + RngSeedValue + + + + + + + + + + + + + + + + + + + + PT0S + + + + + SpoutAvailableState + + + + + + + + + + + + + + + + + + + + + + + + + + ThisTrial + + + FastRetractSettings + + + + + - + - - + + + - + + + + + + + + @@ -479,7 +632,10 @@ Item2 - EnableFastRetract + FastRetractSettings + + + (it != null) && (it.EnableOnResponse) @@ -489,6 +645,7 @@ + @@ -607,7 +764,10 @@ Item2 - EnableFastRetract + FastRetractSettings + + + (it != null) && (it.EnableOnResponse) @@ -619,6 +779,7 @@ + @@ -1224,9 +1385,23 @@ - + + ThisTrial + + + FastRetractSettings + + + EnableOnResponse? + (it != null) && it.EnableOnResponse + + + + true + + - ResetQuickRetract + SpoutAvailableState @@ -1269,8 +1444,11 @@ + + + diff --git a/src/aind_behavior_dynamic_foraging/task_logic/trial_models.py b/src/aind_behavior_dynamic_foraging/task_logic/trial_models.py index e483824..bc32b78 100644 --- a/src/aind_behavior_dynamic_foraging/task_logic/trial_models.py +++ b/src/aind_behavior_dynamic_foraging/task_logic/trial_models.py @@ -1,5 +1,6 @@ from typing import TYPE_CHECKING, Annotated, Any, Literal, Optional, TypeAliasType, Union +from aind_behavior_services.task.distributions import Distribution from pydantic import BaseModel, Field, SerializeAsAny @@ -21,6 +22,23 @@ class AuditorySecondaryReinforcer(BaseModel): ) +class QuickRetractSettings(BaseModel): + """Settings for the quick retract feature.""" + + enable_during_quiescence: bool = Field( + default=False, description="If true, the quick retract feature is enabled during the quiescence period." + ) + time_to_reset_during_quiescence: Distribution = Field( + default=1.0, + ge=0, + description="If enable_during_quiescence is true, this is the time the spout will take to reset. If the quiescence period is shorter than this time, the spout will retract at the end of the period.", + ) + enable_on_response: bool = Field( + default=False, + description="If true, the quick retract feature is enabled immediately after a response is registered.", + ) + + class Trial(BaseModel): """Represents a single trial that can be instantiated by the Bonsai state machine.""" @@ -42,8 +60,9 @@ class Trial(BaseModel): response_deadline_duration: float = Field( default=5.0, ge=0, description="Time allowed for the subject to make a response (in seconds)." ) - enable_fast_retract: bool = Field( - default=False, description="If true, the opposite lickspout retracts quickly after a response is made." + fast_retract_settings: Optional[QuickRetractSettings] = Field( + default=None, + description="Settings for the quick retract feature. If null, the feature will be disabled for this trial.", ) quiescence_period_duration: float = Field( default=0.5,