pub fn kgd_get_all_grid_addresses(grid_address: &mut [[i32; 3]], mesh: &[i32; 3]) {
let total_size = mesh[0] as usize * mesh[1] as usize * mesh[2] as usize;
assert!(
grid_address.len() >= total_size,
"grid_address buffer is too small"
);
let mut address = [0; 3];
for i in 0..mesh[0] {
address[0] = i;
for j in 0..mesh[1] {
address[1] = j;
for k in 0..mesh[2] {
address[2] = k;
let grid_point = get_grid_point_single_mesh(&address, mesh);
grid_address[grid_point] = address;
reduce_grid_address(&mut grid_address[grid_point], mesh);
}
}
}
}
pub fn kgd_get_grid_point_double_mesh(address_double: &[i32; 3], mesh: &[i32; 3]) -> usize {
get_grid_point_double_mesh(address_double, mesh)
}
pub fn kgd_get_dense_grid_point_double_mesh(address_double: &[i32; 3], mesh: &[i32; 3]) -> usize {
get_grid_point_double_mesh(address_double, mesh)
}
pub fn kgd_get_grid_address_double_mesh(
address_double: &mut [i32; 3],
address: &[i32; 3],
mesh: &[i32; 3],
is_shift: &[i32; 3],
) {
for i in 0..3 {
address_double[i] = address[i] * 2 + if is_shift[i] != 0 { 1 } else { 0 };
}
reduce_grid_address_double(address_double, mesh);
}
#[inline]
fn get_grid_point_double_mesh(address_double: &[i32; 3], mesh: &[i32; 3]) -> usize {
let mut address = [0; 3];
for i in 0..3 {
if address_double[i] % 2 == 0 {
address[i] = address_double[i] / 2;
} else {
address[i] = (address_double[i] - 1) / 2;
}
}
modulo_i3(&mut address, mesh);
get_grid_point_single_mesh(&address, mesh)
}
#[inline]
fn get_grid_point_single_mesh(address: &[i32; 3], mesh: &[i32; 3]) -> usize {
(address[2] as usize * mesh[0] as usize * mesh[1] as usize)
+ (address[1] as usize * mesh[0] as usize)
+ (address[0] as usize)
}
#[inline]
fn modulo_i3(v: &mut [i32; 3], m: &[i32; 3]) {
for i in 0..3 {
v[i] = v[i] % m[i];
if v[i] < 0 {
v[i] += m[i];
}
}
}
#[inline]
fn reduce_grid_address(address: &mut [i32; 3], mesh: &[i32; 3]) {
for i in 0..3 {
if address[i] > mesh[i] / 2 {
address[i] -= mesh[i];
}
}
}
#[inline]
fn reduce_grid_address_double(address: &mut [i32; 3], mesh: &[i32; 3]) {
for i in 0..3 {
if address[i] > mesh[i] {
address[i] -= 2 * mesh[i];
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_all_grid_addresses() {
let mesh = [2, 2, 1];
let mut addresses = vec![[0; 3]; 4];
kgd_get_all_grid_addresses(&mut addresses, &mesh);
assert_eq!(addresses[0], [0, 0, 0]);
assert_eq!(addresses[1], [1, 0, 0]);
assert_eq!(addresses[2], [0, 1, 0]); assert_eq!(addresses[3], [1, 1, 0]);
}
#[test]
fn test_reduce_grid_address() {
let mesh = [4, 4, 4];
let mut addr = [0, 2, 3];
reduce_grid_address(&mut addr, &mesh);
assert_eq!(addr, [0, 2, -1]);
}
#[test]
fn test_grid_point_single() {
let mesh = [4, 4, 4];
let addr = [1, 0, 0];
assert_eq!(get_grid_point_single_mesh(&addr, &mesh), 1);
let addr2 = [0, 1, 0];
assert_eq!(get_grid_point_single_mesh(&addr2, &mesh), 4);
}
#[test]
fn test_modulo() {
let mesh = [4, 4, 4];
let mut v = [-1, 5, 0];
modulo_i3(&mut v, &mesh);
assert_eq!(v, [3, 1, 0]);
}
#[test]
fn test_double_mesh_logic() {
let mesh = [4, 4, 4];
let addr_d = [0, 4, 8];
assert_eq!(get_grid_point_double_mesh(&addr_d, &mesh), get_grid_point_single_mesh(&[0, 2, 0], &mesh));
let addr_d_odd = [1, 5, 9];
assert_eq!(get_grid_point_double_mesh(&addr_d_odd, &mesh), get_grid_point_single_mesh(&[0, 2, 0], &mesh));
}
}