Compare commits
107 Commits
Author | SHA1 | Date | |
---|---|---|---|
885508e104 | |||
6193ecb9c9 | |||
5ad442750e | |||
9b1538b3c6 | |||
7b277fdc85 | |||
e5fc1207a8 | |||
387a607e09 | |||
9e6d1df559 | |||
45031857f2 | |||
64181eeef2 | |||
d682d50554 | |||
e9e34162a3 | |||
32a7812a43 | |||
7c39475742 | |||
1dd7569fde | |||
4a63552129 | |||
9c88c9ab96 | |||
631ba13c79 | |||
e2bdeda638 | |||
806b9b667f | |||
e61838d85f | |||
3ebe2bb824 | |||
ed9dd2c94f | |||
74c1b01a6c | |||
50f98ed89b | |||
18cc48471d | |||
d60a0cb386 | |||
e01d0e14a9 | |||
dfaf8abed5 | |||
ca710e359f | |||
dc43e4bfbc | |||
dbf924490e | |||
f280448cfe | |||
feb0a5f645 | |||
e9bb62c0a0 | |||
857391425f | |||
46dc6dd6d9 | |||
29abc8af89 | |||
23e3b95bb6 | |||
a326e80e00 | |||
56f660ff25 | |||
a5fd9c2304 | |||
0dbe874ac4 | |||
36454d5044 | |||
156019fdac | |||
c49b8eb034 | |||
c034ae81fd | |||
5acf0ac347 | |||
2a1ae3b1a7 | |||
0447b5d3a7 | |||
e894c89702 | |||
7566744c96 | |||
b9621ff55d | |||
6277e843d5 | |||
ed0c6e2858 | |||
ad87d5ebde | |||
96a3a8fac4 | |||
7f69b2009c | |||
b4b0767443 | |||
f6525b84b6 | |||
50323b4ed7 | |||
280de7280b | |||
9b55e5e581 | |||
d19466cea6 | |||
33c4da6281 | |||
aff7b4ba26 | |||
2cdf46afa1 | |||
eb080fed02 | |||
0bd179232e | |||
01f905a237 | |||
5da9eddd7b | |||
2c6b62ca95 | |||
b48bb67605 | |||
8cbb3eaeee | |||
7a9fa1ba04 | |||
6587ab4800 | |||
dfdff12997 | |||
623cadea2e | |||
333a5af1dc | |||
27cbb364a6 | |||
ab25de9558 | |||
79957edf21 | |||
8264ca3d6e | |||
3b3078ef23 | |||
55d4e3252d | |||
cb3c280464 | |||
58441b8ddb | |||
011400fa97 | |||
a777b713f3 | |||
f18d805e0d | |||
ee6a2773bc | |||
0c64ed02f0 | |||
fe5273346b | |||
8cd08da854 | |||
1bad2f743a | |||
b670bc3fa4 | |||
029021e393 | |||
7930d8f7ab | |||
bc06f2a368 | |||
70d95c8d6d | |||
bbfbfa359a | |||
0f78c7c2db | |||
7eba3311c7 | |||
0d5508a0b5 | |||
946945d791 | |||
c04d863d7f | |||
6d2f01f8d7 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -114,6 +114,10 @@ ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
#direnv
|
||||
.envrc
|
||||
.direnv
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
191
CHANGELOG.md
191
CHANGELOG.md
@ -2,6 +2,197 @@
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [1.5.0](https://gitea.deepak.science:2222/physics/pdme/compare/1.4.0...1.5.0) (2024-05-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds mcmc chain that returns number of repeats ([6193ecb](https://gitea.deepak.science:2222/physics/pdme/commit/6193ecb9c9f7a21d24e860987a7107549a4b2fa7))
|
||||
|
||||
## [1.4.0](https://gitea.deepak.science:2222/physics/pdme/compare/1.3.0...1.4.0) (2024-05-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds relative squared diff calc utility method ([9b1538b](https://gitea.deepak.science:2222/physics/pdme/commit/9b1538b3c63bfaf2a779bb109cd160a8d7887195))
|
||||
|
||||
## [1.3.0](https://gitea.deepak.science:2222/physics/pdme/compare/1.2.0...1.3.0) (2024-05-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds utility function for sorting samples by frequency for subspace simulation ([e5fc120](https://gitea.deepak.science:2222/physics/pdme/commit/e5fc1207a8b7d5b67208ad825907baa442eec648))
|
||||
|
||||
## [1.2.0](https://gitea.deepak.science:2222/physics/pdme/compare/1.1.0...1.2.0) (2024-05-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds pdme fast calc for e field xs ([9e6d1df](https://gitea.deepak.science:2222/physics/pdme/commit/9e6d1df559e58998851a1c2bf24fcc46d8c1b148))
|
||||
|
||||
## [1.1.0](https://gitea.deepak.science:2222/physics/pdme/compare/1.0.0...1.1.0) (2024-05-02)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds both electric potential and electric field x sources, makes some fast util tests use the slower explicit versions as double check ([e9e3416](https://gitea.deepak.science:2222/physics/pdme/commit/e9e34162a3b84faad5c18ddeda327c2f7f5ac5aa))
|
||||
|
||||
## [1.0.0](https://gitea.deepak.science:2222/physics/pdme/compare/0.9.3...1.0.0) (2024-04-29)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fixes the broken implementation of the tarucha frequency calculation ([631ba13](https://gitea.deepak.science:2222/physics/pdme/commit/631ba13c791c71ad8922d39a13b780a40eac2391))
|
||||
|
||||
### [0.9.3](https://gitea.deepak.science:2222/physics/pdme/compare/0.9.2...0.9.3) (2024-02-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds util func for calculating arg using sign instead of complex arithmetic ([3ebe2bb](https://gitea.deepak.science:2222/physics/pdme/commit/3ebe2bb82430d677680383c42a1c269df83d99cd))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fixes stupid cost shape issue ([ed9dd2c](https://gitea.deepak.science:2222/physics/pdme/commit/ed9dd2c94f88a08c36f581f05b26a87a6b780d5b))
|
||||
|
||||
### [0.9.2](https://gitea.deepak.science:2222/physics/pdme/compare/0.9.1...0.9.2) (2023-07-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update tests but for git also don't wrap costs ([50f98ed](https://gitea.deepak.science:2222/physics/pdme/commit/50f98ed89b2a05cd47c41958036dd50bc872e07c))
|
||||
|
||||
### [0.9.1](https://gitea.deepak.science:2222/physics/pdme/compare/0.9.0...0.9.1) (2023-07-24)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fixes some of the shape mangling of our mcmc code ([e01d0e1](https://gitea.deepak.science:2222/physics/pdme/commit/e01d0e14a9bcd6d7e8fe9449ce562dbf1b8fd25c))
|
||||
|
||||
## [0.9.0](https://gitea.deepak.science:2222/physics/pdme/compare/0.8.9...0.9.0) (2023-07-24)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* separates threshold cost and the seed_cost in mcmc
|
||||
|
||||
### Features
|
||||
|
||||
* separates threshold cost and the seed_cost in mcmc ([ca710e3](https://gitea.deepak.science:2222/physics/pdme/commit/ca710e359fd0cfbb620a3574a2fa4fab1be2b52a))
|
||||
|
||||
### [0.8.9](https://gitea.deepak.science:2222/physics/pdme/compare/0.8.8...0.8.9) (2023-07-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds a bunch of mcmc generation code for log spaced models, yay ([f280448](https://gitea.deepak.science:2222/physics/pdme/commit/f280448cfe2fcf5bdc5ac2317ee52b27523bb49d))
|
||||
* adds utility functions for dealing with markov chain monte carlo ([feb0a5f](https://gitea.deepak.science:2222/physics/pdme/commit/feb0a5f6453dcb5e71a07c7749cd579dab15171c))
|
||||
|
||||
### [0.8.8](https://gitea.deepak.science:2222/physics/pdme/compare/0.8.7...0.8.8) (2023-04-09)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds fast calc that allows for variable temp ([36454d5](https://gitea.deepak.science:2222/physics/pdme/commit/36454d5044d93b6b178e016b84dd59a5ebaf15e2))
|
||||
|
||||
### [0.8.7](https://gitea.deepak.science:2222/physics/pdme/compare/0.8.6...0.8.7) (2022-09-17)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds xy model for convenience to pdme ([e894c89](https://gitea.deepak.science:2222/physics/pdme/commit/e894c897029c05a1d4754e7930ae9ba2be7a1cfd))
|
||||
* moves xy model up to model package ([2a1ae3b](https://gitea.deepak.science:2222/physics/pdme/commit/2a1ae3b1a7f7e10469b7fd2930fee0b338f0c03f))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Correctly generates monte carlo version of xy model dipoles ([5acf0ac](https://gitea.deepak.science:2222/physics/pdme/commit/5acf0ac347382705674bb596440d27cba3730bac))
|
||||
|
||||
### [0.8.6](https://gitea.deepak.science:2222/physics/pdme/compare/0.8.5...0.8.6) (2022-06-13)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* makes library build system poetry-core ([ed0c6e2](https://gitea.deepak.science:2222/physics/pdme/commit/ed0c6e2858f45fec9b9a673d9b5bc98605e73508))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* pyproject build system now core as well ([6277e84](https://gitea.deepak.science:2222/physics/pdme/commit/6277e843d5a7df8eba1878db490d2fae4052af57))
|
||||
|
||||
### [0.8.5](https://gitea.deepak.science:2222/physics/pdme/compare/0.8.4...0.8.5) (2022-06-04)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds fixedorientation model ([2cdf46a](https://gitea.deepak.science:2222/physics/pdme/commit/2cdf46afa1492f86b4c403e4c5013cefc89b21d6))
|
||||
|
||||
### [0.8.4](https://gitea.deepak.science:2222/physics/pdme/compare/0.8.3...0.8.4) (2022-05-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* probability of occupancy fixed ([01f905a](https://gitea.deepak.science:2222/physics/pdme/commit/01f905a237a2423f5637ee6a0f43e0937c55d2ea))
|
||||
|
||||
### [0.8.3](https://gitea.deepak.science:2222/physics/pdme/compare/0.8.2...0.8.3) (2022-05-22)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Adds log spaced in frequency space model ([7a9fa1b](https://gitea.deepak.science:2222/physics/pdme/commit/7a9fa1ba04a12586ef09c89e35e706817012faab))
|
||||
|
||||
### [0.8.2](https://gitea.deepak.science:2222/physics/pdme/compare/0.8.1...0.8.2) (2022-05-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Adds Random count dipole model with binomial type distribution for dipole number ([27cbb36](https://gitea.deepak.science:2222/physics/pdme/commit/27cbb364a6d9625abca6145dafedf0df5743f816))
|
||||
|
||||
### [0.8.1](https://gitea.deepak.science:2222/physics/pdme/compare/0.8.0...0.8.1) (2022-04-30)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds multidipole nonlocal spectrum calculations ([8264ca3](https://gitea.deepak.science:2222/physics/pdme/commit/8264ca3d6edb703422229fde57bbb1d726ce5139))
|
||||
|
||||
## [0.8.0](https://gitea.deepak.science:2222/physics/pdme/compare/0.7.0...0.8.0) (2022-04-30)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* single dipole still outputs collection now to make interface consistent
|
||||
|
||||
### Features
|
||||
|
||||
* single dipole still outputs collection now to make interface consistent ([cb3c280](https://gitea.deepak.science:2222/physics/pdme/commit/cb3c280464aa2c4b0ec9320e6a319f4a454a0e9f))
|
||||
|
||||
## [0.7.0](https://gitea.deepak.science:2222/physics/pdme/compare/0.6.2...0.7.0) (2022-04-30)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* Changes names of classes to make more clear for dipole model and single dipole fixed magnitude model
|
||||
* reduces model to minimal bayes needed stuff
|
||||
* Guts the model interface for only the things useful for monte carlo bayes stuff
|
||||
* Removes unused models to make refactoring a bit easier
|
||||
|
||||
### Features
|
||||
|
||||
* adds fast method for calculating multiple dipole calculations ([1bad2f7](https://gitea.deepak.science:2222/physics/pdme/commit/1bad2f743af6a95189448d8929c70a036e6c21ab))
|
||||
* adds multidipole fixed mag model ([0c64ed0](https://gitea.deepak.science:2222/physics/pdme/commit/0c64ed02f0d42cd0957be0511a35dc49153a256f))
|
||||
* Changes names of classes to make more clear for dipole model and single dipole fixed magnitude model ([7eba331](https://gitea.deepak.science:2222/physics/pdme/commit/7eba3311c7ba90e4404b1a7b7c33df1585a800ba))
|
||||
* Guts the model interface for only the things useful for monte carlo bayes stuff ([946945d](https://gitea.deepak.science:2222/physics/pdme/commit/946945d791ed763e435afff7a6ae8c2b1c0e1711))
|
||||
* reduces model to minimal bayes needed stuff ([0d5508a](https://gitea.deepak.science:2222/physics/pdme/commit/0d5508a0b5641d98ee6f3484f58c923440c4c2c1))
|
||||
* Removes unused models to make refactoring a bit easier ([c04d863](https://gitea.deepak.science:2222/physics/pdme/commit/c04d863d7fa22c98d8542a5f72791b542358ff61))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* makes name of method match interface ([029021e](https://gitea.deepak.science:2222/physics/pdme/commit/029021e39328c7ca7a73afcf23d86ad17516982f))
|
||||
* makes repr return actual name ([0f78c7c](https://gitea.deepak.science:2222/physics/pdme/commit/0f78c7c2db742d59f2a5ee9da767f35aafa49b78))
|
||||
* uses rng passed in correctly ([70d95c8](https://gitea.deepak.science:2222/physics/pdme/commit/70d95c8d6d5af10f926d8729a5a0eaed9ad8259d))
|
||||
|
||||
### [0.6.2](https://gitea.deepak.science:2222/physics/pdme/compare/0.6.1...0.6.2) (2022-04-18)
|
||||
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
[](https://jenkins.deepak.science/job/gitea-physics/job/pdme/job/master/)
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
This repo has library code for evaluating dipole models.
|
||||
|
||||
|
5029
diagnosis1.nb
5029
diagnosis1.nb
File diff suppressed because it is too large
Load Diff
38
do.sh
38
do.sh
@ -1,38 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Do - The Simplest Build Tool on Earth.
|
||||
# Documentation and examples see https://github.com/8gears/do
|
||||
|
||||
set -Eeuo pipefail # -e "Automatic exit from bash shell script on error" -u "Treat unset variables and parameters as errors"
|
||||
|
||||
build() {
|
||||
echo "I am ${FUNCNAME[0]}ing"
|
||||
poetry build
|
||||
}
|
||||
|
||||
test() {
|
||||
echo "I am ${FUNCNAME[0]}ing"
|
||||
poetry run flake8 pdme tests
|
||||
poetry run mypy pdme
|
||||
poetry run pytest
|
||||
}
|
||||
|
||||
fmt() {
|
||||
poetry run black .
|
||||
find . -type f -name "*.py" -exec sed -i -e 's/ /\t/g' {} \;
|
||||
}
|
||||
|
||||
htmlcov() {
|
||||
poetry run pytest --cov-report=html
|
||||
}
|
||||
|
||||
release() {
|
||||
./scripts/release.sh
|
||||
}
|
||||
|
||||
all() {
|
||||
build && test
|
||||
}
|
||||
|
||||
"$@" # <- execute the task
|
||||
|
||||
[ "$#" -gt 0 ] || printf "Usage:\n\t./do.sh %s\n" "($(compgen -A function | grep '^[^_]' | paste -sd '|' -))"
|
95
flake.lock
generated
Normal file
95
flake.lock
generated
Normal file
@ -0,0 +1,95 @@
|
||||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1648297722,
|
||||
"narHash": "sha256-W+qlPsiZd8F3XkzXOzAoR+mpFqzm3ekQkJNa+PIh1BQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "0f8662f1319ad6abf89b3380dd2722369fc51ade",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "0f8662f1319ad6abf89b3380dd2722369fc51ade",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"locked": {
|
||||
"lastModified": 1653893745,
|
||||
"narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1648854265,
|
||||
"narHash": "sha256-e/RlfodBOMr2SH9diDPYMraTWvhOWSSsXDQikHFdUvM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e194871435cad8ffb1d64b64fb7df3b2b8a10088",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e194871435cad8ffb1d64b64fb7df3b2b8a10088",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1655043425,
|
||||
"narHash": "sha256-A+oT+aQGhW5lXy8H0cqBLsYtgcnT5glmGOXWQDcGw6I=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "914ef51ffa88d9b386c71bdc88bffc5273c08ada",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"poetry2nix": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": "nixpkgs_2"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1654921554,
|
||||
"narHash": "sha256-hkfMdQAHSwLWlg0sBVvgrQdIiBP45U1/ktmFpY4g2Mo=",
|
||||
"owner": "nix-community",
|
||||
"repo": "poetry2nix",
|
||||
"rev": "7b71679fa7df00e1678fc3f1d1d4f5f372341b63",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "poetry2nix",
|
||||
"rev": "7b71679fa7df00e1678fc3f1d1d4f5f372341b63",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"poetry2nix": "poetry2nix"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
55
flake.nix
Normal file
55
flake.nix
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
description = "Application packaged using poetry2nix";
|
||||
|
||||
inputs.flake-utils.url = "github:numtide/flake-utils?rev=0f8662f1319ad6abf89b3380dd2722369fc51ade";
|
||||
inputs.nixpkgs.url = "github:NixOS/nixpkgs?rev=e194871435cad8ffb1d64b64fb7df3b2b8a10088";
|
||||
inputs.poetry2nix.url = "github:nix-community/poetry2nix?rev=7b71679fa7df00e1678fc3f1d1d4f5f372341b63";
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, poetry2nix }:
|
||||
{
|
||||
# Nixpkgs overlay providing the application
|
||||
overlay = nixpkgs.lib.composeManyExtensions [
|
||||
poetry2nix.overlay
|
||||
(final: prev: {
|
||||
# The application
|
||||
pdme = prev.poetry2nix.mkPoetryApplication {
|
||||
overrides = [
|
||||
prev.poetry2nix.defaultPoetryOverrides
|
||||
];
|
||||
projectDir = ./.;
|
||||
};
|
||||
pdmeEnv = prev.poetry2nix.mkPoetryEnv {
|
||||
overrides = [
|
||||
prev.poetry2nix.defaultPoetryOverrides
|
||||
];
|
||||
projectDir = ./.;
|
||||
};
|
||||
})
|
||||
];
|
||||
} // (flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = [ self.overlay ];
|
||||
};
|
||||
in
|
||||
{
|
||||
apps = {
|
||||
pdme = pkgs.pdme;
|
||||
};
|
||||
|
||||
defaultApp = pkgs.pdme;
|
||||
devShell = pkgs.mkShell {
|
||||
buildInputs = [
|
||||
pkgs.poetry
|
||||
pkgs.pdmeEnv
|
||||
pkgs.pdme
|
||||
];
|
||||
shellHook = ''
|
||||
export DO_NIX_CUSTOM=1
|
||||
'';
|
||||
packages = [ pkgs.nodejs-16_x pkgs.gnupg ];
|
||||
};
|
||||
|
||||
}));
|
||||
}
|
64
justfile
Normal file
64
justfile
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
# execute default build
|
||||
default: build
|
||||
|
||||
# builds the python module using poetry
|
||||
build:
|
||||
echo "building..."
|
||||
poetry build
|
||||
|
||||
# print a message displaying whether nix is being used
|
||||
checknix:
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
if [[ "${DO_NIX_CUSTOM:=0}" -eq 1 ]]; then
|
||||
echo "In an interactive nix env."
|
||||
else
|
||||
echo "Using poetry as runner, no nix detected."
|
||||
fi
|
||||
|
||||
# run all tests
|
||||
test: fmt
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
|
||||
if [[ "${DO_NIX_CUSTOM:=0}" -eq 1 ]]; then
|
||||
echo "testing, using nix..."
|
||||
flake8 pdme tests
|
||||
mypy pdme
|
||||
pytest
|
||||
else
|
||||
echo "testing..."
|
||||
poetry run flake8 pdme tests
|
||||
poetry run mypy pdme
|
||||
poetry run pytest
|
||||
fi
|
||||
|
||||
# update all test snapshots, use if snapshots are out of date
|
||||
update-snapshots:
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
if [[ "${DO_NIX_CUSTOM:=0}" -eq 1 ]]; then
|
||||
pytest --snapshot-update
|
||||
else
|
||||
poetry run pytest --snapshot-update
|
||||
fi
|
||||
|
||||
# format code
|
||||
fmt:
|
||||
#!/usr/bin/env bash
|
||||
set -euxo pipefail
|
||||
if [[ "${DO_NIX_CUSTOM:=0}" -eq 1 ]]; then
|
||||
black .
|
||||
else
|
||||
poetry run black .
|
||||
fi
|
||||
find pdme -type f -name "*.py" -exec sed -i -e 's/ /\t/g' {} \;
|
||||
find tests -type f -name "*.py" -exec sed -i -e 's/ /\t/g' {} \;
|
||||
|
||||
# release the app, checking that our working tree is clean and ready for release
|
||||
release:
|
||||
./scripts/release.sh
|
||||
|
||||
htmlcov:
|
||||
poetry run pytest --cov-report=html
|
46
pdme/calculations/__init__.py
Normal file
46
pdme/calculations/__init__.py
Normal file
@ -0,0 +1,46 @@
|
||||
"""
|
||||
This module is a canonical source of the accurate expressions we want to use for calculating our noise.
|
||||
No reference to class or anything, just a straight set of math functions.
|
||||
"""
|
||||
import numpy
|
||||
|
||||
|
||||
def telegraph_beta(f: float, w: float) -> float:
|
||||
"""
|
||||
This function represents the frequency component of analytic telegraph noise.
|
||||
|
||||
We're assuming we care about the one-sided PSD where we are ignoring negative frequencies.
|
||||
This matches with experimental data from say Connors et al., and I think is better than keeping with one-sided.
|
||||
Note that this means that it will only be comparable then with time series data assuming one-sided!
|
||||
|
||||
Don't bikeshed yet, if we care about two-sided things for any reason down the line divide this by two or just change it then.
|
||||
"""
|
||||
return 2 * w / ((numpy.pi * f) ** 2 + w**2)
|
||||
|
||||
|
||||
def electric_potential(p: numpy.ndarray, s: numpy.ndarray, r: numpy.ndarray) -> float:
|
||||
"""
|
||||
Gives the electric potential of a defect with dipole moment p, located at position s,
|
||||
as measured from position r.
|
||||
|
||||
p, s, r, are numpy arrays of length 3
|
||||
"""
|
||||
diff = r - s
|
||||
return (p.dot(diff) / (numpy.linalg.norm(diff) ** 3)).item()
|
||||
|
||||
|
||||
def electric_field(
|
||||
p: numpy.ndarray, s: numpy.ndarray, r: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
Gives the electric field of a defect with dipole moment p, located at position s,
|
||||
as measured from position r.
|
||||
|
||||
p, s, r, are numpy arrays of length 3
|
||||
|
||||
Returns an array of length 3, ideally.
|
||||
"""
|
||||
diff = r - s
|
||||
norm_diff = numpy.linalg.norm(diff)
|
||||
|
||||
return ((3 * (p.dot(diff) * diff) / (norm_diff**2)) - p) / (norm_diff**3)
|
@ -7,6 +7,7 @@ from pdme.measurement.dot_pair_measure import (
|
||||
DotPairMeasurement,
|
||||
DotPairRangeMeasurement,
|
||||
)
|
||||
import pdme.calculations
|
||||
from pdme.measurement.input_types import DotInput, DotPairInput
|
||||
|
||||
|
||||
@ -38,10 +39,27 @@ class OscillatingDipole:
|
||||
self.p = numpy.array(self.p)
|
||||
self.s = numpy.array(self.s)
|
||||
|
||||
def s_at_position(self, r: numpy.ndarray, f: float) -> float:
|
||||
def _alpha_electric_potential(self, r: numpy.ndarray) -> float:
|
||||
"""
|
||||
Returns the electric potential of this dipole at position r.
|
||||
"""
|
||||
return pdme.calculations.electric_potential(self.p, self.s, r)
|
||||
|
||||
def _alpha_electric_field(self, r: numpy.ndarray) -> numpy.ndarray:
|
||||
"""
|
||||
Returns the electric field of this dipole at position r.
|
||||
"""
|
||||
return pdme.calculations.electric_field(self.p, self.s, r)
|
||||
|
||||
def _b(self, f: float) -> float:
|
||||
return pdme.calculations.telegraph_beta(f, self.w)
|
||||
|
||||
def s_electric_potential_at_position(self, r: numpy.ndarray, f: float) -> float:
|
||||
"""
|
||||
Returns the noise potential at a point r, at some frequency f.
|
||||
|
||||
Specifically for electric potential!
|
||||
|
||||
Parameters
|
||||
----------
|
||||
r : numpy.ndarray
|
||||
@ -50,17 +68,49 @@ class OscillatingDipole:
|
||||
f : float
|
||||
The dot frequency to sample.
|
||||
"""
|
||||
return (self._alpha(r)) ** 2 * self._b(f)
|
||||
return (self._alpha_electric_potential(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 s_electric_potential_for_dot_pair(
|
||||
self, r1: numpy.ndarray, r2: numpy.ndarray, f: float
|
||||
) -> float:
|
||||
"""
|
||||
This is specifically the analytic cpsd for electric potential noise.
|
||||
This should be deprecated
|
||||
"""
|
||||
return (
|
||||
self._alpha_electric_potential(r1)
|
||||
* self._alpha_electric_potential(r2)
|
||||
* self._b(f)
|
||||
)
|
||||
|
||||
def _b(self, f: float) -> float:
|
||||
return (1 / numpy.pi) * (self.w / (f**2 + self.w**2))
|
||||
def s_electric_fieldx_at_position(self, r: numpy.ndarray, f: float) -> float:
|
||||
"""
|
||||
Returns the noise potential at a point r, at some frequency f.
|
||||
|
||||
def s_for_dot_pair(self, r1: numpy.ndarray, r2: numpy.ndarray, f: float) -> float:
|
||||
return self._alpha(r1) * self._alpha(r2) * self._b(f)
|
||||
Specifically for electric potential!
|
||||
|
||||
Parameters
|
||||
----------
|
||||
r : numpy.ndarray
|
||||
The position of the dot.
|
||||
|
||||
f : float
|
||||
The dot frequency to sample.
|
||||
"""
|
||||
return (self._alpha_electric_field(r)[0]) ** 2 * self._b(f)
|
||||
|
||||
def s_electric_fieldx_for_dot_pair(
|
||||
self, r1: numpy.ndarray, r2: numpy.ndarray, f: float
|
||||
) -> float:
|
||||
"""
|
||||
This is specifically the analytic cpsd for electric potential noise.
|
||||
This should be deprecated
|
||||
"""
|
||||
return (
|
||||
self._alpha_electric_field(r1)[0]
|
||||
* self._alpha_electric_field(r2)[0]
|
||||
* self._b(f)
|
||||
)
|
||||
|
||||
def to_flat_array(self) -> numpy.ndarray:
|
||||
return numpy.concatenate([self.p, self.s, numpy.array([self.w])])
|
||||
@ -78,69 +128,97 @@ class OscillatingDipoleArrangement:
|
||||
def __init__(self, dipoles: Sequence[OscillatingDipole]):
|
||||
self.dipoles = dipoles
|
||||
|
||||
def get_dot_measurement(self, dot_input: DotInput) -> DotMeasurement:
|
||||
def get_potential_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
|
||||
sum(
|
||||
[
|
||||
dipole.s_electric_potential_at_position(r, f)
|
||||
for dipole in self.dipoles
|
||||
]
|
||||
),
|
||||
r,
|
||||
f,
|
||||
)
|
||||
|
||||
def get_dot_pair_measurement(
|
||||
def get_potential_dot_pair_measurement(
|
||||
self, dot_pair_input: DotPairInput
|
||||
) -> DotPairMeasurement:
|
||||
r1 = numpy.array(dot_pair_input[0])
|
||||
r2 = numpy.array(dot_pair_input[1])
|
||||
f = dot_pair_input[2]
|
||||
return DotPairMeasurement(
|
||||
sum([dipole.s_for_dot_pair(r1, r2, f) for dipole in self.dipoles]),
|
||||
sum(
|
||||
[
|
||||
dipole.s_electric_potential_for_dot_pair(r1, r2, f)
|
||||
for dipole in self.dipoles
|
||||
]
|
||||
),
|
||||
r1,
|
||||
r2,
|
||||
f,
|
||||
)
|
||||
|
||||
def get_dot_measurements(
|
||||
def get_potential_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]
|
||||
return [
|
||||
self.get_potential_dot_measurement(dot_input) for dot_input in dot_inputs
|
||||
]
|
||||
|
||||
def get_dot_pair_measurements(
|
||||
def get_potential_dot_pair_measurements(
|
||||
self, dot_pair_inputs: Sequence[DotPairInput]
|
||||
) -> List[DotPairMeasurement]:
|
||||
"""
|
||||
For a series of pairs of points, each with three coordinates and a frequency, return a list of the corresponding DotPairMeasurements.
|
||||
"""
|
||||
return [
|
||||
self.get_dot_pair_measurement(dot_pair_input)
|
||||
self.get_potential_dot_pair_measurement(dot_pair_input)
|
||||
for dot_pair_input in dot_pair_inputs
|
||||
]
|
||||
|
||||
def get_percent_range_dot_measurement(
|
||||
def get_percent_range_potential_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]),
|
||||
low_percent
|
||||
* sum(
|
||||
[
|
||||
dipole.s_electric_potential_at_position(r, f)
|
||||
for dipole in self.dipoles
|
||||
]
|
||||
),
|
||||
high_percent
|
||||
* sum(
|
||||
[
|
||||
dipole.s_electric_potential_at_position(r, f)
|
||||
for dipole in self.dipoles
|
||||
]
|
||||
),
|
||||
r,
|
||||
f,
|
||||
)
|
||||
|
||||
def get_percent_range_dot_measurements(
|
||||
def get_percent_range_potential_dot_measurements(
|
||||
self, dot_inputs: Sequence[DotInput], low_percent: float, high_percent: float
|
||||
) -> List[DotRangeMeasurement]:
|
||||
"""
|
||||
For a series of pairs 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 DotPairRangeMeasurements.
|
||||
"""
|
||||
return [
|
||||
self.get_percent_range_dot_measurement(dot_input, low_percent, high_percent)
|
||||
self.get_percent_range_potential_dot_measurement(
|
||||
dot_input, low_percent, high_percent
|
||||
)
|
||||
for dot_input in dot_inputs
|
||||
]
|
||||
|
||||
def get_percent_range_dot_pair_measurement(
|
||||
def get_percent_range_potential_dot_pair_measurement(
|
||||
self, pair_input: DotPairInput, low_percent: float, high_percent: float
|
||||
) -> DotPairRangeMeasurement:
|
||||
r1 = numpy.array(pair_input[0])
|
||||
@ -148,15 +226,25 @@ class OscillatingDipoleArrangement:
|
||||
f = pair_input[2]
|
||||
return DotPairRangeMeasurement(
|
||||
low_percent
|
||||
* sum([dipole.s_for_dot_pair(r1, r2, f) for dipole in self.dipoles]),
|
||||
* sum(
|
||||
[
|
||||
dipole.s_electric_potential_for_dot_pair(r1, r2, f)
|
||||
for dipole in self.dipoles
|
||||
]
|
||||
),
|
||||
high_percent
|
||||
* sum([dipole.s_for_dot_pair(r1, r2, f) for dipole in self.dipoles]),
|
||||
* sum(
|
||||
[
|
||||
dipole.s_electric_potential_for_dot_pair(r1, r2, f)
|
||||
for dipole in self.dipoles
|
||||
]
|
||||
),
|
||||
r1,
|
||||
r2,
|
||||
f,
|
||||
)
|
||||
|
||||
def get_percent_range_dot_pair_measurements(
|
||||
def get_percent_range_potential_dot_pair_measurements(
|
||||
self,
|
||||
pair_inputs: Sequence[DotPairInput],
|
||||
low_percent: float,
|
||||
@ -166,7 +254,7 @@ class OscillatingDipoleArrangement:
|
||||
For a series of pairs 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 DotPairRangeMeasurements.
|
||||
"""
|
||||
return [
|
||||
self.get_percent_range_dot_pair_measurement(
|
||||
self.get_percent_range_potential_dot_pair_measurement(
|
||||
pair_input, low_percent, high_percent
|
||||
)
|
||||
for pair_input in pair_inputs
|
||||
|
@ -1,14 +1,30 @@
|
||||
from pdme.model.model import Model, Discretisation
|
||||
from pdme.model.fixed_z_plane_model import FixedZPlaneModel
|
||||
from pdme.model.unrestricted_model import UnrestrictedModel
|
||||
from pdme.model.fixed_dipole_model import FixedDipoleModel
|
||||
from pdme.model.fixed_magnitude_model import FixedMagnitudeModel
|
||||
from pdme.model.model import DipoleModel
|
||||
from pdme.model.fixed_magnitude_model import SingleDipoleFixedMagnitudeModel
|
||||
from pdme.model.multidipole_fixed_magnitude_model import (
|
||||
MultipleDipoleFixedMagnitudeModel,
|
||||
)
|
||||
from pdme.model.random_count_multidipole_fixed_magnitude_model import (
|
||||
RandomCountMultipleDipoleFixedMagnitudeModel,
|
||||
)
|
||||
|
||||
from pdme.model.log_spaced_random_choice_model import (
|
||||
LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel,
|
||||
)
|
||||
|
||||
from pdme.model.log_spaced_random_choice_xy_model import (
|
||||
LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel,
|
||||
)
|
||||
|
||||
from pdme.model.log_spaced_random_choice_fixed_orientation_model import (
|
||||
LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"Model",
|
||||
"Discretisation",
|
||||
"FixedZPlaneModel",
|
||||
"UnrestrictedModel",
|
||||
"FixedDipoleModel",
|
||||
"FixedMagnitudeModel",
|
||||
"DipoleModel",
|
||||
"SingleDipoleFixedMagnitudeModel",
|
||||
"MultipleDipoleFixedMagnitudeModel",
|
||||
"RandomCountMultipleDipoleFixedMagnitudeModel",
|
||||
"LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel",
|
||||
"LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel",
|
||||
"LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel",
|
||||
]
|
||||
|
@ -1,184 +0,0 @@
|
||||
import numpy
|
||||
import numpy.random
|
||||
from dataclasses import dataclass
|
||||
from typing import Sequence, Tuple
|
||||
import scipy.optimize
|
||||
from pdme.model.model import Model, Discretisation
|
||||
from pdme.measurement import (
|
||||
DotMeasurement,
|
||||
OscillatingDipoleArrangement,
|
||||
OscillatingDipole,
|
||||
)
|
||||
|
||||
|
||||
class FixedDipoleModel(Model):
|
||||
"""
|
||||
Model of oscillating dipole with a fixed dipole moment.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
p : numpy.ndarray
|
||||
The fixed dipole moment.
|
||||
|
||||
n : int
|
||||
The number of dipoles to assume.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
xmin: float,
|
||||
xmax: float,
|
||||
ymin: float,
|
||||
ymax: float,
|
||||
zmin: float,
|
||||
zmax: float,
|
||||
p: numpy.ndarray,
|
||||
n: int,
|
||||
) -> None:
|
||||
self.xmin = xmin
|
||||
self.xmax = xmax
|
||||
self.ymin = ymin
|
||||
self.ymax = ymax
|
||||
self.zmin = zmin
|
||||
self.zmax = zmax
|
||||
self.p = p
|
||||
self._n = n
|
||||
self.rng = numpy.random.default_rng()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"FixedDipoleModel({self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.zmin}, {self.zmax}, {self.p}, {self.n()})"
|
||||
|
||||
# TODO: this signature doesn't make sense.
|
||||
def get_dipoles(self, frequency: float) -> OscillatingDipoleArrangement:
|
||||
s_pts = numpy.array(
|
||||
(
|
||||
self.rng.uniform(self.xmin, self.xmax),
|
||||
self.rng.uniform(self.ymin, self.ymax),
|
||||
self.rng.uniform(self.zmin, self.zmax),
|
||||
)
|
||||
)
|
||||
return OscillatingDipoleArrangement(
|
||||
[OscillatingDipole(self.p, s_pts, frequency)]
|
||||
)
|
||||
|
||||
def solution_single_dipole(self, pt: numpy.ndarray) -> OscillatingDipole:
|
||||
# assume length is 4.
|
||||
s = pt[0:3]
|
||||
w = pt[3]
|
||||
return OscillatingDipole(self.p, s, w)
|
||||
|
||||
def point_length(self) -> int:
|
||||
"""
|
||||
Dipole is constrained magnitude, but free orientation.
|
||||
Six degrees of freedom: (sx, sy, sz, w).
|
||||
"""
|
||||
return 4
|
||||
|
||||
def n(self) -> int:
|
||||
return self._n
|
||||
|
||||
def v_for_point_at_dot(self, dot: DotMeasurement, pt: numpy.ndarray) -> float:
|
||||
s = pt[0:3]
|
||||
w = pt[3]
|
||||
|
||||
diff = dot.r - s
|
||||
alpha = self.p.dot(diff) / (numpy.linalg.norm(diff) ** 3)
|
||||
b = (1 / numpy.pi) * (w / (w**2 + dot.f**2))
|
||||
return alpha**2 * b
|
||||
|
||||
def jac_for_point_at_dot(
|
||||
self, dot: DotMeasurement, pt: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
s = pt[0:3]
|
||||
w = pt[3]
|
||||
|
||||
diff = dot.r - s
|
||||
alpha = self.p.dot(diff) / (numpy.linalg.norm(diff) ** 3)
|
||||
b = (1 / numpy.pi) * (w / (w**2 + dot.f**2))
|
||||
|
||||
r_divs = (
|
||||
(
|
||||
-self.p / (numpy.linalg.norm(diff) ** 3)
|
||||
+ 3 * self.p.dot(diff) * diff / (numpy.linalg.norm(diff) ** 5)
|
||||
)
|
||||
* 2
|
||||
* alpha
|
||||
* b
|
||||
)
|
||||
|
||||
f2 = dot.f**2
|
||||
w2 = w**2
|
||||
|
||||
w_div = alpha**2 * (1 / numpy.pi) * ((f2 - w2) / ((f2 + w2) ** 2))
|
||||
|
||||
return numpy.concatenate((r_divs, w_div), axis=None)
|
||||
|
||||
|
||||
@dataclass
|
||||
class FixedDipoleDiscretisation(Discretisation):
|
||||
"""
|
||||
Representation of a discretisation of a FixedDipoleDiscretisation.
|
||||
Also captures a rough maximum value of dipole.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
model : FixedDipoleModel
|
||||
The parent model of the discretisation.
|
||||
|
||||
num_x : int
|
||||
The number of partitions of the x axis.
|
||||
|
||||
num_y : int
|
||||
The number of partitions of the y axis.
|
||||
|
||||
num_z : int
|
||||
The number of partitions of the z axis.
|
||||
"""
|
||||
|
||||
model: FixedDipoleModel
|
||||
num_x: int
|
||||
num_y: int
|
||||
num_z: int
|
||||
|
||||
def __post_init__(self):
|
||||
self.cell_count = self.num_x * self.num_y * self.num_z
|
||||
self.x_step = (self.model.xmax - self.model.xmin) / self.num_x
|
||||
self.y_step = (self.model.ymax - self.model.ymin) / self.num_y
|
||||
self.z_step = (self.model.zmax - self.model.zmin) / self.num_z
|
||||
|
||||
def bounds(self, index: Tuple[float, ...]) -> Tuple:
|
||||
xi, yi, zi = index
|
||||
|
||||
# For this model, a point is (sx, sx, sy, w).
|
||||
# We want to keep w unbounded, restrict sx, sy, sz, px and py based on step.
|
||||
return (
|
||||
[
|
||||
xi * self.x_step + self.model.xmin,
|
||||
yi * self.y_step + self.model.ymin,
|
||||
zi * self.z_step + self.model.zmin,
|
||||
-numpy.inf,
|
||||
],
|
||||
[
|
||||
(xi + 1) * self.x_step + self.model.xmin,
|
||||
(yi + 1) * self.y_step + self.model.ymin,
|
||||
(zi + 1) * self.z_step + self.model.zmin,
|
||||
numpy.inf,
|
||||
],
|
||||
)
|
||||
|
||||
def all_indices(self) -> numpy.ndindex:
|
||||
# see https://github.com/numpy/numpy/issues/20706 for why this is a mypy problem.
|
||||
return numpy.ndindex((self.num_x, self.num_y, self.num_z)) # type:ignore
|
||||
|
||||
def solve_for_index(
|
||||
self, dots: Sequence[DotMeasurement], index: Tuple[float, ...]
|
||||
) -> scipy.optimize.OptimizeResult:
|
||||
bounds = self.bounds(index)
|
||||
sx_mean = (bounds[0][0] + bounds[1][0]) / 2
|
||||
sy_mean = (bounds[0][1] + bounds[1][1]) / 2
|
||||
sz_mean = (bounds[0][2] + bounds[1][2]) / 2
|
||||
return self.model.solve(
|
||||
dots,
|
||||
initial_pt=numpy.array([sx_mean, sy_mean, sz_mean, 0.1]),
|
||||
bounds=bounds,
|
||||
)
|
@ -1,27 +1,20 @@
|
||||
import numpy
|
||||
import numpy.random
|
||||
from dataclasses import dataclass
|
||||
from typing import Sequence, Tuple
|
||||
import scipy.optimize
|
||||
from pdme.model.model import Model, Discretisation
|
||||
from pdme.model.model import DipoleModel
|
||||
from pdme.measurement import (
|
||||
DotMeasurement,
|
||||
OscillatingDipole,
|
||||
OscillatingDipoleArrangement,
|
||||
)
|
||||
|
||||
|
||||
class FixedMagnitudeModel(Model):
|
||||
class SingleDipoleFixedMagnitudeModel(DipoleModel):
|
||||
"""
|
||||
Model of oscillating dipole with a fixed magnitude, but free rotation.
|
||||
Model of single oscillating dipole with a fixed magnitude, but free rotation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pfixed : float
|
||||
The fixed dipole magnitude.
|
||||
|
||||
n : int
|
||||
The number of dipoles to assume.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@ -33,7 +26,6 @@ class FixedMagnitudeModel(Model):
|
||||
zmin: float,
|
||||
zmax: float,
|
||||
pfixed: float,
|
||||
n: int,
|
||||
) -> None:
|
||||
self.xmin = xmin
|
||||
self.xmax = xmax
|
||||
@ -42,56 +34,40 @@ class FixedMagnitudeModel(Model):
|
||||
self.zmin = zmin
|
||||
self.zmax = zmax
|
||||
self.pfixed = pfixed
|
||||
self._n = n
|
||||
self.rng = numpy.random.default_rng()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"FixedMagnitudeModel({self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.zmin}, {self.zmax}, {self.pfixed}, {self.n()})"
|
||||
return f"SingleDipoleFixedMagnitudeModel({self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.zmin}, {self.zmax}, {self.pfixed})"
|
||||
|
||||
def solution_single_dipole(self, pt: numpy.ndarray) -> OscillatingDipole:
|
||||
# assume length is 6, who needs error checking.
|
||||
p_theta = pt[0]
|
||||
p_phi = pt[1]
|
||||
s = pt[2:5]
|
||||
w = pt[5]
|
||||
def get_dipoles(
|
||||
self, max_frequency: float, rng_to_use: numpy.random.Generator = None
|
||||
) -> OscillatingDipoleArrangement:
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
rng = self.rng
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
p = numpy.array(
|
||||
[
|
||||
self.pfixed * numpy.sin(p_theta) * numpy.cos(p_phi),
|
||||
self.pfixed * numpy.sin(p_theta) * numpy.sin(p_phi),
|
||||
self.pfixed * numpy.cos(p_theta),
|
||||
]
|
||||
)
|
||||
return OscillatingDipole(p, s, w)
|
||||
|
||||
def point_length(self) -> int:
|
||||
"""
|
||||
Dipole is constrained magnitude, but free orientation.
|
||||
Six degrees of freedom: (p_theta, p_phi, sx, sy, sz, w).
|
||||
"""
|
||||
return 6
|
||||
|
||||
def get_dipoles(self, frequency: float) -> OscillatingDipoleArrangement:
|
||||
theta = numpy.arccos(self.rng.uniform(-1, 1))
|
||||
phi = self.rng.uniform(0, 2 * numpy.pi)
|
||||
theta = numpy.arccos(rng.uniform(-1, 1))
|
||||
phi = rng.uniform(0, 2 * numpy.pi)
|
||||
px = self.pfixed * numpy.sin(theta) * numpy.cos(phi)
|
||||
py = self.pfixed * numpy.sin(theta) * numpy.sin(phi)
|
||||
pz = self.pfixed * numpy.cos(theta)
|
||||
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),
|
||||
rng.uniform(self.xmin, self.xmax),
|
||||
rng.uniform(self.ymin, self.ymax),
|
||||
rng.uniform(self.zmin, self.zmax),
|
||||
)
|
||||
)
|
||||
frequency = rng.uniform(0, max_frequency)
|
||||
return OscillatingDipoleArrangement(
|
||||
[OscillatingDipole(numpy.array([px, py, pz]), s_pts, frequency)]
|
||||
)
|
||||
|
||||
def get_n_single_dipoles(
|
||||
def get_monte_carlo_dipole_inputs(
|
||||
self, n: int, max_frequency: float, rng_to_use: numpy.random.Generator = None
|
||||
) -> numpy.ndarray:
|
||||
# psw
|
||||
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
@ -99,179 +75,17 @@ class FixedMagnitudeModel(Model):
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
theta = 2 * numpy.pi * rng.random(n)
|
||||
phi = numpy.arccos(2 * rng.random(n) - 1)
|
||||
shape = (n, 1)
|
||||
theta = 2 * numpy.pi * rng.random(shape)
|
||||
phi = numpy.arccos(2 * rng.random(shape) - 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 = rng.uniform(self.xmin, self.xmax, n)
|
||||
sy = rng.uniform(self.ymin, self.ymax, n)
|
||||
sz = rng.uniform(self.zmin, self.zmax, n)
|
||||
sx = rng.uniform(self.xmin, self.xmax, shape)
|
||||
sy = rng.uniform(self.ymin, self.ymax, shape)
|
||||
sz = rng.uniform(self.zmin, self.zmax, shape)
|
||||
|
||||
w = rng.uniform(1, max_frequency, n)
|
||||
w = rng.uniform(1, max_frequency, shape)
|
||||
|
||||
return numpy.array([px, py, pz, sx, sy, sz, w]).T
|
||||
|
||||
def n(self) -> int:
|
||||
return self._n
|
||||
|
||||
def v_for_point_at_dot(self, dot: DotMeasurement, pt: numpy.ndarray) -> float:
|
||||
p_theta = pt[0]
|
||||
p_phi = pt[1]
|
||||
s = pt[2:5]
|
||||
w = pt[5]
|
||||
|
||||
p = numpy.array(
|
||||
[
|
||||
self.pfixed * numpy.sin(p_theta) * numpy.cos(p_phi),
|
||||
self.pfixed * numpy.sin(p_theta) * numpy.sin(p_phi),
|
||||
self.pfixed * numpy.cos(p_theta),
|
||||
]
|
||||
)
|
||||
diff = dot.r - s
|
||||
alpha = p.dot(diff) / (numpy.linalg.norm(diff) ** 3)
|
||||
b = (1 / numpy.pi) * (w / (w**2 + dot.f**2))
|
||||
return alpha**2 * b
|
||||
|
||||
def jac_for_point_at_dot(
|
||||
self, dot: DotMeasurement, pt: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
p_theta = pt[0]
|
||||
p_phi = pt[1]
|
||||
s = pt[2:5]
|
||||
w = pt[5]
|
||||
|
||||
p = numpy.array(
|
||||
[
|
||||
self.pfixed * numpy.sin(p_theta) * numpy.cos(p_phi),
|
||||
self.pfixed * numpy.sin(p_theta) * numpy.sin(p_phi),
|
||||
self.pfixed * numpy.cos(p_theta),
|
||||
]
|
||||
)
|
||||
diff = dot.r - s
|
||||
alpha = p.dot(diff) / (numpy.linalg.norm(diff) ** 3)
|
||||
b = (1 / numpy.pi) * (w / (w**2 + dot.f**2))
|
||||
|
||||
theta_div_middle = self.pfixed * (
|
||||
diff[0] * numpy.cos(p_phi) * numpy.cos(p_theta)
|
||||
+ diff[1] * numpy.sin(p_phi) * numpy.cos(p_theta)
|
||||
- diff[2] * numpy.sin(p_theta)
|
||||
)
|
||||
theta_div = 2 * alpha * (theta_div_middle) / (numpy.linalg.norm(diff) ** 3) * b
|
||||
|
||||
phi_div_middle = self.pfixed * (
|
||||
diff[1] * numpy.sin(p_theta) * numpy.cos(p_phi)
|
||||
- diff[0] * numpy.sin(p_theta) * numpy.sin(p_phi)
|
||||
)
|
||||
phi_div = 2 * alpha * (phi_div_middle) / (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 = dot.f**2
|
||||
w2 = w**2
|
||||
|
||||
w_div = alpha**2 * (1 / numpy.pi) * ((f2 - w2) / ((f2 + w2) ** 2))
|
||||
|
||||
return numpy.concatenate((theta_div, phi_div, r_divs, w_div), axis=None)
|
||||
|
||||
|
||||
@dataclass
|
||||
class FixedMagnitudeDiscretisation(Discretisation):
|
||||
"""
|
||||
Representation of a discretisation of a FixedMagnitudeDiscretisation.
|
||||
Also captures a rough maximum value of dipole.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
model : FixedMagnitudeModel
|
||||
The parent model of the discretisation.
|
||||
|
||||
num_ptheta: int
|
||||
The number of partitions of ptheta.
|
||||
|
||||
num_pphi: int
|
||||
The number of partitions of pphi.
|
||||
|
||||
num_x : int
|
||||
The number of partitions of the x axis.
|
||||
|
||||
num_y : int
|
||||
The number of partitions of the y axis.
|
||||
|
||||
num_z : int
|
||||
The number of partitions of the z axis.
|
||||
"""
|
||||
|
||||
model: FixedMagnitudeModel
|
||||
num_ptheta: int
|
||||
num_pphi: int
|
||||
num_x: int
|
||||
num_y: int
|
||||
num_z: int
|
||||
|
||||
def __post_init__(self):
|
||||
self.cell_count = self.num_x * self.num_y * self.num_z
|
||||
self.x_step = (self.model.xmax - self.model.xmin) / self.num_x
|
||||
self.y_step = (self.model.ymax - self.model.ymin) / self.num_y
|
||||
self.z_step = (self.model.zmax - self.model.zmin) / self.num_z
|
||||
self.h_step = 2 / self.num_ptheta
|
||||
self.phi_step = 2 * numpy.pi / self.num_pphi
|
||||
|
||||
def bounds(self, index: Tuple[float, ...]) -> Tuple:
|
||||
pthetai, pphii, xi, yi, zi = index
|
||||
|
||||
# For this model, a point is (p_theta, p_phi, sx, sx, sy, w).
|
||||
# We want to keep w unbounded, restrict sx, sy, sz, px and py based on step.
|
||||
return (
|
||||
[
|
||||
numpy.arccos(1 - pthetai * self.h_step),
|
||||
pphii * self.phi_step,
|
||||
xi * self.x_step + self.model.xmin,
|
||||
yi * self.y_step + self.model.ymin,
|
||||
zi * self.z_step + self.model.zmin,
|
||||
-numpy.inf,
|
||||
],
|
||||
[
|
||||
numpy.arccos(1 - (pthetai + 1) * self.h_step),
|
||||
(pphii + 1) * self.phi_step,
|
||||
(xi + 1) * self.x_step + self.model.xmin,
|
||||
(yi + 1) * self.y_step + self.model.ymin,
|
||||
(zi + 1) * self.z_step + self.model.zmin,
|
||||
numpy.inf,
|
||||
],
|
||||
)
|
||||
|
||||
def get_model(self) -> Model:
|
||||
return self.model
|
||||
|
||||
def all_indices(self) -> numpy.ndindex:
|
||||
# see https://github.com/numpy/numpy/issues/20706 for why this is a mypy problem.
|
||||
return numpy.ndindex(
|
||||
(self.num_ptheta, self.num_pphi, self.num_x, self.num_y, self.num_z)
|
||||
) # type:ignore
|
||||
|
||||
def solve_for_index(
|
||||
self, dots: Sequence[DotMeasurement], index: Tuple[float, ...]
|
||||
) -> scipy.optimize.OptimizeResult:
|
||||
bounds = self.bounds(index)
|
||||
ptheta_mean = (bounds[0][0] + bounds[1][0]) / 2
|
||||
pphi_mean = (bounds[0][1] + bounds[1][1]) / 2
|
||||
sx_mean = (bounds[0][2] + bounds[1][2]) / 2
|
||||
sy_mean = (bounds[0][3] + bounds[1][3]) / 2
|
||||
sz_mean = (bounds[0][4] + bounds[1][4]) / 2
|
||||
return self.model.solve(
|
||||
dots,
|
||||
initial_pt=numpy.array(
|
||||
[ptheta_mean, pphi_mean, sx_mean, sy_mean, sz_mean, 0.1]
|
||||
),
|
||||
bounds=bounds,
|
||||
)
|
||||
return numpy.stack([px, py, pz, sx, sy, sz, w], axis=-1)
|
||||
|
@ -1,173 +0,0 @@
|
||||
import numpy
|
||||
from dataclasses import dataclass
|
||||
from typing import Tuple, Sequence
|
||||
import scipy.optimize
|
||||
|
||||
from pdme.model.model import Model
|
||||
from pdme.measurement import DotMeasurement
|
||||
|
||||
|
||||
class FixedZPlaneModel(Model):
|
||||
"""
|
||||
Model of oscillating dipoles constrained to lie within a plane.
|
||||
Additionally, each dipole is assumed to be orientated in the plus or minus z direction.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
z : float
|
||||
The z position of the plane where dipoles are constrained to lie.
|
||||
|
||||
xmin : float
|
||||
The minimum x value for dipoles.
|
||||
|
||||
xmax : float
|
||||
The maximum x value for dipoles.
|
||||
|
||||
ymin : float
|
||||
The minimum y value for dipoles.
|
||||
|
||||
ymax : float
|
||||
The maximum y value for dipoles.
|
||||
|
||||
n : int
|
||||
The number of dipoles to assume.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, z: float, xmin: float, xmax: float, ymin: float, ymax: float, n: int
|
||||
) -> None:
|
||||
self.z = z
|
||||
self.xmin = xmin
|
||||
self.xmax = xmax
|
||||
self.ymin = ymin
|
||||
self.ymax = ymax
|
||||
self._n = n
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"FixedZPlaneModel({self.z}, {self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.n()})"
|
||||
|
||||
def point_length(self) -> int:
|
||||
"""
|
||||
Dipole is constrained in this model to have (px, py, pz) = (0, 0, pz) and (sx, sy, sz) = (sx, sy, self.z).
|
||||
With some frequency w, there are four degrees of freedom: (pz, sx, sy, w).
|
||||
"""
|
||||
return 4
|
||||
|
||||
def n(self) -> int:
|
||||
return self._n
|
||||
|
||||
def v_for_point_at_dot(self, dot: DotMeasurement, pt: numpy.ndarray) -> float:
|
||||
p = numpy.array([0, 0, pt[0]])
|
||||
s = numpy.array([pt[1], pt[2], self.z])
|
||||
w = pt[3]
|
||||
|
||||
diff = dot.r - s
|
||||
alpha = p.dot(diff) / (numpy.linalg.norm(diff) ** 3)
|
||||
b = (1 / numpy.pi) * (w / (w**2 + dot.f**2))
|
||||
return alpha**2 * b
|
||||
|
||||
def jac_for_point_at_dot(
|
||||
self, dot: DotMeasurement, pt: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
p = numpy.array([0, 0, pt[0]])
|
||||
s = numpy.array([pt[1], pt[2], self.z])
|
||||
w = pt[3]
|
||||
|
||||
diff = dot.r - s
|
||||
alpha = p.dot(diff) / (numpy.linalg.norm(diff) ** 3)
|
||||
b = (1 / numpy.pi) * (w / (w**2 + dot.f**2))
|
||||
|
||||
p_divs = (
|
||||
2 * alpha * diff[2] / (numpy.linalg.norm(diff) ** 3) * b
|
||||
) # only need the z component.
|
||||
|
||||
r_divs = (
|
||||
(
|
||||
-p[0:2] / (numpy.linalg.norm(diff) ** 3)
|
||||
+ 3 * p.dot(diff) * diff[0:2] / (numpy.linalg.norm(diff) ** 5)
|
||||
)
|
||||
* 2
|
||||
* alpha
|
||||
* b
|
||||
)
|
||||
|
||||
f2 = dot.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)
|
||||
|
||||
|
||||
@dataclass
|
||||
class FixedZPlaneDiscretisation:
|
||||
"""
|
||||
Representation of a discretisation of a FixedZPlaneModel.
|
||||
Also captures a rough maximum value of dipole.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
model : FixedZPlaneModel
|
||||
The parent model of the discretisation.
|
||||
|
||||
num_pz: int
|
||||
The number of partitions of pz.
|
||||
|
||||
num_x : int
|
||||
The number of partitions of the x axis.
|
||||
|
||||
num_y : int
|
||||
The number of partitions of the y axis.
|
||||
"""
|
||||
|
||||
model: FixedZPlaneModel
|
||||
num_pz: int
|
||||
num_x: int
|
||||
num_y: int
|
||||
max_pz: int
|
||||
|
||||
def __post_init__(self):
|
||||
self.cell_count = self.num_x * self.num_y
|
||||
self.pz_step = (2 * self.max_pz) / self.num_pz
|
||||
self.x_step = (self.model.xmax - self.model.xmin) / self.num_x
|
||||
self.y_step = (self.model.ymax - self.model.ymin) / self.num_y
|
||||
|
||||
def bounds(
|
||||
self, index: Tuple[float, float, float]
|
||||
) -> Tuple[numpy.ndarray, numpy.ndarray]:
|
||||
pzi, xi, yi = index
|
||||
|
||||
# For this model, a point is (pz, sx, sy, w).
|
||||
# We want to keep w bounded, and restrict pz, sx and sy based on step.
|
||||
return (
|
||||
numpy.array(
|
||||
(
|
||||
pzi * self.pz_step - self.max_pz,
|
||||
xi * self.x_step + self.model.xmin,
|
||||
yi * self.y_step + self.model.ymin,
|
||||
-numpy.inf,
|
||||
)
|
||||
),
|
||||
numpy.array(
|
||||
(
|
||||
(pzi + 1) * self.pz_step - self.max_pz,
|
||||
(xi + 1) * self.x_step + self.model.xmin,
|
||||
(yi + 1) * self.y_step + self.model.ymin,
|
||||
numpy.inf,
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
def all_indices(self) -> numpy.ndindex:
|
||||
# see https://github.com/numpy/numpy/issues/20706 for why this is a mypy problem.
|
||||
return numpy.ndindex((self.num_pz, self.num_x, self.num_y)) # type:ignore
|
||||
|
||||
def solve_for_index(
|
||||
self, dots: Sequence[DotMeasurement], index: Tuple[float, float, float]
|
||||
) -> scipy.optimize.OptimizeResult:
|
||||
bounds = self.bounds(index)
|
||||
pz_mean = (bounds[0][0] + bounds[1][0]) / 2
|
||||
sx_mean = (bounds[0][1] + bounds[1][1]) / 2
|
||||
sy_mean = (bounds[0][2] + bounds[1][2]) / 2
|
||||
# I don't care about the typing here at the moment.
|
||||
return self.model.solve(dots, initial_pt=numpy.array((pz_mean, sx_mean, sy_mean, 0.1)), bounds=bounds) # type: ignore
|
195
pdme/model/log_spaced_random_choice_fixed_orientation_model.py
Normal file
195
pdme/model/log_spaced_random_choice_fixed_orientation_model.py
Normal file
@ -0,0 +1,195 @@
|
||||
import numpy
|
||||
import numpy.random
|
||||
from pdme.model.model import DipoleModel
|
||||
from pdme.measurement import (
|
||||
OscillatingDipole,
|
||||
OscillatingDipoleArrangement,
|
||||
)
|
||||
import logging
|
||||
from typing import Optional
|
||||
import pdme.subspace_simulation
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel(
|
||||
DipoleModel
|
||||
):
|
||||
"""
|
||||
Model of multiple oscillating dipoles with a fixed magnitude and fixed rotation. Spaced log uniformly in relaxation time.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
wexp_min: log-10 lower bound for dipole frequency
|
||||
wexp_min: log-10 upper bound for dipole frequency
|
||||
|
||||
pfixed : float
|
||||
The fixed dipole magnitude.
|
||||
|
||||
thetafixed: float
|
||||
The fixed theta (polar angle).
|
||||
Should be between 0 and pi.
|
||||
|
||||
phifixed: float
|
||||
The fixed phi (azimuthal angle).
|
||||
Should be between 0 and 2 pi.
|
||||
|
||||
n_max : int
|
||||
The maximum number of dipoles.
|
||||
|
||||
prob_occupancy : float
|
||||
The probability of dipole occupancy
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
xmin: float,
|
||||
xmax: float,
|
||||
ymin: float,
|
||||
ymax: float,
|
||||
zmin: float,
|
||||
zmax: float,
|
||||
wexp_min: float,
|
||||
wexp_max: float,
|
||||
pfixed: float,
|
||||
thetafixed: float,
|
||||
phifixed: float,
|
||||
n_max: int,
|
||||
prob_occupancy: float,
|
||||
) -> None:
|
||||
self.xmin = xmin
|
||||
self.xmax = xmax
|
||||
self.ymin = ymin
|
||||
self.ymax = ymax
|
||||
self.zmin = zmin
|
||||
self.zmax = zmax
|
||||
self.wexp_min = wexp_min
|
||||
self.wexp_max = wexp_max
|
||||
self.pfixed = pfixed
|
||||
self.thetafixed = thetafixed
|
||||
self.phifixed = phifixed
|
||||
self.rng = numpy.random.default_rng()
|
||||
self.n_max = n_max
|
||||
|
||||
px = self.pfixed * numpy.sin(self.thetafixed) * numpy.cos(self.phifixed)
|
||||
py = self.pfixed * numpy.sin(self.thetafixed) * numpy.sin(self.phifixed)
|
||||
pz = self.pfixed * numpy.cos(self.thetafixed)
|
||||
|
||||
self.moment_fixed = numpy.array([px, py, pz])
|
||||
if prob_occupancy >= 1 or prob_occupancy <= 0:
|
||||
raise ValueError(
|
||||
f"The probability of a dipole site occupancy must be between 0 and 1, got {prob_occupancy}"
|
||||
)
|
||||
self.prob_occupancy = prob_occupancy
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel({self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.zmin}, {self.zmax}, {self.wexp_min}, {self.wexp_max}, {self.pfixed}, {self.thetafixed}, {self.phifixed}, {self.n_max}, {self.prob_occupancy})"
|
||||
|
||||
def get_dipoles(
|
||||
self, max_frequency: float, rng_to_use: numpy.random.Generator = None
|
||||
) -> OscillatingDipoleArrangement:
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
rng = self.rng
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
dipoles = []
|
||||
|
||||
n = rng.binomial(self.n_max, self.prob_occupancy)
|
||||
|
||||
for i in range(n):
|
||||
s_pts = numpy.array(
|
||||
(
|
||||
rng.uniform(self.xmin, self.xmax),
|
||||
rng.uniform(self.ymin, self.ymax),
|
||||
rng.uniform(self.zmin, self.zmax),
|
||||
)
|
||||
)
|
||||
frequency = 10 ** rng.uniform(self.wexp_min, self.wexp_max)
|
||||
|
||||
dipoles.append(OscillatingDipole(self.moment_fixed, s_pts, frequency))
|
||||
return OscillatingDipoleArrangement(dipoles)
|
||||
|
||||
def get_monte_carlo_dipole_inputs(
|
||||
self,
|
||||
monte_carlo_n: int,
|
||||
_: float,
|
||||
rng_to_use: numpy.random.Generator = None,
|
||||
) -> numpy.ndarray:
|
||||
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
rng = self.rng
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
shape = (monte_carlo_n, self.n_max)
|
||||
|
||||
p_mask = rng.binomial(1, self.prob_occupancy, shape)
|
||||
|
||||
# dipoles = numpy.einsum("ij,k->ijk", p_mask, self.moment_fixed)
|
||||
# Is there a better way to create the final array? probably! can create a flatter guy then reshape.
|
||||
# this is easier to reason about.
|
||||
p_magnitude = self.pfixed * p_mask
|
||||
|
||||
px = p_magnitude * numpy.sin(self.thetafixed) * numpy.cos(self.phifixed)
|
||||
py = p_magnitude * numpy.sin(self.thetafixed) * numpy.sin(self.phifixed)
|
||||
pz = p_magnitude * numpy.cos(self.thetafixed)
|
||||
|
||||
sx = rng.uniform(self.xmin, self.xmax, shape)
|
||||
sy = rng.uniform(self.ymin, self.ymax, shape)
|
||||
sz = rng.uniform(self.zmin, self.zmax, shape)
|
||||
|
||||
w = 10 ** rng.uniform(self.wexp_min, self.wexp_max, shape)
|
||||
|
||||
return numpy.stack([px, py, pz, sx, sy, sz, w], axis=-1)
|
||||
|
||||
def markov_chain_monte_carlo_proposal(
|
||||
self,
|
||||
dipole: numpy.ndarray,
|
||||
stdev: pdme.subspace_simulation.DipoleStandardDeviation,
|
||||
rng_arg: Optional[numpy.random.Generator] = None,
|
||||
) -> numpy.ndarray:
|
||||
if rng_arg is None:
|
||||
rng_to_use = self.rng
|
||||
else:
|
||||
rng_to_use = rng_arg
|
||||
|
||||
px = dipole[0]
|
||||
py = dipole[1]
|
||||
pz = dipole[2]
|
||||
# won't change p for this model of fixed dipole moment.
|
||||
|
||||
rx = dipole[3]
|
||||
ry = dipole[4]
|
||||
rz = dipole[5]
|
||||
|
||||
tentative_rx = rx + stdev.rx_step * rng_to_use.uniform(-1, 1)
|
||||
if tentative_rx < self.xmin or tentative_rx > self.xmax:
|
||||
tentative_rx = rx
|
||||
|
||||
tentative_ry = ry + stdev.ry_step * rng_to_use.uniform(-1, 1)
|
||||
if tentative_ry < self.ymin or tentative_ry > self.ymax:
|
||||
tentative_ry = ry
|
||||
tentative_rz = rz + stdev.rz_step * rng_to_use.uniform(-1, 1)
|
||||
if tentative_rz < self.zmin or tentative_rz > self.zmax:
|
||||
tentative_rz = rz
|
||||
|
||||
w = dipole[6]
|
||||
tentative_w = numpy.exp(
|
||||
numpy.log(w) + (stdev.w_log_step * rng_to_use.uniform(-1, 1))
|
||||
)
|
||||
tentative_dip = numpy.array(
|
||||
[
|
||||
px,
|
||||
py,
|
||||
pz,
|
||||
tentative_rx,
|
||||
tentative_ry,
|
||||
tentative_rz,
|
||||
tentative_w,
|
||||
]
|
||||
)
|
||||
return tentative_dip
|
199
pdme/model/log_spaced_random_choice_model.py
Normal file
199
pdme/model/log_spaced_random_choice_model.py
Normal file
@ -0,0 +1,199 @@
|
||||
import numpy
|
||||
import numpy.random
|
||||
from pdme.model.model import DipoleModel
|
||||
from pdme.measurement import (
|
||||
OscillatingDipole,
|
||||
OscillatingDipoleArrangement,
|
||||
)
|
||||
import pdme.subspace_simulation
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel(DipoleModel):
|
||||
"""
|
||||
Model of multiple oscillating dipoles with a fixed magnitude, but free rotation. Spaced logarithmically.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
wexp_min: log-10 lower bound for dipole frequency
|
||||
wexp_min: log-10 upper bound for dipole frequency
|
||||
|
||||
pfixed : float
|
||||
The fixed dipole magnitude.
|
||||
|
||||
n_max : int
|
||||
The maximum number of dipoles.
|
||||
|
||||
prob_occupancy : float
|
||||
The probability of dipole occupancy
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
xmin: float,
|
||||
xmax: float,
|
||||
ymin: float,
|
||||
ymax: float,
|
||||
zmin: float,
|
||||
zmax: float,
|
||||
wexp_min: float,
|
||||
wexp_max: float,
|
||||
pfixed: float,
|
||||
n_max: int,
|
||||
prob_occupancy: float,
|
||||
) -> None:
|
||||
self.xmin = xmin
|
||||
self.xmax = xmax
|
||||
self.ymin = ymin
|
||||
self.ymax = ymax
|
||||
self.zmin = zmin
|
||||
self.zmax = zmax
|
||||
self.wexp_min = wexp_min
|
||||
self.wexp_max = wexp_max
|
||||
self.pfixed = pfixed
|
||||
self.rng = numpy.random.default_rng()
|
||||
self.n_max = n_max
|
||||
if prob_occupancy >= 1 or prob_occupancy <= 0:
|
||||
raise ValueError(
|
||||
f"The probability of a dipole site occupancy must be between 0 and 1, got {prob_occupancy}"
|
||||
)
|
||||
self.prob_occupancy = prob_occupancy
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel({self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.zmin}, {self.zmax}, {self.wexp_min}, {self.wexp_max}, {self.pfixed}, {self.n_max}, {self.prob_occupancy})"
|
||||
|
||||
def get_dipoles(
|
||||
self, max_frequency: float, rng_to_use: numpy.random.Generator = None
|
||||
) -> OscillatingDipoleArrangement:
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
rng = self.rng
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
dipoles = []
|
||||
|
||||
n = rng.binomial(self.n_max, self.prob_occupancy)
|
||||
|
||||
for i in range(n):
|
||||
theta = numpy.arccos(rng.uniform(-1, 1))
|
||||
phi = rng.uniform(0, 2 * numpy.pi)
|
||||
px = self.pfixed * numpy.sin(theta) * numpy.cos(phi)
|
||||
py = self.pfixed * numpy.sin(theta) * numpy.sin(phi)
|
||||
pz = self.pfixed * numpy.cos(theta)
|
||||
s_pts = numpy.array(
|
||||
(
|
||||
rng.uniform(self.xmin, self.xmax),
|
||||
rng.uniform(self.ymin, self.ymax),
|
||||
rng.uniform(self.zmin, self.zmax),
|
||||
)
|
||||
)
|
||||
frequency = 10 ** rng.uniform(self.wexp_min, self.wexp_max)
|
||||
|
||||
dipoles.append(
|
||||
OscillatingDipole(numpy.array([px, py, pz]), s_pts, frequency)
|
||||
)
|
||||
return OscillatingDipoleArrangement(dipoles)
|
||||
|
||||
def get_monte_carlo_dipole_inputs(
|
||||
self,
|
||||
monte_carlo_n: int,
|
||||
_: float,
|
||||
rng_to_use: numpy.random.Generator = None,
|
||||
) -> numpy.ndarray:
|
||||
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
rng = self.rng
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
shape = (monte_carlo_n, self.n_max)
|
||||
theta = 2 * numpy.pi * rng.random(shape)
|
||||
phi = numpy.arccos(2 * rng.random(shape) - 1)
|
||||
|
||||
p_mask = rng.binomial(1, self.prob_occupancy, shape)
|
||||
p_magnitude = self.pfixed * p_mask
|
||||
|
||||
px = p_magnitude * numpy.cos(theta) * numpy.sin(phi)
|
||||
py = p_magnitude * numpy.sin(theta) * numpy.sin(phi)
|
||||
pz = p_magnitude * numpy.cos(phi)
|
||||
|
||||
sx = rng.uniform(self.xmin, self.xmax, shape)
|
||||
sy = rng.uniform(self.ymin, self.ymax, shape)
|
||||
sz = rng.uniform(self.zmin, self.zmax, shape)
|
||||
|
||||
w = 10 ** rng.uniform(self.wexp_min, self.wexp_max, shape)
|
||||
|
||||
return numpy.stack([px, py, pz, sx, sy, sz, w], axis=-1)
|
||||
|
||||
def markov_chain_monte_carlo_proposal(
|
||||
self,
|
||||
dipole: numpy.ndarray,
|
||||
stdev: pdme.subspace_simulation.DipoleStandardDeviation,
|
||||
rng_arg: Optional[numpy.random.Generator] = None,
|
||||
) -> numpy.ndarray:
|
||||
if rng_arg is None:
|
||||
rng_to_use = self.rng
|
||||
else:
|
||||
rng_to_use = rng_arg
|
||||
|
||||
px = dipole[0]
|
||||
py = dipole[1]
|
||||
pz = dipole[2]
|
||||
theta = numpy.arccos(pz / self.pfixed)
|
||||
phi = numpy.arctan2(py, px)
|
||||
|
||||
# need to step phi, theta, rx, ry, rz, w
|
||||
# then p^\ast is 1/(2 phi_step) and Delta = phi_step(2 * {0, 1} - 1)
|
||||
delta_phi = stdev.p_phi_step * rng_to_use.uniform(-1, 1)
|
||||
tentative_phi = phi + delta_phi
|
||||
|
||||
# theta
|
||||
delta_theta = stdev.p_theta_step * rng_to_use.uniform(-1, 1)
|
||||
r = (numpy.sin(theta + delta_theta)) / (numpy.sin(theta))
|
||||
if r > rng_to_use.uniform(0, 1):
|
||||
tentative_theta = theta + delta_theta
|
||||
else:
|
||||
tentative_theta = theta
|
||||
|
||||
tentative_px = (
|
||||
self.pfixed * numpy.sin(tentative_theta) * numpy.cos(tentative_phi)
|
||||
)
|
||||
tentative_py = (
|
||||
self.pfixed * numpy.sin(tentative_theta) * numpy.sin(tentative_phi)
|
||||
)
|
||||
tentative_pz = self.pfixed * numpy.cos(tentative_theta)
|
||||
|
||||
rx = dipole[3]
|
||||
ry = dipole[4]
|
||||
rz = dipole[5]
|
||||
|
||||
tentative_rx = rx + stdev.rx_step * rng_to_use.uniform(-1, 1)
|
||||
if tentative_rx < self.xmin or tentative_rx > self.xmax:
|
||||
tentative_rx = rx
|
||||
|
||||
tentative_ry = ry + stdev.ry_step * rng_to_use.uniform(-1, 1)
|
||||
if tentative_ry < self.ymin or tentative_ry > self.ymax:
|
||||
tentative_ry = ry
|
||||
tentative_rz = rz + stdev.rz_step * rng_to_use.uniform(-1, 1)
|
||||
if tentative_rz < self.zmin or tentative_rz > self.zmax:
|
||||
tentative_rz = rz
|
||||
|
||||
w = dipole[6]
|
||||
tentative_w = numpy.exp(
|
||||
numpy.log(w) + (stdev.w_log_step * rng_to_use.uniform(-1, 1))
|
||||
)
|
||||
tentative_dip = numpy.array(
|
||||
[
|
||||
tentative_px,
|
||||
tentative_py,
|
||||
tentative_pz,
|
||||
tentative_rx,
|
||||
tentative_ry,
|
||||
tentative_rz,
|
||||
tentative_w,
|
||||
]
|
||||
)
|
||||
return tentative_dip
|
183
pdme/model/log_spaced_random_choice_xy_model.py
Normal file
183
pdme/model/log_spaced_random_choice_xy_model.py
Normal file
@ -0,0 +1,183 @@
|
||||
import numpy
|
||||
import numpy.random
|
||||
from pdme.model.model import DipoleModel
|
||||
from pdme.measurement import (
|
||||
OscillatingDipole,
|
||||
OscillatingDipoleArrangement,
|
||||
)
|
||||
import pdme.subspace_simulation
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel(DipoleModel):
|
||||
"""
|
||||
Model of multiple oscillating dipoles with a fixed magnitude, but free rotation in XY plane. Spaced logarithmically.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
wexp_min: log-10 lower bound for dipole frequency
|
||||
wexp_min: log-10 upper bound for dipole frequency
|
||||
|
||||
pfixed : float
|
||||
The fixed dipole magnitude.
|
||||
|
||||
n_max : int
|
||||
The maximum number of dipoles.
|
||||
|
||||
prob_occupancy : float
|
||||
The probability of dipole occupancy
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
xmin: float,
|
||||
xmax: float,
|
||||
ymin: float,
|
||||
ymax: float,
|
||||
zmin: float,
|
||||
zmax: float,
|
||||
wexp_min: float,
|
||||
wexp_max: float,
|
||||
pfixed: float,
|
||||
n_max: int,
|
||||
prob_occupancy: float,
|
||||
) -> None:
|
||||
self.xmin = xmin
|
||||
self.xmax = xmax
|
||||
self.ymin = ymin
|
||||
self.ymax = ymax
|
||||
self.zmin = zmin
|
||||
self.zmax = zmax
|
||||
self.wexp_min = wexp_min
|
||||
self.wexp_max = wexp_max
|
||||
self.pfixed = pfixed
|
||||
self.rng = numpy.random.default_rng()
|
||||
self.n_max = n_max
|
||||
if prob_occupancy >= 1 or prob_occupancy <= 0:
|
||||
raise ValueError(
|
||||
f"The probability of a dipole site occupancy must be between 0 and 1, got {prob_occupancy}"
|
||||
)
|
||||
self.prob_occupancy = prob_occupancy
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel({self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.zmin}, {self.zmax}, {self.wexp_min}, {self.wexp_max}, {self.pfixed}, {self.n_max}, {self.prob_occupancy})"
|
||||
|
||||
def get_dipoles(
|
||||
self, max_frequency: float, rng_to_use: numpy.random.Generator = None
|
||||
) -> OscillatingDipoleArrangement:
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
rng = self.rng
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
dipoles = []
|
||||
|
||||
n = rng.binomial(self.n_max, self.prob_occupancy)
|
||||
|
||||
for i in range(n):
|
||||
phi = rng.uniform(0, 2 * numpy.pi)
|
||||
px = self.pfixed * numpy.cos(phi)
|
||||
py = self.pfixed * numpy.sin(phi)
|
||||
pz = 0
|
||||
s_pts = numpy.array(
|
||||
(
|
||||
rng.uniform(self.xmin, self.xmax),
|
||||
rng.uniform(self.ymin, self.ymax),
|
||||
rng.uniform(self.zmin, self.zmax),
|
||||
)
|
||||
)
|
||||
frequency = 10 ** rng.uniform(self.wexp_min, self.wexp_max)
|
||||
|
||||
dipoles.append(
|
||||
OscillatingDipole(numpy.array([px, py, pz]), s_pts, frequency)
|
||||
)
|
||||
return OscillatingDipoleArrangement(dipoles)
|
||||
|
||||
def get_monte_carlo_dipole_inputs(
|
||||
self,
|
||||
monte_carlo_n: int,
|
||||
_: float,
|
||||
rng_to_use: numpy.random.Generator = None,
|
||||
) -> numpy.ndarray:
|
||||
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
rng = self.rng
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
shape = (monte_carlo_n, self.n_max)
|
||||
phi = 2 * numpy.pi * rng.random(shape)
|
||||
|
||||
p_mask = rng.binomial(1, self.prob_occupancy, shape)
|
||||
p_magnitude = self.pfixed * p_mask
|
||||
|
||||
px = p_magnitude * numpy.cos(phi)
|
||||
py = p_magnitude * numpy.sin(phi)
|
||||
pz = p_magnitude * 0
|
||||
|
||||
sx = rng.uniform(self.xmin, self.xmax, shape)
|
||||
sy = rng.uniform(self.ymin, self.ymax, shape)
|
||||
sz = rng.uniform(self.zmin, self.zmax, shape)
|
||||
|
||||
w = 10 ** rng.uniform(self.wexp_min, self.wexp_max, shape)
|
||||
|
||||
return numpy.stack([px, py, pz, sx, sy, sz, w], axis=-1)
|
||||
|
||||
def markov_chain_monte_carlo_proposal(
|
||||
self,
|
||||
dipole: numpy.ndarray,
|
||||
stdev: pdme.subspace_simulation.DipoleStandardDeviation,
|
||||
rng_arg: Optional[numpy.random.Generator] = None,
|
||||
) -> numpy.ndarray:
|
||||
if rng_arg is None:
|
||||
rng_to_use = self.rng
|
||||
else:
|
||||
rng_to_use = rng_arg
|
||||
|
||||
px = dipole[0]
|
||||
py = dipole[1]
|
||||
pz = dipole[2]
|
||||
phi = numpy.arctan2(py, px)
|
||||
|
||||
# need to step phi, rx, ry, rz, w
|
||||
# then p^\ast is 1/(2 phi_step) and Delta = phi_step(2 * {0, 1} - 1)
|
||||
delta_phi = stdev.p_phi_step * rng_to_use.uniform(-1, 1)
|
||||
tentative_phi = phi + delta_phi
|
||||
|
||||
tentative_px = self.pfixed * numpy.cos(tentative_phi)
|
||||
tentative_py = self.pfixed * numpy.sin(tentative_phi)
|
||||
|
||||
rx = dipole[3]
|
||||
ry = dipole[4]
|
||||
rz = dipole[5]
|
||||
|
||||
tentative_rx = rx + stdev.rx_step * rng_to_use.uniform(-1, 1)
|
||||
if tentative_rx < self.xmin or tentative_rx > self.xmax:
|
||||
tentative_rx = rx
|
||||
|
||||
tentative_ry = ry + stdev.ry_step * rng_to_use.uniform(-1, 1)
|
||||
if tentative_ry < self.ymin or tentative_ry > self.ymax:
|
||||
tentative_ry = ry
|
||||
tentative_rz = rz + stdev.rz_step * rng_to_use.uniform(-1, 1)
|
||||
if tentative_rz < self.zmin or tentative_rz > self.zmax:
|
||||
tentative_rz = rz
|
||||
|
||||
w = dipole[6]
|
||||
tentative_w = numpy.exp(
|
||||
numpy.log(w) + (stdev.w_log_step * rng_to_use.uniform(-1, 1))
|
||||
)
|
||||
tentative_dip = numpy.array(
|
||||
[
|
||||
tentative_px,
|
||||
tentative_py,
|
||||
pz,
|
||||
tentative_rx,
|
||||
tentative_ry,
|
||||
tentative_rz,
|
||||
tentative_w,
|
||||
]
|
||||
)
|
||||
return tentative_dip
|
@ -1,154 +1,163 @@
|
||||
import numpy
|
||||
import numpy.random
|
||||
import scipy.optimize
|
||||
from typing import Callable, Sequence, Tuple, List
|
||||
from pdme.measurement import (
|
||||
DotMeasurement,
|
||||
OscillatingDipoleArrangement,
|
||||
OscillatingDipole,
|
||||
)
|
||||
import pdme.util
|
||||
import logging
|
||||
|
||||
import pdme.subspace_simulation
|
||||
from typing import List, Tuple, Optional
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Model:
|
||||
class DipoleModel:
|
||||
"""
|
||||
Interface for models.
|
||||
Interface for models based on dipoles.
|
||||
Some concepts are kept specific for dipole-based models, even though other types of models could be useful later on.
|
||||
"""
|
||||
|
||||
def point_length(self) -> int:
|
||||
def get_dipoles(
|
||||
self, max_frequency: float, rng: numpy.random.Generator = None
|
||||
) -> OscillatingDipoleArrangement:
|
||||
"""
|
||||
For a particular maximum frequency, gets a dipole arrangement based on the model that uniformly distributes its choices according to the model.
|
||||
If no rng is passed in, uses some default, but you might not want that.
|
||||
Frequencies should be chosen uniformly on range of (0, max_frequency).
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def n(self) -> int:
|
||||
raise NotImplementedError
|
||||
|
||||
def v_for_point_at_dot(self, dot: DotMeasurement, pt: numpy.ndarray) -> float:
|
||||
raise NotImplementedError
|
||||
|
||||
def get_dipoles(self, frequency: float) -> OscillatingDipoleArrangement:
|
||||
raise NotImplementedError
|
||||
|
||||
def get_n_single_dipoles(
|
||||
def get_monte_carlo_dipole_inputs(
|
||||
self, n: int, max_frequency: float, rng: numpy.random.Generator = None
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
For a given DipoleModel, gets a set of dipole collections as a monte_carlo_n x dipole_count x 7 numpy array.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def solution_single_dipole(self, pt: numpy.ndarray) -> OscillatingDipole:
|
||||
raise NotImplementedError
|
||||
|
||||
def solution_as_dipoles(self, pts: numpy.ndarray) -> List[OscillatingDipole]:
|
||||
pt_length = self.point_length()
|
||||
chunked_pts = [pts[i : i + pt_length] for i in range(0, len(pts), pt_length)]
|
||||
return [self.solution_single_dipole(pt) for pt in chunked_pts]
|
||||
|
||||
def cost_for_dot(self, dot: DotMeasurement, pts: numpy.ndarray) -> float:
|
||||
# creates numpy.ndarrays in groups of self.point_length().
|
||||
# Will throw problems for irregular points, but that's okay for now.
|
||||
pt_length = self.point_length()
|
||||
chunked_pts = [pts[i : i + pt_length] for i in range(0, len(pts), pt_length)]
|
||||
return sum(self.v_for_point_at_dot(dot, pt) for pt in chunked_pts) - dot.v
|
||||
|
||||
def costs(
|
||||
self, dots: Sequence[DotMeasurement]
|
||||
) -> Callable[[numpy.ndarray], numpy.ndarray]:
|
||||
"""
|
||||
Returns a function that returns the cost for the given list of DotMeasurements for a particular model-dependent phase space point.
|
||||
Default implementation assumes a single dot cost from which to build the list.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
dots: A list of dot measurements to use to find the cost functions.
|
||||
|
||||
Returns
|
||||
----------
|
||||
Returns the model's cost function.
|
||||
"""
|
||||
_logger.debug(f"Constructing costs for dots: {dots}")
|
||||
|
||||
def costs_to_return(pts: numpy.ndarray) -> numpy.ndarray:
|
||||
return numpy.array([self.cost_for_dot(dot, pts) for dot in dots])
|
||||
|
||||
return costs_to_return
|
||||
|
||||
def jac_for_point_at_dot(
|
||||
self, dot: DotMeasurement, pt: numpy.ndarray
|
||||
def markov_chain_monte_carlo_proposal(
|
||||
self,
|
||||
dipole: numpy.ndarray,
|
||||
stdev: pdme.subspace_simulation.DipoleStandardDeviation,
|
||||
rng_arg: Optional[numpy.random.Generator] = None,
|
||||
) -> numpy.ndarray:
|
||||
raise NotImplementedError
|
||||
|
||||
def jac_for_dot(self, dot: DotMeasurement, pts: numpy.ndarray) -> numpy.ndarray:
|
||||
# creates numpy.ndarrays in groups of self.point_length().
|
||||
# Will throw problems for irregular points, but that's okay for now.
|
||||
pt_length = self.point_length()
|
||||
chunked_pts = [pts[i : i + pt_length] for i in range(0, len(pts), pt_length)]
|
||||
return numpy.append(
|
||||
[], [self.jac_for_point_at_dot(dot, pt) for pt in chunked_pts]
|
||||
)
|
||||
|
||||
def jac(
|
||||
self, dots: Sequence[DotMeasurement]
|
||||
) -> Callable[[numpy.ndarray], numpy.ndarray]:
|
||||
"""
|
||||
Returns a function that returns the cost function's Jacobian for the given list of DotMeasurements for a particular model-dependent phase space point.
|
||||
Default implementation assumes a single dot jacobian from which to build the list.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
dots: A list of dot measurements to use to find the cost functions and their Jacobian.
|
||||
|
||||
Returns
|
||||
----------
|
||||
Returns the model's cost function's Jacobian.
|
||||
"""
|
||||
|
||||
def jac_to_return(pts: numpy.ndarray) -> numpy.ndarray:
|
||||
return numpy.array([self.jac_for_dot(dot, pts) for dot in dots])
|
||||
|
||||
return jac_to_return
|
||||
|
||||
def solve(
|
||||
def get_mcmc_chain(
|
||||
self,
|
||||
dots: Sequence[DotMeasurement],
|
||||
initial_pt: numpy.ndarray = None,
|
||||
bounds=(-numpy.inf, numpy.inf),
|
||||
) -> scipy.optimize.OptimizeResult:
|
||||
if initial_pt is None:
|
||||
initial = numpy.tile(0.1, self.n() * self.point_length())
|
||||
seed,
|
||||
cost_function,
|
||||
chain_length,
|
||||
threshold_cost: float,
|
||||
stdevs: pdme.subspace_simulation.MCMCStandardDeviation,
|
||||
initial_cost: Optional[float] = None,
|
||||
rng_arg: Optional[numpy.random.Generator] = None,
|
||||
) -> List[Tuple[float, numpy.ndarray]]:
|
||||
"""
|
||||
performs constrained markov chain monte carlo starting on seed parameter.
|
||||
The cost function given is used as a constrained to condition the chain;
|
||||
a new state is only accepted if cost_function(state) < cost_function(previous_state).
|
||||
The stdevs passed in are the stdevs we're expected to use.
|
||||
|
||||
Because we're using this for subspace simulation where our proposal function is not too important, we're in good shape.
|
||||
Note that for our adaptive stdevs to work, there's an unwritten contract that we sort each dipole in the state by frequency (increasing).
|
||||
|
||||
The seed is a list of dipoles, and each chain state is a list of dipoles as well.
|
||||
|
||||
initial_cost is a performance guy that lets you pre-populate the initial cost used to define the condition.
|
||||
Probably premature optimisation.
|
||||
|
||||
Returns a chain of [ (cost: float, state: dipole_ndarray ) ] format.
|
||||
"""
|
||||
_logger.debug(
|
||||
f"Starting Markov Chain Monte Carlo with seed: {seed} for chain length {chain_length} and provided stdevs {stdevs}"
|
||||
)
|
||||
chain: List[Tuple[float, numpy.ndarray]] = []
|
||||
if initial_cost is None:
|
||||
current_cost = cost_function(numpy.array([seed]))
|
||||
else:
|
||||
if len(initial_pt) != self.point_length():
|
||||
raise ValueError(
|
||||
f"The initial point {initial_pt} does not have the model's expected length: {self.point_length()}"
|
||||
current_cost = initial_cost
|
||||
current = seed
|
||||
for i in range(chain_length):
|
||||
dips = []
|
||||
for dipole_index, dipole in enumerate(current):
|
||||
_logger.debug(dipole_index)
|
||||
_logger.debug(dipole)
|
||||
stdev = stdevs[dipole_index]
|
||||
tentative_dip = self.markov_chain_monte_carlo_proposal(
|
||||
dipole, stdev, rng_arg
|
||||
)
|
||||
initial = numpy.tile(initial_pt, self.n())
|
||||
|
||||
result = scipy.optimize.least_squares(
|
||||
self.costs(dots),
|
||||
initial,
|
||||
jac=self.jac(dots),
|
||||
ftol=1e-15,
|
||||
gtol=3e-16,
|
||||
xtol=None,
|
||||
bounds=bounds,
|
||||
dips.append(tentative_dip)
|
||||
dips_array = pdme.subspace_simulation.sort_array_of_dipoles_by_frequency(
|
||||
dips
|
||||
)
|
||||
tentative_cost = cost_function(numpy.array([dips_array]))[0]
|
||||
if tentative_cost < threshold_cost:
|
||||
chain.append((numpy.squeeze(tentative_cost).item(), dips_array))
|
||||
current = dips_array
|
||||
current_cost = tentative_cost
|
||||
else:
|
||||
chain.append((numpy.squeeze(current_cost).item(), current))
|
||||
return chain
|
||||
|
||||
def get_repeat_counting_mcmc_chain(
|
||||
self,
|
||||
seed,
|
||||
cost_function,
|
||||
chain_length,
|
||||
threshold_cost: float,
|
||||
stdevs: pdme.subspace_simulation.MCMCStandardDeviation,
|
||||
initial_cost: Optional[float] = None,
|
||||
rng_arg: Optional[numpy.random.Generator] = None,
|
||||
) -> Tuple[int, List[Tuple[float, numpy.ndarray]]]:
|
||||
"""
|
||||
performs constrained markov chain monte carlo starting on seed parameter.
|
||||
The cost function given is used as a constrained to condition the chain;
|
||||
a new state is only accepted if cost_function(state) < cost_function(previous_state).
|
||||
The stdevs passed in are the stdevs we're expected to use.
|
||||
|
||||
Because we're using this for subspace simulation where our proposal function is not too important, we're in good shape.
|
||||
Note that for our adaptive stdevs to work, there's an unwritten contract that we sort each dipole in the state by frequency (increasing).
|
||||
|
||||
The seed is a list of dipoles, and each chain state is a list of dipoles as well.
|
||||
|
||||
initial_cost is a performance guy that lets you pre-populate the initial cost used to define the condition.
|
||||
Probably premature optimisation.
|
||||
|
||||
Chain has type of [ (cost: float, state: dipole_ndarray ) ] format,
|
||||
returning (repeat_count, chain) to keep track of number of repeats
|
||||
"""
|
||||
_logger.debug(
|
||||
f"Starting Markov Chain Monte Carlo with seed: {seed} for chain length {chain_length} and provided stdevs {stdevs}"
|
||||
)
|
||||
result.normalised_x = pdme.util.normalise_point_list(
|
||||
result.x, self.point_length()
|
||||
)
|
||||
return result
|
||||
chain: List[Tuple[float, numpy.ndarray]] = []
|
||||
if initial_cost is None:
|
||||
current_cost = cost_function(numpy.array([seed]))
|
||||
else:
|
||||
current_cost = initial_cost
|
||||
current = seed
|
||||
repeat_event_count = 0
|
||||
for _ in range(chain_length):
|
||||
dips = []
|
||||
for dipole_index, dipole in enumerate(current):
|
||||
_logger.debug(dipole_index)
|
||||
_logger.debug(dipole)
|
||||
stdev = stdevs[dipole_index]
|
||||
tentative_dip = self.markov_chain_monte_carlo_proposal(
|
||||
dipole, stdev, rng_arg
|
||||
)
|
||||
|
||||
|
||||
class Discretisation:
|
||||
def bounds(self, index: Tuple[float, ...]) -> Tuple:
|
||||
raise NotImplementedError
|
||||
|
||||
def all_indices(self) -> numpy.ndindex:
|
||||
raise NotImplementedError
|
||||
|
||||
def solve_for_index(
|
||||
self, dots: Sequence[DotMeasurement], index: Tuple
|
||||
) -> scipy.optimize.OptimizeResult:
|
||||
raise NotImplementedError
|
||||
|
||||
def get_model(self) -> Model:
|
||||
raise NotImplementedError
|
||||
dips.append(tentative_dip)
|
||||
dips_array = pdme.subspace_simulation.sort_array_of_dipoles_by_frequency(
|
||||
dips
|
||||
)
|
||||
tentative_cost = cost_function(numpy.array([dips_array]))[0]
|
||||
if tentative_cost < threshold_cost:
|
||||
chain.append((numpy.squeeze(tentative_cost).item(), dips_array))
|
||||
current = dips_array
|
||||
current_cost = tentative_cost
|
||||
else:
|
||||
# repeating a sample, increase count
|
||||
repeat_event_count += 1
|
||||
chain.append((numpy.squeeze(current_cost).item(), current))
|
||||
return (repeat_event_count, chain)
|
||||
|
104
pdme/model/multidipole_fixed_magnitude_model.py
Normal file
104
pdme/model/multidipole_fixed_magnitude_model.py
Normal file
@ -0,0 +1,104 @@
|
||||
import numpy
|
||||
import numpy.random
|
||||
from pdme.model.model import DipoleModel
|
||||
from pdme.measurement import (
|
||||
OscillatingDipole,
|
||||
OscillatingDipoleArrangement,
|
||||
)
|
||||
|
||||
|
||||
class MultipleDipoleFixedMagnitudeModel(DipoleModel):
|
||||
"""
|
||||
Model of multiple oscillating dipoles with a fixed magnitude, but free rotation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pfixed : float
|
||||
The fixed dipole magnitude.
|
||||
|
||||
n : int
|
||||
The number of dipoles.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
xmin: float,
|
||||
xmax: float,
|
||||
ymin: float,
|
||||
ymax: float,
|
||||
zmin: float,
|
||||
zmax: float,
|
||||
pfixed: float,
|
||||
n: int,
|
||||
) -> None:
|
||||
self.xmin = xmin
|
||||
self.xmax = xmax
|
||||
self.ymin = ymin
|
||||
self.ymax = ymax
|
||||
self.zmin = zmin
|
||||
self.zmax = zmax
|
||||
self.pfixed = pfixed
|
||||
self.rng = numpy.random.default_rng()
|
||||
self.n = n
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"MultipleDipoleFixedMagnitudeModel({self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.zmin}, {self.zmax}, {self.pfixed}, {self.n})"
|
||||
|
||||
def get_dipoles(
|
||||
self, max_frequency: float, rng_to_use: numpy.random.Generator = None
|
||||
) -> OscillatingDipoleArrangement:
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
rng = self.rng
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
dipoles = []
|
||||
|
||||
for i in range(self.n):
|
||||
theta = numpy.arccos(rng.uniform(-1, 1))
|
||||
phi = rng.uniform(0, 2 * numpy.pi)
|
||||
px = self.pfixed * numpy.sin(theta) * numpy.cos(phi)
|
||||
py = self.pfixed * numpy.sin(theta) * numpy.sin(phi)
|
||||
pz = self.pfixed * numpy.cos(theta)
|
||||
s_pts = numpy.array(
|
||||
(
|
||||
rng.uniform(self.xmin, self.xmax),
|
||||
rng.uniform(self.ymin, self.ymax),
|
||||
rng.uniform(self.zmin, self.zmax),
|
||||
)
|
||||
)
|
||||
frequency = rng.uniform(0, max_frequency)
|
||||
|
||||
dipoles.append(
|
||||
OscillatingDipole(numpy.array([px, py, pz]), s_pts, frequency)
|
||||
)
|
||||
return OscillatingDipoleArrangement(dipoles)
|
||||
|
||||
def get_monte_carlo_dipole_inputs(
|
||||
self,
|
||||
monte_carlo_n: int,
|
||||
max_frequency: float,
|
||||
rng_to_use: numpy.random.Generator = None,
|
||||
) -> numpy.ndarray:
|
||||
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
rng = self.rng
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
shape = (monte_carlo_n, self.n)
|
||||
theta = 2 * numpy.pi * rng.random(shape)
|
||||
phi = numpy.arccos(2 * rng.random(shape) - 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 = rng.uniform(self.xmin, self.xmax, shape)
|
||||
sy = rng.uniform(self.ymin, self.ymax, shape)
|
||||
sz = rng.uniform(self.zmin, self.zmax, shape)
|
||||
|
||||
w = rng.uniform(1, max_frequency, shape)
|
||||
|
||||
return numpy.stack([px, py, pz, sx, sy, sz, w], axis=-1)
|
119
pdme/model/random_count_multidipole_fixed_magnitude_model.py
Normal file
119
pdme/model/random_count_multidipole_fixed_magnitude_model.py
Normal file
@ -0,0 +1,119 @@
|
||||
import numpy
|
||||
import numpy.random
|
||||
from pdme.model.model import DipoleModel
|
||||
from pdme.measurement import (
|
||||
OscillatingDipole,
|
||||
OscillatingDipoleArrangement,
|
||||
)
|
||||
|
||||
|
||||
class RandomCountMultipleDipoleFixedMagnitudeModel(DipoleModel):
|
||||
"""
|
||||
Model of multiple oscillating dipoles with a fixed magnitude, but free rotation.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pfixed : float
|
||||
The fixed dipole magnitude.
|
||||
|
||||
n_max : int
|
||||
The maximum number of dipoles.
|
||||
|
||||
prob_occupancy : float
|
||||
The probability of dipole occupancy
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
xmin: float,
|
||||
xmax: float,
|
||||
ymin: float,
|
||||
ymax: float,
|
||||
zmin: float,
|
||||
zmax: float,
|
||||
pfixed: float,
|
||||
n_max: int,
|
||||
prob_occupancy: float,
|
||||
) -> None:
|
||||
self.xmin = xmin
|
||||
self.xmax = xmax
|
||||
self.ymin = ymin
|
||||
self.ymax = ymax
|
||||
self.zmin = zmin
|
||||
self.zmax = zmax
|
||||
self.pfixed = pfixed
|
||||
self.rng = numpy.random.default_rng()
|
||||
self.n_max = n_max
|
||||
if prob_occupancy >= 1 or prob_occupancy <= 0:
|
||||
raise ValueError(
|
||||
f"The probability of a dipole site occupancy must be between 0 and 1, got {prob_occupancy}"
|
||||
)
|
||||
self.prob_occupancy = prob_occupancy
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"RandomCountMultipleDipoleFixedMagnitudeModel({self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.zmin}, {self.zmax}, {self.pfixed}, {self.n_max}, {self.prob_occupancy})"
|
||||
|
||||
def get_dipoles(
|
||||
self, max_frequency: float, rng_to_use: numpy.random.Generator = None
|
||||
) -> OscillatingDipoleArrangement:
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
rng = self.rng
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
dipoles = []
|
||||
|
||||
n = rng.binomial(self.n_max, self.prob_occupancy)
|
||||
|
||||
for i in range(n):
|
||||
theta = numpy.arccos(rng.uniform(-1, 1))
|
||||
phi = rng.uniform(0, 2 * numpy.pi)
|
||||
px = self.pfixed * numpy.sin(theta) * numpy.cos(phi)
|
||||
py = self.pfixed * numpy.sin(theta) * numpy.sin(phi)
|
||||
pz = self.pfixed * numpy.cos(theta)
|
||||
s_pts = numpy.array(
|
||||
(
|
||||
rng.uniform(self.xmin, self.xmax),
|
||||
rng.uniform(self.ymin, self.ymax),
|
||||
rng.uniform(self.zmin, self.zmax),
|
||||
)
|
||||
)
|
||||
frequency = rng.uniform(0, max_frequency)
|
||||
|
||||
dipoles.append(
|
||||
OscillatingDipole(numpy.array([px, py, pz]), s_pts, frequency)
|
||||
)
|
||||
return OscillatingDipoleArrangement(dipoles)
|
||||
|
||||
def get_monte_carlo_dipole_inputs(
|
||||
self,
|
||||
monte_carlo_n: int,
|
||||
max_frequency: float,
|
||||
rng_to_use: numpy.random.Generator = None,
|
||||
) -> numpy.ndarray:
|
||||
|
||||
rng: numpy.random.Generator
|
||||
if rng_to_use is None:
|
||||
rng = self.rng
|
||||
else:
|
||||
rng = rng_to_use
|
||||
|
||||
shape = (monte_carlo_n, self.n_max)
|
||||
theta = 2 * numpy.pi * rng.random(shape)
|
||||
phi = numpy.arccos(2 * rng.random(shape) - 1)
|
||||
|
||||
p_mask = rng.binomial(1, self.prob_occupancy, shape)
|
||||
p_magnitude = self.pfixed * p_mask
|
||||
|
||||
px = p_magnitude * numpy.cos(theta) * numpy.sin(phi)
|
||||
py = p_magnitude * numpy.sin(theta) * numpy.sin(phi)
|
||||
pz = p_magnitude * numpy.cos(phi)
|
||||
|
||||
sx = rng.uniform(self.xmin, self.xmax, shape)
|
||||
sy = rng.uniform(self.ymin, self.ymax, shape)
|
||||
sz = rng.uniform(self.zmin, self.zmax, shape)
|
||||
|
||||
w = rng.uniform(1, max_frequency, shape)
|
||||
|
||||
return numpy.stack([px, py, pz, sx, sy, sz, w], axis=-1)
|
@ -1,216 +0,0 @@
|
||||
import numpy
|
||||
from dataclasses import dataclass
|
||||
from typing import Sequence, Tuple
|
||||
import scipy.optimize
|
||||
from pdme.model.model import Model, Discretisation
|
||||
from pdme.measurement import (
|
||||
DotMeasurement,
|
||||
OscillatingDipoleArrangement,
|
||||
OscillatingDipole,
|
||||
)
|
||||
|
||||
|
||||
class UnrestrictedModel(Model):
|
||||
"""
|
||||
Model of oscillating dipoles with no restrictions.
|
||||
Additionally, each dipole is assumed to be orientated in the plus or minus z direction.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
n : int
|
||||
The number of dipoles to assume.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
xmin: float,
|
||||
xmax: float,
|
||||
ymin: float,
|
||||
ymax: float,
|
||||
zmin: float,
|
||||
zmax: float,
|
||||
max_p: float,
|
||||
n: int,
|
||||
) -> None:
|
||||
self.xmin = xmin
|
||||
self.xmax = xmax
|
||||
self.ymin = ymin
|
||||
self.ymax = ymax
|
||||
self.zmin = zmin
|
||||
self.zmax = zmax
|
||||
self.max_p = max_p
|
||||
self._n = n
|
||||
self.rng = numpy.random.default_rng()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"UnrestrictedModel({self.xmin}, {self.xmax}, {self.ymin}, {self.ymax}, {self.zmin}, {self.zmax}, {self.max_p}, {self.n()})"
|
||||
|
||||
def point_length(self) -> int:
|
||||
"""
|
||||
Dipole is unconstrained in this model.
|
||||
All seven degrees of freedom: (px, py, pz, sx, sy, sz, w).
|
||||
"""
|
||||
return 7
|
||||
|
||||
def n(self) -> int:
|
||||
return self._n
|
||||
|
||||
def v_for_point_at_dot(self, dot: DotMeasurement, pt: numpy.ndarray) -> float:
|
||||
p = pt[0:3]
|
||||
s = pt[3:6]
|
||||
w = pt[6]
|
||||
|
||||
diff = dot.r - s
|
||||
alpha = p.dot(diff) / (numpy.linalg.norm(diff) ** 3)
|
||||
b = (1 / numpy.pi) * (w / (w**2 + dot.f**2))
|
||||
return alpha**2 * b
|
||||
|
||||
def jac_for_point_at_dot(
|
||||
self, dot: DotMeasurement, pt: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
p = pt[0:3]
|
||||
s = pt[3:6]
|
||||
w = pt[6]
|
||||
|
||||
diff = dot.r - s
|
||||
alpha = p.dot(diff) / (numpy.linalg.norm(diff) ** 3)
|
||||
b = (1 / numpy.pi) * (w / (w**2 + dot.f**2))
|
||||
|
||||
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 = dot.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 get_dipoles(self, frequency: float) -> OscillatingDipoleArrangement:
|
||||
theta = numpy.arccos(self.rng.uniform(-1, 1))
|
||||
phi = self.rng.uniform(0, 2 * numpy.pi)
|
||||
p = self.rng.uniform(0, self.max_p)
|
||||
px = p * numpy.sin(theta) * numpy.cos(phi)
|
||||
py = p * numpy.sin(theta) * numpy.sin(phi)
|
||||
pz = p * numpy.cos(theta)
|
||||
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)]
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class UnrestrictedDiscretisation(Discretisation):
|
||||
"""
|
||||
Representation of a discretisation of a UnrestrictedModel.
|
||||
Also captures a rough maximum value of dipole.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
model : UnrestrictedModel
|
||||
The parent model of the discretisation.
|
||||
|
||||
num_px: int
|
||||
The number of partitions of the px.
|
||||
|
||||
num_py: int
|
||||
The number of partitions of the py.
|
||||
|
||||
num_pz: int
|
||||
The number of partitions of pz.
|
||||
|
||||
num_x : int
|
||||
The number of partitions of the x axis.
|
||||
|
||||
num_y : int
|
||||
The number of partitions of the y axis.
|
||||
|
||||
num_z : int
|
||||
The number of partitions of the z axis.
|
||||
|
||||
max_p : int
|
||||
The maximum p coordinate in any direction.
|
||||
"""
|
||||
|
||||
model: UnrestrictedModel
|
||||
num_px: int
|
||||
num_py: int
|
||||
num_pz: int
|
||||
num_x: int
|
||||
num_y: int
|
||||
num_z: int
|
||||
|
||||
def __post_init__(self):
|
||||
self.max_p = self.model.max_p
|
||||
self.cell_count = self.num_x * self.num_y * self.num_z
|
||||
self.x_step = (self.model.xmax - self.model.xmin) / self.num_x
|
||||
self.y_step = (self.model.ymax - self.model.ymin) / self.num_y
|
||||
self.z_step = (self.model.zmax - self.model.zmin) / self.num_z
|
||||
self.px_step = 2 * self.max_p / self.num_px
|
||||
self.py_step = 2 * self.max_p / self.num_py
|
||||
self.pz_step = 2 * self.max_p / self.num_pz
|
||||
|
||||
def bounds(self, index: Tuple[float, ...]) -> Tuple:
|
||||
pxi, pyi, pzi, xi, yi, zi = index
|
||||
|
||||
# For this model, a point is (px, py, pz, sx, sx, sy, w).
|
||||
# We want to keep w unbounded, restrict sx, sy, sz, px and py based on step.
|
||||
return (
|
||||
[
|
||||
pxi * self.px_step - self.max_p,
|
||||
pyi * self.py_step - self.max_p,
|
||||
pzi * self.pz_step - self.max_p,
|
||||
xi * self.x_step + self.model.xmin,
|
||||
yi * self.y_step + self.model.ymin,
|
||||
zi * self.z_step + self.model.zmin,
|
||||
-numpy.inf,
|
||||
],
|
||||
[
|
||||
(pxi + 1) * self.px_step - self.max_p,
|
||||
(pyi + 1) * self.py_step - self.max_p,
|
||||
(pzi + 1) * self.pz_step - self.max_p,
|
||||
(xi + 1) * self.x_step + self.model.xmin,
|
||||
(yi + 1) * self.y_step + self.model.ymin,
|
||||
(zi + 1) * self.z_step + self.model.zmin,
|
||||
numpy.inf,
|
||||
],
|
||||
)
|
||||
|
||||
def all_indices(self) -> numpy.ndindex:
|
||||
# see https://github.com/numpy/numpy/issues/20706 for why this is a mypy problem.
|
||||
return numpy.ndindex(
|
||||
(self.num_px, self.num_py, self.num_pz, self.num_x, self.num_y, self.num_z)
|
||||
) # type:ignore
|
||||
|
||||
def solve_for_index(
|
||||
self, dots: Sequence[DotMeasurement], index: Tuple[float, ...]
|
||||
) -> scipy.optimize.OptimizeResult:
|
||||
bounds = self.bounds(index)
|
||||
px_mean = (bounds[0][0] + bounds[1][0]) / 2
|
||||
py_mean = (bounds[0][1] + bounds[1][1]) / 2
|
||||
pz_mean = (bounds[0][2] + bounds[1][2]) / 2
|
||||
sx_mean = (bounds[0][3] + bounds[1][3]) / 2
|
||||
sy_mean = (bounds[0][4] + bounds[1][4]) / 2
|
||||
sz_mean = (bounds[0][5] + bounds[1][5]) / 2
|
||||
return self.model.solve(
|
||||
dots,
|
||||
initial_pt=numpy.array(
|
||||
[px_mean, py_mean, pz_mean, sx_mean, sy_mean, sz_mean, 0.1]
|
||||
),
|
||||
bounds=bounds,
|
||||
)
|
74
pdme/subspace_simulation/__init__.py
Normal file
74
pdme/subspace_simulation/__init__.py
Normal file
@ -0,0 +1,74 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Sequence
|
||||
import numpy
|
||||
from pdme.subspace_simulation.mcmc_costs import (
|
||||
proportional_cost,
|
||||
proportional_costs_vs_actual_measurement,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class DipoleStandardDeviation:
|
||||
"""
|
||||
contains the dipole standard deviation to be used in porposals for markov chain monte carlo
|
||||
"""
|
||||
|
||||
p_phi_step: float
|
||||
p_theta_step: float
|
||||
rx_step: float
|
||||
ry_step: float
|
||||
rz_step: float
|
||||
w_log_step: float
|
||||
|
||||
|
||||
class MCMCStandardDeviation:
|
||||
"""
|
||||
wrapper for multiple standard deviations, allows for flexible length stuff
|
||||
"""
|
||||
|
||||
def __init__(self, stdevs: Sequence[DipoleStandardDeviation]):
|
||||
self.stdevs = stdevs
|
||||
if len(stdevs) < 1:
|
||||
raise ValueError(f"Got stdevs: {stdevs}, must have length > 1")
|
||||
|
||||
def __getitem__(self, key):
|
||||
newkey = key % len(self.stdevs)
|
||||
return self.stdevs[newkey]
|
||||
|
||||
|
||||
def sort_array_of_dipoles_by_frequency(configuration) -> numpy.ndarray:
|
||||
"""
|
||||
Say we have a situation of 2 dipoles, and we've created 8 samples. Then we'll have an (8, 2, 7) numpy array.
|
||||
For each of the 8 samples, we want the 2 dipoles to be in order of frequency.
|
||||
|
||||
This just sorts each sample, the 2x7 array.
|
||||
|
||||
Utility function.
|
||||
"""
|
||||
return numpy.array(sorted(configuration, key=lambda l: l[6]))
|
||||
|
||||
|
||||
def sort_array_of_dipoleses_by_frequency(configurations) -> numpy.ndarray:
|
||||
"""
|
||||
Say we have a situation of 2 dipoles, and we've created 8 samples. Then we'll have an (8, 2, 7) numpy array.
|
||||
For each of the 8 samples, we want the 2 dipoles to be in order of frequency.
|
||||
|
||||
This is the wrapper that sorts everything.
|
||||
|
||||
Utility function.
|
||||
"""
|
||||
return numpy.array(
|
||||
[
|
||||
sort_array_of_dipoles_by_frequency(configuration)
|
||||
for configuration in configurations
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
__all__ = [
|
||||
"DipoleStandardDeviation",
|
||||
"MCMCStandardDeviation",
|
||||
"sort_array_of_dipoles_by_frequency",
|
||||
"proportional_cost",
|
||||
"proportional_costs_vs_actual_measurement",
|
||||
]
|
30
pdme/subspace_simulation/mcmc_costs.py
Normal file
30
pdme/subspace_simulation/mcmc_costs.py
Normal file
@ -0,0 +1,30 @@
|
||||
import numpy
|
||||
import numpy.typing
|
||||
import pdme.util.fast_v_calc
|
||||
|
||||
|
||||
def proportional_cost(a: numpy.ndarray, b: numpy.ndarray) -> numpy.ndarray:
|
||||
tops = numpy.max(b / a, axis=-1)
|
||||
bottoms = numpy.max(a / b, axis=-1)
|
||||
return numpy.maximum(tops, bottoms)
|
||||
|
||||
|
||||
def proportional_costs_vs_actual_measurement(
|
||||
dot_inputs_array: numpy.ndarray,
|
||||
actual_measurement_array: numpy.ndarray,
|
||||
dipoles_to_test: numpy.ndarray,
|
||||
) -> numpy.ndarray:
|
||||
vals = pdme.util.fast_v_calc.fast_vs_for_dipoleses(
|
||||
dot_inputs_array, dipoles_to_test
|
||||
)
|
||||
return proportional_cost(actual_measurement_array, vals)
|
||||
|
||||
|
||||
def relative_square_diffs(
|
||||
approx: numpy.ndarray, target: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
# Assume that both approx and target are arrays of length m
|
||||
# Approx can broadcast if additional indexes to the left
|
||||
# diffs.shape = [ m ]
|
||||
diffs = (approx - target) ** 2 / (target**2)
|
||||
return diffs.sum(axis=-1)
|
@ -1,3 +0,0 @@
|
||||
from pdme.util.normal_form import normalise_point_list
|
||||
|
||||
__all__ = ["normalise_point_list"]
|
@ -45,8 +45,229 @@ def fast_s_nonlocal(
|
||||
_logger.debug(f"alphses1: {alphses1}")
|
||||
_logger.debug(f"alphses2: {alphses2}")
|
||||
|
||||
bses = (1 / numpy.pi) * (ws[:, None] / (f1s**2 + ws[:, None] ** 2))
|
||||
bses = 2 * ws[:, None] / ((numpy.pi * f1s) ** 2 + ws[:, None] ** 2)
|
||||
if _logger.isEnabledFor(logging.DEBUG):
|
||||
_logger.debug(f"bses: {bses}")
|
||||
|
||||
return alphses1 * alphses2 * bses
|
||||
|
||||
|
||||
def fast_s_nonlocal_dipoleses(
|
||||
dot_pair_inputs: numpy.ndarray, dipoleses: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
No error correction here baby.
|
||||
"""
|
||||
|
||||
# We're going to annotate the indices on this class.
|
||||
# Let's define some indices:
|
||||
# A -> index of dipoleses configurations
|
||||
# measurement_index -> if we have 100 frequencies for example, indexes which one of them it is
|
||||
# j -> within a particular configuration, indexes dipole j
|
||||
# If we need to use numbers, let's use A -> 2, j -> 10, measurement_index -> 9 for consistency with
|
||||
# my other notes
|
||||
# cart -> {x, y, z} is a cartesian axis
|
||||
|
||||
# ps, ss have shape [A, j, cart]
|
||||
ps = dipoleses[:, :, 0:3]
|
||||
ss = dipoleses[:, :, 3:6]
|
||||
# ws shape [A, j]
|
||||
ws = dipoleses[:, :, 6]
|
||||
|
||||
_logger.debug(f"ps: {ps}")
|
||||
_logger.debug(f"ss: {ss}")
|
||||
_logger.debug(f"ws: {ws}")
|
||||
|
||||
# rs have shape [meas_idx, {}, cart], where the inner index goes away leaving
|
||||
# [meas, cart]
|
||||
r1s = dot_pair_inputs[:, 0, 0:3]
|
||||
r2s = dot_pair_inputs[:, 1, 0:3]
|
||||
# fs have index [meas_idx], this makes sense
|
||||
f1s = dot_pair_inputs[:, 0, 3]
|
||||
f2s = dot_pair_inputs[:, 1, 3]
|
||||
|
||||
if (f1s != f2s).all():
|
||||
raise ValueError(f"Dot pair frequencies are inconsistent: {dot_pair_inputs}")
|
||||
|
||||
# r1s have shape [meas, cart], adding the none makes it
|
||||
# r1s[:, None].shape = [meas, 1, cart]
|
||||
# ss[:, None, :].shape = [A, 1, j, cart]
|
||||
# subtracting broadcasts by matching from the right to the left, giving a final shape of
|
||||
# diffses.shape [A, meas, j, cart]
|
||||
diffses1 = r1s[:, None] - ss[:, None, :]
|
||||
diffses2 = r2s[:, None] - ss[:, None, :]
|
||||
if _logger.isEnabledFor(logging.DEBUG):
|
||||
_logger.debug(f"diffses1: {diffses1}")
|
||||
_logger.debug(f"diffses2: {diffses2}")
|
||||
|
||||
# norming on the cartesian axis, which is axis 3 as seen above
|
||||
# norms.shape [A, meas, j]
|
||||
norms1 = numpy.linalg.norm(diffses1, axis=3) ** 3
|
||||
norms2 = numpy.linalg.norm(diffses2, axis=3) ** 3
|
||||
if _logger.isEnabledFor(logging.DEBUG):
|
||||
_logger.debug(f"norms1: {norms1}")
|
||||
_logger.debug(f"norms2: {norms2}")
|
||||
|
||||
# diffses shape [A, meas, j, cart]
|
||||
# ps shape [A, j, cart]
|
||||
# so we're summing over the d axis, the cartesian one.
|
||||
# final shape of numerator is [A, meas, j]
|
||||
# denom shape is [A, meas, j]
|
||||
# final shape stayes [A, meas, j]
|
||||
alphses1 = numpy.einsum("abcd,acd->abc", diffses1, ps) / norms1
|
||||
alphses2 = numpy.einsum("abcd,acd->abc", diffses2, ps) / norms2
|
||||
if _logger.isEnabledFor(logging.DEBUG):
|
||||
_logger.debug(f"alphses1: {alphses1}")
|
||||
_logger.debug(f"alphses2: {alphses2}")
|
||||
|
||||
# ws shape [A, j], so numerator has shape [A, 1, j]
|
||||
# f1s shape is [meas], so first term of denom is [meas, 1]
|
||||
# ws[:, None, :].shape [A, 1, j] so breadcasting the sum in denom gives
|
||||
# denom.shape [A meas, j]
|
||||
# so now overall shape is [A, meas, j]
|
||||
bses = 2 * ws[:, None, :] / ((numpy.pi * f1s[:, None]) ** 2 + ws[:, None, :] ** 2)
|
||||
if _logger.isEnabledFor(logging.DEBUG):
|
||||
_logger.debug(f"bses: {bses}")
|
||||
|
||||
# so our output shape is [A, meas, j]
|
||||
_logger.debug(f"Raw pair calc: [{alphses1 * alphses2 * bses}]")
|
||||
return numpy.einsum("...j->...", alphses1 * alphses2 * bses)
|
||||
|
||||
|
||||
def fast_s_spin_qubit_tarucha_nonlocal_dipoleses(
|
||||
dot_pair_inputs: numpy.ndarray, dipoleses: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
No error correction here baby.
|
||||
"""
|
||||
|
||||
# We're going to annotate the indices on this class.
|
||||
# Let's define some indices:
|
||||
# A -> index of dipoleses configurations
|
||||
# j -> within a particular configuration, indexes dipole j
|
||||
# measurement_index -> if we have 100 frequencies for example, indexes which one of them it is
|
||||
# If we need to use numbers, let's use A -> 2, j -> 10, measurement_index -> 9 for consistency with
|
||||
# my other notes
|
||||
|
||||
# axes are [dipole_config_idx A, dipole_idx j, {px, py, pz}3]
|
||||
ps = dipoleses[:, :, 0:3]
|
||||
# axes are [dipole_config_idx A, dipole_idx j, {sx, sy, sz}3]
|
||||
ss = dipoleses[:, :, 3:6]
|
||||
# axes are [dipole_config_idx A, dipole_idx j, w], last axis is just 1
|
||||
ws = dipoleses[:, :, 6]
|
||||
|
||||
_logger.debug(f"ps: {ps}")
|
||||
_logger.debug(f"ss: {ss}")
|
||||
_logger.debug(f"ws: {ws}")
|
||||
|
||||
# dot_index is either 0 or 1 for dot1 or dot2
|
||||
# hopefully this adhoc grammar is making sense, with the explicit labelling of the values of the last axis in cartesian space
|
||||
# axes are [measurement_idx, {dot_index}, {rx, ry, rz}] where the inner {dot_index} is gone
|
||||
# [measurement_idx, cartesian3]
|
||||
r1s = dot_pair_inputs[:, 0, 0:3]
|
||||
r2s = dot_pair_inputs[:, 1, 0:3]
|
||||
# axes are [measurement_idx]
|
||||
f1s = dot_pair_inputs[:, 0, 3]
|
||||
f2s = dot_pair_inputs[:, 1, 3]
|
||||
|
||||
if (f1s != f2s).all():
|
||||
raise ValueError(f"Dot pair frequencies are inconsistent: {dot_pair_inputs}")
|
||||
|
||||
# first operation!
|
||||
# r1s has shape [measurement_idx, rxs]
|
||||
# None inserts an extra axis so the r1s[:, None] has shape
|
||||
# [measurement_idx, 1]([rxs]) with the last rxs hidden
|
||||
#
|
||||
# ss has shape [ A, j, {sx, sy, sz}3], so second term has shape [A, 1, j]([sxs])
|
||||
# these broadcast from right to left
|
||||
# [ measurement_idx, 1, rxs]
|
||||
# [A, 1, j, sxs]
|
||||
# resulting in [A, measurement_idx, j, cart3] sxs rxs are both cart3
|
||||
diffses1 = r1s[:, None] - ss[:, None, :]
|
||||
diffses2 = r2s[:, None] - ss[:, None, :]
|
||||
if _logger.isEnabledFor(logging.DEBUG):
|
||||
_logger.debug(f"diffses1: {diffses1}")
|
||||
_logger.debug(f"diffses2: {diffses2}")
|
||||
|
||||
# norms takes out axis 3, the last one, giving [A, measurement_idx, j]
|
||||
norms1 = numpy.linalg.norm(diffses1, axis=3)
|
||||
norms2 = numpy.linalg.norm(diffses2, axis=3)
|
||||
if _logger.isEnabledFor(logging.DEBUG):
|
||||
_logger.debug(f"norms1: {norms1}")
|
||||
_logger.debug(f"norms2: {norms2}")
|
||||
|
||||
# _logger.info(f"norms1: {norms1}")
|
||||
# _logger.info(f"norms1 shape: {norms1.shape}")
|
||||
#
|
||||
# diffses1 (A, measurement_idx, j, xs)
|
||||
# ps: (A, j, px)
|
||||
# result is (A, measurement_idx, j)
|
||||
# intermediate_dot_prod = numpy.einsum("abcd,acd->abc", diffses1, ps)
|
||||
# _logger.info(f"dot product shape: {intermediate_dot_prod.shape}")
|
||||
|
||||
# transpose makes it (j, measurement_idx, A)
|
||||
# transp_intermediate_dot_prod = numpy.transpose(numpy.einsum("abcd,acd->abc", diffses1, ps) / (norms1**3))
|
||||
|
||||
# transpose of diffses has shape (xs, j, measurement_idx, A)
|
||||
# numpy.transpose(diffses1)
|
||||
# _logger.info(f"dot product shape: {transp_intermediate_dot_prod.shape}")
|
||||
|
||||
# inner transpose is (j, measurement_idx, A) * (xs, j, measurement_idx, A)
|
||||
# next transpose puts it back to (A, measurement_idx, j, xs)
|
||||
# p_dot_r_times_r_term = 3 * numpy.transpose(numpy.transpose(numpy.einsum("abcd,acd->abc", diffses1, ps) / (norms1**3)) * numpy.transpose(diffses1))
|
||||
# _logger.info(f"p_dot_r_times_r_term: {p_dot_r_times_r_term.shape}")
|
||||
|
||||
# only x axis puts us at (A, measurement_idx, j)
|
||||
# p_dot_r_times_r_term_x_only = p_dot_r_times_r_term[:, :, :, 0]
|
||||
# _logger.info(f"p_dot_r_times_r_term_x_only.shape: {p_dot_r_times_r_term_x_only.shape}")
|
||||
|
||||
# now to complete the numerator we subtract the ps, which are (A, j, px):
|
||||
# slicing off the end gives us (A, j), so we newaxis to get (A, 1, j)
|
||||
# _logger.info(ps[:, numpy.newaxis, :, 0].shape)
|
||||
alphses1 = (
|
||||
(
|
||||
3
|
||||
* numpy.transpose(
|
||||
numpy.transpose(
|
||||
numpy.einsum("abcd,acd->abc", diffses1, ps) / (norms1**2)
|
||||
)
|
||||
* numpy.transpose(diffses1)
|
||||
)[:, :, :, 0]
|
||||
)
|
||||
- ps[:, numpy.newaxis, :, 0]
|
||||
) / (norms1**3)
|
||||
alphses2 = (
|
||||
(
|
||||
3
|
||||
* numpy.transpose(
|
||||
numpy.transpose(
|
||||
numpy.einsum("abcd,acd->abc", diffses2, ps) / (norms2**2)
|
||||
)
|
||||
* numpy.transpose(diffses2)
|
||||
)[:, :, :, 0]
|
||||
)
|
||||
- ps[:, numpy.newaxis, :, 0]
|
||||
) / (norms2**3)
|
||||
if _logger.isEnabledFor(logging.DEBUG):
|
||||
_logger.debug(f"alphses1: {alphses1}")
|
||||
_logger.debug(f"alphses2: {alphses2}")
|
||||
|
||||
# ws has shape (A, j), so it becomes (A, 1, j) in numerator with the new axis
|
||||
# f1s has shape (m), so we get in the denominator (m, 1) + (A, 1, j)
|
||||
# This becomes (A, m, j)
|
||||
bses = 2 * ws[:, None, :] / ((numpy.pi * f1s[:, None]) ** 2 + ws[:, None, :] ** 2)
|
||||
if _logger.isEnabledFor(logging.DEBUG):
|
||||
_logger.debug(f"bses: {bses}")
|
||||
|
||||
# alphas have (A, 1, j), betas have (A, m, j)
|
||||
# Final result is (A, m, j)
|
||||
_logger.debug(f"Raw pair calc: [{alphses1 * alphses2 * bses}]")
|
||||
return numpy.einsum("...j->...", alphses1 * alphses2 * bses)
|
||||
|
||||
|
||||
def signarg(x, **kwargs):
|
||||
"""
|
||||
uses numpy.sign to implement Arg for real numbers only. Should return pi for negative inputs, 0 for positive.
|
||||
Passes through args to numpy.sign
|
||||
"""
|
||||
return numpy.pi * (numpy.sign(x, **kwargs) - 1) / (-2)
|
||||
|
@ -10,31 +10,241 @@ def fast_vs_for_dipoles(
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
No error correction here baby.
|
||||
Expects dot_inputs to be numpy array of [rx, ry, rz, f] entries, so a n by 4 where n is number of measurement points.
|
||||
"""
|
||||
# name indexes:
|
||||
# A: dipole config index
|
||||
# cart: cartesian index
|
||||
# m: measurement index
|
||||
|
||||
# [A, cart]
|
||||
ps = dipoles[:, 0:3]
|
||||
ss = dipoles[:, 3:6]
|
||||
# [A]
|
||||
ws = dipoles[:, 6]
|
||||
|
||||
_logger.debug(f"ps: {ps}")
|
||||
_logger.debug(f"ss: {ss}")
|
||||
_logger.debug(f"ws: {ws}")
|
||||
|
||||
# [m, cart]
|
||||
rs = dot_inputs[:, 0:3]
|
||||
# [m]
|
||||
fs = dot_inputs[:, 3]
|
||||
|
||||
# [m, cart] - [A, 1, cart]
|
||||
# [A, m, cart]
|
||||
diffses = rs - ss[:, None]
|
||||
|
||||
_logger.debug(f"diffses: {diffses}")
|
||||
# [A, m]
|
||||
norms = numpy.linalg.norm(diffses, axis=2) ** 3
|
||||
_logger.debug(f"norms: {norms}")
|
||||
# [A, m, cart] [A, cart] -> [A, m]
|
||||
ases = (numpy.einsum("...ji, ...i", diffses, ps) / norms) ** 2
|
||||
_logger.debug(f"ases: {ases}")
|
||||
|
||||
# [A, 1], denom [m] + [A, 1] -> [A, m]
|
||||
# [A, m]
|
||||
bses = 2 * ws[:, None] / ((numpy.pi * fs) ** 2 + ws[:, None] ** 2)
|
||||
|
||||
_logger.debug(f"bses: {bses}")
|
||||
# returns shape [A, m]
|
||||
return ases * bses
|
||||
|
||||
|
||||
def fast_vs_for_dipoleses(
|
||||
dot_inputs: numpy.ndarray, dipoleses: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
No error correction here baby.
|
||||
Expects dot_inputs to be numpy array of [rx, ry, rz, f] entries, so a n by 4 where n is number of measurement points.
|
||||
|
||||
Dipoleses are expected to be array of arrays of arrays: list of sets of dipoles which are part of a single arrangement to be added together.
|
||||
"""
|
||||
ps = dipoleses[:, :, 0:3]
|
||||
ss = dipoleses[:, :, 3:6]
|
||||
ws = dipoleses[:, :, 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]
|
||||
diffses = rs[:, None] - ss[:, None, :]
|
||||
|
||||
_logger.debug(f"diffses: {diffses}")
|
||||
norms = numpy.linalg.norm(diffses, axis=2) ** 3
|
||||
norms = numpy.linalg.norm(diffses, axis=3) ** 3
|
||||
_logger.debug(f"norms: {norms}")
|
||||
ases = (numpy.einsum("...ji, ...i", diffses, ps) / norms) ** 2
|
||||
ases = (numpy.einsum("abcd,acd->abc", diffses, ps) / norms) ** 2
|
||||
_logger.debug(f"ases: {ases}")
|
||||
|
||||
bses = (1 / numpy.pi) * (ws[:, None] / (fs**2 + ws[:, None] ** 2))
|
||||
bses = 2 * ws[:, None, :] / ((numpy.pi * fs[:, None]) ** 2 + ws[:, None, :] ** 2)
|
||||
_logger.debug(f"bses: {bses}")
|
||||
return numpy.einsum("...j->...", ases * bses)
|
||||
|
||||
|
||||
def fast_efieldxs_for_dipoles(
|
||||
dot_inputs: numpy.ndarray, dipoles: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
No error correction here baby.
|
||||
Expects dot_inputs to be numpy array of [rx, ry, rz, f] entries, so a n by 4 where n is number of measurement points.
|
||||
"""
|
||||
# name indexes:
|
||||
# A: dipole config index
|
||||
# j: dipole index within a config
|
||||
# cart: cartesian index
|
||||
# m: measurement index
|
||||
|
||||
# Indexes [A, cart]
|
||||
ps = dipoles[:, 0:3]
|
||||
ss = dipoles[:, 3:6]
|
||||
# Indexes [A]
|
||||
ws = dipoles[:, 6]
|
||||
|
||||
# Indexes [m, cart]
|
||||
rs = dot_inputs[:, 0:3]
|
||||
# Indexes [m]
|
||||
fs = dot_inputs[:, 3]
|
||||
|
||||
# Indexes [m, cart] - [A, 1, cart]
|
||||
# Broadcasting from right
|
||||
# diffses.indexes [A, m, cart]
|
||||
diffses = rs - ss[:, None, :]
|
||||
|
||||
# [A, m, cart][2] = cart
|
||||
# norms takes out axis 2, the last one, giving [A, m]
|
||||
norms = numpy.linalg.norm(diffses, axis=2)
|
||||
|
||||
# long story but this ends up becoming (A, 1, j)
|
||||
# Some evidence is looking at ps term, which has shape (A, 1, j, cart=0) becoming (A, 1, j)
|
||||
|
||||
# [A, m, cart] einsum [A, cart] explicitly gives [A, m]
|
||||
dot_products = numpy.einsum("amc,ac->am", diffses, ps) / (norms**2)
|
||||
|
||||
# [m, A] * [cart, m, A] -> [cart, m, A], transpose that and you get [A, m, cart]
|
||||
projections = numpy.transpose(
|
||||
numpy.transpose(dot_products) * numpy.transpose(diffses)
|
||||
)
|
||||
|
||||
# numerator [A, m, cart] - [A, 1, cart] -> [A, m, cart][:, :, 0] -> [A, m]
|
||||
alphas = (3 * projections - ps[:, numpy.newaxis])[:, :, 0] / norms**3
|
||||
|
||||
# [A, m]
|
||||
ases = alphas**2
|
||||
|
||||
# [A, 1], denom [m] + [A, 1] -> [A, m]
|
||||
# [A, m]
|
||||
bses = 2 * ws[:, None] / ((numpy.pi * fs) ** 2 + ws[:, None] ** 2)
|
||||
|
||||
# return shape [A, m, j]
|
||||
return ases * bses
|
||||
|
||||
|
||||
def fast_efieldxs_for_dipoleses(
|
||||
dot_inputs: numpy.ndarray, dipoleses: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
No error correction here baby.
|
||||
Expects dot_inputs to be numpy array of [rx, ry, rz, f] entries, so a n by 4 where n is number of measurement points.
|
||||
|
||||
Dipoleses are expected to be array of arrays of arrays:
|
||||
list of sets of dipoles which are part of a single arrangement to be added together.
|
||||
"""
|
||||
# name indexes:
|
||||
# A: dipole config index
|
||||
# j: dipole index within a config
|
||||
# cart: cartesian index
|
||||
# m: measurement index
|
||||
|
||||
# Indexes [A, j, cart]
|
||||
ps = dipoleses[:, :, 0:3]
|
||||
ss = dipoleses[:, :, 3:6]
|
||||
# Indexes [A, j]
|
||||
ws = dipoleses[:, :, 6]
|
||||
|
||||
# Indexes [m, cart]
|
||||
rs = dot_inputs[:, 0:3]
|
||||
# Indexes [m]
|
||||
fs = dot_inputs[:, 3]
|
||||
|
||||
# Indexes [m, 1, cart] - [A, 1, j, cart]
|
||||
# Broadcasting from right
|
||||
# diffses.indexes [A, m, j, cart]
|
||||
diffses = rs[:, None] - ss[:, None, :]
|
||||
|
||||
# norms takes out axis 3, the last one, giving [A, m, j]
|
||||
norms = numpy.linalg.norm(diffses, axis=3)
|
||||
|
||||
# long story but this ends up becoming (A, 1, j)
|
||||
# Some evidence is looking at ps term, which has shape (A, 1, j, cart=0) becoming (A, 1, j)
|
||||
alphas = (
|
||||
(
|
||||
3
|
||||
* numpy.transpose(
|
||||
numpy.transpose(
|
||||
numpy.einsum("abcd,acd->abc", diffses, ps) / (norms**2)
|
||||
)
|
||||
* numpy.transpose(diffses)
|
||||
)[:, :, :, 0]
|
||||
)
|
||||
- ps[:, numpy.newaxis, :, 0]
|
||||
) / (norms**3)
|
||||
ases = alphas**2
|
||||
# bses.shape [A, m, j)]
|
||||
bses = 2 * ws[:, None, :] / ((numpy.pi * fs[:, None]) ** 2 + ws[:, None, :] ** 2)
|
||||
|
||||
# return shape [A, m, j]
|
||||
return numpy.einsum("...j->...", ases * bses)
|
||||
|
||||
|
||||
def fast_vs_for_asymmetric_dipoleses(
|
||||
dot_inputs: numpy.ndarray, dipoleses: numpy.ndarray, temp: numpy.ndarray
|
||||
) -> numpy.ndarray:
|
||||
"""
|
||||
No error correction here baby.
|
||||
Expects dot_inputs to be numpy array of [rx, ry, rz, f] entries, so a n by 4 where n is number of measurement points.
|
||||
|
||||
Dipoleses are expected to be array of arrays of arrays:
|
||||
list of sets of dipoles which are part of a single arrangement to be added together.
|
||||
Within each dipole, the expected format is [px, py, pz, sx, sy, sz, e1, e2, w]
|
||||
The passed in w is expected to be half the actual. This is bad, but here for historical reasons to be changed later.
|
||||
"""
|
||||
raw_ps = dipoleses[:, :, 0:3]
|
||||
ss = dipoleses[:, :, 3:6]
|
||||
e1s = dipoleses[:, :, 6]
|
||||
e2s = dipoleses[:, :, 7]
|
||||
raw_ws = dipoleses[:, :, 8]
|
||||
|
||||
rs = dot_inputs[:, 0:3]
|
||||
fs = dot_inputs[:, 3]
|
||||
|
||||
diffses = rs[:, None] - ss[:, None, :]
|
||||
|
||||
_logger.warning(
|
||||
"This method is very likely to be broken, and should not be used without more thought"
|
||||
)
|
||||
w1s = numpy.exp(-e1s / temp) * raw_ws
|
||||
w2s = numpy.exp(-e2s / temp) * raw_ws
|
||||
|
||||
mag_prefactor = 4 * ((w1s * w2s) / ((w1s + w2s) ** 2))
|
||||
ws = w1s + w2s
|
||||
|
||||
# some annoying broadcast thing here?
|
||||
ps = (raw_ps.T * mag_prefactor.T).T
|
||||
|
||||
norms = numpy.linalg.norm(diffses, axis=3) ** 3
|
||||
|
||||
ases = (numpy.einsum("abcd,acd->abc", diffses, ps) / norms) ** 2
|
||||
|
||||
bses = ws[:, None, :] / ((numpy.pi * fs[:, None]) ** 2 + ws[:, None, :] ** 2)
|
||||
|
||||
return numpy.einsum("...j->...", 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.
|
||||
|
@ -1,45 +0,0 @@
|
||||
import numpy
|
||||
import operator
|
||||
import logging
|
||||
|
||||
|
||||
# flips px, py, pz
|
||||
SIGN_ARRAY_7 = numpy.array((-1, -1, -1, 1, 1, 1, 1))
|
||||
SIGN_ARRAY_4 = numpy.array((-1, 1, 1, 1))
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def flip_chunk_to_positive_px(pt: numpy.ndarray) -> numpy.ndarray:
|
||||
if pt[0] > 0:
|
||||
return pt
|
||||
else:
|
||||
# godawful hack.
|
||||
if len(pt) == 7:
|
||||
return SIGN_ARRAY_7 * pt
|
||||
elif len(pt) == 4:
|
||||
return SIGN_ARRAY_4 * pt
|
||||
else:
|
||||
_logger.warning(f"Could not normalise pt: {pt}. Returning as is...")
|
||||
return pt
|
||||
|
||||
|
||||
def normalise_point_list(pts: numpy.ndarray, pt_length) -> numpy.ndarray:
|
||||
chunked_pts = [
|
||||
flip_chunk_to_positive_px(pts[i : i + pt_length])
|
||||
for i in range(0, len(pts), pt_length)
|
||||
]
|
||||
range_to_length = list(range(pt_length))
|
||||
rotated_range = (
|
||||
range_to_length[pt_length - 1 :] + range_to_length[0 : pt_length - 1]
|
||||
)
|
||||
return numpy.concatenate(
|
||||
sorted(
|
||||
chunked_pts,
|
||||
key=lambda x: tuple(
|
||||
round(val, 3) for val in operator.itemgetter(*rotated_range)(x)
|
||||
),
|
||||
),
|
||||
axis=None,
|
||||
)
|
446
poetry.lock
generated
446
poetry.lock
generated
@ -20,28 +20,6 @@ six = "*"
|
||||
[package.extras]
|
||||
test = ["astroid", "pytest"]
|
||||
|
||||
[[package]]
|
||||
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.*"
|
||||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "21.4.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[package.extras]
|
||||
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", "cloudpickle"]
|
||||
docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
|
||||
tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
|
||||
tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
|
||||
|
||||
[[package]]
|
||||
name = "backcall"
|
||||
version = "0.2.0"
|
||||
@ -91,16 +69,24 @@ category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "colored"
|
||||
version = "1.4.4"
|
||||
description = "Simple library for color and formatting to terminal"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "6.3.2"
|
||||
version = "7.2.7"
|
||||
description = "Code coverage measurement for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
tomli = {version = "*", optional = true, markers = "extra == \"toml\""}
|
||||
tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
|
||||
|
||||
[package.extras]
|
||||
toml = ["tomli"]
|
||||
@ -113,6 +99,17 @@ category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.1.2"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest (>=6)"]
|
||||
|
||||
[[package]]
|
||||
name = "executing"
|
||||
version = "0.8.3"
|
||||
@ -213,7 +210,7 @@ python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "0.942"
|
||||
version = "0.961"
|
||||
description = "Optional static typing for Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
@ -221,7 +218,7 @@ python-versions = ">=3.6"
|
||||
|
||||
[package.dependencies]
|
||||
mypy-extensions = ">=0.4.3"
|
||||
tomli = ">=1.1.0"
|
||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
||||
typing-extensions = ">=3.10"
|
||||
|
||||
[package.extras]
|
||||
@ -349,14 +346,6 @@ python-versions = "*"
|
||||
[package.extras]
|
||||
tests = ["pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "py"
|
||||
version = "1.11.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.*, !=3.4.*"
|
||||
|
||||
[[package]]
|
||||
name = "pycodestyle"
|
||||
version = "2.8.0"
|
||||
@ -394,32 +383,30 @@ diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "6.2.5"
|
||||
version = "7.4.0"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
|
||||
attrs = ">=19.2.0"
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=0.12,<2.0"
|
||||
py = ">=1.8.2"
|
||||
toml = "*"
|
||||
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
|
||||
testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-cov"
|
||||
version = "3.0.0"
|
||||
version = "4.1.0"
|
||||
description = "Pytest plugin for measuring coverage."
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
|
||||
[package.dependencies]
|
||||
coverage = {version = ">=5.2.1", extras = ["toml"]}
|
||||
@ -430,14 +417,19 @@ testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtuale
|
||||
|
||||
[[package]]
|
||||
name = "scipy"
|
||||
version = "1.8.0"
|
||||
description = "SciPy: Scientific Library for Python"
|
||||
version = "1.10.0"
|
||||
description = "Fundamental algorithms for scientific computing in Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8,<3.11"
|
||||
python-versions = "<3.12,>=3.8"
|
||||
|
||||
[package.dependencies]
|
||||
numpy = ">=1.17.3,<1.25.0"
|
||||
numpy = ">=1.19.5,<1.27.0"
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "asv", "mpmath", "gmpy2", "threadpoolctl", "scikit-umfpack", "pooch"]
|
||||
doc = ["sphinx (!=4.1.0)", "pydata-sphinx-theme (==0.9.0)", "sphinx-design (>=0.2.0)", "matplotlib (>2)", "numpydoc"]
|
||||
dev = ["mypy", "typing-extensions", "pycodestyle", "flake8", "rich-click", "click", "doit (>=0.36.0)", "pydevtool"]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
@ -464,12 +456,16 @@ pure-eval = "*"
|
||||
tests = ["pytest", "typeguard", "pygments", "littleutils", "cython"]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.10.2"
|
||||
description = "Python Library for Tom's Obvious, Minimal Language"
|
||||
name = "syrupy"
|
||||
version = "4.0.8"
|
||||
description = "Pytest Snapshot Test Utility"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
python-versions = ">=3.8.1,<4"
|
||||
|
||||
[package.dependencies]
|
||||
colored = ">=1.3.92,<2.0.0"
|
||||
pytest = ">=7.0.0,<8.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "tomli"
|
||||
@ -508,307 +504,51 @@ python-versions = "*"
|
||||
|
||||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.8,<3.10"
|
||||
content-hash = "8ea36a899ad85e7854524e233e51ffc01d2cdf5b493549f1d10536a5f706fc63"
|
||||
python-versions = ">=3.8.1,<3.10"
|
||||
content-hash = "b5275c33449e8f85acbf9c0f6dfe1ec4e7296adfa16360d782b33534e1223638"
|
||||
|
||||
[metadata.files]
|
||||
appnope = [
|
||||
{file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"},
|
||||
{file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"},
|
||||
]
|
||||
asttokens = [
|
||||
{file = "asttokens-2.0.5-py2.py3-none-any.whl", hash = "sha256:0844691e88552595a6f4a4281a9f7f79b8dd45ca4ccea82e5e05b4bbdb76705c"},
|
||||
{file = "asttokens-2.0.5.tar.gz", hash = "sha256:9a54c114f02c7a9480d56550932546a3f1fe71d8a02f1bc7ccd0ee3ee35cf4d5"},
|
||||
]
|
||||
atomicwrites = [
|
||||
{file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
|
||||
{file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
|
||||
]
|
||||
attrs = [
|
||||
{file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
|
||||
{file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
|
||||
]
|
||||
backcall = [
|
||||
{file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"},
|
||||
{file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"},
|
||||
]
|
||||
black = [
|
||||
{file = "black-22.3.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2497f9c2386572e28921fa8bec7be3e51de6801f7459dffd6e62492531c47e09"},
|
||||
{file = "black-22.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5795a0375eb87bfe902e80e0c8cfaedf8af4d49694d69161e5bd3206c18618bb"},
|
||||
{file = "black-22.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e3556168e2e5c49629f7b0f377070240bd5511e45e25a4497bb0073d9dda776a"},
|
||||
{file = "black-22.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67c8301ec94e3bcc8906740fe071391bce40a862b7be0b86fb5382beefecd968"},
|
||||
{file = "black-22.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:fd57160949179ec517d32ac2ac898b5f20d68ed1a9c977346efbac9c2f1e779d"},
|
||||
{file = "black-22.3.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cc1e1de68c8e5444e8f94c3670bb48a2beef0e91dddfd4fcc29595ebd90bb9ce"},
|
||||
{file = "black-22.3.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d2fc92002d44746d3e7db7cf9313cf4452f43e9ea77a2c939defce3b10b5c82"},
|
||||
{file = "black-22.3.0-cp36-cp36m-win_amd64.whl", hash = "sha256:a6342964b43a99dbc72f72812bf88cad8f0217ae9acb47c0d4f141a6416d2d7b"},
|
||||
{file = "black-22.3.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:328efc0cc70ccb23429d6be184a15ce613f676bdfc85e5fe8ea2a9354b4e9015"},
|
||||
{file = "black-22.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06f9d8846f2340dfac80ceb20200ea5d1b3f181dd0556b47af4e8e0b24fa0a6b"},
|
||||
{file = "black-22.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:ad4efa5fad66b903b4a5f96d91461d90b9507a812b3c5de657d544215bb7877a"},
|
||||
{file = "black-22.3.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8477ec6bbfe0312c128e74644ac8a02ca06bcdb8982d4ee06f209be28cdf163"},
|
||||
{file = "black-22.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:637a4014c63fbf42a692d22b55d8ad6968a946b4a6ebc385c5505d9625b6a464"},
|
||||
{file = "black-22.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:863714200ada56cbc366dc9ae5291ceb936573155f8bf8e9de92aef51f3ad0f0"},
|
||||
{file = "black-22.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dbe6e6d2988049b4655b2b739f98785a884d4d6b85bc35133a8fb9a2233176"},
|
||||
{file = "black-22.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:cee3e11161dde1b2a33a904b850b0899e0424cc331b7295f2a9698e79f9a69a0"},
|
||||
{file = "black-22.3.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:5891ef8abc06576985de8fa88e95ab70641de6c1fca97e2a15820a9b69e51b20"},
|
||||
{file = "black-22.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:30d78ba6bf080eeaf0b7b875d924b15cd46fec5fd044ddfbad38c8ea9171043a"},
|
||||
{file = "black-22.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ee8f1f7228cce7dffc2b464f07ce769f478968bfb3dd1254a4c2eeed84928aad"},
|
||||
{file = "black-22.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ee227b696ca60dd1c507be80a6bc849a5a6ab57ac7352aad1ffec9e8b805f21"},
|
||||
{file = "black-22.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:9b542ced1ec0ceeff5b37d69838106a6348e60db7b8fdd245294dc1d26136265"},
|
||||
{file = "black-22.3.0-py3-none-any.whl", hash = "sha256:bc58025940a896d7e5356952228b68f793cf5fcb342be703c3a2669a1488cb72"},
|
||||
{file = "black-22.3.0.tar.gz", hash = "sha256:35020b8886c022ced9282b51b5a875b6d1ab0c387b31a065b84db7c33085ca79"},
|
||||
]
|
||||
click = [
|
||||
{file = "click-8.1.2-py3-none-any.whl", hash = "sha256:24e1a4a9ec5bf6299411369b208c1df2188d9eb8d916302fe6bf03faed227f1e"},
|
||||
{file = "click-8.1.2.tar.gz", hash = "sha256:479707fe14d9ec9a0757618b7a100a0ae4c4e236fac5b7f80ca68028141a1a72"},
|
||||
]
|
||||
colorama = [
|
||||
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
|
||||
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
|
||||
]
|
||||
coverage = [
|
||||
{file = "coverage-6.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf"},
|
||||
{file = "coverage-6.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac"},
|
||||
{file = "coverage-6.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1"},
|
||||
{file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4"},
|
||||
{file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903"},
|
||||
{file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c"},
|
||||
{file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f"},
|
||||
{file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05"},
|
||||
{file = "coverage-6.3.2-cp310-cp310-win32.whl", hash = "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39"},
|
||||
{file = "coverage-6.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1"},
|
||||
{file = "coverage-6.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa"},
|
||||
{file = "coverage-6.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518"},
|
||||
{file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7"},
|
||||
{file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6"},
|
||||
{file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad"},
|
||||
{file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359"},
|
||||
{file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4"},
|
||||
{file = "coverage-6.3.2-cp37-cp37m-win32.whl", hash = "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca"},
|
||||
{file = "coverage-6.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3"},
|
||||
{file = "coverage-6.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d"},
|
||||
{file = "coverage-6.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059"},
|
||||
{file = "coverage-6.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512"},
|
||||
{file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca"},
|
||||
{file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d"},
|
||||
{file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0"},
|
||||
{file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6"},
|
||||
{file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"},
|
||||
{file = "coverage-6.3.2-cp38-cp38-win32.whl", hash = "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e"},
|
||||
{file = "coverage-6.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1"},
|
||||
{file = "coverage-6.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620"},
|
||||
{file = "coverage-6.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d"},
|
||||
{file = "coverage-6.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536"},
|
||||
{file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7"},
|
||||
{file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2"},
|
||||
{file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4"},
|
||||
{file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69"},
|
||||
{file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684"},
|
||||
{file = "coverage-6.3.2-cp39-cp39-win32.whl", hash = "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4"},
|
||||
{file = "coverage-6.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92"},
|
||||
{file = "coverage-6.3.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf"},
|
||||
{file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"},
|
||||
]
|
||||
decorator = [
|
||||
{file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
|
||||
{file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
|
||||
]
|
||||
executing = [
|
||||
{file = "executing-0.8.3-py2.py3-none-any.whl", hash = "sha256:d1eef132db1b83649a3905ca6dd8897f71ac6f8cac79a7e58a1a09cf137546c9"},
|
||||
{file = "executing-0.8.3.tar.gz", hash = "sha256:c6554e21c6b060590a6d3be4b82fb78f8f0194d809de5ea7df1c093763311501"},
|
||||
]
|
||||
flake8 = [
|
||||
{file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
|
||||
{file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
|
||||
]
|
||||
iniconfig = [
|
||||
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
||||
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
||||
]
|
||||
ipython = [
|
||||
{file = "ipython-8.2.0-py3-none-any.whl", hash = "sha256:1b672bfd7a48d87ab203d9af8727a3b0174a4566b4091e9447c22fb63ea32857"},
|
||||
{file = "ipython-8.2.0.tar.gz", hash = "sha256:70e5eb132cac594a34b5f799bd252589009905f05104728aea6a403ec2519dc1"},
|
||||
]
|
||||
jedi = [
|
||||
{file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"},
|
||||
{file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"},
|
||||
]
|
||||
matplotlib-inline = [
|
||||
{file = "matplotlib-inline-0.1.3.tar.gz", hash = "sha256:a04bfba22e0d1395479f866853ec1ee28eea1485c1d69a6faf00dc3e24ff34ee"},
|
||||
{file = "matplotlib_inline-0.1.3-py3-none-any.whl", hash = "sha256:aed605ba3b72462d64d475a21a9296f400a19c4f74a31b59103d2a99ffd5aa5c"},
|
||||
]
|
||||
mccabe = [
|
||||
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
|
||||
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
|
||||
]
|
||||
mypy = [
|
||||
{file = "mypy-0.942-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5bf44840fb43ac4074636fd47ee476d73f0039f4f54e86d7265077dc199be24d"},
|
||||
{file = "mypy-0.942-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dcd955f36e0180258a96f880348fbca54ce092b40fbb4b37372ae3b25a0b0a46"},
|
||||
{file = "mypy-0.942-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6776e5fa22381cc761df53e7496a805801c1a751b27b99a9ff2f0ca848c7eca0"},
|
||||
{file = "mypy-0.942-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:edf7237137a1a9330046dbb14796963d734dd740a98d5e144a3eb1d267f5f9ee"},
|
||||
{file = "mypy-0.942-cp310-cp310-win_amd64.whl", hash = "sha256:64235137edc16bee6f095aba73be5334677d6f6bdb7fa03cfab90164fa294a17"},
|
||||
{file = "mypy-0.942-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b840cfe89c4ab6386c40300689cd8645fc8d2d5f20101c7f8bd23d15fca14904"},
|
||||
{file = "mypy-0.942-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2b184db8c618c43c3a31b32ff00cd28195d39e9c24e7c3b401f3db7f6e5767f5"},
|
||||
{file = "mypy-0.942-cp36-cp36m-win_amd64.whl", hash = "sha256:1a0459c333f00e6a11cbf6b468b870c2b99a906cb72d6eadf3d1d95d38c9352c"},
|
||||
{file = "mypy-0.942-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4c3e497588afccfa4334a9986b56f703e75793133c4be3a02d06a3df16b67a58"},
|
||||
{file = "mypy-0.942-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f6ad963172152e112b87cc7ec103ba0f2db2f1cd8997237827c052a3903eaa6"},
|
||||
{file = "mypy-0.942-cp37-cp37m-win_amd64.whl", hash = "sha256:0e2dd88410937423fba18e57147dd07cd8381291b93d5b1984626f173a26543e"},
|
||||
{file = "mypy-0.942-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:246e1aa127d5b78488a4a0594bd95f6d6fb9d63cf08a66dafbff8595d8891f67"},
|
||||
{file = "mypy-0.942-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d8d3ba77e56b84cd47a8ee45b62c84b6d80d32383928fe2548c9a124ea0a725c"},
|
||||
{file = "mypy-0.942-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2bc249409a7168d37c658e062e1ab5173300984a2dada2589638568ddc1db02b"},
|
||||
{file = "mypy-0.942-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9521c1265ccaaa1791d2c13582f06facf815f426cd8b07c3a485f486a8ffc1f3"},
|
||||
{file = "mypy-0.942-cp38-cp38-win_amd64.whl", hash = "sha256:e865fec858d75b78b4d63266c9aff770ecb6a39dfb6d6b56c47f7f8aba6baba8"},
|
||||
{file = "mypy-0.942-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6ce34a118d1a898f47def970a2042b8af6bdcc01546454726c7dd2171aa6dfca"},
|
||||
{file = "mypy-0.942-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:10daab80bc40f84e3f087d896cdb53dc811a9f04eae4b3f95779c26edee89d16"},
|
||||
{file = "mypy-0.942-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3841b5433ff936bff2f4dc8d54cf2cdbfea5d8e88cedfac45c161368e5770ba6"},
|
||||
{file = "mypy-0.942-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6f7106cbf9cc2f403693bf50ed7c9fa5bb3dfa9007b240db3c910929abe2a322"},
|
||||
{file = "mypy-0.942-cp39-cp39-win_amd64.whl", hash = "sha256:7742d2c4e46bb5017b51c810283a6a389296cda03df805a4f7869a6f41246534"},
|
||||
{file = "mypy-0.942-py3-none-any.whl", hash = "sha256:a1b383fe99678d7402754fe90448d4037f9512ce70c21f8aee3b8bf48ffc51db"},
|
||||
{file = "mypy-0.942.tar.gz", hash = "sha256:17e44649fec92e9f82102b48a3bf7b4a5510ad0cd22fa21a104826b5db4903e2"},
|
||||
]
|
||||
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.22.3-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:92bfa69cfbdf7dfc3040978ad09a48091143cffb778ec3b03fa170c494118d75"},
|
||||
{file = "numpy-1.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8251ed96f38b47b4295b1ae51631de7ffa8260b5b087808ef09a39a9d66c97ab"},
|
||||
{file = "numpy-1.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48a3aecd3b997bf452a2dedb11f4e79bc5bfd21a1d4cc760e703c31d57c84b3e"},
|
||||
{file = "numpy-1.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3bae1a2ed00e90b3ba5f7bd0a7c7999b55d609e0c54ceb2b076a25e345fa9f4"},
|
||||
{file = "numpy-1.22.3-cp310-cp310-win32.whl", hash = "sha256:f950f8845b480cffe522913d35567e29dd381b0dc7e4ce6a4a9f9156417d2430"},
|
||||
{file = "numpy-1.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:08d9b008d0156c70dc392bb3ab3abb6e7a711383c3247b410b39962263576cd4"},
|
||||
{file = "numpy-1.22.3-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:201b4d0552831f7250a08d3b38de0d989d6f6e4658b709a02a73c524ccc6ffce"},
|
||||
{file = "numpy-1.22.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8c1f39caad2c896bc0018f699882b345b2a63708008be29b1f355ebf6f933fe"},
|
||||
{file = "numpy-1.22.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:568dfd16224abddafb1cbcce2ff14f522abe037268514dd7e42c6776a1c3f8e5"},
|
||||
{file = "numpy-1.22.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ca688e1b9b95d80250bca34b11a05e389b1420d00e87a0d12dc45f131f704a1"},
|
||||
{file = "numpy-1.22.3-cp38-cp38-win32.whl", hash = "sha256:e7927a589df200c5e23c57970bafbd0cd322459aa7b1ff73b7c2e84d6e3eae62"},
|
||||
{file = "numpy-1.22.3-cp38-cp38-win_amd64.whl", hash = "sha256:07a8c89a04997625236c5ecb7afe35a02af3896c8aa01890a849913a2309c676"},
|
||||
{file = "numpy-1.22.3-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:2c10a93606e0b4b95c9b04b77dc349b398fdfbda382d2a39ba5a822f669a0123"},
|
||||
{file = "numpy-1.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fade0d4f4d292b6f39951b6836d7a3c7ef5b2347f3c420cd9820a1d90d794802"},
|
||||
{file = "numpy-1.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bfb1bb598e8229c2d5d48db1860bcf4311337864ea3efdbe1171fb0c5da515d"},
|
||||
{file = "numpy-1.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97098b95aa4e418529099c26558eeb8486e66bd1e53a6b606d684d0c3616b168"},
|
||||
{file = "numpy-1.22.3-cp39-cp39-win32.whl", hash = "sha256:fdf3c08bce27132395d3c3ba1503cac12e17282358cb4bddc25cc46b0aca07aa"},
|
||||
{file = "numpy-1.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:639b54cdf6aa4f82fe37ebf70401bbb74b8508fddcf4797f9fe59615b8c5813a"},
|
||||
{file = "numpy-1.22.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c34ea7e9d13a70bf2ab64a2532fe149a9aced424cd05a2c4ba662fd989e3e45f"},
|
||||
{file = "numpy-1.22.3.zip", hash = "sha256:dbc7601a3b7472d559dc7b933b18b4b66f9aa7452c120e87dfb33d02008c8a18"},
|
||||
]
|
||||
packaging = [
|
||||
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||
]
|
||||
parso = [
|
||||
{file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"},
|
||||
{file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"},
|
||||
]
|
||||
pathspec = [
|
||||
{file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"},
|
||||
{file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"},
|
||||
]
|
||||
pexpect = [
|
||||
{file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"},
|
||||
{file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"},
|
||||
]
|
||||
pickleshare = [
|
||||
{file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"},
|
||||
{file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"},
|
||||
]
|
||||
platformdirs = [
|
||||
{file = "platformdirs-2.5.1-py3-none-any.whl", hash = "sha256:bcae7cab893c2d310a711b70b24efb93334febe65f8de776ee320b517471e227"},
|
||||
{file = "platformdirs-2.5.1.tar.gz", hash = "sha256:7535e70dfa32e84d4b34996ea99c5e432fa29a708d0f4e394bbcb2a8faa4f16d"},
|
||||
]
|
||||
pluggy = [
|
||||
{file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
|
||||
{file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"},
|
||||
]
|
||||
prompt-toolkit = [
|
||||
{file = "prompt_toolkit-3.0.28-py3-none-any.whl", hash = "sha256:30129d870dcb0b3b6a53efdc9d0a83ea96162ffd28ffe077e94215b233dc670c"},
|
||||
{file = "prompt_toolkit-3.0.28.tar.gz", hash = "sha256:9f1cd16b1e86c2968f2519d7fb31dd9d669916f515612c269d14e9ed52b51650"},
|
||||
]
|
||||
ptyprocess = [
|
||||
{file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
|
||||
{file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
|
||||
]
|
||||
pure-eval = [
|
||||
{file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"},
|
||||
{file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"},
|
||||
]
|
||||
py = [
|
||||
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
||||
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||
]
|
||||
pycodestyle = [
|
||||
{file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
|
||||
{file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
|
||||
]
|
||||
pyflakes = [
|
||||
{file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
|
||||
{file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
|
||||
]
|
||||
pygments = [
|
||||
{file = "Pygments-2.11.2-py3-none-any.whl", hash = "sha256:44238f1b60a76d78fc8ca0528ee429702aae011c265fe6a8dd8b63049ae41c65"},
|
||||
{file = "Pygments-2.11.2.tar.gz", hash = "sha256:4e426f72023d88d03b2fa258de560726ce890ff3b630f88c21cbb8b2503b8c6a"},
|
||||
]
|
||||
pyparsing = [
|
||||
{file = "pyparsing-3.0.6-py3-none-any.whl", hash = "sha256:04ff808a5b90911829c55c4e26f75fa5ca8a2f5f36aa3a51f68e27033341d3e4"},
|
||||
{file = "pyparsing-3.0.6.tar.gz", hash = "sha256:d9bdec0013ef1eb5a84ab39a3b3868911598afa494f5faa038647101504e2b81"},
|
||||
]
|
||||
pytest = [
|
||||
{file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
|
||||
{file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
|
||||
]
|
||||
pytest-cov = [
|
||||
{file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"},
|
||||
{file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"},
|
||||
]
|
||||
scipy = [
|
||||
{file = "scipy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:87b01c7d5761e8a266a0fbdb9d88dcba0910d63c1c671bdb4d99d29f469e9e03"},
|
||||
{file = "scipy-1.8.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ae3e327da323d82e918e593460e23babdce40d7ab21490ddf9fc06dec6b91a18"},
|
||||
{file = "scipy-1.8.0-cp310-cp310-macosx_12_0_universal2.macosx_10_9_x86_64.whl", hash = "sha256:16e09ef68b352d73befa8bcaf3ebe25d3941fe1a58c82909d5589856e6bc8174"},
|
||||
{file = "scipy-1.8.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c17a1878d00a5dd2797ccd73623ceca9d02375328f6218ee6d921e1325e61aff"},
|
||||
{file = "scipy-1.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937d28722f13302febde29847bbe554b89073fbb924a30475e5ed7b028898b5f"},
|
||||
{file = "scipy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:8f4d059a97b29c91afad46b1737274cb282357a305a80bdd9e8adf3b0ca6a3f0"},
|
||||
{file = "scipy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:38aa39b6724cb65271e469013aeb6f2ce66fd44f093e241c28a9c6bc64fd79ed"},
|
||||
{file = "scipy-1.8.0-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:559a8a4c03a5ba9fe3232f39ed24f86457e4f3f6c0abbeae1fb945029f092720"},
|
||||
{file = "scipy-1.8.0-cp38-cp38-macosx_12_0_universal2.macosx_10_9_x86_64.whl", hash = "sha256:f4a6d3b9f9797eb2d43938ac2c5d96d02aed17ef170c8b38f11798717523ddba"},
|
||||
{file = "scipy-1.8.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:92b2c2af4183ed09afb595709a8ef5783b2baf7f41e26ece24e1329c109691a7"},
|
||||
{file = "scipy-1.8.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a279e27c7f4566ef18bab1b1e2c37d168e365080974758d107e7d237d3f0f484"},
|
||||
{file = "scipy-1.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad5be4039147c808e64f99c0e8a9641eb5d2fa079ff5894dcd8240e94e347af4"},
|
||||
{file = "scipy-1.8.0-cp38-cp38-win32.whl", hash = "sha256:3d9dd6c8b93a22bf9a3a52d1327aca7e092b1299fb3afc4f89e8eba381be7b59"},
|
||||
{file = "scipy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:5e73343c5e0d413c1f937302b2e04fb07872f5843041bcfd50699aef6e95e399"},
|
||||
{file = "scipy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:de2e80ee1d925984c2504812a310841c241791c5279352be4707cdcd7c255039"},
|
||||
{file = "scipy-1.8.0-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:c2bae431d127bf0b1da81fc24e4bba0a84d058e3a96b9dd6475dfcb3c5e8761e"},
|
||||
{file = "scipy-1.8.0-cp39-cp39-macosx_12_0_universal2.macosx_10_9_x86_64.whl", hash = "sha256:723b9f878095ed994756fa4ee3060c450e2db0139c5ba248ee3f9628bd64e735"},
|
||||
{file = "scipy-1.8.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:011d4386b53b933142f58a652aa0f149c9b9242abd4f900b9f4ea5fbafc86b89"},
|
||||
{file = "scipy-1.8.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e6f0cd9c0bd374ef834ee1e0f0999678d49dcc400ea6209113d81528958f97c7"},
|
||||
{file = "scipy-1.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3720d0124aced49f6f2198a6900304411dbbeed12f56951d7c66ebef05e3df6"},
|
||||
{file = "scipy-1.8.0-cp39-cp39-win32.whl", hash = "sha256:3d573228c10a3a8c32b9037be982e6440e411b443a6267b067cac72f690b8d56"},
|
||||
{file = "scipy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bb7088e89cd751acf66195d2f00cf009a1ea113f3019664032d9075b1e727b6c"},
|
||||
{file = "scipy-1.8.0.tar.gz", hash = "sha256:31d4f2d6b724bc9a98e527b5849b8a7e589bf1ea630c33aa563eda912c9ff0bd"},
|
||||
]
|
||||
six = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
]
|
||||
stack-data = [
|
||||
{file = "stack_data-0.2.0-py3-none-any.whl", hash = "sha256:999762f9c3132308789affa03e9271bbbe947bf78311851f4d485d8402ed858e"},
|
||||
{file = "stack_data-0.2.0.tar.gz", hash = "sha256:45692d41bd633a9503a5195552df22b583caf16f0b27c4e58c98d88c8b648e12"},
|
||||
]
|
||||
toml = [
|
||||
{file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
|
||||
{file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
|
||||
]
|
||||
tomli = [
|
||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
||||
]
|
||||
traitlets = [
|
||||
{file = "traitlets-5.1.1-py3-none-any.whl", hash = "sha256:2d313cc50a42cd6c277e7d7dc8d4d7fedd06a2c215f78766ae7b1a66277e0033"},
|
||||
{file = "traitlets-5.1.1.tar.gz", hash = "sha256:059f456c5a7c1c82b98c2e8c799f39c9b8128f6d0d46941ee118daace9eb70c7"},
|
||||
]
|
||||
typing-extensions = [
|
||||
{file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"},
|
||||
{file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"},
|
||||
]
|
||||
wcwidth = [
|
||||
{file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
|
||||
{file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
|
||||
]
|
||||
appnope = []
|
||||
asttokens = []
|
||||
backcall = []
|
||||
black = []
|
||||
click = []
|
||||
colorama = []
|
||||
colored = []
|
||||
coverage = []
|
||||
decorator = []
|
||||
exceptiongroup = []
|
||||
executing = []
|
||||
flake8 = []
|
||||
iniconfig = []
|
||||
ipython = []
|
||||
jedi = []
|
||||
matplotlib-inline = []
|
||||
mccabe = []
|
||||
mypy = []
|
||||
mypy-extensions = []
|
||||
numpy = []
|
||||
packaging = []
|
||||
parso = []
|
||||
pathspec = []
|
||||
pexpect = []
|
||||
pickleshare = []
|
||||
platformdirs = []
|
||||
pluggy = []
|
||||
prompt-toolkit = []
|
||||
ptyprocess = []
|
||||
pure-eval = []
|
||||
pycodestyle = []
|
||||
pyflakes = []
|
||||
pygments = []
|
||||
pyparsing = []
|
||||
pytest = []
|
||||
pytest-cov = []
|
||||
scipy = []
|
||||
six = []
|
||||
stack-data = []
|
||||
syrupy = []
|
||||
tomli = []
|
||||
traitlets = []
|
||||
typing-extensions = []
|
||||
wcwidth = []
|
||||
|
@ -1,32 +1,35 @@
|
||||
[tool.poetry]
|
||||
name = "pdme"
|
||||
version = "0.6.2"
|
||||
version = "1.5.0"
|
||||
description = "Python dipole model evaluator"
|
||||
authors = ["Deepak <dmallubhotla+github@gmail.com>"]
|
||||
license = "GPL-3.0-only"
|
||||
readme = "README.md"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.8,<3.10"
|
||||
python = ">=3.8.1,<3.10"
|
||||
numpy = "^1.22.3"
|
||||
scipy = "~1.8"
|
||||
scipy = "~1.10"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pytest = ">=6"
|
||||
flake8 = "^4.0.0"
|
||||
pytest-cov = "^3.0.0"
|
||||
mypy = "^0.942"
|
||||
pytest-cov = "^4.1.0"
|
||||
mypy = "^0.961"
|
||||
ipython = "^8.2.0"
|
||||
black = "^22.3.0"
|
||||
syrupy = "^4.0.8"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry>=0.12"]
|
||||
build-backend = "poetry.masonry.api"
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
addopts = "--junitxml pytest.xml --cov pdme --cov-report=xml:coverage.xml --cov-fail-under=50 --cov-report=html"
|
||||
junit_family = "xunit1"
|
||||
log_format = "%(asctime)s | %(levelname)s | %(pathname)s:%(lineno)d | %(message)s"
|
||||
log_level = "WARNING"
|
||||
|
||||
[tool.mypy]
|
||||
plugins = "numpy.typing.mypy_plugin"
|
||||
|
@ -1,4 +1,4 @@
|
||||
const pattern = /(\[tool\.poetry\]\nname = "pdme"\nversion = ")(?<vers>\d+\.\d+\.\d)(")/mg;
|
||||
const pattern = /(\[tool\.poetry\]\nname = "pdme"\nversion = ")(?<vers>\d+\.\d+\.\d+)(")/mg;
|
||||
|
||||
module.exports.readVersion = function (contents) {
|
||||
const result = pattern.exec(contents);
|
||||
|
81
tests/calculations/__snapshots__/test_calculations.ambr
Normal file
81
tests/calculations/__snapshots__/test_calculations.ambr
Normal file
@ -0,0 +1,81 @@
|
||||
# serializer version: 1
|
||||
# name: test_multiple_electric_field_alphas
|
||||
list([
|
||||
list([
|
||||
0.009579434215333742,
|
||||
0.007714411624737791,
|
||||
0.0035604976729559034,
|
||||
]),
|
||||
list([
|
||||
0.005036717012002481,
|
||||
0.006259221141129298,
|
||||
-0.009682232702684382,
|
||||
]),
|
||||
list([
|
||||
0.01503516326014651,
|
||||
0.012028130608117207,
|
||||
0.009021097956087907,
|
||||
]),
|
||||
list([
|
||||
0.0033871215792458027,
|
||||
0.0038182097802407235,
|
||||
-0.005604146612933966,
|
||||
]),
|
||||
list([
|
||||
0.007409666906433089,
|
||||
0.006778734778841714,
|
||||
0.003467602973242188,
|
||||
]),
|
||||
list([
|
||||
0.004730939083250055,
|
||||
0.0046546336141653774,
|
||||
-0.011766303332857395,
|
||||
]),
|
||||
list([
|
||||
-0.010766266772985707,
|
||||
-0.012631289363581657,
|
||||
-0.010851040527103707,
|
||||
]),
|
||||
list([
|
||||
-0.008410828408392494,
|
||||
-0.020391368873835285,
|
||||
0.009877833363344673,
|
||||
]),
|
||||
list([
|
||||
-0.015035163260146511,
|
||||
-0.018042195912175815,
|
||||
-0.021049228564205113,
|
||||
]),
|
||||
list([
|
||||
-0.005850482727788205,
|
||||
-0.012193637685284892,
|
||||
0.0054809785555068454,
|
||||
]),
|
||||
list([
|
||||
-0.007682229585552562,
|
||||
-0.010584517372472879,
|
||||
-0.009352937859414517,
|
||||
]),
|
||||
list([
|
||||
-0.009767100042838822,
|
||||
-0.020831393060117175,
|
||||
0.014024945217763873,
|
||||
]),
|
||||
])
|
||||
# ---
|
||||
# name: test_multiple_electric_potential_alphas
|
||||
list([
|
||||
0.05035560994609065,
|
||||
-0.03369221379873504,
|
||||
0.07216878364870323,
|
||||
-0.024633611485424027,
|
||||
0.04496779459769236,
|
||||
-0.03108684810509794,
|
||||
-0.08019597139562586,
|
||||
0.08293468011996319,
|
||||
-0.10825317547305485,
|
||||
0.060044427995721066,
|
||||
-0.06935710692186449,
|
||||
0.08733923991432278,
|
||||
])
|
||||
# ---
|
102
tests/calculations/test_calculations.py
Normal file
102
tests/calculations/test_calculations.py
Normal file
@ -0,0 +1,102 @@
|
||||
import pdme.calculations
|
||||
import pytest
|
||||
import numpy
|
||||
import numpy.testing
|
||||
|
||||
|
||||
# generated in mathematica to compare here
|
||||
beta_test_data = [
|
||||
[-2, -2, 0.8072976151],
|
||||
[-1, -2, 0.008105366193],
|
||||
[0, -2, 0.00008105691406],
|
||||
[1, -2, 8.105694659e-7],
|
||||
[2, -2, 8.105694691e-9],
|
||||
[-2, -1, 5.768008783],
|
||||
[-1, -1, 0.08072976151],
|
||||
[0, -1, 0.0008105366193],
|
||||
[1, -1, 8.105691406e-6],
|
||||
[2, -1, 8.105694659e-8],
|
||||
[-2, 0, 1.951840272],
|
||||
[-1, 0, 0.5768008783],
|
||||
[0, 0, 0.008072976151],
|
||||
[1, 0, 0.00008105366193],
|
||||
[2, 0, 8.105691406e-7],
|
||||
[-2, 1, 0.1999506642],
|
||||
[-1, 1, 0.1951840272],
|
||||
[0, 1, 0.05768008783],
|
||||
[1, 1, 0.0008072976151],
|
||||
[2, 1, 8.105366193e-6],
|
||||
[-2, 2, 0.01999995065],
|
||||
[-1, 2, 0.01999506642],
|
||||
[0, 2, 0.01951840272],
|
||||
[1, 2, 0.005768008783],
|
||||
[2, 2, 0.00008072976151],
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("f, w, expected", beta_test_data)
|
||||
def test_calculations_beta_func(f, w, expected):
|
||||
# there's nothing special about the 5 * 10^ f and 10^w passing in logs
|
||||
# this was just to get a variety of orders of magnitude in results.
|
||||
actual = pdme.calculations.telegraph_beta(5 * 10**f, 10**w)
|
||||
numpy.testing.assert_allclose(actual, expected, atol=0, rtol=1e-8)
|
||||
|
||||
|
||||
def test_multiple_electric_potential_alphas(snapshot):
|
||||
"""
|
||||
Manually compare these with mathematica stuff because manually including a list is a bit annoying.
|
||||
Basically just visually compare the snapshot values to make sure they're actually correct.
|
||||
"""
|
||||
dipole_ps = [
|
||||
numpy.array([1, 2, 3]),
|
||||
numpy.array([-4, -3, -2]),
|
||||
]
|
||||
dipole_ss = [
|
||||
numpy.array([0, 0, 1]),
|
||||
numpy.array([1, 1, 1]),
|
||||
numpy.array([0, -0.5, 0.5]),
|
||||
]
|
||||
|
||||
test_rs = [
|
||||
numpy.array([5, 5, 5]),
|
||||
numpy.array([-4, -6, 2]),
|
||||
]
|
||||
|
||||
actuals = [
|
||||
pdme.calculations.electric_potential(p, s, r)
|
||||
for p in dipole_ps
|
||||
for s in dipole_ss
|
||||
for r in test_rs
|
||||
]
|
||||
|
||||
assert actuals == snapshot
|
||||
|
||||
|
||||
def test_multiple_electric_field_alphas(snapshot):
|
||||
"""
|
||||
Manually compare these with mathematica stuff because manually including a list is a bit annoying.
|
||||
Basically just visually compare the snapshot values to make sure they're actually correct.
|
||||
"""
|
||||
dipole_ps = [
|
||||
numpy.array([1, 2, 3]),
|
||||
numpy.array([-4, -3, -2]),
|
||||
]
|
||||
dipole_ss = [
|
||||
numpy.array([0, 0, 1]),
|
||||
numpy.array([1, 1, 1]),
|
||||
numpy.array([0, -0.5, 0.5]),
|
||||
]
|
||||
|
||||
test_rs = [
|
||||
numpy.array([5, 5, 5]),
|
||||
numpy.array([-4, -6, 2]),
|
||||
]
|
||||
|
||||
actuals = [
|
||||
pdme.calculations.electric_field(p, s, r).tolist()
|
||||
for p in dipole_ps
|
||||
for s in dipole_ss
|
||||
for r in test_rs
|
||||
]
|
||||
|
||||
assert actuals == snapshot
|
@ -2,23 +2,30 @@ import numpy
|
||||
import pdme.measurement
|
||||
|
||||
|
||||
def test_static_dipole():
|
||||
d1 = pdme.measurement.OscillatingDipole((1, 2, 3), (4, 5, 6), 7)
|
||||
d2 = pdme.measurement.OscillatingDipole((2, 5, 3), (4, -5, -6), 2)
|
||||
def test_static_dipole_electric_potential():
|
||||
d1 = pdme.measurement.OscillatingDipole(
|
||||
numpy.array((1, 2, 3)), numpy.array([4, 5, 6]), 7
|
||||
)
|
||||
d2 = pdme.measurement.OscillatingDipole(
|
||||
numpy.array([2, 5, 3]), numpy.array([4, -5, -6]), 2
|
||||
)
|
||||
dipoles = pdme.measurement.OscillatingDipoleArrangement([d1, d2])
|
||||
|
||||
dot_position1 = (-1, -1, -1)
|
||||
dot_position1 = numpy.array([-1, -1, -1])
|
||||
dot_frequency1 = 11
|
||||
expected_v1 = 0.00001421963287022476
|
||||
expected_v2 = 0.00001107180225755457
|
||||
|
||||
expected_v1 = 0.00001221710876727626
|
||||
expected_v2 = 7.257229625870065e-6
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
d1.s_at_position(dot_position1, dot_frequency1),
|
||||
d1.s_electric_potential_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)])
|
||||
dot_measurements = dipoles.get_potential_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(
|
||||
@ -38,24 +45,57 @@ def test_static_dipole():
|
||||
)
|
||||
|
||||
|
||||
def test_dipole_dot_pair():
|
||||
d1 = pdme.measurement.OscillatingDipole((1, 2, 3), (4, 5, 6), 7)
|
||||
dipoles = pdme.measurement.OscillatingDipoleArrangement([d1])
|
||||
def test_static_dipole_electric_field_x():
|
||||
d1 = pdme.measurement.OscillatingDipole(
|
||||
numpy.array((1, 2, 3)), numpy.array([4, 5, 6]), 7
|
||||
)
|
||||
d2 = pdme.measurement.OscillatingDipole(
|
||||
numpy.array([2, 5, 3]), numpy.array([4, -5, -6]), 2
|
||||
)
|
||||
# dipoles = pdme.measurement.OscillatingDipoleArrangement([d1, d2])
|
||||
|
||||
dot_position1 = (-1, -1, -1)
|
||||
dot_position2 = (1, 2, 3)
|
||||
dot_frequency = 8
|
||||
expected_sij = 0.000083328037100902801698
|
||||
dot_position1 = numpy.array([-1, -1, -1])
|
||||
dot_frequency1 = 11
|
||||
|
||||
# these should be true for electric field
|
||||
expected_v1 = 1.479556451978925e-7
|
||||
expected_v2 = 6.852024308908262e-7
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
d1.s_for_dot_pair(dot_position1, dot_position2, dot_frequency),
|
||||
d1.s_electric_fieldx_at_position(dot_position1, dot_frequency1),
|
||||
expected_v1,
|
||||
err_msg="Fieldx noise at dot isn't as expected.",
|
||||
)
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
d2.s_electric_fieldx_at_position(dot_position1, dot_frequency1),
|
||||
expected_v2,
|
||||
err_msg="Fieldx at dot isn't as expected.",
|
||||
)
|
||||
|
||||
|
||||
def test_dipole_dot_pair():
|
||||
d1 = pdme.measurement.OscillatingDipole(
|
||||
numpy.array([1, 2, 3]), numpy.array([4, 5, 6]), 7
|
||||
)
|
||||
dipoles = pdme.measurement.OscillatingDipoleArrangement([d1])
|
||||
|
||||
dot_position1 = numpy.array([-1, -1, -1])
|
||||
dot_position2 = numpy.array([1, 2, 3])
|
||||
dot_frequency = 8
|
||||
expected_sij = 0.00008692058236162933
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
d1.s_electric_potential_for_dot_pair(
|
||||
dot_position1, dot_position2, dot_frequency
|
||||
),
|
||||
expected_sij,
|
||||
err_msg="Sij for dot pair isn't as expected.",
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
[
|
||||
m.v
|
||||
for m in dipoles.get_dot_pair_measurements(
|
||||
for m in dipoles.get_potential_dot_pair_measurements(
|
||||
[(dot_position1, dot_position2, dot_frequency)]
|
||||
)
|
||||
],
|
||||
@ -65,15 +105,17 @@ def test_dipole_dot_pair():
|
||||
|
||||
|
||||
def test_range_pairs():
|
||||
d1 = pdme.measurement.OscillatingDipole((1, 2, 3), (4, 5, 6), 7)
|
||||
d1 = pdme.measurement.OscillatingDipole(
|
||||
numpy.array([1, 2, 3]), numpy.array([4, 5, 6]), 7
|
||||
)
|
||||
dipoles = pdme.measurement.OscillatingDipoleArrangement([d1])
|
||||
|
||||
dot_position1 = (-1, -1, -1)
|
||||
dot_position2 = (1, 2, 3)
|
||||
dot_position1 = numpy.array([-1, -1, -1])
|
||||
dot_position2 = numpy.array([1, 2, 3])
|
||||
dot_frequency = 8
|
||||
expected_sij = 0.000083328037100902801698
|
||||
expected_sij = 0.00008692058236162933
|
||||
|
||||
actuals = dipoles.get_percent_range_dot_pair_measurements(
|
||||
actuals = dipoles.get_percent_range_potential_dot_pair_measurements(
|
||||
[(dot_position1, dot_position2, dot_frequency)], 0.5, 1.5
|
||||
)
|
||||
assert len(actuals) == 1, "should have only been one pair"
|
||||
@ -86,22 +128,26 @@ def test_range_pairs():
|
||||
|
||||
|
||||
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)
|
||||
d1 = pdme.measurement.OscillatingDipole(
|
||||
numpy.array([1, 2, 3]), numpy.array([4, 5, 6]), 7
|
||||
)
|
||||
d2 = pdme.measurement.OscillatingDipole(
|
||||
numpy.array([2, 5, 3]), numpy.array([4, -5, -6]), 2
|
||||
)
|
||||
dipoles = pdme.measurement.OscillatingDipoleArrangement([d1, d2])
|
||||
|
||||
dot_position1 = (-1, -1, -1)
|
||||
dot_position1 = numpy.array([-1, -1, -1])
|
||||
dot_frequency1 = 11
|
||||
expected_v1 = 0.00001421963287022476
|
||||
expected_v2 = 0.00001107180225755457
|
||||
expected_v1 = 0.00001221710876727626
|
||||
expected_v2 = 7.257229625870065e-6
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
d1.s_at_position(dot_position1, dot_frequency1),
|
||||
d1.s_electric_potential_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(
|
||||
range_dot_measurements = dipoles.get_percent_range_potential_dot_measurements(
|
||||
[(dot_position1, dot_frequency1)], 0.5, 1.5
|
||||
)
|
||||
assert len(range_dot_measurements) == 1, "Should have only had one dot measurement."
|
||||
|
@ -0,0 +1,55 @@
|
||||
# serializer version: 1
|
||||
# name: test_log_spaced_fixedxy_orientation_mcmc_basic
|
||||
list([
|
||||
tuple(
|
||||
3984.4199552664,
|
||||
array([[ 9.55610128, 2.94634152, 0. , 9.21529051, -2.46576127,
|
||||
2.42481096, 9.19034554]]),
|
||||
),
|
||||
tuple(
|
||||
8583.8032728084,
|
||||
array([[ 9.99991539, 0.04113671, 0. , 8.71258954, -2.26599865,
|
||||
2.60452102, 6.37042214]]),
|
||||
),
|
||||
tuple(
|
||||
6215.5671525452,
|
||||
array([[ 9.81950685, -1.89137124, 0. , 8.90637055, -2.48043039,
|
||||
2.28444435, 8.84239221]]),
|
||||
),
|
||||
tuple(
|
||||
424.7282747232,
|
||||
array([[ 1.00028483, 9.94984574, 0. , 8.53064898, -2.59230757,
|
||||
2.33774773, 8.6714416 ]]),
|
||||
),
|
||||
tuple(
|
||||
300.920463669,
|
||||
array([[ 1.4003442 , 9.90146636, 0. , 8.05557992, -2.6753126 ,
|
||||
2.65915755, 13.02021385]]),
|
||||
),
|
||||
tuple(
|
||||
2400.0053792245,
|
||||
array([[ 9.97761813, 0.66868263, 0. , 8.69171028, -2.73145011,
|
||||
2.90140456, 19.94999593]]),
|
||||
),
|
||||
tuple(
|
||||
5001.4154377966,
|
||||
array([[ 9.93976109, -1.09596962, 0. , 8.95245025, -2.59409162,
|
||||
2.90140456, 9.75535945]]),
|
||||
),
|
||||
tuple(
|
||||
195.2191433934,
|
||||
array([[ 0.20690762, 9.99785923, 0. , 9.59636585, -2.83240984,
|
||||
2.90140456, 16.14771567]]),
|
||||
),
|
||||
tuple(
|
||||
2698.2459654601,
|
||||
array([[-9.68130127, -2.50447712, 0. , 8.94823619, -2.92889659,
|
||||
2.77065328, 13.63173263]]),
|
||||
),
|
||||
tuple(
|
||||
1193.6653292625,
|
||||
array([[-6.16597091, -7.87278875, 0. , 9.62210721, -2.75993924,
|
||||
2.77065328, 5.64553534]]),
|
||||
),
|
||||
])
|
||||
# ---
|
@ -0,0 +1,55 @@
|
||||
# serializer version: 1
|
||||
# name: test_log_spaced_free_orientation_mcmc_basic
|
||||
list([
|
||||
tuple(
|
||||
3167.6603875494,
|
||||
array([[ 9.60483896, -1.41627817, -2.3960853 , -4.76615152, -1.80902942,
|
||||
2.11809123, 16.17452242]]),
|
||||
),
|
||||
tuple(
|
||||
3167.6603875494,
|
||||
array([[ 9.60483896, -1.41627817, -2.3960853 , -4.76615152, -1.80902942,
|
||||
2.11809123, 16.17452242]]),
|
||||
),
|
||||
tuple(
|
||||
3167.6603875494,
|
||||
array([[ 9.60483896, -1.41627817, -2.3960853 , -4.76615152, -1.80902942,
|
||||
2.11809123, 16.17452242]]),
|
||||
),
|
||||
tuple(
|
||||
2320.6090682509,
|
||||
array([[ 4.1660069 , -8.11557337, 4.0965663 , -4.35968351, -1.97945216,
|
||||
2.43615641, 12.92143144]]),
|
||||
),
|
||||
tuple(
|
||||
2320.6090682509,
|
||||
array([[ 4.1660069 , -8.11557337, 4.0965663 , -4.35968351, -1.97945216,
|
||||
2.43615641, 12.92143144]]),
|
||||
),
|
||||
tuple(
|
||||
2320.6090682509,
|
||||
array([[ 4.1660069 , -8.11557337, 4.0965663 , -4.35968351, -1.97945216,
|
||||
2.43615641, 12.92143144]]),
|
||||
),
|
||||
tuple(
|
||||
2248.0760851141,
|
||||
array([[-1.71755535, -5.59925137, 8.10545419, -4.03306318, -1.81098441,
|
||||
2.77407111, 32.28020575]]),
|
||||
),
|
||||
tuple(
|
||||
1663.3101472167,
|
||||
array([[-5.16785855, 2.7558756 , 8.10545419, -3.34620897, -1.74763642,
|
||||
2.42770463, 52.98214008]]),
|
||||
),
|
||||
tuple(
|
||||
1329.2703365134,
|
||||
array([[ -1.39600464, 9.69718343, -2.00394725, -2.59147366,
|
||||
-1.91246681, 2.07361175, 123.01833742]]),
|
||||
),
|
||||
tuple(
|
||||
355.7695549121,
|
||||
array([[ 9.76047401, 0.84696075, -2.00394725, -3.04310053,
|
||||
-1.99338573, 2.1185589 , 271.35743739]]),
|
||||
),
|
||||
])
|
||||
# ---
|
@ -0,0 +1,55 @@
|
||||
# serializer version: 1
|
||||
# name: test_log_spaced_fixed_orientation_mcmc_basic
|
||||
list([
|
||||
tuple(
|
||||
50.5632126772,
|
||||
array([[ 0. , 0. , 10. , -2.3960853 , 4.23246234,
|
||||
2.26169242, 39.39900844]]),
|
||||
),
|
||||
tuple(
|
||||
50.5632126772,
|
||||
array([[ 0. , 0. , 10. , -2.3960853 , 4.23246234,
|
||||
2.26169242, 39.39900844]]),
|
||||
),
|
||||
tuple(
|
||||
47.4038652151,
|
||||
array([[ 0. , 0. , 10. , -2.03666518, 4.14084039,
|
||||
2.21309317, 47.82371559]]),
|
||||
),
|
||||
tuple(
|
||||
47.4038652151,
|
||||
array([[ 0. , 0. , 10. , -2.03666518, 4.14084039,
|
||||
2.21309317, 47.82371559]]),
|
||||
),
|
||||
tuple(
|
||||
47.4038652151,
|
||||
array([[ 0. , 0. , 10. , -2.03666518, 4.14084039,
|
||||
2.21309317, 47.82371559]]),
|
||||
),
|
||||
tuple(
|
||||
47.4038652151,
|
||||
array([[ 0. , 0. , 10. , -2.03666518, 4.14084039,
|
||||
2.21309317, 47.82371559]]),
|
||||
),
|
||||
tuple(
|
||||
22.9304785991,
|
||||
array([[ 0. , 0. , 10. , -1.63019717, 3.97041764,
|
||||
2.53115835, 38.2051999 ]]),
|
||||
),
|
||||
tuple(
|
||||
28.8090658953,
|
||||
array([[ 0. , 0. , 10. , -1.14570315, 4.07709911,
|
||||
2.48697441, 49.58615195]]),
|
||||
),
|
||||
tuple(
|
||||
28.8090658953,
|
||||
array([[ 0. , 0. , 10. , -1.14570315, 4.07709911,
|
||||
2.48697441, 49.58615195]]),
|
||||
),
|
||||
tuple(
|
||||
40.9699102596,
|
||||
array([[ 0. , 0. , 10. , -0.50178755, 3.83878089,
|
||||
2.93560796, 82.07827571]]),
|
||||
),
|
||||
])
|
||||
# ---
|
@ -0,0 +1,31 @@
|
||||
# serializer version: 1
|
||||
# name: test_random_count_multiple_dipole_fixed_or_fixed_mag_model_get_n_dipoles
|
||||
list([
|
||||
list([
|
||||
list([
|
||||
10.0,
|
||||
0.0,
|
||||
6.123233995736766e-16,
|
||||
-2.3960852996076447,
|
||||
4.232462337639554,
|
||||
2.2616924238635443,
|
||||
39.399008444891905,
|
||||
]),
|
||||
]),
|
||||
])
|
||||
# ---
|
||||
# name: test_random_count_multiple_dipole_fixed_or_fixed_mag_model_get_n_dipoles.1
|
||||
list([
|
||||
list([
|
||||
list([
|
||||
10.0,
|
||||
0.0,
|
||||
6.123233995736766e-16,
|
||||
-2.3960852996076447,
|
||||
4.232462337639554,
|
||||
2.2616924238635443,
|
||||
39.399008444891905,
|
||||
]),
|
||||
]),
|
||||
])
|
||||
# ---
|
@ -1,49 +0,0 @@
|
||||
from pdme.model import FixedDipoleModel
|
||||
from pdme.measurement import OscillatingDipole, OscillatingDipoleArrangement
|
||||
import logging
|
||||
import numpy
|
||||
import itertools
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="No idea why this is failing, but it shouldn't!")
|
||||
def test_fixed_dipole_model_solve_basic():
|
||||
# Initialise our dipole arrangement and create dot measurements along a square.
|
||||
fixed_dipole_moment = numpy.array((2, 1, 2))
|
||||
dipoles = OscillatingDipoleArrangement(
|
||||
[OscillatingDipole(fixed_dipole_moment, (1, 2, 4), 6)]
|
||||
)
|
||||
dot_inputs = list(
|
||||
itertools.chain.from_iterable(
|
||||
(
|
||||
([1, 2, 1], f),
|
||||
([1, 1, -2], f),
|
||||
([1.5, 2, 0.1], f),
|
||||
([1.5, 1, -0.2], f),
|
||||
([2, 1, 0], f),
|
||||
([2, 2, 0], f),
|
||||
([0, 2, -0.1], f),
|
||||
([0, 1, 0.04], f),
|
||||
([2, 0, 2], f),
|
||||
([1, 0, 0], f),
|
||||
)
|
||||
for f in numpy.arange(1, 10, 1)
|
||||
)
|
||||
)
|
||||
dots = dipoles.get_dot_measurements(dot_inputs)
|
||||
|
||||
model = FixedDipoleModel(-3, 3, -3, 3, 3, 5, fixed_dipole_moment, 1)
|
||||
|
||||
# from the dipole, these are the unspecified variables in ((.5, 0, 2), (1, 2, 4), 8)
|
||||
expected_solution = [1, 2, 4, 6]
|
||||
|
||||
result = model.solve(dots)
|
||||
logging.info(result)
|
||||
assert result.success
|
||||
numpy.testing.assert_allclose(
|
||||
result.normalised_x,
|
||||
expected_solution,
|
||||
err_msg="Even well specified problem solution was wrong.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
@ -1,74 +0,0 @@
|
||||
from pdme.model import FixedMagnitudeModel
|
||||
from pdme.measurement import OscillatingDipole, OscillatingDipoleArrangement
|
||||
import logging
|
||||
import numpy
|
||||
import itertools
|
||||
|
||||
|
||||
def test_fixed_magnitude_model_solve_basic():
|
||||
# Initialise our dipole arrangement and create dot measurements along a square.
|
||||
dipoles = OscillatingDipoleArrangement([OscillatingDipole((2, 0, 0), (1, 2, 4), 1)])
|
||||
dot_inputs = list(
|
||||
itertools.chain.from_iterable(
|
||||
(
|
||||
([1, 2, 0.01], f),
|
||||
([1, 1, -0.2], f),
|
||||
([1.5, 2, 0.01], f),
|
||||
([1.5, 1, -0.2], f),
|
||||
([2, 1, 0], f),
|
||||
([2, 2, 0], f),
|
||||
([0, 2, -0.1], f),
|
||||
([0, 1, 0.04], f),
|
||||
([2, 0, 0], f),
|
||||
([1, 0, 0], f),
|
||||
)
|
||||
for f in numpy.arange(1, 10, 2)
|
||||
)
|
||||
)
|
||||
dots = dipoles.get_dot_measurements(dot_inputs)
|
||||
|
||||
model = FixedMagnitudeModel(-5, 5, -5, 5, -5, 5, 2, 1)
|
||||
|
||||
# from the dipole, these are the unspecified variables in ((0, 0, 2), (1, 2, 4), 1)
|
||||
expected_solution = [numpy.pi / 2, 0, 1, 2, 4, 1]
|
||||
|
||||
result = model.solve(dots)
|
||||
logging.info(result)
|
||||
assert result.success
|
||||
numpy.testing.assert_allclose(
|
||||
result.normalised_x,
|
||||
expected_solution,
|
||||
err_msg="Even well specified problem solution was wrong.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
||||
|
||||
solved_dipoles = model.solution_as_dipoles(result.normalised_x)
|
||||
|
||||
assert len(solved_dipoles) == 1
|
||||
numpy.testing.assert_allclose(
|
||||
solved_dipoles[0].p,
|
||||
(2, 0, 0),
|
||||
err_msg="Shove it in a dipole correctly.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
solved_dipoles[0].s,
|
||||
(1, 2, 4),
|
||||
err_msg="Shove it in a dipole correctly.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
solved_dipoles[0].w,
|
||||
1,
|
||||
err_msg="Shove it in a dipole correctly.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
||||
|
||||
|
||||
def test_fixed_magnitude_model_repr():
|
||||
model = FixedMagnitudeModel(-5, 5, -5, 5, -5, 5, 2, 1)
|
||||
assert repr(model) == "FixedMagnitudeModel(-5, 5, -5, 5, -5, 5, 2, 1)"
|
@ -1,54 +0,0 @@
|
||||
from pdme.model import FixedZPlaneModel
|
||||
from pdme.measurement import OscillatingDipole, OscillatingDipoleArrangement
|
||||
import logging
|
||||
import numpy
|
||||
import itertools
|
||||
import pytest
|
||||
|
||||
|
||||
def test_fixed_z_plane_model_solve_error_initial():
|
||||
|
||||
model = FixedZPlaneModel(4, -10, 10, -10, 10, 1)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
model.solve([], initial_pt=[1, 2])
|
||||
|
||||
|
||||
def test_fixed_z_plane_model_solve_basic():
|
||||
# Initialise our dipole arrangement and create dot measurements along a square.
|
||||
dipoles = OscillatingDipoleArrangement([OscillatingDipole((0, 0, 2), (1, 2, 4), 1)])
|
||||
dot_inputs = list(
|
||||
itertools.chain.from_iterable(
|
||||
(([1, 2, 0], f), ([1, 1, 0], f), ([2, 1, 0], f), ([2, 2, 0], f))
|
||||
for f in numpy.arange(1, 10, 2)
|
||||
)
|
||||
)
|
||||
dots = dipoles.get_dot_measurements(dot_inputs)
|
||||
|
||||
model = FixedZPlaneModel(4, -10, 10, -10, 10, 1)
|
||||
|
||||
# from the dipole, these are the unspecified variables in ((0, 0, pz), (sx, sy, 4), w)
|
||||
expected_solution = [2, 1, 2, 1]
|
||||
|
||||
result = model.solve(dots)
|
||||
logging.info(result)
|
||||
assert result.success
|
||||
numpy.testing.assert_allclose(
|
||||
result.x,
|
||||
expected_solution,
|
||||
err_msg="Even well specified problem solution was wrong.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
||||
|
||||
# Do it again with an initial point
|
||||
result = model.solve(dots, initial_pt=[2, 2, 2, 2])
|
||||
logging.info(result)
|
||||
assert result.success
|
||||
numpy.testing.assert_allclose(
|
||||
result.x,
|
||||
expected_solution,
|
||||
err_msg="Even well specified problem solution was wrong.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
@ -1,20 +0,0 @@
|
||||
from pdme.model.fixed_z_plane_model import FixedZPlaneModel, FixedZPlaneDiscretisation
|
||||
import numpy
|
||||
|
||||
|
||||
def test_fixed_z_plane_model_discretization():
|
||||
model = FixedZPlaneModel(4, -10, 10, -10, 10, 1)
|
||||
discretisation = FixedZPlaneDiscretisation(model, 1, 2, 5, 15)
|
||||
# x: (-10, 0) and (0, 10)
|
||||
# y: (-10, -6, -2, 2, 6, 10)
|
||||
assert discretisation.cell_count == 10
|
||||
assert discretisation.pz_step == 30
|
||||
assert discretisation.x_step == 10
|
||||
assert discretisation.y_step == 4
|
||||
numpy.testing.assert_allclose(
|
||||
discretisation.bounds((0, 0, 0)),
|
||||
((-15, -10, -10, -numpy.inf), (15, 0, -6, numpy.inf)),
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
list(discretisation.all_indices()), list(numpy.ndindex((1, 2, 5)))
|
||||
)
|
@ -1,46 +0,0 @@
|
||||
from pdme.model.fixed_z_plane_model import FixedZPlaneModel
|
||||
from pdme.measurement import DotMeasurement
|
||||
import logging
|
||||
import numpy
|
||||
|
||||
|
||||
def test_fixed_z_plane_model_repr():
|
||||
model = FixedZPlaneModel(1, 2, 3, 4, 5, 6)
|
||||
assert repr(model) == "FixedZPlaneModel(1, 2, 3, 4, 5, 6)"
|
||||
|
||||
|
||||
def test_fixed_z_plane_model_cost_and_jac_single():
|
||||
model = FixedZPlaneModel(4, -10, 10, -10, 10, 1)
|
||||
measured_v = 0.000191292 # from dipole with p=(0, 0, 2) at (1, 2, 4) with w = 1
|
||||
dot = DotMeasurement(measured_v, (1, 2, 0), 5)
|
||||
pt = [2, 2, 2, 2]
|
||||
|
||||
cost_function = model.costs([dot])
|
||||
|
||||
expected_cost = [0.0000946746]
|
||||
actual_cost = cost_function(pt)
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
actual_cost,
|
||||
expected_cost,
|
||||
err_msg="Cost wasn't as expected.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
||||
|
||||
jac_function = model.jac([dot])
|
||||
|
||||
expected_jac = [
|
||||
[0.0002859666151836802, -0.0001009293935942401, 0, 0.0001035396365320221]
|
||||
]
|
||||
actual_jac = jac_function(pt)
|
||||
|
||||
logging.warning(actual_jac)
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
actual_jac,
|
||||
expected_jac,
|
||||
err_msg="Jac wasn't as expected.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
@ -0,0 +1,100 @@
|
||||
from pdme.model import (
|
||||
LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel,
|
||||
)
|
||||
import pdme.inputs
|
||||
import pdme.measurement.input_types
|
||||
import pdme.subspace_simulation
|
||||
import numpy
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
SEED_TO_USE = 42
|
||||
|
||||
|
||||
def get_cost_function():
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel(
|
||||
x_min,
|
||||
x_max,
|
||||
y_min,
|
||||
y_max,
|
||||
z_min,
|
||||
z_max,
|
||||
0,
|
||||
max_frequency,
|
||||
p_fixed,
|
||||
1,
|
||||
0.5,
|
||||
)
|
||||
model.rng = numpy.random.default_rng(SEED_TO_USE)
|
||||
|
||||
freqs = [0.01, 0.1, 1, 10, 100]
|
||||
dot_positions = [[-1.5, 0, 0], [-0.5, 0, 0], [0.5, 0, 0], [1.5, 0, 0]]
|
||||
dot_inputs = pdme.inputs.inputs_with_frequency_range(dot_positions, freqs)
|
||||
dot_input_array = pdme.measurement.input_types.dot_inputs_to_array(dot_inputs)
|
||||
|
||||
actual_dipoles = model.get_dipoles(0, numpy.random.default_rng(SEED_TO_USE))
|
||||
actual_measurements = actual_dipoles.get_potential_dot_measurements(dot_inputs)
|
||||
actual_measurements_array = numpy.array([m.v for m in actual_measurements])
|
||||
|
||||
def cost_to_use(sample_dipoleses: numpy.ndarray) -> numpy.ndarray:
|
||||
return pdme.subspace_simulation.proportional_costs_vs_actual_measurement(
|
||||
dot_input_array, actual_measurements_array, sample_dipoleses
|
||||
)
|
||||
|
||||
return cost_to_use
|
||||
|
||||
|
||||
def test_log_spaced_fixedxy_orientation_mcmc_basic(snapshot):
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel(
|
||||
x_min,
|
||||
x_max,
|
||||
y_min,
|
||||
y_max,
|
||||
z_min,
|
||||
z_max,
|
||||
0,
|
||||
max_frequency,
|
||||
p_fixed,
|
||||
1,
|
||||
0.5,
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
seed = model.get_monte_carlo_dipole_inputs(1, -1)
|
||||
|
||||
cost_function = get_cost_function()
|
||||
stdev = pdme.subspace_simulation.DipoleStandardDeviation(2, 2, 1, 0.25, 0.5, 1)
|
||||
stdevs = pdme.subspace_simulation.MCMCStandardDeviation([stdev])
|
||||
|
||||
chain = model.get_mcmc_chain(
|
||||
seed[0],
|
||||
cost_function,
|
||||
10,
|
||||
cost_function(seed)[0],
|
||||
stdevs,
|
||||
rng_arg=numpy.random.default_rng(1515),
|
||||
)
|
||||
|
||||
chain_rounded = [(round(cost, 10), dipoles) for (cost, dipoles) in chain]
|
||||
|
||||
assert chain_rounded == snapshot
|
@ -0,0 +1,100 @@
|
||||
from pdme.model import (
|
||||
LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel,
|
||||
)
|
||||
import pdme.inputs
|
||||
import pdme.measurement.input_types
|
||||
import pdme.subspace_simulation
|
||||
import numpy
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
SEED_TO_USE = 42
|
||||
|
||||
|
||||
def get_cost_function():
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
x_min,
|
||||
x_max,
|
||||
y_min,
|
||||
y_max,
|
||||
z_min,
|
||||
z_max,
|
||||
0,
|
||||
max_frequency,
|
||||
p_fixed,
|
||||
1,
|
||||
0.5,
|
||||
)
|
||||
model.rng = numpy.random.default_rng(SEED_TO_USE)
|
||||
|
||||
freqs = [0.01, 0.1, 1, 10, 100]
|
||||
dot_positions = [[-1.5, 0, 0], [-0.5, 0, 0], [0.5, 0, 0], [1.5, 0, 0]]
|
||||
dot_inputs = pdme.inputs.inputs_with_frequency_range(dot_positions, freqs)
|
||||
dot_input_array = pdme.measurement.input_types.dot_inputs_to_array(dot_inputs)
|
||||
|
||||
actual_dipoles = model.get_dipoles(0, numpy.random.default_rng(SEED_TO_USE))
|
||||
actual_measurements = actual_dipoles.get_potential_dot_measurements(dot_inputs)
|
||||
actual_measurements_array = numpy.array([m.v for m in actual_measurements])
|
||||
|
||||
def cost_to_use(sample_dipoleses: numpy.ndarray) -> numpy.ndarray:
|
||||
return pdme.subspace_simulation.proportional_costs_vs_actual_measurement(
|
||||
dot_input_array, actual_measurements_array, sample_dipoleses
|
||||
)
|
||||
|
||||
return cost_to_use
|
||||
|
||||
|
||||
def test_log_spaced_free_orientation_mcmc_basic(snapshot):
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
x_min,
|
||||
x_max,
|
||||
y_min,
|
||||
y_max,
|
||||
z_min,
|
||||
z_max,
|
||||
0,
|
||||
max_frequency,
|
||||
p_fixed,
|
||||
1,
|
||||
0.5,
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
seed = model.get_monte_carlo_dipole_inputs(1, -1)
|
||||
|
||||
cost_function = get_cost_function()
|
||||
stdev = pdme.subspace_simulation.DipoleStandardDeviation(2, 2, 1, 0.25, 0.5, 1)
|
||||
stdevs = pdme.subspace_simulation.MCMCStandardDeviation([stdev])
|
||||
|
||||
chain = model.get_mcmc_chain(
|
||||
seed[0],
|
||||
cost_function,
|
||||
10,
|
||||
cost_function(seed)[0],
|
||||
stdevs,
|
||||
rng_arg=numpy.random.default_rng(1515),
|
||||
)
|
||||
|
||||
chain_rounded = [(round(cost, 10), dipoles) for (cost, dipoles) in chain]
|
||||
|
||||
assert chain_rounded == snapshot
|
108
tests/model/test_log_spaced_fixed_orientation_mcmc.py
Normal file
108
tests/model/test_log_spaced_fixed_orientation_mcmc.py
Normal file
@ -0,0 +1,108 @@
|
||||
from pdme.model import (
|
||||
LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel,
|
||||
)
|
||||
import pdme.inputs
|
||||
import pdme.measurement.input_types
|
||||
import pdme.subspace_simulation
|
||||
import numpy
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
SEED_TO_USE = 42
|
||||
|
||||
|
||||
def get_cost_function():
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
theta = 0
|
||||
phi = 0
|
||||
max_frequency = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel(
|
||||
x_min,
|
||||
x_max,
|
||||
y_min,
|
||||
y_max,
|
||||
z_min,
|
||||
z_max,
|
||||
0,
|
||||
max_frequency,
|
||||
p_fixed,
|
||||
theta,
|
||||
phi,
|
||||
1,
|
||||
0.5,
|
||||
)
|
||||
model.rng = numpy.random.default_rng(SEED_TO_USE)
|
||||
|
||||
freqs = [0.01, 0.1, 1, 10, 100]
|
||||
dot_positions = [[-1.5, 0, 0], [-0.5, 0, 0], [0.5, 0, 0], [1.5, 0, 0]]
|
||||
dot_inputs = pdme.inputs.inputs_with_frequency_range(dot_positions, freqs)
|
||||
dot_input_array = pdme.measurement.input_types.dot_inputs_to_array(dot_inputs)
|
||||
|
||||
actual_dipoles = model.get_dipoles(0, numpy.random.default_rng(SEED_TO_USE))
|
||||
actual_measurements = actual_dipoles.get_potential_dot_measurements(dot_inputs)
|
||||
actual_measurements_array = numpy.array([m.v for m in actual_measurements])
|
||||
|
||||
def cost_to_use(sample_dipoleses: numpy.ndarray) -> numpy.ndarray:
|
||||
return pdme.subspace_simulation.proportional_costs_vs_actual_measurement(
|
||||
dot_input_array, actual_measurements_array, sample_dipoleses
|
||||
)
|
||||
|
||||
return cost_to_use
|
||||
|
||||
|
||||
def test_log_spaced_fixed_orientation_mcmc_basic(snapshot):
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
theta = 0
|
||||
phi = 0
|
||||
max_frequency = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel(
|
||||
x_min,
|
||||
x_max,
|
||||
y_min,
|
||||
y_max,
|
||||
z_min,
|
||||
z_max,
|
||||
0,
|
||||
max_frequency,
|
||||
p_fixed,
|
||||
theta,
|
||||
phi,
|
||||
1,
|
||||
0.5,
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
seed = model.get_monte_carlo_dipole_inputs(1, -1)
|
||||
|
||||
cost_function = get_cost_function()
|
||||
stdev = pdme.subspace_simulation.DipoleStandardDeviation(2, 2, 1, 0.25, 0.5, 1)
|
||||
stdevs = pdme.subspace_simulation.MCMCStandardDeviation([stdev])
|
||||
|
||||
chain = model.get_mcmc_chain(
|
||||
seed[0],
|
||||
cost_function,
|
||||
10,
|
||||
cost_function(seed)[0],
|
||||
stdevs,
|
||||
rng_arg=numpy.random.default_rng(1515),
|
||||
)
|
||||
|
||||
chain_rounded = [(round(cost, 10), dipoles) for (cost, dipoles) in chain]
|
||||
|
||||
assert chain_rounded == snapshot
|
@ -0,0 +1,229 @@
|
||||
from pdme.model import LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel
|
||||
import numpy
|
||||
import logging
|
||||
import pytest
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_wrong_probability():
|
||||
with pytest.raises(ValueError):
|
||||
LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
-10, 10, -5, 5, 2, 3, 1, 2, 10, 5, 2
|
||||
)
|
||||
|
||||
|
||||
def test_repr_random_count_multiple_dipole_fixed_mag():
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
-10, 10, -5, 5, 2, 3, 1, 2, 10, 5, 0.5
|
||||
)
|
||||
assert (
|
||||
repr(model)
|
||||
== "LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel(-10, 10, -5, 5, 2, 3, 1, 2, 10, 5, 0.5)"
|
||||
), "Repr should be what I want."
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_dipoles():
|
||||
|
||||
p_fixed = 10
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
-10, 10, -5, 5, 2, 3, 0, 5, p_fixed, 1, 0.5
|
||||
)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(5, numpy.random.default_rng(1234))
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
expected_p = numpy.array([8.60141814, -4.50270821, -2.3960853])
|
||||
expected_s = numpy.array([-4.76615152, -1.80902942, 2.11809123])
|
||||
expected_w = 10**1.2088314662639255
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].p,
|
||||
expected_p,
|
||||
err_msg="Random multiple dipole p wasn't as expected",
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].s,
|
||||
expected_s,
|
||||
err_msg="Random multiple dipole s wasn't as expected",
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].w, expected_w, err_msg="Random multiple dipole w wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
numpy.linalg.norm(dipoles[0].p),
|
||||
p_fixed,
|
||||
err_msg="Should have had the expected dipole moment magnitude.",
|
||||
)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_dipoles_multiple():
|
||||
|
||||
p_fixed = 10
|
||||
dipole_count = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
-10, 10, -5, 5, 2, 3, 0, 5, p_fixed, dipole_count, 0.5
|
||||
)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(20, numpy.random.default_rng(1234))
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert (
|
||||
len(dipoles) == dipole_count
|
||||
), "Should have had multiple dipole based on count generated."
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_dipoles_invariant():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, 0, max_frequency, p_fixed, 1, 0.5
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(5)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
expected_p = numpy.array([8.60141814, -4.50270821, -2.3960853])
|
||||
expected_s = numpy.array([-4.76615152, -1.80902942, 2.11809123])
|
||||
expected_w = 10**1.2088314662639255
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].p,
|
||||
expected_p,
|
||||
err_msg="Random multiple dipole p wasn't as expected",
|
||||
rtol=1e-06,
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].s, expected_s, err_msg="Random multiple dipole s wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].w, expected_w, err_msg="Random multiple dipole w wasn't as expected"
|
||||
)
|
||||
for i in range(10):
|
||||
dipole_arrangement = model.get_dipoles(max_frequency)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) in (
|
||||
0,
|
||||
1,
|
||||
), "Should have either zero or one dipole generated."
|
||||
|
||||
if len(dipoles) > 0:
|
||||
min_s = numpy.array([x_min, y_min, z_min])
|
||||
max_s = numpy.array([x_max, y_max, z_max])
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
numpy.logical_and(min_s < dipoles[0].s, max_s > dipoles[0].s),
|
||||
True,
|
||||
f"Dipole location [{dipoles[0].s}] should have been between min [{min_s}] and max [{max_s}] bounds.",
|
||||
)
|
||||
assert (
|
||||
dipoles[0].w < 10 ** max_frequency and dipoles[0].w > 10**0
|
||||
), "Dipole frequency should have been between 0 and max."
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
numpy.linalg.norm(dipoles[0].p),
|
||||
p_fixed,
|
||||
err_msg="Should have had the expected dipole moment magnitude.",
|
||||
)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_n_dipoles():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, 0, max_frequency, p_fixed, 1, 0.5
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
dipole_array = model.get_monte_carlo_dipole_inputs(1, max_frequency)
|
||||
expected_dipole_array = numpy.array(
|
||||
[
|
||||
[
|
||||
[
|
||||
9.60483896,
|
||||
-1.41627817,
|
||||
-2.3960853,
|
||||
-4.76615152,
|
||||
-1.80902942,
|
||||
2.11809123,
|
||||
10**1.2088314662639255,
|
||||
]
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipole_array,
|
||||
expected_dipole_array,
|
||||
err_msg="Should have had the expected output dipole array.",
|
||||
rtol=1e-6,
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
model.get_monte_carlo_dipole_inputs(
|
||||
1, max_frequency, numpy.random.default_rng(1234)
|
||||
),
|
||||
expected_dipole_array,
|
||||
err_msg="Should have had the expected output dipole array, even with explicitly passed rng.",
|
||||
)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_shape():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
num_dipoles = 13
|
||||
monte_carlo_n = 11
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
x_min,
|
||||
x_max,
|
||||
y_min,
|
||||
y_max,
|
||||
z_min,
|
||||
z_max,
|
||||
0,
|
||||
max_frequency,
|
||||
p_fixed,
|
||||
num_dipoles,
|
||||
0.5,
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
actual_shape = model.get_monte_carlo_dipole_inputs(
|
||||
monte_carlo_n, max_frequency
|
||||
).shape
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
actual_shape,
|
||||
(monte_carlo_n, num_dipoles, 7),
|
||||
err_msg="shape was wrong for monte carlo outputs",
|
||||
)
|
@ -0,0 +1,206 @@
|
||||
from pdme.model import LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel
|
||||
import numpy
|
||||
import logging
|
||||
import pytest
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_xy_wrong_probability():
|
||||
with pytest.raises(ValueError):
|
||||
LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel(
|
||||
-10, 10, -5, 5, 2, 3, 1, 2, 10, 5, 2
|
||||
)
|
||||
|
||||
|
||||
def test_repr_random_count_multiple_dipole_fixed_mag_xy():
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel(
|
||||
-10, 10, -5, 5, 2, 3, 1, 2, 10, 5, 0.5
|
||||
)
|
||||
assert (
|
||||
repr(model)
|
||||
== "LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel(-10, 10, -5, 5, 2, 3, 1, 2, 10, 5, 0.5)"
|
||||
), "Repr should be what I want."
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_dipoles_multiple_xy():
|
||||
|
||||
p_fixed = 10
|
||||
dipole_count = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel(
|
||||
-10, 10, -5, 5, 2, 3, 0, 5, p_fixed, dipole_count, 0.5
|
||||
)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(20, numpy.random.default_rng(1234))
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert (
|
||||
len(dipoles) == dipole_count
|
||||
), "Should have had multiple dipole based on count generated."
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_dipoles_invariant_xy():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, 0, max_frequency, p_fixed, 1, 0.5
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(5)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
for i in range(10):
|
||||
dipole_arrangement = model.get_dipoles(max_frequency)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) in (
|
||||
0,
|
||||
1,
|
||||
), "Should have either zero or one dipole generated."
|
||||
|
||||
if len(dipoles) > 0:
|
||||
min_s = numpy.array([x_min, y_min, z_min])
|
||||
max_s = numpy.array([x_max, y_max, z_max])
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
numpy.logical_and(min_s < dipoles[0].s, max_s > dipoles[0].s),
|
||||
True,
|
||||
f"Dipole location [{dipoles[0].s}] should have been between min [{min_s}] and max [{max_s}] bounds.",
|
||||
)
|
||||
assert (
|
||||
dipoles[0].w < 10 ** max_frequency and dipoles[0].w > 10**0
|
||||
), "Dipole frequency should have been between 0 and max."
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
numpy.linalg.norm(dipoles[0].p),
|
||||
p_fixed,
|
||||
err_msg="Should have had the expected dipole moment magnitude.",
|
||||
)
|
||||
|
||||
_logger.warning(dipoles[0].p)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].p[2],
|
||||
0,
|
||||
err_msg="Should have had zero z magnitude.",
|
||||
)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_dipoles_invariant_monte_carlo_xy():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
monte_carlo_n = 20
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, 0, max_frequency, p_fixed, 1, 0.5
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(5)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
for i in range(10):
|
||||
dipoles = model.get_monte_carlo_dipole_inputs(monte_carlo_n, max_frequency)
|
||||
|
||||
min_s = numpy.array([x_min, y_min, z_min])
|
||||
max_s = numpy.array([x_max, y_max, z_max])
|
||||
|
||||
_logger.warning(dipoles)
|
||||
_logger.warning(dipoles[:, 0, 0:3])
|
||||
_logger.warning(dipoles[:, 0, 3:6])
|
||||
_logger.warning(dipoles[:, 0, 6])
|
||||
|
||||
ps = dipoles[:, 0, 0:3]
|
||||
ss = dipoles[:, 0, 3:6]
|
||||
ws = dipoles[:, 0, 6]
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
numpy.logical_and(min_s < ss, max_s > ss).all(),
|
||||
True,
|
||||
f"Dipole location [{ss}] should have been between min [{min_s}] and max [{max_s}] bounds.",
|
||||
)
|
||||
assert (ws < 10**max_frequency).all() and (
|
||||
ws > 10**0
|
||||
).all(), "Dipole frequency should have been between 0 and max."
|
||||
|
||||
norms = numpy.linalg.norm(ps, axis=1)
|
||||
filtered_norms = norms[norms > 0]
|
||||
numpy.testing.assert_allclose(
|
||||
filtered_norms,
|
||||
p_fixed,
|
||||
err_msg="Should have had the expected dipole moment magnitude.",
|
||||
)
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
ps[:, 2],
|
||||
0,
|
||||
err_msg="Should have had zero z magnitude.",
|
||||
)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_shape():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
num_dipoles = 13
|
||||
monte_carlo_n = 11
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeXYModel(
|
||||
x_min,
|
||||
x_max,
|
||||
y_min,
|
||||
y_max,
|
||||
z_min,
|
||||
z_max,
|
||||
0,
|
||||
max_frequency,
|
||||
p_fixed,
|
||||
num_dipoles,
|
||||
0.5,
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
actual_shape = model.get_monte_carlo_dipole_inputs(
|
||||
monte_carlo_n, max_frequency
|
||||
).shape
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
actual_shape,
|
||||
(monte_carlo_n, num_dipoles, 7),
|
||||
err_msg="shape was wrong for monte carlo outputs",
|
||||
)
|
||||
|
||||
actual_shape = model.get_monte_carlo_dipole_inputs(
|
||||
monte_carlo_n, max_frequency, rng_to_use=numpy.random.default_rng(1515)
|
||||
).shape
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
actual_shape,
|
||||
(monte_carlo_n, num_dipoles, 7),
|
||||
err_msg="shape was wrong for monte carlo outputs",
|
||||
)
|
@ -0,0 +1,152 @@
|
||||
from pdme.model import (
|
||||
LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel,
|
||||
)
|
||||
|
||||
import numpy
|
||||
import logging
|
||||
import pytest
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_random_count_fixedorientation_multiple_dipole_wrong_probability():
|
||||
with pytest.raises(ValueError):
|
||||
LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel(
|
||||
-10, 10, -5, 5, 2, 3, 1, 2, 10, 0, 0, 5, 2
|
||||
)
|
||||
|
||||
|
||||
def test_repr_random_count_multiple_dipole_fixed_orientation_mag():
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel(
|
||||
-10, 10, -5, 5, 2, 3, 1, 2, 10, 0, 1, 5, 0.5
|
||||
)
|
||||
assert (
|
||||
repr(model)
|
||||
== "LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel(-10, 10, -5, 5, 2, 3, 1, 2, 10, 0, 1, 5, 0.5)"
|
||||
), "Repr should be same as instantiation."
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_dipoles_invariant():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
theta = 0
|
||||
phi = 0
|
||||
max_frequency = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel(
|
||||
x_min,
|
||||
x_max,
|
||||
y_min,
|
||||
y_max,
|
||||
z_min,
|
||||
z_max,
|
||||
0,
|
||||
max_frequency,
|
||||
p_fixed,
|
||||
theta,
|
||||
phi,
|
||||
1,
|
||||
0.5,
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
for i in range(10):
|
||||
dipole_arrangement = model.get_dipoles(max_frequency)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) in (
|
||||
0,
|
||||
1,
|
||||
), "Should have either zero or one dipole generated."
|
||||
|
||||
if len(dipoles) > 0:
|
||||
min_s = numpy.array([x_min, y_min, z_min])
|
||||
max_s = numpy.array([x_max, y_max, z_max])
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
numpy.logical_and(min_s < dipoles[0].s, max_s > dipoles[0].s),
|
||||
True,
|
||||
f"Dipole location [{dipoles[0].s}] should have been between min [{min_s}] and max [{max_s}] bounds.",
|
||||
)
|
||||
assert (
|
||||
dipoles[0].w < 10 ** max_frequency and dipoles[0].w > 10**0
|
||||
), "Dipole frequency should have been between 0 and max."
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].p,
|
||||
numpy.array([0, 0, p_fixed]),
|
||||
err_msg="Should have had the expected dipole moment.",
|
||||
)
|
||||
|
||||
custom_rng = numpy.random.default_rng(1234)
|
||||
for i in range(10):
|
||||
dipole_arrangement = model.get_dipoles(max_frequency, custom_rng)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) in (
|
||||
0,
|
||||
1,
|
||||
), "Should have either zero or one dipole generated."
|
||||
|
||||
if len(dipoles) > 0:
|
||||
min_s = numpy.array([x_min, y_min, z_min])
|
||||
max_s = numpy.array([x_max, y_max, z_max])
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
numpy.logical_and(min_s < dipoles[0].s, max_s > dipoles[0].s),
|
||||
True,
|
||||
f"Dipole location [{dipoles[0].s}] should have been between min [{min_s}] and max [{max_s}] bounds.",
|
||||
)
|
||||
assert (
|
||||
dipoles[0].w < 10 ** max_frequency and dipoles[0].w > 10**0
|
||||
), "Dipole frequency should have been between 0 and max."
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].p,
|
||||
numpy.array([0, 0, p_fixed]),
|
||||
err_msg="Should have had the expected dipole moment.",
|
||||
)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_or_fixed_mag_model_get_n_dipoles(snapshot):
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
theta = numpy.pi / 2
|
||||
phi = 0
|
||||
max_frequency = 5
|
||||
|
||||
model = LogSpacedRandomCountMultipleDipoleFixedMagnitudeFixedOrientationModel(
|
||||
x_min,
|
||||
x_max,
|
||||
y_min,
|
||||
y_max,
|
||||
z_min,
|
||||
z_max,
|
||||
0,
|
||||
max_frequency,
|
||||
p_fixed,
|
||||
theta,
|
||||
phi,
|
||||
1,
|
||||
0.5,
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
actual_inputs = model.get_monte_carlo_dipole_inputs(1, max_frequency)
|
||||
assert actual_inputs.tolist() == snapshot
|
||||
actual_monte_carlo_inputs = model.get_monte_carlo_dipole_inputs(
|
||||
1, max_frequency, numpy.random.default_rng(1234)
|
||||
)
|
||||
assert actual_monte_carlo_inputs.tolist() == snapshot
|
@ -1,35 +1,16 @@
|
||||
from pdme.model import Model
|
||||
from pdme.measurement import DotMeasurement
|
||||
from pdme.model import DipoleModel
|
||||
import pytest
|
||||
|
||||
|
||||
def test_model_interface_not_implemented_point_length():
|
||||
model = Model()
|
||||
with pytest.raises(NotImplementedError):
|
||||
model.point_length()
|
||||
|
||||
|
||||
def test_model_interface_not_implemented_point_n():
|
||||
model = Model()
|
||||
with pytest.raises(NotImplementedError):
|
||||
model.n()
|
||||
|
||||
|
||||
def test_model_interface_not_implemented_cost():
|
||||
model = Model()
|
||||
|
||||
model.point_length = lambda: 2
|
||||
def test_model_interface_not_implemented_one_dipoles():
|
||||
model = DipoleModel()
|
||||
|
||||
with pytest.raises(NotImplementedError):
|
||||
cost = model.costs([DotMeasurement(0, [1, 2, 3], 4)])
|
||||
cost([1, 2])
|
||||
model.get_dipoles(5)
|
||||
|
||||
|
||||
def test_model_interface_not_implemented_jac():
|
||||
model = Model()
|
||||
|
||||
model.point_length = lambda: 2
|
||||
def test_model_interface_not_implemented_n_dipoles():
|
||||
model = DipoleModel()
|
||||
|
||||
with pytest.raises(NotImplementedError):
|
||||
jac = model.jac([DotMeasurement(0, [1, 2, 3], 4)])
|
||||
jac([1, 2])
|
||||
model.get_monte_carlo_dipole_inputs(5, 10)
|
||||
|
194
tests/model/test_multiple_dipole_fixed_magnitude_model.py
Normal file
194
tests/model/test_multiple_dipole_fixed_magnitude_model.py
Normal file
@ -0,0 +1,194 @@
|
||||
from pdme.model import MultipleDipoleFixedMagnitudeModel
|
||||
import numpy
|
||||
import logging
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_repr_multiple_dipole_fixed_mag():
|
||||
model = MultipleDipoleFixedMagnitudeModel(-10, 10, -5, 5, 2, 3, 10, 3.5)
|
||||
assert (
|
||||
repr(model)
|
||||
== "MultipleDipoleFixedMagnitudeModel(-10, 10, -5, 5, 2, 3, 10, 3.5)"
|
||||
), "Repr should be what I want."
|
||||
|
||||
|
||||
def test_multiple_dipole_fixed_mag_model_get_dipoles():
|
||||
|
||||
p_fixed = 10
|
||||
|
||||
model = MultipleDipoleFixedMagnitudeModel(-10, 10, -5, 5, 2, 3, p_fixed, 1)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(5, numpy.random.default_rng(1234))
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
expected_p = numpy.array([-2.20191453, 2.06264523, 9.5339953])
|
||||
expected_s = numpy.array([8.46492468, -2.38307576, 2.31909706])
|
||||
expected_w = 0.5904561648332141
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].p, expected_p, err_msg="Random multiple dipole p wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].s, expected_s, err_msg="Random multiple dipole s wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].w, expected_w, err_msg="Random multiple dipole w wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
numpy.linalg.norm(dipoles[0].p),
|
||||
p_fixed,
|
||||
err_msg="Should have had the expected dipole moment magnitude.",
|
||||
)
|
||||
|
||||
|
||||
def test_multiple_dipole_fixed_mag_model_get_dipoles_multiple():
|
||||
|
||||
p_fixed = 10
|
||||
dipole_count = 5
|
||||
|
||||
model = MultipleDipoleFixedMagnitudeModel(
|
||||
-10, 10, -5, 5, 2, 3, p_fixed, dipole_count
|
||||
)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(20, numpy.random.default_rng(1234))
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert (
|
||||
len(dipoles) == dipole_count
|
||||
), "Should have had multiple dipole based on count generated."
|
||||
|
||||
|
||||
def test_multiple_dipole_fixed_mag_model_get_dipoles_invariant():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = MultipleDipoleFixedMagnitudeModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, p_fixed, 1
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(5)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
expected_p = numpy.array([-2.20191453, 2.06264523, 9.5339953])
|
||||
expected_s = numpy.array([8.46492468, -2.38307576, 2.31909706])
|
||||
expected_w = 0.5904561648332141
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].p, expected_p, err_msg="Random multiple dipole p wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].s, expected_s, err_msg="Random multiple dipole s wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].w, expected_w, err_msg="Random multiple dipole w wasn't as expected"
|
||||
)
|
||||
for i in range(10):
|
||||
dipole_arrangement = model.get_dipoles(max_frequency)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
|
||||
min_s = numpy.array([x_min, y_min, z_min])
|
||||
max_s = numpy.array([x_max, y_max, z_max])
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
numpy.logical_and(min_s < dipoles[0].s, max_s > dipoles[0].s),
|
||||
True,
|
||||
f"Dipole location [{dipoles[0].s}] should have been between min [{min_s}] and max [{max_s}] bounds.",
|
||||
)
|
||||
assert (
|
||||
dipoles[0].w < max_frequency and dipoles[0].w > 0
|
||||
), "Dipole frequency should have been between 0 and max."
|
||||
numpy.testing.assert_allclose(
|
||||
numpy.linalg.norm(dipoles[0].p),
|
||||
p_fixed,
|
||||
err_msg="Should have had the expected dipole moment magnitude.",
|
||||
)
|
||||
|
||||
|
||||
def test_multiple_dipole_fixed_mag_model_get_n_dipoles():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = MultipleDipoleFixedMagnitudeModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, p_fixed, 1
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
dipole_array = model.get_monte_carlo_dipole_inputs(1, max_frequency)
|
||||
expected_dipole_array = numpy.array(
|
||||
[
|
||||
[
|
||||
[
|
||||
9.60483896,
|
||||
-1.41627817,
|
||||
-2.3960853,
|
||||
8.46492468,
|
||||
-2.38307576,
|
||||
2.31909706,
|
||||
1.47236493,
|
||||
]
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipole_array,
|
||||
expected_dipole_array,
|
||||
err_msg="Should have had the expected output dipole array.",
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
model.get_monte_carlo_dipole_inputs(
|
||||
1, max_frequency, numpy.random.default_rng(1234)
|
||||
),
|
||||
expected_dipole_array,
|
||||
err_msg="Should have had the expected output dipole array, even with explicitly passed rng.",
|
||||
)
|
||||
|
||||
|
||||
def test_multiple_dipole_shape():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
num_dipoles = 13
|
||||
monte_carlo_n = 11
|
||||
|
||||
model = MultipleDipoleFixedMagnitudeModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, p_fixed, num_dipoles
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
actual_shape = model.get_monte_carlo_dipole_inputs(
|
||||
monte_carlo_n, max_frequency
|
||||
).shape
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
actual_shape,
|
||||
(monte_carlo_n, num_dipoles, 7),
|
||||
err_msg="shape was wrong for monte carlo outputs",
|
||||
)
|
@ -0,0 +1,217 @@
|
||||
from pdme.model import RandomCountMultipleDipoleFixedMagnitudeModel
|
||||
import numpy
|
||||
import logging
|
||||
import pytest
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_wrong_probability():
|
||||
with pytest.raises(ValueError):
|
||||
RandomCountMultipleDipoleFixedMagnitudeModel(-10, 10, -5, 5, 2, 3, 10, 5, 2)
|
||||
|
||||
|
||||
def test_repr_random_count_multiple_dipole_fixed_mag():
|
||||
model = RandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
-10, 10, -5, 5, 2, 3, 10, 5, 0.5
|
||||
)
|
||||
assert (
|
||||
repr(model)
|
||||
== "RandomCountMultipleDipoleFixedMagnitudeModel(-10, 10, -5, 5, 2, 3, 10, 5, 0.5)"
|
||||
), "Repr should be what I want."
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_dipoles():
|
||||
|
||||
p_fixed = 10
|
||||
|
||||
model = RandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
-10, 10, -5, 5, 2, 3, p_fixed, 1, 0.5
|
||||
)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(5, numpy.random.default_rng(1234))
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
expected_p = numpy.array([8.60141814, -4.50270821, -2.3960853])
|
||||
expected_s = numpy.array([-4.76615152, -1.80902942, 2.11809123])
|
||||
expected_w = 1.2088314662639255
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].p,
|
||||
expected_p,
|
||||
err_msg="Random multiple dipole p wasn't as expected",
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].s,
|
||||
expected_s,
|
||||
err_msg="Random multiple dipole s wasn't as expected",
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].w, expected_w, err_msg="Random multiple dipole w wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
numpy.linalg.norm(dipoles[0].p),
|
||||
p_fixed,
|
||||
err_msg="Should have had the expected dipole moment magnitude.",
|
||||
)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_dipoles_multiple():
|
||||
|
||||
p_fixed = 10
|
||||
dipole_count = 5
|
||||
|
||||
model = RandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
-10, 10, -5, 5, 2, 3, p_fixed, dipole_count, 0.5
|
||||
)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(20, numpy.random.default_rng(1234))
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert (
|
||||
len(dipoles) == dipole_count
|
||||
), "Should have had multiple dipole based on count generated."
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_dipoles_invariant():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = RandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, p_fixed, 1, 0.5
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(5)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
expected_p = numpy.array([8.60141814, -4.50270821, -2.3960853])
|
||||
expected_s = numpy.array([-4.76615152, -1.80902942, 2.11809123])
|
||||
expected_w = 1.2088314662639255
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].p,
|
||||
expected_p,
|
||||
err_msg="Random multiple dipole p wasn't as expected",
|
||||
rtol=1e-06,
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].s, expected_s, err_msg="Random multiple dipole s wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].w, expected_w, err_msg="Random multiple dipole w wasn't as expected"
|
||||
)
|
||||
for i in range(10):
|
||||
dipole_arrangement = model.get_dipoles(max_frequency)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) in (
|
||||
0,
|
||||
1,
|
||||
), "Should have either zero or one dipole generated."
|
||||
|
||||
if len(dipoles) > 0:
|
||||
min_s = numpy.array([x_min, y_min, z_min])
|
||||
max_s = numpy.array([x_max, y_max, z_max])
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
numpy.logical_and(min_s < dipoles[0].s, max_s > dipoles[0].s),
|
||||
True,
|
||||
f"Dipole location [{dipoles[0].s}] should have been between min [{min_s}] and max [{max_s}] bounds.",
|
||||
)
|
||||
assert (
|
||||
dipoles[0].w < max_frequency and dipoles[0].w > 0
|
||||
), "Dipole frequency should have been between 0 and max."
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
numpy.linalg.norm(dipoles[0].p),
|
||||
p_fixed,
|
||||
err_msg="Should have had the expected dipole moment magnitude.",
|
||||
)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_fixed_mag_model_get_n_dipoles():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = RandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, p_fixed, 1, 0.5
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
dipole_array = model.get_monte_carlo_dipole_inputs(1, max_frequency)
|
||||
expected_dipole_array = numpy.array(
|
||||
[
|
||||
[
|
||||
[
|
||||
9.60483896,
|
||||
-1.41627817,
|
||||
-2.3960853,
|
||||
-4.76615152,
|
||||
-1.80902942,
|
||||
2.11809123,
|
||||
1.96706517,
|
||||
]
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipole_array,
|
||||
expected_dipole_array,
|
||||
err_msg="Should have had the expected output dipole array.",
|
||||
rtol=1e-6,
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
model.get_monte_carlo_dipole_inputs(
|
||||
1, max_frequency, numpy.random.default_rng(1234)
|
||||
),
|
||||
expected_dipole_array,
|
||||
err_msg="Should have had the expected output dipole array, even with explicitly passed rng.",
|
||||
)
|
||||
|
||||
|
||||
def test_random_count_multiple_dipole_shape():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
num_dipoles = 13
|
||||
monte_carlo_n = 11
|
||||
|
||||
model = RandomCountMultipleDipoleFixedMagnitudeModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, p_fixed, num_dipoles, 0.5
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
actual_shape = model.get_monte_carlo_dipole_inputs(
|
||||
monte_carlo_n, max_frequency
|
||||
).shape
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
actual_shape,
|
||||
(monte_carlo_n, num_dipoles, 7),
|
||||
err_msg="shape was wrong for monte carlo outputs",
|
||||
)
|
147
tests/model/test_single_dipole_fixed_magnitude_model.py
Normal file
147
tests/model/test_single_dipole_fixed_magnitude_model.py
Normal file
@ -0,0 +1,147 @@
|
||||
from pdme.model import SingleDipoleFixedMagnitudeModel
|
||||
import numpy
|
||||
import logging
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def test_repr_single_dipole_fixed_mag():
|
||||
model = SingleDipoleFixedMagnitudeModel(-10, 10, -5, 5, 2, 3, 5)
|
||||
assert (
|
||||
repr(model) == "SingleDipoleFixedMagnitudeModel(-10, 10, -5, 5, 2, 3, 5)"
|
||||
), "Repr should be what I want."
|
||||
|
||||
|
||||
def test_single_dipole_fixed_mag_model_get_dipoles():
|
||||
|
||||
p_fixed = 10
|
||||
|
||||
model = SingleDipoleFixedMagnitudeModel(-10, 10, -5, 5, 2, 3, p_fixed)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(5, numpy.random.default_rng(1234))
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
expected_p = numpy.array([-2.20191453, 2.06264523, 9.5339953])
|
||||
expected_s = numpy.array([8.46492468, -2.38307576, 2.31909706])
|
||||
expected_w = 0.5904561648332141
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].p, expected_p, err_msg="Random single dipole p wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].s, expected_s, err_msg="Random single dipole s wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].w, expected_w, err_msg="Random single dipole w wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
numpy.linalg.norm(dipoles[0].p),
|
||||
p_fixed,
|
||||
err_msg="Should have had the expected dipole moment magnitude.",
|
||||
)
|
||||
|
||||
|
||||
def test_single_dipole_fixed_mag_model_get_dipoles_invariant():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = SingleDipoleFixedMagnitudeModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, p_fixed
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
dipole_arrangement = model.get_dipoles(5)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
expected_p = numpy.array([-2.20191453, 2.06264523, 9.5339953])
|
||||
expected_s = numpy.array([8.46492468, -2.38307576, 2.31909706])
|
||||
expected_w = 0.5904561648332141
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].p, expected_p, err_msg="Random single dipole p wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].s, expected_s, err_msg="Random single dipole s wasn't as expected"
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
dipoles[0].w, expected_w, err_msg="Random single dipole w wasn't as expected"
|
||||
)
|
||||
for i in range(10):
|
||||
dipole_arrangement = model.get_dipoles(max_frequency)
|
||||
dipoles = dipole_arrangement.dipoles
|
||||
|
||||
assert len(dipoles) == 1, "Should have only had one dipole generated."
|
||||
|
||||
min_s = numpy.array([x_min, y_min, z_min])
|
||||
max_s = numpy.array([x_max, y_max, z_max])
|
||||
|
||||
numpy.testing.assert_equal(
|
||||
numpy.logical_and(min_s < dipoles[0].s, max_s > dipoles[0].s),
|
||||
True,
|
||||
f"Dipole location [{dipoles[0].s}] should have been between min [{min_s}] and max [{max_s}] bounds.",
|
||||
)
|
||||
assert (
|
||||
dipoles[0].w < max_frequency and dipoles[0].w > 0
|
||||
), "Dipole frequency should have been between 0 and max."
|
||||
numpy.testing.assert_allclose(
|
||||
numpy.linalg.norm(dipoles[0].p),
|
||||
p_fixed,
|
||||
err_msg="Should have had the expected dipole moment magnitude.",
|
||||
)
|
||||
|
||||
|
||||
def test_single_dipole_fixed_mag_model_get_n_dipoles():
|
||||
|
||||
x_min = -10
|
||||
x_max = 10
|
||||
y_min = -5
|
||||
y_max = 5
|
||||
z_min = 2
|
||||
z_max = 3
|
||||
p_fixed = 10
|
||||
max_frequency = 5
|
||||
|
||||
model = SingleDipoleFixedMagnitudeModel(
|
||||
x_min, x_max, y_min, y_max, z_min, z_max, p_fixed
|
||||
)
|
||||
model.rng = numpy.random.default_rng(1234)
|
||||
|
||||
dipole_array = model.get_monte_carlo_dipole_inputs(1, max_frequency)
|
||||
expected_dipole_array = numpy.array(
|
||||
[
|
||||
[
|
||||
[
|
||||
9.60483896,
|
||||
-1.41627817,
|
||||
-2.3960853,
|
||||
8.46492468,
|
||||
-2.38307576,
|
||||
2.31909706,
|
||||
1.47236493,
|
||||
]
|
||||
]
|
||||
]
|
||||
)
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
dipole_array,
|
||||
expected_dipole_array,
|
||||
err_msg="Should have had the expected output dipole array.",
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
model.get_monte_carlo_dipole_inputs(
|
||||
1, max_frequency, numpy.random.default_rng(1234)
|
||||
),
|
||||
expected_dipole_array,
|
||||
err_msg="Should have had the expected output dipole array, even with explicitly passed rng.",
|
||||
)
|
@ -1,46 +0,0 @@
|
||||
from pdme.model import UnrestrictedModel
|
||||
from pdme.measurement import OscillatingDipole, OscillatingDipoleArrangement
|
||||
import logging
|
||||
import numpy
|
||||
import itertools
|
||||
|
||||
|
||||
def test_unrestricted_model_solve_basic():
|
||||
# Initialise our dipole arrangement and create dot measurements along a square.
|
||||
dipoles = OscillatingDipoleArrangement(
|
||||
[OscillatingDipole((0.2, 0, 2), (1, 2, 4), 1)]
|
||||
)
|
||||
dot_inputs = list(
|
||||
itertools.chain.from_iterable(
|
||||
(
|
||||
([1, 2, 0.01], f),
|
||||
([1, 1, -0.2], f),
|
||||
([1.5, 2, 0.01], f),
|
||||
([1.5, 1, -0.2], f),
|
||||
([2, 1, 0], f),
|
||||
([2, 2, 0], f),
|
||||
([0, 2, -0.1], f),
|
||||
([0, 1, 0.04], f),
|
||||
([2, 0, 0], f),
|
||||
([1, 0, 0], f),
|
||||
)
|
||||
for f in numpy.arange(1, 10, 2)
|
||||
)
|
||||
)
|
||||
dots = dipoles.get_dot_measurements(dot_inputs)
|
||||
|
||||
model = UnrestrictedModel(1, -1, 1, -1, 1, -1, 5, 1)
|
||||
|
||||
# from the dipole, these are the unspecified variables in ((0, 0, 2), (1, 2, 4), 1)
|
||||
expected_solution = [0.2, 0, 2, 1, 2, 4, 1]
|
||||
|
||||
result = model.solve(dots)
|
||||
logging.info(result)
|
||||
assert result.success
|
||||
numpy.testing.assert_allclose(
|
||||
result.normalised_x,
|
||||
expected_solution,
|
||||
err_msg="Even well specified problem solution was wrong.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
@ -1,23 +0,0 @@
|
||||
from pdme.model.unrestricted_model import UnrestrictedModel, UnrestrictedDiscretisation
|
||||
import numpy
|
||||
|
||||
|
||||
def test_unrestricted_model_discretization():
|
||||
model = UnrestrictedModel(-10, 10, -10, 10, -10, 10, 15, 1)
|
||||
discretisation = UnrestrictedDiscretisation(model, 1, 1, 2, 2, 5, 1)
|
||||
# x: (-10, 0) and (0, 10)
|
||||
# y: (-10, -6, -2, 2, 6, 10)
|
||||
assert discretisation.cell_count == 10
|
||||
assert discretisation.px_step == 30
|
||||
assert discretisation.py_step == 30
|
||||
assert discretisation.pz_step == 15
|
||||
assert discretisation.x_step == 10
|
||||
assert discretisation.y_step == 4
|
||||
assert discretisation.z_step == 20
|
||||
numpy.testing.assert_allclose(
|
||||
discretisation.bounds((0, 0, 0, 0, 0, 0)),
|
||||
((-15, -15, -15, -10, -10, -10, -numpy.inf), (15, 15, 0, 0, -6, 10, numpy.inf)),
|
||||
)
|
||||
numpy.testing.assert_allclose(
|
||||
list(discretisation.all_indices()), list(numpy.ndindex((1, 1, 2, 2, 5, 1)))
|
||||
)
|
@ -1,54 +0,0 @@
|
||||
from pdme.model import UnrestrictedModel
|
||||
from pdme.measurement import DotMeasurement
|
||||
import logging
|
||||
import numpy
|
||||
|
||||
|
||||
def test_unrestricted_plane_model_repr():
|
||||
model = UnrestrictedModel(1, 2, 3, 4, 5, 6, 7, 6)
|
||||
assert repr(model) == "UnrestrictedModel(1, 2, 3, 4, 5, 6, 7, 6)"
|
||||
|
||||
|
||||
def test_unrestricted_model_cost_and_jac_single():
|
||||
model = UnrestrictedModel(1, -1, 1, -1, 1, -1, 1, 1)
|
||||
measured_v = 0.000191292 # from dipole with p=(0, 0, 2) at (1, 2, 4) with w = 1
|
||||
dot = DotMeasurement(measured_v, (1, 2, 0), 5)
|
||||
pt = numpy.array([0, 0, 2, 2, 2, 4, 2])
|
||||
|
||||
cost_function = model.costs([dot])
|
||||
|
||||
expected_cost = [0.0000946746]
|
||||
actual_cost = cost_function(pt)
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
actual_cost,
|
||||
expected_cost,
|
||||
err_msg="Cost wasn't as expected.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
||||
|
||||
jac_function = model.jac([dot])
|
||||
|
||||
expected_jac = [
|
||||
[
|
||||
0.00007149165379592005,
|
||||
0,
|
||||
0.0002859666151836802,
|
||||
-0.0001009293935942401,
|
||||
0,
|
||||
-0.0002607342667851202,
|
||||
0.0001035396365320221,
|
||||
]
|
||||
]
|
||||
actual_jac = jac_function(pt)
|
||||
|
||||
logging.warning(actual_jac)
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
actual_jac,
|
||||
expected_jac,
|
||||
err_msg="Jac wasn't as expected.",
|
||||
rtol=1e-6,
|
||||
atol=1e-11,
|
||||
)
|
4
tests/subspace_simulation/__snapshots__/test_costs.ambr
Normal file
4
tests/subspace_simulation/__snapshots__/test_costs.ambr
Normal file
@ -0,0 +1,4 @@
|
||||
# serializer version: 1
|
||||
# name: test_proportional_costs
|
||||
7000.0
|
||||
# ---
|
@ -0,0 +1,94 @@
|
||||
# serializer version: 1
|
||||
# name: test_sort_dipoles_by_freq
|
||||
list([
|
||||
list([
|
||||
100.0,
|
||||
200.0,
|
||||
300.0,
|
||||
400.0,
|
||||
500.0,
|
||||
600.0,
|
||||
0.07,
|
||||
]),
|
||||
list([
|
||||
1.0,
|
||||
2.0,
|
||||
3.0,
|
||||
4.0,
|
||||
5.0,
|
||||
6.0,
|
||||
7.0,
|
||||
]),
|
||||
list([
|
||||
10.0,
|
||||
200.0,
|
||||
30.0,
|
||||
41.0,
|
||||
315.0,
|
||||
0.31,
|
||||
100.0,
|
||||
]),
|
||||
])
|
||||
# ---
|
||||
# name: test_sort_dipoleses_by_freq
|
||||
list([
|
||||
list([
|
||||
list([
|
||||
100.0,
|
||||
200.0,
|
||||
300.0,
|
||||
400.0,
|
||||
500.0,
|
||||
600.0,
|
||||
0.07,
|
||||
]),
|
||||
list([
|
||||
1.0,
|
||||
2.0,
|
||||
3.0,
|
||||
4.0,
|
||||
5.0,
|
||||
6.0,
|
||||
7.0,
|
||||
]),
|
||||
list([
|
||||
10.0,
|
||||
200.0,
|
||||
30.0,
|
||||
41.0,
|
||||
315.0,
|
||||
0.31,
|
||||
100.0,
|
||||
]),
|
||||
]),
|
||||
list([
|
||||
list([
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
1.0,
|
||||
100.0,
|
||||
]),
|
||||
list([
|
||||
22.0,
|
||||
22.2,
|
||||
2.2,
|
||||
222.0,
|
||||
22.0,
|
||||
2.0,
|
||||
200.0,
|
||||
]),
|
||||
list([
|
||||
33.0,
|
||||
33.3,
|
||||
33.0,
|
||||
3.3,
|
||||
0.33,
|
||||
0.3,
|
||||
300.0,
|
||||
]),
|
||||
]),
|
||||
])
|
||||
# ---
|
22
tests/subspace_simulation/__snapshots__/test_stdevs.ambr
Normal file
22
tests/subspace_simulation/__snapshots__/test_stdevs.ambr
Normal file
@ -0,0 +1,22 @@
|
||||
# serializer version: 1
|
||||
# name: test_return_four
|
||||
DipoleStandardDeviation(p_phi_step=1, p_theta_step=2, rx_step=3, ry_step=4, rz_step=5, w_log_step=6)
|
||||
# ---
|
||||
# name: test_return_four.1
|
||||
DipoleStandardDeviation(p_phi_step=10, p_theta_step=20, rx_step=30, ry_step=40, rz_step=50, w_log_step=60)
|
||||
# ---
|
||||
# name: test_return_four.2
|
||||
DipoleStandardDeviation(p_phi_step=0.1, p_theta_step=0.2, rx_step=0.3, ry_step=0.4, rz_step=0.5, w_log_step=0.6)
|
||||
# ---
|
||||
# name: test_return_four.3
|
||||
DipoleStandardDeviation(p_phi_step=1, p_theta_step=2, rx_step=3, ry_step=4, rz_step=5, w_log_step=6)
|
||||
# ---
|
||||
# name: test_return_four.4
|
||||
DipoleStandardDeviation(p_phi_step=10, p_theta_step=20, rx_step=30, ry_step=40, rz_step=50, w_log_step=60)
|
||||
# ---
|
||||
# name: test_return_four.5
|
||||
DipoleStandardDeviation(p_phi_step=0.1, p_theta_step=0.2, rx_step=0.3, ry_step=0.4, rz_step=0.5, w_log_step=0.6)
|
||||
# ---
|
||||
# name: test_return_one
|
||||
DipoleStandardDeviation(p_phi_step=1, p_theta_step=2, rx_step=3, ry_step=4, rz_step=5, w_log_step=6)
|
||||
# ---
|
31
tests/subspace_simulation/test_costs.py
Normal file
31
tests/subspace_simulation/test_costs.py
Normal file
@ -0,0 +1,31 @@
|
||||
import pdme.subspace_simulation
|
||||
import pdme.subspace_simulation.mcmc_costs
|
||||
import numpy
|
||||
|
||||
|
||||
def test_proportional_costs(snapshot):
|
||||
a = numpy.array([2, 4, 5, 6, 7, 8, 10])
|
||||
b = numpy.array([51, 13, 1, 31, 0.001, 3, 1])
|
||||
|
||||
actual_result = pdme.subspace_simulation.proportional_cost(a, b).tolist()
|
||||
assert actual_result == snapshot
|
||||
|
||||
|
||||
def test_squared_costs_manual():
|
||||
target = numpy.array([100, 400, 900])
|
||||
approx1 = numpy.array([0, 400, 800])
|
||||
approx2 = numpy.array([200, 400, 600])
|
||||
|
||||
expected1 = 1.0123456790123457
|
||||
expected2 = 1.1111111111111111
|
||||
|
||||
actual1 = pdme.subspace_simulation.mcmc_costs.relative_square_diffs(approx1, target)
|
||||
assert actual1 == expected1
|
||||
|
||||
actual2 = pdme.subspace_simulation.mcmc_costs.relative_square_diffs(approx2, target)
|
||||
assert actual2 == expected2
|
||||
|
||||
combined_actual = pdme.subspace_simulation.mcmc_costs.relative_square_diffs(
|
||||
numpy.array([approx1, approx2]), target
|
||||
)
|
||||
numpy.testing.assert_allclose(combined_actual, [expected1, expected2], rtol=1e-14)
|
40
tests/subspace_simulation/test_sort_dipoles.py
Normal file
40
tests/subspace_simulation/test_sort_dipoles.py
Normal file
@ -0,0 +1,40 @@
|
||||
import numpy
|
||||
import pdme.subspace_simulation
|
||||
|
||||
|
||||
def test_sort_dipoles_by_freq(snapshot):
|
||||
orig = numpy.array(
|
||||
[
|
||||
[1, 2, 3, 4, 5, 6, 7],
|
||||
[100, 200, 300, 400, 500, 600, 0.07],
|
||||
[10, 200, 30, 41, 315, 0.31, 100],
|
||||
]
|
||||
)
|
||||
|
||||
actual_sorted = pdme.subspace_simulation.sort_array_of_dipoles_by_frequency(orig)
|
||||
assert actual_sorted.tolist() == snapshot
|
||||
|
||||
|
||||
def test_sort_dipoleses_by_freq(snapshot):
|
||||
sample_1 = numpy.array(
|
||||
[
|
||||
[1, 2, 3, 4, 5, 6, 7],
|
||||
[100, 200, 300, 400, 500, 600, 0.07],
|
||||
[10, 200, 30, 41, 315, 0.31, 100],
|
||||
]
|
||||
)
|
||||
|
||||
sample_2 = numpy.array(
|
||||
[
|
||||
[1, 1, 1, 1, 1, 1, 100],
|
||||
[33, 33.3, 33, 3.3, 0.33, 0.3, 300],
|
||||
[22, 22.2, 2.2, 222, 22, 2, 200],
|
||||
]
|
||||
)
|
||||
|
||||
original_samples = numpy.array([sample_1, sample_2])
|
||||
|
||||
actual_sorted = pdme.subspace_simulation.sort_array_of_dipoleses_by_frequency(
|
||||
original_samples
|
||||
)
|
||||
assert actual_sorted.tolist() == snapshot
|
38
tests/subspace_simulation/test_stdevs.py
Normal file
38
tests/subspace_simulation/test_stdevs.py
Normal file
@ -0,0 +1,38 @@
|
||||
import pytest
|
||||
import pdme.subspace_simulation
|
||||
|
||||
|
||||
def test_empty():
|
||||
with pytest.raises(ValueError):
|
||||
pdme.subspace_simulation.MCMCStandardDeviation([])
|
||||
|
||||
|
||||
def test_return_one(snapshot):
|
||||
stdev = pdme.subspace_simulation.DipoleStandardDeviation(
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
)
|
||||
stdevs = pdme.subspace_simulation.MCMCStandardDeviation([stdev])
|
||||
|
||||
assert stdevs[3] == snapshot
|
||||
assert stdevs[3] == stdev
|
||||
|
||||
|
||||
def test_return_four(snapshot):
|
||||
stdev_list = [
|
||||
pdme.subspace_simulation.DipoleStandardDeviation(1, 2, 3, 4, 5, 6),
|
||||
pdme.subspace_simulation.DipoleStandardDeviation(10, 20, 30, 40, 50, 60),
|
||||
pdme.subspace_simulation.DipoleStandardDeviation(0.1, 0.2, 0.3, 0.4, 0.5, 0.6),
|
||||
]
|
||||
stdevs = pdme.subspace_simulation.MCMCStandardDeviation(stdev_list)
|
||||
|
||||
assert stdevs[0] == snapshot
|
||||
assert stdevs[1] == snapshot
|
||||
assert stdevs[2] == snapshot
|
||||
assert stdevs[3] == snapshot
|
||||
assert stdevs[4] == snapshot
|
||||
assert stdevs[5] == snapshot
|
20
tests/util/__snapshots__/test_fast_nonlocal_spectrum.ambr
Normal file
20
tests/util/__snapshots__/test_fast_nonlocal_spectrum.ambr
Normal file
@ -0,0 +1,20 @@
|
||||
# serializer version: 1
|
||||
# name: test_arg
|
||||
list([
|
||||
list([
|
||||
-0.0,
|
||||
-0.0,
|
||||
-0.0,
|
||||
]),
|
||||
list([
|
||||
3.141592653589793,
|
||||
-0.0,
|
||||
-0.0,
|
||||
]),
|
||||
list([
|
||||
-0.0,
|
||||
-0.0,
|
||||
3.141592653589793,
|
||||
]),
|
||||
])
|
||||
# ---
|
@ -0,0 +1,25 @@
|
||||
# serializer version: 1
|
||||
# name: test_fast_nonlocal_calc_multidipole_phase_snapshot
|
||||
list([
|
||||
list([
|
||||
-0.0,
|
||||
-0.0,
|
||||
]),
|
||||
list([
|
||||
-0.0,
|
||||
3.141592653589793,
|
||||
]),
|
||||
])
|
||||
# ---
|
||||
# name: test_fast_spin_qubit_frequency_tarucha_calc
|
||||
list([
|
||||
list([
|
||||
1.1471308805198364,
|
||||
0.042486328908142086,
|
||||
]),
|
||||
list([
|
||||
0.0008292459978410822,
|
||||
0.0006214312613006971,
|
||||
]),
|
||||
])
|
||||
# ---
|
@ -1,9 +1,24 @@
|
||||
import numpy
|
||||
import pdme.util.fast_nonlocal_spectrum
|
||||
import pdme.measurement
|
||||
import logging
|
||||
import pytest
|
||||
|
||||
|
||||
def dipole_from_array(arr: numpy.ndarray) -> pdme.measurement.OscillatingDipole:
|
||||
return pdme.measurement.OscillatingDipole(arr[0:3], arr[3:6], arr[6])
|
||||
|
||||
|
||||
def s_potential_from_arrays(
|
||||
dipole_array: numpy.ndarray, dotf_pair_array: numpy.ndarray
|
||||
) -> float:
|
||||
dipole = dipole_from_array(dipole_array)
|
||||
r1 = dotf_pair_array[0][0:3]
|
||||
f1 = dotf_pair_array[0][3]
|
||||
r2 = dotf_pair_array[1][0:3]
|
||||
return dipole.s_electric_potential_for_dot_pair(r1, r2, f1)
|
||||
|
||||
|
||||
def test_fast_nonlocal_calc():
|
||||
d1 = [1, 2, 3, 4, 5, 6, 7]
|
||||
d2 = [1, 2, 3, 4, 5, 6, 8]
|
||||
@ -16,21 +31,11 @@ def test_fast_nonlocal_calc():
|
||||
[[[-1, -2, -3, 11], [-1, 2, 5, 11]], [[-1, -2, -3, 6], [2, 4, 6, 6]]]
|
||||
)
|
||||
# expected_ij is for pair i, dipole j
|
||||
expected_11 = 0.000021124454334947546213
|
||||
expected_12 = 0.000022184755131682365135
|
||||
expected_13 = 0.0000053860643617855849275
|
||||
expected_14 = -0.0000023069501696755220764
|
||||
expected_21 = 0.00022356021100884617796
|
||||
expected_22 = 0.00021717277640859343002
|
||||
expected_23 = 0.000017558321044891869169
|
||||
expected_24 = -0.000034714318479634499683
|
||||
|
||||
expected = numpy.array(
|
||||
[
|
||||
[expected_11, expected_21],
|
||||
[expected_12, expected_22],
|
||||
[expected_13, expected_23],
|
||||
[expected_14, expected_24],
|
||||
[s_potential_from_arrays(dipole_array, dot_pair) for dot_pair in dot_pairs]
|
||||
for dipole_array in dipoles
|
||||
]
|
||||
)
|
||||
|
||||
@ -53,3 +58,11 @@ def test_fast_nonlocal_frequency_check():
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
pdme.util.fast_nonlocal_spectrum.fast_s_nonlocal(dot_pairs, dipoles)
|
||||
|
||||
|
||||
def test_arg(snapshot):
|
||||
|
||||
test_input = numpy.array([[1, 2, 3], [-1, 1, 3], [3, 5, -1]])
|
||||
|
||||
actual_result = pdme.util.fast_nonlocal_spectrum.signarg(test_input)
|
||||
assert actual_result.tolist() == snapshot
|
||||
|
113
tests/util/test_fast_nonlocal_spectrum_pairs.py
Normal file
113
tests/util/test_fast_nonlocal_spectrum_pairs.py
Normal file
@ -0,0 +1,113 @@
|
||||
import numpy
|
||||
import pdme.util.fast_nonlocal_spectrum
|
||||
import pdme.measurement
|
||||
import logging
|
||||
import pytest
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def dipole_from_array(arr: numpy.ndarray) -> pdme.measurement.OscillatingDipole:
|
||||
return pdme.measurement.OscillatingDipole(arr[0:3], arr[3:6], arr[6])
|
||||
|
||||
|
||||
def s_potential_from_arrays(
|
||||
dipole_array: numpy.ndarray, dotf_pair_array: numpy.ndarray
|
||||
) -> float:
|
||||
dipole = dipole_from_array(dipole_array)
|
||||
r1 = dotf_pair_array[0][0:3]
|
||||
f1 = dotf_pair_array[0][3]
|
||||
r2 = dotf_pair_array[1][0:3]
|
||||
return dipole.s_electric_potential_for_dot_pair(r1, r2, f1)
|
||||
|
||||
|
||||
def test_fast_nonlocal_calc_multidipole():
|
||||
d1 = [1, 2, 3, 4, 5, 6, 7]
|
||||
d2 = [1, 2, 3, 4, 5, 6, 8]
|
||||
d3 = [2, 5, 3, 4, -5, -6, 2]
|
||||
d4 = [-3, 2, 1, 4, 5, 6, 10]
|
||||
|
||||
dipoleses = numpy.array([[d1, d2], [d3, d4]])
|
||||
|
||||
dot_pairs = numpy.array(
|
||||
[[[-1, -2, -3, 11], [-1, 2, 5, 11]], [[-1, -2, -3, 6], [2, 4, 6, 6]]]
|
||||
)
|
||||
# expected_ij is for pair i, dipole j
|
||||
|
||||
expected = numpy.array(
|
||||
[
|
||||
[
|
||||
sum(
|
||||
[
|
||||
s_potential_from_arrays(dipole_array, dot_pair)
|
||||
for dipole_array in dipoles
|
||||
]
|
||||
)
|
||||
for dot_pair in dot_pairs
|
||||
]
|
||||
for dipoles in dipoleses
|
||||
]
|
||||
)
|
||||
|
||||
# this is a bit silly but just set the logger to debug so that the coverage stats don't get affected by the debug statements.
|
||||
pdme.util.fast_nonlocal_spectrum._logger.setLevel(logging.DEBUG)
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
pdme.util.fast_nonlocal_spectrum.fast_s_nonlocal_dipoleses(
|
||||
dot_pairs, dipoleses
|
||||
),
|
||||
expected,
|
||||
err_msg="nonlocal voltages at dot aren't as expected for dipoleses.",
|
||||
)
|
||||
|
||||
|
||||
def test_fast_nonlocal_frequency_check_multidipole():
|
||||
d1 = [1, 2, 3, 4, 5, 6, 7]
|
||||
|
||||
dipoles = numpy.array([[d1]])
|
||||
|
||||
dot_pairs = numpy.array([[[-1, -2, -3, 11], [-1, 2, 5, 10]]])
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
pdme.util.fast_nonlocal_spectrum.fast_s_nonlocal_dipoleses(dot_pairs, dipoles)
|
||||
|
||||
|
||||
def test_fast_nonlocal_calc_multidipole_phase_snapshot(snapshot):
|
||||
d1 = [1, 2, 3, 4, 5, 6, 7]
|
||||
d2 = [1, 2, 3, 4, 5, 6, 8]
|
||||
d3 = [2, 5, 3, 4, -5, -6, 2]
|
||||
d4 = [-3, 2, 1, 4, 5, 6, 10]
|
||||
|
||||
dipoleses = numpy.array([[d1, d2], [d3, d4]])
|
||||
|
||||
dot_pairs = numpy.array(
|
||||
[[[-1, -2, -3, 11], [-1, 2, 5, 11]], [[-1, -2, -3, 6], [2, 4, 6, 6]]]
|
||||
)
|
||||
|
||||
# this is a bit silly but just set the logger to debug so that the coverage stats don't get affected by the debug statements.
|
||||
pdme.util.fast_nonlocal_spectrum._logger.setLevel(logging.DEBUG)
|
||||
|
||||
actual_phases = pdme.util.fast_nonlocal_spectrum.signarg(
|
||||
pdme.util.fast_nonlocal_spectrum.fast_s_nonlocal_dipoleses(dot_pairs, dipoleses)
|
||||
)
|
||||
assert actual_phases.tolist() == snapshot
|
||||
|
||||
|
||||
def test_fast_spin_qubit_frequency_tarucha_calc(snapshot):
|
||||
d1 = [1, 2, 3, 0, 0, 0, 5]
|
||||
d2 = [6, 7, 8, 5, 4, 3, 8]
|
||||
dipoleses = numpy.array([[d1], [d2]])
|
||||
|
||||
dot_pairs = numpy.array(
|
||||
[[[1, 0, 0, 1], [1, 0, 0, 1]], [[1, 0, 0, 1], [3, 0, 0, 1]]]
|
||||
)
|
||||
|
||||
actual = (
|
||||
pdme.util.fast_nonlocal_spectrum.fast_s_spin_qubit_tarucha_nonlocal_dipoleses(
|
||||
dot_pairs, dipoleses
|
||||
)
|
||||
)
|
||||
|
||||
pdme.util.fast_nonlocal_spectrum._logger.setLevel(logging.DEBUG)
|
||||
_logger.info(actual)
|
||||
assert actual.tolist() == snapshot
|
@ -1,6 +1,30 @@
|
||||
import numpy
|
||||
import pdme.util.fast_v_calc
|
||||
|
||||
import pdme.measurement
|
||||
|
||||
|
||||
def dipole_from_array(arr: numpy.ndarray) -> pdme.measurement.OscillatingDipole:
|
||||
return pdme.measurement.OscillatingDipole(arr[0:3], arr[3:6], arr[6])
|
||||
|
||||
|
||||
def s_potential_from_arrays(
|
||||
dipole_array: numpy.ndarray, dotf_array: numpy.ndarray
|
||||
) -> float:
|
||||
dipole = dipole_from_array(dipole_array)
|
||||
r = dotf_array[0:3]
|
||||
f = dotf_array[3]
|
||||
return dipole.s_electric_potential_at_position(r, f)
|
||||
|
||||
|
||||
def s_electric_field_x_from_arrays(
|
||||
dipole_array: numpy.ndarray, dotf_array: numpy.ndarray
|
||||
) -> float:
|
||||
dipole = dipole_from_array(dipole_array)
|
||||
r = dotf_array[0:3]
|
||||
f = dotf_array[3]
|
||||
return dipole.s_electric_fieldx_at_position(r, f)
|
||||
|
||||
|
||||
def test_fast_v_calc():
|
||||
d1 = [1, 2, 3, 4, 5, 6, 7]
|
||||
@ -9,11 +33,11 @@ def test_fast_v_calc():
|
||||
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_11 = s_potential_from_arrays(dipoles[0], dot_inputs[0])
|
||||
expected_12 = s_potential_from_arrays(dipoles[1], dot_inputs[0])
|
||||
expected_21 = s_potential_from_arrays(dipoles[0], dot_inputs[1])
|
||||
expected_22 = s_potential_from_arrays(dipoles[1], dot_inputs[1])
|
||||
|
||||
expected = numpy.array([[expected_11, expected_21], [expected_12, expected_22]])
|
||||
|
||||
@ -24,6 +48,164 @@ def test_fast_v_calc():
|
||||
)
|
||||
|
||||
|
||||
def test_fast_v_calc_multidipoles():
|
||||
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_11 = s_potential_from_arrays(dipoles[0][0], dot_inputs[0])
|
||||
expected_12 = s_potential_from_arrays(dipoles[0][1], dot_inputs[0])
|
||||
expected_21 = s_potential_from_arrays(dipoles[0][0], dot_inputs[1])
|
||||
expected_22 = s_potential_from_arrays(dipoles[0][1], dot_inputs[1])
|
||||
|
||||
expected = numpy.array([[expected_11 + expected_12, expected_21 + expected_22]])
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
pdme.util.fast_v_calc.fast_vs_for_dipoleses(dot_inputs, dipoles),
|
||||
expected,
|
||||
err_msg="Voltages at dot aren't as expected for multidipole calc.",
|
||||
)
|
||||
|
||||
|
||||
def test_fast_v_calc_big_multidipole():
|
||||
|
||||
dipoleses = numpy.array(
|
||||
[
|
||||
[
|
||||
[1, 1, 5, 6, 3, 1, 1],
|
||||
[5, 3, 2, 13, 1, 1, 2],
|
||||
[-5, -5, -3, -1, -3, 8, 3],
|
||||
],
|
||||
[
|
||||
[-3, -1, -2, -2, -6, 3, 4],
|
||||
[8, 0, 2, 0, 1, 5, 5],
|
||||
[1, 4, -4, -1, -3, -5, 6],
|
||||
],
|
||||
]
|
||||
)
|
||||
|
||||
dot_inputs = numpy.array(
|
||||
[
|
||||
[1, 1, 0, 1],
|
||||
[2, 5, 6, 2],
|
||||
[3, 1, 3, 3],
|
||||
[0.5, 0.5, 0.5, 4],
|
||||
]
|
||||
)
|
||||
|
||||
expected = [
|
||||
[
|
||||
sum(
|
||||
[
|
||||
s_potential_from_arrays(dipole_array, dot_input)
|
||||
for dipole_array in dipole_config
|
||||
]
|
||||
)
|
||||
for dot_input in dot_inputs
|
||||
]
|
||||
for dipole_config in dipoleses
|
||||
]
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
pdme.util.fast_v_calc.fast_vs_for_dipoleses(dot_inputs, dipoleses),
|
||||
expected,
|
||||
err_msg="Voltages at dot aren't as expected for multidipole calc.",
|
||||
)
|
||||
|
||||
|
||||
def test_fast_electric_field_x_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_11 = s_electric_field_x_from_arrays(dipoles[0], dot_inputs[0])
|
||||
expected_12 = s_electric_field_x_from_arrays(dipoles[1], dot_inputs[0])
|
||||
expected_21 = s_electric_field_x_from_arrays(dipoles[0], dot_inputs[1])
|
||||
expected_22 = s_electric_field_x_from_arrays(dipoles[1], dot_inputs[1])
|
||||
|
||||
expected = numpy.array([[expected_11, expected_21], [expected_12, expected_22]])
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
pdme.util.fast_v_calc.fast_efieldxs_for_dipoles(dot_inputs, dipoles),
|
||||
expected,
|
||||
err_msg="E x fast calc at dot aren't as expected.",
|
||||
)
|
||||
|
||||
|
||||
def test_fast_electric_field_x_calc_multidipoles():
|
||||
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_11 = s_electric_field_x_from_arrays(dipoles[0][0], dot_inputs[0])
|
||||
expected_12 = s_electric_field_x_from_arrays(dipoles[0][1], dot_inputs[0])
|
||||
expected_21 = s_electric_field_x_from_arrays(dipoles[0][0], dot_inputs[1])
|
||||
expected_22 = s_electric_field_x_from_arrays(dipoles[0][1], dot_inputs[1])
|
||||
|
||||
expected = numpy.array([[expected_11 + expected_12, expected_21 + expected_22]])
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
pdme.util.fast_v_calc.fast_efieldxs_for_dipoleses(dot_inputs, dipoles),
|
||||
expected,
|
||||
err_msg="E x fast calc at dot aren't as expected for multidipole calc.",
|
||||
)
|
||||
|
||||
|
||||
def test_fast_electric_field_x_calc_big_multidipole():
|
||||
|
||||
dipoleses = numpy.array(
|
||||
[
|
||||
[
|
||||
[1, 1, 5, 6, 3, 1, 1],
|
||||
[5, 3, 2, 13, 1, 1, 2],
|
||||
[-5, -5, -3, -1, -3, 8, 3],
|
||||
],
|
||||
[
|
||||
[-3, -1, -2, -2, -6, 3, 4],
|
||||
[8, 0, 2, 0, 1, 5, 5],
|
||||
[1, 4, -4, -1, -3, -5, 6],
|
||||
],
|
||||
]
|
||||
)
|
||||
|
||||
dot_inputs = numpy.array(
|
||||
[
|
||||
[1, 1, 0, 1],
|
||||
[2, 5, 6, 2],
|
||||
[3, 1, 3, 3],
|
||||
[0.5, 0.5, 0.5, 4],
|
||||
]
|
||||
)
|
||||
|
||||
expected = [
|
||||
[
|
||||
sum(
|
||||
[
|
||||
s_electric_field_x_from_arrays(dipole_array, dot_input)
|
||||
for dipole_array in dipole_config
|
||||
]
|
||||
)
|
||||
for dot_input in dot_inputs
|
||||
]
|
||||
for dipole_config in dipoleses
|
||||
]
|
||||
|
||||
numpy.testing.assert_allclose(
|
||||
pdme.util.fast_v_calc.fast_efieldxs_for_dipoleses(dot_inputs, dipoleses),
|
||||
expected,
|
||||
err_msg="E x fast calc at dot aren't as expected for multidipole calc.",
|
||||
)
|
||||
|
||||
|
||||
def test_between():
|
||||
low = numpy.array([1, 2, 3])
|
||||
high = numpy.array([6, 7, 8])
|
||||
|
Loading…
x
Reference in New Issue
Block a user