Compare commits
25 Commits
472ff166cc
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
3a73fee801
|
|||
|
c6a5ee637f
|
|||
|
231c5d4b60
|
|||
|
ad0553ce6e
|
|||
|
5726b1d50a
|
|||
|
10b72bfaaa
|
|||
|
69d8befe68
|
|||
|
ca8269b538
|
|||
|
b22a977b9c
|
|||
|
6af5d6f78c
|
|||
|
60e194853e
|
|||
|
2b022927b5
|
|||
|
ba57e32cc5
|
|||
|
4011a5c698
|
|||
|
0e3eddebcc
|
|||
| d31fbb55eb | |||
|
c279f1b470
|
|||
|
359e048531
|
|||
|
7230d37244
|
|||
|
a9c37559f8
|
|||
|
e37849295a
|
|||
|
56e88759fe
|
|||
|
c51c477579
|
|||
|
0c8527704d
|
|||
|
026519697b
|
3
.flake8
3
.flake8
@@ -1,2 +1,3 @@
|
||||
[flake8]
|
||||
ignore = W191
|
||||
ignore = W191, E501
|
||||
max-line-length = 120
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -45,6 +45,7 @@ htmlcov/
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
pytest.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
|
||||
73
Jenkinsfile
vendored
Normal file
73
Jenkinsfile
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
pipeline {
|
||||
agent {
|
||||
kubernetes {
|
||||
label 'pathfinder' // all your pods will be named with this prefix, followed by a unique id
|
||||
idleMinutes 5 // how long the pod will live after no jobs have run on it
|
||||
yamlFile 'jenkins/ci-agent-pod.yaml' // path to the pod definition relative to the root of our project
|
||||
defaultContainer 'python' // define a default container if more than a few stages use it, will default to jnlp container
|
||||
}
|
||||
}
|
||||
|
||||
options {
|
||||
parallelsAlwaysFailFast()
|
||||
}
|
||||
|
||||
environment {
|
||||
POETRY_HOME="/opt/poetry"
|
||||
POETRY_VERSION="1.1.4"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Build') {
|
||||
steps {
|
||||
echo 'Building...'
|
||||
sh 'python --version'
|
||||
sh 'curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python'
|
||||
sh '${POETRY_HOME}/bin/poetry --version'
|
||||
sh '${POETRY_HOME}/bin/poetry install'
|
||||
}
|
||||
}
|
||||
stage('Test') {
|
||||
parallel{
|
||||
stage('pytest') {
|
||||
steps {
|
||||
sh '${POETRY_HOME}/bin/poetry run pytest'
|
||||
}
|
||||
}
|
||||
stage('lint') {
|
||||
steps {
|
||||
sh '${POETRY_HOME}/bin/poetry run flake8'
|
||||
}
|
||||
}
|
||||
stage('mypy') {
|
||||
steps {
|
||||
sh '${POETRY_HOME}/bin/poetry run mypy pathfinder'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
post {
|
||||
always {
|
||||
echo 'This will always run'
|
||||
junit 'pytest.xml'
|
||||
cobertura coberturaReportFile: 'coverage.xml'
|
||||
mail (bcc: '',
|
||||
body: "Project: ${env.JOB_NAME} <br>Build Number: ${env.BUILD_NUMBER} <br> Build URL: ${env.BUILD_URL}", cc: '', charset: 'UTF-8', from: 'jenkins@jenkins.deepak.science', mimeType: 'text/html', replyTo: 'dmallubhotla+jenkins@gmail.com', subject: "${env.JOB_NAME} #${env.BUILD_NUMBER}: Build ${currentBuild.currentResult}", to: "dmallubhotla+ci@gmail.com")
|
||||
}
|
||||
success {
|
||||
echo 'This will run only if successful'
|
||||
}
|
||||
failure {
|
||||
echo 'This will run only if failed'
|
||||
}
|
||||
unstable {
|
||||
echo 'This will run only if the run was marked as unstable'
|
||||
}
|
||||
changed {
|
||||
echo 'This will run only if the state of the Pipeline has changed'
|
||||
echo 'For example, if the Pipeline was previously failing but is now successful'
|
||||
}
|
||||
}
|
||||
}
|
||||
4
do.sh
4
do.sh
@@ -16,6 +16,10 @@ test() {
|
||||
poetry run pytest
|
||||
}
|
||||
|
||||
htmlcov() {
|
||||
poetry run pytest --cov-report=html
|
||||
}
|
||||
|
||||
all() {
|
||||
build && test
|
||||
}
|
||||
|
||||
14
jenkins/ci-agent-pod.yaml
Normal file
14
jenkins/ci-agent-pod.yaml
Normal file
@@ -0,0 +1,14 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
spec:
|
||||
containers: # list of containers that you want present for your build, you can define a default container in the Jenkinsfile
|
||||
- name: python
|
||||
image: python:3.8
|
||||
command: ["tail", "-f", "/dev/null"] # this or any command that is bascially a noop is required, this is so that you don't overwrite the entrypoint of the base container
|
||||
imagePullPolicy: Always # use cache or pull image for agent
|
||||
resources: # limits the resources your build contaienr
|
||||
requests:
|
||||
memory: "2Gi"
|
||||
cpu: "500m"
|
||||
limits:
|
||||
memory: "2Gi"
|
||||
5
pathfinder/model/oscillating/__init__.py
Normal file
5
pathfinder/model/oscillating/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from pathfinder.model.oscillating.oscillating_dipole import OscillatingDipole, OscillatingDipoleArrangement
|
||||
from pathfinder.model.oscillating.dot import DotMeasurement
|
||||
from pathfinder.model.oscillating.model import DotOscillatingDipoleModel
|
||||
|
||||
__all__ = ['DotMeasurement', 'OscillatingDipole', 'OscillatingDipoleArrangement', 'DotOscillatingDipoleModel']
|
||||
87
pathfinder/model/oscillating/dot.py
Normal file
87
pathfinder/model/oscillating/dot.py
Normal file
@@ -0,0 +1,87 @@
|
||||
from dataclasses import dataclass
|
||||
import numpy
|
||||
import numpy.typing
|
||||
|
||||
|
||||
@dataclass
|
||||
class DotMeasurement():
|
||||
'''
|
||||
Representation of a dot measuring oscillating dipoles.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
v : float
|
||||
The voltage measured at the dot.
|
||||
r : numpy.ndarray
|
||||
The position of the dot.
|
||||
f : float
|
||||
The measurement frequency.
|
||||
'''
|
||||
v: float
|
||||
r: numpy.ndarray
|
||||
f: float
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
self.r = numpy.array(self.r)
|
||||
|
||||
def v_for_point(self, pt: numpy.ndarray) -> float:
|
||||
'''
|
||||
Returns the voltage for an oscillating dipole represented as a phase space point.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pt: A length 7 numpy array representing a dipole, as (px, py, pz, sx, sy, sz, w).
|
||||
|
||||
Returns
|
||||
----------
|
||||
Returns the voltage from that dipole at the point.
|
||||
'''
|
||||
p = pt[0:3] # hardcoded here because chances
|
||||
s = pt[3:6] # are we'll only ever work in 3d.
|
||||
w = pt[6]
|
||||
|
||||
return (self._alpha(p, s))**2 * self._b(w)
|
||||
|
||||
def _alpha(self, p: numpy.ndarray, s: numpy.ndarray) -> float:
|
||||
diff = self.r - s
|
||||
return p.dot(diff) / (numpy.linalg.norm(diff)**3)
|
||||
|
||||
def _b(self, w: float) -> float:
|
||||
return (1 / numpy.pi) * (w / (self.f**2 + w**2))
|
||||
|
||||
def cost(self, pts: numpy.ndarray) -> float:
|
||||
# 7 because dipole in 3d has 7 degrees of freedom.
|
||||
pt_length = 7
|
||||
# creates numpy.ndarrays in groups of pt_length.
|
||||
# Will throw problems for irregular points, but that's okay for now.
|
||||
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
|
||||
|
||||
def jac_pt(self, pt: numpy.ndarray) -> numpy.ndarray:
|
||||
p = pt[0:3] # hardcoded here because chances
|
||||
s = pt[3:6] # are we'll only ever work in 3d.
|
||||
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:
|
||||
# 7 because oscillating dipole in 3d has 7 degrees of freedom.
|
||||
pt_length = 7
|
||||
# creates numpy.ndarrays in groups of pt_length.
|
||||
# Will throw problems for irregular points, but that's okay for now.
|
||||
chunked_pts = [pts[i: i + pt_length] for i in range(0, len(pts), pt_length)]
|
||||
|
||||
return numpy.append([], [self.jac_pt(pt) for pt in chunked_pts])
|
||||
45
pathfinder/model/oscillating/model.py
Normal file
45
pathfinder/model/oscillating/model.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from typing import Callable, Sequence
|
||||
import numpy
|
||||
import scipy.optimize
|
||||
from pathfinder.model.oscillating.dot import DotMeasurement
|
||||
import pathfinder.model.oscillating.util
|
||||
|
||||
|
||||
class DotOscillatingDipoleModel():
|
||||
'''
|
||||
Model of n static oscillating with a collection of voltage measurements
|
||||
at dots at different positions and frequencies.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
dots : Sequence[DotMeasurement]
|
||||
A collection of dots representing a series of measured noise spectrum values.
|
||||
n: int
|
||||
The number of dipoles to assume.
|
||||
'''
|
||||
def __init__(self, dots: Sequence[DotMeasurement], n: int) -> None:
|
||||
self.dots = dots
|
||||
self.m = len(dots)
|
||||
self.n = n
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'DotOscillatingDipoleModel({repr(list(self.dots))}, {self.n})'
|
||||
|
||||
def costs(self) -> Callable[[numpy.ndarray], numpy.ndarray]:
|
||||
def costs_to_return(pt: numpy.ndarray) -> numpy.ndarray:
|
||||
return numpy.array([dot.cost(pt) for dot in self.dots])
|
||||
|
||||
return costs_to_return
|
||||
|
||||
def jac(self) -> Callable[[numpy.ndarray], numpy.ndarray]:
|
||||
def jac_to_return(pts: numpy.ndarray) -> numpy.ndarray:
|
||||
return numpy.array([dot.jac(pts) for dot in self.dots])
|
||||
|
||||
return jac_to_return
|
||||
|
||||
def sol(self, initial_dipole=(0.1, 0.1, 0.1), initial_position=(.1, .1, .1), initial_frequency=1, use_root=True):
|
||||
initial = numpy.tile(numpy.concatenate((initial_dipole, initial_position, initial_frequency), axis=None), self.n)
|
||||
|
||||
result = scipy.optimize.least_squares(self.costs(), initial, jac=self.jac(), ftol=1e-15, gtol=3e-16)
|
||||
result.pathfinder_x = pathfinder.model.oscillating.util.normalize_oscillating_dipole_list(result.x)
|
||||
return result
|
||||
77
pathfinder/model/oscillating/oscillating_dipole.py
Normal file
77
pathfinder/model/oscillating/oscillating_dipole.py
Normal file
@@ -0,0 +1,77 @@
|
||||
from dataclasses import dataclass
|
||||
import numpy
|
||||
import numpy.typing
|
||||
from typing import Sequence, List, Tuple
|
||||
from pathfinder.model.oscillating.dot import DotMeasurement
|
||||
|
||||
|
||||
DotInput = Tuple[numpy.typing.ArrayLike, float]
|
||||
|
||||
|
||||
@dataclass
|
||||
class OscillatingDipole():
|
||||
'''
|
||||
Representation of an oscilltaing dipole, either known or guessed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
p : numpy.ndarray
|
||||
The oscillating dipole moment, with overall sign arbitrary.
|
||||
s : numpy.ndarray
|
||||
The position of the dipole.
|
||||
w : float
|
||||
The oscillation frequency.
|
||||
'''
|
||||
p: numpy.ndarray
|
||||
s: numpy.ndarray
|
||||
w: float
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
'''
|
||||
Coerce the inputs into numpy arrays.
|
||||
'''
|
||||
self.p = numpy.array(self.p)
|
||||
self.s = numpy.array(self.s)
|
||||
|
||||
def s_at_position(self, r: numpy.ndarray, f: float) -> float:
|
||||
'''
|
||||
Returns the noise potential at a point r, at some frequency f.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
r : numpy.ndarray
|
||||
The position of the dot.
|
||||
f : float
|
||||
The dot frequency to sample.
|
||||
'''
|
||||
return (self._alpha(r))**2 * self._b(f)
|
||||
|
||||
def _alpha(self, r: numpy.ndarray) -> float:
|
||||
diff = r - self.s
|
||||
return self.p.dot(diff) / (numpy.linalg.norm(diff)**3)
|
||||
|
||||
def _b(self, f: float) -> float:
|
||||
return (1 / numpy.pi) * (self.w / (f**2 + self.w**2))
|
||||
|
||||
|
||||
class OscillatingDipoleArrangement():
|
||||
'''
|
||||
A collection of oscillating dipoles, which we are interested in being able to characterise.
|
||||
|
||||
Parameters
|
||||
--------
|
||||
dipoles : Sequence[OscillatingDipole]
|
||||
'''
|
||||
def __init__(self, dipoles: Sequence[OscillatingDipole]):
|
||||
self.dipoles = dipoles
|
||||
|
||||
def get_dot_measurement(self, dot_input: DotInput) -> DotMeasurement:
|
||||
r = numpy.array(dot_input[0])
|
||||
f = dot_input[1]
|
||||
return DotMeasurement(sum([dipole.s_at_position(r, f) for dipole in self.dipoles]), r, f)
|
||||
|
||||
def get_dot_measurements(self, dot_inputs: Sequence[DotInput]) -> List[DotMeasurement]:
|
||||
'''
|
||||
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]
|
||||
19
pathfinder/model/oscillating/util.py
Normal file
19
pathfinder/model/oscillating/util.py
Normal file
@@ -0,0 +1,19 @@
|
||||
import numpy
|
||||
import operator
|
||||
|
||||
|
||||
# flips px, py, pz
|
||||
SIGN_ARRAY = numpy.array((-1, -1, -1, 1, 1, 1, 1))
|
||||
|
||||
|
||||
def flip_chunk_to_positive_px(pt: numpy.ndarray) -> numpy.ndarray:
|
||||
if pt[0] > 0:
|
||||
return pt
|
||||
else:
|
||||
return SIGN_ARRAY * pt
|
||||
|
||||
|
||||
def normalize_oscillating_dipole_list(pts: numpy.ndarray) -> numpy.ndarray:
|
||||
pt_length = 7
|
||||
chunked_pts = [flip_chunk_to_positive_px(pts[i: i + pt_length]) for i in range(0, len(pts), pt_length)]
|
||||
return numpy.concatenate(sorted(chunked_pts, key=lambda x: tuple(round(val, 3) for val in operator.itemgetter(0, 1, 2, 3, 4, 5, 6)(x))), axis=None)
|
||||
5
pathfinder/model/static/__init__.py
Normal file
5
pathfinder/model/static/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
from pathfinder.model.static.dot import DotMeasurement
|
||||
from pathfinder.model.static.model import DotDipoleModel
|
||||
from pathfinder.model.static.staticdipole import StaticDipoleArrangement, StaticDipole
|
||||
|
||||
__all__ = ['DotMeasurement', 'DotDipoleModel', 'StaticDipoleArrangement', 'StaticDipole']
|
||||
69
pathfinder/model/static/dot.py
Normal file
69
pathfinder/model/static/dot.py
Normal file
@@ -0,0 +1,69 @@
|
||||
from dataclasses import dataclass
|
||||
import numpy
|
||||
import numpy.typing
|
||||
|
||||
|
||||
@dataclass
|
||||
class DotMeasurement():
|
||||
'''
|
||||
Representation of a dot measuring static dipoles.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
v : float
|
||||
The voltage measured at the dot.
|
||||
r : numpy.ndarray
|
||||
The position of the dot.
|
||||
'''
|
||||
v: float
|
||||
r: numpy.ndarray
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
self.r = numpy.array(self.r)
|
||||
|
||||
def v_for_point(self, pt: numpy.ndarray) -> float:
|
||||
'''
|
||||
Returns the voltage for a static dipole represented as a phase space point.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pt: A length 6 numpy array representing a dipole, as (px, py, pz, sx, sy, sz).
|
||||
|
||||
Returns
|
||||
----------
|
||||
Returns the voltage from that dipole at the point.
|
||||
'''
|
||||
p = pt[0:3] # hardcoded here because chances
|
||||
s = pt[3:6] # are we'll only ever work in 3d.
|
||||
|
||||
diff = self.r - s
|
||||
return p.dot(diff) / (numpy.linalg.norm(diff)**3)
|
||||
|
||||
def cost(self, pts: numpy.ndarray) -> float:
|
||||
# 6 because dipole in 3d has 6 degrees of freedom.
|
||||
pt_length = 6
|
||||
# creates numpy.ndarrays in groups of pt_length.
|
||||
# Will throw problems for irregular points, but that's okay for now.
|
||||
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
|
||||
|
||||
def jac_pt(self, pt: numpy.ndarray) -> numpy.ndarray:
|
||||
p = pt[0:3] # hardcoded here because chances
|
||||
s = pt[3:6] # are we'll only ever work in 3d.
|
||||
|
||||
diff = self.r - s
|
||||
|
||||
p_divs = diff / (numpy.linalg.norm(diff)**3)
|
||||
|
||||
r_divs = -p / (numpy.linalg.norm(diff)**3) + 3 * p.dot(diff) * diff / (numpy.linalg.norm(diff)**5)
|
||||
|
||||
return numpy.append(p_divs, r_divs)
|
||||
|
||||
def jac(self, pts: numpy.ndarray) -> numpy.ndarray:
|
||||
# 6 because dipole in 3d has 6 degrees of freedom.
|
||||
pt_length = 6
|
||||
# creates numpy.ndarrays in groups of pt_length.
|
||||
# Will throw problems for irregular points, but that's okay for now.
|
||||
chunked_pts = [pts[i: i + pt_length] for i in range(0, len(pts), pt_length)]
|
||||
|
||||
return numpy.append([], [self.jac_pt(pt) for pt in chunked_pts])
|
||||
44
pathfinder/model/static/model.py
Normal file
44
pathfinder/model/static/model.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from typing import Callable, Sequence
|
||||
import numpy
|
||||
import scipy.optimize
|
||||
from pathfinder.model.static.dot import DotMeasurement
|
||||
|
||||
|
||||
class DotDipoleModel():
|
||||
'''
|
||||
Model of n static dipoles with a collection of voltage measurements
|
||||
at dots at different positions.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
dots : Sequence[Dot]
|
||||
A collection of dots representing a series of measured voltages.
|
||||
n: int
|
||||
The number of dipoles to assume.
|
||||
'''
|
||||
def __init__(self, dots: Sequence[DotMeasurement], n: int) -> None:
|
||||
self.dots = dots
|
||||
self.m = len(dots)
|
||||
self.n = n
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'DotDipoleModel({repr(list(self.dots))}, {self.n})'
|
||||
|
||||
def costs(self) -> Callable[[numpy.ndarray], numpy.ndarray]:
|
||||
def costs_to_return(pt: numpy.ndarray) -> numpy.ndarray:
|
||||
return numpy.array([dot.cost(pt) for dot in self.dots])
|
||||
|
||||
return costs_to_return
|
||||
|
||||
def jac(self) -> Callable[[numpy.ndarray], numpy.ndarray]:
|
||||
def jac_to_return(pts: numpy.ndarray) -> numpy.ndarray:
|
||||
return numpy.array([dot.jac(pts) for dot in self.dots])
|
||||
|
||||
return jac_to_return
|
||||
|
||||
def sol(self, initial_dipole=(0.1, 0.1, 0.1), initial_position=(.1, .1, .1), use_root=True):
|
||||
initial = numpy.tile(numpy.append(initial_dipole, initial_position), self.n)
|
||||
if use_root and self.m == 6 * self.n:
|
||||
# We are perfectly specified
|
||||
return scipy.optimize.root(self.costs(), initial, jac=self.jac(), tol=1e-12)
|
||||
return scipy.optimize.least_squares(self.costs(), initial, jac=self.jac(), ftol=1e-15, gtol=3e-16)
|
||||
58
pathfinder/model/static/staticdipole.py
Normal file
58
pathfinder/model/static/staticdipole.py
Normal file
@@ -0,0 +1,58 @@
|
||||
from dataclasses import dataclass
|
||||
import numpy
|
||||
import numpy.typing
|
||||
from typing import Sequence, List
|
||||
from pathfinder.model.static.dot import DotMeasurement
|
||||
|
||||
|
||||
@dataclass
|
||||
class StaticDipole():
|
||||
'''
|
||||
Representation of a static dipoles, either known or guessed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
p : numpy.ndarray
|
||||
The static dipole moment.
|
||||
s : numpy.ndarray
|
||||
The position of the dipole.
|
||||
'''
|
||||
p: numpy.ndarray
|
||||
s: numpy.ndarray
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
'''
|
||||
Coerce the inputs into numpy arrays.
|
||||
'''
|
||||
self.p = numpy.array(self.p)
|
||||
self.s = numpy.array(self.s)
|
||||
|
||||
def v_at_position(self, r: numpy.ndarray) -> float:
|
||||
'''
|
||||
Mirrors the same function in pathfinder.model.dot.
|
||||
'''
|
||||
diff = r - self.s
|
||||
return self.p.dot(diff) / (numpy.linalg.norm(diff)**3)
|
||||
|
||||
|
||||
class StaticDipoleArrangement():
|
||||
'''
|
||||
A collection of static dipoles, which we are interested in being able to characterise.
|
||||
|
||||
Parameters
|
||||
--------
|
||||
dipoles : Sequence[StaticDipole]
|
||||
'''
|
||||
def __init__(self, dipoles):
|
||||
self.dipoles = dipoles
|
||||
|
||||
def get_dot_measurement(self, dot_position: numpy.typing.ArrayLike) -> DotMeasurement:
|
||||
r = numpy.array(dot_position)
|
||||
return DotMeasurement(sum([dipole.v_at_position(r) for dipole in self.dipoles]), r)
|
||||
|
||||
def get_dot_measurements(self, dot_positions: Sequence[numpy.typing.ArrayLike]) -> List[DotMeasurement]:
|
||||
'''
|
||||
For a series of points, each with three coordinates, return
|
||||
'''
|
||||
|
||||
return [self.get_dot_measurement(dot_position) for dot_position in dot_positions]
|
||||
376
poetry.lock
generated
376
poetry.lock
generated
@@ -1,215 +1,196 @@
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Atomic file writes."
|
||||
marker = "sys_platform == \"win32\""
|
||||
name = "atomicwrites"
|
||||
version = "1.4.0"
|
||||
description = "Atomic file writes."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "1.4.0"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Classes Without Boilerplate"
|
||||
name = "attrs"
|
||||
version = "21.2.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "21.2.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
|
||||
dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
|
||||
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
|
||||
tests = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
|
||||
tests_no_zope = ["coverage (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
|
||||
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
|
||||
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Cross-platform colored terminal text."
|
||||
marker = "sys_platform == \"win32\""
|
||||
name = "colorama"
|
||||
version = "0.4.4"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "0.4.4"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Code coverage measurement for Python"
|
||||
name = "coverage"
|
||||
version = "5.5"
|
||||
description = "Code coverage measurement for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||
version = "5.5"
|
||||
|
||||
[package.extras]
|
||||
toml = ["toml"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "the modular source code checker: pep8 pyflakes and co"
|
||||
name = "flake8"
|
||||
version = "3.9.2"
|
||||
description = "the modular source code checker: pep8 pyflakes and co"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
version = "3.9.2"
|
||||
|
||||
[package.dependencies]
|
||||
mccabe = ">=0.6.0,<0.7.0"
|
||||
pycodestyle = ">=2.7.0,<2.8.0"
|
||||
pyflakes = ">=2.3.0,<2.4.0"
|
||||
|
||||
[package.dependencies.importlib-metadata]
|
||||
python = "<3.8"
|
||||
version = "*"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Read metadata from Python packages"
|
||||
marker = "python_version < \"3.8\""
|
||||
name = "importlib-metadata"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
version = "4.6.1"
|
||||
|
||||
[package.dependencies]
|
||||
zipp = ">=0.5"
|
||||
|
||||
[package.dependencies.typing-extensions]
|
||||
python = "<3.8"
|
||||
version = ">=3.6.4"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||
perf = ["ipython"]
|
||||
testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "iniconfig: brain-dead simple config-ini parsing"
|
||||
name = "iniconfig"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.1.1"
|
||||
|
||||
[[package]]
|
||||
description = "iniconfig: brain-dead simple config-ini parsing"
|
||||
category = "dev"
|
||||
description = "McCabe checker, plugin for flake8"
|
||||
name = "mccabe"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.6.1"
|
||||
|
||||
[[package]]
|
||||
name = "mccabe"
|
||||
version = "0.6.1"
|
||||
description = "McCabe checker, plugin for flake8"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "more-itertools"
|
||||
version = "8.8.0"
|
||||
description = "More routines for operating on iterables, beyond itertools"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "0.910"
|
||||
description = "Optional static typing for Python"
|
||||
category = "dev"
|
||||
description = "Optional static typing for Python"
|
||||
name = "mypy"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
version = "0.790"
|
||||
|
||||
[package.dependencies]
|
||||
mypy-extensions = ">=0.4.3,<0.5.0"
|
||||
typed-ast = ">=1.4.0,<1.5.0"
|
||||
toml = "*"
|
||||
typing-extensions = ">=3.7.4"
|
||||
|
||||
[package.extras]
|
||||
dmypy = ["psutil (>=4.0)"]
|
||||
python2 = ["typed-ast (>=1.4.0,<1.5.0)"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Experimental type system extensions for programs checked with the mypy typechecker."
|
||||
name = "mypy-extensions"
|
||||
version = "0.4.3"
|
||||
description = "Experimental type system extensions for programs checked with the mypy typechecker."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "0.4.3"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Core utilities for Python packages"
|
||||
name = "numpy"
|
||||
version = "1.21.1"
|
||||
description = "NumPy is the fundamental package for array computing with Python."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "21.0"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
version = "21.0"
|
||||
|
||||
[package.dependencies]
|
||||
pyparsing = ">=2.0.2"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
name = "pluggy"
|
||||
version = "0.13.1"
|
||||
description = "plugin and hook calling mechanisms for python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "0.13.1"
|
||||
|
||||
[package.dependencies]
|
||||
[package.dependencies.importlib-metadata]
|
||||
python = "<3.8"
|
||||
version = ">=0.12"
|
||||
|
||||
[package.extras]
|
||||
dev = ["pre-commit", "tox"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||
name = "py"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "1.10.0"
|
||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Python style guide checker"
|
||||
name = "pycodestyle"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "2.7.0"
|
||||
|
||||
[[package]]
|
||||
description = "Python style guide checker"
|
||||
category = "dev"
|
||||
description = "passive checker of Python programs"
|
||||
name = "pyflakes"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
version = "2.3.1"
|
||||
|
||||
[[package]]
|
||||
name = "pyflakes"
|
||||
version = "2.3.1"
|
||||
description = "passive checker of Python programs"
|
||||
category = "dev"
|
||||
description = "Python parsing module"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "2.4.7"
|
||||
description = "Python parsing module"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
version = "2.4.7"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
name = "pytest"
|
||||
version = "6.2.4"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
version = "6.2.4"
|
||||
|
||||
[package.dependencies]
|
||||
atomicwrites = ">=1.0"
|
||||
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
|
||||
attrs = ">=19.2.0"
|
||||
colorama = "*"
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=0.12,<1.0.0a1"
|
||||
py = ">=1.8.2"
|
||||
toml = "*"
|
||||
|
||||
[package.dependencies.importlib-metadata]
|
||||
python = "<3.8"
|
||||
version = ">=0.12"
|
||||
|
||||
[package.extras]
|
||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Pytest plugin for measuring coverage."
|
||||
name = "pytest-cov"
|
||||
version = "2.12.1"
|
||||
description = "Pytest plugin for measuring coverage."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
version = "2.12.1"
|
||||
|
||||
[package.dependencies]
|
||||
coverage = ">=5.2.1"
|
||||
@@ -220,45 +201,36 @@ toml = "*"
|
||||
testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"]
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||
name = "toml"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
version = "0.10.2"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "a fork of Python 2 and 3 ast modules with type comment support"
|
||||
name = "typed-ast"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "1.4.3"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Backported and Experimental Type Hints for Python 3.5+"
|
||||
name = "typing-extensions"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
version = "3.10.0.0"
|
||||
|
||||
[[package]]
|
||||
category = "dev"
|
||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||
marker = "python_version < \"3.8\""
|
||||
name = "zipp"
|
||||
name = "scipy"
|
||||
version = "1.5.4"
|
||||
description = "SciPy: Scientific Library for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
version = "3.5.0"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
|
||||
testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
|
||||
[package.dependencies]
|
||||
numpy = ">=1.14.5"
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.10.2"
|
||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "3.10.0.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.5+"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[metadata]
|
||||
content-hash = "b3de1ca8a251edc8dae2c93e878deb3131846055ac2a6d6b34e43ea20a8f1ea2"
|
||||
python-versions = "^3.7"
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.8,<3.10"
|
||||
content-hash = "daffa6e91d6921845be603d5c0565d1afb511a57bb9a2f4b9c1084754b7a5314"
|
||||
|
||||
[metadata.files]
|
||||
atomicwrites = [
|
||||
@@ -331,10 +303,6 @@ flake8 = [
|
||||
{file = "flake8-3.9.2-py2.py3-none-any.whl", hash = "sha256:bf8fd333346d844f616e8d47905ef3a3384edae6b4e9beb0c5101e25e3110907"},
|
||||
{file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"},
|
||||
]
|
||||
importlib-metadata = [
|
||||
{file = "importlib_metadata-4.6.1-py3-none-any.whl", hash = "sha256:9f55f560e116f8643ecf2922d9cd3e1c7e8d52e683178fecd9d08f6aa357e11e"},
|
||||
{file = "importlib_metadata-4.6.1.tar.gz", hash = "sha256:079ada16b7fc30dfbb5d13399a5113110dab1aa7c2bc62f66af75f0b717c8cac"},
|
||||
]
|
||||
iniconfig = [
|
||||
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
||||
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
||||
@@ -343,26 +311,69 @@ mccabe = [
|
||||
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
|
||||
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
|
||||
]
|
||||
more-itertools = [
|
||||
{file = "more-itertools-8.8.0.tar.gz", hash = "sha256:83f0308e05477c68f56ea3a888172c78ed5d5b3c282addb67508e7ba6c8f813a"},
|
||||
{file = "more_itertools-8.8.0-py3-none-any.whl", hash = "sha256:2cf89ec599962f2ddc4d568a05defc40e0a587fbc10d5989713638864c36be4d"},
|
||||
]
|
||||
mypy = [
|
||||
{file = "mypy-0.790-cp35-cp35m-macosx_10_6_x86_64.whl", hash = "sha256:bd03b3cf666bff8d710d633d1c56ab7facbdc204d567715cb3b9f85c6e94f669"},
|
||||
{file = "mypy-0.790-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:2170492030f6faa537647d29945786d297e4862765f0b4ac5930ff62e300d802"},
|
||||
{file = "mypy-0.790-cp35-cp35m-win_amd64.whl", hash = "sha256:e86bdace26c5fe9cf8cb735e7cedfe7850ad92b327ac5d797c656717d2ca66de"},
|
||||
{file = "mypy-0.790-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e97e9c13d67fbe524be17e4d8025d51a7dca38f90de2e462243ab8ed8a9178d1"},
|
||||
{file = "mypy-0.790-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0d34d6b122597d48a36d6c59e35341f410d4abfa771d96d04ae2c468dd201abc"},
|
||||
{file = "mypy-0.790-cp36-cp36m-win_amd64.whl", hash = "sha256:72060bf64f290fb629bd4a67c707a66fd88ca26e413a91384b18db3876e57ed7"},
|
||||
{file = "mypy-0.790-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:eea260feb1830a627fb526d22fbb426b750d9f5a47b624e8d5e7e004359b219c"},
|
||||
{file = "mypy-0.790-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:c614194e01c85bb2e551c421397e49afb2872c88b5830e3554f0519f9fb1c178"},
|
||||
{file = "mypy-0.790-cp37-cp37m-win_amd64.whl", hash = "sha256:0a0d102247c16ce93c97066443d11e2d36e6cc2a32d8ccc1f705268970479324"},
|
||||
{file = "mypy-0.790-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cf4e7bf7f1214826cf7333627cb2547c0db7e3078723227820d0a2490f117a01"},
|
||||
{file = "mypy-0.790-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:af4e9ff1834e565f1baa74ccf7ae2564ae38c8df2a85b057af1dbbc958eb6666"},
|
||||
{file = "mypy-0.790-cp38-cp38-win_amd64.whl", hash = "sha256:da56dedcd7cd502ccd3c5dddc656cb36113dd793ad466e894574125945653cea"},
|
||||
{file = "mypy-0.790-py3-none-any.whl", hash = "sha256:2842d4fbd1b12ab422346376aad03ff5d0805b706102e475e962370f874a5122"},
|
||||
{file = "mypy-0.790.tar.gz", hash = "sha256:2b21ba45ad9ef2e2eb88ce4aeadd0112d0f5026418324176fd494a6824b74975"},
|
||||
{file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"},
|
||||
{file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"},
|
||||
{file = "mypy-0.910-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9"},
|
||||
{file = "mypy-0.910-cp35-cp35m-win_amd64.whl", hash = "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e"},
|
||||
{file = "mypy-0.910-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921"},
|
||||
{file = "mypy-0.910-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6"},
|
||||
{file = "mypy-0.910-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212"},
|
||||
{file = "mypy-0.910-cp36-cp36m-win_amd64.whl", hash = "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885"},
|
||||
{file = "mypy-0.910-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0"},
|
||||
{file = "mypy-0.910-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de"},
|
||||
{file = "mypy-0.910-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703"},
|
||||
{file = "mypy-0.910-cp37-cp37m-win_amd64.whl", hash = "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a"},
|
||||
{file = "mypy-0.910-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504"},
|
||||
{file = "mypy-0.910-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9"},
|
||||
{file = "mypy-0.910-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072"},
|
||||
{file = "mypy-0.910-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811"},
|
||||
{file = "mypy-0.910-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e"},
|
||||
{file = "mypy-0.910-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b"},
|
||||
{file = "mypy-0.910-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2"},
|
||||
{file = "mypy-0.910-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97"},
|
||||
{file = "mypy-0.910-cp39-cp39-win_amd64.whl", hash = "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8"},
|
||||
{file = "mypy-0.910-py3-none-any.whl", hash = "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"},
|
||||
{file = "mypy-0.910.tar.gz", hash = "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150"},
|
||||
]
|
||||
mypy-extensions = [
|
||||
{file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
|
||||
{file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
|
||||
]
|
||||
numpy = [
|
||||
{file = "numpy-1.21.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50"},
|
||||
{file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a"},
|
||||
{file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a75b4498b1e93d8b700282dc8e655b8bd559c0904b3910b144646dbbbc03e062"},
|
||||
{file = "numpy-1.21.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1412aa0aec3e00bc23fbb8664d76552b4efde98fb71f60737c83efbac24112f1"},
|
||||
{file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e46ceaff65609b5399163de5893d8f2a82d3c77d5e56d976c8b5fb01faa6b671"},
|
||||
{file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c6a2324085dd52f96498419ba95b5777e40b6bcbc20088fddb9e8cbb58885e8e"},
|
||||
{file = "numpy-1.21.1-cp37-cp37m-win32.whl", hash = "sha256:73101b2a1fef16602696d133db402a7e7586654682244344b8329cdcbbb82172"},
|
||||
{file = "numpy-1.21.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7a708a79c9a9d26904d1cca8d383bf869edf6f8e7650d85dbc77b041e8c5a0f8"},
|
||||
{file = "numpy-1.21.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95b995d0c413f5d0428b3f880e8fe1660ff9396dcd1f9eedbc311f37b5652e16"},
|
||||
{file = "numpy-1.21.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:635e6bd31c9fb3d475c8f44a089569070d10a9ef18ed13738b03049280281267"},
|
||||
{file = "numpy-1.21.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a3d5fb89bfe21be2ef47c0614b9c9c707b7362386c9a3ff1feae63e0267ccb6"},
|
||||
{file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a326af80e86d0e9ce92bcc1e65c8ff88297de4fa14ee936cb2293d414c9ec63"},
|
||||
{file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:791492091744b0fe390a6ce85cc1bf5149968ac7d5f0477288f78c89b385d9af"},
|
||||
{file = "numpy-1.21.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0318c465786c1f63ac05d7c4dbcecd4d2d7e13f0959b01b534ea1e92202235c5"},
|
||||
{file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a513bd9c1551894ee3d31369f9b07460ef223694098cf27d399513415855b68"},
|
||||
{file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91c6f5fc58df1e0a3cc0c3a717bb3308ff850abdaa6d2d802573ee2b11f674a8"},
|
||||
{file = "numpy-1.21.1-cp38-cp38-win32.whl", hash = "sha256:978010b68e17150db8765355d1ccdd450f9fc916824e8c4e35ee620590e234cd"},
|
||||
{file = "numpy-1.21.1-cp38-cp38-win_amd64.whl", hash = "sha256:9749a40a5b22333467f02fe11edc98f022133ee1bfa8ab99bda5e5437b831214"},
|
||||
{file = "numpy-1.21.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d7a4aeac3b94af92a9373d6e77b37691b86411f9745190d2c351f410ab3a791f"},
|
||||
{file = "numpy-1.21.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9e7912a56108aba9b31df688a4c4f5cb0d9d3787386b87d504762b6754fbb1b"},
|
||||
{file = "numpy-1.21.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:25b40b98ebdd272bc3020935427a4530b7d60dfbe1ab9381a39147834e985eac"},
|
||||
{file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a92c5aea763d14ba9d6475803fc7904bda7decc2a0a68153f587ad82941fec1"},
|
||||
{file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05a0f648eb28bae4bcb204e6fd14603de2908de982e761a2fc78efe0f19e96e1"},
|
||||
{file = "numpy-1.21.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f01f28075a92eede918b965e86e8f0ba7b7797a95aa8d35e1cc8821f5fc3ad6a"},
|
||||
{file = "numpy-1.21.1-cp39-cp39-win32.whl", hash = "sha256:88c0b89ad1cc24a5efbb99ff9ab5db0f9a86e9cc50240177a571fbe9c2860ac2"},
|
||||
{file = "numpy-1.21.1-cp39-cp39-win_amd64.whl", hash = "sha256:01721eefe70544d548425a07c80be8377096a54118070b8a62476866d5208e33"},
|
||||
{file = "numpy-1.21.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d4d1de6e6fb3d28781c73fbde702ac97f03d79e4ffd6598b880b2d95d62ead4"},
|
||||
{file = "numpy-1.21.1.zip", hash = "sha256:dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd"},
|
||||
]
|
||||
packaging = [
|
||||
{file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"},
|
||||
{file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"},
|
||||
@@ -395,48 +406,39 @@ pytest-cov = [
|
||||
{file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"},
|
||||
{file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"},
|
||||
]
|
||||
scipy = [
|
||||
{file = "scipy-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4f12d13ffbc16e988fa40809cbbd7a8b45bc05ff6ea0ba8e3e41f6f4db3a9e47"},
|
||||
{file = "scipy-1.5.4-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a254b98dbcc744c723a838c03b74a8a34c0558c9ac5c86d5561703362231107d"},
|
||||
{file = "scipy-1.5.4-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:368c0f69f93186309e1b4beb8e26d51dd6f5010b79264c0f1e9ca00cd92ea8c9"},
|
||||
{file = "scipy-1.5.4-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:4598cf03136067000855d6b44d7a1f4f46994164bcd450fb2c3d481afc25dd06"},
|
||||
{file = "scipy-1.5.4-cp36-cp36m-win32.whl", hash = "sha256:e98d49a5717369d8241d6cf33ecb0ca72deee392414118198a8e5b4c35c56340"},
|
||||
{file = "scipy-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:65923bc3809524e46fb7eb4d6346552cbb6a1ffc41be748535aa502a2e3d3389"},
|
||||
{file = "scipy-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9ad4fcddcbf5dc67619379782e6aeef41218a79e17979aaed01ed099876c0e62"},
|
||||
{file = "scipy-1.5.4-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f87b39f4d69cf7d7529d7b1098cb712033b17ea7714aed831b95628f483fd012"},
|
||||
{file = "scipy-1.5.4-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:25b241034215247481f53355e05f9e25462682b13bd9191359075682adcd9554"},
|
||||
{file = "scipy-1.5.4-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:fa789583fc94a7689b45834453fec095245c7e69c58561dc159b5d5277057e4c"},
|
||||
{file = "scipy-1.5.4-cp37-cp37m-win32.whl", hash = "sha256:d6d25c41a009e3c6b7e757338948d0076ee1dd1770d1c09ec131f11946883c54"},
|
||||
{file = "scipy-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:2c872de0c69ed20fb1a9b9cf6f77298b04a26f0b8720a5457be08be254366c6e"},
|
||||
{file = "scipy-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e360cb2299028d0b0d0f65a5c5e51fc16a335f1603aa2357c25766c8dab56938"},
|
||||
{file = "scipy-1.5.4-cp38-cp38-manylinux1_i686.whl", hash = "sha256:3397c129b479846d7eaa18f999369a24322d008fac0782e7828fa567358c36ce"},
|
||||
{file = "scipy-1.5.4-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:168c45c0c32e23f613db7c9e4e780bc61982d71dcd406ead746c7c7c2f2004ce"},
|
||||
{file = "scipy-1.5.4-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:213bc59191da2f479984ad4ec39406bf949a99aba70e9237b916ce7547b6ef42"},
|
||||
{file = "scipy-1.5.4-cp38-cp38-win32.whl", hash = "sha256:634568a3018bc16a83cda28d4f7aed0d803dd5618facb36e977e53b2df868443"},
|
||||
{file = "scipy-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:b03c4338d6d3d299e8ca494194c0ae4f611548da59e3c038813f1a43976cb437"},
|
||||
{file = "scipy-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3d5db5d815370c28d938cf9b0809dade4acf7aba57eaf7ef733bfedc9b2474c4"},
|
||||
{file = "scipy-1.5.4-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6b0ceb23560f46dd236a8ad4378fc40bad1783e997604ba845e131d6c680963e"},
|
||||
{file = "scipy-1.5.4-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:ed572470af2438b526ea574ff8f05e7f39b44ac37f712105e57fc4d53a6fb660"},
|
||||
{file = "scipy-1.5.4-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8c8d6ca19c8497344b810b0b0344f8375af5f6bb9c98bd42e33f747417ab3f57"},
|
||||
{file = "scipy-1.5.4-cp39-cp39-win32.whl", hash = "sha256:d84cadd7d7998433334c99fa55bcba0d8b4aeff0edb123b2a1dfcface538e474"},
|
||||
{file = "scipy-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:cc1f78ebc982cd0602c9a7615d878396bec94908db67d4ecddca864d049112f2"},
|
||||
{file = "scipy-1.5.4.tar.gz", hash = "sha256:4a453d5e5689de62e5d38edf40af3f17560bfd63c9c5bd228c18c1f99afa155b"},
|
||||
]
|
||||
toml = [
|
||||
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
|
||||
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
|
||||
]
|
||||
typed-ast = [
|
||||
{file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"},
|
||||
{file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"},
|
||||
{file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"},
|
||||
{file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"},
|
||||
{file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"},
|
||||
{file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"},
|
||||
{file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"},
|
||||
{file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"},
|
||||
{file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"},
|
||||
{file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"},
|
||||
]
|
||||
typing-extensions = [
|
||||
{file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"},
|
||||
{file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"},
|
||||
{file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"},
|
||||
]
|
||||
zipp = [
|
||||
{file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"},
|
||||
{file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"},
|
||||
]
|
||||
|
||||
@@ -5,14 +5,32 @@ description = ""
|
||||
authors = ["Deepak <dmallubhotla+github@gmail.com>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.7"
|
||||
python = "^3.8,<3.10"
|
||||
numpy = "^1.21.1"
|
||||
scipy = "~1.5"
|
||||
more-itertools = "^8.8.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest = ">=6"
|
||||
flake8 = "^3.8.4"
|
||||
pytest-cov = "^2.10.1"
|
||||
mypy = "^0.790"
|
||||
mypy = "^0.910"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=0.12"]
|
||||
build-backend = "poetry.masonry.api"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
addopts = "--junitxml pytest.xml --cov pathfinder --cov-report=xml:coverage.xml --cov-fail-under=90 --cov-report=html"
|
||||
junit_family = "xunit1"
|
||||
|
||||
[tool.mypy]
|
||||
plugins = "numpy.typing.mypy_plugin"
|
||||
|
||||
[[tool.mypy.overrides]]
|
||||
module = [
|
||||
"scipy",
|
||||
"scipy.optimize"
|
||||
]
|
||||
ignore_missing_imports = true
|
||||
|
||||
29
scripts/patch.sh
Normal file
29
scripts/patch.sh
Normal file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
if [ -z "$(git status --porcelain)" ]; then
|
||||
# Working directory clean
|
||||
branch_name=$(git symbolic-ref -q HEAD)
|
||||
branch_name=${branch_name##refs/heads/}
|
||||
branch_name=${branch_name:-HEAD}
|
||||
|
||||
poetry version patch
|
||||
version=`sed 's/version = "\([0-9]*.[0-9]*.[0-9]*\)"/\1/p' -n <pyproject.toml`
|
||||
read -p "Create commit for version $version? " -n 1 -r
|
||||
echo # (optional) move to a new line
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||
then
|
||||
# do dangerous stuff
|
||||
echo "Creating a new patch"
|
||||
git add pyproject.toml
|
||||
git commit -m "Created version $version"
|
||||
git tag -a "$version" -m "patch.sh created version $version"
|
||||
git push --tags
|
||||
else
|
||||
echo "Surrendering, clean up by reverting pyproject.toml..."
|
||||
exit 2
|
||||
fi
|
||||
else
|
||||
echo "Can't create patch version, working tree unclean..."
|
||||
exit 1
|
||||
fi
|
||||
109
tests/model/oscillating/test_osc_model_sol.py
Normal file
109
tests/model/oscillating/test_osc_model_sol.py
Normal file
@@ -0,0 +1,109 @@
|
||||
import numpy
|
||||
import pathfinder.model.oscillating
|
||||
|
||||
|
||||
def chunk_n_sort(pts):
|
||||
pt_length = 7
|
||||
chunked_pts = [pts[i: i + pt_length] for i in range(0, len(pts), pt_length)]
|
||||
|
||||
return chunked_pts
|
||||
|
||||
|
||||
def print_result(msg, result):
|
||||
print(msg)
|
||||
print(f"\tResult: {result.pathfinder_x}")
|
||||
print(f"\tSuccess: {result.success}. {result.message}")
|
||||
try:
|
||||
print(f"\tFunc evals: {result.nfev}")
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
print(f"\tJacb evals: {result.njev}")
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
def test_one_dipole_six_dot_two_frequencies():
|
||||
# setup
|
||||
dot_inputs = [
|
||||
([0, 0, .01], 5), ([-1, 0, -.01], 5), ([-2, 0, -.01], 5), ([0, -1, .01], 5), ([-1, -1, 0], 5), ([-2, -1, 0], 5),
|
||||
([0, 0, .01], 1), ([-1, 0, -.01], 1), ([-2, 0, -.01], 1), ([0, -1, .01], 1), ([-1, -1, 0], 1), ([-2, -1, 0], 1),
|
||||
]
|
||||
dipole = pathfinder.model.oscillating.OscillatingDipole([1, 2, 3], [0, 4, -1], 7)
|
||||
expected_result = numpy.array([1, 2, 3, 0, 4, -1, 7])
|
||||
dipole_arrangement = pathfinder.model.oscillating.OscillatingDipoleArrangement([dipole])
|
||||
dot_measurements = dipole_arrangement.get_dot_measurements(dot_inputs)
|
||||
|
||||
model = pathfinder.model.oscillating.DotOscillatingDipoleModel(dot_measurements, 1)
|
||||
res = model.sol()
|
||||
|
||||
print_result("one oscillating dipole six dots", res)
|
||||
assert res.success, "The solution for a single dipole and six dots should have succeeded."
|
||||
numpy.testing.assert_allclose(res.pathfinder_x, expected_result, err_msg="Dipole wasn't as expected.", rtol=1e-6, atol=1e-6)
|
||||
|
||||
|
||||
def test_two_dipole_six_dot_two_frequencies():
|
||||
# setup
|
||||
dot_inputs = [
|
||||
([0, 0, .01], 5), ([-1, 0, -.01], 5), ([-2, 0, -.01], 5), ([0, -1, .01], 5), ([-1, -1, 0], 5), ([-2, -1, 0], 5),
|
||||
([0, -2, .01], 5), ([-1, -2, -.01], 5), ([-2, -2, -.01], 5), ([0, -3, .01], 5), ([-1, -3, 0], 5), ([-2, -3, 0], 5),
|
||||
([0, 0, .01], 1), ([-1, 0, -.01], 1), ([-2, 0, -.01], 1), ([0, -1, .01], 1), ([-1, -1, 0], 1), ([-2, -1, 0], 1),
|
||||
([0, -2, .01], 1), ([-1, -2, -.01], 1), ([-2, -2, -.01], 1), ([0, -3, .01], 1), ([-1, -3, 0], 1), ([-2, -3, 0], 1),
|
||||
]
|
||||
dipole = pathfinder.model.oscillating.OscillatingDipole([1, 2, 3], [0, 4, -1], 7)
|
||||
dipole2 = pathfinder.model.oscillating.OscillatingDipole([-1, 2, 0], [2, -1, 1], 4)
|
||||
expected_result = numpy.array([1, -2, 0, 2, -1, 1, 4, 1, 2, 3, 0, 4, -1, 7])
|
||||
dipole_arrangement = pathfinder.model.oscillating.OscillatingDipoleArrangement([dipole, dipole2])
|
||||
dot_measurements = dipole_arrangement.get_dot_measurements(dot_inputs)
|
||||
|
||||
model = pathfinder.model.oscillating.DotOscillatingDipoleModel(dot_measurements, 2)
|
||||
res = model.sol()
|
||||
|
||||
print_result("two oscillating dipole six dots", res)
|
||||
assert res.success, "The solution for two dipole and six dots should have succeeded."
|
||||
numpy.testing.assert_allclose(res.pathfinder_x, expected_result, err_msg="Dipole wasn't as expected.", rtol=1e-6, atol=1e-6)
|
||||
|
||||
|
||||
def test_two_dipole_six_dot_two_frequencies_morerealistic():
|
||||
# setup
|
||||
dot_inputs = [
|
||||
([0, 0, .01], 5), ([-1, 0, -.01], 5), ([-2, 0, -.01], 5), ([-3, 0, 0], 5), ([0, -1, .01], 5), ([-1, -1, 0], 5), ([-2, -1, 0], 5), ([-3, -1, 0], 5),
|
||||
([0, -2, .01], 5), ([-1, -2, -.01], 5), ([-2, -2, -.01], 5), ([-3, -2, 0], 5), ([0, -3, .01], 5), ([-1, -3, 0], 5), ([-2, -3, 0], 5), ([-3, -3, 0], 5),
|
||||
([0, 0, .01], 1), ([-1, 0, -.01], 1), ([-2, 0, -.01], 1), ([-3, 0, 0], 1), ([0, -1, .01], 1), ([-1, -1, 0], 1), ([-2, -1, 0], 1), ([-3, -1, 0], 1),
|
||||
([0, -2, .01], 1), ([-1, -2, -.01], 1), ([-2, -2, -.01], 1), ([-3, -2, 0], 1), ([0, -3, .01], 1), ([-1, -3, 0], 1), ([-2, -3, 0], 1), ([-3, -3, 0], 1),
|
||||
]
|
||||
dipole = pathfinder.model.oscillating.OscillatingDipole([1, 2, 3], [0, 4, -1], 7)
|
||||
dipole2 = pathfinder.model.oscillating.OscillatingDipole([-1, 2, 0], [-1, 2, 1], 4)
|
||||
expected_result = numpy.array([1, -2, 0, -1, 2, 1, 4, 1, 2, 3, 0, 4, -1, 7])
|
||||
dipole_arrangement = pathfinder.model.oscillating.OscillatingDipoleArrangement([dipole, dipole2])
|
||||
dot_measurements = dipole_arrangement.get_dot_measurements(dot_inputs)
|
||||
|
||||
model = pathfinder.model.oscillating.DotOscillatingDipoleModel(dot_measurements, 2)
|
||||
res = model.sol()
|
||||
|
||||
print_result("two oscillating dipole six dots", res)
|
||||
numpy.testing.assert_allclose(res.pathfinder_x, expected_result, err_msg="Dipole wasn't as expected.", rtol=1e-6, atol=1e-6)
|
||||
|
||||
|
||||
def test_two_dipole_eighteen_dot_two_frequencies_morerealistic():
|
||||
# setup
|
||||
dot_inputs = [
|
||||
([0, 0, .01], 5), ([-1, 0, -.01], 5), ([-2, 0, -.01], 5), ([0, -1, .01], 5), ([-1, -1, 0], 5), ([-2, -1, 0], 5),
|
||||
([0, -2, .01], 5), ([-1, -2, -.01], 5), ([-2, -2, -.01], 5), ([0, -3, .01], 5), ([-1, -3, 0], 5), ([-2, -3, 0], 5),
|
||||
([0, -4, .01], 5), ([-1, -4, -.01], 5), ([-2, -4, -.01], 5), ([0, -5, .01], 5), ([-1, -5, 0], 5), ([-2, -5, 0], 5),
|
||||
([0, 0, .01], 1), ([-1, 0, -.01], 1), ([-2, 0, -.01], 1), ([0, -1, .01], 1), ([-1, -1, 0], 1), ([-2, -1, 0], 1),
|
||||
([0, -2, .01], 1), ([-1, -2, -.01], 1), ([-2, -2, -.01], 1), ([0, -3, .01], 1), ([-1, -3, 0], 1), ([-2, -3, 0], 1),
|
||||
([0, -4, .01], 1), ([-1, -4, -.01], 1), ([-2, -4, -.01], 1), ([0, -5, .01], 1), ([-1, -5, 0], 1), ([-2, -5, 0], 1),
|
||||
]
|
||||
dipole = pathfinder.model.oscillating.OscillatingDipole([1, 2, 3], [0, 4, -1], 7)
|
||||
dipole2 = pathfinder.model.oscillating.OscillatingDipole([-1, 2, 0], [-1, 2, 1], 4)
|
||||
expected_result = numpy.array([1, -2, 0, -1, 2, 1, 4, 1, 2, 3, 0, 4, -1, 7])
|
||||
dipole_arrangement = pathfinder.model.oscillating.OscillatingDipoleArrangement([dipole, dipole2])
|
||||
dot_measurements = dipole_arrangement.get_dot_measurements(dot_inputs)
|
||||
|
||||
model = pathfinder.model.oscillating.DotOscillatingDipoleModel(dot_measurements, 2)
|
||||
res = model.sol()
|
||||
|
||||
print_result("two oscillating dipole six dots", res)
|
||||
assert res.success, "The solution for two dipole and six dots should have succeeded."
|
||||
numpy.testing.assert_allclose(res.pathfinder_x, expected_result, err_msg="Dipole wasn't as expected.", rtol=1e-6, atol=1e-6)
|
||||
43
tests/model/oscillating/test_oscdot.py
Normal file
43
tests/model/oscillating/test_oscdot.py
Normal file
@@ -0,0 +1,43 @@
|
||||
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
|
||||
]
|
||||
|
||||
expected_jac2 = [
|
||||
-4.428720903021825e-6, 3.5429767224174605e-6, 4.428720903021825e-6,
|
||||
-6.804125751006259e-6, -4.0261099118380183e-7, 2.3754048479844336e-6,
|
||||
5.181603456535536e-6
|
||||
]
|
||||
|
||||
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))
|
||||
pt2 = numpy.array((2, 5, 3, 4, -5, -6, 2))
|
||||
pts = numpy.append(pt, pt2)
|
||||
expected_jac_all = expected_jac + expected_jac2
|
||||
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), expected_jac_all, err_msg="whole row should match")
|
||||
22
tests/model/oscillating/test_oscillatingdipole.py
Normal file
22
tests/model/oscillating/test_oscillatingdipole.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import numpy
|
||||
import pathfinder.model.oscillating as model
|
||||
|
||||
|
||||
def test_static_dipole():
|
||||
d1 = model.OscillatingDipole((1, 2, 3), (4, 5, 6), 7)
|
||||
d2 = model.OscillatingDipole((2, 5, 3), (4, -5, -6), 2)
|
||||
dipoles = model.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.")
|
||||
|
||||
dot_measurements = dipoles.get_dot_measurements([(dot_position1, dot_frequency1)])
|
||||
assert len(dot_measurements) == 1, "Should have only had one dot measurement."
|
||||
measurement = dot_measurements[0]
|
||||
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.")
|
||||
35
tests/model/oscillating/test_oscmodel.py
Normal file
35
tests/model/oscillating/test_oscmodel.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import numpy
|
||||
import pathfinder.model.oscillating as model
|
||||
|
||||
|
||||
def test_dotdipolemodel_repr():
|
||||
mod = model.DotOscillatingDipoleModel((), 1)
|
||||
assert repr(mod) == "DotOscillatingDipoleModel([], 1)"
|
||||
|
||||
|
||||
def test_dotdipolemodel_m():
|
||||
mod = model.DotOscillatingDipoleModel([model.DotMeasurement(1, (-1, -1, -1), 11), model.DotMeasurement(2, (0, 0, 0), 3)], 1)
|
||||
assert mod.m == 2
|
||||
|
||||
|
||||
def test_dotdipolemodel_cost():
|
||||
mod = model.DotOscillatingDipoleModel([model.DotMeasurement(.05, (-1, -1, -1), 11), model.DotMeasurement(.002, (0, 0, 0), 3)], 1)
|
||||
costs = mod.costs()
|
||||
jac = mod.jac()
|
||||
|
||||
pt_to_test = numpy.array((1, 2, 3, 4, 5, 6, 7))
|
||||
expected_cost = [-0.04998578036712978, -0.00191383161468913]
|
||||
expected_jacobian = [
|
||||
[
|
||||
3.742008650059147e-6, 4.4904103800709765e-6, 5.238812110082806e-6,
|
||||
-3.12967996186765e-6, -3.1568945702317167e-6, -3.184109178595783e-6,
|
||||
8.603475350051953e-7
|
||||
], [
|
||||
0.000021542096327717702, 0.000026927620409647127, 0.000032313144491576555,
|
||||
-0.000021472154456523818, -0.0000228010500092077, -0.000024129945561891588,
|
||||
-8.489496089740964e-6
|
||||
]
|
||||
]
|
||||
|
||||
numpy.testing.assert_allclose(costs(pt_to_test), expected_cost, err_msg="Costs aren't as expected.")
|
||||
numpy.testing.assert_allclose(jac(pt_to_test), expected_jacobian, err_msg="Jacobian aren't as expected.")
|
||||
20
tests/model/oscillating/test_util.py
Normal file
20
tests/model/oscillating/test_util.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import pathfinder.model.oscillating.util as util
|
||||
import numpy
|
||||
|
||||
|
||||
def test_util_flip():
|
||||
pt = numpy.array((1, 2, 3, 4, 5, 6, 7))
|
||||
expected = (1, 2, 3, 4, 5, 6, 7)
|
||||
numpy.testing.assert_allclose(util.flip_chunk_to_positive_px(pt), expected, err_msg="Point should remain unchanged.")
|
||||
|
||||
|
||||
def test_util_flip_negative():
|
||||
pt = numpy.array((-1, -2, 3, 4, 5, 6, 7))
|
||||
expected = (1, 2, -3, 4, 5, 6, 7)
|
||||
numpy.testing.assert_allclose(util.flip_chunk_to_positive_px(pt), expected, err_msg="Point should remain unchanged.")
|
||||
|
||||
|
||||
def test_util_normalise_two():
|
||||
pt = numpy.array((1, 2, 3, 4, 5, 6, 7, -.5, 1, 1.5, 2, 2.5, 3, 3.5))
|
||||
expected = (.5, -1, -1.5, 2, 2.5, 3, 3.5, 1, 2, 3, 4, 5, 6, 7)
|
||||
numpy.testing.assert_allclose(util.normalize_oscillating_dipole_list(pt), expected, err_msg="Sort should have happened.")
|
||||
45
tests/model/static/test_dot.py
Normal file
45
tests/model/static/test_dot.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import numpy
|
||||
import numpy.testing
|
||||
|
||||
import pathfinder.model.static as model
|
||||
|
||||
|
||||
def test_dot():
|
||||
dot = model.DotMeasurement(0.235, (1, 2, 3))
|
||||
assert dot.v == 0.235
|
||||
numpy.testing.assert_array_equal(dot.r, (1, 2, 3), "These arrays should have been equal!")
|
||||
|
||||
|
||||
def test_dot_v_from_dipole():
|
||||
# for a dot located at (1, 2, 3)
|
||||
dot = model.DotMeasurement(50, (1, 2, 3))
|
||||
|
||||
# and dipole located at (4, 7, 11) with p=(8, 9, 10)
|
||||
pt = numpy.array((8, 9, 10, 4, 7, 11))
|
||||
|
||||
# V should be -0.153584
|
||||
target = -0.1535844174880402
|
||||
cost = -50.1535844174880402
|
||||
|
||||
numpy.testing.assert_allclose(dot.v_for_point(pt), target, err_msg="v from dipole at a dot was incorrect!")
|
||||
numpy.testing.assert_allclose(dot.cost(pt), cost, err_msg="cost from dipole at a dot was incorrect!")
|
||||
|
||||
|
||||
def test_dot_jac():
|
||||
# for a dot located at (1, 2, 3)
|
||||
dot = model.DotMeasurement(50, (1, 2, 3))
|
||||
|
||||
# and dipole located at (4, 7, 11) with p=(8, 9, 10)
|
||||
pt = numpy.array((8, 9, 10, 4, 7, 11))
|
||||
|
||||
target_jac_pt = [-0.003092303707812889, -0.005153839513021483, -0.00824614322083437, 0.0058585481811285, 0.01423090787983279, 0.02730483137919137]
|
||||
|
||||
# assume a second dipole at (12, 13, -5), with p = (-1, -2, -3)
|
||||
second_target = [-0.002054993939616119, -0.002054993939616119, 0.001494541046993541, 5.494636202182148e-6, 0.0001923122670763748, 0.0006923241614749492]
|
||||
pt2 = numpy.array((-1, -2, -3, 12, 13, -5))
|
||||
jac_row_target = target_jac_pt + second_target
|
||||
pts = numpy.append(pt, pt2)
|
||||
|
||||
assert len(dot.jac_pt(pt)) == 6
|
||||
numpy.testing.assert_allclose(dot.jac_pt(pt), target_jac_pt, 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")
|
||||
76
tests/model/static/test_model.py
Normal file
76
tests/model/static/test_model.py
Normal file
@@ -0,0 +1,76 @@
|
||||
import numpy
|
||||
import pathfinder.model.static as model
|
||||
|
||||
|
||||
def test_dotdipolemodel_repr():
|
||||
mod = model.DotDipoleModel((), 1)
|
||||
assert repr(mod) == "DotDipoleModel([], 1)"
|
||||
|
||||
|
||||
def test_dotdipolemodel_m():
|
||||
mod = model.DotDipoleModel([model.DotMeasurement(1, (0, 0, 0)), model.DotMeasurement(2, (0, 0, 0))], 1)
|
||||
assert mod.m == 2
|
||||
|
||||
|
||||
def test_dotdipolemodel_cost():
|
||||
mod = model.DotDipoleModel([model.DotMeasurement(1, (0, 0, 1)), model.DotMeasurement(2, (1, 0, 0))], 1)
|
||||
costs = mod.costs()
|
||||
jac = mod.jac()
|
||||
|
||||
pt_to_test = numpy.array((1, 2, 3, 4, 5, 6))
|
||||
expected_cost = [-1.05408565512728256, -2.05293155269909457]
|
||||
expected_jacobian = [
|
||||
[
|
||||
-0.007460090362383803, -0.009325112952979752, -0.009325112952979752,
|
||||
0.007968732887091788, 0.00856214916591777, 0.006697126575321822
|
||||
], [
|
||||
-0.00512240832571883, -0.008537347209531383, -0.01024481665143766,
|
||||
0.005098015905120168, 0.007927536694564856, 0.008488562368334061
|
||||
]
|
||||
]
|
||||
|
||||
numpy.testing.assert_allclose(costs(pt_to_test), expected_cost, err_msg="Costs aren't as expected.")
|
||||
numpy.testing.assert_allclose(jac(pt_to_test), expected_jacobian, err_msg="Jacobian aren't as expected.")
|
||||
|
||||
|
||||
def print_result(msg, result):
|
||||
print(msg)
|
||||
print(f"\tResult: {result.x}")
|
||||
print(f"\tSuccess: {result.success}. {result.message}")
|
||||
try:
|
||||
print(f"\tFunc evals: {result.nfev}")
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
print(f"\tJacb evals: {result.njev}")
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
def test_dot_dipole_model_solution():
|
||||
v1 = -0.05547767706400186526225414
|
||||
v2 = -0.06018573388098888319642888
|
||||
v3 = -0.06364032191901859480476888
|
||||
v4 = -0.06488383879243851188402150
|
||||
v5 = -0.06297148063759813929659130
|
||||
v6 = -0.05735489606460216
|
||||
v7 = -0.07237320672886623
|
||||
v8 = -0.1082531754730548
|
||||
v9 = -0.04471694936155558
|
||||
|
||||
c1 = model.DotMeasurement(v1, [0, 0, 1])
|
||||
c2 = model.DotMeasurement(v2, [0, 0, 2])
|
||||
c3 = model.DotMeasurement(v3, [0, 0, 3])
|
||||
c4 = model.DotMeasurement(v4, [0, 0, 4])
|
||||
c5 = model.DotMeasurement(v5, [0, 0, 5])
|
||||
c6 = model.DotMeasurement(v6, [0, 0, 6])
|
||||
c7 = model.DotMeasurement(v7, [1, 1, 7])
|
||||
c8 = model.DotMeasurement(v8, [1, 2, 3])
|
||||
c9 = model.DotMeasurement(v9, [0, -1, 0])
|
||||
|
||||
expected_result = numpy.array([1, 3, 5, 5, 6, 7])
|
||||
|
||||
mod = model.DotDipoleModel([c1, c2, c3, c4, c5, c6, c7, c8, c9], 1)
|
||||
res = mod.sol()
|
||||
assert res.success, "The solution for a single dipole should have succeeded."
|
||||
numpy.testing.assert_allclose(res.x, expected_result, err_msg="Dipole wasn't as expected.")
|
||||
120
tests/model/static/test_model_sol.py
Normal file
120
tests/model/static/test_model_sol.py
Normal file
@@ -0,0 +1,120 @@
|
||||
import numpy
|
||||
import pathfinder.model.static
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def chunk_n_sort(pts):
|
||||
pt_length = 6
|
||||
chunked_pts = [pts[i: i + pt_length] for i in range(0, len(pts), pt_length)]
|
||||
|
||||
return sorted(chunked_pts, key=lambda x: x[0])
|
||||
|
||||
|
||||
def print_result(msg, result):
|
||||
print(msg)
|
||||
print(f"\tResult: {chunk_n_sort(result.x)}")
|
||||
print(f"\tSuccess: {result.success}. {result.message}")
|
||||
try:
|
||||
print(f"\tFunc evals: {result.nfev}")
|
||||
except AttributeError:
|
||||
pass
|
||||
try:
|
||||
print(f"\tJacb evals: {result.njev}")
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
|
||||
def test_one_dipole_six_dot():
|
||||
# setup
|
||||
dot_positions = [[0, 0, 0], [-1, 0, 0], [-2, 0, 0], [-1, -1, 0], [-1, -1, 1], [0, -2, 0]]
|
||||
dipole = pathfinder.model.static.StaticDipole([1, 2, 3], [0, 4, 0])
|
||||
expected_result = numpy.array([1, 2, 3, 0, 4, 0])
|
||||
dipole_arrangement = pathfinder.model.static.StaticDipoleArrangement([dipole])
|
||||
dot_measurements = dipole_arrangement.get_dot_measurements(dot_positions)
|
||||
|
||||
model = pathfinder.model.static.DotDipoleModel(dot_measurements, 1)
|
||||
res = model.sol()
|
||||
|
||||
print_result("one dipole six dots", res)
|
||||
assert res.success, "The solution for a single dipole and six dots should have succeeded."
|
||||
numpy.testing.assert_allclose(res.x, expected_result, err_msg="Dipole wasn't as expected.", rtol=1e-6, atol=1e-6)
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="don't care at the moment")
|
||||
def test_two_dipole_thirteen_dot():
|
||||
dot_positions = [[x, y, 0] for x in (-4, -1, 1, 4) for y in (-1, -5, -9)]
|
||||
dot_positions.append((1, -1, 2))
|
||||
# dot_positions.append((-1, -1, -2))
|
||||
dipole = pathfinder.model.static.StaticDipole([0, 8, 0], [0, 5, 0])
|
||||
dipole2 = pathfinder.model.static.StaticDipole([8, 1, 1], [2, 2, -2])
|
||||
expected_result = numpy.array([0, 8, 0, 0, 5, 0, 8, 1, 1, 2, 2, -2])
|
||||
dipole_arrangement = pathfinder.model.static.StaticDipoleArrangement([dipole, dipole2])
|
||||
dot_measurements = dipole_arrangement.get_dot_measurements(dot_positions)
|
||||
|
||||
model = pathfinder.model.static.DotDipoleModel(dot_measurements, 2)
|
||||
res = model.sol(initial_dipole=(2, 2, 0), initial_position=(0, 3, 0))
|
||||
print(model.costs()(res.x))
|
||||
print(res.x)
|
||||
print_result("two dipole 13 dot", res)
|
||||
assert res.success, "The solution for two dipoles and twelve dots should have succeeded."
|
||||
numpy.testing.assert_allclose(chunk_n_sort(res.x), chunk_n_sort(expected_result), err_msg="Dipole wasn't as expected.", rtol=1e-6, atol=1e-4)
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="don't care at the moment")
|
||||
def test_two_dipole_twelve_dot():
|
||||
dot_positions = [[x, y, 0] for x in (-4, -1, 1, 4) for y in (-1, -5, -9)][:-1]
|
||||
dot_positions.append((1, -1, 2))
|
||||
# dot_positions.append((-1, -1, -2))
|
||||
dipole = pathfinder.model.static.StaticDipole([0, 8, 0], [0, 5, 0])
|
||||
dipole2 = pathfinder.model.static.StaticDipole([8, 1, 1], [2, 2, -2])
|
||||
expected_result = numpy.array([0, 8, 0, 0, 5, 0, 8, 1, 1, 2, 2, -2])
|
||||
dipole_arrangement = pathfinder.model.static.StaticDipoleArrangement([dipole, dipole2])
|
||||
dot_measurements = dipole_arrangement.get_dot_measurements(dot_positions)
|
||||
|
||||
model = pathfinder.model.static.DotDipoleModel(dot_measurements, 2)
|
||||
res = model.sol(initial_dipole=(2, 2, 0), initial_position=(0, 3, 0), use_root=False)
|
||||
print(model.costs()(res.x))
|
||||
print(res.x)
|
||||
print_result("two dipole 13 dot", res)
|
||||
assert res.success, "The solution for two dipoles and twelve dots should have succeeded."
|
||||
numpy.testing.assert_allclose(chunk_n_sort(res.x), chunk_n_sort(expected_result), err_msg="Dipole wasn't as expected.", rtol=1e-6, atol=1e-4)
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="don't care at the moment")
|
||||
def test_two_dipole_twelve_dot_smallguy():
|
||||
dot_positions = [[x, y, 0] for x in (-4, -1, 1, 4) for y in (-1, -5, -9)][:-1]
|
||||
dot_positions.append((1, -1, 2))
|
||||
# dot_positions.append((-1, -1, -2))
|
||||
dipole = pathfinder.model.static.StaticDipole([0, 1, 0], [0, 5, 0])
|
||||
dipole2 = pathfinder.model.static.StaticDipole([8, 1, 1], [2, 2, -2])
|
||||
expected_result = numpy.array([0, 1, 0, 0, 5, 0, 8, 1, 1, 2, 2, -2])
|
||||
dipole_arrangement = pathfinder.model.static.StaticDipoleArrangement([dipole, dipole2])
|
||||
dot_measurements = dipole_arrangement.get_dot_measurements(dot_positions)
|
||||
|
||||
model = pathfinder.model.static.DotDipoleModel(dot_measurements, 2)
|
||||
res = model.sol(initial_dipole=(2, 2, 0), initial_position=(0, 3, 0), use_root=False)
|
||||
print(model.costs()(res.x))
|
||||
print(res.x)
|
||||
print_result("two dipole 13 dot", res)
|
||||
assert res.success, "The solution for two dipoles and twelve dots should have succeeded."
|
||||
numpy.testing.assert_allclose(chunk_n_sort(res.x), chunk_n_sort(expected_result), err_msg="Dipole wasn't as expected.", rtol=1e-6, atol=1e-4)
|
||||
|
||||
|
||||
def test_two_dipole_twelve_dot_2():
|
||||
dot_positions = [[x, y, 0] for x in (-4, -1, 1, 4) for y in (-1, -5, -9)]
|
||||
dot_positions.append((1, -1, 2))
|
||||
dot_positions.append((-1, -1, -2))
|
||||
dipole = pathfinder.model.static.StaticDipole([0, 8, 0], [0, 5, 0])
|
||||
dipole2 = pathfinder.model.static.StaticDipole([8, 1, 1], [2, 2, -2])
|
||||
expected_result = numpy.array([0, 8, 0, 0, 5, 0, 8, 1, 1, 2, 2, -2])
|
||||
dipole_arrangement = pathfinder.model.static.StaticDipoleArrangement([dipole, dipole2])
|
||||
dot_measurements = dipole_arrangement.get_dot_measurements(dot_positions)
|
||||
|
||||
model = pathfinder.model.static.DotDipoleModel(dot_measurements, 2)
|
||||
res = model.sol()
|
||||
print(model.costs()(res.x))
|
||||
|
||||
print_result("two dipole twelve dot", res)
|
||||
# assert res.success, "The solution for two dipoles and twelve dots should have succeeded."
|
||||
numpy.testing.assert_allclose(chunk_n_sort(res.x), chunk_n_sort(expected_result), err_msg="Dipole wasn't as expected.", rtol=1e-6, atol=1e-4)
|
||||
23
tests/model/static/test_staticdipole.py
Normal file
23
tests/model/static/test_staticdipole.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import numpy
|
||||
import pathfinder.model.static as model
|
||||
|
||||
|
||||
def test_static_dipole():
|
||||
d1 = model.StaticDipole((1, 2, 3), (4, 5, 6))
|
||||
d2 = model.StaticDipole((4, 5, 6), (1, 2, 3))
|
||||
dipoles = model.StaticDipoleArrangement([d1, d2])
|
||||
|
||||
dot_position1 = (-1, -1, -1)
|
||||
expected_v1 = -0.3338923121348659
|
||||
|
||||
numpy.testing.assert_allclose(dipoles.get_dot_measurement(dot_position1).v, expected_v1, err_msg="Voltage at dot isn't as expected.")
|
||||
numpy.testing.assert_allclose(dipoles.get_dot_measurement(dot_position1).r, dot_position1, err_msg="Dot isn't where expected.")
|
||||
|
||||
# test multiple dots
|
||||
dot_position2 = (-1, -1, -5)
|
||||
expected_v2 = -0.1254445237566694
|
||||
|
||||
both_measurements = dipoles.get_dot_measurements([dot_position1, dot_position2])
|
||||
measured_voltages = numpy.sort([m.v for m in both_measurements])
|
||||
expected_measured_voltages = numpy.sort([expected_v1, expected_v2])
|
||||
numpy.testing.assert_allclose(measured_voltages, expected_measured_voltages, err_msg="Didn't get the measured voltages expected")
|
||||
@@ -1,5 +1,7 @@
|
||||
from pathfinder import __version__
|
||||
import pathfinder
|
||||
|
||||
|
||||
def test_version():
|
||||
assert __version__ == '0.0.1'
|
||||
assert pathfinder.get_version() == __version__
|
||||
|
||||
Reference in New Issue
Block a user