Merge pull request 'newalgorithm' (#8) from newalgorithm into master
All checks were successful
gitea-physics/pdme/pipeline/head This commit looks good
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:
@@ -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']
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
40
pdme/util/fast_v_calc.py
Normal 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)
|
||||
@@ -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.")
|
||||
|
||||
33
tests/util/test_fast_v_calc.py
Normal file
33
tests/util/test_fast_v_calc.py
Normal 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")
|
||||
Reference in New Issue
Block a user