## Guide: Implementing Trajectory Readers in `groan_rs` (v0.7.0+) ### Overview This guide shows you how to read custom trajectory formats in `groan_rs`. Check `src/io/traj_io.rs` for method signatures and `src/io/{xtc_io.rs, trr_io.rs}` for examples. A "template" for creating your own custom trajectory reader is also provided further down in this guide. ### Steps 1. **Trajectory File Wrapper** - Create a wrapper struct for your trajectory file. - Implement the empty `TrajFile` trait: ```rust impl TrajFile for YourTrajectoryFile {} ``` 2. **Frame Data Holder** - Define a struct to hold frame data. - Implement `FrameData` trait, specifying your `TrajFile` type. - Include: - `from_frame`: Reads and stores data from a frame. - `update_system`: Transfers data to the `System` struct. 3. **Trajectory Reader** - Make a struct that reads the trajectory file and holds a mutable `System` pointer. - Implement `TrajRead` and `TrajReadOpen` traits: - `TrajRead` requires: - `get_system`: Returns a mutable `System` pointer. - `get_file_handle`: Gets a reference to the trajectory file. - `TrajReadOpen` requires: - `new`: Opens the trajectory file and initializes the handler. - Use `System::traj_iter::` to iterate frames. Add a `ProgressPrinter` for progress updates. ### Advanced Iteration - **Iteration in Range** - Extend `FrameData` with `FrameDataTime` for time-based data handling. - Implement `TrajRangeRead` in your reader for range-specific iterations. - Use `with_range` for time range iterations. - **Iteration with Step** - For stepping through frames, implement `TrajStepRead` in your reader. - Include `skip_frame` method for frame skipping. - Use `with_step` for stepping through frames. ### Concatenating Trajectories - Implement `FrameDataTime` to enable trajectory concatenation via `System::traj_cat_iter::`. - For range-limited iteration, use `with_range`. - To step through concatenated trajectories, implement `TrajStepTimeRead` with `skip_frame_time`, allowing `with_step` usage. ### Template for a Custom Trajectory Reader ```rust use std::path::Path; use crate::{errors::ReadTrajError, system::System}; use crate::io::traj_io::*; /*******************************************/ /* BASIC ITERATION */ /*******************************************/ /* Trajectory File Wrapper */ struct TrajFilePlaceholder { /* some fields */ } impl TrajFile for TrajFilePlaceholder {} /* Frame Data Holder */ struct FrameDataPlaceholder { /* some fields */ } impl FrameData for FrameDataPlaceholder { type TrajFile = TrajFilePlaceholder; fn from_frame( traj_file: &mut Self::TrajFile, system: &System, ) -> Option> { todo!(); } fn update_system(self, system: &mut System) { todo!(); } } /* Trajectory Reader */ struct TrajectoryReaderPlaceholder { /* some fields */ } impl<'a> TrajRead<'a> for TrajectoryReaderPlaceholder { type FrameData = FrameDataPlaceholder; fn get_system(&mut self) -> *mut System { todo!(); } fn get_file_handle( &mut self, ) -> &mut <>::FrameData as FrameData>::TrajFile { todo!(); } } impl<'a> TrajReadOpen<'a> for TrajectoryReaderPlaceholder { fn new(system: &'a mut System, filename: impl AsRef) -> Result { todo!(); } } // If you implement the above methods, you should be able to create a trajectory iterator: let iterator = system.traj_iter::("trajectory_placeholder"); /*******************************************/ /* ITERATION IN RANGE */ /*******************************************/ /* Frame Data Extension */ impl FrameDataTime for FrameDataPlaceholder { fn get_time(&self) -> f32 { todo!(); } } /* Trajectory Reader Extension */ impl<'a> TrajRangeRead<'a> for TrajectoryReaderPlaceholder { fn jump_to_start(&mut self, start_time: f32) -> Result<(), ReadTrajError> { todo!(); } } // If you implement the above methods, you should be able to apply the `with_range` method to your iterator: let iterator = system .traj_iter::("trajectory_placeholder") .unwrap() .with_range(start_time, end_time) .unwrap(); // Furthermore, you can now concatenate your trajectories (and apply `with_range` method to them): let concatenated_iterator = system .traj_cat_iter::(&vec!["traj1", "traj2", "traj3"]) .unwrap() .with_range(start_time, end_time) .unwrap(); /*******************************************/ /* ITERATION WITH STEP */ /*******************************************/ /* Trajectory Reader Extension */ impl<'a> TrajStepRead<'a> for TrajectoryReaderPlaceholder { fn skip_frame(&mut self) -> Result { todo!(); } } // If you implement the above method, you should be able to apply the `with_step` method to your iterator: let iterator = system .traj_iter::("trajectory_placeholder") .unwrap() .with_step(step) .unwrap(); /*******************************************/ /* CONCATENATING TRAJECTORIES */ /*******************************************/ // If you want to use the `with_step` method for your concatenated trajectories, you must implement the following method: impl<'a >TrajStepTimeRead<'a> for TrajectoryReaderPlaceholder { fn skip_frame_time(&mut self) -> Result, ReadTrajError> { todo!(); } } // Now you should be able to apply the `with_step` method to your concatenated trajectories: let concatenated_iterator = system .traj_cat_iter::(&vec!["traj1", "traj2", "traj3"]) .unwrap() .with_step(step) .unwrap(); ```