Compare commits
50 Commits
Author | SHA1 | Date | |
---|---|---|---|
f168666045
|
|||
604916a829 | |||
941313a14c
|
|||
cb64c0b7b6
|
|||
ec7b4cac39
|
|||
31e6cfaf51
|
|||
c1c711f47b
|
|||
6463b135ef
|
|||
a283cbd670 | |||
0b45172ca0 | |||
b6383d0a47 | |||
450d8e0ec9 | |||
f81904a898
|
|||
88d961313c
|
|||
fa82caa752
|
|||
0784cd53d7
|
|||
fb4b012491
|
|||
8617e4d274
|
|||
fe2af1644e
|
|||
e6d8d33c27
|
|||
e00dc95f02
|
|||
527be26fb2
|
|||
456c81bca5
|
|||
7284dbeb34
|
|||
d078004773
|
|||
0441cde421
|
|||
a9e91779bc
|
|||
751bc66704 | |||
413ff16acc | |||
5118173f09
|
|||
|
6dfc26104a
|
||
3a6be738b1
|
|||
bd240900b4
|
|||
0e1fbec043
|
|||
3d3b1a83f6
|
|||
63cecba824
|
|||
344998835d
|
|||
838aeb0cf3
|
|||
e715d329fd
|
|||
521b49f14c
|
|||
6d65e8dec5
|
|||
36354c2f2c
|
|||
3534593557
|
|||
6ada52f82c
|
|||
34e124b18f
|
|||
c1591c9ce9
|
|||
10358287d9
|
|||
d4f6e2f99e
|
|||
d64939f346
|
|||
0c6490dad7
|
10
.versionrc
Normal file
10
.versionrc
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"bumpFiles": [
|
||||||
|
{
|
||||||
|
"filename": "pyproject.toml",
|
||||||
|
"updater": "scripts/standard-version/pyproject-updater.js"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sign": true,
|
||||||
|
"tag-prefix": ""
|
||||||
|
}
|
56
CHANGELOG.md
Normal file
56
CHANGELOG.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
## [0.4.0](https://gitea.deepak.science:2222/physics/deepdog/compare/0.3.5...0.4.0) (2022-04-10)
|
||||||
|
|
||||||
|
|
||||||
|
### ⚠ BREAKING CHANGES
|
||||||
|
|
||||||
|
* Adds pair calculations, with changing api format
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Adds dynamic cycle count increases to help reach minimum success count ([ec7b4ca](https://gitea.deepak.science:2222/physics/deepdog/commit/ec7b4cac393c15e94c513215c4f1ba32be2ae87a))
|
||||||
|
* Adds pair calculations, with changing api format ([6463b13](https://gitea.deepak.science:2222/physics/deepdog/commit/6463b135ef2d212b565864b5ac1b655e014d2194))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* uses bigfix from pdme for negatives ([c1c711f](https://gitea.deepak.science:2222/physics/deepdog/commit/c1c711f47b574d3a9b8a24dbcbdd7f50b9be8ea9))
|
||||||
|
|
||||||
|
### [0.3.5](https://gitea.deepak.science:2222/physics/deepdog/compare/0.3.4...0.3.5) (2022-03-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* makes chunksize configurable ([88d9613](https://gitea.deepak.science:2222/physics/deepdog/commit/88d961313c1db0d49fd96939aa725a8706fa0412))
|
||||||
|
|
||||||
|
### [0.3.4](https://gitea.deepak.science:2222/physics/deepdog/compare/0.3.3...0.3.4) (2022-03-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Changes chunksize for multiprocessing ([0784cd5](https://gitea.deepak.science:2222/physics/deepdog/commit/0784cd53d79e00684506604f094b5d820b3994d4))
|
||||||
|
|
||||||
|
### [0.3.3](https://gitea.deepak.science:2222/physics/deepdog/compare/0.3.2...0.3.3) (2022-03-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* Fixes count to use cycles as well ([8617e4d](https://gitea.deepak.science:2222/physics/deepdog/commit/8617e4d2742b112cc824068150682ce3b2cdd879))
|
||||||
|
|
||||||
|
### [0.3.2](https://gitea.deepak.science:2222/physics/deepdog/compare/0.3.1...0.3.2) (2022-03-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Adds monte carlo cycles to trade off space and cpu ([e6d8d33](https://gitea.deepak.science:2222/physics/deepdog/commit/e6d8d33c27e7922581e91c10de4f5faff2a51f8b))
|
||||||
|
|
||||||
|
### [0.3.1](https://gitea.deepak.science:2222/physics/deepdog/compare/v0.3.0...v0.3.1) (2022-03-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Adds alt bayes solver with monte carlo sampler ([7284dbe](https://gitea.deepak.science:2222/physics/deepdog/commit/7284dbeb34ef46189d81fb719252dfa74b8e9fa8))
|
||||||
|
* Updates to pdme version for faster bayes resolution ([d078004](https://gitea.deepak.science:2222/physics/deepdog/commit/d078004773d9d9dccd0a9a52ca96aa57690f9b7e))
|
17
README.md
17
README.md
@@ -1,3 +1,18 @@
|
|||||||
# deepdog
|
# deepdog
|
||||||
|
|
||||||
The dipole diagnostic tool.
|
[](https://conventionalcommits.org)
|
||||||
|
[](https://pypi.org/project/deepdog/)
|
||||||
|
[](https://jenkins.deepak.science/job/gitea-physics/job/deepdog/job/master/)
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
The DiPole DiaGnostic tool.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
`poetry install` to start locally
|
||||||
|
|
||||||
|
Commit using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), and when commits are on master, release with `doo release`.
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,13 +1,15 @@
|
|||||||
import logging
|
import logging
|
||||||
from deepdog.meta import __version__
|
from deepdog.meta import __version__
|
||||||
from deepdog.bayes_run import BayesRun
|
from deepdog.bayes_run import BayesRun
|
||||||
|
from deepdog.alt_bayes_run import AltBayesRun
|
||||||
|
from deepdog.diagnostic import Diagnostic
|
||||||
|
|
||||||
|
|
||||||
def get_version():
|
def get_version():
|
||||||
return __version__
|
return __version__
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["get_version", "BayesRun"]
|
__all__ = ["get_version", "BayesRun", "AltBayesRun", "Diagnostic"]
|
||||||
|
|
||||||
|
|
||||||
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
||||||
|
189
deepdog/alt_bayes_run.py
Normal file
189
deepdog/alt_bayes_run.py
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
import pdme.inputs
|
||||||
|
import pdme.model
|
||||||
|
import pdme.measurement.input_types
|
||||||
|
import pdme.measurement.oscillating_dipole
|
||||||
|
import pdme.util.fast_v_calc
|
||||||
|
import pdme.util.fast_nonlocal_spectrum
|
||||||
|
from typing import Sequence, Tuple, List
|
||||||
|
import datetime
|
||||||
|
import csv
|
||||||
|
import multiprocessing
|
||||||
|
import logging
|
||||||
|
import numpy
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: remove hardcode
|
||||||
|
CHUNKSIZE = 50
|
||||||
|
|
||||||
|
# TODO: It's garbage to have this here duplicated from pdme.
|
||||||
|
DotInput = Tuple[numpy.typing.ArrayLike, float]
|
||||||
|
|
||||||
|
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def get_a_result(input) -> int:
|
||||||
|
discretisation, dot_inputs, lows, highs, monte_carlo_count, max_frequency = input
|
||||||
|
sample_dipoles = discretisation.get_model().get_n_single_dipoles(monte_carlo_count, max_frequency)
|
||||||
|
vals = pdme.util.fast_v_calc.fast_vs_for_dipoles(dot_inputs, sample_dipoles)
|
||||||
|
return numpy.count_nonzero(pdme.util.fast_v_calc.between(vals, lows, highs))
|
||||||
|
|
||||||
|
|
||||||
|
def get_a_result_using_pairs(input) -> int:
|
||||||
|
discretisation, dot_inputs, pair_inputs, local_lows, local_highs, nonlocal_lows, nonlocal_highs, monte_carlo_count, max_frequency = input
|
||||||
|
sample_dipoles = discretisation.get_model().get_n_single_dipoles(monte_carlo_count, max_frequency)
|
||||||
|
local_vals = pdme.util.fast_v_calc.fast_vs_for_dipoles(dot_inputs, sample_dipoles)
|
||||||
|
local_matches = pdme.util.fast_v_calc.between(local_vals, local_lows, local_highs)
|
||||||
|
nonlocal_vals = pdme.util.fast_nonlocal_spectrum.fast_s_nonlocal(pair_inputs, sample_dipoles)
|
||||||
|
nonlocal_matches = pdme.util.fast_v_calc.between(nonlocal_vals, nonlocal_lows, nonlocal_highs)
|
||||||
|
combined_matches = numpy.logical_and(local_matches, nonlocal_matches)
|
||||||
|
return numpy.count_nonzero(combined_matches)
|
||||||
|
|
||||||
|
|
||||||
|
class AltBayesRun():
|
||||||
|
'''
|
||||||
|
A single Bayes run for a given set of dots.
|
||||||
|
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
dot_inputs : Sequence[DotInput]
|
||||||
|
The dot inputs for this bayes run.
|
||||||
|
discretisations_with_names : Sequence[Tuple(str, pdme.model.Model)]
|
||||||
|
The models to evaluate.
|
||||||
|
actual_model_discretisation : pdme.model.Discretisation
|
||||||
|
The discretisation for the model which is actually correct.
|
||||||
|
filename_slug : str
|
||||||
|
The filename slug to include.
|
||||||
|
run_count: int
|
||||||
|
The number of runs to do.
|
||||||
|
'''
|
||||||
|
def __init__(self, dot_positions: Sequence[numpy.typing.ArrayLike], frequency_range: Sequence[float], discretisations_with_names: Sequence[Tuple[str, pdme.model.Discretisation]], actual_model: pdme.model.Model, filename_slug: str, run_count: int = 100, low_error: float = 0.9, high_error: float = 1.1, pairs_high_error=None, pairs_low_error=None, monte_carlo_count: int = 10000, monte_carlo_cycles: int = 10, target_success: int = 100, max_monte_carlo_cycles_steps: int = 10, max_frequency: float = 20, end_threshold: float = None, chunksize: int = CHUNKSIZE, use_pairs: bool = False) -> None:
|
||||||
|
self.dot_inputs = pdme.inputs.inputs_with_frequency_range(dot_positions, frequency_range)
|
||||||
|
self.dot_inputs_array = pdme.measurement.input_types.dot_inputs_to_array(self.dot_inputs)
|
||||||
|
|
||||||
|
self.use_pairs = use_pairs
|
||||||
|
|
||||||
|
self.dot_pair_inputs = pdme.inputs.input_pairs_with_frequency_range(dot_positions, frequency_range)
|
||||||
|
self.dot_pair_inputs_array = pdme.measurement.input_types.dot_pair_inputs_to_array(self.dot_pair_inputs)
|
||||||
|
|
||||||
|
self.discretisations = [disc for (_, disc) in discretisations_with_names]
|
||||||
|
self.model_names = [name for (name, _) in discretisations_with_names]
|
||||||
|
self.actual_model = actual_model
|
||||||
|
self.model_count = len(self.discretisations)
|
||||||
|
self.monte_carlo_count = monte_carlo_count
|
||||||
|
self.monte_carlo_cycles = monte_carlo_cycles
|
||||||
|
self.target_success = target_success
|
||||||
|
self.max_monte_carlo_cycles_steps = max_monte_carlo_cycles_steps
|
||||||
|
self.run_count = run_count
|
||||||
|
self.low_error = low_error
|
||||||
|
self.high_error = high_error
|
||||||
|
if pairs_low_error is None:
|
||||||
|
self.pairs_low_error = self.low_error
|
||||||
|
else:
|
||||||
|
self.pairs_low_error = pairs_low_error
|
||||||
|
if pairs_high_error is None:
|
||||||
|
self.pairs_high_error = self.high_error
|
||||||
|
else:
|
||||||
|
self.pairs_high_error = pairs_high_error
|
||||||
|
self.csv_fields = ["dipole_moment", "dipole_location", "dipole_frequency"]
|
||||||
|
self.compensate_zeros = True
|
||||||
|
self.chunksize = chunksize
|
||||||
|
for name in self.model_names:
|
||||||
|
self.csv_fields.extend([f"{name}_success", f"{name}_count", f"{name}_prob"])
|
||||||
|
|
||||||
|
self.probabilities = [1 / self.model_count] * self.model_count
|
||||||
|
|
||||||
|
timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||||
|
if self.use_pairs:
|
||||||
|
self.filename = f"{timestamp}-{filename_slug}.altbayes.pairs.csv"
|
||||||
|
else:
|
||||||
|
self.filename = f"{timestamp}-{filename_slug}.altbayes.csv"
|
||||||
|
self.max_frequency = max_frequency
|
||||||
|
|
||||||
|
if end_threshold is not None:
|
||||||
|
if 0 < end_threshold < 1:
|
||||||
|
self.end_threshold: float = end_threshold
|
||||||
|
self.use_end_threshold = True
|
||||||
|
_logger.info(f"Will abort early, at {self.end_threshold}.")
|
||||||
|
else:
|
||||||
|
raise ValueError(f"end_threshold should be between 0 and 1, but is actually {end_threshold}")
|
||||||
|
|
||||||
|
def go(self) -> None:
|
||||||
|
with open(self.filename, "a", newline="") as outfile:
|
||||||
|
writer = csv.DictWriter(outfile, fieldnames=self.csv_fields, dialect="unix")
|
||||||
|
writer.writeheader()
|
||||||
|
|
||||||
|
for run in range(1, self.run_count + 1):
|
||||||
|
|
||||||
|
rng = numpy.random.default_rng()
|
||||||
|
frequency = rng.uniform(1, self.max_frequency)
|
||||||
|
|
||||||
|
# Generate the actual dipoles
|
||||||
|
actual_dipoles = self.actual_model.get_dipoles(frequency)
|
||||||
|
|
||||||
|
dots = actual_dipoles.get_percent_range_dot_measurements(self.dot_inputs, self.low_error, self.high_error)
|
||||||
|
lows, highs = pdme.measurement.input_types.dot_range_measurements_low_high_arrays(dots)
|
||||||
|
|
||||||
|
pair_lows, pair_highs = (None, None)
|
||||||
|
if self.use_pairs:
|
||||||
|
pair_measurements = actual_dipoles.get_percent_range_dot_pair_measurements(self.dot_pair_inputs, self.pairs_low_error, self.pairs_high_error)
|
||||||
|
pair_lows, pair_highs = pdme.measurement.input_types.dot_range_measurements_low_high_arrays(pair_measurements)
|
||||||
|
|
||||||
|
_logger.info(f"Going to work on dipole at {actual_dipoles.dipoles}")
|
||||||
|
|
||||||
|
results = []
|
||||||
|
_logger.debug("Going to iterate over discretisations now")
|
||||||
|
for disc_count, discretisation in enumerate(self.discretisations):
|
||||||
|
_logger.debug(f"Doing discretisation #{disc_count}")
|
||||||
|
with multiprocessing.Pool(multiprocessing.cpu_count() - 1 or 1) as pool:
|
||||||
|
cycle_count = 0
|
||||||
|
cycle_success = 0
|
||||||
|
cycles = 0
|
||||||
|
while (cycles < self.max_monte_carlo_cycles_steps) and (cycle_success <= self.target_success):
|
||||||
|
_logger.debug(f"Starting cycle {cycles}")
|
||||||
|
cycles += 1
|
||||||
|
current_success = 0
|
||||||
|
cycle_count += self.monte_carlo_count * self.monte_carlo_cycles
|
||||||
|
if self.use_pairs:
|
||||||
|
current_success = sum(
|
||||||
|
pool.imap_unordered(get_a_result_using_pairs, [(discretisation, self.dot_inputs_array, self.dot_pair_inputs_array, lows, highs, pair_lows, pair_highs, self.monte_carlo_count, self.max_frequency)] * self.monte_carlo_cycles, self.chunksize)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
current_success = sum(
|
||||||
|
pool.imap_unordered(get_a_result, [(discretisation, self.dot_inputs_array, lows, highs, self.monte_carlo_count, self.max_frequency)] * self.monte_carlo_cycles, self.chunksize)
|
||||||
|
)
|
||||||
|
|
||||||
|
cycle_success += current_success
|
||||||
|
results.append((cycle_count, cycle_success))
|
||||||
|
|
||||||
|
_logger.debug("Done, constructing output now")
|
||||||
|
row = {
|
||||||
|
"dipole_moment": actual_dipoles.dipoles[0].p,
|
||||||
|
"dipole_location": actual_dipoles.dipoles[0].s,
|
||||||
|
"dipole_frequency": actual_dipoles.dipoles[0].w
|
||||||
|
}
|
||||||
|
successes: List[float] = []
|
||||||
|
counts: List[int] = []
|
||||||
|
for model_index, (name, (count, result)) in enumerate(zip(self.model_names, results)):
|
||||||
|
|
||||||
|
row[f"{name}_success"] = result
|
||||||
|
row[f"{name}_count"] = count
|
||||||
|
successes.append(max(result, 0.5))
|
||||||
|
counts.append(count)
|
||||||
|
|
||||||
|
success_weight = sum([(succ / count) * prob for succ, count, prob in zip(successes, counts, self.probabilities)])
|
||||||
|
new_probabilities = [(succ / count) * old_prob / success_weight for succ, count, old_prob in zip(successes, counts, self.probabilities)]
|
||||||
|
self.probabilities = new_probabilities
|
||||||
|
for name, probability in zip(self.model_names, self.probabilities):
|
||||||
|
row[f"{name}_prob"] = probability
|
||||||
|
_logger.info(row)
|
||||||
|
|
||||||
|
with open(self.filename, "a", newline="") as outfile:
|
||||||
|
writer = csv.DictWriter(outfile, fieldnames=self.csv_fields, dialect="unix")
|
||||||
|
writer.writerow(row)
|
||||||
|
|
||||||
|
if self.use_end_threshold:
|
||||||
|
max_prob = max(self.probabilities)
|
||||||
|
if max_prob > self.end_threshold:
|
||||||
|
_logger.info(f"Aborting early, because {max_prob} is greater than {self.end_threshold}")
|
||||||
|
break
|
@@ -41,7 +41,7 @@ class BayesRun():
|
|||||||
run_count: int
|
run_count: int
|
||||||
The number of runs to do.
|
The number of runs to do.
|
||||||
'''
|
'''
|
||||||
def __init__(self, dot_inputs: Sequence[DotInput], discretisations_with_names: Sequence[Tuple[str, pdme.model.Discretisation]], actual_model: pdme.model.Model, filename_slug: str, run_count: int) -> None:
|
def __init__(self, dot_inputs: Sequence[DotInput], discretisations_with_names: Sequence[Tuple[str, pdme.model.Discretisation]], actual_model: pdme.model.Model, filename_slug: str, run_count: int, max_frequency: float = None, end_threshold: float = None) -> None:
|
||||||
self.dot_inputs = dot_inputs
|
self.dot_inputs = dot_inputs
|
||||||
self.discretisations = [disc for (_, disc) in discretisations_with_names]
|
self.discretisations = [disc for (_, disc) in discretisations_with_names]
|
||||||
self.model_names = [name for (name, _) in discretisations_with_names]
|
self.model_names = [name for (name, _) in discretisations_with_names]
|
||||||
@@ -50,7 +50,6 @@ class BayesRun():
|
|||||||
self.run_count = run_count
|
self.run_count = run_count
|
||||||
self.csv_fields = ["dipole_moment", "dipole_location", "dipole_frequency"]
|
self.csv_fields = ["dipole_moment", "dipole_location", "dipole_frequency"]
|
||||||
self.compensate_zeros = True
|
self.compensate_zeros = True
|
||||||
|
|
||||||
for name in self.model_names:
|
for name in self.model_names:
|
||||||
self.csv_fields.extend([f"{name}_success", f"{name}_count", f"{name}_prob"])
|
self.csv_fields.extend([f"{name}_success", f"{name}_count", f"{name}_prob"])
|
||||||
|
|
||||||
@@ -58,6 +57,15 @@ class BayesRun():
|
|||||||
|
|
||||||
timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||||
self.filename = f"{timestamp}-{filename_slug}.csv"
|
self.filename = f"{timestamp}-{filename_slug}.csv"
|
||||||
|
self.max_frequency = max_frequency
|
||||||
|
|
||||||
|
if end_threshold is not None:
|
||||||
|
if 0 < end_threshold < 1:
|
||||||
|
self.end_threshold: float = end_threshold
|
||||||
|
self.use_end_threshold = True
|
||||||
|
_logger.info(f"Will abort early, at {self.end_threshold}.")
|
||||||
|
else:
|
||||||
|
raise ValueError(f"end_threshold should be between 0 and 1, but is actually {end_threshold}")
|
||||||
|
|
||||||
def go(self) -> None:
|
def go(self) -> None:
|
||||||
with open(self.filename, "a", newline="") as outfile:
|
with open(self.filename, "a", newline="") as outfile:
|
||||||
@@ -65,7 +73,11 @@ class BayesRun():
|
|||||||
writer.writeheader()
|
writer.writeheader()
|
||||||
|
|
||||||
for run in range(1, self.run_count + 1):
|
for run in range(1, self.run_count + 1):
|
||||||
dipoles = self.actual_model.get_dipoles(run)
|
frequency: float = run
|
||||||
|
if self.max_frequency is not None and self.max_frequency > 1:
|
||||||
|
rng = numpy.random.default_rng()
|
||||||
|
frequency = rng.uniform(1, self.max_frequency)
|
||||||
|
dipoles = self.actual_model.get_dipoles(frequency)
|
||||||
|
|
||||||
dots = dipoles.get_dot_measurements(self.dot_inputs)
|
dots = dipoles.get_dot_measurements(self.dot_inputs)
|
||||||
_logger.info(f"Going to work on dipole at {dipoles.dipoles}")
|
_logger.info(f"Going to work on dipole at {dipoles.dipoles}")
|
||||||
@@ -83,7 +95,8 @@ class BayesRun():
|
|||||||
"dipole_location": dipoles.dipoles[0].s,
|
"dipole_location": dipoles.dipoles[0].s,
|
||||||
"dipole_frequency": dipoles.dipoles[0].w
|
"dipole_frequency": dipoles.dipoles[0].w
|
||||||
}
|
}
|
||||||
successes: List[int] = []
|
successes: List[float] = []
|
||||||
|
counts: List[int] = []
|
||||||
for model_index, (name, result) in enumerate(zip(self.model_names, results)):
|
for model_index, (name, result) in enumerate(zip(self.model_names, results)):
|
||||||
count = 0
|
count = 0
|
||||||
success = 0
|
success = 0
|
||||||
@@ -94,10 +107,11 @@ class BayesRun():
|
|||||||
|
|
||||||
row[f"{name}_success"] = success
|
row[f"{name}_success"] = success
|
||||||
row[f"{name}_count"] = count
|
row[f"{name}_count"] = count
|
||||||
successes.append(max(success, 1))
|
successes.append(max(success, 0.5))
|
||||||
|
counts.append(count)
|
||||||
|
|
||||||
success_weight = sum([succ * prob for succ, prob in zip(successes, self.probabilities)])
|
success_weight = sum([(succ / count) * prob for succ, count, prob in zip(successes, counts, self.probabilities)])
|
||||||
new_probabilities = [succ * old_prob / success_weight for succ, old_prob in zip(successes, self.probabilities)]
|
new_probabilities = [(succ / count) * old_prob / success_weight for succ, count, old_prob in zip(successes, counts, self.probabilities)]
|
||||||
self.probabilities = new_probabilities
|
self.probabilities = new_probabilities
|
||||||
for name, probability in zip(self.model_names, self.probabilities):
|
for name, probability in zip(self.model_names, self.probabilities):
|
||||||
row[f"{name}_prob"] = probability
|
row[f"{name}_prob"] = probability
|
||||||
@@ -106,3 +120,9 @@ class BayesRun():
|
|||||||
with open(self.filename, "a", newline="") as outfile:
|
with open(self.filename, "a", newline="") as outfile:
|
||||||
writer = csv.DictWriter(outfile, fieldnames=self.csv_fields, dialect="unix")
|
writer = csv.DictWriter(outfile, fieldnames=self.csv_fields, dialect="unix")
|
||||||
writer.writerow(row)
|
writer.writerow(row)
|
||||||
|
|
||||||
|
if self.use_end_threshold:
|
||||||
|
max_prob = max(self.probabilities)
|
||||||
|
if max_prob > self.end_threshold:
|
||||||
|
_logger.info(f"Aborting early, because {max_prob} is greater than {self.end_threshold}")
|
||||||
|
break
|
||||||
|
@@ -3,6 +3,7 @@ import pdme
|
|||||||
from deepdog.bayes_run import DotInput
|
from deepdog.bayes_run import DotInput
|
||||||
import datetime
|
import datetime
|
||||||
import numpy
|
import numpy
|
||||||
|
from dataclasses import dataclass
|
||||||
import logging
|
import logging
|
||||||
from typing import Sequence, Tuple
|
from typing import Sequence, Tuple
|
||||||
import csv
|
import csv
|
||||||
@@ -16,6 +17,32 @@ def get_a_result(discretisation, dots, index):
|
|||||||
return (index, discretisation.solve_for_index(dots, index))
|
return (index, discretisation.solve_for_index(dots, index))
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class SingleDipoleDiagnostic():
|
||||||
|
model: str
|
||||||
|
index: Tuple
|
||||||
|
bounds: Tuple
|
||||||
|
actual_dipole: OscillatingDipole
|
||||||
|
result_dipole: OscillatingDipole
|
||||||
|
success: bool
|
||||||
|
|
||||||
|
def __post_init__(self) -> None:
|
||||||
|
self.p_actual_x = self.actual_dipole.p[0]
|
||||||
|
self.p_actual_y = self.actual_dipole.p[1]
|
||||||
|
self.p_actual_z = self.actual_dipole.p[2]
|
||||||
|
self.s_actual_x = self.actual_dipole.s[0]
|
||||||
|
self.s_actual_y = self.actual_dipole.s[1]
|
||||||
|
self.s_actual_z = self.actual_dipole.s[2]
|
||||||
|
self.p_result_x = self.result_dipole.p[0]
|
||||||
|
self.p_result_y = self.result_dipole.p[1]
|
||||||
|
self.p_result_z = self.result_dipole.p[2]
|
||||||
|
self.s_result_x = self.result_dipole.s[0]
|
||||||
|
self.s_result_y = self.result_dipole.s[1]
|
||||||
|
self.s_result_z = self.result_dipole.s[2]
|
||||||
|
self.w_actual = self.actual_dipole.w
|
||||||
|
self.w_result = self.result_dipole.w
|
||||||
|
|
||||||
|
|
||||||
class Diagnostic():
|
class Diagnostic():
|
||||||
'''
|
'''
|
||||||
Represents a diagnostic for a single dipole moment given a set of discretisations.
|
Represents a diagnostic for a single dipole moment given a set of discretisations.
|
||||||
@@ -40,10 +67,10 @@ class Diagnostic():
|
|||||||
self.discretisations_with_names = discretisations_with_names
|
self.discretisations_with_names = discretisations_with_names
|
||||||
self.model_count = len(self.discretisations_with_names)
|
self.model_count = len(self.discretisations_with_names)
|
||||||
|
|
||||||
self.csv_fields = ["model", "index", "bounds", "actual_dipole_moment", "actual_dipole_position", "actual_dipole_freq", "success", "result"]
|
self.csv_fields = ["model", "index", "bounds", "p_actual_x", "p_actual_y", "p_actual_z", "s_actual_x", "s_actual_y", "s_actual_z", "w_actual", "success", "p_result_x", "p_result_y", "p_result_z", "s_result_x", "s_result_y", "s_result_z", "w_result"]
|
||||||
|
|
||||||
timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
timestamp = datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
|
||||||
self.filename = f"{timestamp}-{filename_slug}.csv"
|
self.filename = f"{timestamp}-{filename_slug}.diag.csv"
|
||||||
|
|
||||||
def go(self):
|
def go(self):
|
||||||
with open(self.filename, "a", newline="") as outfile:
|
with open(self.filename, "a", newline="") as outfile:
|
||||||
@@ -59,22 +86,14 @@ class Diagnostic():
|
|||||||
results = pool.starmap(get_a_result, zip(itertools.repeat(discretisation), itertools.repeat(self.dots), discretisation.all_indices()))
|
results = pool.starmap(get_a_result, zip(itertools.repeat(discretisation), itertools.repeat(self.dots), discretisation.all_indices()))
|
||||||
|
|
||||||
with open(self.filename, "a", newline='') as outfile:
|
with open(self.filename, "a", newline='') as outfile:
|
||||||
writer = csv.DictWriter(outfile, fieldnames=self.csv_fields, dialect='unix')
|
writer = csv.DictWriter(outfile, fieldnames=self.csv_fields, dialect='unix', extrasaction="ignore")
|
||||||
|
|
||||||
for idx, result in results:
|
for idx, result in results:
|
||||||
|
|
||||||
bounds = discretisation.bounds(idx)
|
bounds = discretisation.bounds(idx)
|
||||||
|
|
||||||
actual_success = result.success and result.cost <= 1e-10
|
actual_success = result.success and result.cost <= 1e-10
|
||||||
row = {
|
diag_row = SingleDipoleDiagnostic(name, idx, bounds, self.dipoles.dipoles[0], discretisation.model.solution_as_dipoles(result.normalised_x)[0], actual_success)
|
||||||
"model": name,
|
row = vars(diag_row)
|
||||||
"index": idx,
|
|
||||||
"bounds_px": bounds,
|
|
||||||
"actual_dipole_moment": self.dipoles.dipoles[0].p,
|
|
||||||
"actual_dipole_position": self.dipoles.dipoles[0].s,
|
|
||||||
"actual_dipole_freq": self.dipoles.dipoles[0].w,
|
|
||||||
"success": actual_success,
|
|
||||||
"result": result.normalised_x if actual_success else None,
|
|
||||||
}
|
|
||||||
_logger.debug(f"Writing result {row}")
|
_logger.debug(f"Writing result {row}")
|
||||||
writer.writerow(row)
|
writer.writerow(row)
|
||||||
|
4
do.sh
4
do.sh
@@ -16,6 +16,10 @@ test() {
|
|||||||
poetry run pytest
|
poetry run pytest
|
||||||
}
|
}
|
||||||
|
|
||||||
|
release() {
|
||||||
|
./scripts/release.sh
|
||||||
|
}
|
||||||
|
|
||||||
htmlcov() {
|
htmlcov() {
|
||||||
poetry run pytest --cov-report=html
|
poetry run pytest --cov-report=html
|
||||||
}
|
}
|
||||||
|
869
poetry.lock
generated
869
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,19 @@
|
|||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "deepdog"
|
name = "deepdog"
|
||||||
version = "0.1.3"
|
version = "0.4.0"
|
||||||
description = ""
|
description = ""
|
||||||
authors = ["Deepak Mallubhotla <dmallubhotla+github@gmail.com>"]
|
authors = ["Deepak Mallubhotla <dmallubhotla+github@gmail.com>"]
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = "^3.8,<3.10"
|
python = "^3.8,<3.10"
|
||||||
pdme = "^0.4.1"
|
pdme = "^0.6.1"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
pytest = ">=6"
|
pytest = ">=6"
|
||||||
flake8 = "^4.0.1"
|
flake8 = "^4.0.1"
|
||||||
pytest-cov = "^3.0.0"
|
pytest-cov = "^3.0.0"
|
||||||
mypy = "^0.931"
|
mypy = "^0.942"
|
||||||
|
python-semantic-release = "^7.24.0"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["poetry-core>=1.0.0"]
|
||||||
@@ -32,3 +33,7 @@ module = [
|
|||||||
"scipy.optimize"
|
"scipy.optimize"
|
||||||
]
|
]
|
||||||
ignore_missing_imports = true
|
ignore_missing_imports = true
|
||||||
|
|
||||||
|
[tool.semantic_release]
|
||||||
|
version_toml = "pyproject.toml:tool.poetry.version"
|
||||||
|
tag_format = "{version}"
|
||||||
|
3
renovate.json
Normal file
3
renovate.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
|
||||||
|
}
|
@@ -1,29 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
set -Eeuo pipefail
|
|
||||||
|
|
||||||
if [ -z "$(git status --porcelain)" ]; then
|
|
||||||
# Working directory clean
|
|
||||||
branch_name=$(git symbolic-ref -q HEAD)
|
|
||||||
branch_name=${branch_name##refs/heads/}
|
|
||||||
branch_name=${branch_name:-HEAD}
|
|
||||||
|
|
||||||
poetry version patch
|
|
||||||
version=`sed 's/version = "\([0-9]*.[0-9]*.[0-9]*\)"/\1/p' -n <pyproject.toml`
|
|
||||||
read -p "Create commit for version $version? " -n 1 -r
|
|
||||||
echo # (optional) move to a new line
|
|
||||||
if [[ $REPLY =~ ^[Yy]$ ]]
|
|
||||||
then
|
|
||||||
# do dangerous stuff
|
|
||||||
echo "Creating a new patch"
|
|
||||||
git add pyproject.toml
|
|
||||||
git commit -m "Created version $version"
|
|
||||||
git tag -a "$version" -m "patch.sh created version $version"
|
|
||||||
git push --tags
|
|
||||||
else
|
|
||||||
echo "Surrendering, clean up by reverting pyproject.toml..."
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "Can't create patch version, working tree unclean..."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
45
scripts/release.sh
Normal file
45
scripts/release.sh
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -Eeuo pipefail
|
||||||
|
|
||||||
|
if [ -z "$(git status --porcelain)" ]; then
|
||||||
|
branch_name=$(git symbolic-ref -q HEAD)
|
||||||
|
branch_name=${branch_name##refs/heads/}
|
||||||
|
branch_name=${branch_name:-HEAD}
|
||||||
|
if [ $branch_name != "master" ]; then
|
||||||
|
echo "The current branch is not master!"
|
||||||
|
echo "I'd feel uncomfortable releasing from here..."
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
release_needed=false
|
||||||
|
if \
|
||||||
|
{ git log "$( git describe --tags --abbrev=0 )..HEAD" --format='%s' | cut -d: -f1 | sort -u | sed -e 's/([^)]*)//' | grep -q -i -E '^feat|fix|perf|refactor|revert$' ; } || \
|
||||||
|
{ git log "$( git describe --tags --abbrev=0 )..HEAD" --format='%s' | cut -d: -f1 | sort -u | sed -e 's/([^)]*)//' | grep -q -E '\!$' ; } || \
|
||||||
|
{ git log "$( git describe --tags --abbrev=0 )..HEAD" --format='%b' | grep -q -E '^BREAKING CHANGE:' ; }
|
||||||
|
then
|
||||||
|
release_needed=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ "$release_needed" = true ]; then
|
||||||
|
echo "No release needed..."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Working directory clean
|
||||||
|
echo "Doing a dry run..."
|
||||||
|
npx standard-version --dry-run
|
||||||
|
read -p "Does that look good? [y/N] " -n 1 -r
|
||||||
|
echo # (optional) move to a new line
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||||
|
then
|
||||||
|
# do dangerous stuff
|
||||||
|
npx standard-version
|
||||||
|
git push --follow-tags origin master
|
||||||
|
else
|
||||||
|
echo "okay, never mind then..."
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Can't create release, working tree unclean..."
|
||||||
|
exit 1
|
||||||
|
fi
|
11
scripts/standard-version/pyproject-updater.js
Normal file
11
scripts/standard-version/pyproject-updater.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
const pattern = /(\[tool\.poetry\]\nname = "deepdog"\nversion = ")(?<vers>\d+\.\d+\.\d)(")/mg;
|
||||||
|
|
||||||
|
module.exports.readVersion = function (contents) {
|
||||||
|
const result = pattern.exec(contents);
|
||||||
|
return result.groups.vers;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.writeVersion = function (contents, version) {
|
||||||
|
const newContents = contents.replace(pattern, `$1${version}$3`);
|
||||||
|
return newContents;
|
||||||
|
}
|
Reference in New Issue
Block a user