Skip to content

Commit

Permalink
Add more docs for rust implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
lan496 committed Aug 3, 2024
1 parent b1490bd commit e1efb7a
Show file tree
Hide file tree
Showing 14 changed files with 132 additions and 73 deletions.
12 changes: 4 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Moyo
# moyo

[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/spglib/moyo/main.svg)](https://results.pre-commit.ci/latest/github/spglib/moyo/main)
[![image](https://img.shields.io/pypi/l/moyopy.svg)](https://pypi.python.org/pypi/moyopy)
[![Moyo at crates.io](https://img.shields.io/crates/v/moyo.svg)](https://img.shields.io/crates/v/moyo)
[![moyo at crates.io](https://img.shields.io/crates/v/moyo.svg)](https://img.shields.io/crates/v/moyo)
[![image](https://img.shields.io/pypi/v/moyopy.svg)](https://pypi.python.org/pypi/moyopy)

A fast and robust crystal symmetry finder, written in Rust.
Expand All @@ -13,12 +14,6 @@ A fast and robust crystal symmetry finder, written in Rust.
<figcaption><a href="bench/mp/analysis.ipynb">Several times faster symmetry detection than Spglib for Materials Project dataset</a></figcaption>
</figure>

- Support most of the symmetry search functionality in Spglib
- Primitive cell search
- Symmetry operation search
- Space-group type identification
- Wyckoff position assignment
- Crystal structure symmetrization
- Rust support available via [crates.io](https://crates.io/crates/moyo)
- Python support available via [PyPI](https://pypi.org/project/moyopy/)

Expand All @@ -31,6 +26,7 @@ A fast and robust crystal symmetry finder, written in Rust.

### How to release

1. `cargo install cargo-release cargo-edit`
1. `cargo set-version --bump patch` for patch version increment
1. Write change log and git-commit
1. `cargo release --execute` (If you already release the package in crates.io, run `cargo release --execute --no-publish`)
Expand Down
3 changes: 3 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ test-python:
profile:
cargo flamegraph --test test_moyo_dataset --root

doc:
cargo doc --open

pre-commit:
pre-commit run --all-files

Expand Down
11 changes: 6 additions & 5 deletions moyo/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# Moyo (Rust)
# moyo (Rust)

[![Moyo at crates.io](https://img.shields.io/crates/v/moyo.svg)](https://img.shields.io/crates/v/moyo)
[![CI](https://github.com/spglib/moyo/actions/workflows/ci-rust.yaml/badge.svg)](https://github.com/spglib/moyo/actions/workflows/ci-rust.yaml)
[![moyo at crates.io](https://img.shields.io/crates/v/moyo.svg)](https://img.shields.io/crates/v/moyo)

The core implementation of Moyo in Rust
The core implementation of moyo in Rust

Crates.io: https://docs.rs/moyo/latest/moyo/
Document: https://docs.rs/moyo/latest/moyo/
- Crates.io: https://docs.rs/moyo/latest/moyo/
- Document: https://docs.rs/moyo/latest/moyo/

## Module dependency

Expand Down
11 changes: 8 additions & 3 deletions moyo/src/base/cell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,23 @@ use union_find::{QuickFindUf, UnionByRank, UnionFind};
use super::lattice::Lattice;
use super::operation::Permutation;

/// Fractional coordinates
pub type Position = Vector3<f64>;
/// Atomic number
pub type AtomicSpecie = i32;

#[derive(Debug, Clone, Serialize, Deserialize)]
/// Representing a crystal structure
pub struct Cell {
/// Lattice of the cell.
pub lattice: Lattice,
/// `positions[i]` is a fractional coordinates of the i-th site.
pub positions: Vec<Position>,
/// `numbers[i]` is an atomic number of the i-th site.
pub numbers: Vec<AtomicSpecie>,
}

impl Cell {
/// * `lattice`: Lattice of the cell.
/// * `positions`: `positions[i]` is a fractional coordinates of the i-th site.
/// * `numbers`: `numbers[i]` is a number of the i-th site.
pub fn new(lattice: Lattice, positions: Vec<Position>, numbers: Vec<AtomicSpecie>) -> Self {
if positions.len() != numbers.len() {
panic!("positions and numbers should be the same length");
Expand All @@ -32,10 +35,12 @@ impl Cell {
}
}

/// Return the number of atoms in the cell.
pub fn num_atoms(&self) -> usize {
self.positions.len()
}

/// Rotate the cell by the given rotation matrix.
pub fn rotate(&self, rotation_matrix: &Matrix3<f64>) -> Self {
Self::new(
self.lattice.rotate(rotation_matrix),
Expand Down
1 change: 1 addition & 0 deletions moyo/src/base/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use thiserror::Error;

#[derive(Error, Debug, PartialEq, Eq, Clone, Copy)]
/// Error types for the **moyo** library
pub enum MoyoError {
#[error("Minkowski reduction failed")]
MinkowskiReductionError,
Expand Down
8 changes: 8 additions & 0 deletions moyo/src/base/lattice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::math::{
use super::error::MoyoError;

#[derive(Debug, Clone, Serialize, Deserialize)]
/// Representing basis vectors of a lattice
pub struct Lattice {
/// basis.column(i) is the i-th basis vector
pub basis: Matrix3<f64>,
Expand All @@ -21,6 +22,7 @@ impl Lattice {
}
}

/// Return Minkowski reduced lattice and transformation matrix to it
pub fn minkowski_reduce(&self) -> Result<(Self, Matrix3<i32>), MoyoError> {
let (reduced_basis, trans_mat) = minkowski_reduce(&self.basis);
let reduced_lattice = Self {
Expand All @@ -39,6 +41,7 @@ impl Lattice {
is_minkowski_reduced(&self.basis)
}

/// Return Niggli reduced lattice and transformation matrix to it
pub fn niggli_reduce(&self) -> Result<(Self, Matrix3<i32>), MoyoError> {
let (reduced_basis, trans_mat) = niggli_reduce(&self.basis);
let reduced_lattice = Self {
Expand All @@ -57,6 +60,7 @@ impl Lattice {
is_niggli_reduced(&self.basis)
}

/// Return Delaunay reduced lattice and transformation matrix to it
pub fn delaunay_reduce(&self) -> Result<(Self, Matrix3<i32>), MoyoError> {
let (reduced_basis, trans_mat) = delaunay_reduce(&self.basis);
let reduced_lattice = Self {
Expand All @@ -66,18 +70,22 @@ impl Lattice {
Ok((reduced_lattice, trans_mat))
}

/// Return metric tensor of the basis vectors
pub fn metric_tensor(&self) -> Matrix3<f64> {
self.basis.transpose() * self.basis
}

/// Return cartesian coordinates from the given fractional coordinates
pub fn cartesian_coords(&self, fractional_coords: &Vector3<f64>) -> Vector3<f64> {
self.basis * fractional_coords
}

/// Return volume of the cell
pub fn volume(&self) -> f64 {
self.basis.determinant().abs()
}

/// Rotate the lattice by the given rotation matrix
pub fn rotate(&self, rotation_matrix: &Matrix3<f64>) -> Self {
Self {
basis: rotation_matrix * self.basis,
Expand Down
6 changes: 6 additions & 0 deletions moyo/src/base/operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,17 @@ use nalgebra::base::{Matrix3, Vector3};

use super::lattice::Lattice;

/// Rotation matrix in a crystallographic basis
pub type Rotation = Matrix3<i32>;
/// Translation vector in a crystallographic basis
pub type Translation = Vector3<f64>;

#[derive(Debug, Clone)]
/// Symmetry operation without basis information
pub struct Operations {
/// `rotations[i]` is a rotation part of the `i`th operation
pub rotations: Vec<Rotation>,
/// `translations[i]` is a translation part of the `i`th operation
pub translations: Vec<Translation>,
}

Expand All @@ -26,10 +30,12 @@ impl Operations {
}
}

/// Return the number of symmetry operations
pub fn num_operations(&self) -> usize {
self.rotations.len()
}

/// Return rotation matrices in cartesian coordinates with respect to the given lattice
pub fn cartesian_rotations(&self, lattice: &Lattice) -> Vec<Matrix3<f64>> {
let inv_basis = lattice.basis.try_inverse().unwrap();
self.rotations
Expand Down
1 change: 1 addition & 0 deletions moyo/src/base/transformation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::math::SNF;

pub type UnimodularLinear = Matrix3<i32>;
pub type Linear = Matrix3<i32>;
/// Origin shift in a crystallographic basis
pub type OriginShift = Vector3<f64>;

/// Represent change of origin and basis for an affine space
Expand Down
26 changes: 13 additions & 13 deletions moyo/src/data/hall_symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ use crate::base::{Linear, Operations, Rotation, Transformation, Translation, EPS

const MAX_DENOMINATOR: i32 = 12;

/// Hall symbol. See A1.4.2.3 in ITB (2010).
///
/// Extended Backus-Naur form (EBNF) for Hall symbols
/// ----------------------------------------------------------
/// <Hall symbol> := <L> <N>+ <V>?
/// <L> := "-"? <lattice symbol>
/// <lattice symbol> := [PABCIRHF] # Table A1.4.2.2
/// <N> := <nfold> <A>? <T>?
/// <nfold> := "-"? ("1" | "2" | "3" | "4" | "6")
/// <A> := [xyz] | "'" | '"' | "=" | "*" # Table A.1.4.2.4, Table A.1.4.2.5, Table A.1.4.2.6
/// <T> := [abcnuvwd] | [1-6] # Table A.1.4.2.3
/// <V> := "(" [0-11] [0-11] [0-11] ")"
// Hall symbol. See A1.4.2.3 in ITB (2010).
//
// Extended Backus-Naur form (EBNF) for Hall symbols
// ----------------------------------------------------------
// <Hall symbol> := <L> <N>+ <V>?
// <L> := "-"? <lattice symbol>
// <lattice symbol> := [PABCIRHF] # Table A1.4.2.2
// <N> := <nfold> <A>? <T>?
// <nfold> := "-"? ("1" | "2" | "3" | "4" | "6")
// <A> := [xyz] | "'" | '"' | "=" | "*" # Table A.1.4.2.4, Table A.1.4.2.5, Table A.1.4.2.6
// <T> := [abcnuvwd] | [1-6] # Table A.1.4.2.3
// <V> := "(" [0-11] [0-11] [0-11] ")"
#[derive(Debug)]
pub struct HallSymbol {
pub hall_symbol: String,
Expand Down Expand Up @@ -54,8 +54,8 @@ impl Centering {
}
}

/// Inverse matrices of https://github.com/spglib/spglib/blob/39a95560dd831c2d16f162126921ac1e519efa31/src/spacegroup.c#L373-L384
/// Transformation matrix from primitive to conventional cell.
// Inverse matrices of https://github.com/spglib/spglib/blob/39a95560dd831c2d16f162126921ac1e519efa31/src/spacegroup.c#L373-L384
pub fn linear(&self) -> Linear {
match self {
Centering::P => Linear::identity(),
Expand Down
1 change: 1 addition & 0 deletions moyo/src/data/setting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use super::hall_symbol_database::HallNumber;
#[derive(Debug, Copy, Clone, PartialEq)]
/// Preference for the setting of the space group.
pub enum Setting {
/// Specific Hall number from 1 to 530
HallNumber(HallNumber),
/// The setting of the smallest Hall number
Spglib,
Expand Down
17 changes: 8 additions & 9 deletions moyo/src/data/wyckoff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ pub struct WyckoffPositionSpace {
}

impl WyckoffPositionSpace {
/// Parse short-hand notation
/// EBNF for Wyckoff coordinates is as follows (we always ignore space):
/// <shorthand> ::= <term>, <term>, <term>
/// <term> ::= "-"?<factor> ([+-]<factor>)* ([+-]<translation>)?
/// <factor> ::= <integer>? <variable>
/// <variable> ::= "x" || "y" || "z"
/// <translation> ::= <integer> ("/" <integer>)?
/// <integer> ::= ("0" || "1" || "2" || "3" || "4" || "5" || "6" || "7" || "8" || "9")+
// Parse short-hand notation
// EBNF for Wyckoff coordinates is as follows (we always ignore space):
// <shorthand> ::= <term>, <term>, <term>
// <term> ::= "-"?<factor> ([+-]<factor>)* ([+-]<translation>)?
// <factor> ::= <integer>? <variable>
// <variable> ::= "x" || "y" || "z"
// <translation> ::= <integer> ("/" <integer>)?
// <integer> ::= ("0" || "1" || "2" || "3" || "4" || "5" || "6" || "7" || "8" || "9")+
pub fn new(coordinates: &str) -> Self {
let coordinates = coordinates.replace(' ', "");
let terms = coordinates.split(',').collect::<Vec<_>>();
Expand Down
93 changes: 65 additions & 28 deletions moyo/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,62 @@
/*!
# moyo
**moyo** is a fast and robust crystal symmetry finder.
## Using **moyo**
Simply add the following to your `Cargo.toml` file:
```ignore
[dependencies]
// TODO: replace the * with the latest version
moyo = "*"
```
## Examples
The basic usage of **moyo** is to create a [`moyo::Cell`](Cell) representing a crystal structure, and then create a [`moyo::MoyoDataset`](MoyoDataset) from the [`moyo::Cell`](Cell).
The [`moyo::MoyoDataset`](MoyoDataset) contains symmetry information of the input crystal structure: for example, the space group number, symmetry operations, and standardized cell.
```
use nalgebra::{matrix, vector, Matrix3, Vector3};
use moyo::{MoyoDataset, Cell, AngleTolerance, Setting, Lattice};
let lattice = Lattice::new(matrix![
4.603, 0.0, 0.0;
0.0, 4.603, 0.0;
0.0, 0.0, 2.969;
]);
let x_4f = 0.3046;
let positions = vec![
Vector3::new(0.0, 0.0, 0.0), // Ti(2a)
Vector3::new(0.5, 0.5, 0.5), // Ti(2a)
Vector3::new(x_4f, x_4f, 0.0), // O(4f)
Vector3::new(-x_4f, -x_4f, 0.0), // O(4f)
Vector3::new(-x_4f + 0.5, x_4f + 0.5, 0.5), // O(4f)
Vector3::new(x_4f + 0.5, -x_4f + 0.5, 0.5), // O(4f)
];
let numbers = vec![0, 0, 1, 1, 1, 1];
let cell = Cell::new(lattice, positions, numbers);
let symprec = 1e-5;
let angle_tolerance = AngleTolerance::Default;
let setting = Setting::Standard;
let dataset = MoyoDataset::new(&cell, symprec, angle_tolerance, setting).unwrap();
assert_eq!(dataset.number, 136); // P4_2/mnm
```
## Features
- Support most of the symmetry search functionality in Spglib
- Primitive cell search
- Symmetry operation search
- Space-group type identification
- Wyckoff position assignment
- Crystal structure symmetrization
*/
#[allow(unused_imports)]
#[macro_use]
extern crate approx;
Expand All @@ -22,6 +81,7 @@ use crate::search::{PrimitiveCell, PrimitiveSymmetrySearch};
use crate::symmetrize::{orbits_in_cell, StandardizedCell};

#[derive(Debug)]
/// A dataset containing symmetry information of the input crystal structure.
pub struct MoyoDataset {
// ------------------------------------------------------------------------
// Space-group type
Expand Down Expand Up @@ -80,34 +140,10 @@ pub struct MoyoDataset {
}

impl MoyoDataset {
/// Create a new `MoyoDataset` from the input cell.
///
/// # Examples
/// ```
/// use nalgebra::{matrix, vector, Matrix3, Vector3};
/// use moyo::{MoyoDataset, Cell, AngleTolerance, Setting, Lattice};
/// let lattice = Lattice::new(matrix![
/// 4.603, 0.0, 0.0;
/// 0.0, 4.603, 0.0;
/// 0.0, 0.0, 2.969;
/// ]);
/// let x_4f = 0.3046;
/// let positions = vec![
/// Vector3::new(0.0, 0.0, 0.0), // Ti(2a)
/// Vector3::new(0.5, 0.5, 0.5), // Ti(2a)
/// Vector3::new(x_4f, x_4f, 0.0), // O(4f)
/// Vector3::new(-x_4f, -x_4f, 0.0), // O(4f)
/// Vector3::new(-x_4f + 0.5, x_4f + 0.5, 0.5), // O(4f)
/// Vector3::new(x_4f + 0.5, -x_4f + 0.5, 0.5), // O(4f)
/// ];
/// let numbers = vec![0, 0, 1, 1, 1, 1];
/// let cell = Cell::new(lattice, positions, numbers);
/// let symprec = 1e-5;
/// let angle_tolerance = AngleTolerance::Default;
/// let setting = Setting::Standard;
/// let dataset = MoyoDataset::new(&cell, symprec, angle_tolerance, setting).unwrap();
/// assert_eq!(dataset.number, 136); // P4_2/mnm
/// ```
/// Create a new [`MoyoDataset`] from the input cell, `cell`.
/// `symprec` and `angle_tolerance` control the tolerances for searching symmetry operations.
/// `setting` determines the preference for the "standardized" setting of a detected space-group type.
/// If the search fails, [`MoyoError`] is returned.
pub fn new(
cell: &Cell,
symprec: f64,
Expand Down Expand Up @@ -186,6 +222,7 @@ impl MoyoDataset {
})
}

/// Return the number of symmetry operations in the input cell.
pub fn num_operations(&self) -> usize {
self.operations.num_operations()
}
Expand Down
Loading

0 comments on commit e1efb7a

Please sign in to comment.