1use std::io::{self, Write};
5
6use readcon_core::types::ConFrame;
7
8pub fn write_frame_extxyz<W: Write>(
10 w: &mut W,
11 frame: &ConFrame,
12 energy_key: &str,
13) -> io::Result<()> {
14 let n = frame.atom_data.len();
15 writeln!(w, "{n}")?;
16
17 let e = crate::export_h5md::edges33_from_header(&frame.header);
18 let lattice = format!(
19 "{:.10} {:.10} {:.10} {:.10} {:.10} {:.10} {:.10} {:.10} {:.10}",
20 e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], e[8]
21 );
22
23 let mut energy = None;
24 if let Some(v) = frame.header.metadata.get("energy") {
25 if let Some(f) = v.as_f64() {
26 energy = Some(f);
27 } else if let Some(s) = v.as_str() {
28 energy = s.parse().ok();
29 }
30 }
31
32 let has_forces = frame.atom_data.iter().any(|a| a.force.is_some());
33 let props = if has_forces {
34 "species:S:1:pos:R:3:forces:R:3"
35 } else {
36 "species:S:1:pos:R:3"
37 };
38
39 let pbc = frame.header.pbc().unwrap_or([true, true, true]);
40 let tf = |b: bool| if b { "T" } else { "F" };
41 write!(
42 w,
43 "Lattice=\"{lattice}\" Properties={props} pbc=\"{} {} {}\"",
44 tf(pbc[0]),
45 tf(pbc[1]),
46 tf(pbc[2])
47 )?;
48 if let Some(e) = energy {
49 write!(w, " {energy_key}={e:.10}")?;
50 }
51 writeln!(w)?;
52
53 for a in &frame.atom_data {
54 write!(
55 w,
56 "{:<2} {:16.10} {:16.10} {:16.10}",
57 a.symbol, a.x, a.y, a.z
58 )?;
59 if has_forces {
60 let f = a.force.unwrap_or([0.0; 3]);
61 write!(w, " {:16.10} {:16.10} {:16.10}", f[0], f[1], f[2])?;
62 }
63 writeln!(w)?;
64 }
65 Ok(())
66}
67
68pub fn write_frames_extxyz<W: Write>(
69 w: &mut W,
70 frames: &[ConFrame],
71 energy_key: &str,
72) -> io::Result<()> {
73 for fr in frames {
74 write_frame_extxyz(w, fr, energy_key)?;
75 }
76 Ok(())
77}