vegas_lattice/
site.rs

1use crate::util::Tagged;
2use serde::{Deserialize, Serialize};
3use serde_json::Error as SerdeError;
4use std::str::FromStr;
5
6/// Represetns a site in a lattice.
7///
8/// The `kind` field is the type of the site, for example `Fe` for iron or `Cu` for copper.
9/// The `position` field is a tuple of the x, y, and z coordinates of the site within the
10/// lattice.
11///
12/// # Exalples
13///
14/// Here is an example of how to create a site and access its fields:
15///
16/// ```rust
17/// use vegas_lattice::Site;
18///
19/// let site = Site::new("Fe");
20///
21/// assert_eq!(site.kind(), "Fe");
22/// assert_eq!(site.position(), (0.0, 0.0, 0.0));
23/// ```
24#[derive(Clone, Debug, Serialize, Deserialize)]
25pub struct Site {
26    kind: String,
27    position: (f64, f64, f64),
28    tags: Option<Vec<String>>,
29}
30
31impl FromStr for Site {
32    type Err = SerdeError;
33    fn from_str(source: &str) -> Result<Site, Self::Err> {
34        serde_json::from_str(source)
35    }
36}
37
38impl Tagged for Site {
39    fn tags(&self) -> Option<Vec<&str>> {
40        self.tags
41            .as_ref()
42            .map(|tags| tags.iter().map(|tag| tag.as_ref()).collect())
43    }
44}
45
46impl Site {
47    /// Create a new site with a given kind located at the origin
48    pub fn new(kind: &str) -> Self {
49        Site {
50            kind: kind.to_string(),
51            position: (0.0, 0.0, 0.0),
52            tags: None,
53        }
54    }
55
56    /// Return the position of the site
57    pub fn position(&self) -> (f64, f64, f64) {
58        self.position
59    }
60
61    /// Return the kind of the site
62    pub fn kind(&self) -> &str {
63        &self.kind
64    }
65
66    /// Move along the x axis
67    pub fn move_x(mut self, distance: f64) -> Self {
68        self.position.0 += distance;
69        self
70    }
71
72    /// Move along the y axis
73    pub fn move_y(mut self, distance: f64) -> Self {
74        self.position.1 += distance;
75        self
76    }
77
78    /// Move along the z axis
79    pub fn move_z(mut self, distance: f64) -> Self {
80        self.position.2 += distance;
81        self
82    }
83
84    /// Changes the kind of the site
85    pub fn with_kind(mut self, kind: &str) -> Self {
86        self.kind = kind.to_string();
87        self
88    }
89
90    /// Changes the position of the site
91    pub fn with_position(mut self, position: (f64, f64, f64)) -> Self {
92        self.position = position;
93        self
94    }
95
96    /// Adds tags to the site
97    pub fn with_tags(mut self, tags: Vec<&str>) -> Self {
98        self.tags = Some(tags.iter().map(|s| s.to_string()).collect());
99        self
100    }
101}
102
103#[cfg(test)]
104mod test {
105    use super::Site;
106    use std::str::FromStr;
107
108    #[test]
109    fn site_can_be_created() {
110        let site = Site::new("Fe");
111        assert_eq!(site.kind, "Fe");
112        assert_eq!(site.position, (0.0, 0.0, 0.0));
113    }
114
115    #[test]
116    fn site_can_be_moved() {
117        let site = Site::new("Fe").move_x(1.0);
118        assert_eq!(site.position, (1.0, 0.0, 0.0));
119    }
120
121    #[test]
122    fn site_can_be_changed() {
123        let site = Site::new("Fe").with_kind("Cu");
124        assert_eq!(site.kind, "Cu");
125    }
126
127    #[test]
128    fn site_can_be_positioned() {
129        let site = Site::new("Fe").with_position((1.0, 1.0, 1.0));
130        assert_eq!(site.position, (1.0, 1.0, 1.0));
131    }
132
133    #[test]
134    fn site_can_be_tagged() {
135        let site = Site::new("Fe").with_tags(vec!["core", "inner"]);
136        assert_eq!(
137            site.tags,
138            Some(vec!["core".to_string(), "inner".to_string()])
139        );
140    }
141
142    #[test]
143    fn site_can_be_read_from_string() {
144        let data = r#"
145            {"kind": "Fe", "position": [0, 0, 0]}
146        "#;
147        let site_result = Site::from_str(data);
148        assert!(site_result.is_ok());
149    }
150
151    #[test]
152    fn site_will_take_optional_tags() {
153        let data = r#"
154            {"kind": "Fe", "position": [0, 0, 0], "tags": ["core", "inner"]}
155        "#;
156        let site_result: Result<Site, _> = data.parse();
157        assert!(site_result.is_ok());
158        assert_eq!(
159            site_result.unwrap().tags,
160            Some(vec!["core".to_string(), "inner".to_string()])
161        );
162    }
163}