1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//! Representation of a bounded atomic structure.

use std::os::raw::c_int;

use spglib_sys as ffi;

use crate::error::SpglibError;

/// Atomic structure with lattice bounds.
#[derive(Clone, Debug)]
pub struct Cell {
    /// Lattice vectors.
    pub lattice: [[f64; 3]; 3],
    /// Position of each atom.
    pub positions: Vec<[f64; 3]>,
    /// Type of each atom.
    pub types: Vec<i32>,
}

impl Cell {
    /// Returns a new cell.
    pub fn new(lattice: &[[f64; 3]; 3], positions: &[[f64; 3]], types: &[i32]) -> Cell {
        let lattice = *lattice;
        let positions = Vec::from(positions);
        let types = Vec::from(types);
        Cell {
            lattice,
            positions,
            types,
        }
    }

    /// Standardizes the cell with a symmetry search.
    /// Refer to the full documentation of the implementation [here](https://spglib.github.io/spglib/api.html#spg-standardize-cell).
    ///
    /// # Example
    ///
    /// Standardize a BCC cell.
    ///
    /// ```
    /// use spglib::cell::Cell;
    ///
    /// let lattice = [
    ///     [4.0, 0.0, 0.0],
    ///     [0.0, 4.0, 0.0],
    ///     [0.0, 0.0, 4.0]
    /// ];
    /// let positions = [
    ///     [0.0, 0.0, 0.0],
    ///     [0.5, 0.5, 0.5]
    /// ];
    /// let types = [1, 1];
    /// let mut cell = Cell::new(&lattice, &positions, &types);
    /// cell.standardize(true, false, 1.0e-6).unwrap();
    /// assert_eq!(
    ///     cell.lattice,
    ///     [
    ///         [-2.0, 2.0, 2.0],
    ///         [2.0, -2.0, 2.0],
    ///         [2.0, 2.0, -2.0]
    ///     ]
    /// );
    /// ```
    pub fn standardize(
        &mut self,
        to_primitive: bool,
        no_idealize: bool,
        symprec: f64,
    ) -> Result<(), SpglibError> {
        let to_primitive = if to_primitive { 1 } else { 0 };
        let no_idealize = if no_idealize { 1 } else { 0 };
        let res = unsafe {
            ffi::spg_standardize_cell(
                self.lattice.as_ptr() as *mut [f64; 3],
                self.positions.as_ptr() as *mut [f64; 3],
                self.types.as_ptr() as *mut c_int,
                self.positions.len() as c_int,
                to_primitive,
                no_idealize,
                symprec,
            )
        };
        if res == 0 {
            return Err(SpglibError::CellStandardizationFailed);
        }
        Ok(())
    }

    /// Applies a Delaunay reduction to the cell.
    /// Refer to the full documentation of the implementation [here](https://spglib.github.io/spglib/api.html#spg-delaunay-reduce).
    pub fn delaunay_reduce(&mut self, eps: f64) -> Result<(), SpglibError> {
        let res = unsafe { ffi::spg_delaunay_reduce(self.lattice.as_ptr() as *mut [f64; 3], eps) };
        if res == 0 {
            return Err(SpglibError::DelaunayFailed);
        }
        Ok(())
    }

    /// Applies a Niggli reduction to the cell.
    /// Refer to the full documentation of the implementation [here](https://spglib.github.io/spglib/api.html#spg-niggli-reduce).
    pub fn niggli_reduce(&mut self, eps: f64) -> Result<(), SpglibError> {
        let res = unsafe { ffi::spg_niggli_reduce(self.lattice.as_ptr() as *mut [f64; 3], eps) };
        if res == 0 {
            return Err(SpglibError::NiggliFailed);
        }
        Ok(())
    }

    /// This method is not yet implemented.
    pub fn ir_reciprocal_mesh(
        &self,
        mesh: (i32, i32, i32),
        shift: (bool, bool, bool),
    ) -> Result<(), SpglibError> {
        unimplemented!()
    }
}