spglib 1.15.1

Rust bindings to spglib.
Documentation
//! Crystallographic information.

use std::convert::TryFrom;
use std::ffi::{CStr, CString};

use spglib_sys as ffi;

use crate::cell::Cell;
use crate::error::SpglibError;

/// Container for a structure's crystallographic properties.
#[derive(Clone, Debug)]
pub struct Dataset {
    /// The space group type number defined in International Tables for Crystallography.
    pub spacegroup_number: i32,
    /// The serial number from 1-530.
    pub hall_number: i32,
    /// The full Hermann-Mauguin notation.
    pub international_symbol: String,
    /// The hall symbol.
    pub hall_symbol: String,
    /// The information on unique axis, setting, or cell choices.
    pub choice: String,
    /// The result of space-group-type matching under a set of unique axis, setting, and cell choices.
    /// For more detail: https://spglib.github.io/spglib/definition.html#transformation-matrix-boldsymbol-p-and-origin-shift-boldsymbol-p
    pub transformation_matrix: [[f64; 3]; 3],
    /// The result of space-group-type matching under a set of unique axis, setting, and cell choices.
    /// For more detail: https://spglib.github.io/spglib/definition.html#transformation-matrix-boldsymbol-p-and-origin-shift-boldsymbol-p
    pub origin_shift: [f64; 3],
    /// The number of symmetry operations.
    pub n_operations: i32,
    /// The rotation symmetry operations.
    pub rotations: Vec<[[i32; 3]; 3]>,
    /// The translation symmetry operations.
    pub translations: Vec<[f64; 3]>,
    /// The number of atoms in the input cell.
    pub n_atoms: i32,
    /// The wyckoff letters encoded as integer numbers.
    pub wyckoffs: Vec<i32>,
    /// Site symmetry symbols for a given space group type.
    pub site_symmetry_symbols: Vec<String>,
    /// The mapping table from the atomic indices of the input cell to the atomic indices of symmetrically independent atoms.
    pub equivalent_atoms: Vec<i32>,
    /// This is almost equivalent to equivalent_atoms. But symmetry of the primitive cell is used to determine the symmetrically equivalent atoms.
    pub crystallographic_orbits: Vec<i32>,
    /// Non-standardized basis vectors of a primitive cell in the input cell.
    pub primitive_lattice: [[f64; 3]; 3],
    /// The atomic indices in the primitive cell of the input structure.
    pub mapping_to_primitive: Vec<i32>,
    /// Number of atoms in the standardized cell after idealization.
    pub n_std_atoms: i32,
    /// Lattice of the standardized cell after idealization.
    pub std_lattice: [[f64; 3]; 3],
    /// Types in the standardized cell after idealization.
    pub std_types: Vec<i32>,
    /// Positions in the standardized cell after idealization.
    pub std_positions: Vec<[f64; 3]>,
    /// Rotation matrix which rotates the cell structure from the pre idealization state to the post idealized state.
    pub std_rotation_matrix: [[f64; 3]; 3],
    /// The atomic indices in the primitive cell of the standardized crystal structure where the same number represents the same atom in the primitive cell.
    pub std_mapping_to_primitive: Vec<i32>,
    /// The symbol of the crystallographic point group in Hermann-Mauguin notation.
    pub pointgroup_symbol: String,
}

impl TryFrom<*mut ffi::SpglibDataset> for Dataset {
    type Error = SpglibError;

    fn try_from(value: *mut ffi::SpglibDataset) -> Result<Self, Self::Error> {
        // dereference the raw pointer
        let ptr = unsafe { &mut *value };
        // process fields
        let spacegroup_number = ptr.spacegroup_number as i32;
        let hall_number = ptr.hall_number as i32;
        let international_symbol =
            match CString::from(unsafe { CStr::from_ptr(ptr.international_symbol.as_ptr()) })
                .to_str()
            {
                Ok(s) => String::from(s),
                Err(_) => return Err(SpglibError::Unknown),
            };
        let hall_symbol =
            match CString::from(unsafe { CStr::from_ptr(ptr.hall_symbol.as_ptr()) }).to_str() {
                Ok(s) => String::from(s),
                Err(_) => return Err(SpglibError::Unknown),
            };
        let choice = match CString::from(unsafe { CStr::from_ptr(ptr.choice.as_ptr()) }).to_str() {
            Ok(s) => String::from(s),
            Err(_) => return Err(SpglibError::Unknown),
        };
        let transformation_matrix = ptr.transformation_matrix;
        let origin_shift = ptr.origin_shift;
        let n_operations = ptr.n_operations as i32;
        let rotations = unsafe {
            Vec::from_raw_parts(ptr.rotations, n_operations as usize, n_operations as usize)
        };
        let translations = unsafe {
            Vec::from_raw_parts(
                ptr.translations,
                n_operations as usize,
                n_operations as usize,
            )
        };
        let n_atoms = ptr.n_atoms as i32;
        let wyckoffs =
            unsafe { Vec::from_raw_parts(ptr.wyckoffs, n_atoms as usize, n_atoms as usize) };
        // TODO
        let site_symmetry_symbols = Vec::new();
        let equivalent_atoms = unsafe {
            Vec::from_raw_parts(ptr.equivalent_atoms, n_atoms as usize, n_atoms as usize)
        };
        let crystallographic_orbits = unsafe {
            Vec::from_raw_parts(
                ptr.crystallographic_orbits,
                n_atoms as usize,
                n_atoms as usize,
            )
        };
        let primitive_lattice = ptr.primitive_lattice;
        let mapping_to_primitive = unsafe {
            Vec::from_raw_parts(ptr.mapping_to_primitive, n_atoms as usize, n_atoms as usize)
        };
        let n_std_atoms = ptr.n_std_atoms as i32;
        let std_lattice = ptr.std_lattice;
        let std_types = unsafe {
            Vec::from_raw_parts(ptr.std_types, n_std_atoms as usize, n_std_atoms as usize)
        };
        let std_positions = unsafe {
            Vec::from_raw_parts(
                ptr.std_positions,
                n_std_atoms as usize,
                n_std_atoms as usize,
            )
        };
        let std_rotation_matrix = ptr.std_rotation_matrix;
        let std_mapping_to_primitive = unsafe {
            Vec::from_raw_parts(
                ptr.std_mapping_to_primitive,
                n_std_atoms as usize,
                n_std_atoms as usize,
            )
        };
        let pointgroup_symbol =
            match CString::from(unsafe { CStr::from_ptr(ptr.pointgroup_symbol.as_ptr()) }).to_str()
            {
                Ok(s) => String::from(s),
                Err(_) => return Err(SpglibError::Unknown),
            };
        Ok(Dataset {
            spacegroup_number,
            hall_number,
            international_symbol,
            hall_symbol,
            choice,
            transformation_matrix,
            origin_shift,
            n_operations,
            rotations,
            translations,
            n_atoms,
            wyckoffs,
            site_symmetry_symbols,
            equivalent_atoms,
            crystallographic_orbits,
            primitive_lattice,
            mapping_to_primitive,
            n_std_atoms,
            std_lattice,
            std_types,
            std_positions,
            std_rotation_matrix,
            std_mapping_to_primitive,
            pointgroup_symbol,
        })
    }
}

impl Dataset {
    /// Returns the dataset for a given cell.
    ///
    /// # Example
    ///
    /// Get the dataset for a BCC cell.
    ///
    /// ```
    /// use spglib::cell::Cell;
    /// use spglib::dataset::Dataset;
    ///
    /// let lattice = [[4., 0., 0.], [0., 4., 0.], [0., 0., 4.]];
    /// let positions = [[0., 0., 0.], [0.5, 0.5, 0.5]];
    /// let types = [1, 1];
    /// let mut bcc_cell = Cell::new(&lattice, &positions, &types);
    /// let dataset = Dataset::new(&mut bcc_cell, 1e-5);
    /// assert_eq!(dataset.hall_number, 529);
    /// ```
    pub fn new(cell: &mut Cell, symprec: f64) -> Dataset {
        let raw = unsafe {
            ffi::spg_get_dataset(
                cell.lattice.as_ptr() as *mut [f64; 3],
                cell.positions.as_ptr() as *mut [f64; 3],
                cell.types.as_ptr() as *const i32,
                cell.positions.len() as i32,
                symprec,
            )
        };
        Dataset::try_from(raw).unwrap()
    }
}