Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING CHANGE: InjectionDynamics #1296

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
7e9e86e
feat: testing out ideas for injection dynamics
dbirman Mar 3, 2025
a6cbfa4
fix optional rate/duration
dbirman Mar 3, 2025
e04a367
Merge branch 'release-v2.0.0' into 1235-20-injections-replace-volumet…
dbirman Mar 4, 2025
3c5513b
Merge branch 'release-v2.0.0' into 1235-20-injections-replace-volumet…
dbirman Mar 4, 2025
8ac6070
Merge branch 'release-v2.0.0' into 1235-20-injections-replace-volumet…
dbirman Mar 5, 2025
e5a57c2
refactor: starting to rip out volume/volume_unit
dbirman Mar 5, 2025
1d10410
refactor: updating examples/tests to the new dynamics pattern
dbirman Mar 5, 2025
d26bf9a
fix: some typos
dbirman Mar 5, 2025
082137d
fix: improving Nanoject validator
dbirman Mar 5, 2025
137a31f
fix: missing InjectionProfile in a few places
dbirman Mar 5, 2025
9e2b28f
feat: add validator for bolus profile + test
dbirman Mar 5, 2025
aa5cac4
chore: lint
dbirman Mar 5, 2025
91e7a1e
tests: fixing test that never tested what it was supposed to
dbirman Mar 5, 2025
bc0adbb
chore: lint
dbirman Mar 5, 2025
6f4bb97
Merge branch 'release-v2.0.0' into 1235-20-injections-replace-volumet…
dbirman Mar 5, 2025
e8fdcaf
Merge branch 'release-v2.0.0' into 1235-20-injections-replace-volumet…
dbirman Mar 5, 2025
c2da78e
refactor: move profile into dynamics, move current into dynamics
dbirman Mar 5, 2025
9850eeb
chore: dependency gone
dbirman Mar 5, 2025
67e9ac5
chore: moving profile into dynamics
dbirman Mar 5, 2025
a70fc53
fix: accidental deletion in procedures, and missing [] on plasmids
dbirman Mar 5, 2025
11b3bcc
chore: lint
dbirman Mar 5, 2025
e5ca5c6
fix: remove old validator, fix plasmid list
dbirman Mar 5, 2025
5b9e8a3
chore: lint
dbirman Mar 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions docs/source/example_workflow/example_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,18 @@
from aind_data_schema_models.organizations import Organization

from aind_data_schema.core.data_description import Funding, RawDataDescription
from aind_data_schema.core.procedures import NanojectInjection, Perfusion, Procedures, Surgery, ViralMaterial
from aind_data_schema.core.procedures import (
NanojectInjection,
Perfusion,
Procedures,
Surgery,
ViralMaterial,
InjectionDynamics,
InjectionProfile,
)
from aind_data_schema.core.subject import BreedingInfo, Housing, Species, Subject
from aind_data_schema_models.species import Strain
from aind_data_schema_models.units import VolumeUnit

from aind_data_schema.components.identifiers import Person

Expand Down Expand Up @@ -105,7 +114,13 @@
injection_angle=float(coords[3]),
# multiple injection volumes at different depths are allowed, but that's not happening here
injection_coordinate_depth=[float(coords[2])],
injection_volume=[float(proc_row["injection_volume"])],
dynamics=[
InjectionDynamics(
volume=proc_row["injection_volume"],
volume_unit=VolumeUnit.NL,
profile=InjectionProfile.BOLUS,
)
],
)
],
),
Expand Down
11 changes: 10 additions & 1 deletion examples/ophys_procedures.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
Surgery,
ViralMaterial,
WaterRestriction,
InjectionDynamics,
InjectionProfile,
)
from aind_data_schema_models.units import VolumeUnit
from aind_data_schema_models.brain_atlas import CCFStructure

t = datetime.datetime(2022, 7, 12, 7, 00, 00)
Expand Down Expand Up @@ -68,7 +71,13 @@
injection_coordinate_depth=[-4.2],
injection_coordinate_reference="Bregma",
injection_angle=0,
injection_volume=[400],
dynamics=[
InjectionDynamics(
volume=400,
volume_unit=VolumeUnit.NL,
profile=InjectionProfile.BOLUS,
)
],
targeted_structure=CCFStructure.VTA,
),
FiberImplant(
Expand Down
11 changes: 10 additions & 1 deletion examples/procedures.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@
Surgery,
TarsVirusIdentifiers,
ViralMaterial,
InjectionDynamics,
InjectionProfile,
)
from aind_data_schema_models.brain_atlas import CCFStructure
from aind_data_schema_models.units import VolumeUnit

# If a timezone isn't specified, the timezone of the computer running this
# script will be used as default
Expand Down Expand Up @@ -62,7 +65,13 @@
injection_coordinate_reference="Lambda",
bregma_to_lambda_distance=4.1,
injection_angle=10,
injection_volume=[200],
dynamics=[
InjectionDynamics(
volume=200,
volume_unit=VolumeUnit.NL,
profile=InjectionProfile.BOLUS,
)
],
targeted_structure=CCFStructure.VISP,
),
],
Expand Down
79 changes: 37 additions & 42 deletions src/aind_data_schema/core/procedures.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,14 @@ class SampleType(str, Enum):
OTHER = "Other"


class InjectionProfile(str, Enum):
"""Injection profile"""

BOLUS = "Bolus"
CONTINUOUS = "Continuous"
PULSED = "Pulsed"


class Readout(Reagent):
"""Description of a readout"""

Expand Down Expand Up @@ -424,6 +432,25 @@ class NonViralMaterial(Reagent):
)


class InjectionDynamics(DataModel):
"""Description of the volume and rate of an injection"""

profile: InjectionProfile = Field(..., title="Injection profile")

volume: Optional[Decimal] = Field(default=None, title="Injection volume")
volume_unit: Optional[VolumeUnit] = Field(default=None, title="Injection volume unit")

rate: Optional[Decimal] = Field(default=None, title="Injection rate")
rate_unit: Optional[VolumeUnit] = Field(default=None, title="Injection rate unit")

duration: Optional[Decimal] = Field(default=None, title="Injection duration")
duration_unit: Optional[TimeUnit] = Field(default=None, title="Injection duration unit")

injection_current: Optional[Decimal] = Field(default=None, title="Injection current (uA)")
injection_current_unit: Optional[CurrentUnit] = Field(default=None, title="Injection current unit")
alternating_current: Optional[str] = Field(default=None, title="Alternating current")


class Injection(DataModel):
"""Description of an injection procedure"""

Expand All @@ -432,26 +459,24 @@ class Injection(DataModel):
] = Field(..., title="Injection material", min_length=1)
recovery_time: Optional[Decimal] = Field(default=None, title="Recovery time")
recovery_time_unit: Optional[TimeUnit] = Field(default=None, title="Recovery time unit")
injection_duration: Optional[Decimal] = Field(default=None, title="Injection duration")
injection_duration_unit: Optional[TimeUnit] = Field(default=None, title="Injection duration unit")
# [TODO] Placeholder for injection target/coordinate information
dynamics: List[InjectionDynamics] = Field(
..., title="Injection dynamics", description="List of injection events, one per location/depth"
)
instrument_id: Optional[str] = Field(default=None, title="Instrument ID")
protocol_id: str = Field(..., title="Protocol ID", description="DOI for protocols.io")


class RetroOrbitalInjection(Injection):
"""Description of a retro-orbital injection procedure"""

injection_volume: Decimal = Field(..., title="Injection volume (uL)")
injection_volume_unit: VolumeUnit = Field(default=VolumeUnit.UL, title="Injection volume unit")
injection_eye: Side = Field(..., title="Injection eye")


class IntraperitonealInjection(Injection):
"""Description of an intraperitoneal injection procedure"""

time: Optional[AwareDatetimeWithDefault] = Field(default=None, title="Injection time")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't remove the time here - it's not a duration field, it's the time when the injection is done. This is for the NBA project where they do timed injections prior to blood collection.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added back

injection_volume: Decimal = Field(..., title="Injection volume (uL)")
injection_volume_unit: VolumeUnit = Field(default=VolumeUnit.UL, title="Injection volume unit")


class BrainInjection(Injection):
Expand All @@ -477,54 +502,25 @@ class BrainInjection(Injection):
class NanojectInjection(BrainInjection):
"""Description of a nanoject injection procedure"""

injection_volume: List[Decimal] = Field(
...,
title="Injection volume (nL)",
description="Injection volume, one value per location",
)
injection_volume_unit: VolumeUnit = Field(VolumeUnit.NL, title="Injection volume unit")

@field_validator("injection_volume")
def check_dv_and_vol_list_lengths(cls, v, info: ValidationInfo):
@model_validator(mode="after")
def check_dv_and_vol_list_lengths(values):
"""Validator for list length of injection volumes and depths"""

injection_vol_len = len(v)
coords_len = len(info.data["injection_coordinate_depth"])
dynamics_len = len(values.dynamics)
coords_len = len(values.injection_coordinate_depth)

if injection_vol_len != coords_len:
if dynamics_len != coords_len:
raise AssertionError("Unmatched list sizes for injection volumes and coordinate depths")
return v


class IontophoresisInjection(BrainInjection):
"""Description of an iotophoresis injection procedure"""

injection_current: Decimal = Field(..., title="Injection current (uA)")
injection_current_unit: CurrentUnit = Field(default=CurrentUnit.UA, title="Injection current unit")
alternating_current: str = Field(..., title="Alternating current")
return values


class IntraCerebellarVentricleInjection(BrainInjection):
"""Description of an interacerebellar ventricle injection"""

injection_volume: List[Decimal] = Field(
...,
title="Injection volume (nL)",
description="Injection volume, one value per location",
)
injection_volume_unit: VolumeUnit = Field(VolumeUnit.NL, title="Injection volume unit")


class IntraCisternalMagnaInjection(BrainInjection):
"""Description of an interacisternal magna injection"""

injection_volume: List[Decimal] = Field(
...,
title="Injection volume (nL)",
description="Injection volume, one value per location",
)
injection_volume_unit: VolumeUnit = Field(VolumeUnit.NL, title="Injection volume unit")


class SampleCollection(DataModel):
"""Description of a single sample collection"""
Expand Down Expand Up @@ -668,7 +664,6 @@ class Surgery(DataModel):
IntraCerebellarVentricleInjection,
IntraCisternalMagnaInjection,
IntraperitonealInjection,
IontophoresisInjection,
MyomatrixInsertion,
NanojectInjection,
OtherSubjectProcedure,
Expand Down
Loading