use super::Device;
use crate::error::{numerical_error, Result};
const CUDA_NOT_IMPLEMENTED: &str =
"CUDA backend: not implemented in v0.9.0 (skeleton only — see gpu::cuda)";
#[derive(Debug, Clone, Copy)]
pub struct CudaDevice {
pub device_id: usize,
available: bool,
}
impl CudaDevice {
pub fn new() -> Result<Self> {
Ok(Self {
device_id: 0,
available: false,
})
}
pub fn with_device_id(device_id: usize) -> Result<Self> {
Ok(Self {
device_id,
available: false,
})
}
pub fn device_name(&self) -> &'static str {
"CUDA stub (v0.9.0)"
}
}
impl Device for CudaDevice {
fn name(&self) -> &'static str {
"cuda"
}
fn is_available(&self) -> bool {
self.available
}
fn step_llg_rk4(
&self,
_spins: &mut [[f64; 3]],
_h_eff: &[[f64; 3]],
_alpha: f64,
_dt: f64,
) -> Result<()> {
Err(numerical_error(CUDA_NOT_IMPLEMENTED))
}
fn step_llg_rk4_multi(
&self,
_spins: &mut [[f64; 3]],
_h_eff: &[[f64; 3]],
_alpha: f64,
_dt: f64,
_n_steps: usize,
) -> Result<()> {
Err(numerical_error(CUDA_NOT_IMPLEMENTED))
}
fn zeeman_energy(&self, _spins: &[[f64; 3]], _h: &[[f64; 3]], _ms: f64) -> Result<f64> {
Err(numerical_error(CUDA_NOT_IMPLEMENTED))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::Error;
#[test]
fn test_cuda_device_construct_returns_ok_unavailable() {
let dev = CudaDevice::new().expect("CUDA stub construction must succeed");
assert_eq!(dev.device_id, 0);
assert!(!dev.available);
assert!(!dev.is_available());
}
#[test]
fn test_cuda_device_with_device_id_succeeds() {
let dev = CudaDevice::with_device_id(0).expect("with_device_id(0) must succeed");
assert_eq!(dev.device_id, 0);
assert!(!dev.is_available());
let dev2 = CudaDevice::with_device_id(3).expect("with_device_id(3) must succeed");
assert_eq!(dev2.device_id, 3);
assert!(!dev2.is_available());
assert_eq!(dev2.device_name(), "CUDA stub (v0.9.0)");
}
#[test]
fn test_cuda_device_name_is_cuda() {
let dev = CudaDevice::new().unwrap();
assert_eq!(dev.name(), "cuda");
}
#[test]
fn test_cuda_is_available_false_in_v09() {
let dev = CudaDevice::new().unwrap();
assert!(!dev.is_available());
}
#[test]
fn test_step_llg_rk4_returns_numerical_error() {
let dev = CudaDevice::new().unwrap();
let mut spins = vec![[1.0_f64, 0.0, 0.0]; 4];
let h_eff = vec![[0.0_f64, 0.0, 1.0]; 4];
let result = dev.step_llg_rk4(&mut spins, &h_eff, 0.01, 1.0e-13);
assert!(result.is_err());
match result.unwrap_err() {
Error::NumericalError { description } => {
assert!(description.contains("CUDA"));
},
other => panic!("expected NumericalError, got {:?}", other),
}
assert!(dev
.step_llg_rk4_multi(&mut spins, &h_eff, 0.01, 1.0e-13, 3)
.is_err());
assert!(dev.zeeman_energy(&spins, &h_eff, 8.0e5).is_err());
}
}