From 3d5877b3fdef9f604d299ea2d53f434b567ad14e Mon Sep 17 00:00:00 2001 From: Micah Woodard Date: Wed, 8 Jul 2026 09:11:05 -0700 Subject: [PATCH 01/10] moves reward size to trial level --- examples/task_logic.py | 2 - schema/aind_behavior_dynamic_foraging.json | 91 +++++-- schema/coupled_baiting.json | 73 +++--- schema/uncoupled.json | 73 +++--- schema/uncoupled_baiting.json | 73 +++--- .../AindBehaviorDynamicForaging.Generated.cs | 227 +++++++++++++++--- src/Extensions/TaskEngine.bonsai | 80 +++++- src/Extensions/ValveUi.bonsai | 54 +---- .../task_logic/__init__.py | 11 +- .../interventions/bias_intervention.py | 6 + .../block_based_trial_generator.py | 16 +- .../task_logic/trial_models.py | 4 + src/main.bonsai | 46 ++-- .../coupled_baiting/stages.py | 17 +- .../uncoupled/stages.py | 15 +- .../uncoupled_baiting/stages.py | 17 +- 16 files changed, 549 insertions(+), 256 deletions(-) diff --git a/examples/task_logic.py b/examples/task_logic.py index dc16f9d8..c298bfa8 100644 --- a/examples/task_logic.py +++ b/examples/task_logic.py @@ -2,13 +2,11 @@ from aind_behavior_curriculum import Stage, TrainerState -import aind_behavior_dynamic_foraging.task_logic as df_task_logic from aind_behavior_dynamic_foraging.task_logic import AindDynamicForagingTaskLogic, AindDynamicForagingTaskParameters task_logic = AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( rng_seed=42, - reward_size=df_task_logic.RewardSize(right_value_volume=4.0, left_value_volume=4.0), ) ) diff --git a/schema/aind_behavior_dynamic_foraging.json b/schema/aind_behavior_dynamic_foraging.json index 07b258fd..f35af4d9 100644 --- a/schema/aind_behavior_dynamic_foraging.json +++ b/schema/aind_behavior_dynamic_foraging.json @@ -199,14 +199,6 @@ "title": "aind_behavior_services package version", "type": "string" }, - "reward_size": { - "$ref": "#/$defs/RewardSize", - "default": { - "right_value_volume": 3.0, - "left_value_volume": 3.0 - }, - "description": "Parameters describing reward size." - }, "trial_generator": { "$ref": "#/$defs/TrialGeneratorSpec", "default": { @@ -440,6 +432,14 @@ "title": "Type", "type": "string" }, + "reward_size": { + "$ref": "#/$defs/RewardSize", + "default": { + "right": 3.0, + "left": 3.0 + }, + "description": "Parameters describing reward size." + }, "quiescent_duration": { "$ref": "#/$defs/Distribution", "default": { @@ -530,7 +530,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "description": "Antibias settings. If set, trial generator will give water and move lickspouts to combat bias.", "oneOf": [ @@ -714,6 +715,14 @@ "minimum": 0, "title": "Lickspout Offset Delta", "type": "number" + }, + "reward_fraction": { + "default": 0.8, + "description": "Fraction of full reward volume delivered for water intervention (0=none, 1=full).", + "maximum": 1, + "minimum": 0, + "title": "Reward Fraction", + "type": "number" } }, "title": "BiasInterventionParameters", @@ -825,6 +834,14 @@ "title": "Type", "type": "string" }, + "reward_size": { + "$ref": "#/$defs/RewardSize", + "default": { + "right": 3.0, + "left": 3.0 + }, + "description": "Parameters describing reward size." + }, "quiescent_duration": { "$ref": "#/$defs/Distribution", "default": { @@ -915,7 +932,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "description": "Antibias settings. If set, trial generator will give water and move lickspouts to combat bias.", "oneOf": [ @@ -1112,6 +1130,14 @@ "title": "Type", "type": "string" }, + "reward_size": { + "$ref": "#/$defs/RewardSize", + "default": { + "right": 3.0, + "left": 3.0 + }, + "description": "Parameters describing reward size." + }, "quiescent_duration": { "$ref": "#/$defs/Distribution", "default": { @@ -1202,7 +1228,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "description": "Antibias settings. If set, trial generator will give water and move lickspouts to combat bias.", "oneOf": [ @@ -1326,6 +1353,14 @@ "title": "Type", "type": "string" }, + "reward_size": { + "$ref": "#/$defs/RewardSize", + "default": { + "right": 3.0, + "left": 3.0 + }, + "description": "Parameters describing reward size." + }, "quiescent_duration": { "$ref": "#/$defs/Distribution", "default": { @@ -1412,7 +1447,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "description": "Antibias settings. If set, trial generator will give water and move lickspouts to combat bias.", "oneOf": [ @@ -2663,18 +2699,18 @@ }, "RewardSize": { "properties": { - "right_value_volume": { + "right": { "title": "Right reward size (uL)", "type": "number" }, - "left_value_volume": { + "left": { "title": "Left reward size (uL)", "type": "number" } }, "required": [ - "right_value_volume", - "left_value_volume" + "right", + "left" ], "title": "RewardSize", "type": "object" @@ -3379,6 +3415,18 @@ "Trial": { "description": "Represents a single trial that can be instantiated by the Bonsai state machine.", "properties": { + "reward_size_left": { + "default": 1.0, + "minimum": 0, + "title": "Left reward size (uL)", + "type": "number" + }, + "reward_size_right": { + "default": 1.0, + "minimum": 0, + "title": "Right reward size (uL)", + "type": "number" + }, "p_reward_left": { "default": 1.0, "description": "The probability of reward on the left side if response is made.", @@ -3686,6 +3734,14 @@ "title": "Type", "type": "string" }, + "reward_size": { + "$ref": "#/$defs/RewardSize", + "default": { + "right": 3.0, + "left": 3.0 + }, + "description": "Parameters describing reward size." + }, "quiescent_duration": { "$ref": "#/$defs/Distribution", "default": { @@ -3773,7 +3829,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "description": "Antibias settings. If set, trial generator will give water and move lickspouts to combat bias.", "oneOf": [ diff --git a/schema/coupled_baiting.json b/schema/coupled_baiting.json index 80179c46..7cc6fe78 100644 --- a/schema/coupled_baiting.json +++ b/schema/coupled_baiting.json @@ -12,15 +12,15 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 4.0, - "left_value_volume": 4.0 - }, "trial_generator": { "type": "TrialGeneratorComposite", "generators": [ { "type": "CoupledWarmupTrialGenerator", + "reward_size": { + "right": 4.0, + "left": 4.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -67,7 +67,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -88,6 +89,10 @@ }, { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 4.0, + "left": 4.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -138,7 +143,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -187,12 +193,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -243,7 +249,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -290,12 +297,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -346,7 +353,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -393,12 +401,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -449,7 +457,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -496,12 +505,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -552,7 +561,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -607,12 +617,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -663,7 +673,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { diff --git a/schema/uncoupled.json b/schema/uncoupled.json index 9b5caf9b..3dd9df07 100644 --- a/schema/uncoupled.json +++ b/schema/uncoupled.json @@ -12,15 +12,15 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 4.0, - "left_value_volume": 4.0 - }, "trial_generator": { "type": "TrialGeneratorComposite", "generators": [ { "type": "CoupledWarmupTrialGenerator", + "reward_size": { + "right": 4.0, + "left": 4.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -67,7 +67,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -88,6 +89,10 @@ }, { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 4.0, + "left": 4.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -138,7 +143,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -187,12 +193,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -243,7 +249,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -290,12 +297,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -346,7 +353,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": false, "reward_probability_parameters": { @@ -393,12 +401,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "UncoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -446,7 +454,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": false, "trial_generation_end_parameters": { @@ -482,12 +491,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "UncoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -531,7 +540,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": false, "trial_generation_end_parameters": { @@ -567,12 +577,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "UncoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -616,7 +626,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": false, "trial_generation_end_parameters": { diff --git a/schema/uncoupled_baiting.json b/schema/uncoupled_baiting.json index 1ceddb14..c3a6cf39 100644 --- a/schema/uncoupled_baiting.json +++ b/schema/uncoupled_baiting.json @@ -12,15 +12,15 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 4.0, - "left_value_volume": 4.0 - }, "trial_generator": { "type": "TrialGeneratorComposite", "generators": [ { "type": "CoupledWarmupTrialGenerator", + "reward_size": { + "right": 4.0, + "left": 4.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -67,7 +67,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -88,6 +89,10 @@ }, { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 4.0, + "left": 4.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -138,7 +143,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -187,12 +193,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -243,7 +249,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -290,12 +297,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "CoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -346,7 +353,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "reward_probability_parameters": { @@ -393,12 +401,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "UncoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -446,7 +454,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "trial_generation_end_parameters": { @@ -482,12 +491,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "UncoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -535,7 +544,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "trial_generation_end_parameters": { @@ -571,12 +581,12 @@ "task_parameters": { "rng_seed": null, "aind_behavior_services_pkg_version": "0.13.5", - "reward_size": { - "right_value_volume": 2.0, - "left_value_volume": 2.0 - }, "trial_generator": { "type": "UncoupledTrialGenerator", + "reward_size": { + "right": 2.0, + "left": 2.0 + }, "quiescent_duration": { "family": "Scalar", "distribution_parameters": { @@ -624,7 +634,8 @@ "intervention_interval": 10, "maximum_water_corrections": 5, "bias_window_length": 200, - "lickspout_offset_delta": 0.05 + "lickspout_offset_delta": 0.05, + "reward_fraction": 0.8 }, "is_baiting": true, "trial_generation_end_parameters": { diff --git a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs index cebc5012..89b40ca0 100644 --- a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs +++ b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs @@ -584,14 +584,11 @@ public partial class AindDynamicForagingTaskParameters private string _aindBehaviorServicesPkgVersion; - private RewardSize _rewardSize; - private TrialGeneratorSpec _trialGenerator; public AindDynamicForagingTaskParameters() { _aindBehaviorServicesPkgVersion = "0.13.5"; - _rewardSize = new RewardSize(); _trialGenerator = new TrialGeneratorSpec(); } @@ -599,7 +596,6 @@ protected AindDynamicForagingTaskParameters(AindDynamicForagingTaskParameters ot { _rngSeed = other._rngSeed; _aindBehaviorServicesPkgVersion = other._aindBehaviorServicesPkgVersion; - _rewardSize = other._rewardSize; _trialGenerator = other._trialGenerator; } @@ -633,24 +629,6 @@ public string AindBehaviorServicesPkgVersion } } - /// - /// Parameters describing reward size. - /// - [System.Xml.Serialization.XmlIgnoreAttribute()] - [Newtonsoft.Json.JsonPropertyAttribute("reward_size")] - [System.ComponentModel.DescriptionAttribute("Parameters describing reward size.")] - public RewardSize RewardSize - { - get - { - return _rewardSize; - } - set - { - _rewardSize = value; - } - } - /// /// Trial generator model for generating trials in the task. /// @@ -683,7 +661,6 @@ protected virtual bool PrintMembers(System.Text.StringBuilder stringBuilder) { stringBuilder.Append("RngSeed = " + _rngSeed + ", "); stringBuilder.Append("AindBehaviorServicesPkgVersion = " + _aindBehaviorServicesPkgVersion + ", "); - stringBuilder.Append("RewardSize = " + _rewardSize + ", "); stringBuilder.Append("TrialGenerator = " + _trialGenerator); return true; } @@ -885,6 +862,8 @@ public override string ToString() public partial class BaseCoupledTrialGeneratorSpec : TrialGeneratorSpec { + private RewardSize _rewardSize; + private AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution _quiescentDuration; private double _responseDuration; @@ -905,6 +884,7 @@ public partial class BaseCoupledTrialGeneratorSpec : TrialGeneratorSpec public BaseCoupledTrialGeneratorSpec() { + _rewardSize = new RewardSize(); _quiescentDuration = new AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution(); _responseDuration = 1D; _rewardConsumptionDuration = 3D; @@ -919,6 +899,7 @@ public BaseCoupledTrialGeneratorSpec() protected BaseCoupledTrialGeneratorSpec(BaseCoupledTrialGeneratorSpec other) : base(other) { + _rewardSize = other._rewardSize; _quiescentDuration = other._quiescentDuration; _responseDuration = other._responseDuration; _rewardConsumptionDuration = other._rewardConsumptionDuration; @@ -930,6 +911,24 @@ protected BaseCoupledTrialGeneratorSpec(BaseCoupledTrialGeneratorSpec other) : _rewardProbabilityParameters = other._rewardProbabilityParameters; } + /// + /// Parameters describing reward size. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + [Newtonsoft.Json.JsonPropertyAttribute("reward_size")] + [System.ComponentModel.DescriptionAttribute("Parameters describing reward size.")] + public RewardSize RewardSize + { + get + { + return _rewardSize; + } + set + { + _rewardSize = value; + } + } + /// /// Distribution describing the quiescence period before trial starts (in seconds). Each lick resets the timer. /// @@ -1109,6 +1108,7 @@ protected override bool PrintMembers(System.Text.StringBuilder stringBuilder) { stringBuilder.Append(", "); } + stringBuilder.Append("RewardSize = " + _rewardSize + ", "); stringBuilder.Append("QuiescentDuration = " + _quiescentDuration + ", "); stringBuilder.Append("ResponseDuration = " + _responseDuration + ", "); stringBuilder.Append("RewardConsumptionDuration = " + _rewardConsumptionDuration + ", "); @@ -1300,6 +1300,8 @@ public partial class BiasInterventionParameters private double _lickspoutOffsetDelta; + private double _rewardFraction; + public BiasInterventionParameters() { _threshold = new BiasThreshold(); @@ -1307,6 +1309,7 @@ public BiasInterventionParameters() _maximumWaterCorrections = 5; _biasWindowLength = 200; _lickspoutOffsetDelta = 0.05D; + _rewardFraction = 0.8D; } protected BiasInterventionParameters(BiasInterventionParameters other) @@ -1316,6 +1319,7 @@ protected BiasInterventionParameters(BiasInterventionParameters other) _maximumWaterCorrections = other._maximumWaterCorrections; _biasWindowLength = other._biasWindowLength; _lickspoutOffsetDelta = other._lickspoutOffsetDelta; + _rewardFraction = other._rewardFraction; } /// @@ -1405,6 +1409,24 @@ public double LickspoutOffsetDelta } } + /// + /// Fraction of full reward volume delivered for water intervention (0=none, 1=full). + /// + [Newtonsoft.Json.JsonPropertyAttribute("reward_fraction")] + [System.ComponentModel.DescriptionAttribute("Fraction of full reward volume delivered for water intervention (0=none, 1=full)." + + "")] + public double RewardFraction + { + get + { + return _rewardFraction; + } + set + { + _rewardFraction = value; + } + } + public System.IObservable Generate() { return System.Reactive.Linq.Observable.Defer(() => System.Reactive.Linq.Observable.Return(new BiasInterventionParameters(this))); @@ -1421,7 +1443,8 @@ protected virtual bool PrintMembers(System.Text.StringBuilder stringBuilder) stringBuilder.Append("InterventionInterval = " + _interventionInterval + ", "); stringBuilder.Append("MaximumWaterCorrections = " + _maximumWaterCorrections + ", "); stringBuilder.Append("BiasWindowLength = " + _biasWindowLength + ", "); - stringBuilder.Append("LickspoutOffsetDelta = " + _lickspoutOffsetDelta); + stringBuilder.Append("LickspoutOffsetDelta = " + _lickspoutOffsetDelta + ", "); + stringBuilder.Append("RewardFraction = " + _rewardFraction); return true; } @@ -1534,6 +1557,8 @@ public override string ToString() public partial class BlockBasedTrialGeneratorSpec : TrialGeneratorSpec { + private RewardSize _rewardSize; + private AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution _quiescentDuration; private double _responseDuration; @@ -1552,6 +1577,7 @@ public partial class BlockBasedTrialGeneratorSpec : TrialGeneratorSpec public BlockBasedTrialGeneratorSpec() { + _rewardSize = new RewardSize(); _quiescentDuration = new AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution(); _responseDuration = 1D; _rewardConsumptionDuration = 3D; @@ -1565,6 +1591,7 @@ public BlockBasedTrialGeneratorSpec() protected BlockBasedTrialGeneratorSpec(BlockBasedTrialGeneratorSpec other) : base(other) { + _rewardSize = other._rewardSize; _quiescentDuration = other._quiescentDuration; _responseDuration = other._responseDuration; _rewardConsumptionDuration = other._rewardConsumptionDuration; @@ -1575,6 +1602,24 @@ protected BlockBasedTrialGeneratorSpec(BlockBasedTrialGeneratorSpec other) : _isBaiting = other._isBaiting; } + /// + /// Parameters describing reward size. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + [Newtonsoft.Json.JsonPropertyAttribute("reward_size")] + [System.ComponentModel.DescriptionAttribute("Parameters describing reward size.")] + public RewardSize RewardSize + { + get + { + return _rewardSize; + } + set + { + _rewardSize = value; + } + } + /// /// Distribution describing the quiescence period before trial starts (in seconds). Each lick resets the timer. /// @@ -1736,6 +1781,7 @@ protected override bool PrintMembers(System.Text.StringBuilder stringBuilder) { stringBuilder.Append(", "); } + stringBuilder.Append("RewardSize = " + _rewardSize + ", "); stringBuilder.Append("QuiescentDuration = " + _quiescentDuration + ", "); stringBuilder.Append("ResponseDuration = " + _responseDuration + ", "); stringBuilder.Append("RewardConsumptionDuration = " + _rewardConsumptionDuration + ", "); @@ -2258,6 +2304,8 @@ public override string ToString() public partial class CoupledTrialGeneratorSpec : TrialGeneratorSpec { + private RewardSize _rewardSize; + private AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution _quiescentDuration; private double _responseDuration; @@ -2288,6 +2336,7 @@ public partial class CoupledTrialGeneratorSpec : TrialGeneratorSpec public CoupledTrialGeneratorSpec() { + _rewardSize = new RewardSize(); _quiescentDuration = new AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution(); _responseDuration = 1D; _rewardConsumptionDuration = 3D; @@ -2307,6 +2356,7 @@ public CoupledTrialGeneratorSpec() protected CoupledTrialGeneratorSpec(CoupledTrialGeneratorSpec other) : base(other) { + _rewardSize = other._rewardSize; _quiescentDuration = other._quiescentDuration; _responseDuration = other._responseDuration; _rewardConsumptionDuration = other._rewardConsumptionDuration; @@ -2323,6 +2373,24 @@ protected CoupledTrialGeneratorSpec(CoupledTrialGeneratorSpec other) : _kernelSize = other._kernelSize; } + /// + /// Parameters describing reward size. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + [Newtonsoft.Json.JsonPropertyAttribute("reward_size")] + [System.ComponentModel.DescriptionAttribute("Parameters describing reward size.")] + public RewardSize RewardSize + { + get + { + return _rewardSize; + } + set + { + _rewardSize = value; + } + } + /// /// Distribution describing the quiescence period before trial starts (in seconds). Each lick resets the timer. /// @@ -2587,6 +2655,7 @@ protected override bool PrintMembers(System.Text.StringBuilder stringBuilder) { stringBuilder.Append(", "); } + stringBuilder.Append("RewardSize = " + _rewardSize + ", "); stringBuilder.Append("QuiescentDuration = " + _quiescentDuration + ", "); stringBuilder.Append("ResponseDuration = " + _responseDuration + ", "); stringBuilder.Append("RewardConsumptionDuration = " + _rewardConsumptionDuration + ", "); @@ -2744,6 +2813,8 @@ public override string ToString() public partial class CoupledWarmupTrialGeneratorSpec : TrialGeneratorSpec { + private RewardSize _rewardSize; + private AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution _quiescentDuration; private double _responseDuration; @@ -2766,6 +2837,7 @@ public partial class CoupledWarmupTrialGeneratorSpec : TrialGeneratorSpec public CoupledWarmupTrialGeneratorSpec() { + _rewardSize = new RewardSize(); _quiescentDuration = new AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution(); _responseDuration = 1D; _rewardConsumptionDuration = 3D; @@ -2781,6 +2853,7 @@ public CoupledWarmupTrialGeneratorSpec() protected CoupledWarmupTrialGeneratorSpec(CoupledWarmupTrialGeneratorSpec other) : base(other) { + _rewardSize = other._rewardSize; _quiescentDuration = other._quiescentDuration; _responseDuration = other._responseDuration; _rewardConsumptionDuration = other._rewardConsumptionDuration; @@ -2793,6 +2866,24 @@ protected CoupledWarmupTrialGeneratorSpec(CoupledWarmupTrialGeneratorSpec other) _trialGenerationEndParameters = other._trialGenerationEndParameters; } + /// + /// Parameters describing reward size. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + [Newtonsoft.Json.JsonPropertyAttribute("reward_size")] + [System.ComponentModel.DescriptionAttribute("Parameters describing reward size.")] + public RewardSize RewardSize + { + get + { + return _rewardSize; + } + set + { + _rewardSize = value; + } + } + /// /// Distribution describing the quiescence period before trial starts (in seconds). Each lick resets the timer. /// @@ -2989,6 +3080,7 @@ protected override bool PrintMembers(System.Text.StringBuilder stringBuilder) { stringBuilder.Append(", "); } + stringBuilder.Append("RewardSize = " + _rewardSize + ", "); stringBuilder.Append("QuiescentDuration = " + _quiescentDuration + ", "); stringBuilder.Append("ResponseDuration = " + _responseDuration + ", "); stringBuilder.Append("RewardConsumptionDuration = " + _rewardConsumptionDuration + ", "); @@ -4721,9 +4813,9 @@ public override string ToString() public partial class RewardSize { - private double _rightValueVolume; + private double _right; - private double _leftValueVolume; + private double _left; public RewardSize() { @@ -4731,33 +4823,33 @@ public RewardSize() protected RewardSize(RewardSize other) { - _rightValueVolume = other._rightValueVolume; - _leftValueVolume = other._leftValueVolume; + _right = other._right; + _left = other._left; } - [Newtonsoft.Json.JsonPropertyAttribute("right_value_volume", Required=Newtonsoft.Json.Required.Always)] - public double RightValueVolume + [Newtonsoft.Json.JsonPropertyAttribute("right", Required=Newtonsoft.Json.Required.Always)] + public double Right { get { - return _rightValueVolume; + return _right; } set { - _rightValueVolume = value; + _right = value; } } - [Newtonsoft.Json.JsonPropertyAttribute("left_value_volume", Required=Newtonsoft.Json.Required.Always)] - public double LeftValueVolume + [Newtonsoft.Json.JsonPropertyAttribute("left", Required=Newtonsoft.Json.Required.Always)] + public double Left { get { - return _leftValueVolume; + return _left; } set { - _leftValueVolume = value; + _left = value; } } @@ -4773,8 +4865,8 @@ public System.IObservable Generate(System.IObservable /// The probability of reward on the left side if response is made. /// @@ -6348,6 +6474,8 @@ public System.IObservable Generate(System.IObservable s protected virtual bool PrintMembers(System.Text.StringBuilder stringBuilder) { + stringBuilder.Append("RewardSizeLeft = " + _rewardSizeLeft + ", "); + stringBuilder.Append("RewardSizeRight = " + _rewardSizeRight + ", "); stringBuilder.Append("PRewardLeft = " + _pRewardLeft + ", "); stringBuilder.Append("PRewardRight = " + _pRewardRight + ", "); stringBuilder.Append("RewardConsumptionDuration = " + _rewardConsumptionDuration + ", "); @@ -6878,6 +7006,8 @@ a higher reward probability than the other. public partial class UncoupledTrialGeneratorSpec : TrialGeneratorSpec { + private RewardSize _rewardSize; + private AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution _quiescentDuration; private double _responseDuration; @@ -6902,6 +7032,7 @@ public partial class UncoupledTrialGeneratorSpec : TrialGeneratorSpec public UncoupledTrialGeneratorSpec() { + _rewardSize = new RewardSize(); _quiescentDuration = new AllenNeuralDynamics.AindBehaviorServices.Distributions.Distribution(); _responseDuration = 1D; _rewardConsumptionDuration = 3D; @@ -6918,6 +7049,7 @@ public UncoupledTrialGeneratorSpec() protected UncoupledTrialGeneratorSpec(UncoupledTrialGeneratorSpec other) : base(other) { + _rewardSize = other._rewardSize; _quiescentDuration = other._quiescentDuration; _responseDuration = other._responseDuration; _rewardConsumptionDuration = other._rewardConsumptionDuration; @@ -6931,6 +7063,24 @@ protected UncoupledTrialGeneratorSpec(UncoupledTrialGeneratorSpec other) : _maximumDominanceStreak = other._maximumDominanceStreak; } + /// + /// Parameters describing reward size. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + [Newtonsoft.Json.JsonPropertyAttribute("reward_size")] + [System.ComponentModel.DescriptionAttribute("Parameters describing reward size.")] + public RewardSize RewardSize + { + get + { + return _rewardSize; + } + set + { + _rewardSize = value; + } + } + /// /// Distribution describing the quiescence period before trial starts (in seconds). Each lick resets the timer. /// @@ -7145,6 +7295,7 @@ protected override bool PrintMembers(System.Text.StringBuilder stringBuilder) { stringBuilder.Append(", "); } + stringBuilder.Append("RewardSize = " + _rewardSize + ", "); stringBuilder.Append("QuiescentDuration = " + _quiescentDuration + ", "); stringBuilder.Append("ResponseDuration = " + _responseDuration + ", "); stringBuilder.Append("RewardConsumptionDuration = " + _rewardConsumptionDuration + ", "); diff --git a/src/Extensions/TaskEngine.bonsai b/src/Extensions/TaskEngine.bonsai index 7cb5dde1..e7f6c294 100644 --- a/src/Extensions/TaskEngine.bonsai +++ b/src/Extensions/TaskEngine.bonsai @@ -747,6 +747,70 @@ response + + SetRightRewardSize + + + + + true + + + + ThisTrial + + + RewardRightSize + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + + SetLeftRewardSize + + + + + false + + + + ThisTrial + + + RewardRightSize + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + response @@ -779,14 +843,14 @@ - - - - - - - - + + + + + + + + diff --git a/src/Extensions/ValveUi.bonsai b/src/Extensions/ValveUi.bonsai index f2541c94..e0ca1c7c 100644 --- a/src/Extensions/ValveUi.bonsai +++ b/src/Extensions/ValveUi.bonsai @@ -363,17 +363,7 @@ Source1 - TaskLogicParameters - - - RewardSize - - - - - - ValveVolume - it.Item1 ? it.Item2.RightValueVolume : it.Item2.LeftValueVolume + DefaultRewardSize @@ -384,14 +374,10 @@ - - - - + + + - - - @@ -896,13 +882,7 @@ - TaskLogicParameters - - - RewardSize - - - LeftValueVolume + DefaultRewardSize @@ -914,12 +894,10 @@ - - + + - - - + @@ -1111,13 +1089,7 @@ - TaskLogicParameters - - - RewardSize - - - RightValueVolume + DefaultRewardSize @@ -1129,12 +1101,10 @@ - - + + - - - + diff --git a/src/aind_behavior_dynamic_foraging/task_logic/__init__.py b/src/aind_behavior_dynamic_foraging/task_logic/__init__.py index 2820d1f9..9ca5f68e 100644 --- a/src/aind_behavior_dynamic_foraging/task_logic/__init__.py +++ b/src/aind_behavior_dynamic_foraging/task_logic/__init__.py @@ -1,7 +1,7 @@ from typing import Literal from aind_behavior_services.task import Task, TaskParameters -from pydantic import BaseModel, Field +from pydantic import Field from aind_behavior_dynamic_foraging import ( __semver__, @@ -10,12 +10,6 @@ from . import trial_models as trial_models from .trial_generators import IntegrationTestTrialGeneratorSpec, TrialGeneratorSpec - -class RewardSize(BaseModel): - right_value_volume: float = Field(title="Right reward size (uL)") - left_value_volume: float = Field(title="Left reward size (uL)") - - # ==================== MAIN TASK LOGIC CLASSES ==================== @@ -28,9 +22,6 @@ class AindDynamicForagingTaskParameters(TaskParameters): and numerical updaters for dynamic parameter modification. """ - reward_size: RewardSize = Field( - default=RewardSize(left_value_volume=3, right_value_volume=3), description="Parameters describing reward size." - ) trial_generator: TrialGeneratorSpec = Field( default=IntegrationTestTrialGeneratorSpec(), description="Trial generator model for generating trials in the task.", diff --git a/src/aind_behavior_dynamic_foraging/task_logic/interventions/bias_intervention.py b/src/aind_behavior_dynamic_foraging/task_logic/interventions/bias_intervention.py index 35670182..2b570bf2 100644 --- a/src/aind_behavior_dynamic_foraging/task_logic/interventions/bias_intervention.py +++ b/src/aind_behavior_dynamic_foraging/task_logic/interventions/bias_intervention.py @@ -23,6 +23,12 @@ class BiasInterventionParameters(BaseModel): ge=0, description="Distance (mm) to move the stage spouts by. This is a relative distance to the current value, not absolute.", ) + reward_fraction: float = Field( + default=0.8, + ge=0, + le=1, + description="Fraction of full reward volume delivered for water intervention (0=none, 1=full).", + ) class BiasIntervention: diff --git a/src/aind_behavior_dynamic_foraging/task_logic/trial_generators/block_based_trial_generator.py b/src/aind_behavior_dynamic_foraging/task_logic/trial_generators/block_based_trial_generator.py index 273ac14f..ccf8e28f 100644 --- a/src/aind_behavior_dynamic_foraging/task_logic/trial_generators/block_based_trial_generator.py +++ b/src/aind_behavior_dynamic_foraging/task_logic/trial_generators/block_based_trial_generator.py @@ -42,7 +42,7 @@ class AutoWaterParameters(BaseModel): ge=0, le=1, description="Fraction of full reward volume delivered during auto water (0=none, 1=full).", - ) # TODO: Not implemented yet + ) class Block(BaseModel): @@ -52,9 +52,18 @@ class Block(BaseModel): left_length: int = Field(ge=0, description="Minimum number of trials in block.") +class RewardSize(BaseModel): + right: float = Field(title="Right reward size (uL)") + left: float = Field(title="Left reward size (uL)") + + class BlockBasedTrialGeneratorSpec(BaseTrialGeneratorSpecModel): type: Literal["BlockBasedTrialGenerator"] = "BlockBasedTrialGenerator" + reward_size: RewardSize = Field( + default=RewardSize(left=3, right=3), description="Parameters describing reward size." + ) + quiescent_duration: Distribution = Field( default=ExponentialDistribution( distribution_parameters=ExponentialDistributionParameters(rate=1), @@ -195,10 +204,12 @@ def next(self) -> Trial | None: logger.debug("Right baited: %s" % self.is_right_baited) is_auto_reward_right = None + reward_frac = 1 # determine autowater if is_autowater := self._are_autowater_conditions_met(): is_auto_reward_right = True if self.block.p_right_reward > self.block.p_left_reward else False + reward_frac = self.spec.autowater_parameters.reward_fraction logger.debug("Delivering autowater: is_auto_reward_right = %s" % is_auto_reward_right) # determine bias correction. Overrides autowater @@ -207,12 +218,15 @@ def next(self) -> Trial | None: is_auto_reward_right, lickspout_offset_delta = self.bias_intervention.determine_antibias_intervention( self.bias ) + reward_frac = 1 if is_auto_reward_right is None else self.spec.bias_intervention_parameters.reward_fraction logger.debug( "Performing bias intervention: is_auto_reward_right = %s, lickspout_offset_delta = %s." % (is_auto_reward_right, lickspout_offset_delta) ) return Trial( + reward_size_left=self.spec.reward_size.left * reward_frac, + reward_size_right=self.spec.reward_size.right * reward_frac, p_reward_left=1 if (self.is_left_baited or is_auto_reward_right is False) else self.block.p_left_reward, p_reward_right=1 if (self.is_right_baited or is_auto_reward_right) else self.block.p_right_reward, reward_consumption_duration=self.spec.reward_consumption_duration, 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 f1b93237..6a4b2f74 100644 --- a/src/aind_behavior_dynamic_foraging/task_logic/trial_models.py +++ b/src/aind_behavior_dynamic_foraging/task_logic/trial_models.py @@ -67,6 +67,10 @@ class Metadata(BaseModel): class Trial(BaseModel): """Represents a single trial that can be instantiated by the Bonsai state machine.""" + reward_size_left: float = Field(default=1.0, ge=0, title="Left reward size (uL)") + + reward_size_right: float = Field(default=1.0, ge=0, title="Right reward size (uL)") + p_reward_left: float = Field( default=1.0, ge=0, le=1, description="The probability of reward on the left side if response is made." ) diff --git a/src/main.bonsai b/src/main.bonsai index e5825026..eab4eaaa 100644 --- a/src/main.bonsai +++ b/src/main.bonsai @@ -208,6 +208,18 @@ ExperimentState + + Default size + + + + + 2 + + + + DefaultRewardSize + SetIsRightRewardAmount @@ -222,13 +234,7 @@ - TaskLogicParameters - - - RewardSize - - - RightValueVolume + DefaultRewardSize @@ -247,13 +253,7 @@ - TaskLogicParameters - - - RewardSize - - - LeftValueVolume + DefaultRewardSize @@ -300,20 +300,18 @@ - - - + + - - - - - - + + + + + + - diff --git a/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/coupled_baiting/stages.py b/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/coupled_baiting/stages.py index a92acb17..85b26359 100644 --- a/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/coupled_baiting/stages.py +++ b/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/coupled_baiting/stages.py @@ -2,13 +2,15 @@ from aind_behavior_dynamic_foraging.task_logic import ( AindDynamicForagingTaskLogic, AindDynamicForagingTaskParameters, - RewardSize, ) from aind_behavior_dynamic_foraging.task_logic.trial_generators import ( CoupledTrialGeneratorSpec, CoupledWarmupTrialGeneratorSpec, TrialGeneratorCompositeSpec, ) +from aind_behavior_dynamic_foraging.task_logic.trial_generators.block_based_trial_generator import ( + RewardSize, +) from aind_behavior_dynamic_foraging.task_logic.trial_generators.coupled_trial_generators.base_coupled_trial_generator import ( RewardProbabilityParameters, ) @@ -35,10 +37,10 @@ def make_s_stage_1_warmup(): name="stage_1_warmup", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=4.0, left_value_volume=4.0), trial_generator=TrialGeneratorCompositeSpec( generators=[ CoupledWarmupTrialGeneratorSpec( + reward_size=RewardSize(right=4.0, left=4.0), reward_probability_parameters=RewardProbabilityParameters( base_reward_sum=1, reward_pairs=[[1.0, 0.0]] ), @@ -53,6 +55,7 @@ def make_s_stage_1_warmup(): reward_consumption_duration=1.0, ), CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=4.0, left=4.0), trial_generation_end_parameters=CoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, @@ -97,8 +100,8 @@ def make_s_stage_1(): name="stage_1", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), trial_generation_end_parameters=CoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, @@ -141,8 +144,8 @@ def make_s_stage_2(): name="stage_2", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), trial_generation_end_parameters=CoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, @@ -185,8 +188,8 @@ def make_s_stage_3(): name="stage_3", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), trial_generation_end_parameters=CoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, @@ -229,8 +232,8 @@ def make_s_stage_final(): name="final", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), trial_generation_end_parameters=CoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, @@ -269,8 +272,8 @@ def make_s_stage_graduated(): name="graduated", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), trial_generation_end_parameters=CoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, diff --git a/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled/stages.py b/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled/stages.py index ae4917d8..be7ed275 100644 --- a/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled/stages.py +++ b/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled/stages.py @@ -2,7 +2,6 @@ from aind_behavior_dynamic_foraging.task_logic import ( AindDynamicForagingTaskLogic, AindDynamicForagingTaskParameters, - RewardSize, ) from aind_behavior_dynamic_foraging.task_logic.trial_generators import ( CoupledTrialGeneratorSpec, @@ -11,6 +10,7 @@ ) from aind_behavior_dynamic_foraging.task_logic.trial_generators.block_based_trial_generator import ( AutoWaterParameters, + RewardSize, ) from aind_behavior_dynamic_foraging.task_logic.trial_generators.coupled_trial_generators.base_coupled_trial_generator import ( RewardProbabilityParameters, @@ -47,10 +47,10 @@ def make_s_stage_1_warmup(): name="stage_1_warmup", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=4.0, left_value_volume=4.0), trial_generator=TrialGeneratorCompositeSpec( generators=[ CoupledWarmupTrialGeneratorSpec( + reward_size=RewardSize(right=4.0, left=4.0), autowater_parameters=AutoWaterParameters( reward_fraction=0.5, min_ignored_trials=3, min_unrewarded_trials=3 ), @@ -74,6 +74,7 @@ def make_s_stage_1_warmup(): reward_consumption_duration=1.0, ), CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=4.0, left=4.0), autowater_parameters=AutoWaterParameters( reward_fraction=0.5, min_ignored_trials=3, min_unrewarded_trials=3 ), @@ -121,8 +122,8 @@ def make_s_stage_1(): name="stage_1", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), autowater_parameters=AutoWaterParameters( reward_fraction=0.5, min_ignored_trials=5, min_unrewarded_trials=5 ), @@ -168,8 +169,8 @@ def make_s_stage_2(): name="stage_2", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), autowater_parameters=AutoWaterParameters( reward_fraction=0.5, min_ignored_trials=7, min_unrewarded_trials=7 ), @@ -215,8 +216,8 @@ def make_s_stage_3(): name="stage_3", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=UncoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), autowater_parameters=AutoWaterParameters( reward_fraction=0.5, min_ignored_trials=10, min_unrewarded_trials=10 ), @@ -251,8 +252,8 @@ def make_s_stage_final(): name="final", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=UncoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), trial_generation_end_parameters=UncoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, @@ -285,8 +286,8 @@ def make_s_stage_graduated(): name="graduated", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=UncoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), autowater_parameters=None, trial_generation_end_parameters=UncoupledTrialGenerationEndConditions( max_trial=1000, diff --git a/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled_baiting/stages.py b/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled_baiting/stages.py index a3098ab3..bcb17af0 100644 --- a/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled_baiting/stages.py +++ b/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled_baiting/stages.py @@ -2,13 +2,15 @@ from aind_behavior_dynamic_foraging.task_logic import ( AindDynamicForagingTaskLogic, AindDynamicForagingTaskParameters, - RewardSize, ) from aind_behavior_dynamic_foraging.task_logic.trial_generators import ( CoupledTrialGeneratorSpec, CoupledWarmupTrialGeneratorSpec, TrialGeneratorCompositeSpec, ) +from aind_behavior_dynamic_foraging.task_logic.trial_generators.block_based_trial_generator import ( + RewardSize, +) from aind_behavior_dynamic_foraging.task_logic.trial_generators.coupled_trial_generators.base_coupled_trial_generator import ( RewardProbabilityParameters, ) @@ -44,10 +46,10 @@ def make_s_stage_1_warmup(): name="stage_1_warmup", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=4.0, left_value_volume=4.0), trial_generator=TrialGeneratorCompositeSpec( generators=[ CoupledWarmupTrialGeneratorSpec( + reward_size=RewardSize(right=4.0, left=4.0), trial_generation_end_parameters=CoupledWarmupTrialGenerationEndConditions( min_trial=50, max_choice_bias=0.1, @@ -68,6 +70,7 @@ def make_s_stage_1_warmup(): reward_consumption_duration=1.0, ), CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=4.0, left=4.0), trial_generation_end_parameters=CoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, @@ -112,8 +115,8 @@ def make_s_stage_1(): name="stage_1", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), trial_generation_end_parameters=CoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, @@ -156,8 +159,8 @@ def make_s_stage_2(): name="stage_2", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=CoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), trial_generation_end_parameters=CoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, @@ -200,8 +203,8 @@ def make_s_stage_3(): name="stage_3", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=UncoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), trial_generation_end_parameters=UncoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, @@ -233,8 +236,8 @@ def make_s_stage_final(): name="final", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=UncoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), trial_generation_end_parameters=UncoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, @@ -266,8 +269,8 @@ def make_s_stage_graduated(): name="graduated", task=AindDynamicForagingTaskLogic( task_parameters=AindDynamicForagingTaskParameters( - reward_size=RewardSize(right_value_volume=2.0, left_value_volume=2.0), trial_generator=UncoupledTrialGeneratorSpec( + reward_size=RewardSize(right=2.0, left=2.0), trial_generation_end_parameters=UncoupledTrialGenerationEndConditions( max_trial=1000, max_time=4500, From 2565ed86f452f51d17274d5b673e20371958313a Mon Sep 17 00:00:00 2001 From: Micah Woodard Date: Wed, 8 Jul 2026 09:30:02 -0700 Subject: [PATCH 02/10] fixes names --- src/Extensions/TaskEngine.bonsai | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Extensions/TaskEngine.bonsai b/src/Extensions/TaskEngine.bonsai index e7f6c294..4e101d66 100644 --- a/src/Extensions/TaskEngine.bonsai +++ b/src/Extensions/TaskEngine.bonsai @@ -760,7 +760,7 @@ ThisTrial - RewardRightSize + RewardSizeRight @@ -792,7 +792,7 @@ ThisTrial - RewardRightSize + RewardSizeLeft From e2c4193852bcc6951dc7c68afcffcfa08757a7d6 Mon Sep 17 00:00:00 2001 From: Micah Woodard Date: Wed, 8 Jul 2026 12:11:55 -0700 Subject: [PATCH 03/10] moves reward size update to iti --- schema/aind_behavior_dynamic_foraging.json | 40 ++- .../AindBehaviorDynamicForaging.Generated.cs | 39 +-- src/Extensions/TaskEngine.bonsai | 231 ++++++++++-------- src/Extensions/ValveUi.bonsai | 2 +- .../block_based_trial_generator.py | 22 +- .../task_logic/trial_models.py | 11 +- 6 files changed, 174 insertions(+), 171 deletions(-) diff --git a/schema/aind_behavior_dynamic_foraging.json b/schema/aind_behavior_dynamic_foraging.json index f35af4d9..2ddf9081 100644 --- a/schema/aind_behavior_dynamic_foraging.json +++ b/schema/aind_behavior_dynamic_foraging.json @@ -435,8 +435,8 @@ "reward_size": { "$ref": "#/$defs/RewardSize", "default": { - "right": 3.0, - "left": 3.0 + "right": 2.0, + "left": 2.0 }, "description": "Parameters describing reward size." }, @@ -837,8 +837,8 @@ "reward_size": { "$ref": "#/$defs/RewardSize", "default": { - "right": 3.0, - "left": 3.0 + "right": 2.0, + "left": 2.0 }, "description": "Parameters describing reward size." }, @@ -1133,8 +1133,8 @@ "reward_size": { "$ref": "#/$defs/RewardSize", "default": { - "right": 3.0, - "left": 3.0 + "right": 2.0, + "left": 2.0 }, "description": "Parameters describing reward size." }, @@ -1356,8 +1356,8 @@ "reward_size": { "$ref": "#/$defs/RewardSize", "default": { - "right": 3.0, - "left": 3.0 + "right": 2.0, + "left": 2.0 }, "description": "Parameters describing reward size." }, @@ -2700,10 +2700,12 @@ "RewardSize": { "properties": { "right": { + "exclusiveMinimum": 0, "title": "Right reward size (uL)", "type": "number" }, "left": { + "exclusiveMinimum": 0, "title": "Left reward size (uL)", "type": "number" } @@ -3415,17 +3417,13 @@ "Trial": { "description": "Represents a single trial that can be instantiated by the Bonsai state machine.", "properties": { - "reward_size_left": { - "default": 1.0, - "minimum": 0, - "title": "Left reward size (uL)", - "type": "number" - }, - "reward_size_right": { - "default": 1.0, - "minimum": 0, - "title": "Right reward size (uL)", - "type": "number" + "reward_size": { + "$ref": "#/$defs/RewardSize", + "default": { + "right": 3.0, + "left": 3.0 + }, + "description": "Parameters describing reward size." }, "p_reward_left": { "default": 1.0, @@ -3737,8 +3735,8 @@ "reward_size": { "$ref": "#/$defs/RewardSize", "default": { - "right": 3.0, - "left": 3.0 + "right": 2.0, + "left": 2.0 }, "description": "Parameters describing reward size." }, diff --git a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs index 89b40ca0..32cf2c59 100644 --- a/src/Extensions/AindBehaviorDynamicForaging.Generated.cs +++ b/src/Extensions/AindBehaviorDynamicForaging.Generated.cs @@ -6165,9 +6165,7 @@ public enum SpinnakerCameraPixelFormat public partial class Trial { - private double _rewardSizeLeft; - - private double _rewardSizeRight; + private RewardSize _rewardSize; private double _pRewardLeft; @@ -6195,8 +6193,7 @@ public partial class Trial public Trial() { - _rewardSizeLeft = 1D; - _rewardSizeRight = 1D; + _rewardSize = new RewardSize(); _pRewardLeft = 1D; _pRewardRight = 1D; _rewardConsumptionDuration = 5D; @@ -6209,8 +6206,7 @@ public Trial() protected Trial(Trial other) { - _rewardSizeLeft = other._rewardSizeLeft; - _rewardSizeRight = other._rewardSizeRight; + _rewardSize = other._rewardSize; _pRewardLeft = other._pRewardLeft; _pRewardRight = other._pRewardRight; _rewardConsumptionDuration = other._rewardConsumptionDuration; @@ -6225,29 +6221,21 @@ protected Trial(Trial other) _metadata = other._metadata; } - [Newtonsoft.Json.JsonPropertyAttribute("reward_size_left")] - public double RewardSizeLeft - { - get - { - return _rewardSizeLeft; - } - set - { - _rewardSizeLeft = value; - } - } - - [Newtonsoft.Json.JsonPropertyAttribute("reward_size_right")] - public double RewardSizeRight + /// + /// Parameters describing reward size. + /// + [System.Xml.Serialization.XmlIgnoreAttribute()] + [Newtonsoft.Json.JsonPropertyAttribute("reward_size")] + [System.ComponentModel.DescriptionAttribute("Parameters describing reward size.")] + public RewardSize RewardSize { get { - return _rewardSizeRight; + return _rewardSize; } set { - _rewardSizeRight = value; + _rewardSize = value; } } @@ -6474,8 +6462,7 @@ public System.IObservable Generate(System.IObservable s protected virtual bool PrintMembers(System.Text.StringBuilder stringBuilder) { - stringBuilder.Append("RewardSizeLeft = " + _rewardSizeLeft + ", "); - stringBuilder.Append("RewardSizeRight = " + _rewardSizeRight + ", "); + stringBuilder.Append("RewardSize = " + _rewardSize + ", "); stringBuilder.Append("PRewardLeft = " + _pRewardLeft + ", "); stringBuilder.Append("PRewardRight = " + _pRewardRight + ", "); stringBuilder.Append("RewardConsumptionDuration = " + _rewardConsumptionDuration + ", "); diff --git a/src/Extensions/TaskEngine.bonsai b/src/Extensions/TaskEngine.bonsai index 4e101d66..cac7762f 100644 --- a/src/Extensions/TaskEngine.bonsai +++ b/src/Extensions/TaskEngine.bonsai @@ -747,70 +747,6 @@ response - - SetRightRewardSize - - - - - true - - - - ThisTrial - - - RewardSizeRight - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - - - SetLeftRewardSize - - - - - false - - - - ThisTrial - - - RewardSizeLeft - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - response @@ -843,14 +779,14 @@ - - - - - - - - + + + + + + + + @@ -1229,30 +1165,6 @@ thisTrialOutcome - - ThisTrial - - - - 1 - - - - InterTrialIntervalDuration - - - - - - - - - - - - PT5S - - SampleNextTrial @@ -1376,6 +1288,108 @@ + + NextTrial + + + SetLeftRewardSize + + + + + false + + + + NextTrial + + + RewardSize.Left + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + + + SetRightRewardSize + + + + + true + + + + NextTrial + + + RewardSize.Right + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + + + ThisTrial + + + + 1 + + + + InterTrialIntervalDuration + + + + + + + + + + + + PT5S + + + + NextTrial + GlobalAutoWaterState @@ -1516,29 +1530,30 @@ - - - - - + + - - - + + + - - + + - + + - + + + + diff --git a/src/Extensions/ValveUi.bonsai b/src/Extensions/ValveUi.bonsai index e0ca1c7c..213f6f68 100644 --- a/src/Extensions/ValveUi.bonsai +++ b/src/Extensions/ValveUi.bonsai @@ -366,7 +366,7 @@ DefaultRewardSize - + SetIsRightRewardAmount diff --git a/src/aind_behavior_dynamic_foraging/task_logic/trial_generators/block_based_trial_generator.py b/src/aind_behavior_dynamic_foraging/task_logic/trial_generators/block_based_trial_generator.py index ccf8e28f..8eee0f80 100644 --- a/src/aind_behavior_dynamic_foraging/task_logic/trial_generators/block_based_trial_generator.py +++ b/src/aind_behavior_dynamic_foraging/task_logic/trial_generators/block_based_trial_generator.py @@ -18,7 +18,7 @@ ) from aind_behavior_dynamic_foraging.task_logic.utils.calculate_bias import calculate_bias -from ..trial_models import Metadata, Trial, TrialMetrics +from ..trial_models import Metadata, RewardSize, Trial, TrialMetrics from ._base import BaseTrialGeneratorSpecModel, ITrialGenerator, TrialOutcome logger = logging.getLogger(__name__) @@ -52,16 +52,11 @@ class Block(BaseModel): left_length: int = Field(ge=0, description="Minimum number of trials in block.") -class RewardSize(BaseModel): - right: float = Field(title="Right reward size (uL)") - left: float = Field(title="Left reward size (uL)") - - class BlockBasedTrialGeneratorSpec(BaseTrialGeneratorSpecModel): type: Literal["BlockBasedTrialGenerator"] = "BlockBasedTrialGenerator" reward_size: RewardSize = Field( - default=RewardSize(left=3, right=3), description="Parameters describing reward size." + default=RewardSize(left=2, right=2), description="Parameters describing reward size." ) quiescent_duration: Distribution = Field( @@ -204,12 +199,12 @@ def next(self) -> Trial | None: logger.debug("Right baited: %s" % self.is_right_baited) is_auto_reward_right = None - reward_frac = 1 + reward_fraction = 1 # determine autowater if is_autowater := self._are_autowater_conditions_met(): is_auto_reward_right = True if self.block.p_right_reward > self.block.p_left_reward else False - reward_frac = self.spec.autowater_parameters.reward_fraction + reward_fraction = self.spec.autowater_parameters.reward_fraction logger.debug("Delivering autowater: is_auto_reward_right = %s" % is_auto_reward_right) # determine bias correction. Overrides autowater @@ -218,15 +213,15 @@ def next(self) -> Trial | None: is_auto_reward_right, lickspout_offset_delta = self.bias_intervention.determine_antibias_intervention( self.bias ) - reward_frac = 1 if is_auto_reward_right is None else self.spec.bias_intervention_parameters.reward_fraction + reward_fraction = ( + 1 if is_auto_reward_right is None else self.spec.bias_intervention_parameters.reward_fraction + ) logger.debug( "Performing bias intervention: is_auto_reward_right = %s, lickspout_offset_delta = %s." % (is_auto_reward_right, lickspout_offset_delta) ) return Trial( - reward_size_left=self.spec.reward_size.left * reward_frac, - reward_size_right=self.spec.reward_size.right * reward_frac, p_reward_left=1 if (self.is_left_baited or is_auto_reward_right is False) else self.block.p_left_reward, p_reward_right=1 if (self.is_right_baited or is_auto_reward_right) else self.block.p_right_reward, reward_consumption_duration=self.spec.reward_consumption_duration, @@ -235,6 +230,9 @@ def next(self) -> Trial | None: inter_trial_interval_duration=iti, lickspout_offset_delta=lickspout_offset_delta, is_auto_reward_right=is_auto_reward_right, + reward_size=RewardSize( + left=self.spec.reward_size.left * reward_fraction, right=self.spec.reward_size.right * reward_fraction + ), metadata=Metadata( p_reward_left=self.block.p_left_reward, p_reward_right=self.block.p_right_reward, 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 6a4b2f74..b595e202 100644 --- a/src/aind_behavior_dynamic_foraging/task_logic/trial_models.py +++ b/src/aind_behavior_dynamic_foraging/task_logic/trial_models.py @@ -64,12 +64,17 @@ class Metadata(BaseModel): ) +class RewardSize(BaseModel): + right: float = Field(gt=0, title="Right reward size (uL)") + left: float = Field(gt=0, title="Left reward size (uL)") + + class Trial(BaseModel): """Represents a single trial that can be instantiated by the Bonsai state machine.""" - reward_size_left: float = Field(default=1.0, ge=0, title="Left reward size (uL)") - - reward_size_right: float = Field(default=1.0, ge=0, title="Right reward size (uL)") + reward_size: RewardSize = Field( + default=RewardSize(left=2.0, right=2.0), description="Parameters describing reward size." + ) p_reward_left: float = Field( default=1.0, ge=0, le=1, description="The probability of reward on the left side if response is made." From bd582a6f3e86d7100535ca4363457cae60c15566 Mon Sep 17 00:00:00 2001 From: Micah Woodard Date: Wed, 8 Jul 2026 12:20:11 -0700 Subject: [PATCH 04/10] regenerates --- schema/aind_behavior_dynamic_foraging.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/schema/aind_behavior_dynamic_foraging.json b/schema/aind_behavior_dynamic_foraging.json index 2ddf9081..3659540d 100644 --- a/schema/aind_behavior_dynamic_foraging.json +++ b/schema/aind_behavior_dynamic_foraging.json @@ -3420,8 +3420,8 @@ "reward_size": { "$ref": "#/$defs/RewardSize", "default": { - "right": 3.0, - "left": 3.0 + "right": 2.0, + "left": 2.0 }, "description": "Parameters describing reward size." }, From 7384231b4cbc1366ee36ce6706780a734c5d429d Mon Sep 17 00:00:00 2001 From: Micah Woodard Date: Wed, 8 Jul 2026 14:50:58 -0700 Subject: [PATCH 05/10] set reward size for first trial --- src/Extensions/TaskEngine.bonsai | 92 ++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 10 deletions(-) diff --git a/src/Extensions/TaskEngine.bonsai b/src/Extensions/TaskEngine.bonsai index cac7762f..56c353d5 100644 --- a/src/Extensions/TaskEngine.bonsai +++ b/src/Extensions/TaskEngine.bonsai @@ -26,6 +26,78 @@ GlobalTrial + + SetLeftRewardSize + + + + + false + + + + ThisTrial + + + RewardSize.Left + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + + + SetRightRewardSize + + + + + true + + + + ThisTrial + + + RewardSize.Right + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + @@ -1601,28 +1673,28 @@ - - - + - + - + - + - + - + - + + - + + From e98dbb554dbcf625bd0dfe2caff2d03117c234f9 Mon Sep 17 00:00:00 2001 From: Micah Woodard Date: Wed, 8 Jul 2026 14:53:35 -0700 Subject: [PATCH 06/10] moves reward size to quiescent period --- src/Extensions/TaskEngine.bonsai | 335 ++++++++++++------------------- 1 file changed, 128 insertions(+), 207 deletions(-) diff --git a/src/Extensions/TaskEngine.bonsai b/src/Extensions/TaskEngine.bonsai index 56c353d5..62fac00a 100644 --- a/src/Extensions/TaskEngine.bonsai +++ b/src/Extensions/TaskEngine.bonsai @@ -26,78 +26,6 @@ GlobalTrial - - SetLeftRewardSize - - - - - false - - - - ThisTrial - - - RewardSize.Left - - - - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - - - - SetRightRewardSize - - - - - true - - - - ThisTrial - - - RewardSize.Right - - - - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - - @@ -247,6 +175,78 @@ QuiescentPeriod + + SetRightRewardSize + + + + + true + + + + ThisTrial + + + RewardSize.Right + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + + + SetLeftRewardSize + + + + + false + + + + ThisTrial + + + RewardSize.Left + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + IsRightLickEvent @@ -432,23 +432,23 @@ - - - - + + - + + - + - - + - - + + + + @@ -1237,6 +1237,30 @@ thisTrialOutcome + + ThisTrial + + + + 1 + + + + InterTrialIntervalDuration + + + + + + + + + + + + PT5S + + SampleNextTrial @@ -1360,108 +1384,6 @@ - - NextTrial - - - SetLeftRewardSize - - - - - false - - - - NextTrial - - - RewardSize.Left - - - - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - - - - SetRightRewardSize - - - - - true - - - - NextTrial - - - RewardSize.Right - - - - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - - - - ThisTrial - - - - 1 - - - - InterTrialIntervalDuration - - - - - - - - - - - - PT5S - - - - NextTrial - GlobalAutoWaterState @@ -1602,30 +1524,29 @@ + + + - - + + - - - + + + - - + + - - + + - - - - @@ -1673,28 +1594,28 @@ - + + + - + - + - + - + - + - + - + - - From 088725a1f84d51286d58b8db1608fbdbb0106412 Mon Sep 17 00:00:00 2001 From: Micah Woodard Date: Wed, 8 Jul 2026 15:28:30 -0700 Subject: [PATCH 07/10] Revert "moves reward size to quiescent period" This reverts commit e98dbb554dbcf625bd0dfe2caff2d03117c234f9. --- src/Extensions/TaskEngine.bonsai | 335 +++++++++++++++++++------------ 1 file changed, 207 insertions(+), 128 deletions(-) diff --git a/src/Extensions/TaskEngine.bonsai b/src/Extensions/TaskEngine.bonsai index 62fac00a..56c353d5 100644 --- a/src/Extensions/TaskEngine.bonsai +++ b/src/Extensions/TaskEngine.bonsai @@ -26,6 +26,78 @@ GlobalTrial + + SetLeftRewardSize + + + + + false + + + + ThisTrial + + + RewardSize.Left + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + + + SetRightRewardSize + + + + + true + + + + ThisTrial + + + RewardSize.Right + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + @@ -175,78 +247,6 @@ QuiescentPeriod - - SetRightRewardSize - - - - - true - - - - ThisTrial - - - RewardSize.Right - - - - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - - - - SetLeftRewardSize - - - - - false - - - - ThisTrial - - - RewardSize.Left - - - - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - - IsRightLickEvent @@ -432,23 +432,23 @@ - - + + + + - + - - + - + + - - - - + + @@ -1237,30 +1237,6 @@ thisTrialOutcome - - ThisTrial - - - - 1 - - - - InterTrialIntervalDuration - - - - - - - - - - - - PT5S - - SampleNextTrial @@ -1384,6 +1360,108 @@ + + NextTrial + + + SetLeftRewardSize + + + + + false + + + + NextTrial + + + RewardSize.Left + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + + + SetRightRewardSize + + + + + true + + + + NextTrial + + + RewardSize.Right + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + + + ThisTrial + + + + 1 + + + + InterTrialIntervalDuration + + + + + + + + + + + + PT5S + + + + NextTrial + GlobalAutoWaterState @@ -1524,29 +1602,30 @@ - - - - - + + - - - + + + - - + + - + + - + + + + @@ -1594,28 +1673,28 @@ - - - + - + - + - + - + - + - + + - + + From d6304ae87797b186a9f2ea95b907d4f620cf0a3b Mon Sep 17 00:00:00 2001 From: Micah Woodard Date: Wed, 8 Jul 2026 15:50:22 -0700 Subject: [PATCH 08/10] create pre trial select many --- src/Extensions/TaskEngine.bonsai | 335 +++++++++++++------------------ 1 file changed, 139 insertions(+), 196 deletions(-) diff --git a/src/Extensions/TaskEngine.bonsai b/src/Extensions/TaskEngine.bonsai index 56c353d5..a25d374b 100644 --- a/src/Extensions/TaskEngine.bonsai +++ b/src/Extensions/TaskEngine.bonsai @@ -26,78 +26,6 @@ GlobalTrial - - SetLeftRewardSize - - - - - false - - - - ThisTrial - - - RewardSize.Left - - - - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - - - - SetRightRewardSize - - - - - true - - - - ThisTrial - - - RewardSize.Right - - - - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - - @@ -234,6 +162,99 @@ 1 + + PreTrial + Configure necessary parameters before trial is run + + + + SetRightRewardSize + + + + + true + + + + ThisTrial + + + RewardSize.Right + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + + + SetLeftRewardSize + + + + + false + + + + ThisTrial + + + RewardSize.Left + + + + + + + + + SetIsRightRewardAmount + + + + + + + + + + + + + + + Source1 + + + + 1 + + + + + + + + + + RunTrial @@ -1237,6 +1258,30 @@ thisTrialOutcome + + ThisTrial + + + + 1 + + + + InterTrialIntervalDuration + + + + + + + + + + + + PT5S + + SampleNextTrial @@ -1360,108 +1405,6 @@ - - NextTrial - - - SetLeftRewardSize - - - - - false - - - - NextTrial - - - RewardSize.Left - - - - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - - - - SetRightRewardSize - - - - - true - - - - NextTrial - - - RewardSize.Right - - - - - - - - - SetIsRightRewardAmount - - - - - - - - - - - - - - - ThisTrial - - - - 1 - - - - InterTrialIntervalDuration - - - - - - - - - - - - PT5S - - - - NextTrial - GlobalAutoWaterState @@ -1602,30 +1545,29 @@ + + + - - + + - - - + + + - - + + - - + + - - - - @@ -1673,28 +1615,29 @@ - + + + - + - + - + - + - + - + - + - From 8528729b4c673ae044c6d06e873260e1347ba988 Mon Sep 17 00:00:00 2001 From: Micah Woodard Date: Mon, 13 Jul 2026 13:20:04 -0700 Subject: [PATCH 09/10] moves distinctuntilchanges --- src/Extensions/OperationControl.bonsai | 4 ++++ src/Extensions/TaskEngine.bonsai | 8 -------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Extensions/OperationControl.bonsai b/src/Extensions/OperationControl.bonsai index b05e227b..6e1c5628 100644 --- a/src/Extensions/OperationControl.bonsai +++ b/src/Extensions/OperationControl.bonsai @@ -545,6 +545,9 @@ + + + HarpBehaviorCommands @@ -584,6 +587,7 @@ + diff --git a/src/Extensions/TaskEngine.bonsai b/src/Extensions/TaskEngine.bonsai index a25d374b..be8d4dba 100644 --- a/src/Extensions/TaskEngine.bonsai +++ b/src/Extensions/TaskEngine.bonsai @@ -185,9 +185,6 @@ - - - SetIsRightRewardAmount @@ -199,7 +196,6 @@ - @@ -221,9 +217,6 @@ - - - SetIsRightRewardAmount @@ -235,7 +228,6 @@ - From 6f046333826dee96dc668678ccd5a057584de84b Mon Sep 17 00:00:00 2001 From: Micah Woodard Date: Mon, 13 Jul 2026 13:25:36 -0700 Subject: [PATCH 10/10] checks --- .../coupled_baiting/stages.py | 2 +- .../uncoupled_baiting/stages.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/coupled_baiting/stages.py b/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/coupled_baiting/stages.py index 22bae444..4f9ed226 100644 --- a/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/coupled_baiting/stages.py +++ b/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/coupled_baiting/stages.py @@ -9,8 +9,8 @@ TrialGeneratorCompositeSpec, ) from aind_behavior_dynamic_foraging.task_logic.trial_generators.block_based_trial_generator import ( - RewardSize, AutoWaterParameters, + RewardSize, ) from aind_behavior_dynamic_foraging.task_logic.trial_generators.coupled_trial_generators.base_coupled_trial_generator import ( RewardProbabilityParameters, diff --git a/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled_baiting/stages.py b/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled_baiting/stages.py index 736266ff..e2528bcd 100644 --- a/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled_baiting/stages.py +++ b/workspace/aind_behavior_dynamic_foraging_curricula/src/aind_behavior_dynamic_foraging_curricula/uncoupled_baiting/stages.py @@ -9,8 +9,8 @@ TrialGeneratorCompositeSpec, ) from aind_behavior_dynamic_foraging.task_logic.trial_generators.block_based_trial_generator import ( - RewardSize, AutoWaterParameters, + RewardSize, ) from aind_behavior_dynamic_foraging.task_logic.trial_generators.coupled_trial_generators.base_coupled_trial_generator import ( RewardProbabilityParameters,