sl-shared-assets 1.0.0rc11__tar.gz → 1.0.0rc12__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sl-shared-assets might be problematic. Click here for more details.

Files changed (23) hide show
  1. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/PKG-INFO +1 -1
  2. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/pyproject.toml +1 -1
  3. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/src/sl_shared_assets/data_classes.py +214 -108
  4. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/.gitignore +0 -0
  5. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/LICENSE +0 -0
  6. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/README.md +0 -0
  7. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/docs/Makefile +0 -0
  8. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/docs/make.bat +0 -0
  9. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/docs/source/api.rst +0 -0
  10. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/docs/source/conf.py +0 -0
  11. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/docs/source/index.rst +0 -0
  12. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/docs/source/welcome.rst +0 -0
  13. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/envs/slsa_dev_lin.yml +0 -0
  14. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/envs/slsa_dev_lin_spec.txt +0 -0
  15. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/src/sl_shared_assets/__init__.py +0 -0
  16. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/src/sl_shared_assets/ascension_tools.py +0 -0
  17. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/src/sl_shared_assets/cli.py +0 -0
  18. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/src/sl_shared_assets/packaging_tools.py +0 -0
  19. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/src/sl_shared_assets/py.typed +0 -0
  20. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/src/sl_shared_assets/server.py +0 -0
  21. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/src/sl_shared_assets/suite2p.py +0 -0
  22. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/src/sl_shared_assets/transfer_tools.py +0 -0
  23. {sl_shared_assets-1.0.0rc11 → sl_shared_assets-1.0.0rc12}/tox.ini +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sl-shared-assets
3
- Version: 1.0.0rc11
3
+ Version: 1.0.0rc12
4
4
  Summary: Stores assets shared between multiple Sun (NeuroAI) lab data pipelines.
5
5
  Project-URL: Homepage, https://github.com/Sun-Lab-NBB/sl-shared-assets
6
6
  Project-URL: Documentation, https://sl-shared-assets-api-docs.netlify.app/
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
8
8
  # Project metdata section. Provides the genral ID information about the project.
9
9
  [project]
10
10
  name = "sl-shared-assets"
11
- version = "1.0.0rc11"
11
+ version = "1.0.0rc12"
12
12
  description = "Stores assets shared between multiple Sun (NeuroAI) lab data pipelines."
13
13
  readme = "README.md"
14
14
  license = { file = "LICENSE" }
@@ -374,73 +374,101 @@ class RawData:
374
374
  """Stores the path to the root raw_data directory of the session. This directory stores all raw data during
375
375
  acquisition and preprocessing. Note, preprocessing does not alter raw data, so at any point in time all data inside
376
376
  the folder is considered 'raw'."""
377
- camera_data_path: str | Path
377
+ camera_data_path: str | Path = "null"
378
378
  """Stores the path to the directory that contains all camera data acquired during the session. Primarily, this
379
379
  includes .mp4 video files from each recorded camera."""
380
- mesoscope_data_path: str | Path
380
+ mesoscope_data_path: str | Path = "null"
381
381
  """Stores the path to the directory that contains all Mesoscope data acquired during the session. Primarily, this
382
382
  includes the mesoscope-acquired .tiff files (brain activity data) and the motion estimation data."""
383
- behavior_data_path: str | Path
383
+ behavior_data_path: str | Path = "null"
384
384
  """Stores the path to the directory that contains all behavior data acquired during the session. Primarily, this
385
385
  includes the .npz log files used by data-acquisition libraries to store all acquired data. The data stored in this
386
386
  way includes the camera and mesoscope frame timestamps and the states of Mesoscope-VR components, such as lick
387
387
  sensors, rotary encoders, and other modules."""
388
- zaber_positions_path: str | Path
388
+ zaber_positions_path: str | Path = "null"
389
389
  """Stores the path to the zaber_positions.yaml file. This file contains the snapshot of all Zaber motor positions
390
390
  at the end of the session. Zaber motors are used to position the LickPort and the HeadBar manipulators, which is
391
391
  essential for supporting proper brain imaging and animal's running behavior during the session."""
392
- session_descriptor_path: str | Path
392
+ session_descriptor_path: str | Path = "null"
393
393
  """Stores the path to the session_descriptor.yaml file. This file is partially filled by the system during runtime
394
394
  and partially by the experimenter after the runtime. It contains session-specific information, such as the specific
395
395
  training parameters, the positions of the Mesoscope objective and the notes made by the experimenter during
396
396
  runtime."""
397
- hardware_configuration_path: str | Path
397
+ hardware_configuration_path: str | Path = "null"
398
398
  """Stores the path to the hardware_configuration.yaml file. This file contains the partial snapshot of the
399
399
  calibration parameters used by the Mesoscope-VR system components during runtime. Primarily, this is used during
400
400
  data processing to read the .npz data log files generated during runtime."""
401
- surgery_metadata_path: str | Path
401
+ surgery_metadata_path: str | Path = "null"
402
402
  """Stores the path to the surgery_metadata.yaml file. This file contains the most actual information about the
403
403
  surgical intervention(s) performed on the animal prior to the session."""
404
- project_configuration_path: str | Path
404
+ project_configuration_path: str | Path = "null"
405
405
  """Stores the path to the project_configuration.yaml file. This file contains the snapshot of the configuration
406
406
  parameters for the session's project."""
407
- session_data_path: str | Path
407
+ session_data_path: str | Path = "null"
408
408
  """Stores the path to the session_data.yaml file. This path is used b y the SessionData instance to save itself to
409
409
  disk as a .yaml file. The file contains all paths used during data acquisition and processing on both the VRPC and
410
410
  the BioHPC server."""
411
- experiment_configuration_path: str | Path
411
+ experiment_configuration_path: str | Path = "null"
412
412
  """Stores the path to the experiment_configuration.yaml file. This file contains the snapshot of the
413
413
  experiment runtime configuration used by the session. This file is only created for experiment session. It does not
414
414
  exist for behavior training sessions."""
415
- mesoscope_positions_path: str | Path
415
+ mesoscope_positions_path: str | Path = "null"
416
416
  """Stores the path to the mesoscope_positions.yaml file. This file contains the snapshot of the positions used
417
417
  by the Mesoscope at the end of the session. This includes both the physical position of the mesoscope objective and
418
418
  the 'virtual' tip, tilt, and fastZ positions set via ScanImage software. This file is only created for experiment
419
419
  sessions that use the mesoscope, it is omitted for behavior training sessions."""
420
- window_screenshot_path: str | Path
420
+ window_screenshot_path: str | Path = "null"
421
421
  """Stores the path to the .png screenshot of the ScanImagePC screen. The screenshot should contain the image of the
422
422
  cranial window and the red-dot alignment windows. This is used to generate a visual snapshot of the cranial window
423
423
  alignment and appearance for each experiment session. This file is only created for experiment sessions that use
424
424
  the mesoscope, it is omitted for behavior training sessions."""
425
+ telomere_path: str | Path = "null"
426
+ """Stores the path to the telomere.bin file. This file is created by the data processing pipelines running on the
427
+ BioHPC server to confirm that the raw_data transferred to the server was not altered or damage in transmission. This
428
+ path is used by the BioHPC server pipeline. The VRPC uses the path stored in the 'destinations' section to check
429
+ for the existence of the file when it purges redundant data."""
430
+ checksum_path: str | Path = "null"
431
+ """Stores the path to the ax_checksum.txt file. This file is generated as part of packaging the data for
432
+ transmission and stores the xxHash-128 checksum of the data. It is used to verify that the transmission did not
433
+ damage or otherwise alter the data.."""
425
434
 
426
435
  def __post_init__(self) -> None:
427
436
  """This method is automatically called after class instantiation and ensures that all path fields of the class
428
437
  are converted to Path objects.
429
438
  """
430
439
 
440
+ # Translates the root raw_data path to the Path object before using it to determine other Path objects.
431
441
  self.raw_data_path = Path(self.raw_data_path)
432
- self.camera_data_path = Path(self.camera_data_path)
433
- self.mesoscope_data_path = Path(self.mesoscope_data_path)
434
- self.behavior_data_path = Path(self.behavior_data_path)
435
- self.zaber_positions_path = Path(self.zaber_positions_path)
436
- self.session_descriptor_path = Path(self.session_descriptor_path)
437
- self.hardware_configuration_path = Path(self.hardware_configuration_path)
438
- self.surgery_metadata_path = Path(self.surgery_metadata_path)
439
- self.project_configuration_path = Path(self.project_configuration_path)
440
- self.session_data_path = Path(self.session_data_path)
441
- self.experiment_configuration_path = Path(self.experiment_configuration_path)
442
- self.mesoscope_positions_path = Path(self.mesoscope_positions_path)
443
- self.window_screenshot_path = Path(self.window_screenshot_path)
442
+
443
+ # When the class is instantiated for the first time, resolves all 'null' path placeholders
444
+ if self.camera_data_path == "null":
445
+ self.camera_data_path = self.raw_data_path.joinpath("camera_data")
446
+ if self.mesoscope_data_path == "null":
447
+ self.mesoscope_data_path = self.raw_data_path.joinpath("mesoscope_data")
448
+ if self.behavior_data_path == "null":
449
+ self.behavior_data_path = self.raw_data_path.joinpath("behavior_data")
450
+ if self.zaber_positions_path == "null":
451
+ self.zaber_positions_path = self.raw_data_path.joinpath("zaber_positions.yaml")
452
+ if self.session_descriptor_path == "null":
453
+ self.session_descriptor_path = self.raw_data_path.joinpath("session_descriptor.yaml")
454
+ if self.hardware_configuration_path == "null":
455
+ self.hardware_configuration_path = self.raw_data_path.joinpath("hardware_configuration.yaml")
456
+ if self.surgery_metadata_path == "null":
457
+ self.surgery_metadata_path = self.raw_data_path.joinpath("surgery_metadata.yaml")
458
+ if self.project_configuration_path == "null":
459
+ self.project_configuration_path = self.raw_data_path.joinpath("project_configuration.yaml")
460
+ if self.session_data_path == "null":
461
+ self.session_data_path = self.raw_data_path.joinpath("session_data.yaml")
462
+ if self.experiment_configuration_path == "null":
463
+ self.experiment_configuration_path = self.raw_data_path.joinpath("experiment_configuration.yaml")
464
+ if self.mesoscope_positions_path == "null":
465
+ self.mesoscope_positions_path = self.raw_data_path.joinpath("mesoscope_positions.yaml")
466
+ if self.window_screenshot_path == "null":
467
+ self.window_screenshot_path = self.raw_data_path.joinpath("window_screenshot.png")
468
+ if self.telomere_path == "null":
469
+ self.telomere_path = self.raw_data_path.joinpath("telomere.bin")
470
+ if self.checksum_path == "null":
471
+ self.checksum_path = self.raw_data_path.joinpath("ax_checksum.txt")
444
472
 
445
473
  def make_string(self) -> None:
446
474
  """Converts all Path objects stored inside the class to strings.
@@ -461,6 +489,8 @@ class RawData:
461
489
  self.experiment_configuration_path = str(self.experiment_configuration_path)
462
490
  self.mesoscope_positions_path = str(self.mesoscope_positions_path)
463
491
  self.window_screenshot_path = str(self.window_screenshot_path)
492
+ self.telomere_path = str(self.telomere_path)
493
+ self.checksum_path = str(self.checksum_path)
464
494
 
465
495
  def make_dirs(self) -> None:
466
496
  """Ensures that all major subdirectories and the root raw_data directory exist.
@@ -480,6 +510,10 @@ class RawData:
480
510
  (another root). This method is only implemented for subclasses intended to be used both locally and on the
481
511
  BioHPC server.
482
512
 
513
+ Note:
514
+ This is the only class that contains this method. Other classes are re-initialized using the data loaded
515
+ from the RawData section, if necessary.
516
+
483
517
  Args:
484
518
  new_root: The new root directory to use for all paths inside the instance. This has to be the path to the
485
519
  directory that stores all Sun lab projects on the target machine.
@@ -505,6 +539,8 @@ class RawData:
505
539
  )
506
540
  self.mesoscope_positions_path = new_root.joinpath(Path(self.mesoscope_positions_path).relative_to(old_root))
507
541
  self.window_screenshot_path = new_root.joinpath(Path(self.window_screenshot_path).relative_to(old_root))
542
+ self.telomere_path = new_root.joinpath(Path(self.telomere_path).relative_to(old_root))
543
+ self.checksum_path = new_root.joinpath(Path(self.checksum_path).relative_to(old_root))
508
544
 
509
545
 
510
546
  @dataclass()
@@ -526,32 +562,59 @@ class ProcessedData:
526
562
  processed_data_path: str | Path
527
563
  """Stores the path to the root processed_data directory of the session. This directory stores the processed data
528
564
  as it is generated by various data processing pipelines."""
529
- camera_data_path: str | Path
530
- """Stores the output of the DeepLabCut pose estimation pipeline."""
531
- mesoscope_data_path: str | Path
532
- """Stores the output of the suite2p cell registration pipeline."""
533
- behavior_data_path: str | Path
534
- """Stores the output of the Sun lab behavior data extraction pipeline."""
535
- deeplabcut_root_path: str | Path
565
+ deeplabcut_path: str | Path
536
566
  """Stores the path to the root DeepLabCut project directory. Since DeepLabCut adopts a project-based directory
537
567
  management hierarchy, it is easier to have a single DLC folder shared by all animals and sessions of a given
538
568
  project. This root folder is typically stored under the main project directory on the fast BioHPC server volume."""
539
- suite2p_configuration_path: str | Path
569
+ configuration_path: str | Path
570
+ """Stores the path to the project's processed data configuration directory. This directory is used by all animals
571
+ and sessions of the project to store data processing configuration files. Since processing configuration is
572
+ typically reused for all data in the project, this allows updating a single file to control the processing for all
573
+ data. This directory is typically stored on the fast BioHPC server volume."""
574
+ camera_data_path: str | Path = "null"
575
+ """Stores the output of the DeepLabCut pose estimation pipeline."""
576
+ mesoscope_data_path: str | Path = "null"
577
+ """Stores the output of the suite2p cell registration pipeline."""
578
+ behavior_data_path: str | Path = "null"
579
+ """Stores the output of the Sun lab behavior data extraction pipeline."""
580
+ suite2p_configuration_path: str | Path = "null"
540
581
  """Stores the path to the suite2p_configuration.yaml file stored inside the project's 'configuration' directory on
541
- the fast BioHPC server volume. Since all sessions share the same suite2p configuration file, it is stored in a
542
- general configuration directory, similar to how project configuration is stored on the VRPC."""
582
+ the fast BioHPC server volume. This configuration file specifies the parameters for the 'single day' suite2p
583
+ registration pipeline, which is applied to each session that generates brain activity data."""
584
+ processing_tracker_path: str | Path = "null"
585
+ """Stores the path to the processing_tracker.yaml file stored inside the sessions' root processed_data directory on
586
+ the fast BioHPC server volume. This file is used to track which processing pipelines to apply to the target
587
+ session and the status (success / failure) of each processing step.
588
+ """
589
+ multiday_configuration_path: str | Path = "null"
590
+ """Stores the path to the multiday_configuration.yaml file stored inside the project's 'configuration' directory
591
+ on the fast BioHPC server volume. This configuration file specifies the parameters for the 'multiday'
592
+ sl-suite2p-based registration pipelines used tot rack brain cells across multiple sessions."""
543
593
 
544
594
  def __post_init__(self) -> None:
545
595
  """This method is automatically called after class instantiation and ensures that all path fields of the class
546
596
  are converted to Path objects.
547
597
  """
548
598
 
599
+ # Ensures all objects that have to be provided externally are transformed to Path objects. Unlike 'null' fields,
600
+ # these paths cannot be resolved automatically
549
601
  self.processed_data_path = Path(self.processed_data_path)
550
- self.camera_data_path = Path(self.camera_data_path)
551
- self.mesoscope_data_path = Path(self.mesoscope_data_path)
552
- self.behavior_data_path = Path(self.behavior_data_path)
553
- self.deeplabcut_root_path = Path(self.deeplabcut_root_path)
554
- self.suite2p_configuration_path = Path(self.suite2p_configuration_path)
602
+ self.deeplabcut_path = Path(self.deeplabcut_path)
603
+ self.configuration_path = Path(self.configuration_path)
604
+
605
+ # When the class is instantiated for the first time, resolves all 'null' path placeholders
606
+ if self.camera_data_path == "null":
607
+ self.camera_data_path = self.processed_data_path.joinpath("camera_data")
608
+ if self.mesoscope_data_path == "null":
609
+ self.mesoscope_data_path = self.processed_data_path.joinpath("mesoscope_data")
610
+ if self.behavior_data_path == "null":
611
+ self.behavior_data_path = self.processed_data_path.joinpath("behavior_data")
612
+ if self.suite2p_configuration_path == "null":
613
+ self.suite2p_configuration_path = self.processed_data_path.joinpath("suite2p_configuration.yaml")
614
+ if self.processing_tracker_path == "null":
615
+ self.processing_tracker_path = self.processed_data_path.joinpath("processing_tracker.yaml")
616
+ if self.multiday_configuration_path == "null":
617
+ self.multiday_configuration_path = self.processed_data_path.joinpath("multiday_configuration.yaml")
555
618
 
556
619
  def make_string(self) -> None:
557
620
  """Converts all Path objects stored inside the class to strings.
@@ -560,11 +623,14 @@ class ProcessedData:
560
623
  on disk.
561
624
  """
562
625
  self.processed_data_path = str(self.processed_data_path)
626
+ self.deeplabcut_path = str(self.deeplabcut_path)
627
+ self.configuration_path = str(self.configuration_path)
563
628
  self.camera_data_path = str(self.camera_data_path)
564
629
  self.mesoscope_data_path = str(self.mesoscope_data_path)
565
630
  self.behavior_data_path = str(self.behavior_data_path)
566
- self.deeplabcut_root_path = str(self.deeplabcut_root_path)
567
631
  self.suite2p_configuration_path = str(self.suite2p_configuration_path)
632
+ self.processing_tracker_path = str(self.processing_tracker_path)
633
+ self.multiday_configuration_path = str(self.multiday_configuration_path)
568
634
 
569
635
  def make_dirs(self) -> None:
570
636
  """Ensures that all major subdirectories of the processed_data directory exist.
@@ -573,34 +639,11 @@ class ProcessedData:
573
639
  library runtime.
574
640
  """
575
641
  ensure_directory_exists(Path(self.processed_data_path))
642
+ ensure_directory_exists(Path(self.deeplabcut_path))
643
+ ensure_directory_exists(Path(self.configuration_path))
576
644
  ensure_directory_exists(Path(self.camera_data_path))
577
645
  ensure_directory_exists(Path(self.mesoscope_data_path))
578
646
  ensure_directory_exists(Path(self.behavior_data_path))
579
- ensure_directory_exists(Path(self.deeplabcut_root_path))
580
- ensure_directory_exists(Path(self.suite2p_configuration_path))
581
-
582
- def switch_root(self, new_root: Path) -> None:
583
- """Changes the root of the managed processed_data directory to the provided root path.
584
-
585
- This service method is used by the SessionData class to convert all paths in this class to be relative to the
586
- new root. This is used to adjust the SessionData instance to work for the VRPC (one root) or the BioHPC server
587
- (another root). This method is only implemented for subclasses intended to be used both locally and on the
588
- BioHPC server.
589
-
590
- Args:
591
- new_root: The new root directory to use for all paths inside the instance. This has to be the path to the
592
- directory that stores all Sun lab projects on the target machine.
593
- """
594
- # Gets current root from the processed_data_path.
595
- old_root = Path(self.processed_data_path).parents[3]
596
-
597
- # Updates all paths by replacing old_root with new_root
598
- self.processed_data_path = new_root.joinpath(Path(self.processed_data_path).relative_to(old_root))
599
- self.camera_data_path = new_root.joinpath(Path(self.camera_data_path).relative_to(old_root))
600
- self.mesoscope_data_path = new_root.joinpath(Path(self.mesoscope_data_path).relative_to(old_root))
601
- self.behavior_data_path = new_root.joinpath(Path(self.behavior_data_path).relative_to(old_root))
602
- self.deeplabcut_root_path = new_root.joinpath(Path(self.deeplabcut_root_path).relative_to(old_root))
603
- self.suite2p_configuration_path = new_root.joinpath(Path(self.suite2p_configuration_path).relative_to(old_root))
604
647
 
605
648
 
606
649
  @dataclass()
@@ -619,13 +662,21 @@ class PersistentData:
619
662
  only used internally by the sl-experiment or sl-forgery libraries and is not intended for end-users.
620
663
  """
621
664
 
622
- zaber_positions_path: str | Path
665
+ scanimage_persistent_path: str | Path
666
+ """Stores the path to the project and animal specific 'persistent_data' directory to which the managed session
667
+ belongs, relative to the ScanImagePC root. This directory is primarily used to store reference motion registration
668
+ data acquired during the first experiment session for each animal."""
669
+ vrpc_persistent_path: str | Path
670
+ """Stores the path to the project and animal specific 'persistent_data' directory to which the managed session
671
+ belongs, relative to the VRPC root. This directory is primarily used to back up the Zaber and Mesoscope positions,
672
+ so that they can be restored between sessions of the same animals."""
673
+ zaber_positions_path: str | Path = "null"
623
674
  """Stores the path to the Zaber motor positions snapshot generated at the end of the previous session runtime. This
624
675
  is used to automatically restore all Zaber motors to the same position across all sessions."""
625
- mesoscope_positions_path: str | Path
676
+ mesoscope_positions_path: str | Path = "null"
626
677
  """Stores the path to the Mesoscope positions snapshot generated at the end of the previous session runtime. This
627
678
  is used to help the user to (manually) restore the Mesoscope to the same position across all sessions."""
628
- motion_estimator_path: str | Path
679
+ motion_estimator_path: str | Path = "null"
629
680
  """Stores the 'reference' motion estimator file generated during the first experiment session of each animal. This
630
681
  file is kept on the ScanImagePC to image the same population of cells across all experiment sessions."""
631
682
 
@@ -634,9 +685,17 @@ class PersistentData:
634
685
  are converted to Path objects.
635
686
  """
636
687
 
637
- self.zaber_positions_path = Path(self.zaber_positions_path)
638
- self.mesoscope_positions_path = Path(self.mesoscope_positions_path)
639
- self.motion_estimator_path = Path(self.motion_estimator_path)
688
+ # Converts 'anchor' paths that have to be provided at class instantiation
689
+ self.scanimage_persistent_path = Path(self.scanimage_persistent_path)
690
+ self.vrpc_persistent_path = Path(self.vrpc_persistent_path)
691
+
692
+ # Replaces 'null' defaults with automatically resolved paths
693
+ if self.zaber_positions_path == "null":
694
+ self.zaber_positions_path = self.vrpc_persistent_path.joinpath("zaber_positions.yaml")
695
+ if self.mesoscope_positions_path == "null":
696
+ self.mesoscope_positions_path = self.vrpc_persistent_path.joinpath("mesoscope_positions.yaml")
697
+ if self.motion_estimator_path == "null":
698
+ self.motion_estimator_path = self.scanimage_persistent_path.joinpath("MotionEstimator.me")
640
699
 
641
700
  def make_string(self) -> None:
642
701
  """Converts all Path objects stored inside the class to strings.
@@ -644,6 +703,8 @@ class PersistentData:
644
703
  This transformation is required to support dumping class data into a .YAML file so that the data can be stored
645
704
  on disk.
646
705
  """
706
+ self.scanimage_persistent_path = str(self.scanimage_persistent_path)
707
+ self.vrpc_persistent_path = str(self.vrpc_persistent_path)
647
708
  self.zaber_positions_path = str(self.zaber_positions_path)
648
709
  self.mesoscope_positions_path = str(self.mesoscope_positions_path)
649
710
  self.motion_estimator_path = str(self.motion_estimator_path)
@@ -652,8 +713,8 @@ class PersistentData:
652
713
  """Ensures that the VRPC and the ScanImagePC persistent_data directories exist."""
653
714
 
654
715
  # We need to call ensure_directory_exists one for each unique directory tree
655
- ensure_directory_exists(Path(self.zaber_positions_path)) # vrpc_root/project/animal/persistent_data
656
- ensure_directory_exists(Path(self.motion_estimator_path)) # scanimagepc_root/project/animal/persistent_data
716
+ ensure_directory_exists(Path(self.vrpc_persistent_path)) # vrpc_root/project/animal/persistent_data
717
+ ensure_directory_exists(Path(self.scanimage_persistent_path)) # scanimagepc_root/project/animal/persistent_data
657
718
 
658
719
 
659
720
  @dataclass()
@@ -670,23 +731,34 @@ class MesoscopeData:
670
731
  """Stores the path to the root ScanImagePC data directory, mounted to the VRPC filesystem via the SMB or equivalent
671
732
  protocol. This path is used during experiment session runtimes to discover the cranial window screenshots
672
733
  taken by the user before starting the experiment."""
673
- mesoscope_data_path: str | Path
734
+ session_specific_path: str | Path
735
+ """Stores the path to the session-specific data directory. This directory is generated at the end of each experiment
736
+ runtime to prepare mesoscope data for further processing and to reset the 'shared' folder for the next session's
737
+ runtime."""
738
+ mesoscope_data_path: str | Path = "null"
674
739
  """Stores the path to the 'general' mesoscope_data directory. All experiment sessions (across all animals and
675
740
  projects) use the same mesoscope_data directory to save the data generated by the mesoscope via ScanImage
676
741
  software. This simplifies ScanImagePC configuration process during runtime. The data is moved into a
677
742
  session-specific directory during preprocessing."""
678
- session_specific_mesoscope_data_path: str | Path
679
- """Stores the path to the session-specific mesoscope_data directory. This directory is generated at the end of
680
- each experiment runtime to prepare mesoscope data for further processing and to reset the 'shared' folder for the
681
- next session's runtime."""
743
+ ubiquitin_path: str | Path = "null"
744
+ """Stores the path to the 'ubiquitin.bin' file. This file is automatically generated inside the session-specific
745
+ data folder after its contents are safely transferred to the VRPC as part of preprocessing. During redundant data
746
+ removal, the VRPC searches for directories marked with ubiquitin.bin, so that they can be safely removed from the
747
+ ScanImagePC filesystem."""
682
748
 
683
749
  def __post_init__(self) -> None:
684
750
  """This method is automatically called after class instantiation and ensures that all path fields of the class
685
751
  are converted to Path objects.
686
752
  """
753
+ # Converts the paths that have to be provided at class instantiation to the Path objects.
687
754
  self.root_data_path = Path(self.root_data_path)
688
- self.mesoscope_data_path = Path(self.mesoscope_data_path)
689
- self.session_specific_mesoscope_data_path = Path(self.session_specific_mesoscope_data_path)
755
+ self.session_specific_path = Path(self.session_specific_path)
756
+
757
+ # Resolves the 'null' placeholders using the 'anchor' paths above
758
+ if self.mesoscope_data_path == "null":
759
+ self.mesoscope_data_path = self.root_data_path.joinpath("mesoscope_data")
760
+ if self.ubiquitin_path == "null":
761
+ self.ubiquitin_path = self.session_specific_path.joinpath("ubiquitin.bin")
690
762
 
691
763
  def make_string(self) -> None:
692
764
  """Converts all Path objects stored inside the class to strings.
@@ -695,8 +767,9 @@ class MesoscopeData:
695
767
  on disk.
696
768
  """
697
769
  self.root_data_path = str(self.root_data_path)
770
+ self.session_specific_path = str(self.session_specific_path)
698
771
  self.mesoscope_data_path = str(self.mesoscope_data_path)
699
- self.session_specific_mesoscope_data_path = str(self.session_specific_mesoscope_data_path)
772
+ self.ubiquitin_path = str(self.ubiquitin_path)
700
773
 
701
774
  def make_dirs(self) -> None:
702
775
  """Ensures that the ScanImagePC data acquisition directories exist."""
@@ -722,6 +795,10 @@ class Destinations:
722
795
  server_raw_data_path: str | Path
723
796
  """Stores the path to the session's raw_data directory on the BioHPC server, which is mounted to the VRPC via the
724
797
  SMB or equivalent protocol."""
798
+ server_telomere_path: str | Path = "null"
799
+ """Stores the path to the session's telomere.bin marker. This marker is generated as part of BioHPC-side data
800
+ processing pipeline to notify he VRPC that the server received the data intact. it is used to determine which
801
+ data can be safely removed from the VRPC filesystem."""
725
802
 
726
803
  def __post_init__(self) -> None:
727
804
  """This method is automatically called after class instantiation and ensures that all path fields of the class
@@ -730,6 +807,9 @@ class Destinations:
730
807
  self.nas_raw_data_path = Path(self.nas_raw_data_path)
731
808
  self.server_raw_data_path = Path(self.server_raw_data_path)
732
809
 
810
+ if self.server_telomere_path == "null":
811
+ self.server_telomere_path = self.server_raw_data_path.joinpath("telomere.bin")
812
+
733
813
  def make_string(self) -> None:
734
814
  """Converts all Path objects stored inside the class to strings.
735
815
 
@@ -738,6 +818,7 @@ class Destinations:
738
818
  """
739
819
  self.nas_raw_data_path = str(self.nas_raw_data_path)
740
820
  self.server_raw_data_path = str(self.server_raw_data_path)
821
+ self.server_telomere_path = str(self.server_telomere_path)
741
822
 
742
823
  def make_dirs(self) -> None:
743
824
  """Ensures that all destination directories exist."""
@@ -892,46 +973,28 @@ class SessionData(YamlConfig):
892
973
  )
893
974
  warnings.warn(message=message)
894
975
 
895
- # Generates subclasses stored inside the main class instance based on the data resolved above.
976
+ # Generates subclasses stored inside the main class instance based on the data resolved above. Note; most fields
977
+ # of these classes are initialized automatically, using the 'root' path arguments.
896
978
  raw_data = RawData(
897
979
  raw_data_path=session_path.joinpath("raw_data"),
898
- camera_data_path=session_path.joinpath("raw_data", "camera_data"),
899
- mesoscope_data_path=session_path.joinpath("raw_data", "mesoscope_data"),
900
- behavior_data_path=session_path.joinpath("raw_data", "behavior_data"),
901
- zaber_positions_path=session_path.joinpath("raw_data", "zaber_positions.yaml"),
902
- mesoscope_positions_path=session_path.joinpath("raw_data", "mesoscope_positions.yaml"),
903
- session_descriptor_path=session_path.joinpath("raw_data", "session_descriptor.yaml"),
904
- hardware_configuration_path=session_path.joinpath("raw_data", "hardware_configuration.yaml"),
905
- surgery_metadata_path=session_path.joinpath("raw_data", "surgery_metadata.yaml"),
906
- project_configuration_path=session_path.joinpath("raw_data", "project_configuration.yaml"),
907
- session_data_path=session_path.joinpath("raw_data", "session_data.yaml"),
908
- experiment_configuration_path=session_path.joinpath("raw_data", "experiment_configuration.yaml"),
909
- window_screenshot_path=session_path.joinpath("raw_data", "window_screenshot.png"),
910
980
  )
911
981
  raw_data.make_dirs() # Generates the local directory tree
912
982
 
913
983
  processed_data = ProcessedData(
914
984
  processed_data_path=session_path.joinpath("processed_data"),
915
- camera_data_path=session_path.joinpath("processed_data", "camera_data"),
916
- mesoscope_data_path=session_path.joinpath("processed_data", "mesoscope_data"),
917
- behavior_data_path=session_path.joinpath("processed_data", "behavior_data"),
918
- deeplabcut_root_path=vrpc_root.joinpath(project_name, "deeplabcut"),
919
- suite2p_configuration_path=vrpc_root.joinpath(project_name, "configuration", "suite2p_configuration.yaml"),
985
+ deeplabcut_path=vrpc_root.joinpath(project_name, "deeplabcut"),
986
+ configuration_path=vrpc_root.joinpath(project_name, "configuration"),
920
987
  )
921
988
 
922
989
  vrpc_persistent_path = vrpc_root.joinpath(project_name, animal_id, "persistent_data")
923
990
  scanimagepc_persistent_path = mesoscope_root.joinpath(project_name, animal_id, "persistent_data")
924
991
  persistent_data = PersistentData(
925
- zaber_positions_path=vrpc_persistent_path.joinpath("zaber_positions.yaml"),
926
- mesoscope_positions_path=vrpc_persistent_path.joinpath("mesoscope_positions.yaml"),
927
- motion_estimator_path=scanimagepc_persistent_path.joinpath("MotionEstimator.me"),
992
+ vrpc_persistent_path=vrpc_persistent_path, scanimage_persistent_path=scanimagepc_persistent_path
928
993
  )
929
994
  persistent_data.make_dirs() # Generates all persistent directory trees
930
995
 
931
996
  mesoscope_data = MesoscopeData(
932
- root_data_path=mesoscope_root,
933
- mesoscope_data_path=mesoscope_root.joinpath("mesoscope_data"),
934
- session_specific_mesoscope_data_path=mesoscope_root.joinpath(f"{session_name}_mesoscope_data"),
997
+ root_data_path=mesoscope_root, session_specific_path=mesoscope_root.joinpath(session_name)
935
998
  )
936
999
  mesoscope_data.make_dirs() # Generates all Mesoscope directory trees
937
1000
 
@@ -1032,11 +1095,15 @@ class SessionData(YamlConfig):
1032
1095
 
1033
1096
  # Resolves the paths to the processed_data directories. The resolution strategy depends on whether the method is
1034
1097
  # called on the VRPC (locally) or the BioHPC server (remotely).
1098
+ new_root: Path
1035
1099
  if not on_server:
1036
1100
  # Local runtimes use the same root session directory for both raw_data and processed_data. This stems from
1037
1101
  # the assumption that most local machines in the lab only use NVME (fast) volumes and, therefore, do not
1038
- # need to separate 'storage' and 'working' data.
1039
- instance.processed_data.switch_root(new_root=session_path.parents[2])
1102
+ # need to separate 'storage' and 'working' data directories.
1103
+
1104
+ # Regenerates the processed_data paths using the information loaded from the session_data.yaml file and
1105
+ # static path definition rules used in the lab.
1106
+ new_root = session_path.parents[2] # Reuses the local root for non-server runtimes
1040
1107
 
1041
1108
  else:
1042
1109
  # The BioHPC server stores raw_data on slow volume and processed_data on fast (NVME) volume. Therefore, to
@@ -1046,7 +1113,16 @@ class SessionData(YamlConfig):
1046
1113
  project_name=instance.project_name,
1047
1114
  configuration_path=Path(instance.raw_data.project_configuration_path),
1048
1115
  )
1049
- instance.processed_data.switch_root(new_root=Path(project_configuration.remote_working_directory))
1116
+ new_root = Path(project_configuration.remote_working_directory)
1117
+
1118
+ # Regenerates the processed_data path depending on the root resolution above
1119
+ instance.processed_data = ProcessedData(
1120
+ processed_data_path=new_root.joinpath(
1121
+ instance.project_name, instance.animal_id, instance.session_name, "processed_data"
1122
+ ),
1123
+ configuration_path=new_root.joinpath(instance.project_name, instance.animal_id, "configuration"),
1124
+ deeplabcut_path=new_root.joinpath(instance.project_name, "deeplabcut"),
1125
+ )
1050
1126
 
1051
1127
  # Generates processed_data directories
1052
1128
  instance.processed_data.make_dirs()
@@ -1502,3 +1578,33 @@ class SurgeryData(YamlConfig):
1502
1578
  intervention."""
1503
1579
  injections: list[InjectionData]
1504
1580
  """Stores the data about all substances infused into the brain of the subject during the surgical intervention."""
1581
+
1582
+
1583
+ @dataclass()
1584
+ class ProcessingTracker(YamlConfig):
1585
+ """ Tracks the data processing status for a single session.
1586
+
1587
+ This class is used during BioHPC-server data processing runtimes to track which processing steps are enabled and
1588
+ have been successfully applied to a given session. This is used to optimize data processing and avoid unnecessary
1589
+ processing step repetitions where possible.
1590
+
1591
+ Notes:
1592
+ This class uses a similar mechanism for determining whether a particular option is enabled as the
1593
+ HardwareConfiguration class. Specifically, if any field of the class is set to None (null), the processing
1594
+ associated with that field is disabled. Otherwise, if the field is False, that session has not been processed
1595
+ and, if True, the session has been processed.
1596
+ """
1597
+
1598
+ checksum: bool | None = None
1599
+ """Tracks whether session data integrity has been verified using checksum recalculation method. This step should
1600
+ be enabled for all sessions to ensure their data was transmitted intact."""
1601
+ log_extractions: bool | None = None
1602
+ """Tracks whether session's behavior and runtime logs have been parsed to extract the relevant data. This step
1603
+ should be enabled for all sessions other than the 'Window checking' session type, which does not generate any log
1604
+ data."""
1605
+ suite2p: bool | None = None
1606
+ """Tracks whether the Mesoscope-acquired brain activity data has been processed (registered) using sl-suite2p.
1607
+ This step should eb enabled for all experiment sessions that collect brain activity data."""
1608
+ deeplabcut: bool | None = None
1609
+ """Tracks whether session's videos have been processed using DeepLabCut to extract pose estimation and various
1610
+ animal body part tracking. This step should only be enabled for projects that need to track this data."""