diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2718818c8625f40c413634e22e99b24a66d2e33a..c963ceea0ece1967cb36a2b252ca9efd03711e7d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -16,38 +16,21 @@ before_script: - pip install --upgrade -r ci/requirements.txt -test_min: +test_all: stage: test script: - python setup.py build_ext --inplace - - nosetests -vv - -test_mpi: - stage: test - script: + - nosetests - ci/install_pyHealpix.sh - ci/install_mpi4py.sh - python setup.py build_ext --inplace - - nosetests -vv - -test_mpi_fftw: - stage: test - script: - - ci/install_pyHealpix.sh - - ci/install_mpi4py.sh + - nosetests - ci/install_pyfftw.sh - python setup.py build_ext --inplace - - nosetests -vv - -test_mpi_fftw_hdf5: - stage: test - script: - - ci/install_pyHealpix.sh - - ci/install_mpi4py.sh - - ci/install_pyfftw.sh + - nosetests - ci/install_h5py.sh - python setup.py build_ext --inplace - - nosetests -vv --with-coverage --cover-package=nifty --cover-branches + - nosetests --with-coverage --cover-package=nifty --cover-branches - > coverage report | grep TOTAL | awk '{ print "TOTAL: "$6; }' diff --git a/README.md b/README.md index 9dec93902b846693af648acc44f4ac76d2b4df36..611f51e2fa6cd8dbd674ac4366c665f1f231a53d 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Summary ### Description -**NIFTY**, "**N**umerical **I**nformation **F**ield **T**heor**y**", is +**NIFTY**, "**N**umerical **I**nformation **F**ield **T**heor<strong>y</strong>", is a versatile library designed to enable the development of signal inference algorithms that operate regardless of the underlying spatial grid and its resolution. Its object-oriented framework is written in @@ -87,21 +87,17 @@ Starting with a fresh Ubuntu installation move to a folder like - Install basic packages like python, python-dev, gsl and others: - sudo apt-get install curl git autoconf python-dev python-pip python-numpy + sudo apt-get install curl git autoconf libtool python-dev python-pip python-numpy - Install pyHealpix: git clone https://gitlab.mpcdf.mpg.de/ift/pyHealpix.git - cd pyHealpix - autoreconf -i && ./configure --prefix=$HOME/.local --enable-openmp --enable-native-optimizations && make -j4 && make install - cd .. + (cd pyHealpix && autoreconf -i && ./configure --prefix=$HOME/.local --enable-openmp --enable-native-optimizations && make -j4 install) - Finally, NIFTy: git clone https://gitlab.mpcdf.mpg.de/ift/NIFTy.git - cd NIFTy - python setup.py install --user - cd .. + (cd NIFTy && python setup.py install --user) ### Installation on Linux systems in general @@ -139,16 +135,13 @@ may cause trouble. - Install NIFTy: git clone https://gitlab.mpcdf.mpg.de/ift/NIFTy.git - cd NIFTy - python setup.py install --user - cd .. + (cd NIFTy && python setup.py install --user) ### Running the tests In oder to run the tests one needs two additional packages: - pip install nose - pip install parameterized + pip install nose parameterized Afterwards the tests (including a coverage report) are run using the following command in the repository root: diff --git a/ci/install_basics.sh b/ci/install_basics.sh index 46e446ce5299080f10d78c3339c488f2d3930728..796ba27fece74fb5cc00c72702abdfc5997e0f69 100644 --- a/ci/install_basics.sh +++ b/ci/install_basics.sh @@ -1,3 +1,3 @@ #!/bin/bash -apt-get install -y build-essential python python-pip python-dev git autoconf gsl-bin libgsl-dev wget +apt-get install -y build-essential python python-pip python-dev git autoconf libtool gsl-bin libgsl-dev wget diff --git a/ci/install_h5py.sh b/ci/install_h5py.sh index 4649934d4559245fa4ee9a25898f281cceb9bd6b..6702ca879bd5710fc269319b067c598ea0bbff53 100644 --- a/ci/install_h5py.sh +++ b/ci/install_h5py.sh @@ -1,9 +1,4 @@ #!/bin/bash apt-get install -y libhdf5-10 libhdf5-dev libhdf5-openmpi-10 libhdf5-openmpi-dev hdf5-tools - -export CC=mpicc -export HDF5_DIR=/usr/lib/x86_64-linux-gnu/hdf5/openmpi -export HDF5_MPI="ON" - -pip install --no-binary=h5py h5py +CC=mpicc HDF5_DIR=/usr/lib/x86_64-linux-gnu/hdf5/openmpi HDF5_MPI="ON" pip install --no-binary=h5py h5py diff --git a/ci/install_mpi4py.sh b/ci/install_mpi4py.sh index d53b536e82b3da88eb4a12362544eb57a2c4b56b..a2f71dca1584c4a95799a1b827361ab6f0b63782 100644 --- a/ci/install_mpi4py.sh +++ b/ci/install_mpi4py.sh @@ -1,4 +1,4 @@ #!/bin/bash apt-get install -y openmpi-bin libopenmpi-dev -pip install mpi4py \ No newline at end of file +pip install mpi4py diff --git a/ci/install_pyHealpix.sh b/ci/install_pyHealpix.sh index 504f9123ff63eb5c9159ebcddc9b43cd06264890..914d0c1d1b7dba1694b5a6d08e446fd576e9f9ed 100644 --- a/ci/install_pyHealpix.sh +++ b/ci/install_pyHealpix.sh @@ -1,7 +1,5 @@ #!/bin/bash git clone https://gitlab.mpcdf.mpg.de/ift/pyHealpix.git -cd pyHealpix -autoreconf -i && ./configure && make -j4 install -cd .. +(cd pyHealpix && autoreconf -i && ./configure --enable-openmp --enable-native-optimizations && make -j4 install) rm -rf pyHealpix diff --git a/ci/install_pyfftw.sh b/ci/install_pyfftw.sh index 670048030bede61ddf1dbcc561a9083876c17f3b..e0c120baf24e0c85671719977cd4b8b73fa853e5 100644 --- a/ci/install_pyfftw.sh +++ b/ci/install_pyfftw.sh @@ -3,7 +3,5 @@ apt-get install -y libatlas-base-dev libfftw3-bin libfftw3-dev libfftw3-double3 libfftw3-long3 libfftw3-mpi-dev libfftw3-mpi3 libfftw3-quad3 libfftw3-single3 git clone -b mpi https://github.com/fredros/pyFFTW.git -cd pyFFTW/ -CC=mpicc python setup.py build_ext install -cd .. -rm -r pyFFTW +(cd pyFFTW && CC=mpicc python setup.py build_ext install) +rm -rf pyFFTW diff --git a/nifty/field_types/field_array.py b/nifty/field_types/field_array.py index bac80ea37fdd739c167058ef2102460d9457c230..4318afa2f3b029c246d992bdaf1cfc25358c8600 100644 --- a/nifty/field_types/field_array.py +++ b/nifty/field_types/field_array.py @@ -22,12 +22,11 @@ from field_type import FieldType class FieldArray(FieldType): def __init__(self, shape): + super(FieldArray, self).__init__() try: - new_shape = tuple([int(i) for i in shape]) + self._shape = tuple([int(i) for i in shape]) except TypeError: - new_shape = (int(shape), ) - self._shape = new_shape - super(FieldArray, self).__init__() + self._shape = (int(shape), ) @property def shape(self): diff --git a/nifty/operators/fft_operator/transformations/gllmtransformation.py b/nifty/operators/fft_operator/transformations/gllmtransformation.py index a0e47652b85fc8f17adf1c08e1bed23bc4130782..7029f80eac7e05f7d967d5de3250665179a0037e 100644 --- a/nifty/operators/fft_operator/transformations/gllmtransformation.py +++ b/nifty/operators/fft_operator/transformations/gllmtransformation.py @@ -100,11 +100,6 @@ class GLLMTransformation(SlicingTransformation): super(GLLMTransformation, cls).check_codomain(domain, codomain) def _transformation_of_slice(self, inp, **kwargs): - if inp.dtype not in (np.float, np.complex): - self.logger.warn("The input array has dtype: %s. The FFT will " - "be performed at double precision." % - str(inp.dtype)) - nlat = self.domain.nlat nlon = self.domain.nlon lmax = self.codomain.lmax diff --git a/nifty/operators/fft_operator/transformations/hplmtransformation.py b/nifty/operators/fft_operator/transformations/hplmtransformation.py index 314caa008bc479aa6596ca658410da7fde233585..c8cb157108cbe4bbe7432a54e461870db370bfac 100644 --- a/nifty/operators/fft_operator/transformations/hplmtransformation.py +++ b/nifty/operators/fft_operator/transformations/hplmtransformation.py @@ -92,11 +92,6 @@ class HPLMTransformation(SlicingTransformation): super(HPLMTransformation, cls).check_codomain(domain, codomain) def _transformation_of_slice(self, inp, **kwargs): - if inp.dtype not in (np.float, np.complex): - self.logger.warn("The input array has dtype: %s. The FFT will " - "be performed at double precision." % - str(inp.dtype)) - lmax = self.codomain.lmax mmax = lmax diff --git a/nifty/operators/fft_operator/transformations/lmgltransformation.py b/nifty/operators/fft_operator/transformations/lmgltransformation.py index 5e743c4da5512902dedf85bdcf7c9353748c109d..44e5c54e8a6c3422fe31705865bd9614ac536a45 100644 --- a/nifty/operators/fft_operator/transformations/lmgltransformation.py +++ b/nifty/operators/fft_operator/transformations/lmgltransformation.py @@ -106,11 +106,6 @@ class LMGLTransformation(SlicingTransformation): super(LMGLTransformation, cls).check_codomain(domain, codomain) def _transformation_of_slice(self, inp, **kwargs): - if inp.dtype not in (np.float, np.complex): - self.logger.warn("The input array has dtype: %s. The FFT will " - "be performed at double precision." % - str(inp.dtype)) - nlat = self.codomain.nlat nlon = self.codomain.nlon lmax = self.domain.lmax diff --git a/nifty/operators/fft_operator/transformations/lmhptransformation.py b/nifty/operators/fft_operator/transformations/lmhptransformation.py index 6aa87e973ae1429e76d5eb8552d586a69ddea1c3..0e9d1e392ff1c14a7bb0e8c391b00cf8a0366e2e 100644 --- a/nifty/operators/fft_operator/transformations/lmhptransformation.py +++ b/nifty/operators/fft_operator/transformations/lmhptransformation.py @@ -94,11 +94,6 @@ class LMHPTransformation(SlicingTransformation): super(LMHPTransformation, cls).check_codomain(domain, codomain) def _transformation_of_slice(self, inp, **kwargs): - if inp.dtype not in (np.float, np.complex): - self.logger.warn("The input array has dtype: %s. The FFT will " - "be performed at double precision." % - str(inp.dtype)) - nside = self.codomain.nside lmax = self.domain.lmax mmax = lmax diff --git a/nifty/operators/fft_operator/transformations/rg_transforms.py b/nifty/operators/fft_operator/transformations/rg_transforms.py index 78028f86b6e39aca0a4168119d6ce73f67038071..0ccdb22c5d7f95adde9c6b220e81aebc6abc8ff8 100644 --- a/nifty/operators/fft_operator/transformations/rg_transforms.py +++ b/nifty/operators/fft_operator/transformations/rg_transforms.py @@ -433,11 +433,6 @@ class FFTW(Transform): not all(axis in range(len(val.shape)) for axis in axes): raise ValueError("Provided axes does not match array shape") - if val.dtype not in (np.float, np.complex): - self.logger.warn("The input array has dtype: %s. The FFT will " - "be performed at double precision." % - str(val.dtype)) - # If the input is a numpy array we transform it locally if not isinstance(val, distributed_data_object): # Cast to a np.ndarray @@ -582,11 +577,6 @@ class NUMPYFFT(Transform): not all(axis in range(len(val.shape)) for axis in axes): raise ValueError("Provided axes does not match array shape") - if val.dtype not in (np.float, np.complex): - self.logger.warn("The input array has dtype: %s. The FFT will " - "be performed at double precision." % - str(val.dtype)) - return_val = val.copy_empty(global_shape=val.shape, dtype=np.complex) diff --git a/nifty/operators/invertible_operator_mixin/invertible_operator_mixin.py b/nifty/operators/invertible_operator_mixin/invertible_operator_mixin.py index 4786a4f9375c7e56e6b52d38005263f2b6f69057..5aaff1097cf10aeeee14ca7232067ed783ff85cc 100644 --- a/nifty/operators/invertible_operator_mixin/invertible_operator_mixin.py +++ b/nifty/operators/invertible_operator_mixin/invertible_operator_mixin.py @@ -104,6 +104,7 @@ class InvertibleOperatorMixin(object): x0=x0) return result + #MR FIXME: why? shouldn't this be equivalent to the adjoint inverse? def _inverse_adjoint_times(self, x, spaces): raise NotImplementedError( "no generic instance method 'inverse_adjoint_times'.") diff --git a/nifty/operators/propagator_operator/harmonic_propagator_operator.py b/nifty/operators/propagator_operator/harmonic_propagator_operator.py index 908e2e372f992dbd0c7afc7ce8fdbc0c62c94833..8789847a8a96dbc2dfa679cf388c5e213fdd6636 100644 --- a/nifty/operators/propagator_operator/harmonic_propagator_operator.py +++ b/nifty/operators/propagator_operator/harmonic_propagator_operator.py @@ -83,7 +83,7 @@ class HarmonicPropagatorOperator(InvertibleOperatorMixin, EndomorphicOperator): # ---Overwritten properties and methods--- - def __init__(self, S=None, M=None, R=None, N=None, inverter=None, + def __init__(self, S, M=None, R=None, N=None, inverter=None, preconditioner=None): """ Sets the standard operator properties and `codomain`, `_A1`, `_A2`, @@ -102,7 +102,6 @@ class HarmonicPropagatorOperator(InvertibleOperatorMixin, EndomorphicOperator): """ # infer domain, and target - # infer domain, and target if M is not None: self._codomain = M.domain self._likelihood = M.times diff --git a/nifty/operators/smoothing_operator/direct_smoothing_operator.py b/nifty/operators/smoothing_operator/direct_smoothing_operator.py index 59ce7406b94bde5c755f6f75e355e3b002f108cf..2e415d62aacb81a4ca97d007912f5650046e9cc8 100644 --- a/nifty/operators/smoothing_operator/direct_smoothing_operator.py +++ b/nifty/operators/smoothing_operator/direct_smoothing_operator.py @@ -144,6 +144,7 @@ class DirectSmoothingOperator(SmoothingOperator): distribution_strategy='not') distance_array = distance_array.get_local_data(copy=False) + #MR FIXME: this causes calls of log(0.) which should probably be avoided if self.log_distances: np.log(distance_array, out=distance_array) diff --git a/nifty/operators/smoothing_operator/fft_smoothing_operator.py b/nifty/operators/smoothing_operator/fft_smoothing_operator.py index 2e764bee29aef937920862bdce9ed318eb32998e..f4f3de8f194f7a8537ed1cacd3e33e0dda216e2f 100644 --- a/nifty/operators/smoothing_operator/fft_smoothing_operator.py +++ b/nifty/operators/smoothing_operator/fft_smoothing_operator.py @@ -24,6 +24,7 @@ class FFTSmoothingOperator(SmoothingOperator): kernel = codomain.get_distance_array( distribution_strategy=axes_local_distribution_strategy) + #MR FIXME: this causes calls of log(0.) which should probably be avoided if self.log_distances: kernel.apply_scalar_function(np.log, inplace=True) @@ -43,6 +44,7 @@ class FFTSmoothingOperator(SmoothingOperator): # apply the kernel if inverse: + #MR FIXME: danger of having division by zero or overflows local_transformed_x /= local_kernel else: local_transformed_x *= local_kernel diff --git a/nifty/spaces/power_space/power_space.py b/nifty/spaces/power_space/power_space.py index ce56812a48db1ddc2751f60dbdd1f60cb101e77c..1e3fbcccff9f9a98d4339fbb7327dcc555a5ce1d 100644 --- a/nifty/spaces/power_space/power_space.py +++ b/nifty/spaces/power_space/power_space.py @@ -261,6 +261,7 @@ class PowerSpace(Space): hdf5_group.attrs['nbin'] = str(self.config["nbin"]) hdf5_group.attrs['binbounds'] = str(self.config["binbounds"]) + #MR FIXME: why not "return None" as happens everywhere else? return { 'harmonic_partner': self.harmonic_partner, 'pindex': self.pindex, diff --git a/nifty/spaces/space/space.py b/nifty/spaces/space/space.py index 84314c48cc968c41d94320d26ee0ba9c4f615d3d..624207d9c44e25800c95e8b90ee0c3e9c54a330f 100644 --- a/nifty/spaces/space/space.py +++ b/nifty/spaces/space/space.py @@ -202,6 +202,4 @@ class Space(DomainObject): raise NotImplementedError def __repr__(self): - string = "" - string += str(type(self)) + "\n" - return string + return str(type(self)) + "\n" diff --git a/nifty/sugar.py b/nifty/sugar.py index d46d25370937fc3d0ebaddb91416801f48e82527..a5bdf5dac97a12bf53b267ec2ea7f74335d35e6d 100644 --- a/nifty/sugar.py +++ b/nifty/sugar.py @@ -18,25 +18,22 @@ from nifty import PowerSpace,\ Field,\ - DiagonalOperator,\ - FFTOperator + DiagonalOperator __all__ = ['create_power_operator'] def create_power_operator(domain, power_spectrum, dtype=None, distribution_strategy='not'): +<<<<<<< nifty/sugar.py """ Creates a diagonal operator with the given power spectrum. - Constructs a diagonal operator that lives over the specified domain, or - its default harmonic codomain in case it is not harmonic. + Constructs a diagonal operator that lives over the specified domain. Parameters ---------- domain : DomainObject - Domain over which the power operator shall live. If this is not a - harmonic domain, it will return an operator for its harmonic codomain - instead. + Domain over which the power operator shall live. power_spectrum : (array-like, method) An array-like object, or a method that implements the square root of a power spectrum as a function of k. @@ -53,21 +50,14 @@ def create_power_operator(domain, power_spectrum, dtype=None, DiagonalOperator : An operator that implements the given power spectrum. """ - - if not domain.harmonic: - fft = FFTOperator(domain) - domain = fft.target[0] +======= +>>>>>>> nifty/sugar.py power_domain = PowerSpace(domain, distribution_strategy=distribution_strategy) - - fp = Field(power_domain, - val=power_spectrum, dtype=dtype, + fp = Field(power_domain, val=power_spectrum, dtype=dtype, distribution_strategy=distribution_strategy) fp **= 2 - f = fp.power_synthesize(mean=1, std=0, real_signal=False) - power_operator = DiagonalOperator(domain, diagonal=f, bare=True) - - return power_operator + return DiagonalOperator(domain, diagonal=f, bare=True) diff --git a/test/test_operators/test_diagonal_operator.py b/test/test_operators/test_diagonal_operator.py index 90f1ef7c4ac2f095d400d4d60e51314b8324cc08..ef953fa0602b50f923d6566fbebe6205f3f8e44c 100644 --- a/test/test_operators/test_diagonal_operator.py +++ b/test/test_operators/test_diagonal_operator.py @@ -106,6 +106,7 @@ class DiagonalOperator_Tests(unittest.TestCase): assert_allclose(trace_op, np.sum(1./diag.val.get_full_data())) @expand(product(spaces, [True, False])) + #MR FIXME: what if any diagonal element <=0? def test_trace_log(self, space, copy): diag = Field.from_random('normal', domain=space) D = DiagonalOperator(space, diagonal=diag, copy=copy) @@ -127,8 +128,9 @@ class DiagonalOperator_Tests(unittest.TestCase): assert_allclose(inv_det, 1./D.determinant()) @expand(product(spaces, [True, False], [True, False])) + #MR FIXME: what if determinant <=0? def test_log_determinant(self, space, bare, copy): diag = Field.from_random('normal', domain=space) D = DiagonalOperator(space, diagonal=diag, bare=bare, copy=copy) log_det = D.log_determinant() - assert_allclose(log_det, np.log(D.determinant())) \ No newline at end of file + assert_allclose(log_det, np.log(D.determinant())) diff --git a/test/test_operators/test_smoothing_operator.py b/test/test_operators/test_smoothing_operator.py index ec582e6d9c627784f4664dc1d0b08c72bfab3103..08505d0eb08838ee3e1d7e6f5dcc54be25bd170c 100644 --- a/test/test_operators/test_smoothing_operator.py +++ b/test/test_operators/test_smoothing_operator.py @@ -36,9 +36,6 @@ def _get_rtol(tp): else: return 1e-5 -from itertools import product -from test.common import expand - class SmoothingOperator_Tests(unittest.TestCase): spaces = [RGSpace(100)]