From 8419818a6c02daac596deaade1a1d4def57fc9b3 Mon Sep 17 00:00:00 2001 From: jammy2211 Date: Fri, 8 May 2020 11:45:35 +0100 Subject: [PATCH 1/2] making pool branch --- autofit/optimize/non_linear/emcee.py | 8 ++-- .../non_linear/nested_sampling/dynesty.py | 2 +- autofit/optimize/non_linear/non_linear.py | 6 ++- pyeuclid.sh | 19 ++++++++- pyeuclid_af.sh | 40 +++++-------------- test_autofit/unit/optimize/test_emcee.py | 3 ++ 6 files changed, 42 insertions(+), 36 deletions(-) diff --git a/autofit/optimize/non_linear/emcee.py b/autofit/optimize/non_linear/emcee.py index 8eb59612f..e0c90562f 100644 --- a/autofit/optimize/non_linear/emcee.py +++ b/autofit/optimize/non_linear/emcee.py @@ -1,11 +1,9 @@ import logging -import math import os - import emcee import numpy as np +import multiprocessing as mp -from autofit import conf from autofit import exc from autofit.text import samples_text from autofit.optimize.non_linear import samples @@ -161,6 +159,9 @@ def copy_with_name_extension(self, extension, remove_phase_tag=False): copy.sigma = self.sigma copy.nwalkers = self.nwalkers copy.nsteps = self.nsteps + copy.initialize_method = self.initialize_method + copy.initialize_ball_lower_limit = self.initialize_ball_lower_limit + copy.initialize_ball_upper_limit = self.initialize_ball_upper_limit copy.auto_correlation_check_for_convergence = self.auto_correlation_check_for_convergence copy.auto_correlation_check_size = self.auto_correlation_check_size copy.auto_correlation_required_length = self.auto_correlation_required_length @@ -194,6 +195,7 @@ def _full_fit(self, model, analysis): ndim=model.prior_count, log_prob_fn=fitness_function.__call__, backend=emcee.backends.HDFBackend(filename=self.paths.path + "/emcee.hdf"), + pool=mp.Pool(processes=2) ) try: diff --git a/autofit/optimize/non_linear/nested_sampling/dynesty.py b/autofit/optimize/non_linear/nested_sampling/dynesty.py index adbc83371..3102828eb 100644 --- a/autofit/optimize/non_linear/nested_sampling/dynesty.py +++ b/autofit/optimize/non_linear/nested_sampling/dynesty.py @@ -22,7 +22,6 @@ def __init__( self, paths=None, sigma=3, - iterations_per_update=None, bound=None, sample=None, bootstrap=None, @@ -37,6 +36,7 @@ def __init__( max_move=None, terminate_at_acceptance_ratio=None, acceptance_ratio_threshold=None, + iterations_per_update=None, ): """ Class to setup and run a Dynesty non-linear search. diff --git a/autofit/optimize/non_linear/non_linear.py b/autofit/optimize/non_linear/non_linear.py index 2b3c161ac..6881e9b1c 100644 --- a/autofit/optimize/non_linear/non_linear.py +++ b/autofit/optimize/non_linear/non_linear.py @@ -1,8 +1,8 @@ +from abc import ABC, abstractmethod import logging import shutil -from abc import ABC, abstractmethod - import numpy as np +import multiprocessing as mp from autofit import conf from autofit.mapper import model_mapper as mm @@ -230,6 +230,8 @@ def fit_instance(self, instance): if log_likelihood > self.max_log_likelihood: + print(mp.current_process()._identity[0]) + self.max_log_likelihood = log_likelihood if self.should_visualize(): diff --git a/pyeuclid.sh b/pyeuclid.sh index a5593d367..3443a16df 100644 --- a/pyeuclid.sh +++ b/pyeuclid.sh @@ -1,2 +1,19 @@ +cd /home/jammy/PycharmProjects/PyAuto/PyAutoFit/ + source pyeuclid_conf.sh -source pyeuclid_af.sh \ No newline at end of file + +cd /home/jammy/PycharmProjects/PyAuto/PyAutoFit/ + +source pyeuclid_af.sh + +# Permissions + +chmod -R 777 ../VIS_AutoFit +chmod -R 777 ../VIS_AutoFit/* +chmod -R 777 ../VIS_AutoFit/*/* +chmod -R 777 ../VIS_AutoFit/*/*/* +chmod -R 777 ../VIS_AutoFit/*/*/*/* +chmod -R 777 ../VIS_AutoFit/*/*/*/*/* +chmod -R 777 ../VIS_AutoFit/*/*/*/*/*/* + +cd /home/jammy/PycharmProjects/PyAuto/PyAutoFit/ \ No newline at end of file diff --git a/pyeuclid_af.sh b/pyeuclid_af.sh index fff6b3b8c..2cc7e53dd 100644 --- a/pyeuclid_af.sh +++ b/pyeuclid_af.sh @@ -1,40 +1,22 @@ +cd /home/jammy/PycharmProjects/PyAuto/PyAutoFit/ # cp -r test_autoconf/unit/conftest.py ../../PyEuclid/VIS_AutoFit/ -cd /home/jammy/PycharmProjects/PyAuto/PyAutoConf/ - cp -r autofit/mapper/prior/* ../../PyEuclid/VIS_AutoFit/VIS_AutoFit_Prior/python/VIS_AutoFit_Prior/ -cp -r test_autofit/unit/mapper/prior/* ../../PyEuclid/VIS_CTI/VIS_CTI_Dataset/tests/python/ - -cd /home/jammy/PycharmProjects/PyEuclid/VIS_AutoFit/ +cp -r autofit/mapper/prior_model/* ../../PyEuclid/VIS_AutoFit/VIS_AutoFit_PriorModel/python/VIS_AutoFit_PriorModel/ +cp -r autofit/mapper/*.py ../../PyEuclid/VIS_AutoFit/VIS_AutoFit_Model/python/VIS_AutoFit_Model/ -cp -r VIS_AutoFit_Conf/python/VIS_AutoFit_Conf/json_prior/config.py VIS_AutoFit_Conf/python/VIS_AutoFit_Conf/config.py -cp -r VIS_AutoFit_Conf/python/VIS_AutoFit_Conf/json_prior/converter.py VIS_AutoFit_Conf/python/VIS_AutoFit_Conf/converter.py -cp -r VIS_AutoFit_Conf/tests/python/json_prior/* VIS_AutoFit_Conf/tests/python/ +# cp -r test_autofit/unit/mapper/prior/* ../../PyEuclid/VIS_CTI/VIS_CTI_Dataset/tests/python/ -rm -rf cp -r VIS_AutoFit_Conf/python/VIS_AutoFit_Conf/json_prior/ -rm -rf cp -r VIS_AutoFit_Conf/tests/python/json_prior/ +cd /home/jammy/PycharmProjects/PyEuclid/VIS_AutoFit/ # Conf -sed -i 's/from autoconf/from VIS_AutoFit_Conf/g' */*/*/*.py - -sed -i 's/import autoconf/import VIS_AutoFit_Conf/g' */*/*/*.py +sed -i 's/from autofit.mapper.prior/from VIS_AutoFit_Prior/g' */*/*/*.py +sed -i 's/from autofit.mapper.prior/from VIS_AutoFit_Prior/g' */*/*/*/*.py -sed -i 's/return autoconf/return VIS_AutoFit_Conf/g' */*/*/*.py +sed -i 's/from autofit.mapper.prior_model/from VIS_AutoFit_PriorModel/g' */*/*/*.py +sed -i 's/from autofit.mapper.prior_model/from VIS_AutoFit_PriorModel/g' */*/*/*/*.py -sed -i 's/from test_autoconf/from VIS_AutoFit_Conf.tests/g' */*/*/*.py - -sed -i 's/.json_prior//g' */*/*/*.py - -# Permissions - -chmod -R 777 ../VIS_AutoFit -chmod -R 777 ../VIS_AutoFit/* -chmod -R 777 ../VIS_AutoFit/*/* -chmod -R 777 ../VIS_AutoFit/*/*/* -chmod -R 777 ../VIS_AutoFit/*/*/*/* -chmod -R 777 ../VIS_AutoFit/*/*/*/*/* -chmod -R 777 ../VIS_AutoFit/*/*/*/*/*/* - -cd /home/jammy/PycharmProjects/PyAuto/PyAutoFit/ +sed -i 's/from autofit.mapper/from VIS_AutoFit_Mapper/g' */*/*/*.py +sed -i 's/from autofit.mapper/from VIS_AutoFit_Mapper/g' */*/*/*/*.py diff --git a/test_autofit/unit/optimize/test_emcee.py b/test_autofit/unit/optimize/test_emcee.py index fc1e71b09..a29b1bf7f 100644 --- a/test_autofit/unit/optimize/test_emcee.py +++ b/test_autofit/unit/optimize/test_emcee.py @@ -137,6 +137,9 @@ def test_emcee(self): assert copy.sigma is optimizer.sigma assert copy.nwalkers is optimizer.nwalkers assert copy.nsteps is optimizer.nsteps + assert copy.initialize_method is optimizer.initialize_method + assert copy.initialize_ball_lower_limit is optimizer.initialize_ball_lower_limit + assert copy.initialize_ball_upper_limit is optimizer.initialize_ball_upper_limit assert copy.auto_correlation_check_for_convergence is optimizer.auto_correlation_check_for_convergence assert copy.auto_correlation_check_size is optimizer.auto_correlation_check_size assert ( From fcf4fe593acf7b743409843aeb39660d2672026d Mon Sep 17 00:00:00 2001 From: jammy2211 Date: Sat, 9 May 2020 12:06:24 +0100 Subject: [PATCH 2/2] parallelization of Dynesty implemented. --- autofit/optimize/non_linear/emcee.py | 54 +++++++++++++++--- .../non_linear/nested_sampling/dynesty.py | 33 ++++++++--- autofit/optimize/non_linear/non_linear.py | 55 +++++++++++++++++-- .../unit/config/non_linear/DynestyDynamic.ini | 5 +- .../unit/config/non_linear/DynestyStatic.ini | 5 +- test_autofit/unit/config/non_linear/Emcee.ini | 5 +- .../files/emcee/config/non_linear/Emcee.ini | 5 +- .../config/non_linear/DynestyDynamic.ini | 5 +- .../config/non_linear/DynestyStatic.ini | 5 +- .../config/non_linear/DynestyStatic.ini | 5 +- .../optimize/nested_sampler/test_dynesty.py | 8 +++ test_autofit/unit/optimize/test_emcee.py | 7 +++ 12 files changed, 166 insertions(+), 26 deletions(-) diff --git a/autofit/optimize/non_linear/emcee.py b/autofit/optimize/non_linear/emcee.py index e0c90562f..ac2b40a06 100644 --- a/autofit/optimize/non_linear/emcee.py +++ b/autofit/optimize/non_linear/emcee.py @@ -28,6 +28,7 @@ def __init__( auto_correlation_check_size=None, auto_correlation_required_length=None, auto_correlation_change_threshold=None, + number_of_cores=None, ): """ Class to setup and run an Emcee non-linear search. @@ -38,11 +39,17 @@ def __init__( https://emcee.readthedocs.io/en/stable/ - **PyAutoFit** extends **emcee** by providing an option to check the auto-correlation length of the samples - during the run and terminating sampling early if these meet a specified threshold. See this page - (https://emcee.readthedocs.io/en/stable/tutorials/autocorr/#autocorr) for a description of how this is implemented. + Extensions: - If you use *emcee* as part of a published work, please cite the package following the instructions under the + **PyAutoFit** provides the option to check the auto-correlation length of the samples during the run and + terminating sampling early if these meet a specified threshold. See this page + (https://emcee.readthedocs.io/en/stable/tutorials/autocorr/#autocorr) for a description. + + **PyAutoFit** also provides different options for walker initialization, with the default 'ball' method + starting all walkers close to one another in parameter space, as recommended in the Emcee documentation + (https://emcee.readthedocs.io/en/stable/user/faq/). + + If you use *Emcee* as part of a published work, please cite the package following the instructions under the *Attribution* section of the GitHub page. Parameters @@ -63,6 +70,20 @@ def __init__( Whether the auto-correlation lengths of the MCMC samples should be checked to determine the stopping criteria. If *True*, this option may terminate the Emcee run before the input number of steps, nsteps, has been performed. If *False* nstep samples will be taken. + initialize_method : str + The method used to generate where walkers are initialized in parameter space, with options: + ball (default): + Walkers are initialized by randomly drawing unit values from a uniform distribution between the + initialize_ball_lower_limit and initialize_ball_upper_limit values. It is recommended these limits are + small, such that all walkers begin close to one another. + prior: + Walkers are initialized by randomly drawing unit values from a uniform distribution between 0 and 1, + thus being fully distributed over the prior. + initialize_ball_upper_limit : float + The lower limit of the uniform distribution unit values are drawn from when initializing walkers using the + ball method. + The upper limit of the uniform distribution unit values are drawn from when initializing walkers using the + ball method. auto_correlation_check_size : int The length of the samples used to check the auto-correlation lengths (from the latest sample backwards). For convergence, the auto-correlations must not change over a certain range of samples. A longer check-size @@ -74,11 +95,20 @@ def __init__( auto_correlation_change_threshold : float The threshold value by which if the change in auto_correlations is below sampling will be terminated early, as it has been determined as converged. + number_of_cores : int + The number of cores Emcee sampling is performed using a Python multiprocessing Pool instance. If 1, a + pool instance is not created and the job runs in serial. All remaining attributes are emcee parameters and described at the emcee API webpage: https://emcee.readthedocs.io/en/stable/ + Attributes + ---------- + sigma : float + The error-bound value that linked Gaussian prior withs are computed using. For example, if sigma=3.0, + parameters will use Gaussian Priors with widths coresponding to errors estimated at 3 sigma confidence. + """ if paths is None: @@ -128,6 +158,12 @@ def __init__( else auto_correlation_change_threshold ) + self.number_of_cores = ( + self.config("parallel", "number_of_cores", int) + if number_of_cores is None + else number_of_cores + ) + logger.debug("Creating Emcee NLO") def _fit(self, model, analysis): @@ -166,6 +202,7 @@ def copy_with_name_extension(self, extension, remove_phase_tag=False): copy.auto_correlation_check_size = self.auto_correlation_check_size copy.auto_correlation_required_length = self.auto_correlation_required_length copy.auto_correlation_change_threshold = self.auto_correlation_change_threshold + copy.number_of_cores = self.number_of_cores return copy @@ -186,8 +223,10 @@ def __call__(self, params): def _full_fit(self, model, analysis): + pool, pool_ids = self.make_pool() + fitness_function = self.fitness_function_from_model_and_analysis( - model=model, analysis=analysis + model=model, analysis=analysis, pool_ids=pool_ids, ) emcee_sampler = emcee.EnsembleSampler( @@ -195,7 +234,7 @@ def _full_fit(self, model, analysis): ndim=model.prior_count, log_prob_fn=fitness_function.__call__, backend=emcee.backends.HDFBackend(filename=self.paths.path + "/emcee.hdf"), - pool=mp.Pool(processes=2) + pool=pool, ) try: @@ -281,13 +320,14 @@ def backend(self) -> emcee.backends.HDFBackend: "The file emcee.hdf does not exist at the path " + self.paths.path ) - def fitness_function_from_model_and_analysis(self, model, analysis): + def fitness_function_from_model_and_analysis(self, model, analysis, pool_ids=None): return Emcee.Fitness( paths=self.paths, model=model, analysis=analysis, samples_from_model=self.samples_from_model, + pool_ids=pool_ids, ) def samples_from_model(self, model): diff --git a/autofit/optimize/non_linear/nested_sampling/dynesty.py b/autofit/optimize/non_linear/nested_sampling/dynesty.py index 3102828eb..09d516bf0 100644 --- a/autofit/optimize/non_linear/nested_sampling/dynesty.py +++ b/autofit/optimize/non_linear/nested_sampling/dynesty.py @@ -37,6 +37,7 @@ def __init__( terminate_at_acceptance_ratio=None, acceptance_ratio_threshold=None, iterations_per_update=None, + number_of_cores=None, ): """ Class to setup and run a Dynesty non-linear search. @@ -69,6 +70,9 @@ def __init__( acceptance_ratio_threshold : float The acceptance ratio threshold below which sampling terminates if *terminate_at_acceptance_ratio* is *True* (see *NestedSampler* for a full description of this feature). + number_of_cores : int + The number of cores Emcee sampling is performed using a Python multiprocessing Pool instance. If 1, a + pool instance is not created and the job runs in serial. Attributes ---------- @@ -125,6 +129,12 @@ def __init__( else iterations_per_update ) + self.number_of_cores = ( + self.config("parallel", "number_of_cores", int) + if number_of_cores is None + else number_of_cores + ) + logger.debug("Creating DynestyStatic NLO") def copy_with_name_extension(self, extension, remove_phase_tag=False): @@ -147,6 +157,7 @@ def copy_with_name_extension(self, extension, remove_phase_tag=False): copy.slices = self.slices copy.fmove = self.fmove copy.max_move = self.max_move + copy.number_of_cores = self.number_of_cores return copy @@ -171,6 +182,8 @@ def _fit(self, model: AbstractPriorModel, analysis) -> Result: of the full samples used by the fit. """ + pool, pool_ids = self.make_pool() + fitness_function = self.fitness_function_from_model_and_analysis( model=model, analysis=analysis ) @@ -193,12 +206,12 @@ def _fit(self, model: AbstractPriorModel, analysis) -> Result: # These hacks are necessary to be able to pickle the sampler. sampler.rstate = np.random - sampler.pool = None - sampler.M = map + sampler.pool = pool - # pool = Pool(processes=1) - # sampler.pool = None - # sampler.M = pool.map + if self.number_of_cores == 1: + sampler.M = map + else: + sampler.M = pool.map dynesty_finished = False @@ -281,7 +294,6 @@ def __init__( self, paths=None, sigma=3, - iterations_per_update=None, n_live_points=None, bound=None, sample=None, @@ -297,6 +309,8 @@ def __init__( max_move=None, terminate_at_acceptance_ratio=None, acceptance_ratio_threshold=None, + iterations_per_update=None, + number_of_cores=None, ): """ Class to setup and run a Dynesty non-linear search, using the static Dynesty nested sampler described at this @@ -334,6 +348,7 @@ def __init__( max_move=max_move, terminate_at_acceptance_ratio=terminate_at_acceptance_ratio, acceptance_ratio_threshold=acceptance_ratio_threshold, + number_of_cores=number_of_cores, ) self.n_live_points = ( @@ -401,6 +416,7 @@ def __init__( max_move=None, terminate_at_acceptance_ratio=None, acceptance_ratio_threshold=None, + number_of_cores=None, ): """ Class to setup and run a Dynesty non-linear search, using the dynamic Dynesty nested sampler described at this @@ -438,6 +454,7 @@ def __init__( max_move=max_move, terminate_at_acceptance_ratio=terminate_at_acceptance_ratio, acceptance_ratio_threshold=acceptance_ratio_threshold, + number_of_cores=number_of_cores, ) logger.debug("Creating DynestyDynamic NLO") @@ -446,8 +463,8 @@ def sampler_fom_model_and_fitness(self, model, fitness_function): """Get the dynamic Dynesty sampler which performs the non-linear search, passing it all associated input Dynesty variables.""" return DynamicNestedSampler( - loglikelihood=fitness, - prior_transform=prior, + loglikelihood=fitness_function, + prior_transform=nl.NonLinearOptimizer.Fitness.prior, ndim=model.prior_count, logl_args=[model, fitness_function], ptform_args=[model], diff --git a/autofit/optimize/non_linear/non_linear.py b/autofit/optimize/non_linear/non_linear.py index 6881e9b1c..3065a97da 100644 --- a/autofit/optimize/non_linear/non_linear.py +++ b/autofit/optimize/non_linear/non_linear.py @@ -3,6 +3,7 @@ import shutil import numpy as np import multiprocessing as mp +from time import sleep from autofit import conf from autofit.mapper import model_mapper as mm @@ -15,7 +16,7 @@ class NonLinearOptimizer(ABC): @convert_paths - def __init__(self, paths=None): + def __init__(self, paths=None, number_of_cores=1): """Abstract base class for non-linear optimizers. This class sets up the file structure for the non-linear optimizer nlo, which are standardized across \ @@ -26,6 +27,8 @@ def __init__(self, paths=None): """ + + if paths is None: paths = Paths() @@ -45,6 +48,8 @@ def __init__(self, paths=None): self.paths.restore() + self.number_of_cores = number_of_cores + @classmethod def fit( cls, @@ -69,6 +74,7 @@ class represented by model M and gives a score for their fitness ------- A result comprising a score, the best fit instance and an updated prior model """ + optimizer = cls() result = optimizer._fit( @@ -196,7 +202,7 @@ def fitness(cube, model, fitness_function): return fitness_function(instance=model.instance_from_vector(cube)) def __init__( - self, paths, model, analysis, samples_from_model + self, paths, model, analysis, samples_from_model, pool_ids=None, ): self.paths = paths @@ -224,13 +230,17 @@ def __init__( self.model_results_output_interval ) + self.pool_ids = pool_ids + def fit_instance(self, instance): log_likelihood = self.analysis.log_likelihood_function(instance=instance) if log_likelihood > self.max_log_likelihood: - print(mp.current_process()._identity[0]) + if self.pool_ids is not None: + if mp.current_process().pid != min(self.pool_ids): + return log_likelihood self.max_log_likelihood = log_likelihood @@ -279,7 +289,7 @@ def copy_with_name_extension(self, extension, remove_phase_tag=False): phase_tag=phase_tag, non_linear_name=self.paths.non_linear_name, remove_files=self.paths.remove_files, - ) + ), ) return new_instance @@ -287,6 +297,32 @@ def copy_with_name_extension(self, extension, remove_phase_tag=False): def samples_from_model(self, model): raise NotImplementedError() + def make_pool(self): + """Make the pool instance used to parallelize a non-linear search alongside a set of unique ids for every + process in the pool. If the specified number of cores is 1, a pool instance is not made and None is returned. + + The pool cannot be set as an attribute of the class itself because this prevents pickling, thus it is generated + via this function before calling the non-linear search. + + The pool instance is also set up with a list of unique pool ids, which are used during model-fitting to + identify a 'master core' (the one whose id value is lowest) which handles model result output, visualization, + etc.""" + + if self.number_of_cores == 1: + + return None, None + + else: + + manager = mp.Manager() + idQueue = manager.Queue() + + [idQueue.put(i) for i in range(self.number_of_cores)] + + pool = mp.Pool(processes=self.number_of_cores, initializer=init, initargs=(idQueue,)) + ids = pool.map(f, range(self.number_of_cores)) + + return pool, [id[1] for id in ids] class Analysis: def log_likelihood_function(self, instance): @@ -396,3 +432,14 @@ def __call__(self): return False self.count += 1 return self.count % self.interval == 0 + + +def init(queue): + global idx + idx = queue.get() + +def f(x): + global idx + process = mp.current_process() + sleep(1) + return (idx, process.pid, x * x) \ No newline at end of file diff --git a/test_autofit/unit/config/non_linear/DynestyDynamic.ini b/test_autofit/unit/config/non_linear/DynestyDynamic.ini index 7fcea0e07..10ebd9c28 100644 --- a/test_autofit/unit/config/non_linear/DynestyDynamic.ini +++ b/test_autofit/unit/config/non_linear/DynestyDynamic.ini @@ -13,4 +13,7 @@ fmove = 0.9 max_move = 100 [settings] -iterations_per_update = 500 \ No newline at end of file +iterations_per_update = 500 + +[parallel] +number_of_cores = 1 \ No newline at end of file diff --git a/test_autofit/unit/config/non_linear/DynestyStatic.ini b/test_autofit/unit/config/non_linear/DynestyStatic.ini index 521d154d2..e06c2c40f 100644 --- a/test_autofit/unit/config/non_linear/DynestyStatic.ini +++ b/test_autofit/unit/config/non_linear/DynestyStatic.ini @@ -14,4 +14,7 @@ fmove = 0.9 max_move = 100 [settings] -iterations_per_update = 500 \ No newline at end of file +iterations_per_update = 500 + +[parallel] +number_of_cores = 1 \ No newline at end of file diff --git a/test_autofit/unit/config/non_linear/Emcee.ini b/test_autofit/unit/config/non_linear/Emcee.ini index 48c24a469..28df15ea5 100644 --- a/test_autofit/unit/config/non_linear/Emcee.ini +++ b/test_autofit/unit/config/non_linear/Emcee.ini @@ -11,4 +11,7 @@ ball_upper_limit = 0.51 check_for_convergence = False check_size = 100 required_length = 50 -change_threshold = 0.01 \ No newline at end of file +change_threshold = 0.01 + +[parallel] +number_of_cores = 1 \ No newline at end of file diff --git a/test_autofit/unit/optimize/files/emcee/config/non_linear/Emcee.ini b/test_autofit/unit/optimize/files/emcee/config/non_linear/Emcee.ini index 2dc98be6c..f54154826 100644 --- a/test_autofit/unit/optimize/files/emcee/config/non_linear/Emcee.ini +++ b/test_autofit/unit/optimize/files/emcee/config/non_linear/Emcee.ini @@ -11,4 +11,7 @@ ball_upper_limit = 0.51 check_for_convergence = True check_size = 100 required_length = 50 -change_threshold = 0.01 \ No newline at end of file +change_threshold = 0.01 + +[parallel] +number_of_cores = 1 \ No newline at end of file diff --git a/test_autofit/unit/optimize/nested_sampler/files/dynesty/config/non_linear/DynestyDynamic.ini b/test_autofit/unit/optimize/nested_sampler/files/dynesty/config/non_linear/DynestyDynamic.ini index bc3b92e93..328649c3d 100644 --- a/test_autofit/unit/optimize/nested_sampler/files/dynesty/config/non_linear/DynestyDynamic.ini +++ b/test_autofit/unit/optimize/nested_sampler/files/dynesty/config/non_linear/DynestyDynamic.ini @@ -13,4 +13,7 @@ fmove = 0.8 max_move = 101 [settings] -iterations_per_update = 501 \ No newline at end of file +iterations_per_update = 501 + +[parallel] +number_of_cores = 4 \ No newline at end of file diff --git a/test_autofit/unit/optimize/nested_sampler/files/dynesty/config/non_linear/DynestyStatic.ini b/test_autofit/unit/optimize/nested_sampler/files/dynesty/config/non_linear/DynestyStatic.ini index 562e03e02..ced3c50e4 100644 --- a/test_autofit/unit/optimize/nested_sampler/files/dynesty/config/non_linear/DynestyStatic.ini +++ b/test_autofit/unit/optimize/nested_sampler/files/dynesty/config/non_linear/DynestyStatic.ini @@ -14,4 +14,7 @@ fmove = 0.9 max_move = 100 [settings] -iterations_per_update = 500 \ No newline at end of file +iterations_per_update = 500 + +[parallel] +number_of_cores = 1 \ No newline at end of file diff --git a/test_autofit/unit/optimize/nested_sampler/files/dynesty_unconverged/config/non_linear/DynestyStatic.ini b/test_autofit/unit/optimize/nested_sampler/files/dynesty_unconverged/config/non_linear/DynestyStatic.ini index 562e03e02..ced3c50e4 100644 --- a/test_autofit/unit/optimize/nested_sampler/files/dynesty_unconverged/config/non_linear/DynestyStatic.ini +++ b/test_autofit/unit/optimize/nested_sampler/files/dynesty_unconverged/config/non_linear/DynestyStatic.ini @@ -14,4 +14,7 @@ fmove = 0.9 max_move = 100 [settings] -iterations_per_update = 500 \ No newline at end of file +iterations_per_update = 500 + +[parallel] +number_of_cores = 1 \ No newline at end of file diff --git a/test_autofit/unit/optimize/nested_sampler/test_dynesty.py b/test_autofit/unit/optimize/nested_sampler/test_dynesty.py index 83cb225ac..35a085b25 100644 --- a/test_autofit/unit/optimize/nested_sampler/test_dynesty.py +++ b/test_autofit/unit/optimize/nested_sampler/test_dynesty.py @@ -55,6 +55,7 @@ def test__loads_from_config_file_if_not_input(self): max_move=101, terminate_at_acceptance_ratio=False, acceptance_ratio_threshold=0.5, + number_of_cores=2, ) assert dynesty.iterations_per_update == 501 @@ -73,6 +74,7 @@ def test__loads_from_config_file_if_not_input(self): assert dynesty.max_move == 101 assert dynesty.terminate_at_acceptance_ratio == False assert dynesty.acceptance_ratio_threshold == 0.5 + assert dynesty.number_of_cores == 2 dynesty = af.DynestyStatic() @@ -92,6 +94,7 @@ def test__loads_from_config_file_if_not_input(self): assert dynesty.max_move == 100 assert dynesty.terminate_at_acceptance_ratio == True assert dynesty.acceptance_ratio_threshold == 2.0 + assert dynesty.number_of_cores == 1 dynesty = af.DynestyDynamic( iterations_per_update=501, @@ -109,6 +112,7 @@ def test__loads_from_config_file_if_not_input(self): max_move=101, terminate_at_acceptance_ratio=False, acceptance_ratio_threshold=0.5, + number_of_cores=3 ) assert dynesty.iterations_per_update == 501 @@ -126,6 +130,7 @@ def test__loads_from_config_file_if_not_input(self): assert dynesty.max_move == 101 assert dynesty.terminate_at_acceptance_ratio == False assert dynesty.acceptance_ratio_threshold == 0.5 + assert dynesty.number_of_cores == 3 dynesty = af.DynestyDynamic() @@ -144,6 +149,7 @@ def test__loads_from_config_file_if_not_input(self): assert dynesty.max_move == 101 assert dynesty.terminate_at_acceptance_ratio == True assert dynesty.acceptance_ratio_threshold == 2.0 + assert dynesty.number_of_cores == 4 def test__samples_from_model(self): # Setup pickle of mock Dynesty sampler that the samples_from_model function uses. @@ -216,6 +222,7 @@ def test_dynesty(self): assert copy.slices == optimizer.slices assert copy.fmove == optimizer.fmove assert copy.max_move == optimizer.max_move + assert copy.number_of_cores == optimizer.number_of_cores optimizer = af.DynestyDynamic(Paths("phase_name"), sigma=2.0) @@ -242,3 +249,4 @@ def test_dynesty(self): assert copy.slices == optimizer.slices assert copy.fmove == optimizer.fmove assert copy.max_move == optimizer.max_move + assert copy.number_of_cores == optimizer.number_of_cores \ No newline at end of file diff --git a/test_autofit/unit/optimize/test_emcee.py b/test_autofit/unit/optimize/test_emcee.py index a29b1bf7f..60f907afb 100644 --- a/test_autofit/unit/optimize/test_emcee.py +++ b/test_autofit/unit/optimize/test_emcee.py @@ -31,6 +31,7 @@ def test__loads_from_config_file_correct(self): auto_correlation_check_size=101, auto_correlation_required_length=51, auto_correlation_change_threshold=0.02, + number_of_cores=2, ) assert emcee.nwalkers == 51 @@ -42,6 +43,7 @@ def test__loads_from_config_file_correct(self): assert emcee.auto_correlation_check_size == 101 assert emcee.auto_correlation_required_length == 51 assert emcee.auto_correlation_change_threshold == 0.02 + assert emcee.number_of_cores == 2 emcee = af.Emcee() @@ -54,6 +56,7 @@ def test__loads_from_config_file_correct(self): assert emcee.auto_correlation_check_size == 100 assert emcee.auto_correlation_required_length == 50 assert emcee.auto_correlation_change_threshold == 0.01 + assert emcee.number_of_cores == 1 def test__samples_from_model(self): @@ -150,3 +153,7 @@ def test_emcee(self): copy.auto_correlation_change_threshold is optimizer.auto_correlation_change_threshold ) + assert ( + copy.number_of_cores + is optimizer.number_of_cores + ) \ No newline at end of file