use rayon::{
iter::{IntoParallelIterator, ParallelIterator},
slice::{ParallelSlice, ParallelSliceMut},
};
use crate::{
chunksize,
macros::{check_length, check_length_3tup, mut_par_chunks_3tup, par_chunks_3tup},
math::{cross3, dot3, ellipe, ellipk, rss3},
};
use crate::{MU_0, MU0_OVER_4PI};
pub fn flux_circular_filament_par(
rzifil: (&[f64], &[f64], &[f64]),
rzobs: (&[f64], &[f64]),
out: &mut [f64],
) -> Result<(), &'static str> {
let (rprime, zprime) = rzobs;
let n = chunksize(rprime.len());
let rprimec = rprime.par_chunks(n);
let zprimec = zprime.par_chunks(n);
let outc = out.par_chunks_mut(n);
(outc, rprimec, zprimec)
.into_par_iter()
.try_for_each(|(outc, rc, zc)| flux_circular_filament(rzifil, (rc, zc), outc))?;
Ok(())
}
pub fn flux_circular_filament(
rzifil: (&[f64], &[f64], &[f64]),
rzobs: (&[f64], &[f64]),
out: &mut [f64],
) -> Result<(), &'static str> {
let (rfil, zfil, ifil) = rzifil;
let (rprime, zprime) = rzobs;
let m: usize = ifil.len();
let n: usize = rprime.len();
check_length_3tup!(m, &rzifil);
check_length!(n, rprime, zprime);
check_length!(n, out);
out.fill(0.0);
for i in 0..n {
for j in 0..m {
out[i] +=
flux_circular_filament_scalar((rfil[j], zfil[j], ifil[j]), (rprime[i], zprime[i]));
}
}
Ok(())
}
#[inline]
pub fn flux_circular_filament_scalar(rzifil: (f64, f64, f64), rzobs: (f64, f64)) -> f64 {
let (rfil, zfil, ifil) = rzifil;
let (rprime, zprime) = rzobs;
let rrprime = rfil * rprime;
let rpr = rfil + rprime;
let zmz = zfil - zprime;
let k2 = 4.0 * rrprime / (rpr.mul_add(rpr, zmz * zmz));
MU_0 * ifil * (rrprime / k2).sqrt() * ((2.0 - k2) * ellipk(k2) - 2.0 * ellipe(k2))
}
pub fn flux_density_circular_filament_par(
rzifil: (&[f64], &[f64], &[f64]),
rzobs: (&[f64], &[f64]),
out: (&mut [f64], &mut [f64]),
) -> Result<(), &'static str> {
let (rprime, zprime) = rzobs;
let (out_r, out_z) = out;
let n = chunksize(rprime.len());
let rprimec = rprime.par_chunks(n);
let zprimec = zprime.par_chunks(n);
let outrc = out_r.par_chunks_mut(n);
let outzc = out_z.par_chunks_mut(n);
(outrc, outzc, rprimec, zprimec)
.into_par_iter()
.try_for_each(|(orc, ozc, rc, zc)| {
flux_density_circular_filament(rzifil, (rc, zc), (orc, ozc))
})?;
Ok(())
}
pub fn flux_density_circular_filament(
rzifil: (&[f64], &[f64], &[f64]),
rzobs: (&[f64], &[f64]),
out: (&mut [f64], &mut [f64]),
) -> Result<(), &'static str> {
let (rfil, zfil, ifil) = rzifil;
let (rprime, zprime) = rzobs;
let (out_r, out_z) = out;
let n = ifil.len();
let m = rprime.len();
check_length_3tup!(n, &rzifil);
check_length!(m, &out_r, &out_z);
out_r.fill(0.0);
out_z.fill(0.0);
for i in 0..n {
for j in 0..m {
let (br, bz) = flux_density_circular_filament_scalar(
(rfil[i], zfil[i], ifil[i]),
(rprime[j], zprime[j]),
);
out_r[j] += br;
out_z[j] += bz;
}
}
Ok(())
}
#[inline]
pub fn flux_density_circular_filament_scalar(
rzifil: (f64, f64, f64),
rzobs: (f64, f64),
) -> (f64, f64) {
let (rfil, zfil, ifil) = rzifil;
let (rprime, zprime) = rzobs;
let z = zprime - zfil;
let z2 = z * z; let r2 = rprime * rprime;
let rpr = rfil + rprime;
let q = rpr.mul_add(rpr, z2); let k2 = 4.0 * rfil * rprime / q;
let a0 = 2.0 * ifil / q.sqrt();
let f = ellipk(k2); let s = ellipe(k2) / (1.0 - k2);
let s_over_q = s / q; let rfil2 = rfil * rfil;
let hr = (z / rprime) * a0 * s_over_q.mul_add(rfil2 + r2 + z2, -f);
let hz = a0 * s_over_q.mul_add(rfil2 - r2 - z2, f);
let br = MU0_OVER_4PI * hr;
let bz = MU0_OVER_4PI * hz;
(br, bz)
}
#[inline]
pub fn flux_density_circular_filament_cartesian_scalar(
rzifil: (f64, f64, f64),
xyzobs: (f64, f64, f64),
) -> (f64, f64, f64) {
let (x, y, z) = xyzobs;
let (robs, phiobs, zobs) = crate::math::cartesian_to_cylindrical(x, y, z);
let (br, bz) = flux_density_circular_filament_scalar(rzifil, (robs, zobs));
let (bx, by, bz) = (br * libm::cos(phiobs), br * libm::sin(phiobs), bz);
(bx, by, bz)
}
pub fn flux_density_circular_filament_cartesian(
rzifil: (&[f64], &[f64], &[f64]),
xyzobs: (&[f64], &[f64], &[f64]),
bxyz_out: (&mut [f64], &mut [f64], &mut [f64]),
) -> Result<(), &'static str> {
let (rfil, zfil, ifil) = rzifil;
let (x, y, z) = xyzobs;
let (bx, by, bz) = bxyz_out;
let n = ifil.len();
check_length_3tup!(n, &rzifil);
let m = x.len();
check_length_3tup!(m, &xyzobs);
check_length!(m, bx, by, bz);
bx.fill(0.0);
by.fill(0.0);
bz.fill(0.0);
for j in 0..m {
for i in 0..n {
let rzifil_i = (rfil[i], zfil[i], ifil[i]);
let xyzobs_j = (x[j], y[j], z[j]);
let (bxo, byo, bzo) =
flux_density_circular_filament_cartesian_scalar(rzifil_i, xyzobs_j);
bx[j] += bxo;
by[j] += byo;
bz[j] += bzo;
}
}
Ok(())
}
pub fn flux_density_circular_filament_cartesian_par(
rzifil: (&[f64], &[f64], &[f64]),
xyzobs: (&[f64], &[f64], &[f64]),
bxyz_out: (&mut [f64], &mut [f64], &mut [f64]),
) -> Result<(), &'static str> {
let n = chunksize(xyzobs.0.len());
let (xc, yc, zc) = par_chunks_3tup!(xyzobs, n);
let (outbxc, outbyc, outbzc) = mut_par_chunks_3tup!(bxyz_out, n);
(xc, yc, zc, outbxc, outbyc, outbzc)
.into_par_iter()
.try_for_each(|(xci, yci, zci, bxci, byci, bzci)| {
let xyzobs_i = (xci, yci, zci);
let bxyz_out_i = (bxci, byci, bzci);
flux_density_circular_filament_cartesian(rzifil, xyzobs_i, bxyz_out_i)
})?;
Ok(())
}
pub fn vector_potential_circular_filament_par(
rzifil: (&[f64], &[f64], &[f64]),
rzobs: (&[f64], &[f64]),
out: &mut [f64],
) -> Result<(), &'static str> {
let (rprime, zprime) = rzobs;
let n = chunksize(rprime.len());
let rprimec = rprime.par_chunks(n);
let zprimec = zprime.par_chunks(n);
let outc = out.par_chunks_mut(n);
(outc, rprimec, zprimec)
.into_par_iter()
.try_for_each(|(outc, rc, zc)| {
vector_potential_circular_filament(rzifil, (rc, zc), outc)
})?;
Ok(())
}
pub fn vector_potential_circular_filament(
rzifil: (&[f64], &[f64], &[f64]),
rzobs: (&[f64], &[f64]),
out: &mut [f64],
) -> Result<(), &'static str> {
let (rfil, zfil, ifil) = rzifil;
let (rprime, zprime) = rzobs;
let n = ifil.len();
check_length_3tup!(n, &rzifil);
let m = rprime.len();
check_length!(m, rprime, zprime, out);
out.fill(0.0);
for i in 0..n {
for j in 0..m {
out[j] += vector_potential_circular_filament_scalar(
(rfil[i], zfil[i], ifil[i]),
(rprime[j], zprime[j]),
);
}
}
Ok(())
}
#[inline]
pub fn vector_potential_circular_filament_scalar(
rzifil: (f64, f64, f64),
rzobs: (f64, f64),
) -> f64 {
let (rfil, zfil, ifil) = rzifil;
let (rprime, zprime) = rzobs;
let z = zprime - zfil;
let rpr = rfil + rprime;
let rpr2 = rpr * rpr;
let denom = z.mul_add(z, rpr2);
let numer = 4.0 * rfil * rprime;
let k2 = numer / denom;
let c0 = ((2.0 - k2) * ellipk(k2) - 2.0 * ellipe(k2)) / k2;
let c1 = MU0_OVER_4PI * ifil * 4.0 * rfil / denom.sqrt();
c0 * c1 }
#[inline]
pub fn mutual_inductance_circular_to_linear_scalar(
rznfil: (f64, f64, f64),
xyzfil0: (f64, f64, f64),
xyzfil1: (f64, f64, f64),
) -> f64 {
let dlxfil = xyzfil1.0 - xyzfil0.0; let dlyfil = xyzfil1.1 - xyzfil0.1;
let dlzfil = xyzfil1.2 - xyzfil0.2;
let path_r = rss3(xyzfil0.0, xyzfil0.1, 0.0); let path_dr = rss3(dlxfil, dlyfil, 0.0);
let path_phi0 = libm::atan2(xyzfil0.1, xyzfil0.0);
let path_phi1 = libm::atan2(xyzfil1.1, xyzfil1.0);
let path_r_mid = path_r + path_dr / 2.0; let path_z_mid = xyzfil0.2 + dlzfil / 2.0; let path_phi_mid = (path_phi0 + path_phi1) / 2.0;
let a_phi_per_A = vector_potential_circular_filament_scalar(rznfil, (path_r_mid, path_z_mid));
let a_x_per_A = -a_phi_per_A * libm::sin(path_phi_mid);
let a_y_per_A = a_phi_per_A * libm::cos(path_phi_mid);
let a_z_per_A = 0.0;
dot3(a_x_per_A, a_y_per_A, a_z_per_A, dlxfil, dlyfil, dlzfil)
}
pub fn mutual_inductance_circular_to_linear(
rznfil: (&[f64], &[f64], &[f64]),
xyzfil: (&[f64], &[f64], &[f64]),
dlxyzfil: (&[f64], &[f64], &[f64]),
) -> Result<f64, &'static str> {
let m = xyzfil.0.len();
check_length_3tup!(m, &xyzfil);
check_length_3tup!(m, &dlxyzfil);
if m < 2 {
return Err("Input length mismatch");
}
let n = rznfil.0.len();
check_length_3tup!(n, &rznfil);
let mut mutual_inductance = 0.0;
for i in 0..m {
for j in 0..n {
let xyzfil0 = (xyzfil.0[i], xyzfil.1[i], xyzfil.2[i]);
let xyzfil1 = (
xyzfil.0[i] + dlxyzfil.0[i],
xyzfil.1[i] + dlxyzfil.1[i],
xyzfil.2[i] + dlxyzfil.2[i],
);
mutual_inductance += mutual_inductance_circular_to_linear_scalar(
(rznfil.0[j], rznfil.1[j], rznfil.2[j]),
xyzfil0,
xyzfil1,
);
}
}
Ok(mutual_inductance)
}
pub fn mutual_inductance_circular_to_linear_par(
rznfil: (&[f64], &[f64], &[f64]),
xyzfil: (&[f64], &[f64], &[f64]),
dlxyzfil: (&[f64], &[f64], &[f64]),
) -> Result<f64, &'static str> {
let n = chunksize(rznfil.0.len());
let (rfilc, zfilc, nfilc) = par_chunks_3tup!(rznfil, n);
let mutual_inductance = (nfilc, rfilc, zfilc)
.into_par_iter()
.try_fold(
|| 0.0,
|acc, (nc, rc, zc)| {
let m_contrib =
mutual_inductance_circular_to_linear((rc, zc, nc), xyzfil, dlxyzfil)?;
Ok::<f64, &'static str>(acc + m_contrib)
},
)
.try_reduce(|| 0.0, |acc, v| Ok(acc + v))?;
Ok(mutual_inductance)
}
pub fn body_force_density_circular_filament_cartesian_scalar(
rzifil: (f64, f64, f64),
xyzobs: (f64, f64, f64),
jobs: (f64, f64, f64),
) -> (f64, f64, f64) {
let (bx, by, bz) = flux_density_circular_filament_cartesian_scalar(rzifil, xyzobs);
cross3(jobs.0, jobs.1, jobs.2, bx, by, bz) }
pub fn body_force_density_circular_filament_cartesian(
rzifil: (&[f64], &[f64], &[f64]),
xyzobs: (&[f64], &[f64], &[f64]),
jobs: (&[f64], &[f64], &[f64]),
out: (&mut [f64], &mut [f64], &mut [f64]),
) -> Result<(), &'static str> {
let (rfil, zfil, ifil) = rzifil;
let (x, y, z) = xyzobs;
let (jx, jy, jz) = jobs;
let (outx, outy, outz) = out;
let n = ifil.len();
check_length!(n, rfil, zfil);
let m = x.len();
check_length!(m, x, y, z, jx, jy, jz, outx, outy, outz);
outx.fill(0.0);
outy.fill(0.0);
outz.fill(0.0);
for j in 0..m {
for i in 0..n {
let rzifil_i = (rfil[i], zfil[i], ifil[i]);
let xyzobs_j = (x[j], y[j], z[j]);
let jj = (jx[j], jy[j], jz[j]);
let (jxbx, jxby, jxbz) =
body_force_density_circular_filament_cartesian_scalar(rzifil_i, xyzobs_j, jj);
outx[j] += jxbx;
outy[j] += jxby;
outz[j] += jxbz;
}
}
Ok(())
}
pub fn body_force_density_circular_filament_cartesian_par(
rzifil: (&[f64], &[f64], &[f64]),
xyzobs: (&[f64], &[f64], &[f64]),
jobs: (&[f64], &[f64], &[f64]),
out: (&mut [f64], &mut [f64], &mut [f64]),
) -> Result<(), &'static str> {
let n = chunksize(xyzobs.0.len());
let (xpc, ypc, zpc) = par_chunks_3tup!(xyzobs, n);
let (jxc, jyc, jzc) = par_chunks_3tup!(jobs, n);
let (outxc, outyc, outzc) = mut_par_chunks_3tup!(out, n);
(outxc, outyc, outzc, xpc, ypc, zpc, jxc, jyc, jzc)
.into_par_iter()
.try_for_each(|(outx, outy, outz, xp, yp, zp, jx, jy, jz)| {
body_force_density_circular_filament_cartesian(
rzifil,
(xp, yp, zp),
(jx, jy, jz),
(outx, outy, outz),
)
})?;
Ok(())
}
#[cfg(test)]
mod test {
use core::f64::consts::PI;
use super::*;
use crate::{physics::linear_filament::body_force_density_linear_filament, testing::*};
#[test]
fn test_body_force_density() {
let (rtol, atol) = (5e-2, 1e-9);
let (rfil, zfil, nfil) = example_circular_filaments();
let rzifil = (&rfil[..], &zfil[..], &nfil[..]);
let xyzfil1 = example_helix();
let n = xyzfil1.0.len();
let xyzobs = (
&xyzfil1.0[..n - 1],
&xyzfil1.1[..n - 1],
&xyzfil1.2[..n - 1],
);
let (x, y, z) = &xyzfil1;
let dl = (&diff(x)[..], &diff(y)[..], &diff(z)[..]);
let j_vec = dl;
let (outx, outy, outz) = (
&mut x.clone()[..n - 1],
&mut x.clone()[..n - 1],
&mut x.clone()[..n - 1],
);
body_force_density_circular_filament_cartesian(rzifil, xyzobs, j_vec, (outx, outy, outz))
.unwrap();
let out_sum: (f64, f64, f64) = (outx.iter().sum(), outy.iter().sum(), outz.iter().sum());
let mut out2_sum = (0.0, 0.0, 0.0);
let ndiscr = 100;
let dl1 = (&diff(x)[..], &diff(y)[..], &diff(z)[..]);
for i in 0..rfil.len() {
let (xi, yi, zi) = discretize_circular_filament(rfil[i], zfil[i], ndiscr);
let (outxi, outyi, outzi) = (
&mut xi.clone()[..ndiscr - 1],
&mut yi.clone()[..ndiscr - 1],
&mut zi.clone()[..ndiscr - 1],
);
let dl2 = (&diff(&xi)[..], &diff(&yi)[..], &diff(&zi)[..]);
let j2 = dl2;
body_force_density_linear_filament(
(
&xyzfil1.0[..n - 1],
&xyzfil1.1[..n - 1],
&xyzfil1.2[..n - 1],
),
dl1,
&vec![1.0; n - 1][..],
&vec![0.0; n - 1][..],
(&midpoints(&xi), &midpoints(&yi), &midpoints(&zi)),
j2,
(outxi, outyi, outzi),
)
.unwrap();
out2_sum.0 += nfil[i] * outxi.iter().sum::<f64>();
out2_sum.1 += nfil[i] * outyi.iter().sum::<f64>();
out2_sum.2 += nfil[i] * outzi.iter().sum::<f64>();
}
assert!(approx(out_sum.0, -out2_sum.0, rtol, atol));
assert!(approx(out_sum.1, -out2_sum.1, rtol, atol));
assert!(approx(out_sum.2, -out2_sum.2, rtol, atol));
}
#[test]
fn test_flux_density_circular_filament_cartesian() {
let rtol = 2e-2;
let atol = 1e-10;
let (rfil, zfil, nfil) = example_circular_filaments();
let rzifil = (&rfil[..], &zfil[..], &nfil[..]);
let xyzfil1 = example_helix();
let xyzobs = (&xyzfil1.0[..], &xyzfil1.1[..], &xyzfil1.2[..]);
let x = &xyzfil1.0;
let (bx0, by0, bz0) = (&mut x.clone()[..], &mut x.clone()[..], &mut x.clone()[..]);
flux_density_circular_filament_cartesian(rzifil, xyzobs, (bx0, by0, bz0)).unwrap();
let (bx1, by1, bz1) = (&mut x.clone()[..], &mut x.clone()[..], &mut x.clone()[..]);
flux_density_circular_filament_cartesian_par(rzifil, xyzobs, (bx1, by1, bz1)).unwrap();
let (bx2, by2, bz2) = (&mut x.clone()[..], &mut x.clone()[..], &mut x.clone()[..]);
bx2.fill(0.0);
by2.fill(0.0);
bz2.fill(0.0);
for i in 0..rfil.len() {
let (r, z, nturns) = (rfil[i], zfil[i], nfil[i]);
let ndiscr = 400;
let xyzfil0 = discretize_circular_filament(r, z, ndiscr);
let xyzfil0 = (&xyzfil0.0[..], &xyzfil0.1[..], &xyzfil0.2[..]);
let dlxyzfil = (
&diff(xyzfil0.0)[..],
&diff(xyzfil0.1)[..],
&diff(xyzfil0.2)[..],
);
let ifil = vec![nturns; ndiscr - 1];
let (xcontrib, ycontrib, zcontrib) =
(&mut x.clone()[..], &mut x.clone()[..], &mut x.clone()[..]);
crate::physics::linear_filament::flux_density_linear_filament_par(
xyzobs,
(
&xyzfil0.0[..ndiscr - 1],
&xyzfil0.1[..ndiscr - 1],
&xyzfil0.2[..ndiscr - 1],
),
dlxyzfil,
&ifil[..],
&vec![0.0; ifil.len()],
(xcontrib, ycontrib, zcontrib),
)
.unwrap();
for j in 0..x.len() {
bx2[j] += xcontrib[j];
by2[j] += ycontrib[j];
bz2[j] += zcontrib[j];
}
}
for j in 0..x.len() {
assert!(approx(bx0[j], bx1[j], 1e-12, 1e-12)); assert!(approx(bx0[j], bx2[j], rtol, atol));
assert!(approx(by0[j], by1[j], 1e-12, 1e-12)); assert!(approx(by0[j], by2[j], rtol, atol));
assert!(approx(bz0[j], bz1[j], 1e-12, 1e-12)); assert!(approx(bz0[j], bz2[j], rtol, atol)); }
}
#[test]
fn test_mutual_inductance_to_linear() {
let rtol = 1e-2;
let atol = 1e-12;
let (rfil, zfil, nfil) = example_circular_filaments();
let xyzfil1 = example_helix();
let (x, y, z) = (&xyzfil1.0[..], &xyzfil1.1[..], &xyzfil1.2[..]);
let dlxyzfil1 = (&diff(x)[..], &diff(y)[..], &diff(z)[..]);
let n = x.len();
let mutual_inductance = mutual_inductance_circular_to_linear(
(&rfil, &zfil, &nfil),
(&x[..n - 1], &y[..n - 1], &z[..n - 1]),
dlxyzfil1,
)
.unwrap();
let mutual_inductance_par = mutual_inductance_circular_to_linear_par(
(&rfil, &zfil, &nfil),
(&x[..n - 1], &y[..n - 1], &z[..n - 1]),
dlxyzfil1,
)
.unwrap();
let mut mutual_inductance_2 = 0.0;
for i in 0..rfil.len() {
let ndiscr = 100;
let (xfil, yfil, zfil) = discretize_circular_filament(rfil[i], zfil[i], ndiscr);
let dlxfil0 = diff(&xfil);
let dlyfil0 = diff(&yfil);
let dlzfil0 = diff(&zfil);
let dlxyzfil0 = (&dlxfil0[..], &dlyfil0[..], &dlzfil0[..]);
let wire_radius = vec![0.0; ndiscr - 1];
mutual_inductance_2 += nfil[i]
* crate::physics::linear_filament::inductance_piecewise_linear_filaments(
(
&xfil[0..ndiscr - 1],
&yfil[0..ndiscr - 1],
&zfil[0..ndiscr - 1],
),
dlxyzfil0,
(&x[0..n - 1], &y[0..n - 1], &z[0..n - 1]),
dlxyzfil1,
&wire_radius,
)
.unwrap();
}
assert!(approx(
mutual_inductance,
mutual_inductance_par,
1e-10,
1e-12
));
assert!(approx(mutual_inductance_2, mutual_inductance, rtol, atol));
}
#[test]
fn test_vector_potential() {
let rfil = 1.0 / core::f64::consts::PI; let zfil = 1.0 / core::f64::consts::E;
let vp = |r: f64, z: f64| {
let mut out = [0.0];
vector_potential_circular_filament((&[rfil], &[zfil], &[1.0]), (&[r], &[z]), &mut out)
.unwrap();
out[0]
};
let zvals = [0.25, 0.5, 2.5, 10.0, 0.0, -10.0, -2.5, -0.5, -0.25];
let rvals = [0.25, 0.5, 2.5, 10.0];
let eps = 1e-7;
for r in rvals.iter() {
for z in zvals.iter() {
let mut ca = [0.0; 3];
let a0 = vp(*r, *z - eps);
let a1 = vp(*r, *z + eps);
ca[0] = -(a1 - a0) / (2.0 * eps);
let ra0 = (*r - eps) * vp(*r - eps, *z);
let ra1 = (*r + eps) * vp(*r + eps, *z);
ca[2] = (ra1 - ra0) / (2.0 * eps) / *r;
let mut br = [0.0];
let mut bz = [0.0];
flux_density_circular_filament(
(&[rfil], &[zfil], &[1.0]),
(&[*r], &[*z]),
(&mut br, &mut bz),
)
.unwrap();
assert!(approx(br[0], ca[0], 1e-7, 1e-13));
assert!(approx(bz[0], ca[2], 1e-7, 1e-13));
let psi_from_a = 2.0 * PI * *r * vp(*r, *z);
let mut psi = [0.0];
flux_circular_filament((&[rfil], &[zfil], &[1.0]), (&[*r], &[*z]), &mut psi)
.unwrap();
println!("{psi:?}, {psi_from_a}");
assert!(approx(psi_from_a, psi[0], 1e-10, 0.0)); }
}
}
#[test]
fn test_serial_vs_parallel() {
const NFIL: usize = 10;
const NOBS: usize = 100;
let rfil: Vec<f64> = (0..NFIL).map(|i| (i as f64).sin() + 1.2).collect();
let zfil: Vec<f64> = (0..NFIL)
.map(|i| (i as f64) - (NFIL as f64) / 2.0)
.collect();
let ifil: Vec<f64> = (0..NFIL).map(|i| i as f64).collect();
let rprime: Vec<f64> = (0..NOBS).map(|i| 2.0 * (i as f64).sin() + 2.1).collect();
let zprime: Vec<f64> = (0..NOBS).map(|i| 4.0 * (2.0 * i as f64).cos()).collect();
let out0 = &mut [0.0; NOBS];
let out1 = &mut [1.0; NOBS];
let out2 = &mut [2.0; NOBS];
let out3 = &mut [3.0; NOBS];
flux_circular_filament((&rfil, &zfil, &ifil), (&rprime, &zprime), out0).unwrap();
flux_circular_filament_par((&rfil, &zfil, &ifil), (&rprime, &zprime), out1).unwrap();
for i in 0..NOBS {
assert_eq!(out0[i], out1[i]);
}
flux_density_circular_filament((&rfil, &zfil, &ifil), (&rprime, &zprime), (out0, out1))
.unwrap();
flux_density_circular_filament_par((&rfil, &zfil, &ifil), (&rprime, &zprime), (out2, out3))
.unwrap();
for i in 0..NOBS {
assert_eq!(out0[i], out2[i]);
assert_eq!(out1[i], out3[i]);
}
let out0 = &mut [0.0; NOBS]; let out1 = &mut [1.0; NOBS];
vector_potential_circular_filament((&rfil, &zfil, &ifil), (&rprime, &zprime), out0)
.unwrap();
vector_potential_circular_filament_par((&rfil, &zfil, &ifil), (&rprime, &zprime), out1)
.unwrap();
for i in 0..NOBS {
assert_eq!(out0[i], out1[i]);
}
}
}