feat: Adds methods for obtaining the full dipole from simpler model description.
Some checks failed
gitea-physics/pdme/pipeline/head There was a failure building this commit
Some checks failed
gitea-physics/pdme/pipeline/head There was a failure building this commit
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
from pdme.model.model import Model, Discretisation
|
||||
from pdme.model.fixed_z_plane_model import FixedZPlaneModel
|
||||
from pdme.model.unrestricted_model import UnrestrictedModel
|
||||
from pdme.model.fixed_dipole_model import FixedDipoleModel
|
||||
from pdme.model.fixed_magnitude_model import FixedMagnitudeModel
|
||||
|
||||
__all__ = ["Model", "Discretisation", "FixedZPlaneModel", "UnrestrictedModel"]
|
||||
__all__ = ["Model", "Discretisation", "FixedZPlaneModel", "UnrestrictedModel", "FixedDipoleModel", "FixedMagnitudeModel"]
|
||||
|
||||
@@ -37,6 +37,12 @@ class FixedDipoleModel(Model):
|
||||
s_pts = numpy.array((self.rng.uniform(self.xmin, self.xmax), self.rng.uniform(self.ymin, self.ymax), self.rng.uniform(self.zmin, self.zmax)))
|
||||
return OscillatingDipoleArrangement([OscillatingDipole(self.p, s_pts, frequency)])
|
||||
|
||||
def solution_single_dipole(self, pt: numpy.ndarray) -> OscillatingDipole:
|
||||
# assume length is 4.
|
||||
s = pt[0:3]
|
||||
w = pt[3]
|
||||
return OscillatingDipole(self.p, s, w)
|
||||
|
||||
def point_length(self) -> int:
|
||||
'''
|
||||
Dipole is constrained magnitude, but free orientation.
|
||||
|
||||
@@ -30,7 +30,21 @@ class FixedMagnitudeModel(Model):
|
||||
self.rng = numpy.random.default_rng()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'FixedMagnitudeModel({self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.zmin}, {self.zmax}, {self.n()})'
|
||||
return f'FixedMagnitudeModel({self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.zmin}, {self.zmax}, {self.pfixed}, {self.n()})'
|
||||
|
||||
def solution_single_dipole(self, pt: numpy.ndarray) -> OscillatingDipole:
|
||||
# assume length is 6, who needs error checking.
|
||||
p_theta = pt[0]
|
||||
p_phi = pt[1]
|
||||
s = pt[2:5]
|
||||
w = pt[5]
|
||||
|
||||
p = numpy.array([
|
||||
self.pfixed * numpy.sin(p_theta) * numpy.cos(p_phi),
|
||||
self.pfixed * numpy.sin(p_theta) * numpy.sin(p_phi),
|
||||
self.pfixed * numpy.cos(p_theta)
|
||||
])
|
||||
return OscillatingDipole(p, s, w)
|
||||
|
||||
def point_length(self) -> int:
|
||||
'''
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import numpy
|
||||
import scipy.optimize
|
||||
from typing import Callable, Sequence, Tuple
|
||||
from pdme.measurement import DotMeasurement, OscillatingDipoleArrangement
|
||||
from typing import Callable, Sequence, Tuple, List
|
||||
from pdme.measurement import DotMeasurement, OscillatingDipoleArrangement, OscillatingDipole
|
||||
import pdme.util
|
||||
import logging
|
||||
|
||||
@@ -26,6 +26,14 @@ class Model():
|
||||
def get_dipoles(self, frequency: float) -> OscillatingDipoleArrangement:
|
||||
raise NotImplementedError
|
||||
|
||||
def solution_single_dipole(self, pt: numpy.ndarray) -> OscillatingDipole:
|
||||
raise NotImplementedError
|
||||
|
||||
def solution_as_dipoles(self, pts: numpy.ndarray) -> List[OscillatingDipole]:
|
||||
pt_length = self.point_length()
|
||||
chunked_pts = [pts[i: i + pt_length] for i in range(0, len(pts), pt_length)]
|
||||
return [self.solution_single_dipole(pt) for pt in chunked_pts]
|
||||
|
||||
def cost_for_dot(self, dot: DotMeasurement, pts: numpy.ndarray) -> float:
|
||||
# creates numpy.ndarrays in groups of self.point_length().
|
||||
# Will throw problems for irregular points, but that's okay for now.
|
||||
|
||||
27
tests/model/test_fixed_dipole_moment_basic_solve.py
Normal file
27
tests/model/test_fixed_dipole_moment_basic_solve.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from pdme.model import FixedDipoleModel
|
||||
from pdme.measurement import OscillatingDipole, OscillatingDipoleArrangement
|
||||
import logging
|
||||
import numpy
|
||||
import itertools
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="No idea why this is failing, but it shouldn't!")
|
||||
def test_fixed_dipole_model_solve_basic():
|
||||
# Initialise our dipole arrangement and create dot measurements along a square.
|
||||
fixed_dipole_moment = numpy.array((2, 1, 2))
|
||||
dipoles = OscillatingDipoleArrangement([OscillatingDipole(fixed_dipole_moment, (1, 2, 4), 6)])
|
||||
dot_inputs = list(itertools.chain.from_iterable(
|
||||
(([1, 2, 1], f), ([1, 1, -2], f), ([1.5, 2, 0.1], f), ([1.5, 1, -0.2], f), ([2, 1, 0], f), ([2, 2, 0], f), ([0, 2, -.1], f), ([0, 1, 0.04], f), ([2, 0, 2], f), ([1, 0, 0], f)) for f in numpy.arange(1, 10, 1)
|
||||
))
|
||||
dots = dipoles.get_dot_measurements(dot_inputs)
|
||||
|
||||
model = FixedDipoleModel(-3, 3, -3, 3, 3, 5, fixed_dipole_moment, 1)
|
||||
|
||||
# from the dipole, these are the unspecified variables in ((.5, 0, 2), (1, 2, 4), 8)
|
||||
expected_solution = [1, 2, 4, 6]
|
||||
|
||||
result = model.solve(dots)
|
||||
logging.info(result)
|
||||
assert result.success
|
||||
numpy.testing.assert_allclose(result.normalised_x, expected_solution, err_msg="Even well specified problem solution was wrong.", rtol=1e-6, atol=1e-11)
|
||||
36
tests/model/test_fixed_magnitude_basic_solve.py
Normal file
36
tests/model/test_fixed_magnitude_basic_solve.py
Normal file
@@ -0,0 +1,36 @@
|
||||
from pdme.model import FixedMagnitudeModel
|
||||
from pdme.measurement import OscillatingDipole, OscillatingDipoleArrangement
|
||||
import logging
|
||||
import numpy
|
||||
import itertools
|
||||
|
||||
|
||||
def test_fixed_magnitude_model_solve_basic():
|
||||
# Initialise our dipole arrangement and create dot measurements along a square.
|
||||
dipoles = OscillatingDipoleArrangement([OscillatingDipole((2, 0, 0), (1, 2, 4), 1)])
|
||||
dot_inputs = list(itertools.chain.from_iterable(
|
||||
(([1, 2, 0.01], f), ([1, 1, -0.2], f), ([1.5, 2, 0.01], f), ([1.5, 1, -0.2], f), ([2, 1, 0], f), ([2, 2, 0], f), ([0, 2, -.1], f), ([0, 1, 0.04], f), ([2, 0, 0], f), ([1, 0, 0], f)) for f in numpy.arange(1, 10, 2)
|
||||
))
|
||||
dots = dipoles.get_dot_measurements(dot_inputs)
|
||||
|
||||
model = FixedMagnitudeModel(-5, 5, -5, 5, -5, 5, 2, 1)
|
||||
|
||||
# from the dipole, these are the unspecified variables in ((0, 0, 2), (1, 2, 4), 1)
|
||||
expected_solution = [numpy.pi / 2, 0, 1, 2, 4, 1]
|
||||
|
||||
result = model.solve(dots)
|
||||
logging.info(result)
|
||||
assert result.success
|
||||
numpy.testing.assert_allclose(result.normalised_x, expected_solution, err_msg="Even well specified problem solution was wrong.", rtol=1e-6, atol=1e-11)
|
||||
|
||||
solved_dipoles = model.solution_as_dipoles(result.normalised_x)
|
||||
|
||||
assert len(solved_dipoles) == 1
|
||||
numpy.testing.assert_allclose(solved_dipoles[0].p, (2, 0, 0), err_msg="Shove it in a dipole correctly.", rtol=1e-6, atol=1e-11)
|
||||
numpy.testing.assert_allclose(solved_dipoles[0].s, (1, 2, 4), err_msg="Shove it in a dipole correctly.", rtol=1e-6, atol=1e-11)
|
||||
numpy.testing.assert_allclose(solved_dipoles[0].w, 1, err_msg="Shove it in a dipole correctly.", rtol=1e-6, atol=1e-11)
|
||||
|
||||
|
||||
def test_fixed_magnitude_model_repr():
|
||||
model = FixedMagnitudeModel(-5, 5, -5, 5, -5, 5, 2, 1)
|
||||
assert repr(model) == "FixedMagnitudeModel(-5, 5, -5, 5, -5, 5, 2, 1)"
|
||||
Reference in New Issue
Block a user