use numpy::PyArray1;
use numpy::borrow::{PyReadonlyArray1, PyReadwriteArray1};
use pyo3::exceptions;
use pyo3::prelude::*;
use std::fmt::Debug;
#[cfg(feature = "rat-mlfmm")]
use crate::mlfmm::MlfmmOptions;
use crate::{math, mesh, physics};
#[derive(Debug)]
#[allow(dead_code)]
enum PyInteropError {
DimensionalityError { msg: String },
}
impl From<PyInteropError> for PyErr {
fn from(val: PyInteropError) -> Self {
exceptions::PyValueError::new_err(format!("{:#?}", &val))
}
}
#[pyfunction]
fn filament_helix_path(
path: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), helix_start_offset: (f64, f64, f64),
twist_pitch: f64,
angle_offset: f64,
mut out: (
PyReadwriteArray1<f64>,
PyReadwriteArray1<f64>,
PyReadwriteArray1<f64>,
),
) -> PyResult<()> {
_3tup_slice_ro!(path);
_3tup_slice_mut!(out);
match mesh::filament_helix_path(path, helix_start_offset, twist_pitch, angle_offset, out) {
Ok(_) => (),
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
}
Ok(())
}
#[pyfunction]
fn rotate_filaments_about_path(
path: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), angle_offset: f64,
mut out: (
PyReadwriteArray1<f64>,
PyReadwriteArray1<f64>,
PyReadwriteArray1<f64>,
),
) -> PyResult<()> {
_3tup_slice_ro!(path);
_3tup_slice_mut!(out);
match mesh::rotate_filaments_about_path(path, angle_offset, out) {
Ok(_) => (),
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
}
Ok(())
}
#[pyfunction]
fn flux_circular_filament(
current: PyReadonlyArray1<f64>,
rfil: PyReadonlyArray1<f64>,
zfil: PyReadonlyArray1<f64>,
rprime: PyReadonlyArray1<f64>,
zprime: PyReadonlyArray1<f64>,
par: bool,
) -> PyResult<Py<PyArray1<f64>>> {
let rzifil = (rfil, zfil, current);
_3tup_slice_ro!(rzifil);
let obs = (rprime, zprime);
_2tup_slice_ro!(obs);
let mut psi = vec![0.0; obs.0.len()];
let func = match par {
true => physics::circular_filament::flux_circular_filament_par,
false => physics::circular_filament::flux_circular_filament,
};
match func(rzifil, obs, &mut psi[..]) {
Ok(_) => {}
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
}
Python::attach(|py| {
Ok(PyArray1::from_vec(py, psi).unbind()) })
}
#[pyfunction]
fn vector_potential_circular_filament(
current: PyReadonlyArray1<f64>,
rfil: PyReadonlyArray1<f64>,
zfil: PyReadonlyArray1<f64>,
rprime: PyReadonlyArray1<f64>,
zprime: PyReadonlyArray1<f64>,
par: bool,
) -> PyResult<Py<PyArray1<f64>>> {
let rzifil = (rfil, zfil, current);
_3tup_slice_ro!(rzifil);
let obs = (rprime, zprime);
_2tup_slice_ro!(obs);
let mut out = vec![0.0; obs.0.len()];
let func = match par {
true => physics::circular_filament::vector_potential_circular_filament_par,
false => physics::circular_filament::vector_potential_circular_filament,
};
match func(rzifil, obs, &mut out[..]) {
Ok(_) => {}
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
}
Python::attach(|py| {
Ok(PyArray1::from_vec(py, out).unbind()) })
}
#[pyfunction]
fn flux_density_circular_filament(
current: PyReadonlyArray1<f64>,
rfil: PyReadonlyArray1<f64>,
zfil: PyReadonlyArray1<f64>,
rprime: PyReadonlyArray1<f64>,
zprime: PyReadonlyArray1<f64>,
par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
let rzifil = (rfil, zfil, current);
_3tup_slice_ro!(rzifil);
let obs = (rprime, zprime);
_2tup_slice_ro!(obs);
let n = obs.0.len();
let (mut br, mut bz) = (vec![0.0; n], vec![0.0; n]);
let func = match par {
true => physics::circular_filament::flux_density_circular_filament_par,
false => physics::circular_filament::flux_density_circular_filament,
};
match func(rzifil, obs, (&mut br, &mut bz)) {
Ok(_) => {}
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
}
Python::attach(|py| {
let br: Py<PyArray1<f64>> = PyArray1::from_slice(py, &br).unbind(); let bz: Py<PyArray1<f64>> = PyArray1::from_slice(py, &bz).unbind();
Ok((br, bz))
})
}
#[pyfunction(signature = (xyzp, xyzfil, dlxyzfil, ifil, wire_radius, par=true))]
fn flux_density_linear_filament(
xyzp: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), xyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), ifil: PyReadonlyArray1<f64>, wire_radius: PyReadonlyArray1<f64>, par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
_3tup_slice_ro!(xyzp);
_3tup_slice_ro!(xyzfil);
_3tup_slice_ro!(dlxyzfil);
let ifil = ifil.as_slice()?;
let wire_radius = wire_radius.as_slice()?;
let n = xyzp.0.len();
let (mut bx, mut by, mut bz) = (vec![0.0; n], vec![0.0; n], vec![0.0; n]);
let func = match par {
true => physics::linear_filament::flux_density_linear_filament_par,
false => physics::linear_filament::flux_density_linear_filament,
};
match func(
xyzp,
xyzfil,
dlxyzfil,
ifil,
wire_radius,
(&mut bx, &mut by, &mut bz),
) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
_3tup_ret!((bx, f64), (by, f64), (bz, f64))
}
#[pyfunction(signature = (xyzp, xyzfil, dlxyzfil, ifil, wire_radius, par=true))]
fn flux_density_linear_filament_matrix(
xyzp: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), xyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), ifil: PyReadonlyArray1<f64>, wire_radius: PyReadonlyArray1<f64>, par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
_3tup_slice_ro!(xyzp);
_3tup_slice_ro!(xyzfil);
_3tup_slice_ro!(dlxyzfil);
let ifil = ifil.as_slice()?;
let wire_radius = wire_radius.as_slice()?;
let nout = xyzp.0.len().checked_mul(xyzfil.0.len()).ok_or_else(|| {
PyInteropError::DimensionalityError {
msg: "Output size overflow in flux_density_linear_filament_matrix".to_string(),
}
})?;
let (mut bx, mut by, mut bz) = (vec![0.0; nout], vec![0.0; nout], vec![0.0; nout]);
let func = match par {
true => physics::linear_filament::flux_density_linear_filament_matrix_par,
false => physics::linear_filament::flux_density_linear_filament_matrix,
};
match func(
xyzp,
xyzfil,
dlxyzfil,
ifil,
wire_radius,
(&mut bx, &mut by, &mut bz),
) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
_3tup_ret!((bx, f64), (by, f64), (bz, f64))
}
#[pyfunction]
fn flux_density_point_segment(
xyzp: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), xyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), ifil: PyReadonlyArray1<f64>, par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
_3tup_slice_ro!(xyzp);
_3tup_slice_ro!(xyzfil);
_3tup_slice_ro!(dlxyzfil);
let ifil = ifil.as_slice()?;
let n = xyzp.0.len();
let (mut bx, mut by, mut bz) = (vec![0.0; n], vec![0.0; n], vec![0.0; n]);
let func = match par {
true => physics::point_source::segment::flux_density_point_segment_par,
false => physics::point_source::segment::flux_density_point_segment,
};
match func(xyzp, xyzfil, dlxyzfil, ifil, (&mut bx, &mut by, &mut bz)) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
_3tup_ret!((bx, f64), (by, f64), (bz, f64))
}
#[pyfunction(signature = (xyzp, xyzfil, dlxyzfil, ifil, wire_radius, par=true))]
fn vector_potential_linear_filament(
xyzp: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), xyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), ifil: PyReadonlyArray1<f64>, wire_radius: PyReadonlyArray1<f64>, par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
_3tup_slice_ro!(xyzp);
_3tup_slice_ro!(xyzfil);
_3tup_slice_ro!(dlxyzfil);
let ifil = ifil.as_slice()?;
let wire_radius = wire_radius.as_slice()?;
let n = xyzp.0.len();
let (mut outx, mut outy, mut outz) = (vec![0.0; n], vec![0.0; n], vec![0.0; n]);
let func = match par {
true => physics::linear_filament::vector_potential_linear_filament_par,
false => physics::linear_filament::vector_potential_linear_filament,
};
match func(
xyzp,
xyzfil,
dlxyzfil,
ifil,
wire_radius,
(&mut outx, &mut outy, &mut outz),
) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
_3tup_ret!((outx, f64), (outy, f64), (outz, f64))
}
#[pyfunction(signature = (xyzp, xyzfil, dlxyzfil, ifil, wire_radius, par=true))]
fn vector_potential_linear_filament_matrix(
xyzp: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), xyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), ifil: PyReadonlyArray1<f64>, wire_radius: PyReadonlyArray1<f64>, par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
_3tup_slice_ro!(xyzp);
_3tup_slice_ro!(xyzfil);
_3tup_slice_ro!(dlxyzfil);
let ifil = ifil.as_slice()?;
let wire_radius = wire_radius.as_slice()?;
let nout = xyzp.0.len().checked_mul(xyzfil.0.len()).ok_or_else(|| {
PyInteropError::DimensionalityError {
msg: "Output size overflow in vector_potential_linear_filament_matrix".to_string(),
}
})?;
let (mut outx, mut outy, mut outz) = (vec![0.0; nout], vec![0.0; nout], vec![0.0; nout]);
let func = match par {
true => physics::linear_filament::vector_potential_linear_filament_matrix_par,
false => physics::linear_filament::vector_potential_linear_filament_matrix,
};
match func(
xyzp,
xyzfil,
dlxyzfil,
ifil,
wire_radius,
(&mut outx, &mut outy, &mut outz),
) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
_3tup_ret!((outx, f64), (outy, f64), (outz, f64))
}
#[pyfunction]
fn vector_potential_point_segment(
xyzp: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), xyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), ifil: PyReadonlyArray1<f64>, par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
_3tup_slice_ro!(xyzp);
_3tup_slice_ro!(xyzfil);
_3tup_slice_ro!(dlxyzfil);
let ifil = ifil.as_slice()?;
let n = xyzp.0.len();
let (mut outx, mut outy, mut outz) = (vec![0.0; n], vec![0.0; n], vec![0.0; n]);
let func = match par {
true => physics::point_source::segment::vector_potential_point_segment_par,
false => physics::point_source::segment::vector_potential_point_segment,
};
match func(
xyzp,
xyzfil,
dlxyzfil,
ifil,
(&mut outx, &mut outy, &mut outz),
) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
_3tup_ret!((outx, f64), (outy, f64), (outz, f64))
}
#[pyfunction(signature = (xyzfil0, dlxyzfil0, xyzfil1, dlxyzfil1, wire_radius))]
fn inductance_piecewise_linear_filaments(
xyzfil0: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil0: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), xyzfil1: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil1: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), wire_radius: PyReadonlyArray1<f64>, ) -> PyResult<f64> {
_3tup_slice_ro!(xyzfil0);
_3tup_slice_ro!(dlxyzfil0);
_3tup_slice_ro!(xyzfil1);
_3tup_slice_ro!(dlxyzfil1);
let wire_radius = wire_radius.as_slice()?;
let inductance = match physics::linear_filament::inductance_piecewise_linear_filaments(
xyzfil0,
dlxyzfil0,
xyzfil1,
dlxyzfil1,
wire_radius,
) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
Ok(inductance)
}
#[pyfunction(signature = (xyzfil_tgt, dlxyzfil_tgt, xyzfil_src, dlxyzfil_src, wire_radius_src))]
fn inductance_linear_filaments(
py: Python<'_>,
xyzfil_tgt: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil_tgt: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), xyzfil_src: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil_src: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), wire_radius_src: PyReadonlyArray1<f64>, ) -> PyResult<Py<PyArray1<f64>>> {
_3tup_slice_ro!(xyzfil_tgt);
_3tup_slice_ro!(dlxyzfil_tgt);
_3tup_slice_ro!(xyzfil_src);
_3tup_slice_ro!(dlxyzfil_src);
let wire_radius_src = wire_radius_src.as_slice()?;
let ntgt = xyzfil_tgt.0.len();
let mut out = vec![0.0; ntgt];
match physics::linear_filament::inductance_linear_filaments(
xyzfil_tgt,
dlxyzfil_tgt,
xyzfil_src,
dlxyzfil_src,
wire_radius_src,
&mut out,
) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
Ok(PyArray1::from_vec(py, out).unbind())
}
#[pyfunction(signature = (xyzfil_tgt, dlxyzfil_tgt, xyzfil_src, dlxyzfil_src, wire_radius_src, par=true))]
fn inductance_linear_filaments_matrix(
py: Python<'_>,
xyzfil_tgt: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil_tgt: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), xyzfil_src: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil_src: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), wire_radius_src: PyReadonlyArray1<f64>, par: bool,
) -> PyResult<Py<PyArray1<f64>>> {
_3tup_slice_ro!(xyzfil_tgt);
_3tup_slice_ro!(dlxyzfil_tgt);
_3tup_slice_ro!(xyzfil_src);
_3tup_slice_ro!(dlxyzfil_src);
let wire_radius_src = wire_radius_src.as_slice()?;
let nout = xyzfil_tgt
.0
.len()
.checked_mul(xyzfil_src.0.len())
.ok_or_else(|| PyInteropError::DimensionalityError {
msg: "Output size overflow in inductance_linear_filaments_matrix".to_string(),
})?;
let mut out = vec![0.0; nout];
let func = match par {
true => physics::linear_filament::inductance_linear_filaments_matrix_par,
false => physics::linear_filament::inductance_linear_filaments_matrix,
};
match func(
xyzfil_tgt,
dlxyzfil_tgt,
xyzfil_src,
dlxyzfil_src,
wire_radius_src,
&mut out,
) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
Ok(PyArray1::from_vec(py, out).unbind())
}
#[pyfunction]
fn gs_operator_order2(
rs: PyReadonlyArray1<f64>,
zs: PyReadonlyArray1<f64>,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<usize>>, Py<PyArray1<usize>>)> {
let rs = rs.as_slice()?;
let zs = zs.as_slice()?;
let (vals, rows, cols) = physics::gradshafranov::gs_operator_order2(rs, zs);
_3tup_ret!((vals, f64), (rows, usize), (cols, usize))
}
#[pyfunction]
fn gs_operator_order4(
rs: PyReadonlyArray1<f64>,
zs: PyReadonlyArray1<f64>,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<usize>>, Py<PyArray1<usize>>)> {
let rs = rs.as_slice()?;
let zs = zs.as_slice()?;
let (vals, rows, cols) = physics::gradshafranov::gs_operator_order4(rs, zs);
_3tup_ret!((vals, f64), (rows, usize), (cols, usize))
}
#[pyfunction]
fn ellipe(x: f64) -> f64 {
math::ellipe(x)
}
#[pyfunction]
fn ellipk(x: f64) -> f64 {
math::ellipk(x)
}
#[pyfunction]
fn flux_density_circular_filament_cartesian(
current: PyReadonlyArray1<f64>,
rfil: PyReadonlyArray1<f64>,
zfil: PyReadonlyArray1<f64>,
xyzobs: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
let rzifil = (rfil, zfil, current);
_3tup_slice_ro!(rzifil);
let (rfil, zfil, current) = rzifil;
_3tup_slice_ro!(xyzobs);
let n = xyzobs.0.len();
let (mut bx, mut by, mut bz) = (vec![0.0; n], vec![0.0; n], vec![0.0; n]);
let func = match par {
true => physics::circular_filament::flux_density_circular_filament_cartesian_par,
false => physics::circular_filament::flux_density_circular_filament_cartesian,
};
match func(
(&rfil, &zfil, ¤t),
xyzobs,
(&mut bx, &mut by, &mut bz),
) {
Ok(_) => {}
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
}
_3tup_ret!((bx, f64), (by, f64), (bz, f64))
}
#[pyfunction]
fn mutual_inductance_circular_to_linear(
rfil: PyReadonlyArray1<f64>,
zfil: PyReadonlyArray1<f64>,
nfil: PyReadonlyArray1<f64>,
xyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), par: bool,
) -> PyResult<f64> {
let rznfil = (rfil, zfil, nfil);
_3tup_slice_ro!(rznfil);
_3tup_slice_ro!(xyzfil);
_3tup_slice_ro!(dlxyzfil);
let func = match par {
true => physics::circular_filament::mutual_inductance_circular_to_linear_par,
false => physics::circular_filament::mutual_inductance_circular_to_linear,
};
let m = match func(rznfil, xyzfil, dlxyzfil) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
Ok(m)
}
#[pyfunction]
fn flux_density_dipole(
loc: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), moment: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), obs: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), outer_radius: PyReadonlyArray1<f64>,
par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
_3tup_slice_ro!(loc);
_3tup_slice_ro!(moment);
_3tup_slice_ro!(obs);
let n = obs.0.len();
let (mut outx, mut outy, mut outz) = (vec![0.0; n], vec![0.0; n], vec![0.0; n]);
let func = match par {
true => physics::point_source::flux_density_dipole_par,
false => physics::point_source::flux_density_dipole,
};
match func(
loc,
moment,
outer_radius.as_slice()?,
obs,
(&mut outx, &mut outy, &mut outz),
) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
_3tup_ret!((outx, f64), (outy, f64), (outz, f64))
}
#[pyfunction]
fn vector_potential_dipole(
loc: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), moment: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), obs: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), outer_radius: PyReadonlyArray1<f64>,
par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
_3tup_slice_ro!(loc);
_3tup_slice_ro!(moment);
_3tup_slice_ro!(obs);
let n = obs.0.len();
let (mut outx, mut outy, mut outz) = (vec![0.0; n], vec![0.0; n], vec![0.0; n]);
let func = match par {
true => physics::point_source::vector_potential_dipole_par,
false => physics::point_source::vector_potential_dipole,
};
match func(
loc,
moment,
outer_radius.as_slice()?,
obs,
(&mut outx, &mut outy, &mut outz),
) {
Ok(x) => x,
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
_3tup_ret!((outx, f64), (outy, f64), (outz, f64))
}
#[pyfunction]
fn body_force_density_circular_filament_cartesian(
current: PyReadonlyArray1<f64>,
rfil: PyReadonlyArray1<f64>,
zfil: PyReadonlyArray1<f64>,
obs: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), j: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
let rzifil = (rfil, zfil, current);
_3tup_slice_ro!(rzifil);
let (rfil, zfil, current) = rzifil;
_3tup_slice_ro!(obs);
_3tup_slice_ro!(j);
let func = match par {
true => physics::circular_filament::body_force_density_circular_filament_cartesian_par,
false => physics::circular_filament::body_force_density_circular_filament_cartesian,
};
let n = obs.0.len();
let (mut outx, mut outy, mut outz) = (vec![0.0; n], vec![0.0; n], vec![0.0; n]);
let out = (&mut outx[..], &mut outy[..], &mut outz[..]);
match func((&rfil, &zfil, ¤t), obs, j, out) {
Ok(_) => (),
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
_3tup_ret!((outx, f64), (outy, f64), (outz, f64))
}
#[pyfunction]
#[pyo3(signature = (xyzfil, dlxyzfil, ifil, obs, j, wire_radius, par=true))]
fn body_force_density_linear_filament(
xyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), dlxyzfil: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), ifil: PyReadonlyArray1<f64>, obs: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), j: (
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
PyReadonlyArray1<f64>,
), wire_radius: PyReadonlyArray1<f64>, par: bool,
) -> PyResult<(Py<PyArray1<f64>>, Py<PyArray1<f64>>, Py<PyArray1<f64>>)> {
_3tup_slice_ro!(xyzfil);
_3tup_slice_ro!(dlxyzfil);
let ifil = ifil.as_slice()?;
_3tup_slice_ro!(obs);
_3tup_slice_ro!(j);
let wire_radius = wire_radius.as_slice()?;
let func = match par {
true => physics::linear_filament::body_force_density_linear_filament_par,
false => physics::linear_filament::body_force_density_linear_filament,
};
let n = obs.0.len();
let (mut outx, mut outy, mut outz) = (vec![0.0; n], vec![0.0; n], vec![0.0; n]);
let out = (&mut outx[..], &mut outy[..], &mut outz[..]);
match func(xyzfil, dlxyzfil, ifil, wire_radius, obs, j, out) {
Ok(_) => (),
Err(x) => {
let err: PyErr = PyInteropError::DimensionalityError { msg: x.to_string() }.into();
return Err(err);
}
};
_3tup_ret!((outx, f64), (outy, f64), (outz, f64))
}
#[pymodule]
#[pyo3(name = "cfsem")]
fn _cfsem<'py>(_py: Python, m: Bound<'py, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(flux_circular_filament, m.clone())?)?;
m.add_function(wrap_pyfunction!(flux_density_circular_filament, m.clone())?)?;
m.add_function(wrap_pyfunction!(
flux_density_circular_filament_cartesian,
m.clone()
)?)?;
m.add_function(wrap_pyfunction!(
vector_potential_circular_filament,
m.clone()
)?)?;
m.add_function(wrap_pyfunction!(
mutual_inductance_circular_to_linear,
m.clone()
)?)?;
m.add_function(wrap_pyfunction!(
body_force_density_circular_filament_cartesian,
m.clone()
)?)?;
m.add_function(wrap_pyfunction!(flux_density_linear_filament, m.clone())?)?;
m.add_function(wrap_pyfunction!(
flux_density_linear_filament_matrix,
m.clone()
)?)?;
m.add_function(wrap_pyfunction!(flux_density_point_segment, m.clone())?)?;
m.add_function(wrap_pyfunction!(
vector_potential_linear_filament,
m.clone()
)?)?;
m.add_function(wrap_pyfunction!(
vector_potential_linear_filament_matrix,
m.clone()
)?)?;
m.add_function(wrap_pyfunction!(vector_potential_point_segment, m.clone())?)?;
#[cfg(feature = "rat-mlfmm")]
m.add_function(wrap_pyfunction!(fields_linear_filament_mlfmm, m.clone())?)?;
m.add_function(wrap_pyfunction!(
inductance_piecewise_linear_filaments,
m.clone()
)?)?;
m.add_function(wrap_pyfunction!(inductance_linear_filaments, m.clone())?)?;
m.add_function(wrap_pyfunction!(
inductance_linear_filaments_matrix,
m.clone()
)?)?;
m.add_function(wrap_pyfunction!(
body_force_density_linear_filament,
m.clone()
)?)?;
m.add_function(wrap_pyfunction!(gs_operator_order2, m.clone())?)?;
m.add_function(wrap_pyfunction!(gs_operator_order4, m.clone())?)?;
m.add_function(wrap_pyfunction!(ellipe, m.clone())?)?;
m.add_function(wrap_pyfunction!(ellipk, m.clone())?)?;
m.add_function(wrap_pyfunction!(filament_helix_path, m.clone())?)?;
m.add_function(wrap_pyfunction!(rotate_filaments_about_path, m.clone())?)?;
m.add_function(wrap_pyfunction!(flux_density_dipole, m.clone())?)?;
m.add_function(wrap_pyfunction!(vector_potential_dipole, m.clone())?)?;
Ok(())
}
macro_rules! _3tup_slice_ro {
($x:ident) => {
let $x = ($x.0.as_slice()?, $x.1.as_slice()?, $x.2.as_slice()?);
};
}
macro_rules! _2tup_slice_ro {
($x:ident) => {
let $x = ($x.0.as_slice()?, $x.1.as_slice()?);
};
}
macro_rules! _3tup_slice_mut {
($x:ident) => {
let $x = (
$x.0.as_slice_mut()?,
$x.1.as_slice_mut()?,
$x.2.as_slice_mut()?,
);
};
}
macro_rules! _3tup_ret {
(($x:ident, $xt:ty), ($y:ident, $yt:ty), ($z:ident, $zt:ty)) => {
Python::attach(|py| {
let $x: Py<PyArray1<$xt>> = PyArray1::from_vec(py, $x).unbind();
let $y: Py<PyArray1<$yt>> = PyArray1::from_vec(py, $y).unbind();
let $z: Py<PyArray1<$zt>> = PyArray1::from_vec(py, $z).unbind();
Ok(($x, $y, $z))
})
};
}
pub(crate) use _2tup_slice_ro;
pub(crate) use _3tup_ret;
pub(crate) use _3tup_slice_mut;
pub(crate) use _3tup_slice_ro;