Skip to main content
← OpenMECP Documentation

omecp/
naming.rs

1//! Dynamic file naming based on input file basename
2//!
3//! This module provides a centralized system for generating file names dynamically
4//! based on the input file basename. This allows multiple jobs to run in the same
5//! directory without file conflicts.
6//!
7//! # Example
8//!
9//! ```
10//! use std::path::Path;
11//! use omecp::naming::FileNaming;
12//!
13//! let input_path = Path::new("compound_xyz_123.input");
14//! let naming = FileNaming::new(input_path);
15//!
16//! // Generate dynamic file names
17//! assert_eq!(naming.state_a_chk(), "compound_xyz_123_state_A.chk");
18//! assert_eq!(naming.pre_a("job_dir", "inp"), "job_dir/compound_xyz_123_pre_A.inp");
19//! assert_eq!(naming.step_state_a("job_dir", 5, "gjf"), "job_dir/compound_xyz_123_5_state_A.gjf");
20//! ```
21
22use std::path::Path;
23
24/// Manages dynamic file naming based on input file basename
25///
26/// All file names are prefixed with the basename extracted from the input file,
27/// ensuring unique file names when multiple jobs run in the same directory.
28#[derive(Debug, Clone)]
29pub struct FileNaming {
30    basename: String,
31}
32
33impl FileNaming {
34    /// Creates a new FileNaming instance from an input file path
35    ///
36    /// Extracts the file stem (filename without extension) to use as the basename
37    /// for all generated file names.
38    ///
39    /// # Arguments
40    ///
41    /// * `input_path` - Path to the input file
42    ///
43    /// # Example
44    ///
45    /// ```
46    /// use std::path::Path;
47    /// use omecp::naming::FileNaming;
48    ///
49    /// let naming = FileNaming::new(Path::new("compound_xyz_123.input"));
50    /// assert_eq!(naming.basename(), "compound_xyz_123");
51    /// ```
52    pub fn new(input_path: &Path) -> Self {
53        let basename = input_path
54            .file_stem()
55            .and_then(|s| s.to_str())
56            .unwrap_or("mecp_job")
57            .to_string();
58
59        Self { basename }
60    }
61
62    /// Returns the basename used for file naming
63    pub fn basename(&self) -> &str {
64        &self.basename
65    }
66
67    // Checkpoint files (Gaussian)
68
69    /// Returns the state A checkpoint file name
70    ///
71    /// Format: `{basename}_state_A.chk`
72    pub fn state_a_chk(&self) -> String {
73        format!("{}_state_A.chk", self.basename)
74    }
75
76    /// Returns the state B checkpoint file name
77    ///
78    /// Format: `{basename}_state_B.chk`
79    pub fn state_b_chk(&self) -> String {
80        format!("{}_state_B.chk", self.basename)
81    }
82
83    /// Returns the 'a' checkpoint file name
84    ///
85    /// Format: `{basename}_a.chk`
86    pub fn a_chk(&self) -> String {
87        format!("{}_a.chk", self.basename)
88    }
89
90    /// Returns the 'b' checkpoint file name
91    ///
92    /// Format: `{basename}_b.chk`
93    pub fn b_chk(&self) -> String {
94        format!("{}_b.chk", self.basename)
95    }
96
97    /// Returns the state A checkpoint file path in a job directory
98    ///
99    /// Format: `{job_dir}/{basename}_state_A.chk`
100    pub fn state_a_chk_path(&self, job_dir: &str) -> String {
101        format!("{}/{}", job_dir, self.state_a_chk())
102    }
103
104    /// Returns the state B checkpoint file path in a job directory
105    ///
106    /// Format: `{job_dir}/{basename}_state_B.chk`
107    pub fn state_b_chk_path(&self, job_dir: &str) -> String {
108        format!("{}/{}", job_dir, self.state_b_chk())
109    }
110
111    /// Returns the 'a' checkpoint file path in a job directory
112    ///
113    /// Format: `{job_dir}/{basename}_a.chk`
114    pub fn a_chk_path(&self, job_dir: &str) -> String {
115        format!("{}/{}", job_dir, self.a_chk())
116    }
117
118    /// Returns the 'b' checkpoint file path in a job directory
119    ///
120    /// Format: `{job_dir}/{basename}_b.chk`
121    pub fn b_chk_path(&self, job_dir: &str) -> String {
122        format!("{}/{}", job_dir, self.b_chk())
123    }
124
125    // Wavefunction files (ORCA)
126
127    /// Returns the state A wavefunction file path
128    ///
129    /// Format: `{job_dir}/{basename}_state_A.gbw`
130    pub fn state_a_gbw(&self, job_dir: &str) -> String {
131        format!("{}/{}_state_A.gbw", job_dir, self.basename)
132    }
133
134    /// Returns the state B wavefunction file path
135    ///
136    /// Format: `{job_dir}/{basename}_state_B.gbw`
137    pub fn state_b_gbw(&self, job_dir: &str) -> String {
138        format!("{}/{}_state_B.gbw", job_dir, self.basename)
139    }
140
141    /// Returns the 'a' wavefunction file path
142    ///
143    /// Format: `{job_dir}/{basename}_a.gbw`
144    pub fn a_gbw(&self, job_dir: &str) -> String {
145        format!("{}/{}_a.gbw", job_dir, self.basename)
146    }
147
148    /// Returns the 'b' wavefunction file path
149    ///
150    /// Format: `{job_dir}/{basename}_b.gbw`
151    pub fn b_gbw(&self, job_dir: &str) -> String {
152        format!("{}/{}_b.gbw", job_dir, self.basename)
153    }
154
155    // Pre-point calculation files
156
157    /// Returns the pre-point A input file path
158    ///
159    /// Format: `{job_dir}/{basename}_pre_A.{ext}`
160    pub fn pre_a(&self, job_dir: &str, ext: &str) -> String {
161        format!("{}/{}_pre_A.{}", job_dir, self.basename, ext)
162    }
163
164    /// Returns the pre-point B input file path
165    ///
166    /// Format: `{job_dir}/{basename}_pre_B.{ext}`
167    pub fn pre_b(&self, job_dir: &str, ext: &str) -> String {
168        format!("{}/{}_pre_B.{}", job_dir, self.basename, ext)
169    }
170
171    /// Returns the pre-point A checkpoint file path
172    ///
173    /// Format: `{job_dir}/{basename}_pre_A.chk`
174    pub fn pre_a_chk(&self, job_dir: &str) -> String {
175        format!("{}/{}_pre_A.chk", job_dir, self.basename)
176    }
177
178    /// Returns the pre-point B checkpoint file path
179    ///
180    /// Format: `{job_dir}/{basename}_pre_B.chk`
181    pub fn pre_b_chk(&self, job_dir: &str) -> String {
182        format!("{}/{}_pre_B.chk", job_dir, self.basename)
183    }
184
185    /// Returns the pre-point A wavefunction file path
186    ///
187    /// Format: `{job_dir}/{basename}_pre_A.gbw`
188    pub fn pre_a_gbw(&self, job_dir: &str) -> String {
189        format!("{}/{}_pre_A.gbw", job_dir, self.basename)
190    }
191
192    /// Returns the pre-point B wavefunction file path
193    ///
194    /// Format: `{job_dir}/{basename}_pre_B.gbw`
195    pub fn pre_b_gbw(&self, job_dir: &str) -> String {
196        format!("{}/{}_pre_B.gbw", job_dir, self.basename)
197    }
198
199    // Optimization step files
200
201    /// Returns the state A input file path for a given step
202    ///
203    /// Format: `{job_dir}/{basename}_{step}_state_A.{ext}`
204    pub fn step_state_a(&self, job_dir: &str, step: usize, ext: &str) -> String {
205        format!("{}/{}_{}_state_A.{}", job_dir, self.basename, step, ext)
206    }
207
208    /// Returns the state B input file path for a given step
209    ///
210    /// Format: `{job_dir}/{basename}_{step}_state_B.{ext}`
211    pub fn step_state_b(&self, job_dir: &str, step: usize, ext: &str) -> String {
212        format!("{}/{}_{}_state_B.{}", job_dir, self.basename, step, ext)
213    }
214
215    /// Returns the state A wavefunction file path for a given step
216    ///
217    /// Format: `{job_dir}/{basename}_{step}_state_A.gbw`
218    pub fn step_state_a_gbw(&self, job_dir: &str, step: usize) -> String {
219        format!("{}/{}_{}_state_A.gbw", job_dir, self.basename, step)
220    }
221
222    /// Returns the state B wavefunction file path for a given step
223    ///
224    /// Format: `{job_dir}/{basename}_{step}_state_B.gbw`
225    pub fn step_state_b_gbw(&self, job_dir: &str, step: usize) -> String {
226        format!("{}/{}_{}_state_B.gbw", job_dir, self.basename, step)
227    }
228
229    /// Returns the state A engrad file path for a given step
230    ///
231    /// Format: `{job_dir}/{basename}_{step}_state_A.engrad`
232    pub fn step_state_a_engrad(&self, job_dir: &str, step: usize) -> String {
233        format!("{}/{}_{}_state_A.engrad", job_dir, self.basename, step)
234    }
235
236    /// Returns the state B engrad file path for a given step
237    ///
238    /// Format: `{job_dir}/{basename}_{step}_state_B.engrad`
239    pub fn step_state_b_engrad(&self, job_dir: &str, step: usize) -> String {
240        format!("{}/{}_{}_state_B.engrad", job_dir, self.basename, step)
241    }
242
243    // Alternative naming for PES analysis modes
244
245    /// Returns the 'A' input file path for a given step (PES analysis)
246    ///
247    /// Format: `{job_dir}/{basename}_{step}_A.{ext}`
248    pub fn step_a(&self, job_dir: &str, step: usize, ext: &str) -> String {
249        format!("{}/{}_{}_A.{}", job_dir, self.basename, step, ext)
250    }
251
252    /// Returns the 'B' input file path for a given step (PES analysis)
253    ///
254    /// Format: `{job_dir}/{basename}_{step}_B.{ext}`
255    pub fn step_b(&self, job_dir: &str, step: usize, ext: &str) -> String {
256        format!("{}/{}_{}_B.{}", job_dir, self.basename, step, ext)
257    }
258
259    // Special files for specific modes
260
261    /// Returns a drive calculation file path
262    ///
263    /// Format: `{job_dir}/{basename}_drive_{step}_{state}.{ext}`
264    pub fn drive_file(&self, job_dir: &str, step: usize, state: &str, ext: &str) -> String {
265        format!(
266            "{}/{}_drive_{}_{}.{}",
267            job_dir, self.basename, step, state, ext
268        )
269    }
270
271    /// Returns a NEB calculation file path
272    ///
273    /// Format: `{job_dir}/{basename}_neb_{step}_{state}.{ext}`
274    pub fn neb_file(&self, job_dir: &str, step: usize, state: &str, ext: &str) -> String {
275        format!(
276            "{}/{}_neb_{}_{}.{}",
277            job_dir, self.basename, step, state, ext
278        )
279    }
280
281    /// Returns the basename for ORCA gbw file references in input headers
282    ///
283    /// This is used in ORCA input files where the gbw path needs to be specified.
284    /// Format: `{job_dir}/{basename}`
285    pub fn orca_basename(&self, job_dir: &str) -> String {
286        format!("{}/{}", job_dir, self.basename)
287    }
288
289    // Final output files
290
291    /// Returns the final MECP geometry output file name
292    ///
293    /// Format: `{basename}_mecp.xyz`
294    ///
295    /// # Example
296    ///
297    /// ```
298    /// use std::path::Path;
299    /// use omecp::naming::FileNaming;
300    ///
301    /// let naming = FileNaming::new(Path::new("compound_xyz_123.input"));
302    /// assert_eq!(naming.final_mecp_xyz(), "compound_xyz_123_mecp.xyz");
303    /// ```
304    pub fn final_mecp_xyz(&self) -> String {
305        format!("{}_mecp.xyz", self.basename)
306    }
307}