Merge pull request 'newalgorithm' (#8) from newalgorithm into master
All checks were successful
gitea-physics/pdme/pipeline/head This commit looks good

Reviewed-on: #8
This commit was merged in pull request #8.
This commit is contained in:
2022-03-06 21:37:56 +00:00
8 changed files with 162 additions and 2 deletions

View File

@@ -1,4 +1,4 @@
from pdme.measurement.dot_measure import DotMeasurement
from pdme.measurement.oscillating_dipole import OscillatingDipole, OscillatingDipoleArrangement
__all__ = ['DotMeasurement', 'OscillatingDipole', 'OscillatingDipoleArrangement']
__all__ = ['DotMeasurement', 'DotRangeMeasurement', 'OscillatingDipole', 'OscillatingDipoleArrangement']

View File

@@ -23,3 +23,28 @@ class DotMeasurement():
def __post_init__(self) -> None:
self.r = numpy.array(self.r)
@dataclass
class DotRangeMeasurement():
'''
Representation of a dot measuring oscillating dipoles.
Parameters
----------
v_low : float
The lower range of voltage measured at the dot.
v_high : float
The upper range of voltage measured at the dot.
r : numpy.ndarray
The position of the dot.
f : float
The measurement frequency.
'''
v_low: float
v_high: float
r: numpy.ndarray
f: float
def __post_init__(self) -> None:
self.r = numpy.array(self.r)

View File

@@ -2,7 +2,7 @@ from dataclasses import dataclass
import numpy
import numpy.typing
from typing import Sequence, List, Tuple
from pdme.measurement.dot_measure import DotMeasurement
from pdme.measurement.dot_measure import DotMeasurement, DotRangeMeasurement
DotInput = Tuple[numpy.typing.ArrayLike, float]
@@ -54,6 +54,16 @@ class OscillatingDipole():
return (1 / numpy.pi) * (self.w / (f**2 + self.w**2))
def dot_inputs_to_array(dot_inputs: Sequence[DotInput]) -> numpy.ndarray:
return numpy.array([numpy.append(numpy.array(input[0]), input[1]) for input in dot_inputs])
def dot_range_measurements_low_high_arrays(dot_range_measurements: Sequence[DotRangeMeasurement]) -> Tuple[numpy.ndarray, numpy.ndarray]:
lows = [measurement.v_low for measurement in dot_range_measurements]
highs = [measurement.v_high for measurement in dot_range_measurements]
return (numpy.array(lows), numpy.array(highs))
class OscillatingDipoleArrangement():
'''
A collection of oscillating dipoles, which we are interested in being able to characterise.
@@ -75,3 +85,14 @@ class OscillatingDipoleArrangement():
For a series of points, each with three coordinates and a frequency, return a list of the corresponding DotMeasurements.
'''
return [self.get_dot_measurement(dot_input) for dot_input in dot_inputs]
def get_percent_range_dot_measurement(self, dot_input: DotInput, low_percent: float, high_percent: float) -> DotRangeMeasurement:
r = numpy.array(dot_input[0])
f = dot_input[1]
return DotRangeMeasurement(low_percent * sum([dipole.s_at_position(r, f) for dipole in self.dipoles]), high_percent * sum([dipole.s_at_position(r, f) for dipole in self.dipoles]), r, f)
def get_percent_range_dot_measurements(self, dot_inputs: Sequence[DotInput], low_percent: float, high_percent: float) -> List[DotRangeMeasurement]:
'''
For a series of points, each with three coordinates and a frequency, and also a lower error range and upper error range, return a list of the corresponding DotRangeMeasurements.
'''
return [self.get_percent_range_dot_measurement(dot_input, low_percent, high_percent) for dot_input in dot_inputs]

View File

@@ -62,6 +62,23 @@ class FixedMagnitudeModel(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(numpy.array([px, py, pz]), s_pts, frequency)])
def get_n_single_dipoles(self, n: int, max_frequency: float) -> numpy.ndarray:
# psw
theta = 2 * numpy.pi * self.rng.random(n)
phi = numpy.arccos(2 * self.rng.random(n) - 1)
px = self.pfixed * numpy.cos(theta) * numpy.sin(phi)
py = self.pfixed * numpy.sin(theta) * numpy.sin(phi)
pz = self.pfixed * numpy.cos(phi)
sx = self.rng.uniform(self.xmin, self.xmax, n)
sy = self.rng.uniform(self.ymin, self.ymax, n)
sz = self.rng.uniform(self.zmin, self.zmax, n)
w = self.rng.uniform(1, max_frequency, n)
return numpy.array([px, py, pz, sx, sy, sz, w]).T
def n(self) -> int:
return self._n

View File

@@ -26,6 +26,9 @@ class Model():
def get_dipoles(self, frequency: float) -> OscillatingDipoleArrangement:
raise NotImplementedError
def get_n_single_dipoles(self, n: int, max_frequency: float) -> numpy.ndarray:
raise NotImplementedError
def solution_single_dipole(self, pt: numpy.ndarray) -> OscillatingDipole:
raise NotImplementedError

40
pdme/util/fast_v_calc.py Normal file
View File

@@ -0,0 +1,40 @@
import numpy
import logging
_logger = logging.getLogger(__name__)
def fast_vs_for_dipoles(dot_inputs: numpy.ndarray, dipoles: numpy.ndarray) -> numpy.ndarray:
'''
No error correction here baby.
'''
ps = dipoles[:, 0:3]
ss = dipoles[:, 3:6]
ws = dipoles[:, 6]
_logger.debug(f"ps: {ps}")
_logger.debug(f"ss: {ss}")
_logger.debug(f"ws: {ws}")
rs = dot_inputs[:, 0:3]
fs = dot_inputs[:, 3]
diffses = rs - ss[:, None]
_logger.debug(f"diffses: {diffses}")
norms = numpy.linalg.norm(diffses, axis=2)**3
_logger.debug(f"norms: {norms}")
ases = (numpy.einsum('...ji, ...i', diffses, ps) / norms)**2
_logger.debug(f"ases: {ases}")
bses = (1 / numpy.pi) * (ws[:, None] / (fs**2 + ws[:, None]**2))
_logger.debug(f"bses: {bses}")
return ases * bses
def between(a: numpy.ndarray, low: numpy.ndarray, high: numpy.ndarray) -> numpy.ndarray:
'''
Intended specifically for the case where a is a list of arrays, and each array must be between the single array low and high, but without error checking.
'''
return numpy.all(numpy.logical_and(low < a, high > a), axis=1)

View File

@@ -20,3 +20,24 @@ def test_static_dipole():
numpy.testing.assert_allclose(measurement.r, dot_position1, err_msg="Dot position should have been passed over")
numpy.testing.assert_allclose(measurement.f, dot_frequency1, err_msg="Dot frequency should have been passed over")
numpy.testing.assert_allclose(measurement.v, expected_v1 + expected_v2, err_msg="Voltage at dot isn't as expected.")
def test_range_dipole_measurements():
d1 = pdme.measurement.OscillatingDipole((1, 2, 3), (4, 5, 6), 7)
d2 = pdme.measurement.OscillatingDipole((2, 5, 3), (4, -5, -6), 2)
dipoles = pdme.measurement.OscillatingDipoleArrangement([d1, d2])
dot_position1 = (-1, -1, -1)
dot_frequency1 = 11
expected_v1 = 0.00001421963287022476
expected_v2 = 0.00001107180225755457
numpy.testing.assert_allclose(d1.s_at_position(dot_position1, dot_frequency1), expected_v1, err_msg="Voltage at dot isn't as expected.")
range_dot_measurements = dipoles.get_percent_range_dot_measurements([(dot_position1, dot_frequency1)], 0.5, 1.5)
assert len(range_dot_measurements) == 1, "Should have only had one dot measurement."
range_measurement = range_dot_measurements[0]
numpy.testing.assert_allclose(range_measurement.r, dot_position1, err_msg="Dot position should have been passed over")
numpy.testing.assert_allclose(range_measurement.f, dot_frequency1, err_msg="Dot frequency should have been passed over")
numpy.testing.assert_allclose(range_measurement.v_low, (expected_v1 + expected_v2) / 2, err_msg="Lower voltage at dot isn't as expected.")
numpy.testing.assert_allclose(range_measurement.v_high, (expected_v1 + expected_v2) * 3 / 2, err_msg="Lower oltage at dot isn't as expected.")

View File

@@ -0,0 +1,33 @@
import numpy
import pdme.util.fast_v_calc
def test_fast_v_calc():
d1 = [1, 2, 3, 4, 5, 6, 7]
d2 = [2, 5, 3, 4, -5, -6, 2]
dipoles = numpy.array([d1, d2])
dot_inputs = numpy.array([[-1, -1, -1, 11], [2, 3, 1, 5.5]])
# expected_ij is for dot i, dipole j
expected_11 = 0.00001421963287022476
expected_12 = 0.00001107180225755457
expected_21 = 0.000345021108583681380388722
expected_22 = 0.0000377061050587914705139781
expected = numpy.array([[expected_11, expected_21], [expected_12, expected_22]])
numpy.testing.assert_allclose(pdme.util.fast_v_calc.fast_vs_for_dipoles(dot_inputs, dipoles), expected, err_msg="Voltages at dot aren't as expected.")
def test_between():
low = numpy.array([1, 2, 3])
high = numpy.array([6, 7, 8])
# FALSE FALSE TRUE
a = [[0, 1, 2], [0, 9, 5], [4, 5, 6]]
actual = pdme.util.fast_v_calc.between(a, low, high)
expected = numpy.array([False, False, True])
numpy.testing.assert_array_equal(actual, expected, err_msg="Between calc wrong")