Adds some tests and dot methods and jacobian
All checks were successful
gitea-physics/pathfinder/pipeline/head This commit looks good

This commit is contained in:
Deepak Mallubhotla 2021-09-13 11:51:52 -05:00
parent 69d8befe68
commit 10b72bfaaa
Signed by: deepak
GPG Key ID: 64BF53A3369104E7
3 changed files with 88 additions and 38 deletions

View File

@ -1,3 +1,4 @@
from pathfinder.model.oscillating.oscillating_dipole import OscillatingDipole, OscillatingDipoleArrangement from pathfinder.model.oscillating.oscillating_dipole import OscillatingDipole, OscillatingDipoleArrangement
from pathfinder.model.oscillating.dot import DotMeasurement
__all__ = ['OscillatingDipole', 'OscillatingDipoleArrangement'] __all__ = ['DotMeasurement', 'OscillatingDipole', 'OscillatingDipoleArrangement']

View File

@ -24,43 +24,58 @@ class DotMeasurement():
def __post_init__(self) -> None: def __post_init__(self) -> None:
self.r = numpy.array(self.r) self.r = numpy.array(self.r)
# def v_for_point(self, pt: numpy.ndarray) -> float: def v_for_point(self, pt: numpy.ndarray) -> float:
# ''' '''
# Returns the voltage for a static dipole represented as a phase space point. Returns the voltage for an oscillating dipole represented as a phase space point.
#
# Parameters Parameters
# ---------- ----------
# pt: A length 6 numpy array representing a dipole, as (px, py, pz, sx, sy, sz). pt: A length 7 numpy array representing a dipole, as (px, py, pz, sx, sy, sz, w).
#
# Returns Returns
# ---------- ----------
# Returns the voltage from that dipole at the point. Returns the voltage from that dipole at the point.
# ''' '''
# p = pt[0:3] # hardcoded here because chances p = pt[0:3] # hardcoded here because chances
# s = pt[3:6] # are we'll only ever work in 3d. s = pt[3:6] # are we'll only ever work in 3d.
# w = pt[6]
# diff = self.r - s
# return p.dot(diff) / (numpy.linalg.norm(diff)**3) return (self._alpha(p, s))**2 * self._b(w)
#
# def cost(self, pts: numpy.ndarray) -> float: def _alpha(self, p: numpy.ndarray, s: numpy.ndarray) -> float:
# # 6 because dipole in 3d has 6 degrees of freedom. diff = self.r - s
# pt_length = 6 return p.dot(diff) / (numpy.linalg.norm(diff)**3)
# # creates numpy.ndarrays in groups of pt_length.
# # Will throw problems for irregular points, but that's okay for now. def _b(self, w: float) -> float:
# chunked_pts = [pts[i: i + pt_length] for i in range(0, len(pts), pt_length)] return (1 / numpy.pi) * (w / (self.f**2 + w**2))
# return sum(self.v_for_point(pt) for pt in chunked_pts) - self.v
# def cost(self, pts: numpy.ndarray) -> float:
# def jac_pt(self, pt: numpy.ndarray) -> numpy.ndarray: # 7 because dipole in 3d has 7 degrees of freedom.
# p = pt[0:3] # hardcoded here because chances pt_length = 7
# s = pt[3:6] # are we'll only ever work in 3d. # creates numpy.ndarrays in groups of pt_length.
# # Will throw problems for irregular points, but that's okay for now.
# diff = self.r - s chunked_pts = [pts[i: i + pt_length] for i in range(0, len(pts), pt_length)]
# return sum(self.v_for_point(pt) for pt in chunked_pts) - self.v
# p_divs = diff / (numpy.linalg.norm(diff)**3)
# def jac_pt(self, pt: numpy.ndarray) -> numpy.ndarray:
# r_divs = -p / (numpy.linalg.norm(diff)**3) + 3 * p.dot(diff) * diff / (numpy.linalg.norm(diff)**5) p = pt[0:3] # hardcoded here because chances
# s = pt[3:6] # are we'll only ever work in 3d.
# return numpy.append(p_divs, r_divs) w = pt[6]
diff = self.r - s
alpha = self._alpha(p, s)
b = self._b(w)
p_divs = 2 * alpha * diff / (numpy.linalg.norm(diff)**3) * b
r_divs = (-p / (numpy.linalg.norm(diff)**3) + 3 * p.dot(diff) * diff / (numpy.linalg.norm(diff)**5)) * 2 * alpha * b
f2 = self.f**2
w2 = w**2
w_div = alpha**2 * (1 / numpy.pi) * ((f2 - w2) / ((f2 + w2)**2))
return numpy.concatenate((p_divs, r_divs, w_div), axis=None)
# #
# def jac(self, pts: numpy.ndarray) -> numpy.ndarray: # def jac(self, pts: numpy.ndarray) -> numpy.ndarray:
# # 6 because dipole in 3d has 6 degrees of freedom. # # 6 because dipole in 3d has 6 degrees of freedom.

View File

@ -0,0 +1,34 @@
import numpy
import numpy.testing
import pathfinder.model.oscillating as model
def test_dot_v_from_dipole():
dot_position1 = (-1, -1, -1)
dot_frequency1 = 11
expected_v1 = 0.00001421963287022476
dot = model.DotMeasurement(expected_v1, dot_position1, dot_frequency1)
# and dipole located at (4, 5, 6) with p=(1, 2, 3) and w = 7
pt = numpy.array((1, 2, 3, 4, 5, 6, 7))
numpy.testing.assert_allclose(dot.v_for_point(pt), dot.v, err_msg="v from dipole at a dot was incorrect!")
numpy.testing.assert_allclose(dot.cost(pt), 0, atol=1e-12, err_msg="cost should be zero")
def test_jac():
expected_jac = [
3.742008650059147e-6, 4.4904103800709765e-6, 5.238812110082806e-6,
-3.12967996186765e-6, -3.1568945702317167e-6, -3.184109178595783e-6,
8.603475350051953e-7
]
dot = model.DotMeasurement(50, (-1, -1, -1), 11)
# dipole located at (4, 5, 6) with p=(1, 2, 3) and w = 7
pt = numpy.array((1, 2, 3, 4, 5, 6, 7))
assert len(dot.jac_pt(pt)) == 7
numpy.testing.assert_allclose(dot.jac_pt(pt), expected_jac, err_msg="Jac pt doesn't match Mathematica result.")
# numpy.testing.assert_allclose(dot.jac(pts), jac_row_target, err_msg="whole row should match")