Skip to main content
← OpenMECP Documentation

omecp/
help.rs

1//! Comprehensive help system for MECP
2//!
3//! This module provides detailed documentation for all keywords, methods,
4//! and features of the MECP program.
5
6use std::collections::HashMap;
7
8/// Category for organizing keywords
9/// Category for organizing keywords in the help system.
10///
11/// This enum helps categorize different configuration keywords for easier
12/// navigation and understanding in the built-in help documentation.
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
14pub enum KeywordCategory {
15    /// Keywords that are generally required for a calculation.
16    Required,
17    /// Keywords that are optional and have default values.
18    Optional,
19    /// Keywords related to convergence thresholds and criteria.
20    Convergence,
21    /// Keywords for specifying quantum chemistry program commands.
22    Program,
23    /// Keywords specific to Time-Dependent Density Functional Theory (TD-DFT).
24    TdDft,
25    /// Keywords for defining geometric constraints.
26    Constraints,
27    /// Keywords for advanced or specialized features.
28    Advanced,
29}
30
31/// Keyword documentation entry
32#[derive(Debug, Clone)]
33/// Documentation entry for a single configuration keyword.
34///
35/// This struct holds all relevant information for a keyword, including its
36/// name, category, description, default value, example usage, and whether it
37/// is a required parameter.
38pub struct Keyword {
39    /// The name of the keyword (e.g., "nprocs", "method").
40    pub name: &'static str,
41    /// The category to which this keyword belongs.
42    pub category: KeywordCategory,
43    /// A brief description of what the keyword does.
44    pub description: &'static str,
45    /// The default value of the keyword, if applicable.
46    pub default_value: Option<&'static str>,
47    /// An example of how to use the keyword in an input file.
48    pub example: Option<&'static str>,
49    /// Indicates whether the keyword is required for a calculation.
50    pub required: bool,
51}
52
53/// QM Program information
54#[derive(Debug, Clone)]
55/// Information about a supported quantum chemistry program.
56///
57/// This struct provides details for each QM program that OpenMECP can interface
58/// with, including its name, a description, the executable command, and a list
59/// of key features.
60pub struct ProgramInfo {
61    /// The name of the QM program (e.g., "Gaussian", "ORCA").
62    pub name: &'static str,
63    /// A brief description of the program.
64    pub description: &'static str,
65    /// The typical executable command for the program.
66    pub executable: &'static str,
67    /// A list of key features or capabilities of the program.
68    pub features: &'static [&'static str],
69}
70
71/// Method information
72#[derive(Debug, Clone)]
73/// Information about a quantum chemistry method.
74///
75/// This struct provides details for each QM method, including its name,
76/// category (e.g., "DFT", "Post-HF"), a description, the programs that
77/// support it, and an example of its usage.
78pub struct MethodInfo {
79    /// The name of the method (e.g., "B3LYP", "MP2").
80    pub name: &'static str,
81    /// The category of the method (e.g., "DFT", "Post-HF", "Multireference").
82    pub category: &'static str,
83    /// A brief description of the method.
84    pub description: &'static str,
85    /// A list of QM programs that support this method.
86    pub programs: &'static [&'static str],
87    /// An example of how to specify this method in the input.
88    pub example: Option<&'static str>,
89}
90
91/// Feature information
92#[derive(Debug, Clone)]
93/// Information about a specific feature of OpenMECP.
94///
95/// This struct provides details for each major feature, including its name,
96/// a description, how to enable or use it, and an example.
97pub struct FeatureInfo {
98    /// The name of the feature (e.g., "Normal Mode", "Restart").
99    pub name: &'static str,
100    /// A brief description of the feature.
101    pub description: &'static str,
102    /// Instructions on how to use or enable the feature.
103    pub usage: &'static str,
104    /// An example demonstrating the feature's usage.
105    pub example: Option<&'static str>,
106}
107
108/// All keyword documentation
109pub const KEYWORDS: &[Keyword] = &[
110    // REQUIRED PARAMETERS
111    Keyword {
112        name: "nprocs",
113        category: KeywordCategory::Required,
114        description: "Number of processors for parallel quantum chemistry calculation",
115        default_value: Some("1"),
116        example: Some("nprocs = 30"),
117        required: false,
118    },
119    Keyword {
120        name: "mem",
121        category: KeywordCategory::Required,
122        description: "Memory allocation for QM calculation (format depends on program)",
123        default_value: Some("\"1GB\""),
124        example: Some("mem = \"120GB\"  # Gaussian\nmem = \"8000\"   # ORCA (MB)"),
125        required: false,
126    },
127    Keyword {
128        name: "method",
129        category: KeywordCategory::Required,
130        description: "Quantum chemistry method and basis set (e.g., 'B3LYP/6-31G*')",
131        default_value: None,
132        example: Some("method = \"B3LYP/6-31G*\"\nmethod = \"n scf(maxcycle=500,xqc) uwb97xd/def2svpp\""),
133        required: true,
134    },
135    Keyword {
136        name: "charge",
137        category: KeywordCategory::Required,
138        description: "Molecular charge for both electronic states",
139        default_value: Some("0"),
140        example: Some("charge = 0\ncharge = 1"),
141        required: false,
142    },
143    Keyword {
144        name: "mult_state_a (or mult_a)",
145        category: KeywordCategory::Required,
146        description: "Spin multiplicity for state A (2S+1, where S is spin)",
147        default_value: Some("1"),
148        example: Some("mult_state_a = 1  # Singlet\nmult_a = 3  # Triplet"),
149        required: false,
150    },
151    Keyword {
152        name: "mult_state_b (or mult_b)",
153        category: KeywordCategory::Required,
154        description: "Spin multiplicity for state B",
155        default_value: Some("1"),
156        example: Some("mult_state_b = 1  # Singlet\nmult_b = 3  # Triplet"),
157        required: false,
158    },
159    Keyword {
160        name: "program",
161        category: KeywordCategory::Required,
162        description: "Quantum chemistry program to use for calculations",
163        default_value: Some("\"gaussian\""),
164        example: Some("program = gaussian\nprogram = orca"),
165        required: false,
166    },
167    Keyword {
168        name: "mode",
169        category: KeywordCategory::Required,
170        description: "Running mode for MECP optimization",
171        default_value: Some("\"normal\""),
172        example: Some("mode = normal\nmode = stable\nmode = read"),
173        required: false,
174    },
175
176    // OPTIONAL PARAMETERS
177    Keyword {
178        name: "td_state_a (or td_a)",
179        category: KeywordCategory::Optional,
180        description: "TD-DFT keywords for state A (Gaussian only, specified in *tail1 for ORCA)",
181        default_value: Some("\".\""),
182        example: Some("td_state_a = \"nstates=10\"\ntd_a = \"nstates=10\""),
183        required: false,
184    },
185    Keyword {
186        name: "td_state_b (or td_b)",
187        category: KeywordCategory::Optional,
188        description: "TD-DFT keywords for state B (Gaussian only, specified in *tail2 for ORCA)",
189        default_value: Some("\".\""),
190        example: Some("td_state_b = \"nstates=10\"\ntd_b = \"nstates=10\""),
191        required: false,
192    },
193    Keyword {
194        name: "mp2",
195        category: KeywordCategory::Optional,
196        description: "Enable MP2 or doubly hybrid DFT calculation (Gaussian only)",
197        default_value: Some("false"),
198        example: Some("mp2 = true"),
199        required: false,
200    },
201    Keyword {
202        name: "bagel_model",
203        category: KeywordCategory::Optional,
204        description: "Path to BAGEL model input file (required when program=bagel)",
205        default_value: None,
206        example: Some("bagel_model = \"model.inp\""),
207        required: false,
208    },
209    Keyword {
210        name: "state_a",
211        category: KeywordCategory::Optional,
212        description: "State index for multireference calculations in BAGEL (0-based) for state A",
213        default_value: Some("0"),
214        example: Some("state_a = 0"),
215        required: false,
216    },
217    Keyword {
218        name: "state_b",
219        category: KeywordCategory::Optional,
220        description: "State index for multireference calculations in BAGEL (0-based) for state B",
221        default_value: Some("1"),
222        example: Some("state_b = 1"),
223        required: false,
224    },
225
226    // PROGRAM COMMANDS
227    Keyword {
228        name: "gau_comm",
229        category: KeywordCategory::Program,
230        description: "Gaussian executable command",
231        default_value: Some("\"g16\""),
232        example: Some("gau_comm = \"g16\""),
233        required: false,
234    },
235    Keyword {
236        name: "orca_comm",
237        category: KeywordCategory::Program,
238        description: "ORCA executable command",
239        default_value: Some("\"orca\""),
240        example: Some("orca_comm = \"/opt/orca5/orca\""),
241        required: false,
242    },
243    Keyword {
244        name: "xtb_comm",
245        category: KeywordCategory::Program,
246        description: "xTB executable command",
247        default_value: Some("\"xtb\""),
248        example: Some("xtb_comm = \"xtb\""),
249        required: false,
250    },
251    Keyword {
252        name: "bagel_comm",
253        category: KeywordCategory::Program,
254        description: "BAGEL executable command (includes MPI options)",
255        default_value: Some("\"bagel\""),
256        example: Some("bagel_comm = \"mpirun -np 36 /opt/bagel/bin/BAGEL\""),
257        required: false,
258    },
259
260    // CONVERGENCE THRESHOLDS
261    Keyword {
262        name: "delta_e",
263        category: KeywordCategory::Convergence,
264        description: "Energy difference threshold (|E1-E2|) for convergence (in Hartree)",
265        default_value: Some("0.000050"),
266        example: Some("delta_e = 0.000050"),
267        required: false,
268    },
269    Keyword {
270        name: "rms_dis",
271        category: KeywordCategory::Convergence,
272        description: "RMS displacement threshold for convergence (in Angstrom)",
273        default_value: Some("0.0025"),
274        example: Some("rms_dis = 0.0025"),
275        required: false,
276    },
277    Keyword {
278        name: "max_dis",
279        category: KeywordCategory::Convergence,
280        description: "Maximum atomic displacement threshold for convergence (in Angstrom)",
281        default_value: Some("0.004"),
282        example: Some("max_dis = 0.004"),
283        required: false,
284    },
285    Keyword {
286        name: "max_grad",
287        category: KeywordCategory::Convergence,
288        description: "Maximum gradient component threshold for convergence (Hartree/Angstrom)",
289        default_value: Some("0.001323"),
290        example: Some("max_grad = 0.001323"),
291        required: false,
292    },
293    Keyword {
294        name: "rms_grad",
295        category: KeywordCategory::Convergence,
296        description: "RMS gradient threshold for convergence (Hartree/Angstrom)",
297        default_value: Some("0.000945"),
298        example: Some("rms_grad = 0.000945"),
299        required: false,
300    },
301    Keyword {
302        name: "max_steps",
303        category: KeywordCategory::Convergence,
304        description: "Maximum number of optimization steps",
305        default_value: Some("100"),
306        example: Some("max_steps = 300"),
307        required: false,
308    },
309    Keyword {
310        name: "max_step_size",
311        category: KeywordCategory::Convergence,
312        description: "Maximum step size for geometry update (in Angstrom)",
313        default_value: Some("0.1"),
314        example: Some("max_step_size = 0.1"),
315        required: false,
316    },
317    Keyword {
318        name: "max_history",
319        category: KeywordCategory::Convergence,
320        description: "Maximum number of history entries for DIIS optimizers (GDIIS/GEDIIS). Controls how many previous iterations are retained for interpolation. Larger values can improve convergence but use more memory.",
321        default_value: Some("4"),
322        example: Some("max_history = 5"),
323        required: false,
324    },
325    Keyword {
326        name: "reduced_factor",
327        category: KeywordCategory::Convergence,
328        description: "Factor for reducing GDIIS step size when RMS gradient is near convergence",
329        default_value: Some("0.5"),
330        example: Some("reduced_factor = 0.5"),
331        required: false,
332    },
333    Keyword {
334        name: "hessian",
335        category: KeywordCategory::Convergence,
336        description: "Hessian update method: direct_psb (default, recommended), inverse_bfgs (Fortran-style), bofill, powell, bfgs_powell_mix. Direct methods required for blend optimizer.",
337        default_value: Some("direct_psb"),
338        example: Some("hessian = direct_psb       # Direct H + PSB (recommended, default)\nhessian = inverse_bfgs    # Inverse H⁻¹ + BFGS\nhessian = bofill          # Bofill update (TS-like)\nhessian = powell          # Powell SR1\nhessian = bfgs_powell_mix # Adaptive BFGS/Powell"),
339        required: false,
340    },
341    Keyword {
342        name: "bfgs_rho",
343        category: KeywordCategory::Convergence,
344        description: "Scaling factor for BFGS step (rho). Larger values amplify Newton steps on flat PES.",
345        default_value: Some("15.0"),
346        example: Some("bfgs_rho = 15.0"),
347        required: false,
348    },
349    Keyword {
350        name: "step_reduction_multiplier",
351        category: KeywordCategory::Convergence,
352        description: "Multiplier for RMS gradient threshold in step reduction activation. Step reduction triggers when history norm < rms_g × this value.",
353        default_value: Some("10.0"),
354        example: Some("step_reduction_multiplier = 10.0"),
355        required: false,
356    },
357    Keyword {
358        name: "steepest_descent_step",
359        category: KeywordCategory::Convergence,
360        description: "Small steepest descent step size (Å) for fallback when DIIS/BFGS produces invalid steps",
361        default_value: Some("0.01"),
362        example: Some("steepest_descent_step = 0.01"),
363        required: false,
364    },
365    Keyword {
366        name: "trust_reduction_factor",
367        category: KeywordCategory::Convergence,
368        description: "Trust radius contraction factor when energy increases above threshold",
369        default_value: Some("0.5"),
370        example: Some("trust_reduction_factor = 0.5"),
371        required: false,
372    },
373    Keyword {
374        name: "trust_increase_factor",
375        category: KeywordCategory::Convergence,
376        description: "Trust radius expansion factor when energy decreases below threshold",
377        default_value: Some("1.2"),
378        example: Some("trust_increase_factor = 1.2"),
379        required: false,
380    },
381    Keyword {
382        name: "trust_inc_threshold",
383        category: KeywordCategory::Convergence,
384        description: "Energy increase threshold (Ha) for trust radius reduction. Increase above this triggers contraction.",
385        default_value: Some("0.0001"),
386        example: Some("trust_inc_threshold = 0.0001"),
387        required: false,
388    },
389    Keyword {
390        name: "trust_dec_threshold",
391        category: KeywordCategory::Convergence,
392        description: "Energy decrease threshold (Ha) for trust radius increase. Decrease below this triggers expansion.",
393        default_value: Some("0.0001"),
394        example: Some("trust_dec_threshold = 0.0001"),
395        required: false,
396    },
397    Keyword {
398        name: "trust_min_radius",
399        category: KeywordCategory::Convergence,
400        description: "Minimum allowed trust radius in Å",
401        default_value: Some("0.01"),
402        example: Some("trust_min_radius = 0.01"),
403        required: false,
404    },
405    Keyword {
406        name: "trust_max_radius",
407        category: KeywordCategory::Convergence,
408        description: "Maximum allowed trust radius in Å",
409        default_value: Some("1.0"),
410        example: Some("trust_max_radius = 1.0"),
411        required: false,
412    },
413    Keyword {
414        name: "print_level",
415        category: KeywordCategory::Convergence,
416        description: "Output verbosity: 0=quiet, 1=normal (default), 2=verbose (DIIS debug internals)",
417        default_value: Some("1"),
418        example: Some("print_level = 0   # Quiet\nprint_level = 1   # Normal\nprint_level = 2   # Verbose debug"),
419        required: false,
420    },
421    Keyword {
422        name: "use_gediis",
423        category: KeywordCategory::Convergence,
424        description: "Optimizer variant: false/\"none\"=GDIIS (default), true/\"sequential\"=sequential hybrid GEDIIS, \"blend\"=GDIIS_blend with trust region.",
425        default_value: Some("false"),
426        example: Some("use_gediis = false         # GDIIS (default)\nuse_gediis = true          # Sequential hybrid GEDIIS\nuse_gediis = sequential    # Same as true\nuse_gediis = blend         # GDIIS_blend with trust region"),
427        required: false,
428    },
429    Keyword {
430        name: "use_hybrid_gediis",
431        category: KeywordCategory::Convergence,
432        description: "Sequential hybrid GEDIIS/GDIIS (Li & Frisch JCTC 2006). Only active when use_gediis=true or use_gediis=\"sequential\".",
433        default_value: Some("false"),
434        example: Some("use_hybrid_gediis = true   # Sequential hybrid\nuse_hybrid_gediis = false  # Pure GEDIIS (default for GEDIIS)"),
435        required: false,
436    },
437    Keyword {
438        name: "gediis_blend_mode",
439        category: KeywordCategory::Convergence,
440        description: "Blend strategy when use_gediis=\"blend\": \"fixed\" (50/50), \"fixed_sequential\" (50/50→GDIIS near minimum), \"gradient\" (RMS-gradient weighted), \"sequential\" (GDIIS↔GEDIIS per step).",
441        default_value: Some("\"fixed_sequential\""),
442        example: Some("gediis_blend_mode = fixed             # 50/50 GDIIS/GEDIIS blend\ngediis_blend_mode = gradient         # RMS-gradient-weighted blend\ngediis_blend_mode = sequential       # Per-step GDIIS/GEDIIS switching"),
443        required: false,
444    },
445    Keyword {
446        name: "gediis_switch_rms",
447        category: KeywordCategory::Convergence,
448        description: "RMS gradient threshold for GDIIS→GEDIIS switch. Paper: 10⁻² au ≈ 0.005 Ha/Å.",
449        default_value: Some("0.005"),
450        example: Some("gediis_switch_rms = 0.005"),
451        required: false,
452    },
453    Keyword {
454        name: "gediis_switch_step",
455        category: KeywordCategory::Convergence,
456        description: "RMS displacement threshold for GEDIIS→GDIIS switch. Paper: 2.5×10⁻³ au ≈ 0.001 Å.",
457        default_value: Some("0.001"),
458        example: Some("gediis_switch_step = 0.001"),
459        required: false,
460    },
461    Keyword {
462        name: "switch_step",
463        category: KeywordCategory::Convergence,
464        description: "Step number to switch from BFGS to DIIS optimizers (0=DIIS-only, >=max_steps=BFGS-only)",
465        default_value: Some("3"),
466        example: Some("switch_step = 10  # BFGS for steps 1-10, then DIIS"),
467        required: false,
468    },
469    // Robust DIIS options
470    Keyword {
471        name: "use_robust_diis",
472        category: KeywordCategory::Convergence,
473        description: "Enable DIIS step validation: rejects bad extrapolations via cosine and coefficient checks. Prevents wild steps near convergence.",
474        default_value: Some("false"),
475        example: Some("use_robust_diis = true"),
476        required: false,
477    },
478    Keyword {
479        name: "gediis_variant",
480        category: KeywordCategory::Convergence,
481        description: "GEDIIS variant: auto, rfo, energy, or simultaneous (only with use_robust_diis)",
482        default_value: Some("auto"),
483        example: Some("gediis_variant = energy"),
484        required: false,
485    },
486    Keyword {
487        name: "gdiis_cosine_check",
488        category: KeywordCategory::Convergence,
489        description: "Cosine check mode for GDIIS: none, zero, standard, variable, strict",
490        default_value: Some("standard"),
491        example: Some("gdiis_cosine_check = variable"),
492        required: false,
493    },
494    Keyword {
495        name: "gdiis_coeff_check",
496        category: KeywordCategory::Convergence,
497        description: "Coefficient check mode for GDIIS: none, regular, force_recent, combined",
498        default_value: Some("regular"),
499        example: Some("gdiis_coeff_check = combined"),
500        required: false,
501    },
502    Keyword {
503        name: "n_neg",
504        category: KeywordCategory::Convergence,
505        description: "Number of negative Hessian eigenvalues (0=minimum, 1=TS search)",
506        default_value: Some("0"),
507        example: Some("n_neg = 1  # Transition state search"),
508        required: false,
509    },
510    Keyword {
511        name: "gediis_sim_switch",
512        category: KeywordCategory::Convergence,
513        description: "RMS error threshold for GEDIIS variant switching",
514        default_value: Some("0.0025"),
515        example: Some("gediis_sim_switch = 0.005"),
516        required: false,
517    },
518    // ADVANCED OPTIONS
519    Keyword {
520        name: "restart",
521        category: KeywordCategory::Advanced,
522        description: "Restart optimization from checkpoint file",
523        default_value: Some("false"),
524        example: Some("restart = true"),
525        required: false,
526    },
527    Keyword {
528        name: "print_checkpoint",
529        category: KeywordCategory::Advanced,
530        description: "Enable or disable checkpoint JSON file generation (supports true/false, yes/no, 1/0)",
531        default_value: Some("false"),
532        example: Some("print_checkpoint = false"),
533        required: false,
534    },
535    Keyword {
536        name: "fixedatoms",
537        category: KeywordCategory::Constraints,
538        description: "Comma-separated list or ranges of atom indices to freeze (1-based, converted to 0-based internally)",
539        default_value: None,
540        example: Some("fixedatoms = \"1,5,10\"      # atoms 1, 5, and 10\nfixedatoms = \"1-5,10-15\"  # ranges"),
541        required: false,
542    },
543    Keyword {
544        name: "fix_de",
545        category: KeywordCategory::Advanced,
546        description: "Fix energy difference to target value (in eV) for specialized optimizations",
547        default_value: Some("0.0"),
548        example: Some("fix_de = 2.5  # Target ΔE = 2.5 eV"),
549        required: false,
550    },
551
552    // SCAN PARAMETERS
553    Keyword {
554        name: "drive_coordinate",
555        category: KeywordCategory::Advanced,
556        description: "Coordinate specification for reaction path following",
557        default_value: None,
558        example: Some("drive_coordinate = \"R 1 2\"  # Distance between atoms 1-2"),
559        required: false,
560    },
561    Keyword {
562        name: "drive_start",
563        category: KeywordCategory::Advanced,
564        description: "Starting value for coordinate driving (in Angstrom or degrees)",
565        default_value: Some("0.0"),
566        example: Some("drive_start = 1.0"),
567        required: false,
568    },
569    Keyword {
570        name: "drive_end",
571        category: KeywordCategory::Advanced,
572        description: "Ending value for coordinate driving (in Angstrom or degrees)",
573        default_value: Some("0.0"),
574        example: Some("drive_end = 2.0"),
575        required: false,
576    },
577    Keyword {
578        name: "drive_steps",
579        category: KeywordCategory::Advanced,
580        description: "Number of steps for coordinate driving",
581        default_value: Some("10"),
582        example: Some("drive_steps = 20"),
583        required: false,
584    },
585    Keyword {
586        name: "drive_type",
587        category: KeywordCategory::Advanced,
588        description: "Type of coordinate driving",
589        default_value: None,
590        example: Some("drive_type = \"bond\"      # Bond distance\ndrive_type = \"angle\"      # Bond angle"),
591        required: false,
592    },
593    Keyword {
594        name: "drive_atoms",
595        category: KeywordCategory::Advanced,
596        description: "Comma-separated atom indices for driving (1-based)",
597        default_value: None,
598        example: Some("drive_atoms = \"1,2\"       # For bond/angle\ndrive_atoms = \"1,2,3\"     # For angle"),
599        required: false,
600    },
601
602    // ONIOM PARAMETERS
603    Keyword {
604        name: "isoniom",
605        category: KeywordCategory::Advanced,
606        description: "Enable ONIOM QM/MM embedding",
607        default_value: Some("false"),
608        example: Some("isoniom = true"),
609        required: false,
610    },
611    Keyword {
612        name: "chargeandmultforoniom1",
613        category: KeywordCategory::Advanced,
614        description: "Charge and multiplicity for ONIOM layer 1",
615        default_value: None,
616        example: Some("chargeandmultforoniom1 = \"0 1\""),
617        required: false,
618    },
619    Keyword {
620        name: "chargeandmultforoniom2",
621        category: KeywordCategory::Advanced,
622        description: "Charge and multiplicity for ONIOM layer 2",
623        default_value: None,
624        example: Some("chargeandmultforoniom2 = \"0 1\""),
625        required: false,
626    },
627
628    // CUSTOM INTERFACE
629    Keyword {
630        name: "custom_interface_file",
631        category: KeywordCategory::Advanced,
632        description: "JSON configuration file for custom QM program interface",
633        default_value: None,
634        example: Some("custom_interface_file = \"custom.json\""),
635        required: false,
636    },
637    Keyword {
638        name: "basis",
639        category: KeywordCategory::Advanced,
640        description: "Basis set specification (for programs that separate method and basis)",
641        default_value: None,
642        example: Some("basis = \"def2-TZVP\""),
643        required: false,
644    },
645    Keyword {
646        name: "solvent",
647        category: KeywordCategory::Advanced,
648        description: "Solvent model specification (e.g., PCM, SMD)",
649        default_value: None,
650        example: Some("solvent = \"smd=water\""),
651        required: false,
652    },
653    Keyword {
654        name: "dispersion",
655        category: KeywordCategory::Advanced,
656        description: "Dispersion correction specification",
657        default_value: None,
658        example: Some("dispersion = \"GD3BJ\""),
659        required: false,
660    },
661    Keyword {
662        name: "charge_b",
663        category: KeywordCategory::Advanced,
664        description: "Separate molecular charge for state B (defaults to charge value)",
665        default_value: None,
666        example: Some("charge = 1\ncharge_b = -1  # State B has different charge"),
667        required: false,
668    },
669];
670
671/// Program information
672pub fn get_programs() -> &'static [ProgramInfo] {
673    &[
674        ProgramInfo {
675            name: "Gaussian",
676            description: "Most widely used quantum chemistry program with extensive functionality",
677            executable: "g16 (or g09, g03)",
678            features: &[
679                "DFT, HF, post-HF methods",
680                "TD-DFT excited states",
681                "MP2 and higher",
682                "Solvent models (PCM, SMD)",
683                "ONIOM QM/MM",
684                "Force calculations",
685                "Frequency analysis",
686            ],
687        },
688        ProgramInfo {
689            name: "ORCA",
690            description: "Modern quantum chemistry program with efficient algorithms",
691            executable: "orca",
692            features: &[
693                "DFT, HF, post-HF methods",
694                "TD-DFT excited states",
695                "Strong correlation (CASSCF, CASPT2)",
696                "Solvent models",
697                "Relativistic corrections",
698                "EPR/NMR properties",
699            ],
700        },
701        ProgramInfo {
702            name: "xTB",
703            description: "Semi-empirical tight-binding program for large systems",
704            executable: "xtb",
705            features: &[
706                "GFN2-xTB method",
707                "Very fast for large systems",
708                "Semi-empirical accuracy",
709                "GPU acceleration",
710                "Solvation models",
711            ],
712        },
713        ProgramInfo {
714            name: "BAGEL",
715            description: "Multireference quantum chemistry program for strong correlation",
716            executable: "mpirun -np N /path/to/BAGEL",
717            features: &[
718                "CASSCF/CASPT2",
719                "MRCI methods",
720                "Strongly correlated systems",
721                "Excited states",
722                "State-specific optimizations",
723            ],
724        },
725        ProgramInfo {
726            name: "Custom",
727            description: "User-defined QM program via JSON configuration",
728            executable: "User-specified",
729            features: &[
730                "Any program with text I/O",
731                "Regex-based parsing",
732                "Configurable via JSON",
733                "Supports forces and energies",
734            ],
735        },
736    ]
737}
738
739/// Method information
740pub fn get_methods() -> &'static [MethodInfo] {
741    &[
742        MethodInfo {
743            name: "B3LYP",
744            category: "DFT",
745            description: "Hybrid DFT functional, widely used for general chemistry",
746            programs: &["Gaussian", "ORCA", "xTB"],
747            example: Some("method = \"B3LYP/6-31G*\""),
748        },
749        MethodInfo {
750            name: "wB97XD",
751            category: "DFT",
752            description: "Long-range corrected DFT functional with dispersion",
753            programs: &["Gaussian"],
754            example: Some("method = \"wB97XD/def2-SVP\""),
755        },
756        MethodInfo {
757            name: "PBE0",
758            category: "DFT",
759            description: "Hybrid DFT functional with 25% exact exchange",
760            programs: &["Gaussian", "ORCA"],
761            example: Some("method = \"PBE0/def2-TZVP\""),
762        },
763        MethodInfo {
764            name: "MP2",
765            category: "Post-HF",
766            description: "Second-order Møller-Plesset perturbation theory",
767            programs: &["Gaussian", "ORCA"],
768            example: Some("mp2 = true  # In Gaussian"),
769        },
770        MethodInfo {
771            name: "CASSCF",
772            category: "Multireference",
773            description: "Complete Active Space Self-Consistent Field",
774            programs: &["ORCA", "BAGEL"],
775            example: Some("# In ORCA: %casscf nel 6 norb 6 end"),
776        },
777        MethodInfo {
778            name: "GFN2-xTB",
779            category: "Semi-empirical",
780            description: "Semi-empirical tight-binding method for large systems",
781            programs: &["xTB"],
782            example: Some("# Automatically used with xTB program"),
783        },
784    ]
785}
786
787/// Feature information
788pub const FEATURES: &[FeatureInfo] = &[
789    FeatureInfo {
790        name: "Normal Mode",
791        description: "Standard MECP optimization between two electronic states",
792        usage: "mode = normal",
793        example: Some("mode = normal"),
794    },
795    FeatureInfo {
796        name: "Stability Analysis",
797        description: "Check wavefunction stability before optimization",
798        usage: "mode = stable",
799        example: Some("mode = stable  # Runs stability check first"),
800    },
801    FeatureInfo {
802        name: "Restart",
803        description: "Restart optimization from saved checkpoint",
804        usage: "restart = true",
805        example: Some("checkpoint = \"restart.chk\"\nrestart = true"),
806    },
807    FeatureInfo {
808        name: "Configuration File (omecp_config.cfg)",
809        description: "Hierarchical configuration system with local/user/system precedence",
810        usage: "Create template: omecp ci omecp_config.cfg",
811        example: Some("# See omecp_config.cfg template for all options"),
812    },
813    FeatureInfo {
814        name: "Parameter Display",
815        description: "Automatic display of all configuration parameters and settings source at startup",
816        usage: "Enabled by default, shows which config file is loaded",
817        example: Some("Displays: source file, all parameters, thresholds, settings"),
818    },
819    FeatureInfo {
820        name: "Debug Logging",
821        description: "Optional file-based debug logging with dynamic filenames",
822        usage: "Enable in omecp_config.cfg: file_logging = true",
823        example: Some("Creates: omecp_debug_<input_basename>.log"),
824    },
825    FeatureInfo {
826        name: "BFGS Optimizer",
827        description: "Quasi-Newton method used for first 3 steps",
828        usage: "Used automatically for initial steps",
829        example: None,
830    },
831    FeatureInfo {
832        name: "GDIIS Optimizer",
833        description: "Geometry Direct Inversion of Iterative Subspace for later steps",
834            usage: "use_gediis = false (default)",
835        example: Some("use_gediis = false"),
836    },
837    FeatureInfo {
838        name: "GEDIIS Optimizer",
839        description: "Energy-informed DIIS with diagonal energy coupling (Li & Frisch JCTC 2006)",
840        usage: "use_gediis = true",
841        example: Some("use_gediis = true  # Enables GEDIIS"),
842    },
843    FeatureInfo {
844        name: "Sequential Hybrid GEDIIS",
845        description: "3-phase switching: GDIIS → GEDIIS → GDIIS (Li & Frisch JCTC 2006)",
846        usage: "use_gediis = true + use_hybrid_gediis = true",
847        example: Some("use_hybrid_gediis = true  # Sequential hybrid"),
848    },
849    FeatureInfo {
850        name: "GDIIS_blend Optimizer",
851        description: "Gradient-weighted and trust-region blend of GDIIS/GEDIIS steps (experimental).",
852        usage: "use_gediis = blend + use_hybrid_gediis = true + gediis_blend_mode = <mode>",
853        example: Some("use_gediis = blend\nuse_hybrid_gediis = true\ngediis_blend_mode = gradient  # RMS-gradient-weighted blend"),
854    },
855    FeatureInfo {
856        name: "Flexible Optimizer Switching",
857        description: "Control when to switch from BFGS to DIIS optimizers",
858        usage: "switch_step = N (default: 3)",
859        example: Some("switch_step = 0   # DIIS-only\nswitch_step = 10  # BFGS for 10 steps\nswitch_step = 999 # BFGS-only"),
860    },
861    FeatureInfo {
862        name: "Bond Constraints",
863        description: "Fix bond distances during optimization",
864        usage: "R i j value (in Angstrom)",
865        example: Some("R 1 2 1.5  # Fix distance between atoms 1-2 to 1.5 Angstrom"),
866    },
867    FeatureInfo {
868        name: "Angle Constraints",
869        description: "Fix bond angles during optimization",
870        usage: "A i j k value (in degrees)",
871        example: Some("A 1 2 3 109.5  # Fix angle 1-2-3 to 109.5°"),
872    },
873    FeatureInfo {
874        name: "PES Scanning",
875        description: "Scan potential energy surface along 1D or 2D coordinate",
876        usage: "S R i j start points step  OR  S A i j k start points step",
877        example: Some("S R 1 2 1.0 10 0.1  # Scan R(1,2) from 1.0 Angstrom, 10 steps"),
878    },
879    FeatureInfo {
880        name: "Coordinate Driving",
881        description: "Drive along reaction coordinate",
882        usage: "drive_type, drive_atoms, drive_start, drive_end, drive_steps",
883        example: Some("drive_type = \"bond\"\ndrive_atoms = \"1,2\"\ndrive_start = 1.0\ndrive_end = 2.0"),
884    },
885    FeatureInfo {
886        name: "LST Interpolation",
887        description: "Linear/Quadratic Synchronous Transit interpolation",
888        usage: "Provide *lst1 and *lst2 geometries in input file",
889        example: Some("*lst1\n# Geometry 1\n*\n*lst2\n# Geometry 2\n*"),
890    },
891    FeatureInfo {
892        name: "External Geometry",
893        description: "Load geometry from external file (.xyz, .log, .gjf)",
894        usage: "@filename in *geom section",
895        example: Some("*geom\n@/path/to/molecule.xyz\n*"),
896    },
897    FeatureInfo {
898        name: "Fixed Atoms",
899        description: "Freeze specific atoms during optimization",
900        usage: "fixedatoms = \"list\"",
901        example: Some("fixedatoms = \"1,2,3\"  # Fix first 3 atoms"),
902    },
903    FeatureInfo {
904        name: "ONIOM QM/MM",
905        description: "Embed molecule in MM environment",
906        usage: "isoniom = true with layer definitions",
907        example: Some("isoniom = true\nchargeandmultforoniom1 = \"0 1\""),
908    },
909    FeatureInfo {
910        name: "Custom Interface",
911        description: "Define custom QM program via JSON configuration",
912        usage: "custom_interface_file = \"config.json\"",
913        example: Some("# See documentation for JSON format"),
914    },
915];
916
917/// Prints the standard OpenMECP program header with version and citation information.
918///
919/// This is the single source of truth for the header block. It is called by
920/// `print_global_help()`, `print_version()`, and at the start of each optimization
921/// run so that the banner only needs to be maintained in one place.
922///
923/// # Examples
924///
925/// ```
926/// use omecp::help::print_header;
927/// print_header();
928/// ```
929pub fn print_header() {
930    println!("**** OpenMECP: Minimum Energy Crossing Point Optimizer ****");
931    println!(
932        "              Version {}  Release date: 2026",
933        env!("CARGO_PKG_VERSION")
934    );
935    println!("               ****Developer Le Nhan Pham****             ");
936    println!("           https://github.com/lenhanpham/OpenMECP        \n");
937    println!(" Please cite this preprint if you use OpenMECP for your research:");
938    println!(" #-------------------------------------------------------------------------------#");
939    println!(" # L.N Pham, \"OpenMECP: A High-Performance Rust Implementation for               #");
940    println!(" # the Rigorous Location of Minimum Energy Crossing Points in Chemical Dynamics\" #");
941    println!(" # 2026, https://doi.org/10.13140/RG.2.2.21309.73443                             #");
942    println!(" #-------------------------------------------------------------------------------#");
943}
944
945/// Print global help
946pub fn print_global_help() {
947    print_header();
948    println!();
949    println!();
950    println!("USAGE:");
951    println!("    omecp [OPTIONS] <COMMAND>");
952    println!();
953    println!("COMMANDS:");
954    println!("    ci <geometry_file> [output_file]");
955    println!("                        Create a template input file from a geometry file");
956    println!("                        Supported formats: .xyz, .log, .gjf");
957    println!();
958    println!("    ci omecp_config.cfg");
959    println!("                        Create a configuration template file");
960    println!("                        See 'Configuration File' section below");
961    println!();
962    println!("    <input_file>");
963    println!("                        Run MECP optimization using the input file");
964    println!();
965    println!("OPTIONS:");
966    println!("    -h, --help [topic]   Show help. Topics: keywords, methods, features, examples");
967    println!();
968    println!("CONFIGURATION FILE:");
969    println!("    OpenMECP uses 'omecp_config.cfg' for program configuration.");
970    println!("    Create template:     omecp ci omecp_config.cfg");
971    println!("    Supported locations:");
972    println!("      - ./omecp_config.cfg (local, highest priority)");
973    println!("      - ~/.config/omecp/omecp_config.cfg (user)");
974    println!("      - /etc/omecp/omecp_config.cfg (system)");
975    println!("    Features: file extensions, logging, cleanup, debug output");
976    println!("    Parameters are automatically displayed at startup");
977    println!();
978    println!("EXAMPLES:");
979    println!("    Create template:     omecp ci molecule.xyz");
980    println!("    Create with name:    omecp ci molecule.xyz custom.inp");
981    println!("    Run MECP:            omecp input.inp > output.log");
982    println!("    Create settings:     omecp ci omecp_config.cfg");
983    println!("    View keywords:       omecp --help keywords");
984    println!("    View methods:        omecp --help methods");
985    println!("    View features:       omecp --help features");
986    println!();
987}
988
989/// Print help for 'ci' command
990pub fn print_ci_help() {
991    println!("Create Input Template (ci) Command");
992    println!("═════════════════════════════════════");
993    println!();
994    println!("USAGE:");
995    println!("    omecp ci <geometry_file> [output_file]");
996    println!();
997    println!("DESCRIPTION:");
998    println!("    Generates a template MECP input file from a geometry file.");
999    println!("    The template includes all required and optional parameters with");
1000    println!("    sensible defaults, ready for customization.");
1001    println!();
1002    println!("ARGUMENTS:");
1003    println!("    <geometry_file>      Input geometry file (required)");
1004    println!("                        Supported formats:");
1005    println!("                        - .xyz: XYZ coordinate file");
1006    println!("                        - .gjf: Gaussian input file");
1007    println!("                        - .log: Gaussian output file");
1008    println!();
1009    println!("    [output_file]        Output template file (optional)");
1010    println!("                        Default naming:");
1011    println!("                        - .xyz/.gjf files: <name>.inp");
1012    println!("                        - .log/.out/.json files: <name>_omecp.inp");
1013    println!("                        (suffix prevents overwriting QM output)");
1014    println!();
1015    println!("EXAMPLES:");
1016    println!("    omecp ci molecule.xyz");
1017    println!("                        Creates 'molecule.inp' with '@molecule.xyz' reference");
1018    println!();
1019    println!("    omecp ci calc.log");
1020    println!("                        Creates 'calc_omecp.inp' (prevents overwriting calc.log)");
1021    println!();
1022    println!("    omecp ci calc.log custom.inp");
1023    println!("                        Creates 'custom.inp' with '@calc.log' reference");
1024    println!();
1025    println!("OUTPUT FORMAT:");
1026    println!("    Generated template includes:");
1027    println!("    - Required parameters (nprocs, mem, method, charge, mult, mode)");
1028    println!("    - Optional parameters with defaults");
1029    println!("    - Convergence thresholds");
1030    println!("    - Program settings");
1031    println!("    - *geom section with @reference");
1032    println!("    - Empty *tail1 and *tail2 sections");
1033    println!("    - Constraint examples");
1034    println!();
1035}
1036
1037/// Print keyword reference
1038pub fn print_keyword_help() {
1039    println!("KEYWORD REFERENCE");
1040    println!("═══════════════════════════════════════════════════════════════════════");
1041    println!();
1042
1043    // Group keywords by category
1044    let mut categories: HashMap<KeywordCategory, Vec<&Keyword>> = HashMap::new();
1045    for keyword in KEYWORDS {
1046        categories
1047            .entry(keyword.category)
1048            .or_default()
1049            .push(keyword);
1050    }
1051
1052    // Print each category
1053    for (category, keywords) in categories {
1054        print_category_header(category);
1055        println!();
1056
1057        for keyword in keywords {
1058            print_keyword(keyword);
1059            println!();
1060        }
1061        println!();
1062    }
1063}
1064
1065/// Print method reference
1066pub fn print_method_help() {
1067    println!("METHOD REFERENCE");
1068    println!("═══════════════════════════════════════════════════════════════════════");
1069    println!();
1070    println!("OpenMECP supports all quantum chemistry methods available in the");
1071    println!("underlying QM program (Gaussian, ORCA, xTB, BAGEL). The methods listed");
1072    println!("below are typical examples — any functional, basis set, and method");
1073    println!("combination supported by your QM program can be used.");
1074    println!();
1075
1076    let methods = get_methods();
1077
1078    // Group methods by category
1079    let mut categories: HashMap<&str, Vec<&MethodInfo>> = HashMap::new();
1080    for method in methods {
1081        categories.entry(method.category).or_default().push(method);
1082    }
1083
1084    for (category, methods) in categories {
1085        println!("{}", category.to_uppercase());
1086        println!("{}", "─".repeat(76));
1087        println!();
1088
1089        for method in methods {
1090            println!("{}", method.name);
1091            println!("    {}", method.description);
1092            println!("    Programs: {}", method.programs.join(", "));
1093            if let Some(example) = method.example {
1094                println!("    Example:  {}", example);
1095            }
1096            println!();
1097        }
1098        println!();
1099    }
1100
1101    println!("SUPPORTED PROGRAMS");
1102    println!("{}", "─".repeat(76));
1103    println!();
1104
1105    for program in get_programs() {
1106        println!("{}", program.name);
1107        println!("    {}", program.description);
1108        println!("    Executable: {}", program.executable);
1109        println!("    Features:");
1110        for feature in program.features {
1111            println!("      • {}", feature);
1112        }
1113        println!();
1114    }
1115}
1116
1117/// Print feature reference
1118pub fn print_feature_help() {
1119    println!("FEATURE REFERENCE");
1120    println!("═══════════════════════════════════════════════════════════════════════");
1121    println!();
1122
1123    for feature in FEATURES {
1124        println!("{}", feature.name);
1125        println!("    {}", feature.description);
1126        println!("    Usage: {}", feature.usage);
1127        if let Some(example) = feature.example {
1128            println!("    Example: {}", example);
1129        }
1130        println!();
1131    }
1132
1133    println!("RUN MODES");
1134    println!("{}", "─".repeat(76));
1135    println!();
1136    println!("normal");
1137    println!("    Standard MECP optimization mode. Runs single-point calculations");
1138    println!("    and optimizes geometry to find minimum energy crossing point.");
1139    println!();
1140    println!("stable");
1141    println!("    Pre-point stability analysis. Checks wavefunction stability before");
1142    println!("    optimization. Useful for avoiding convergence to saddle points.");
1143    println!();
1144    println!("read");
1145    println!("    Restart mode with wavefunction reading. Uses saved checkpoint to");
1146    println!("    continue previous optimization or start from known wavefunction.");
1147    println!();
1148    println!("noread");
1149    println!("    Fresh start without reading wavefunction. Useful when initial");
1150    println!("    guess is poor or when switching between methods.");
1151    println!();
1152    println!("inter_read");
1153    println!("    Intermediate read mode. Copies wavefunction from state B to state A");
1154    println!("    with guess=mix for better convergence in Gaussian.");
1155    println!();
1156    println!("coordinate_drive");
1157    println!("    Drives the system along a specified reaction coordinate without");
1158    println!("    full optimization. Useful for exploring reaction paths.");
1159    println!();
1160    println!("fix_de");
1161    println!("    Fix-dE optimization. Constrains the energy difference between states");
1162    println!("    to a target value while optimizing geometry.");
1163    println!();
1164
1165    println!("OPTIMIZATION ALGORITHMS");
1166    println!("{}", "─".repeat(76));
1167    println!();
1168    println!("BFGS");
1169    println!("    Broyden-Fletcher-Goldfarb-Shanno quasi-Newton method. Used for the");
1170    println!("    first 3 optimization steps when Hessian is not available.");
1171    println!();
1172    println!("GDIIS (default)");
1173    println!("    Geometry Direct Inversion of Iterative Subspace. Robust convergence");
1174    println!("    for MECP using Newton-step error vectors. Default optimizer.");
1175    println!();
1176    println!("GEDIIS");
1177    println!("    Energy-informed DIIS (Li & Frisch JCTC 2006). Uses GDIIS-compatible");
1178    println!("    error vectors (e_i = H⁻¹·(g_vec+f_vec)) with a diagonal energy coupling");
1179    println!("    B[i,i] += α·E_i² that biases interpolation toward low-gap points.");
1180    println!("    Enforces interpolation (c_i > 0) for stability. Enable: 'use_gediis = true'.");
1181    println!();
1182    println!("Sequential Hybrid");
1183    println!("    3-phase switching strategy (Li & Frisch JCTC 2006 Sec II.B):");
1184    println!("    Phase 1: GDIIS (pre-optimizer)");
1185    println!("    Phase 2: GEDIIS when RMS gradient < gediis_switch_rms (default 0.005 Ha/Å)");
1186    println!("    Phase 3: GDIIS when RMS step < gediis_switch_step (default 0.001 Å)");
1187    println!("    Enable: 'use_gediis = true' + 'use_hybrid_gediis = true'.");
1188    println!("    Configurable thresholds: gediis_switch_rms, gediis_switch_step.");
1189    println!();
1190    println!("GDIIS_blend");
1191    println!("    Gradient-weighted and trust-region blend of GDIIS/GEDIIS steps.");
1192    println!("    Four blend modes (gediis_blend_mode):");
1193    println!("    - 'fixed' (50/50): Equal weight to GDIIS and GEDIIS steps.");
1194    println!("    - 'fixed_sequential' (default): 50/50 blend far from minimum,");
1195    println!("      automatically transitions to pure GDIIS near convergence");
1196    println!("      (RMS displacement < gediis_switch_step).");
1197    println!("    - 'gradient': Smooth blend weight w = RMS_grad / (RMS_grad + gediis_switch_rms)");
1198    println!("      EDIIS-dominated when far from minimum (energy-guided navigation),");
1199    println!("      smoothly transitions to GDIIS-dominated near convergence (Newton step).");
1200    println!("    - 'sequential': Per-step switching based on RMS displacement trend.");
1201    println!("    All modes use a trust radius that contracts on energy rise and");
1202    println!("    expands on energy drop. Enable: 'use_gediis = blend'.");
1203    println!();
1204    println!("OPTIMIZER SWITCHING");
1205    println!("    Control when to switch from BFGS to DIIS with 'switch_step = N':");
1206    println!("    - switch_step = 0: Pure DIIS (no BFGS)");
1207    println!("    - switch_step = 3: Default hybrid (BFGS steps 1-3, then DIIS)");
1208    println!("    - switch_step = 10: Extended BFGS (steps 1-10, then DIIS)");
1209    println!("    - switch_step >= max_steps: Pure BFGS (no DIIS)");
1210    println!();
1211
1212    println!("CONSTRAINT TYPES");
1213    println!("{}", "─".repeat(76));
1214    println!();
1215    println!("Bond Constraints (R)");
1216    println!("    Fix distance between two atoms:");
1217    println!("    R i j value    # value in Angstrom, atoms are 1-based");
1218    println!();
1219    println!("Angle Constraints (A)");
1220    println!("    Fix angle formed by three atoms:");
1221    println!("    A i j k value  # value in degrees, atoms are 1-based");
1222    println!();
1223    println!("Fixed Atoms");
1224    println!("    Freeze specific atoms during optimization:");
1225    println!("    fixedatoms = \"1,2,3\"");
1226    println!("    fixedatoms = \"1-5,10-15\"  # Can use ranges");
1227    println!();
1228    println!("PES Scans");
1229    println!("    Scan along 1D or 2D coordinate:");
1230    println!("    S R i j start num_points step_size");
1231    println!("    S A i j k start num_points step_size");
1232    println!();
1233}
1234
1235/// Print example usages
1236pub fn print_examples() {
1237    println!("USAGE EXAMPLES");
1238    println!("═══════════════════════════════════════════════════════════════════════");
1239    println!();
1240
1241    println!("BASIC USAGE");
1242    println!("{}", "─".repeat(76));
1243    println!();
1244    println!("1. Create template from XYZ file:");
1245    println!("   $ omecp ci water.xyz");
1246    println!("   → Creates water.inp with @water.xyz reference");
1247    println!();
1248    println!("2. Run MECP optimization:");
1249    println!("   $ omecp calculation.inp");
1250    println!();
1251    println!("3. View help:");
1252    println!("   $ omecp --help");
1253    println!("   $ omecp --help keywords");
1254    println!();
1255
1256    println!("INPUT FILE EXAMPLE");
1257    println!("{}", "─".repeat(76));
1258    println!();
1259    println!("# Required parameters");
1260    println!("nprocs = 30");
1261    println!("mem = 120GB");
1262    println!("method = n scf(maxcycle=500,xqc) uwb97xd/def2svpp scrf=(smd,solvent=acetonitrile)");
1263    println!("charge = 1");
1264    println!("mult_state_a = 3  # or mult_a = 3");
1265    println!("mult_state_b = 1  # or mult_b = 1");
1266    println!("mode = normal");
1267    println!();
1268    println!("# Optional convergence thresholds");
1269    println!("delta_e = 0.000050");
1270    println!("rms_dis = 0.0025");
1271    println!("max_history = 4");
1272    println!();
1273    println!("# Program settings");
1274    println!("program = gaussian");
1275    println!("gau_comm = g16");
1276    println!();
1277    println!("# Geometry section");
1278    println!("*geom");
1279    println!("@molecule.xyz  # Or inline coordinates");
1280    println!("C    0.0    0.0    0.0");
1281    println!("H    0.0    0.0    1.0");
1282    println!("*");
1283    println!();
1284    println!("# Constraints (optional)");
1285    println!("*constr");
1286    println!("R 1 2 1.0  # Fix bond distance");
1287    println!("*");
1288    println!();
1289
1290    println!("ADVANCED EXAMPLES");
1291    println!("{}", "─".repeat(76));
1292    println!();
1293    println!("1. Stability analysis mode:");
1294    println!("   mode = stable");
1295    println!();
1296    println!("2. Restart from checkpoint:");
1297    println!("   checkpoint = \"restart.chk\"");
1298    println!("   restart = true");
1299    println!();
1300    println!("3. Use custom QM program:");
1301    println!("   program = custom");
1302    println!("   custom_interface_file = \"my_qm.json\"");
1303    println!();
1304    println!("4. Coordinate driving:");
1305    println!("   mode = coordinate_drive");
1306    println!("   drive_type = \"bond\"");
1307    println!("   drive_atoms = \"1,2\"");
1308    println!("   drive_start = 1.0");
1309    println!("   drive_end = 2.0");
1310    println!("   drive_steps = 10");
1311    println!();
1312    println!("5. PES scan:");
1313    println!("   # Add to *constr section:");
1314    println!("   S R 1 2 1.0 10 0.1");
1315    println!();
1316    println!("6. Fix energy difference:");
1317    println!("   mode = fix_de");
1318    println!("   fix_de = 2.5  # Target ΔE in eV");
1319    println!();
1320
1321    println!("TROUBLESHOOTING");
1322    println!("{}", "─".repeat(76));
1323    println!();
1324    println!("• Convergence problems:");
1325    println!("  - Increase max_steps");
1326    println!("  - Relax convergence thresholds");
1327    println!("  - Try stable mode for wavefunction check");
1328    println!("  - Use smaller max_step_size");
1329    println!();
1330    println!("• Wrong spin state:");
1331    println!("  - Check mult_state_a and mult_state_b values");
1332    println!("  - Use inter_read mode in Gaussian");
1333    println!();
1334    println!("• Large systems:");
1335    println!("  - Use xTB program for faster calculations");
1336    println!("  - Freeze non-reactive atoms with fixedatoms");
1337    println!("  - Use lower-cost methods for pre-optimization");
1338    println!();
1339}
1340
1341/// Print category header
1342fn print_category_header(category: KeywordCategory) {
1343    match category {
1344        KeywordCategory::Required => {
1345            println!("REQUIRED PARAMETERS");
1346            println!("{}", "─".repeat(76));
1347        }
1348        KeywordCategory::Optional => {
1349            println!("OPTIONAL PARAMETERS");
1350            println!("{}", "─".repeat(76));
1351        }
1352        KeywordCategory::Convergence => {
1353            println!("CONVERGENCE THRESHOLDS");
1354            println!("{}", "─".repeat(76));
1355        }
1356        KeywordCategory::Program => {
1357            println!("PROGRAM COMMANDS");
1358            println!("{}", "─".repeat(76));
1359        }
1360        KeywordCategory::TdDft => {
1361            println!("TD-DFT PARAMETERS");
1362            println!("{}", "─".repeat(76));
1363        }
1364        KeywordCategory::Constraints => {
1365            println!("CONSTRAINT PARAMETERS");
1366            println!("{}", "─".repeat(76));
1367        }
1368        KeywordCategory::Advanced => {
1369            println!("ADVANCED PARAMETERS");
1370            println!("{}", "─".repeat(76));
1371        }
1372    }
1373}
1374
1375/// Print single keyword
1376fn print_keyword(keyword: &Keyword) {
1377    let required_str = if keyword.required { " [REQUIRED]" } else { "" };
1378
1379    println!("{}{}", keyword.name, required_str);
1380    println!("    {}", keyword.description);
1381
1382    if let Some(default) = keyword.default_value {
1383        println!("    Default: {}", default);
1384    }
1385
1386    if let Some(example) = keyword.example {
1387        println!("    Example: {}", example);
1388    }
1389}