use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
use pyo3::types::PyDict;
use crate::caloritronics::cross_effects::SpinCaloritronicsMaterial;
use crate::caloritronics::onsager::OnsagerMatrix;
use crate::vector3::Vector3;
#[inline]
fn arr_to_vec(a: [f64; 3]) -> Vector3<f64> {
Vector3::new(a[0], a[1], a[2])
}
#[inline]
fn vec_to_arr(v: &Vector3<f64>) -> [f64; 3] {
[v.x, v.y, v.z]
}
#[pyclass(name = "OnsagerMatrix")]
#[derive(Clone)]
pub struct PyOnsagerMatrix {
inner: OnsagerMatrix,
}
#[pymethods]
impl PyOnsagerMatrix {
#[new]
pub fn new(
temperature: f64,
conductivity: f64,
seebeck: f64,
spin_seebeck: f64,
hall_angle: f64,
thermal_conductivity: f64,
) -> Self {
Self {
inner: OnsagerMatrix::new(
temperature,
conductivity,
seebeck,
spin_seebeck,
hall_angle,
thermal_conductivity,
),
}
}
#[staticmethod]
pub fn yig_pt(temperature: f64) -> Self {
Self {
inner: OnsagerMatrix::yig_pt(temperature),
}
}
#[staticmethod]
pub fn fe_pt(temperature: f64) -> Self {
Self {
inner: OnsagerMatrix::fe_pt(temperature),
}
}
#[staticmethod]
pub fn cofeb_pt(temperature: f64) -> Self {
Self {
inner: OnsagerMatrix::cofeb_pt(temperature),
}
}
#[getter]
pub fn temperature(&self) -> f64 {
self.inner.temperature
}
#[getter]
pub fn conductivity(&self) -> f64 {
self.inner.conductivity
}
#[getter]
pub fn seebeck(&self) -> f64 {
self.inner.seebeck
}
#[getter]
pub fn spin_seebeck(&self) -> f64 {
self.inner.spin_seebeck
}
#[getter]
pub fn hall_angle(&self) -> f64 {
self.inner.hall_angle
}
#[getter]
pub fn thermal_conductivity(&self) -> f64 {
self.inner.thermal_conductivity
}
pub fn reciprocity_error(&self) -> f64 {
self.inner.reciprocity_error()
}
pub fn spin_current_from_grad_t(&self, grad_t: [f64; 3]) -> [f64; 3] {
let result = self.inner.spin_current_from_grad_t(&arr_to_vec(grad_t));
vec_to_arr(&result)
}
pub fn heat_current_from_spin_current(&self, j_spin: [f64; 3]) -> [f64; 3] {
let result = self
.inner
.heat_current_from_spin_current(&arr_to_vec(j_spin));
vec_to_arr(&result)
}
pub fn nernst_voltage(&self, grad_t: f64) -> f64 {
self.inner.nernst_voltage(grad_t)
}
pub fn all_currents(
&self,
py: Python<'_>,
grad_t: [f64; 3],
e_field: [f64; 3],
) -> PyResult<PyObject> {
let currents = self
.inner
.all_currents(&arr_to_vec(grad_t), &arr_to_vec(e_field));
let dict = PyDict::new(py);
dict.set_item(
"charge_current",
vec_to_arr(¤ts.charge_current).to_vec(),
)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
dict.set_item("spin_current", vec_to_arr(¤ts.spin_current).to_vec())
.map_err(|e| PyValueError::new_err(e.to_string()))?;
dict.set_item("heat_current", vec_to_arr(¤ts.heat_current).to_vec())
.map_err(|e| PyValueError::new_err(e.to_string()))?;
Ok(dict.into())
}
pub fn __repr__(&self) -> String {
format!(
"OnsagerMatrix(T={:.1} K, σ={:.2e} S/m, S_e={:.2e} V/K, S_s={:.2e} A/(m·K))",
self.inner.temperature,
self.inner.conductivity,
self.inner.seebeck,
self.inner.spin_seebeck
)
}
}
impl PyOnsagerMatrix {
pub fn inner(&self) -> &OnsagerMatrix {
&self.inner
}
}
#[pyclass(name = "SpinCaloritronicsMaterial")]
#[derive(Clone)]
pub struct PySpinCaloritronicsMaterial {
inner: SpinCaloritronicsMaterial,
}
#[pymethods]
impl PySpinCaloritronicsMaterial {
#[staticmethod]
pub fn yig_pt(temperature: f64) -> Self {
Self {
inner: SpinCaloritronicsMaterial::yig_pt(temperature),
}
}
#[staticmethod]
pub fn fe_pt(temperature: f64) -> Self {
Self {
inner: SpinCaloritronicsMaterial::fe_pt(temperature),
}
}
#[staticmethod]
pub fn cofeb_pt(temperature: f64) -> Self {
Self {
inner: SpinCaloritronicsMaterial::cofeb_pt(temperature),
}
}
#[staticmethod]
pub fn from_onsager(onsager: &PyOnsagerMatrix) -> Self {
Self {
inner: SpinCaloritronicsMaterial::new(onsager.inner.clone()),
}
}
#[getter]
pub fn name(&self) -> &str {
&self.inner.name
}
#[getter]
pub fn onsager(&self) -> PyOnsagerMatrix {
PyOnsagerMatrix {
inner: self.inner.onsager.clone(),
}
}
pub fn compute_all(
&self,
py: Python<'_>,
grad_t: [f64; 3],
j_spin: [f64; 3],
) -> PyResult<PyObject> {
let result = self
.inner
.compute_all(&arr_to_vec(grad_t), &arr_to_vec(j_spin))
.map_err(|e| PyValueError::new_err(e.to_string()))?;
let dict = PyDict::new(py);
dict.set_item(
"spin_seebeck_current",
vec_to_arr(&result.spin_seebeck_current).to_vec(),
)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
dict.set_item("peltier_heat", result.peltier_heat)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
dict.set_item("nernst_voltage", result.nernst_voltage)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
dict.set_item(
"spin_nernst_current",
vec_to_arr(&result.spin_nernst_current).to_vec(),
)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
dict.set_item("reciprocity_satisfied", result.reciprocity_satisfied)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
dict.set_item(
"total_heat_current",
vec_to_arr(&result.total_heat_current).to_vec(),
)
.map_err(|e| PyValueError::new_err(e.to_string()))?;
Ok(dict.into())
}
pub fn __repr__(&self) -> String {
format!(
"SpinCaloritronicsMaterial(name='{}', T={:.1} K)",
self.inner.name, self.inner.onsager.temperature
)
}
}