1use indexmap::{indexmap, IndexMap};
5use serde_json::json;
6
7use gchemol_core::{Atom, Molecule};
8use gut::prelude::*;
9mod hbs;
13mod jinja;
14mod tera;
15#[derive(Debug, Serialize)]
19struct AtomData {
20 index: usize,
21 element_index: usize,
22 symbol: String,
23 number: usize,
24 freezing: [bool; 3],
25 x: f64,
26 y: f64,
27 z: f64,
28 fx: f64,
29 fy: f64,
30 fz: f64,
31 vx: f64,
32 vy: f64,
33 vz: f64,
34}
35
36impl Default for AtomData {
37 fn default() -> Self {
38 AtomData {
39 index: 0,
40 element_index: 0,
41 symbol: "C".into(),
42 number: 6,
43 freezing: [false; 3],
44 x: 0.0,
45 y: 0.0,
46 z: 0.0,
47 fx: 0.0,
48 fy: 0.0,
49 fz: 0.0,
50 vx: 0.0,
51 vy: 0.0,
52 vz: 0.0,
53 }
54 }
55}
56
57#[derive(Debug, Serialize)]
58struct BondData {
59 i: usize,
60 j: usize,
61 order: f64,
62}
63
64#[derive(Debug, Serialize)]
65struct UnitCell {
66 a: f64,
67 b: f64,
68 c: f64,
69 alpha: f64,
70 beta: f64,
71 gamma: f64,
72 va: [f64; 3],
73 vb: [f64; 3],
74 vc: [f64; 3],
75}
76
77#[derive(Debug, Serialize)]
78struct SpeciesData {
79 index: usize,
80 element_symbol: String,
81 element_number: usize,
82 number_of_atoms: usize,
83}
84
85#[derive(Debug, Serialize)]
86struct MoleculeData {
87 title: String,
88 unit_cell: Option<UnitCell>,
89 number_of_atoms: usize,
90 number_of_bonds: usize,
91 number_of_species: usize,
92 atoms: Vec<AtomData>,
93 bonds: Vec<BondData>,
94
95 element_types: Vec<(String, usize)>,
99 species: Vec<SpeciesData>,
100}
101
102pub(self) fn renderable(mol: &Molecule) -> serde_json::Value {
104 let unit_cell = if let Some(lat) = mol.lattice {
106 let [va, vb, vc] = lat.vectors();
107 let [a, b, c] = lat.lengths();
108 let [alpha, beta, gamma] = lat.angles();
109
110 let cell = UnitCell {
111 a,
112 b,
113 c,
114 alpha,
115 beta,
116 gamma,
117 va: va.into(),
118 vb: vb.into(),
119 vc: vc.into(),
120 };
121
122 Some(cell)
123 } else {
124 None
125 };
126
127 let mut element_types: IndexMap<String, usize> = indexmap! {};
128 for (_, a) in mol.atoms() {
129 let k = a.symbol().into();
130 let c = element_types.entry(k).or_insert(0);
131 *c += 1;
132 }
133
134 let mut atoms = vec![];
136 for (i, a) in mol.atoms() {
137 let [x, y, z] = a.position();
138 let index = i;
139 let number = a.number();
140 let symbol = a.symbol().to_string();
141 let [fx, fy, fz] = mol.lattice.map(|lat| lat.to_frac([x, y, z]).into()).unwrap_or([0.0; 3]);
142
143 let element_index = {
144 let (x, _, _) = element_types.get_full(a.symbol()).expect("element type index");
145 x + 1
146 };
147
148 let [vx, vy, vz] = a.velocity();
149 let freezing = a.freezing();
150 atoms.push(AtomData {
151 index,
152 element_index,
153 symbol,
154 number,
155 freezing,
156 x,
157 y,
158 z,
159 fx,
160 fy,
161 fz,
162 vx,
163 vy,
164 vz,
165 })
166 }
167
168 let element_types: Vec<(_, _)> = element_types.into_iter().collect();
170
171 let n = element_types.len();
172 let species: Vec<_> = element_types
173 .iter()
174 .enumerate()
175 .map(|(i, (s, n))| SpeciesData {
176 index: i + 1,
177 element_symbol: s.clone(),
178 element_number: Atom::new(s.as_str(), [0.0; 3]).number(),
180 number_of_atoms: *n,
181 })
182 .collect();
183
184 let bonds = vec![];
185 let md = MoleculeData {
186 title: mol.title(),
187 number_of_atoms: mol.natoms(),
188 number_of_bonds: mol.nbonds(),
189 number_of_species: n,
190 unit_cell,
191 atoms,
192 bonds,
193 element_types,
194 species,
195 };
196
197 json!({
198 "molecule": md,
199 })
200}
201pub trait TemplateRendering {
206 fn render_with(&self, f: &std::path::Path) -> Result<String>;
208}
209
210impl TemplateRendering for Molecule {
211 fn render_with(&self, path: &std::path::Path) -> Result<String> {
212 let template = gut::fs::read_file(path)?;
213
214 match path.extension().and_then(|x| x.to_str()) {
216 Some("hbs") => self::hbs::render_molecule_with(&self, &template),
217 Some("tera") => self::tera::render_molecule_with(&self, &template),
218 _ => self::jinja::render_molecule_with(&self, &template),
219 }
220 }
221}
222pub fn to_json(mol: &Molecule) -> Result<String> {
227 let data = renderable(mol);
228 let serialized = serde_json::to_string_pretty(&data)?;
229 Ok(serialized)
230}
231
232pub fn to_json_value(mol: &Molecule) -> serde_json::Value {
234 renderable(mol)
235}
236pub use self::jinja::Template;
240