From 979496462e34c9041de11bdbf5630f70e4666adf Mon Sep 17 00:00:00 2001 From: Arnaud De-Mattia Date: Mon, 26 Sep 2022 15:19:58 +0200 Subject: [PATCH 01/15] support for input Python MPI communicator --- pypolychord/_pypolychord.cpp | 40 ++++++++++++++++++++------------ pypolychord/polychord.py | 23 ++++++++++-------- run_pypolychord.py | 2 +- setup.py | 36 +++++++++++++++++++--------- src/drivers/polychord_CC.cpp | 2 +- src/drivers/polychord_CC_ini.cpp | 3 +-- 6 files changed, 66 insertions(+), 40 deletions(-) diff --git a/pypolychord/_pypolychord.cpp b/pypolychord/_pypolychord.cpp index 72b88ab5..46fff485 100644 --- a/pypolychord/_pypolychord.cpp +++ b/pypolychord/_pypolychord.cpp @@ -5,6 +5,10 @@ #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include +#ifdef USE_MPI +#include +#include +#endif /* Initialize the module */ #ifdef PYTHON3 @@ -29,13 +33,13 @@ static PyObject *python_loglikelihood = NULL; double loglikelihood(double* theta, int nDims, double* phi, int nDerived) { /* Create a python version of theta */ - npy_intp theta_shape[] = {nDims}; + npy_intp theta_shape[] = {nDims}; PyObject *array_theta = PyArray_SimpleNewFromData(1, theta_shape, NPY_DOUBLE, theta); if (array_theta==NULL) throw PythonException(); PyArray_CLEARFLAGS(reinterpret_cast(array_theta), NPY_ARRAY_WRITEABLE); /* Create a python version of phi */ - npy_intp phi_shape[] = {nDerived}; + npy_intp phi_shape[] = {nDerived}; PyObject *array_phi = PyArray_SimpleNewFromData(1, phi_shape, NPY_DOUBLE, phi); if (array_phi==NULL) {Py_DECREF(array_theta); throw PythonException();} @@ -63,7 +67,7 @@ static PyObject *python_prior = NULL; void prior(double* cube, double* theta, int nDims) { /* create a python version of cube */ - npy_intp shape[] = {nDims}; + npy_intp shape[] = {nDims}; PyObject *array_cube = PyArray_SimpleNewFromData(1, shape, NPY_DOUBLE, cube); if (array_cube==NULL) throw PythonException(); PyArray_CLEARFLAGS(reinterpret_cast(array_cube), NPY_ARRAY_WRITEABLE); @@ -85,19 +89,19 @@ static PyObject *python_dumper = NULL; void dumper(int ndead, int nlive, int npars, double* live, double* dead, double* logweights, double logZ, double logZerr) { /* create a python version of live points */ - npy_intp live_shape[] = {nlive, npars}; + npy_intp live_shape[] = {nlive, npars}; PyObject *array_live = PyArray_SimpleNewFromData(2, live_shape, NPY_DOUBLE, live); if (array_live==NULL) throw PythonException(); PyArray_CLEARFLAGS(reinterpret_cast(array_live), NPY_ARRAY_WRITEABLE); /* create a python version of dead points */ - npy_intp dead_shape[] = {ndead, npars}; + npy_intp dead_shape[] = {ndead, npars}; PyObject *array_dead = PyArray_SimpleNewFromData(2, dead_shape, NPY_DOUBLE, dead); if (array_dead==NULL) {Py_DECREF(array_live); throw PythonException();} PyArray_CLEARFLAGS(reinterpret_cast(array_dead), NPY_ARRAY_WRITEABLE); /* create a python version of posterior weights */ - npy_intp logweights_shape[] = {ndead}; + npy_intp logweights_shape[] = {ndead}; PyObject *array_logweights = PyArray_SimpleNewFromData(1, logweights_shape, NPY_DOUBLE, logweights); if (array_logweights==NULL) {Py_DECREF(array_live); Py_DECREF(array_dead); throw PythonException();} PyArray_CLEARFLAGS(reinterpret_cast(array_logweights), NPY_ARRAY_WRITEABLE); @@ -121,12 +125,11 @@ static PyObject *run_pypolychord(PyObject *, PyObject *args) Settings S; PyObject *temp_logl, *temp_prior, *temp_dumper; - PyObject* py_grade_dims, *py_grade_frac, *py_nlives; + PyObject* py_grade_dims, *py_grade_frac, *py_nlives, *py_comm; char* base_dir, *file_root; - if (!PyArg_ParseTuple(args, - "OOOiiiiiiiiddidiiiiiiiiiiidissO!O!O!i:run", + "OOOiiiiiiiiddidiiiiiiiiiiidissO!O!O!iO:run", &temp_logl, &temp_prior, &temp_dumper, @@ -163,13 +166,14 @@ static PyObject *run_pypolychord(PyObject *, PyObject *args) &py_grade_dims, &PyDict_Type, &py_nlives, - &S.seed + &S.seed, + &py_comm ) ) return NULL; S.base_dir = base_dir; S.file_root = file_root; - + int nGrade = PyList_Size(py_grade_frac); S.grade_frac.resize(nGrade); S.grade_dims.resize(nGrade); @@ -216,14 +220,20 @@ static PyObject *run_pypolychord(PyObject *, PyObject *args) python_dumper = temp_dumper; /* Run PolyChord */ - try{ run_polychord(loglikelihood, prior, dumper, S); } + try{ +#ifdef USE_MPI + MPI_Comm comm = PyMPIComm_Get(py_comm); + run_polychord(loglikelihood, prior, dumper, S, comm); +#else + run_polychord(loglikelihood, prior, dumper, S); +#endif + } catch (PythonException& e) - { + { Py_DECREF(py_grade_frac);Py_DECREF(py_grade_dims);Py_DECREF(python_loglikelihood);Py_DECREF(python_prior); - return NULL; + return NULL; } /* Return None */ Py_RETURN_NONE; } - diff --git a/pypolychord/polychord.py b/pypolychord/polychord.py index 580fba94..74d89bee 100644 --- a/pypolychord/polychord.py +++ b/pypolychord/polychord.py @@ -13,7 +13,7 @@ def default_dumper(live, dead, logweights, logZ, logZerr): def run_polychord(loglikelihood, nDims, nDerived, settings, - prior=default_prior, dumper=default_dumper): + prior=default_prior, dumper=default_dumper, comm=None): """ Runs PolyChord. @@ -144,20 +144,22 @@ def run_polychord(loglikelihood, nDims, nDerived, settings, Final output evidence statistics """ - - try: - from mpi4py import MPI - comm = MPI.COMM_WORLD - rank = comm.Get_rank() - except ImportError: - rank = 0 + rank = 0 + if comm is None: + try: + from mpi4py import MPI + comm = MPI.COMM_WORLD + except ImportError: + pass + if comm is not None: + rank = comm.rank try: if rank == 0: os.makedirs(settings.base_dir) except OSError: pass - + try: if rank == 0: os.makedirs(settings.cluster_dir) @@ -213,7 +215,8 @@ def wrap_prior(cube, theta): settings.grade_frac, settings.grade_dims, settings.nlives, - settings.seed) + settings.seed, + comm) if settings.cube_samples is not None: settings.read_resume = read_resume diff --git a/run_pypolychord.py b/run_pypolychord.py index 465c3543..50b09e69 100755 --- a/run_pypolychord.py +++ b/run_pypolychord.py @@ -73,4 +73,4 @@ def dumper(live, dead, logweights, logZ, logZerr): except ImportError: print("Install matplotlib and getdist for plotting examples") - print("Install anesthetic or getdist for for plotting examples") + print("Install anesthetic or getdist for plotting examples") diff --git a/setup.py b/setup.py index 17b939eb..19a39e02 100644 --- a/setup.py +++ b/setup.py @@ -3,13 +3,13 @@ Polychord is a tool to solve high dimensional problems. """ +import os, sys, subprocess, shutil from setuptools import setup, Extension, find_packages, Distribution from setuptools.command.build_py import build_py as _build_py +from setuptools.command.develop import develop as _develop from distutils.command.clean import clean as _clean -import os, sys, subprocess, shutil - import numpy def check_compiler(default_CC="gcc"): @@ -17,7 +17,7 @@ def check_compiler(default_CC="gcc"): CC = default_CC if "CC" not in os.environ else os.environ["CC"] CC_version = subprocess.check_output([CC, "-v"], stderr=subprocess.STDOUT).decode("utf-8").lower() - + if "clang" in CC_version: CC_family = "clang" elif "icc" in CC_version: @@ -63,7 +63,8 @@ def get_version(short=False): return line[44:50] -class DistributionWithOption(Distribution, object): +class DistributionWithOption(Distribution): + def __init__(self, *args, **kwargs): self.global_options = self.global_options \ + [("no-mpi", None, "Don't compile with MPI support."), @@ -72,7 +73,9 @@ def __init__(self, *args, **kwargs): self.debug_flags = None super(DistributionWithOption, self).__init__(*args, **kwargs) -class CustomBuildPy(_build_py, object): + +class CustomBuildPy(_build_py): + def run(self): env = {} env["PATH"] = os.environ["PATH"] @@ -90,23 +93,33 @@ def run(self): if self.distribution.debug_flags is not None: self.distribution.ext_modules[0].extra_compile_args += ["-g", "-O0"] env["DEBUG"] = "1" - + BASE_PATH = os.path.dirname(os.path.abspath(__file__)) env["PWD"] = BASE_PATH - env.update({k : os.environ[k] for k in ["CC", "CXX", "FC"] if k in os.environ}) + env.update({k: os.environ[k] for k in ["CC", "CXX", "FC"] if k in os.environ}) subprocess.check_call(["make", "-e", "libchord.so"], env=env, cwd=BASE_PATH) if not os.path.isdir("pypolychord/lib/"): os.makedirs(os.path.join(BASE_PATH, "pypolychord/lib/")) - shutil.copy(os.path.join(BASE_PATH, "lib/libchord.so"), + shutil.copy(os.path.join(BASE_PATH, "lib/libchord.so"), os.path.join(BASE_PATH, "pypolychord/lib/")) self.run_command("build_ext") return super(CustomBuildPy, self).run() + +class CustomDevelop(_develop): + + def run(self): + self.run_command('build_py') + super(CustomDevelop, self).run() + + class CustomClean(_clean): + def run(self): subprocess.run(["make", "veryclean"], check=True, env=os.environ) return super().run() + if "--no-mpi" in sys.argv: NAME += '_nompi' DOCLINES[1] = DOCLINES[1] + ' (cannot be used with MPI)' @@ -134,8 +147,9 @@ def run(self): extras_require={'plotting': 'getdist'}, distclass=DistributionWithOption, ext_modules=[pypolychord_module], - cmdclass={'build_py' : CustomBuildPy, - 'clean' : CustomClean}, - package_data={"" : ["lib/libchord.so"]}, + cmdclass={'build_py': CustomBuildPy, + 'develop': CustomDevelop, + 'clean': CustomClean}, + package_data={"": ["lib/libchord.so"]}, include_package_data=True, zip_safe=False) diff --git a/src/drivers/polychord_CC.cpp b/src/drivers/polychord_CC.cpp index af2eed91..c400ce0d 100644 --- a/src/drivers/polychord_CC.cpp +++ b/src/drivers/polychord_CC.cpp @@ -36,7 +36,7 @@ int main() settings.boost_posterior= 5.0; setup_loglikelihood(); - run_polychord(loglikelihood,prior,dumper,settings) ; + run_polychord(loglikelihood,prior,dumper,settings); } diff --git a/src/drivers/polychord_CC_ini.cpp b/src/drivers/polychord_CC_ini.cpp index 02a18e41..ae5704aa 100644 --- a/src/drivers/polychord_CC_ini.cpp +++ b/src/drivers/polychord_CC_ini.cpp @@ -7,7 +7,7 @@ int main(int argc, char *argv[]) if (argc > 1) { std::string input_file = argv[1]; set_ini(input_file); - run_polychord(loglikelihood,setup_loglikelihood,input_file) ; + run_polychord(loglikelihood,setup_loglikelihood,input_file); return 0; } else{ @@ -15,4 +15,3 @@ int main(int argc, char *argv[]) return 1; } } - From 713898635d3411658050b37a4e8a4e039d64739c Mon Sep 17 00:00:00 2001 From: Arnaud De-Mattia Date: Wed, 5 Oct 2022 18:04:20 +0200 Subject: [PATCH 02/15] compile extension with MPI, and avoid use of ANY_TAG --- pypolychord/_pypolychord.cpp | 10 +- setup.py | 18 ++- src/polychord/c_interface.cpp | 80 +++++----- src/polychord/mpi_utils.F90 | 273 ++++++++++++++++++---------------- 4 files changed, 211 insertions(+), 170 deletions(-) diff --git a/pypolychord/_pypolychord.cpp b/pypolychord/_pypolychord.cpp index 46fff485..8b3de6ce 100644 --- a/pypolychord/_pypolychord.cpp +++ b/pypolychord/_pypolychord.cpp @@ -15,6 +15,9 @@ PyMODINIT_FUNC PyInit__pypolychord(void) { import_array(); +#ifdef USE_MPI + import_mpi4py(); +#endif return PyModule_Create(&_pypolychordmodule); } #else @@ -22,6 +25,9 @@ PyMODINIT_FUNC init_pypolychord(void) { Py_InitModule3("_pypolychord", module_methods, module_docstring); import_array(); +#ifdef USE_MPI + import_mpi4py(); +#endif } #endif @@ -222,8 +228,8 @@ static PyObject *run_pypolychord(PyObject *, PyObject *args) /* Run PolyChord */ try{ #ifdef USE_MPI - MPI_Comm comm = PyMPIComm_Get(py_comm); - run_polychord(loglikelihood, prior, dumper, S, comm); + MPI_Comm *comm = PyMPIComm_Get(py_comm); + run_polychord(loglikelihood, prior, dumper, S, *comm); #else run_polychord(loglikelihood, prior, dumper, S); #endif diff --git a/setup.py b/setup.py index 19a39e02..b3dae1d4 100644 --- a/setup.py +++ b/setup.py @@ -12,6 +12,15 @@ import numpy + +try: + import mpi4py +except ImportError: + mpi4py_get_include = None +else: + mpi4py_get_include = mpi4py.get_include() + + def check_compiler(default_CC="gcc"): """Checks what compiler is being used (clang, intel, or gcc).""" @@ -120,14 +129,21 @@ def run(self): return super().run() +include_dirs = ['src/polychord', numpy.get_include()] + if "--no-mpi" in sys.argv: NAME += '_nompi' DOCLINES[1] = DOCLINES[1] + ' (cannot be used with MPI)' +elif mpi4py_get_include: + CPPRUNTIMELIB_FLAG += ["-DUSE_MPI"] + include_dirs += [mpi4py_get_include] + + pypolychord_module = Extension( name='_pypolychord', library_dirs=['lib'], - include_dirs=['src/polychord', numpy.get_include()], + include_dirs=include_dirs, libraries=['chord',], extra_link_args=RPATH_FLAG + CPPRUNTIMELIB_FLAG, extra_compile_args= ["-std=c++11"] + RPATH_FLAG + CPPRUNTIMELIB_FLAG, diff --git a/src/polychord/c_interface.cpp b/src/polychord/c_interface.cpp index bbd44cb7..1f1c556d 100644 --- a/src/polychord/c_interface.cpp +++ b/src/polychord/c_interface.cpp @@ -3,10 +3,10 @@ #include // Constructor for settings struct -Settings::Settings(int _nDims,int _nDerived): +Settings::Settings(int _nDims,int _nDerived): nDims {_nDims}, nDerived {_nDerived}, - nlive {500}, + nlive {500}, num_repeats {nDims*5}, nprior {-1}, nfail {-1}, @@ -42,16 +42,16 @@ Settings::Settings(int _nDims,int _nDerived): #ifdef USE_MPI -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_prior_ptr)(double*,double*,int), - void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_prior_ptr)(double*,double*,int), + void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), Settings s, MPI_Comm& comm) #else -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_prior_ptr)(double*,double*,int), - void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_prior_ptr)(double*,double*,int), + void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), Settings s) #endif { @@ -70,11 +70,11 @@ void run_polychord( int fortran_comm = 0; #endif - polychord_c_interface( - c_loglikelihood_ptr, - c_prior_ptr, - c_dumper_ptr, - s.nlive, + polychord_c_interface( + c_loglikelihood_ptr, + c_prior_ptr, + c_dumper_ptr, + s.nlive, s.num_repeats, s.nprior, s.nfail, @@ -118,10 +118,10 @@ void run_polychord( #ifdef USE_MPI // In this function no MPI communicator is given, so a communicator is automatically // made from MPI_COMM_WORLD -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_prior_ptr)(double*,double*,int), - void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_prior_ptr)(double*,double*,int), + void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), Settings s) { int flag; @@ -132,47 +132,47 @@ void run_polychord( run_polychord(c_loglikelihood_ptr,c_prior_ptr,c_dumper_ptr,s,world_comm); if (flag==0) MPI_Finalize(); } -void run_polychord( +void run_polychord( double (*loglikelihood)(double*,int,double*,int), - void (*dumper)(int,int,int,double*,double*,double*,double,double), + void (*dumper)(int,int,int,double*,double*,double*,double,double), Settings S, MPI_Comm &comm) -{ run_polychord(loglikelihood,default_prior,dumper,S,comm); } -void run_polychord( +{ run_polychord(loglikelihood,default_prior,dumper,S,comm); } +void run_polychord( double (*loglikelihood)(double*,int,double*,int), void (*prior)(double*,double*,int), Settings S, MPI_Comm &comm) -{ run_polychord(loglikelihood,prior,default_dumper,S,comm); } +{ run_polychord(loglikelihood,prior,default_dumper,S,comm); } void run_polychord( double (*loglikelihood)(double*,int,double*,int), Settings S, MPI_Comm &comm) -{ run_polychord(loglikelihood,default_prior,default_dumper,S,comm); } +{ run_polychord(loglikelihood,default_prior,default_dumper,S,comm); } #endif -void run_polychord( +void run_polychord( double (*loglikelihood)(double*,int,double*,int), - void (*dumper)(int,int,int,double*,double*,double*,double,double), + void (*dumper)(int,int,int,double*,double*,double*,double,double), Settings S) -{ run_polychord(loglikelihood,default_prior,dumper,S); } -void run_polychord( +{ run_polychord(loglikelihood,default_prior,dumper,S); } +void run_polychord( double (*loglikelihood)(double*,int,double*,int), void (*prior)(double*,double*,int), Settings S) -{ run_polychord(loglikelihood,prior,default_dumper,S); } +{ run_polychord(loglikelihood,prior,default_dumper,S); } void run_polychord( double (*loglikelihood)(double*,int,double*,int), Settings S) -{ run_polychord(loglikelihood,default_prior,default_dumper,S); } +{ run_polychord(loglikelihood,default_prior,default_dumper,S); } #ifdef USE_MPI -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_setup_loglikelihood_ptr)(), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_setup_loglikelihood_ptr)(), std::string inifile, MPI_Comm &comm) #else -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_setup_loglikelihood_ptr)(), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_setup_loglikelihood_ptr)(), std::string inifile) #endif { @@ -192,9 +192,9 @@ void run_polychord( #ifdef USE_MPI // In this function no MPI communicator is given, so a communicator is automatically // made from MPI_COMM_WORLD -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_setup_loglikelihood_ptr)(), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_setup_loglikelihood_ptr)(), std::string inifile) { int flag; diff --git a/src/polychord/mpi_utils.F90 b/src/polychord/mpi_utils.F90 index 9a891b2a..316b4387 100644 --- a/src/polychord/mpi_utils.F90 +++ b/src/polychord/mpi_utils.F90 @@ -22,6 +22,9 @@ module mpi_module integer, parameter :: tag_run_epoch_babies=10 integer, parameter :: tag_run_stop=11 + integer, parameter :: tag_tag_gen=12 + integer, parameter :: tag_tag_run=13 + type mpi_bundle integer :: rank integer :: nprocs @@ -56,7 +59,7 @@ function get_mpi_information(mpi_communicator,colour) result(mpi_information) end function !> Returns whether this is the root node - function is_root(mpi_information) + function is_root(mpi_information) implicit none type(mpi_bundle),intent(in) :: mpi_information logical :: is_root @@ -66,7 +69,7 @@ function is_root(mpi_information) end function is_root !> Returns whether there is a single processor - function linear_mode(mpi_information) + function linear_mode(mpi_information) implicit none type(mpi_bundle),intent(in) :: mpi_information logical :: linear_mode @@ -84,7 +87,7 @@ function get_nprocs(mpi_communicator) result(nprocs) integer :: nprocs #ifdef MPI - call MPI_COMM_SIZE( & + call MPI_COMM_SIZE( & mpi_communicator,&!handle nprocs, &!return number of processors mpierror &!error flag @@ -104,9 +107,9 @@ function get_rank(mpi_communicator) result(myrank) integer :: myrank #ifdef MPI - call MPI_COMM_RANK( & + call MPI_COMM_RANK( & mpi_communicator,&!handle - myrank, &!return rank of calling processor + myrank, &!return rank of calling processor mpierror &!error flag ) #else @@ -134,7 +137,7 @@ function get_root(mpi_communicator) result(root) #ifdef MPI call MPI_ALLREDUCE( & - myrank, &!send buffer + myrank, &!send buffer root, &!recieve buffer 1, &!number of elements sent MPI_INTEGER, &!type of element sent @@ -219,7 +222,7 @@ subroutine mpi_synchronise(mpi_information) #ifdef MPI call MPI_BARRIER(mpi_information%communicator,mpierror) -#endif +#endif end subroutine mpi_synchronise @@ -237,7 +240,7 @@ function sum_integers(intgr_local,mpi_information) result(intgr) integer :: intgr call MPI_ALLREDUCE( & - intgr_local, &!send buffer + intgr_local, &!send buffer intgr, &!recieve buffer 1, &!number of elements sent MPI_INTEGER, &!type of element sent @@ -255,7 +258,7 @@ function sum_doubles(db_local,mpi_information) result(db) real(dp) :: db call MPI_ALLREDUCE( & - db_local, &!send buffer + db_local, &!send buffer db, &!recieve buffer 1, &!number of elements sent MPI_DOUBLE_PRECISION, &!type of element sent @@ -271,7 +274,7 @@ subroutine broadcast_doubles(doubles,mpi_information) real(dp), dimension(:), intent(inout) :: doubles type(mpi_bundle), intent(in) :: mpi_information - call MPI_BCAST( & + call MPI_BCAST( & doubles, &!broadcast buffer size(doubles), &!size of buffer MPI_DOUBLE_PRECISION, &!type of element sent @@ -287,7 +290,7 @@ subroutine broadcast_integers(integers,mpi_information) integer, dimension(:), intent(inout) :: integers type(mpi_bundle), intent(in) :: mpi_information - call MPI_BCAST( & + call MPI_BCAST( & integers, &!broadcast buffer size(integers), &!size of buffer MPI_INTEGER, &!type of element sent @@ -299,7 +302,7 @@ subroutine broadcast_integers(integers,mpi_information) end subroutine broadcast_integers !============== Throwing and catching routines ==================== - ! There are four points in the algorithm where arrays need to be transferred + ! There are four points in the algorithm where arrays need to be transferred ! between administrator and workers ! ! 1) live point during initial generation @@ -317,7 +320,7 @@ end subroutine broadcast_integers !> Root catch !! - !! This a process by which the root node 'catches' a thrown point from + !! This a process by which the root node 'catches' a thrown point from !! any worker, and returns the worker identifier for use to throw back function catch_point(live_point,mpi_information) result(worker_id) implicit none @@ -399,26 +402,26 @@ function catch_babies(baby_points,nlike,epoch,mpi_information) result(worker_id) ! Pass on the worker id worker_id = mpistatus(MPI_SOURCE) - call MPI_RECV( &! - nlike, &! - size(nlike), &! - MPI_INTEGER, &! - worker_id, &! - tag_run_nlike, &! - mpi_information%communicator,&! - mpistatus, &! - mpierror &! + call MPI_RECV( &! + nlike, &! + size(nlike), &! + MPI_INTEGER, &! + worker_id, &! + tag_run_nlike, &! + mpi_information%communicator,&! + mpistatus, &! + mpierror &! ) - call MPI_RECV( &! - epoch, &! - 1, &! - MPI_INTEGER, &! - worker_id, &! - tag_run_epoch_babies, &! - mpi_information%communicator,&! - mpistatus, &! - mpierror &! + call MPI_RECV( &! + epoch, &! + 1, &! + MPI_INTEGER, &! + worker_id, &! + tag_run_epoch_babies, &! + mpi_information%communicator,&! + mpistatus, &! + mpierror &! ) end function catch_babies @@ -432,32 +435,32 @@ subroutine throw_babies(baby_points,nlike,epoch,mpi_information) integer, intent(in) :: epoch !> The epoch the babies were generated in type(mpi_bundle), intent(in) :: mpi_information - call MPI_SEND( &! - baby_points, &! - size(baby_points,1)*size(baby_points,2),&! - MPI_DOUBLE_PRECISION, &! - mpi_information%root, &! - tag_run_baby, &! - mpi_information%communicator, &! - mpierror &! - ) - call MPI_SEND( &! - nlike, &! - size(nlike), &! - MPI_INTEGER, &! - mpi_information%root, &! - tag_run_nlike, &! - mpi_information%communicator,&! - mpierror &! + call MPI_SEND( &! + baby_points, &! + size(baby_points,1)*size(baby_points,2),&! + MPI_DOUBLE_PRECISION, &! + mpi_information%root, &! + tag_run_baby, &! + mpi_information%communicator, &! + mpierror &! + ) + call MPI_SEND( &! + nlike, &! + size(nlike), &! + MPI_INTEGER, &! + mpi_information%root, &! + tag_run_nlike, &! + mpi_information%communicator,&! + mpierror &! ) - call MPI_SEND( &! - epoch, &! - 1, &! - MPI_INTEGER, &! - mpi_information%root, &! - tag_run_epoch_babies, &! - mpi_information%communicator,&! - mpierror &! + call MPI_SEND( &! + epoch, &! + 1, &! + MPI_INTEGER, &! + mpi_information%root, &! + tag_run_epoch_babies, &! + mpi_information%communicator,&! + mpierror &! ) end subroutine throw_babies @@ -476,6 +479,7 @@ function catch_seed(seed_point,cholesky,logL,epoch,mpi_information) result(more_ real(dp),intent(out),dimension(:) :: seed_point !> The seed point to be caught real(dp),intent(out),dimension(:,:) :: cholesky !> Cholesky matrix to be caught real(dp),intent(out) :: logL !> loglikelihood contour to be caught + integer :: tag_run integer, intent(out) :: epoch type(mpi_bundle), intent(in) :: mpi_information @@ -483,26 +487,37 @@ function catch_seed(seed_point,cholesky,logL,epoch,mpi_information) result(more_ integer, dimension(MPI_STATUS_SIZE) :: mpistatus ! status identifier - call MPI_RECV( &! - seed_point, &! - size(seed_point), &! - MPI_DOUBLE_PRECISION, &! + tag_run, &! + 1, &! + MPI_INTEGER, &! mpi_information%root, &! - MPI_ANY_TAG, &! + tag_tag_run, &! mpi_information%communicator,&! mpistatus, &! mpierror &! ) - if(mpistatus(MPI_TAG) == tag_run_stop ) then + + if(tag_run == tag_run_stop) then more_points_needed = .false. return - else if(mpistatus(MPI_TAG) == tag_run_seed) then + else if(tag_run == tag_run_seed) then more_points_needed = .true. else call halt_program('worker error: unrecognised tag') end if + call MPI_RECV( &! + seed_point, &! + size(seed_point), &! + MPI_DOUBLE_PRECISION, &! + mpi_information%root, &! + tag_run, &! + mpi_information%communicator,&! + mpistatus, &! + mpierror &! + ) + call MPI_RECV( &! cholesky, &! size(cholesky,1)*size(cholesky,1),&! @@ -523,15 +538,15 @@ function catch_seed(seed_point,cholesky,logL,epoch,mpi_information) result(more_ mpistatus, &! mpierror &! ) - call MPI_RECV( &! - epoch, &! - 1, &! - MPI_INTEGER, &! - mpi_information%root, &! - tag_run_epoch_seed, &! - mpi_information%communicator,&! - mpistatus, &! - mpierror &! + call MPI_RECV( &! + epoch, &! + 1, &! + MPI_INTEGER, &! + mpi_information%root, &! + tag_run_epoch_seed, &! + mpi_information%communicator,&! + mpistatus, &! + mpierror &! ) end function catch_seed @@ -548,52 +563,61 @@ subroutine throw_seed(seed_point,cholesky,logL,mpi_information,worker_id,epoch,k type(mpi_bundle),intent(in) :: mpi_information !> mpi handle integer, intent(in) :: worker_id !> identity of target worker integer, intent(in) :: epoch !> epoch of seed - logical, intent(in) :: keep_going !> Further signal whether to keep going + logical, intent(in) :: keep_going !> Further signal whether to keep going - integer :: tag ! tag variable to + integer :: tag_run ! tag variable to - tag = tag_run_stop ! Default tag is stop tag - if(keep_going) tag = tag_run_seed ! If we want to keep going then change this to the seed tag + tag_run = tag_run_stop ! Default tag is stop tag + if(keep_going) tag_run = tag_run_seed ! If we want to keep going then change this to the seed tag - - call MPI_SEND( &! - seed_point, &! - size(seed_point), &! - MPI_DOUBLE_PRECISION, &! - worker_id, &! - tag, &! - mpi_information%communicator,&! - mpierror &! + call MPI_SEND( &! + tag_run, &! + 1, &! + MPI_INTEGER, &! + worker_id, &! + tag_tag_run, &! + mpi_information%communicator,&! + mpierror &! ) if(.not. keep_going) return ! Stop here if we're wrapping up - call MPI_SEND( &! - cholesky, &! - size(cholesky,1)*size(cholesky,2),&! - MPI_DOUBLE_PRECISION, &! - worker_id, &! - tag_run_cholesky, &! - mpi_information%communicator, &! - mpierror &! + call MPI_SEND( &! + seed_point, &! + size(seed_point), &! + MPI_DOUBLE_PRECISION, &! + worker_id, &! + tag_run, &! + mpi_information%communicator,&! + mpierror &! ) - call MPI_SEND( &! - logL, &! - 1, &! - MPI_DOUBLE_PRECISION, &! - worker_id, &! - tag_run_logL, &! - mpi_information%communicator,&! - mpierror &! + + call MPI_SEND( &! + cholesky, &! + size(cholesky,1)*size(cholesky,2),&! + MPI_DOUBLE_PRECISION, &! + worker_id, &! + tag_run_cholesky, &! + mpi_information%communicator, &! + mpierror &! + ) + call MPI_SEND( &! + logL, &! + 1, &! + MPI_DOUBLE_PRECISION, &! + worker_id, &! + tag_run_logL, &! + mpi_information%communicator,&! + mpierror &! ) - call MPI_SEND( &! - epoch, &! - 1, &! - MPI_INTEGER, &! - worker_id, &! - tag_run_epoch_seed, &! - mpi_information%communicator,&! - mpierror &! + call MPI_SEND( &! + epoch, &! + 1, &! + MPI_INTEGER, &! + worker_id, &! + tag_run_epoch_seed, &! + mpi_information%communicator,&! + mpierror &! ) @@ -609,7 +633,7 @@ end subroutine throw_seed ! administrator ----> worker ! request_point more_points_needed -> true ! no_more_points more_points_needed -> false - ! + ! !> Request point !! @@ -620,14 +644,12 @@ subroutine request_point(mpi_information,worker_id) integer, intent(in) :: worker_id !> Worker to request a new point from - integer :: empty_buffer(0) ! empty buffer to send - call MPI_SEND( & - empty_buffer, &! not sending anything - 0, &! size of nothing + tag_gen_request, &! not sending anything + 1, &! size of nothing MPI_INTEGER, &! sending no integers worker_id, &! process id to send to - tag_gen_request, &! continuation tag + tag_tag_gen, &! continuation tag mpi_information%communicator,&! mpi handle mpierror &! error flag ) @@ -643,15 +665,12 @@ subroutine no_more_points(mpi_information,worker_id) type(mpi_bundle), intent(in) :: mpi_information integer, intent(in) :: worker_id !> Worker to request a new point from - - integer :: empty_buffer(0) ! empty buffer to send - call MPI_SEND( & - empty_buffer, &! not sending anything - 0, &! size of nothing + tag_gen_stop, &! not sending anything + 1, &! size of nothing MPI_INTEGER, &! sending no integers worker_id, &! process id to send to - tag_gen_stop, &! continuation tag + tag_tag_gen, &! continuation tag mpi_information%communicator,&! mpi handle mpierror &! error flag ) @@ -666,26 +685,26 @@ function more_points_needed(mpi_information) implicit none type(mpi_bundle), intent(in) :: mpi_information - integer :: empty_buffer(0) ! empty buffer to send integer, dimension(MPI_STATUS_SIZE) :: mpistatus ! status identifier + integer :: tag_gen logical :: more_points_needed !> Whether we need more points or not call MPI_RECV( &! - empty_buffer, &! - 0, &! + tag_gen, &! + 1, &! MPI_INTEGER, &! mpi_information%root, &! - MPI_ANY_TAG, &! + tag_tag_gen, &! mpi_information%communicator,&! mpistatus, &! mpierror &! ) ! If we've recieved a kill signal, then exit this loop - if(mpistatus(MPI_TAG) == tag_gen_stop ) then + if(tag_gen == tag_gen_stop) then more_points_needed = .false. - else if(mpistatus(MPI_TAG) == tag_gen_request) then + else if(tag_gen == tag_gen_request) then more_points_needed = .true. else call halt_program('generate error: unrecognised tag') From fb33113b219d447a48468ae9afa5b41f653d295d Mon Sep 17 00:00:00 2001 From: adematti Date: Tue, 6 Dec 2022 00:44:35 -0800 Subject: [PATCH 03/15] simplifying setup.py for NERSC --- setup.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/setup.py b/setup.py index b3dae1d4..883595e6 100644 --- a/setup.py +++ b/setup.py @@ -86,27 +86,23 @@ def __init__(self, *args, **kwargs): class CustomBuildPy(_build_py): def run(self): - env = {} - env["PATH"] = os.environ["PATH"] if self.distribution.no_mpi is None: - env["MPI"] = "1" + os.environ["MPI"] = "1" # These need to be set so that build_ext uses the right compilers - cc_compiler = subprocess.check_output(["make", "print_CC"]).decode('utf-8').strip() - os.environ["CC"] = cc_compiler + #cc_compiler = subprocess.check_output(["make", "print_CC"]).decode('utf-8').strip() + #os.environ"CC"] = cc_compiler - cxx_compiler = subprocess.check_output(["make", "print_CXX"]).decode('utf-8').strip() - os.environ["CXX"] = cxx_compiler + #cxx_compiler = subprocess.check_output(["make", "print_CXX"]).decode('utf-8').strip() + #os.environ["CXX"] = cxx_compiler else: - env["MPI"] = "0" + os.environ["MPI"] = "0" if self.distribution.debug_flags is not None: self.distribution.ext_modules[0].extra_compile_args += ["-g", "-O0"] - env["DEBUG"] = "1" + os.environ["DEBUG"] = "1" BASE_PATH = os.path.dirname(os.path.abspath(__file__)) - env["PWD"] = BASE_PATH - env.update({k: os.environ[k] for k in ["CC", "CXX", "FC"] if k in os.environ}) - subprocess.check_call(["make", "-e", "libchord.so"], env=env, cwd=BASE_PATH) + subprocess.check_call(["make", "-e", "libchord.so"], cwd=BASE_PATH) if not os.path.isdir("pypolychord/lib/"): os.makedirs(os.path.join(BASE_PATH, "pypolychord/lib/")) shutil.copy(os.path.join(BASE_PATH, "lib/libchord.so"), @@ -159,7 +155,7 @@ def run(self): author_email='wh260@cam.ac.uk', license='PolyChord', packages=find_packages(), - install_requires=['numpy','scipy'], + install_requires=['numpy', 'scipy'], extras_require={'plotting': 'getdist'}, distclass=DistributionWithOption, ext_modules=[pypolychord_module], From 00d37b9646268b011479e93d0f5b02081412d303 Mon Sep 17 00:00:00 2001 From: Arnaud De-Mattia Date: Tue, 6 Dec 2022 10:32:32 +0100 Subject: [PATCH 04/15] test --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 883595e6..7e7a5ff2 100644 --- a/setup.py +++ b/setup.py @@ -102,7 +102,9 @@ def run(self): os.environ["DEBUG"] = "1" BASE_PATH = os.path.dirname(os.path.abspath(__file__)) + os.environ["PWD"] = BASE_PATH subprocess.check_call(["make", "-e", "libchord.so"], cwd=BASE_PATH) + #subprocess.call(['make', '-e', 'libpolychord.so'], shell=True, cwd=BASE_PATH) if not os.path.isdir("pypolychord/lib/"): os.makedirs(os.path.join(BASE_PATH, "pypolychord/lib/")) shutil.copy(os.path.join(BASE_PATH, "lib/libchord.so"), From e1a09cf07a48cd6e60125eaf25dd3a7392ff3812 Mon Sep 17 00:00:00 2001 From: Arnaud De-Mattia Date: Tue, 6 Dec 2022 10:37:46 +0100 Subject: [PATCH 05/15] test --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 7e7a5ff2..2661ce21 100644 --- a/setup.py +++ b/setup.py @@ -104,7 +104,6 @@ def run(self): BASE_PATH = os.path.dirname(os.path.abspath(__file__)) os.environ["PWD"] = BASE_PATH subprocess.check_call(["make", "-e", "libchord.so"], cwd=BASE_PATH) - #subprocess.call(['make', '-e', 'libpolychord.so'], shell=True, cwd=BASE_PATH) if not os.path.isdir("pypolychord/lib/"): os.makedirs(os.path.join(BASE_PATH, "pypolychord/lib/")) shutil.copy(os.path.join(BASE_PATH, "lib/libchord.so"), From feb642f54542bd33dc027ffe8a9aad69c1bed0da Mon Sep 17 00:00:00 2001 From: Arnaud De-Mattia Date: Fri, 28 Jul 2023 23:05:57 +0200 Subject: [PATCH 06/15] cleanups --- setup.py | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/setup.py b/setup.py index 2661ce21..6a16e9c4 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,10 @@ Polychord is a tool to solve high dimensional problems. """ -import os, sys, subprocess, shutil +import os +import sys +import subprocess +import shutil from setuptools import setup, Extension, find_packages, Distribution from setuptools.command.build_py import build_py as _build_py @@ -21,10 +24,14 @@ mpi4py_get_include = mpi4py.get_include() -def check_compiler(default_CC="gcc"): +def check_compiler(default_CC=None): """Checks what compiler is being used (clang, intel, or gcc).""" - CC = default_CC if "CC" not in os.environ else os.environ["CC"] + default_CC = 'gcc' + if mpi4py_get_include: + default_CC = 'mpicc' + CC = os.getenv('CC', default_CC) + os.environ['CC'] = CC CC_version = subprocess.check_output([CC, "-v"], stderr=subprocess.STDOUT).decode("utf-8").lower() if "clang" in CC_version: @@ -75,9 +82,7 @@ def get_version(short=False): class DistributionWithOption(Distribution): def __init__(self, *args, **kwargs): - self.global_options = self.global_options \ - + [("no-mpi", None, "Don't compile with MPI support."), - ("debug-flags", None, "Compile in debug mode.")] + self.global_options = self.global_options + [("no-mpi", None, "Compile without MPI support."), ("debug-flags", None, "Compile in debug mode.")] self.no_mpi = None self.debug_flags = None super(DistributionWithOption, self).__init__(*args, **kwargs) @@ -134,19 +139,19 @@ def run(self): elif mpi4py_get_include: CPPRUNTIMELIB_FLAG += ["-DUSE_MPI"] + print(mpi4py_get_include) include_dirs += [mpi4py_get_include] -pypolychord_module = Extension( - name='_pypolychord', - library_dirs=['lib'], - include_dirs=include_dirs, - libraries=['chord',], - extra_link_args=RPATH_FLAG + CPPRUNTIMELIB_FLAG, - extra_compile_args= ["-std=c++11"] + RPATH_FLAG + CPPRUNTIMELIB_FLAG, - runtime_library_dirs=['lib'], - sources=['pypolychord/_pypolychord.cpp'] - ) +pypolychord_module = Extension(name='_pypolychord', + library_dirs=['lib'], + include_dirs=include_dirs, + libraries=['chord'], + extra_link_args=RPATH_FLAG + CPPRUNTIMELIB_FLAG, + extra_compile_args=["-std=c++11"] + RPATH_FLAG + CPPRUNTIMELIB_FLAG, + runtime_library_dirs=['lib'], + sources=['pypolychord/_pypolychord.cpp']) + setup(name=NAME, version=get_version(), @@ -163,6 +168,6 @@ def run(self): cmdclass={'build_py': CustomBuildPy, 'develop': CustomDevelop, 'clean': CustomClean}, - package_data={"": ["lib/libchord.so"]}, + package_data={NAME: ["lib/libchord.so"]}, include_package_data=True, zip_safe=False) From 67585b78a6a85aab7dcd52d5b73f5f8ac6720180 Mon Sep 17 00:00:00 2001 From: Will Handley Date: Tue, 9 Jan 2024 13:23:14 +0000 Subject: [PATCH 07/15] Removed linter changes --- pypolychord/_pypolychord.cpp | 20 +-- pypolychord/polychord.py | 2 +- run_pypolychord.py | 2 +- setup.py | 47 ++++--- src/drivers/polychord_CC.cpp | 2 +- src/drivers/polychord_CC_ini.cpp | 3 +- src/polychord/c_interface.cpp | 80 ++++++------ src/polychord/mpi_utils.F90 | 215 +++++++++++++++---------------- 8 files changed, 185 insertions(+), 186 deletions(-) diff --git a/pypolychord/_pypolychord.cpp b/pypolychord/_pypolychord.cpp index 8b3de6ce..ac92ea69 100644 --- a/pypolychord/_pypolychord.cpp +++ b/pypolychord/_pypolychord.cpp @@ -39,13 +39,13 @@ static PyObject *python_loglikelihood = NULL; double loglikelihood(double* theta, int nDims, double* phi, int nDerived) { /* Create a python version of theta */ - npy_intp theta_shape[] = {nDims}; + npy_intp theta_shape[] = {nDims}; PyObject *array_theta = PyArray_SimpleNewFromData(1, theta_shape, NPY_DOUBLE, theta); if (array_theta==NULL) throw PythonException(); PyArray_CLEARFLAGS(reinterpret_cast(array_theta), NPY_ARRAY_WRITEABLE); /* Create a python version of phi */ - npy_intp phi_shape[] = {nDerived}; + npy_intp phi_shape[] = {nDerived}; PyObject *array_phi = PyArray_SimpleNewFromData(1, phi_shape, NPY_DOUBLE, phi); if (array_phi==NULL) {Py_DECREF(array_theta); throw PythonException();} @@ -73,7 +73,7 @@ static PyObject *python_prior = NULL; void prior(double* cube, double* theta, int nDims) { /* create a python version of cube */ - npy_intp shape[] = {nDims}; + npy_intp shape[] = {nDims}; PyObject *array_cube = PyArray_SimpleNewFromData(1, shape, NPY_DOUBLE, cube); if (array_cube==NULL) throw PythonException(); PyArray_CLEARFLAGS(reinterpret_cast(array_cube), NPY_ARRAY_WRITEABLE); @@ -95,19 +95,19 @@ static PyObject *python_dumper = NULL; void dumper(int ndead, int nlive, int npars, double* live, double* dead, double* logweights, double logZ, double logZerr) { /* create a python version of live points */ - npy_intp live_shape[] = {nlive, npars}; + npy_intp live_shape[] = {nlive, npars}; PyObject *array_live = PyArray_SimpleNewFromData(2, live_shape, NPY_DOUBLE, live); if (array_live==NULL) throw PythonException(); PyArray_CLEARFLAGS(reinterpret_cast(array_live), NPY_ARRAY_WRITEABLE); /* create a python version of dead points */ - npy_intp dead_shape[] = {ndead, npars}; + npy_intp dead_shape[] = {ndead, npars}; PyObject *array_dead = PyArray_SimpleNewFromData(2, dead_shape, NPY_DOUBLE, dead); if (array_dead==NULL) {Py_DECREF(array_live); throw PythonException();} PyArray_CLEARFLAGS(reinterpret_cast(array_dead), NPY_ARRAY_WRITEABLE); /* create a python version of posterior weights */ - npy_intp logweights_shape[] = {ndead}; + npy_intp logweights_shape[] = {ndead}; PyObject *array_logweights = PyArray_SimpleNewFromData(1, logweights_shape, NPY_DOUBLE, logweights); if (array_logweights==NULL) {Py_DECREF(array_live); Py_DECREF(array_dead); throw PythonException();} PyArray_CLEARFLAGS(reinterpret_cast(array_logweights), NPY_ARRAY_WRITEABLE); @@ -133,6 +133,7 @@ static PyObject *run_pypolychord(PyObject *, PyObject *args) PyObject *temp_logl, *temp_prior, *temp_dumper; PyObject* py_grade_dims, *py_grade_frac, *py_nlives, *py_comm; char* base_dir, *file_root; + if (!PyArg_ParseTuple(args, "OOOiiiiiiiiddidiiiiiiiiiiidissO!O!O!iO:run", @@ -179,7 +180,7 @@ static PyObject *run_pypolychord(PyObject *, PyObject *args) return NULL; S.base_dir = base_dir; S.file_root = file_root; - + int nGrade = PyList_Size(py_grade_frac); S.grade_frac.resize(nGrade); S.grade_dims.resize(nGrade); @@ -235,11 +236,12 @@ static PyObject *run_pypolychord(PyObject *, PyObject *args) #endif } catch (PythonException& e) - { + { Py_DECREF(py_grade_frac);Py_DECREF(py_grade_dims);Py_DECREF(python_loglikelihood);Py_DECREF(python_prior); - return NULL; + return NULL; } /* Return None */ Py_RETURN_NONE; } + diff --git a/pypolychord/polychord.py b/pypolychord/polychord.py index ab35020f..b631b5fb 100644 --- a/pypolychord/polychord.py +++ b/pypolychord/polychord.py @@ -159,7 +159,7 @@ def run_polychord(loglikelihood, nDims, nDerived, settings, os.makedirs(settings.base_dir) except OSError: pass - + try: if rank == 0: os.makedirs(settings.cluster_dir) diff --git a/run_pypolychord.py b/run_pypolychord.py index 44781aa4..8f739315 100755 --- a/run_pypolychord.py +++ b/run_pypolychord.py @@ -74,4 +74,4 @@ def dumper(live, dead, logweights, logZ, logZerr): except ImportError: print("Install matplotlib and getdist for plotting examples") - print("Install anesthetic or getdist for plotting examples") + print("Install anesthetic or getdist for for plotting examples") diff --git a/setup.py b/setup.py index 6a16e9c4..3810bd0a 100644 --- a/setup.py +++ b/setup.py @@ -3,18 +3,15 @@ Polychord is a tool to solve high dimensional problems. """ -import os -import sys -import subprocess -import shutil from setuptools import setup, Extension, find_packages, Distribution from setuptools.command.build_py import build_py as _build_py from setuptools.command.develop import develop as _develop from distutils.command.clean import clean as _clean -import numpy +import os, sys, subprocess, shutil +import numpy try: import mpi4py @@ -33,7 +30,7 @@ def check_compiler(default_CC=None): CC = os.getenv('CC', default_CC) os.environ['CC'] = CC CC_version = subprocess.check_output([CC, "-v"], stderr=subprocess.STDOUT).decode("utf-8").lower() - + if "clang" in CC_version: CC_family = "clang" elif "icc" in CC_version: @@ -80,16 +77,15 @@ def get_version(short=False): class DistributionWithOption(Distribution): - def __init__(self, *args, **kwargs): - self.global_options = self.global_options + [("no-mpi", None, "Compile without MPI support."), ("debug-flags", None, "Compile in debug mode.")] + self.global_options = self.global_options \ + + [("no-mpi", None, "Don't compile with MPI support."), + ("debug-flags", None, "Compile in debug mode.")] self.no_mpi = None self.debug_flags = None super(DistributionWithOption, self).__init__(*args, **kwargs) - class CustomBuildPy(_build_py): - def run(self): if self.distribution.no_mpi is None: os.environ["MPI"] = "1" @@ -104,10 +100,11 @@ def run(self): if self.distribution.debug_flags is not None: self.distribution.ext_modules[0].extra_compile_args += ["-g", "-O0"] - os.environ["DEBUG"] = "1" - + env["DEBUG"] = "1" + BASE_PATH = os.path.dirname(os.path.abspath(__file__)) os.environ["PWD"] = BASE_PATH + os.environ.update({k : os.environ[k] for k in ["CC", "CXX", "FC"] if k in os.environ}) subprocess.check_call(["make", "-e", "libchord.so"], cwd=BASE_PATH) if not os.path.isdir("pypolychord/lib/"): os.makedirs(os.path.join(BASE_PATH, "pypolychord/lib/")) @@ -125,7 +122,6 @@ def run(self): class CustomClean(_clean): - def run(self): subprocess.run(["make", "veryclean"], check=True, env=os.environ) return super().run() @@ -143,15 +139,16 @@ def run(self): include_dirs += [mpi4py_get_include] -pypolychord_module = Extension(name='_pypolychord', - library_dirs=['lib'], - include_dirs=include_dirs, - libraries=['chord'], - extra_link_args=RPATH_FLAG + CPPRUNTIMELIB_FLAG, - extra_compile_args=["-std=c++11"] + RPATH_FLAG + CPPRUNTIMELIB_FLAG, - runtime_library_dirs=['lib'], - sources=['pypolychord/_pypolychord.cpp']) - +pypolychord_module = Extension( + name='_pypolychord', + library_dirs=['lib'], + include_dirs=include_dirs, + libraries=['chord',], + extra_link_args=RPATH_FLAG + CPPRUNTIMELIB_FLAG, + extra_compile_args= ["-std=c++11"] + RPATH_FLAG + CPPRUNTIMELIB_FLAG, + runtime_library_dirs=['lib'], + sources=['pypolychord/_pypolychord.cpp'] + ) setup(name=NAME, version=get_version(), @@ -161,13 +158,13 @@ def run(self): author_email='wh260@cam.ac.uk', license='PolyChord', packages=find_packages(), - install_requires=['numpy', 'scipy'], + install_requires=['numpy','scipy'], extras_require={'plotting': 'getdist'}, distclass=DistributionWithOption, ext_modules=[pypolychord_module], - cmdclass={'build_py': CustomBuildPy, + cmdclass={'build_py' : CustomBuildPy, 'develop': CustomDevelop, - 'clean': CustomClean}, + 'clean' : CustomClean}, package_data={NAME: ["lib/libchord.so"]}, include_package_data=True, zip_safe=False) diff --git a/src/drivers/polychord_CC.cpp b/src/drivers/polychord_CC.cpp index c400ce0d..af2eed91 100644 --- a/src/drivers/polychord_CC.cpp +++ b/src/drivers/polychord_CC.cpp @@ -36,7 +36,7 @@ int main() settings.boost_posterior= 5.0; setup_loglikelihood(); - run_polychord(loglikelihood,prior,dumper,settings); + run_polychord(loglikelihood,prior,dumper,settings) ; } diff --git a/src/drivers/polychord_CC_ini.cpp b/src/drivers/polychord_CC_ini.cpp index ae5704aa..02a18e41 100644 --- a/src/drivers/polychord_CC_ini.cpp +++ b/src/drivers/polychord_CC_ini.cpp @@ -7,7 +7,7 @@ int main(int argc, char *argv[]) if (argc > 1) { std::string input_file = argv[1]; set_ini(input_file); - run_polychord(loglikelihood,setup_loglikelihood,input_file); + run_polychord(loglikelihood,setup_loglikelihood,input_file) ; return 0; } else{ @@ -15,3 +15,4 @@ int main(int argc, char *argv[]) return 1; } } + diff --git a/src/polychord/c_interface.cpp b/src/polychord/c_interface.cpp index 1f1c556d..bbd44cb7 100644 --- a/src/polychord/c_interface.cpp +++ b/src/polychord/c_interface.cpp @@ -3,10 +3,10 @@ #include // Constructor for settings struct -Settings::Settings(int _nDims,int _nDerived): +Settings::Settings(int _nDims,int _nDerived): nDims {_nDims}, nDerived {_nDerived}, - nlive {500}, + nlive {500}, num_repeats {nDims*5}, nprior {-1}, nfail {-1}, @@ -42,16 +42,16 @@ Settings::Settings(int _nDims,int _nDerived): #ifdef USE_MPI -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_prior_ptr)(double*,double*,int), - void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_prior_ptr)(double*,double*,int), + void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), Settings s, MPI_Comm& comm) #else -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_prior_ptr)(double*,double*,int), - void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_prior_ptr)(double*,double*,int), + void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), Settings s) #endif { @@ -70,11 +70,11 @@ void run_polychord( int fortran_comm = 0; #endif - polychord_c_interface( - c_loglikelihood_ptr, - c_prior_ptr, - c_dumper_ptr, - s.nlive, + polychord_c_interface( + c_loglikelihood_ptr, + c_prior_ptr, + c_dumper_ptr, + s.nlive, s.num_repeats, s.nprior, s.nfail, @@ -118,10 +118,10 @@ void run_polychord( #ifdef USE_MPI // In this function no MPI communicator is given, so a communicator is automatically // made from MPI_COMM_WORLD -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_prior_ptr)(double*,double*,int), - void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_prior_ptr)(double*,double*,int), + void (*c_dumper_ptr)(int,int,int,double*,double*,double*,double,double), Settings s) { int flag; @@ -132,47 +132,47 @@ void run_polychord( run_polychord(c_loglikelihood_ptr,c_prior_ptr,c_dumper_ptr,s,world_comm); if (flag==0) MPI_Finalize(); } -void run_polychord( +void run_polychord( double (*loglikelihood)(double*,int,double*,int), - void (*dumper)(int,int,int,double*,double*,double*,double,double), + void (*dumper)(int,int,int,double*,double*,double*,double,double), Settings S, MPI_Comm &comm) -{ run_polychord(loglikelihood,default_prior,dumper,S,comm); } -void run_polychord( +{ run_polychord(loglikelihood,default_prior,dumper,S,comm); } +void run_polychord( double (*loglikelihood)(double*,int,double*,int), void (*prior)(double*,double*,int), Settings S, MPI_Comm &comm) -{ run_polychord(loglikelihood,prior,default_dumper,S,comm); } +{ run_polychord(loglikelihood,prior,default_dumper,S,comm); } void run_polychord( double (*loglikelihood)(double*,int,double*,int), Settings S, MPI_Comm &comm) -{ run_polychord(loglikelihood,default_prior,default_dumper,S,comm); } +{ run_polychord(loglikelihood,default_prior,default_dumper,S,comm); } #endif -void run_polychord( +void run_polychord( double (*loglikelihood)(double*,int,double*,int), - void (*dumper)(int,int,int,double*,double*,double*,double,double), + void (*dumper)(int,int,int,double*,double*,double*,double,double), Settings S) -{ run_polychord(loglikelihood,default_prior,dumper,S); } -void run_polychord( +{ run_polychord(loglikelihood,default_prior,dumper,S); } +void run_polychord( double (*loglikelihood)(double*,int,double*,int), void (*prior)(double*,double*,int), Settings S) -{ run_polychord(loglikelihood,prior,default_dumper,S); } +{ run_polychord(loglikelihood,prior,default_dumper,S); } void run_polychord( double (*loglikelihood)(double*,int,double*,int), Settings S) -{ run_polychord(loglikelihood,default_prior,default_dumper,S); } +{ run_polychord(loglikelihood,default_prior,default_dumper,S); } #ifdef USE_MPI -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_setup_loglikelihood_ptr)(), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_setup_loglikelihood_ptr)(), std::string inifile, MPI_Comm &comm) #else -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_setup_loglikelihood_ptr)(), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_setup_loglikelihood_ptr)(), std::string inifile) #endif { @@ -192,9 +192,9 @@ void run_polychord( #ifdef USE_MPI // In this function no MPI communicator is given, so a communicator is automatically // made from MPI_COMM_WORLD -void run_polychord( - double (*c_loglikelihood_ptr)(double*,int,double*,int), - void (*c_setup_loglikelihood_ptr)(), +void run_polychord( + double (*c_loglikelihood_ptr)(double*,int,double*,int), + void (*c_setup_loglikelihood_ptr)(), std::string inifile) { int flag; diff --git a/src/polychord/mpi_utils.F90 b/src/polychord/mpi_utils.F90 index 5b172943..0278cc0c 100644 --- a/src/polychord/mpi_utils.F90 +++ b/src/polychord/mpi_utils.F90 @@ -59,7 +59,7 @@ function get_mpi_information(mpi_communicator,colour) result(mpi_information) end function !> Returns whether this is the root node - function is_root(mpi_information) + function is_root(mpi_information) implicit none type(mpi_bundle),intent(in) :: mpi_information logical :: is_root @@ -69,7 +69,7 @@ function is_root(mpi_information) end function is_root !> Returns whether there is a single processor - function linear_mode(mpi_information) + function linear_mode(mpi_information) implicit none type(mpi_bundle),intent(in) :: mpi_information logical :: linear_mode @@ -87,7 +87,7 @@ function get_nprocs(mpi_communicator) result(nprocs) integer :: nprocs #ifdef MPI - call MPI_COMM_SIZE( & + call MPI_COMM_SIZE( & mpi_communicator,&!handle nprocs, &!return number of processors mpierror &!error flag @@ -107,9 +107,9 @@ function get_rank(mpi_communicator) result(myrank) integer :: myrank #ifdef MPI - call MPI_COMM_RANK( & + call MPI_COMM_RANK( & mpi_communicator,&!handle - myrank, &!return rank of calling processor + myrank, &!return rank of calling processor mpierror &!error flag ) #else @@ -137,7 +137,7 @@ function get_root(mpi_communicator) result(root) #ifdef MPI call MPI_ALLREDUCE( & - myrank, &!send buffer + myrank, &!send buffer root, &!recieve buffer 1, &!number of elements sent MPI_INTEGER, &!type of element sent @@ -222,7 +222,7 @@ subroutine mpi_synchronise(mpi_information) #ifdef MPI call MPI_BARRIER(mpi_information%communicator,mpierror) -#endif +#endif end subroutine mpi_synchronise @@ -240,7 +240,7 @@ function sum_integers(intgr_local,mpi_information) result(intgr) integer :: intgr call MPI_ALLREDUCE( & - intgr_local, &!send buffer + intgr_local, &!send buffer intgr, &!recieve buffer 1, &!number of elements sent MPI_INTEGER, &!type of element sent @@ -258,7 +258,7 @@ function sum_doubles(db_local,mpi_information) result(db) real(dp) :: db call MPI_ALLREDUCE( & - db_local, &!send buffer + db_local, &!send buffer db, &!recieve buffer 1, &!number of elements sent MPI_DOUBLE_PRECISION, &!type of element sent @@ -274,7 +274,7 @@ subroutine broadcast_doubles(doubles,mpi_information) real(dp), dimension(:), intent(inout) :: doubles type(mpi_bundle), intent(in) :: mpi_information - call MPI_BCAST( & + call MPI_BCAST( & doubles, &!broadcast buffer size(doubles), &!size of buffer MPI_DOUBLE_PRECISION, &!type of element sent @@ -290,7 +290,7 @@ subroutine broadcast_integers(integers,mpi_information) integer, dimension(:), intent(inout) :: integers type(mpi_bundle), intent(in) :: mpi_information - call MPI_BCAST( & + call MPI_BCAST( & integers, &!broadcast buffer size(integers), &!size of buffer MPI_INTEGER, &!type of element sent @@ -302,7 +302,7 @@ subroutine broadcast_integers(integers,mpi_information) end subroutine broadcast_integers !============== Throwing and catching routines ==================== - ! There are four points in the algorithm where arrays need to be transferred + ! There are four points in the algorithm where arrays need to be transferred ! between administrator and workers ! ! 1) live point during initial generation @@ -320,7 +320,7 @@ end subroutine broadcast_integers !> Root catch !! - !! This a process by which the root node 'catches' a thrown point from + !! This a process by which the root node 'catches' a thrown point from !! any worker, and returns the worker identifier for use to throw back function catch_point(live_point,mpi_information) result(worker_id) implicit none @@ -402,26 +402,26 @@ function catch_babies(baby_points,nlike,epoch,mpi_information) result(worker_id) ! Pass on the worker id worker_id = mpistatus(MPI_SOURCE) - call MPI_RECV( &! - nlike, &! - size(nlike), &! - MPI_INTEGER, &! - worker_id, &! - tag_run_nlike, &! - mpi_information%communicator,&! - mpistatus, &! - mpierror &! + call MPI_RECV( &! + nlike, &! + size(nlike), &! + MPI_INTEGER, &! + worker_id, &! + tag_run_nlike, &! + mpi_information%communicator,&! + mpistatus, &! + mpierror &! ) - call MPI_RECV( &! - epoch, &! - 1, &! - MPI_INTEGER, &! - worker_id, &! - tag_run_epoch_babies, &! - mpi_information%communicator,&! - mpistatus, &! - mpierror &! + call MPI_RECV( &! + epoch, &! + 1, &! + MPI_INTEGER, &! + worker_id, &! + tag_run_epoch_babies, &! + mpi_information%communicator,&! + mpistatus, &! + mpierror &! ) end function catch_babies @@ -435,32 +435,32 @@ subroutine throw_babies(baby_points,nlike,epoch,mpi_information) integer, intent(in) :: epoch !> The epoch the babies were generated in type(mpi_bundle), intent(in) :: mpi_information - call MPI_SEND( &! - baby_points, &! - size(baby_points,1)*size(baby_points,2),&! - MPI_DOUBLE_PRECISION, &! - mpi_information%root, &! - tag_run_baby, &! - mpi_information%communicator, &! - mpierror &! + call MPI_SEND( &! + baby_points, &! + size(baby_points,1)*size(baby_points,2),&! + MPI_DOUBLE_PRECISION, &! + mpi_information%root, &! + tag_run_baby, &! + mpi_information%communicator, &! + mpierror &! + ) + call MPI_SEND( &! + nlike, &! + size(nlike), &! + MPI_INTEGER, &! + mpi_information%root, &! + tag_run_nlike, &! + mpi_information%communicator,&! + mpierror &! ) - call MPI_SEND( &! - nlike, &! - size(nlike), &! - MPI_INTEGER, &! - mpi_information%root, &! - tag_run_nlike, &! - mpi_information%communicator,&! - mpierror &! - ) - call MPI_SEND( &! - epoch, &! - 1, &! - MPI_INTEGER, &! - mpi_information%root, &! - tag_run_epoch_babies, &! - mpi_information%communicator,&! - mpierror &! + call MPI_SEND( &! + epoch, &! + 1, &! + MPI_INTEGER, &! + mpi_information%root, &! + tag_run_epoch_babies, &! + mpi_information%communicator,&! + mpierror &! ) end subroutine throw_babies @@ -538,15 +538,15 @@ function catch_seed(seed_point,cholesky,logL,epoch,mpi_information) result(more_ mpistatus, &! mpierror &! ) - call MPI_RECV( &! - epoch, &! - 1, &! - MPI_INTEGER, &! - mpi_information%root, &! - tag_run_epoch_seed, &! - mpi_information%communicator,&! - mpistatus, &! - mpierror &! + call MPI_RECV( &! + epoch, &! + 1, &! + MPI_INTEGER, &! + mpi_information%root, &! + tag_run_epoch_seed, &! + mpi_information%communicator,&! + mpistatus, &! + mpierror &! ) end function catch_seed @@ -570,54 +570,53 @@ subroutine throw_seed(seed_point,cholesky,logL,mpi_information,worker_id,epoch,k tag_run = tag_run_stop ! Default tag is stop tag if(keep_going) tag_run = tag_run_seed ! If we want to keep going then change this to the seed tag - call MPI_SEND( &! - tag_run, &! - 1, &! - MPI_INTEGER, &! - worker_id, &! - tag_tag_run, &! - mpi_information%communicator,&! - mpierror &! + call MPI_SEND( &! + tag_run, &! + 1, &! + MPI_INTEGER, &! + worker_id, &! + tag_tag_run, &! + mpi_information%communicator,&! + mpierror &! ) if(.not. keep_going) return ! Stop here if we're wrapping up - call MPI_SEND( &! - seed_point, &! - size(seed_point), &! - MPI_DOUBLE_PRECISION, &! - worker_id, &! - tag_run, &! - mpi_information%communicator,&! - mpierror &! + call MPI_SEND( &! + seed_point, &! + size(seed_point), &! + MPI_DOUBLE_PRECISION, &! + worker_id, &! + tag_run, &! + mpi_information%communicator, &! + mpierror &! ) - - call MPI_SEND( &! - cholesky, &! - size(cholesky,1)*size(cholesky,2),&! - MPI_DOUBLE_PRECISION, &! - worker_id, &! - tag_run_cholesky, &! - mpi_information%communicator, &! - mpierror &! + call MPI_SEND( &! + cholesky, &! + size(cholesky,1)*size(cholesky,2),&! + MPI_DOUBLE_PRECISION, &! + worker_id, &! + tag_run_cholesky, &! + mpi_information%communicator, &! + mpierror &! ) - call MPI_SEND( &! - logL, &! - 1, &! - MPI_DOUBLE_PRECISION, &! - worker_id, &! - tag_run_logL, &! - mpi_information%communicator,&! - mpierror &! + call MPI_SEND( &! + logL, &! + 1, &! + MPI_DOUBLE_PRECISION, &! + worker_id, &! + tag_run_logL, &! + mpi_information%communicator,&! + mpierror &! ) - call MPI_SEND( &! - epoch, &! - 1, &! - MPI_INTEGER, &! - worker_id, &! - tag_run_epoch_seed, &! - mpi_information%communicator,&! - mpierror &! + call MPI_SEND( &! + epoch, &! + 1, &! + MPI_INTEGER, &! + worker_id, &! + tag_run_epoch_seed, &! + mpi_information%communicator,&! + mpierror &! ) @@ -633,7 +632,7 @@ end subroutine throw_seed ! administrator ----> worker ! request_point more_points_needed -> true ! no_more_points more_points_needed -> false - ! + ! !> Request point !! @@ -670,7 +669,7 @@ subroutine no_more_points(mpi_information,worker_id) 1, &! size of nothing MPI_INTEGER, &! sending no integers worker_id, &! process id to send to - tag_tag_gen, &! continuation tag + tag_tag_gen, &! continuation tag mpi_information%communicator,&! mpi handle mpierror &! error flag ) From bfb256e653c418504f5c4c4da229c631acbe7089 Mon Sep 17 00:00:00 2001 From: adematti Date: Thu, 18 Jan 2024 07:15:55 -0800 Subject: [PATCH 08/15] cleanup setup.py --- setup.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/setup.py b/setup.py index 3810bd0a..08cb89d3 100644 --- a/setup.py +++ b/setup.py @@ -87,25 +87,30 @@ def __init__(self, *args, **kwargs): class CustomBuildPy(_build_py): def run(self): + env = os.environ.copy() if self.distribution.no_mpi is None: - os.environ["MPI"] = "1" + env["MPI"] = "1" # These need to be set so that build_ext uses the right compilers #cc_compiler = subprocess.check_output(["make", "print_CC"]).decode('utf-8').strip() - #os.environ"CC"] = cc_compiler + #os.environ["CC"] = cc_compiler #cxx_compiler = subprocess.check_output(["make", "print_CXX"]).decode('utf-8').strip() - #os.environ["CXX"] = cxx_compiler + #env["CXX"] = cxx_compiler else: - os.environ["MPI"] = "0" + env["MPI"] = "0" if self.distribution.debug_flags is not None: self.distribution.ext_modules[0].extra_compile_args += ["-g", "-O0"] env["DEBUG"] = "1" BASE_PATH = os.path.dirname(os.path.abspath(__file__)) - os.environ["PWD"] = BASE_PATH - os.environ.update({k : os.environ[k] for k in ["CC", "CXX", "FC"] if k in os.environ}) - subprocess.check_call(["make", "-e", "libchord.so"], cwd=BASE_PATH) + env["PWD"] = BASE_PATH + #env.update({k : os.environ[k] for k in ["CC", "CXX", "FC"] if k in os.environ}) + + def compile(): + subprocess.call(["make", "-e", "libchord.so"], env=env, cwd=BASE_PATH) + + self.execute(compile, [], 'Compiling') if not os.path.isdir("pypolychord/lib/"): os.makedirs(os.path.join(BASE_PATH, "pypolychord/lib/")) shutil.copy(os.path.join(BASE_PATH, "lib/libchord.so"), @@ -123,7 +128,7 @@ def run(self): class CustomClean(_clean): def run(self): - subprocess.run(["make", "veryclean"], check=True, env=os.environ) + subprocess.run(["make", "veryclean"], check=True) return super().run() From c47765603e2478c597873b42abc0e2a3e0cde097 Mon Sep 17 00:00:00 2001 From: Will Handley Date: Wed, 28 Feb 2024 16:33:12 +0000 Subject: [PATCH 09/15] Removed commented regions for setup.py to see if that fixes pip --- setup.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index 38cc91c1..586cfa7a 100644 --- a/setup.py +++ b/setup.py @@ -21,13 +21,10 @@ mpi4py_get_include = mpi4py.get_include() -def check_compiler(default_CC=None): +def check_compiler(): """Checks what compiler is being used (clang, intel, or gcc).""" - default_CC = 'gcc' - if mpi4py_get_include: - default_CC = 'mpicc' - CC = os.getenv('CC', default_CC) + CC = os.getenv('CC', 'mpicc' if mpi4py_get_include else 'gcc') os.environ['CC'] = CC CC_version = subprocess.check_output([CC, "-v"], stderr=subprocess.STDOUT).decode("utf-8").lower() @@ -91,11 +88,11 @@ def run(self): if self.distribution.no_mpi is None: env["MPI"] = "1" # These need to be set so that build_ext uses the right compilers - #cc_compiler = subprocess.check_output(["make", "print_CC"]).decode('utf-8').strip() - #os.environ["CC"] = cc_compiler + cc_compiler = subprocess.check_output(["make", "print_CC"]).decode('utf-8').strip() + os.environ["CC"] = cc_compiler - #cxx_compiler = subprocess.check_output(["make", "print_CXX"]).decode('utf-8').strip() - #env["CXX"] = cxx_compiler + cxx_compiler = subprocess.check_output(["make", "print_CXX"]).decode('utf-8').strip() + env["CXX"] = cxx_compiler else: env["MPI"] = "0" @@ -105,7 +102,7 @@ def run(self): BASE_PATH = os.path.dirname(os.path.abspath(__file__)) env["PWD"] = BASE_PATH - #env.update({k : os.environ[k] for k in ["CC", "CXX", "FC"] if k in os.environ}) + env.update({k : os.environ[k] for k in ["CC", "CXX", "FC"] if k in os.environ}) def compile(): subprocess.call(["make", "-e", "libchord.so"], env=env, cwd=BASE_PATH) From 178ed1fa6d6fd152796098e3ae6e8b53f0d7da75 Mon Sep 17 00:00:00 2001 From: Will Handley Date: Wed, 28 Feb 2024 16:42:05 +0000 Subject: [PATCH 10/15] Further simplification --- setup.py | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/setup.py b/setup.py index 586cfa7a..b87bccd2 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,6 @@ from setuptools import setup, Extension, find_packages, Distribution from setuptools.command.build_py import build_py as _build_py -from setuptools.command.develop import develop as _develop from distutils.command.clean import clean as _clean import os, sys, subprocess, shutil @@ -73,7 +72,7 @@ def get_version(short=False): return line[44:50] -class DistributionWithOption(Distribution): +class DistributionWithOption(Distribution, object): def __init__(self, *args, **kwargs): self.global_options = self.global_options \ + [("no-mpi", None, "Don't compile with MPI support."), @@ -84,7 +83,8 @@ def __init__(self, *args, **kwargs): class CustomBuildPy(_build_py): def run(self): - env = os.environ.copy() + env = {} + env["PATH"] = os.environ["PATH"] if self.distribution.no_mpi is None: env["MPI"] = "1" # These need to be set so that build_ext uses the right compilers @@ -92,7 +92,7 @@ def run(self): os.environ["CC"] = cc_compiler cxx_compiler = subprocess.check_output(["make", "print_CXX"]).decode('utf-8').strip() - env["CXX"] = cxx_compiler + os.environ["CXX"] = cxx_compiler else: env["MPI"] = "0" @@ -101,13 +101,9 @@ def run(self): env["DEBUG"] = "1" BASE_PATH = os.path.dirname(os.path.abspath(__file__)) - env["PWD"] = BASE_PATH + env["CURDIR"] = BASE_PATH env.update({k : os.environ[k] for k in ["CC", "CXX", "FC"] if k in os.environ}) - - def compile(): - subprocess.call(["make", "-e", "libchord.so"], env=env, cwd=BASE_PATH) - - self.execute(compile, [], 'Compiling') + subprocess.check_call(["make", "-e", "libchord.so"], env=env, cwd=BASE_PATH) if not os.path.isdir("pypolychord/lib/"): os.makedirs(os.path.join(BASE_PATH, "pypolychord/lib/")) shutil.copy(os.path.join(BASE_PATH, "lib/libchord.so"), @@ -115,17 +111,9 @@ def compile(): self.run_command("build_ext") return super(CustomBuildPy, self).run() - -class CustomDevelop(_develop): - - def run(self): - self.run_command('build_py') - super(CustomDevelop, self).run() - - class CustomClean(_clean): def run(self): - subprocess.run(["make", "veryclean"], check=True) + subprocess.run(["make", "veryclean"], check=True, env=os.environ) return super().run() @@ -165,7 +153,6 @@ def run(self): distclass=DistributionWithOption, ext_modules=[pypolychord_module], cmdclass={'build_py' : CustomBuildPy, - 'develop': CustomDevelop, 'clean' : CustomClean}, package_data={NAME: ["lib/libchord.so"]}, include_package_data=True, From 4573658d9b0465ff1179e765623895a336dd1180 Mon Sep 17 00:00:00 2001 From: Will Handley Date: Wed, 28 Feb 2024 16:59:02 +0000 Subject: [PATCH 11/15] Added in communicator to new run function --- pypolychord/polychord.py | 13 +++++++++---- setup.py | 5 ++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/pypolychord/polychord.py b/pypolychord/polychord.py index 01b80502..c3a68b62 100644 --- a/pypolychord/polychord.py +++ b/pypolychord/polychord.py @@ -515,10 +515,9 @@ def run(loglikelihood, nDims, **kwargs): try: from mpi4py import MPI - comm = MPI.COMM_WORLD - rank = comm.Get_rank() + default_comm = MPI.COMM_WORLD except ImportError: - rank = 0 + default_comm = None paramnames = kwargs.pop('paramnames', None) @@ -555,6 +554,7 @@ def run(loglikelihood, nDims, **kwargs): 'grade_dims': [nDims], 'nlives': {}, 'seed': -1, + 'comm': default_comm, } default_kwargs['grade_frac'] = ([1.0]*len(default_kwargs['grade_dims']) if 'grade_dims' not in kwargs else @@ -566,6 +566,11 @@ def run(loglikelihood, nDims, **kwargs): default_kwargs.update(kwargs) kwargs = default_kwargs + if kwargs['comm'] is not None: + rank = kwargs['comm'].rank + else: + rank = 0 + if rank == 0: (Path(kwargs['base_dir']) / kwargs['cluster_dir']).mkdir( parents=True, exist_ok=True) @@ -634,7 +639,7 @@ def wrap_prior(cube, theta): kwargs['grade_dims'], kwargs['nlives'], kwargs['seed'], - ) + kwargs['comm']) if 'cube_samples' in kwargs: kwargs['read_resume'] = read_resume diff --git a/setup.py b/setup.py index b87bccd2..0bef7dc8 100644 --- a/setup.py +++ b/setup.py @@ -81,7 +81,7 @@ def __init__(self, *args, **kwargs): self.debug_flags = None super(DistributionWithOption, self).__init__(*args, **kwargs) -class CustomBuildPy(_build_py): +class CustomBuildPy(_build_py, object): def run(self): env = {} env["PATH"] = os.environ["PATH"] @@ -128,7 +128,6 @@ def run(self): print(mpi4py_get_include) include_dirs += [mpi4py_get_include] - pypolychord_module = Extension( name='_pypolychord', library_dirs=['lib'], @@ -154,6 +153,6 @@ def run(self): ext_modules=[pypolychord_module], cmdclass={'build_py' : CustomBuildPy, 'clean' : CustomClean}, - package_data={NAME: ["lib/libchord.so"]}, + package_data={"" : ["lib/libchord.so"]}, include_package_data=True, zip_safe=False) From eca1581fe2aeefc7d5f562cc5773a122503b8ae0 Mon Sep 17 00:00:00 2001 From: Will Handley Date: Wed, 13 Mar 2024 16:18:55 +0000 Subject: [PATCH 12/15] Final whitespace correction --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0bef7dc8..d075db15 100644 --- a/setup.py +++ b/setup.py @@ -106,7 +106,7 @@ def run(self): subprocess.check_call(["make", "-e", "libchord.so"], env=env, cwd=BASE_PATH) if not os.path.isdir("pypolychord/lib/"): os.makedirs(os.path.join(BASE_PATH, "pypolychord/lib/")) - shutil.copy(os.path.join(BASE_PATH, "lib/libchord.so"), + shutil.copy(os.path.join(BASE_PATH, "lib/libchord.so"), os.path.join(BASE_PATH, "pypolychord/lib/")) self.run_command("build_ext") return super(CustomBuildPy, self).run() From e0b0165918025d836c3032dc7995bc78e8f8a15a Mon Sep 17 00:00:00 2001 From: Will Handley Date: Wed, 13 Mar 2024 16:42:31 +0000 Subject: [PATCH 13/15] Removed misleading copy-pasted comments --- src/polychord/mpi_utils.F90 | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/polychord/mpi_utils.F90 b/src/polychord/mpi_utils.F90 index 468c55cf..e5bd84bc 100644 --- a/src/polychord/mpi_utils.F90 +++ b/src/polychord/mpi_utils.F90 @@ -644,13 +644,13 @@ subroutine no_more_points(mpi_information,worker_id) integer, intent(in) :: worker_id !> Worker to request a new point from call MPI_SEND( & - tag_gen_stop, &! not sending anything - 1, &! size of nothing - MPI_INTEGER, &! sending no integers - worker_id, &! process id to send to - tag_tag_gen, &! continuation tag - mpi_information%communicator,&! mpi handle - mpierror &! error flag + tag_gen_stop, &! + 1, &! + MPI_INTEGER, &! + worker_id, &! + tag_tag_gen, &! + mpi_information%communicator,&! + mpierror &! ) end subroutine no_more_points @@ -671,13 +671,13 @@ subroutine request_live_point(live_point,mpi_information,worker_id) real(dp), intent(in), dimension(:) :: live_point !> The live point to be sent call MPI_SEND( & - tag_gen_request, &! not sending anything - 1, &! size of nothing - MPI_INTEGER, &! sending no integers - worker_id, &! process id to send to - tag_tag_gen, &! continuation tag - mpi_information%communicator,&! mpi handle - mpierror &! error flag + tag_gen_request, &! + 1, &! + MPI_INTEGER, &! + worker_id, &! + tag_tag_gen, &! + mpi_information%communicator,&! + mpierror &! ) From a867970a19b4535225ef5babe774adca92839f00 Mon Sep 17 00:00:00 2001 From: Will Handley Date: Wed, 13 Aug 2025 17:54:33 +0100 Subject: [PATCH 14/15] Add test for custom MPI communicator functionality Tests that the new comm parameter is properly supported in both run_polychord() and run() interfaces. Validates interface exists without running full MPI tests that could hang in CI. Validates PR #94 custom communicator feature. --- tests/test_custom_mpi_comm.py | 90 +++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 tests/test_custom_mpi_comm.py diff --git a/tests/test_custom_mpi_comm.py b/tests/test_custom_mpi_comm.py new file mode 100644 index 00000000..e3aa70cf --- /dev/null +++ b/tests/test_custom_mpi_comm.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +""" +Test custom MPI communicator functionality in PolyChord. + +This test validates that the new `comm` parameter in pypolychord.run() +and run_polychord() correctly accepts custom MPI communicators instead +of just using MPI.COMM_WORLD. +""" + +import numpy as np +import pytest + +try: + from mpi4py import MPI + HAS_MPI = True +except ImportError: + HAS_MPI = False + +# Only run MPI tests if mpi4py is available +pytest_plugins = [] +if HAS_MPI: + import pypolychord + from pypolychord.priors import UniformPrior + from pypolychord.settings import PolyChordSettings + + +def gaussian_likelihood(theta): + """Simple 2D gaussian likelihood for testing.""" + nDims = len(theta) + r2 = sum(theta**2) + logL = -0.5 * r2 + return logL, [r2] # return likelihood and derived parameter + + +@pytest.mark.skipif(not HAS_MPI, reason="mpi4py not available") +def test_custom_communicator_interface_exists(): + """Test that the comm parameter exists in the interfaces.""" + # Just test that we can call the functions with comm parameter without hanging + import inspect + + # Check run_polychord signature has explicit comm parameter + run_polychord_sig = inspect.signature(pypolychord.run_polychord) + assert 'comm' in run_polychord_sig.parameters + + # run() uses **kwargs, so comm should be accepted as keyword argument + # Test that we can bind comm parameter to run() + run_sig = inspect.signature(pypolychord.run) + try: + bound_args = run_sig.bind(gaussian_likelihood, 2, comm=None) + # If we get here, comm is accepted as a keyword argument + assert True + except TypeError: + pytest.fail("run() does not accept comm as keyword argument") + + # This test just validates the interface exists - actual MPI testing + # would require more complex setup to avoid hangs + + +@pytest.mark.skipif(not HAS_MPI, reason="mpi4py not available") +def test_none_communicator_parameter(): + """Test that passing comm=None parameter is accepted.""" + # Just test that the parameter is accepted without actually running + # (to avoid MPI hangs in CI) + comm = MPI.COMM_WORLD + + # Test that we can pass None without error + try: + # We won't actually run this to avoid hangs, just test signature + import inspect + sig = inspect.signature(pypolychord.run) + bound_args = sig.bind( + gaussian_likelihood, 2, + nlive=5, comm=None + ) + # If we get here, the signature accepts comm=None + assert True + except TypeError: + pytest.fail("comm=None parameter not accepted") + + +if __name__ == "__main__": + # Simple interface test only to avoid MPI hangs + if HAS_MPI: + print("Testing MPI communicator interface...") + test_custom_communicator_interface_exists() + print("Interface test passed!") + test_none_communicator_parameter() + print("None parameter test passed!") + else: + print("mpi4py not available, skipping tests") \ No newline at end of file From 215f3ab5a5c6b11d04fae29505c1d1510d013468 Mon Sep 17 00:00:00 2001 From: Will Handley Date: Wed, 13 Aug 2025 18:11:19 +0100 Subject: [PATCH 15/15] Add functional test for custom MPI communicators Tests that PolyChord actually runs successfully with: - Default COMM_WORLD behavior - Explicit COMM_WORLD parameter - Custom duplicated communicator Uses realistic 2D Gaussian likelihood and validates that the custom communicator feature works end-to-end through all Python -> C++ -> Fortran layers. Validates PR #94 MPI communicator functionality. --- tests/test_mpi_functional.py | 89 ++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 tests/test_mpi_functional.py diff --git a/tests/test_mpi_functional.py b/tests/test_mpi_functional.py new file mode 100644 index 00000000..a74bc3c8 --- /dev/null +++ b/tests/test_mpi_functional.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 +""" +Minimal functional test for custom MPI communicator support. +This actually runs PolyChord with different communicators. +""" + +try: + from mpi4py import MPI + import pypolychord + from pypolychord.priors import UniformPrior + HAS_MPI = True +except ImportError: + HAS_MPI = False + exit(0) + +def gaussian_likelihood(theta): + """Simple Gaussian likelihood centered at origin.""" + # 2D Gaussian with unit variance + logL = -0.5 * sum(theta**2) + r2 = sum(theta**2) + return logL, [r2] # return log likelihood and derived parameter + +if __name__ == "__main__": + comm = MPI.COMM_WORLD + rank = comm.Get_rank() + size = comm.Get_size() + + print(f"Rank {rank}/{size}: Testing custom MPI communicator functionality") + + # Test 1: Default behavior (should use COMM_WORLD internally) + try: + output1 = pypolychord.run( + gaussian_likelihood, 2, # 2D Gaussian + nlive=10, num_repeats=5, max_ndead=50, + file_root=f'test_default_{rank}', + write_resume=False, write_dead=False, + write_stats=False, + feedback=0, do_clustering=False + ) + # run() returns None when anesthetic not installed, but that means it completed + if output1 is None: + print(f"Rank {rank}: Default comm test - SUCCESS (completed, anesthetic not available)") + else: + print(f"Rank {rank}: Default comm test - SUCCESS (logZ ≈ {output1.logZ:.2f})") + except Exception as e: + print(f"Rank {rank}: Default comm test - FAILED: {e}") + + # Test 2: Explicit COMM_WORLD + try: + output2 = pypolychord.run( + gaussian_likelihood, 2, # 2D Gaussian + nlive=10, num_repeats=5, max_ndead=50, + file_root=f'test_explicit_{rank}', + write_resume=False, write_dead=False, + write_stats=False, + feedback=0, do_clustering=False, + comm=comm # Explicit COMM_WORLD + ) + if output2 is None: + print(f"Rank {rank}: Explicit COMM_WORLD test - SUCCESS (completed, anesthetic not available)") + else: + print(f"Rank {rank}: Explicit COMM_WORLD test - SUCCESS (logZ ≈ {output2.logZ:.2f})") + except Exception as e: + print(f"Rank {rank}: Explicit COMM_WORLD test - FAILED: {e}") + + # Test 3: Duplicated communicator + try: + dup_comm = comm.Dup() + output3 = pypolychord.run( + gaussian_likelihood, 2, # 2D Gaussian + nlive=10, num_repeats=5, max_ndead=50, + file_root=f'test_dup_{rank}', + write_resume=False, write_dead=False, + write_stats=False, + feedback=0, do_clustering=False, + comm=dup_comm # Custom duplicated communicator + ) + dup_comm.Free() + if output3 is None: + print(f"Rank {rank}: Duplicated communicator test - SUCCESS (completed, anesthetic not available)") + else: + print(f"Rank {rank}: Duplicated communicator test - SUCCESS (logZ ≈ {output3.logZ:.2f})") + except Exception as e: + print(f"Rank {rank}: Duplicated communicator test - FAILED: {e}") + + print(f"Rank {rank}: All tests completed") + + # Synchronize before exit + comm.Barrier() \ No newline at end of file