Commit 8392d7ae authored by Goran Jelic-Cizmek's avatar Goran Jelic-Cizmek
Browse files

Merge branch 'feature/dir_refactor' into 'feature/conda'

Refactored directory structure for Python wrapper

See merge request !3
parents 97f8900c 2a9716b4
# The main product
bin_PROGRAMS = coffe # make all
bin_PROGRAMS = coffe-cli # make all
lib_LIBRARIES = libcoffe.a
......@@ -195,7 +195,7 @@ libcoffe_a_SOURCES = \
src/average_multipoles.c
#include .c and .h in SOURCES so that both appear in dist
coffe_SOURCES = \
coffe_cli_SOURCES = \
$(libcoffe_a_HEADERS) \
src/utils.h \
src/twobessel.h \
......@@ -283,4 +283,3 @@ test_covariance_SOURCES = \
src/twobessel.c \
src/utils.c \
src/covariance.c
from coffe.coffe import (
Coffe,
COFFE_HUBBLE,
)
from coffe.representation import (
Corrfunc,
Multipoles,
Covariance,
)
......@@ -9,16 +9,20 @@
# TODO figure out how to use OpenMP
from libc.stdlib cimport malloc, free
cimport ccoffe
from coffe cimport ccoffe
from coffe.representation import (
Corrfunc,
Multipoles,
Covariance,
)
_COFFE_HUBBLE = (1./(2997.92458))
COFFE_HUBBLE = (1./(2997.92458))
from cython.operator cimport dereference
from ctypes import CFUNCTYPE
from abc import ABC, abstractmethod
from typing import Any, Callable, List, Tuple, Union
from dataclasses import dataclass
import os
......@@ -733,7 +737,7 @@ cdef class Coffe:
f'Cannot find integral with n = {n}, l = {l}'
)
return ccoffe.coffe_interp_spline(&result.result, r * _COFFE_HUBBLE)
return ccoffe.coffe_interp_spline(&result.result, r * COFFE_HUBBLE)
def galaxy_bias1(self, z : float):
......@@ -1309,7 +1313,7 @@ cdef class Coffe:
ccoffe.coffe_interp_spline(&self._background.comoving_distance, z_mean + deltaz) \
- \
ccoffe.coffe_interp_spline(&self._background.comoving_distance, z_mean)
) / _COFFE_HUBBLE
) / COFFE_HUBBLE
@property
......@@ -1385,7 +1389,7 @@ cdef class Coffe:
def k_min(self, value):
_check_parameter('k_min', value, (int, float), 1e-7, 1e-3)
self._parameters.k_min = value
self._parameters.k_min_norm = value / _COFFE_HUBBLE
self._parameters.k_min_norm = value / COFFE_HUBBLE
@property
......@@ -1399,7 +1403,7 @@ cdef class Coffe:
def k_max(self, value):
_check_parameter('k_max', value, (int, float), 0.1, 1e3)
self._parameters.k_max = value
self._parameters.k_max_norm = value / _COFFE_HUBBLE
self._parameters.k_max_norm = value / COFFE_HUBBLE
def set_power_spectrum_linear(self, k : List[float], pk : List[float], z : float = 0):
......@@ -1431,8 +1435,8 @@ cdef class Coffe:
self._free_power_spectrum()
self._parameters.k_min = k[0]
self._parameters.k_max = k[-1]
self._parameters.k_min_norm = k[0] / _COFFE_HUBBLE
self._parameters.k_max_norm = k[-1] / _COFFE_HUBBLE
self._parameters.k_min_norm = k[0] / COFFE_HUBBLE
self._parameters.k_max_norm = k[-1] / COFFE_HUBBLE
size = len(k)
cdef double *x = <double *>ccoffe.coffe_malloc(sizeof(double) * size)
......@@ -1443,8 +1447,8 @@ cdef class Coffe:
for (i, ki), pki in zip(enumerate(k), pk):
x[i] = ki
y[i] = pki
x_norm[i] = ki / _COFFE_HUBBLE
y_norm[i] = pki * _COFFE_HUBBLE**3
x_norm[i] = ki / COFFE_HUBBLE
y_norm[i] = pki * COFFE_HUBBLE**3
ccoffe.coffe_init_spline(
&self._parameters.power_spectrum,
......@@ -1476,7 +1480,7 @@ cdef class Coffe:
if not self._background.flag:
self._background_init()
return ccoffe.coffe_interp_spline(&self._background.comoving_distance, z) / _COFFE_HUBBLE
return ccoffe.coffe_interp_spline(&self._background.comoving_distance, z) / COFFE_HUBBLE
def hubble_rate(self, z : float):
......@@ -1488,7 +1492,7 @@ cdef class Coffe:
if not self._background.flag:
self._background_init()
return ccoffe.coffe_interp_spline(&self._background.Hz, z) * _COFFE_HUBBLE
return ccoffe.coffe_interp_spline(&self._background.Hz, z) * COFFE_HUBBLE
def scale_factor(self, z : float):
......@@ -1512,7 +1516,7 @@ cdef class Coffe:
if not self._background.flag:
self._background_init()
return ccoffe.coffe_interp_spline(&self._background.conformal_Hz, z) * _COFFE_HUBBLE
return ccoffe.coffe_interp_spline(&self._background.conformal_Hz, z) * COFFE_HUBBLE
def hubble_rate_conformal_derivative(self, z : float):
......@@ -1525,7 +1529,7 @@ cdef class Coffe:
if not self._background.flag:
self._background_init()
return ccoffe.coffe_interp_spline(&self._background.conformal_Hz_prime, z) * _COFFE_HUBBLE**2
return ccoffe.coffe_interp_spline(&self._background.conformal_Hz_prime, z) * COFFE_HUBBLE**2
def growth_factor(self, z : float):
......@@ -1596,21 +1600,21 @@ cdef class Coffe:
&self._parameters,
&self._background,
&self._integral,
z, r * _COFFE_HUBBLE, mu, 0,
z, r * COFFE_HUBBLE, mu, 0,
ccoffe.NONINTEGRATED, ccoffe.CORRFUNC
) + \
ccoffe.coffe_integrate(
&self._parameters,
&self._background,
&self._integral,
z, r * _COFFE_HUBBLE, mu, 0,
z, r * COFFE_HUBBLE, mu, 0,
ccoffe.SINGLE_INTEGRATED, ccoffe.CORRFUNC
) + \
ccoffe.coffe_integrate(
&self._parameters,
&self._background,
&self._integral,
z, r * _COFFE_HUBBLE, mu, 0,
z, r * COFFE_HUBBLE, mu, 0,
ccoffe.DOUBLE_INTEGRATED, ccoffe.CORRFUNC
)
......@@ -1660,21 +1664,21 @@ cdef class Coffe:
&self._parameters,
&self._background,
&self._integral,
z, r * _COFFE_HUBBLE, 0, l,
z, r * COFFE_HUBBLE, 0, l,
ccoffe.NONINTEGRATED, ccoffe.MULTIPOLES
) + \
ccoffe.coffe_integrate(
&self._parameters,
&self._background,
&self._integral,
z, r * _COFFE_HUBBLE, 0, l,
z, r * COFFE_HUBBLE, 0, l,
ccoffe.SINGLE_INTEGRATED, ccoffe.MULTIPOLES
) + \
ccoffe.coffe_integrate(
&self._parameters,
&self._background,
&self._integral,
z, r * _COFFE_HUBBLE, 0, l,
z, r * COFFE_HUBBLE, 0, l,
ccoffe.DOUBLE_INTEGRATED, ccoffe.MULTIPOLES
)
......@@ -1717,7 +1721,7 @@ cdef class Coffe:
return np.array([
Multipoles(
z=self._multipoles.array[i].coords.z_mean,
r=self._multipoles.array[i].coords.separation / _COFFE_HUBBLE,
r=self._multipoles.array[i].coords.separation / COFFE_HUBBLE,
l=self._multipoles.array[i].coords.l,
value=self._multipoles.array[i].value,
) for i in range(self._multipoles.size)
......@@ -1759,7 +1763,7 @@ cdef class Coffe:
return np.array([
Corrfunc(
z=self._corrfunc.array[i].coords.z_mean,
r=self._corrfunc.array[i].coords.separation / _COFFE_HUBBLE,
r=self._corrfunc.array[i].coords.separation / COFFE_HUBBLE,
mu=self._corrfunc.array[i].coords.mu,
value=self._corrfunc.array[i].value,
) for i in range(self._corrfunc.size)
......@@ -1861,142 +1865,3 @@ cdef class Coffe:
&self._covariance_multipoles,
&self.__dummy
)
class Representation(ABC):
@abstractmethod
def __init__(self, *args, **kwargs):
pass
def to_dict(self):
"""
The representation of the class as a dictionary.
"""
return {
key : getattr(self, key) \
for key in dir(self.__class__) \
if hasattr(getattr(self.__class__, key), '__set__') \
and not key.startswith('__')
}
def __repr__(self):
"""
User-friendly representation of the class
"""
return f'{self.__class__}({self.to_dict()})'
def _repr_html_(self):
names = self.to_dict().keys()
values = self.to_dict().values()
temp = (
'<tr>' + ('<th>{}</th>' * len(names)).format(*names) + '</tr>'
) if names else ''
header = f'<thead>{temp}</thead>'
body = '<tbody>' + (
'<td>{}</td>' * len(values)
).format(*values) + '</tbody>'
return f'<table>{header}{body}</table>'
class Covariance(Representation):
def __init__(
self, *,
r1 : float, r2 : float,
l1 : int, l2 : int,
z : float,
value : float,
):
self._r1 = r1
self._r2 = r2
self._l1 = l1
self._l2 = l2
self._z = z
self._value = value
@property
def r1(self):
return self._r1
@property
def r2(self):
return self._r2
@property
def l1(self):
return self._l1
@property
def l2(self):
return self._l2
@property
def z(self):
return self._z
@property
def value(self):
return self._value
class Corrfunc(Representation):
def __init__(
self, *,
r : float, mu : float, z : float,
value : float,
):
self._r = r
self._mu = mu
self._z = z
self._value = value
@property
def mu(self):
return self._mu
@property
def r(self):
return self._r
@property
def z(self):
return self._z
@property
def value(self):
return self._value
class Multipoles(Representation):
def __init__(
self, *,
l : int, r : float, z : float,
value : float,
):
self._l = l
self._r = r
self._z = z
self._value = value
@property
def l(self):
return self._l
@property
def r(self):
return self._r
@property
def z(self):
return self._z
@property
def value(self):
return self._value
class Representation:
from abc import ABC, abstractmethod
class Representation(ABC):
@abstractmethod
def __init__(self, *args, **kwargs):
pass
def to_dict(self):
"""
The representation of the class as a dictionary.
"""
return {
key : getattr(self, key) \
for key in dir(self.__class__) \
if hasattr(getattr(self.__class__, key), '__set__') \
and not key.startswith('__')
key: getattr(self, key)
for key in dir(self.__class__)
if hasattr(getattr(self.__class__, key), "__set__")
and not key.startswith("__")
}
def __repr__(self):
"""
User-friendly representation of the class
"""
return f'{self.__class__}({self.to_dict()})'
return f"{self.__class__}({self.to_dict()})"
def _repr_html_(self):
names = self.to_dict().keys()
values = self.to_dict().values()
temp = (
'<tr>' + ('<th>{}</th>' * len(names)).format(*names) + '</tr>'
) if names else ''
header = f'<thead>{temp}</thead>'
("<tr>" + ("<th>{}</th>" * len(names)).format(*names) + "</tr>")
if names
else ""
)
header = f"<thead>{temp}</thead>"
body = '<tbody>' + (
'<td>{}</td>' * len(values)
).format(*values) + '</tbody>'
return f'<table>{header}{body}</table>'
body = "<tbody>" + ("<td>{}</td>" * len(values)).format(*values) + "</tbody>"
return f"<table>{header}{body}</table>"
class Covariance(Representation):
def __init__(
self, *,
r1 : float, r2 : float,
l1 : int, l2 : int,
z : float,
value : float,
self,
*,
r1: float,
r2: float,
l1: int,
l2: int,
z: float,
value: float,
):
self._r1 = r1
self._r2 = r2
......@@ -74,12 +81,14 @@ class Covariance(Representation):
return self._value
class Corrfunc(Representation):
def __init__(
self, *,
r : float, mu : float, z : float,
value : float,
self,
*,
r: float,
mu: float,
z: float,
value: float,
):
self._r = r
self._mu = mu
......@@ -103,12 +112,14 @@ class Corrfunc(Representation):
return self._value
class Multipoles(Representation):
def __init__(
self, *,
l : int, r : float, z : float,
value : float,
self,
*,
l: int,
r: float,
z: float,
value: float,
):
self._l = l
self._r = r
......@@ -130,5 +141,3 @@ class Multipoles(Representation):
@property
def value(self):
return self._value
......@@ -24,7 +24,7 @@ install_cuba(){
git clone --branch "${CUBA_BRANCH}" "${CUBA_REMOTE_URL}" "${CUBA_DIR}"
fi
cd "${CUBA_DIR}" && autoreconf --install && ./configure --prefix="${CONDA_PREFIX}" && make install && cd -
cd "${CUBA_DIR}" && autoreconf --install && ./configure --prefix="${CONDA_PREFIX}" CFLAGS=-fPIC && make install && cd -
printf 'CUBA successfully installed\n'
}
......
#!/usr/bin/env python3
from setuptools import Extension, setup
from Cython.Build import cythonize
setup(
name='Coffe',
version='3.0',
description='The COrrelation Function Full-sky Estimator code',
url='https://github.com/JCGoran/coffe',
author='Goran Jelic-Cizmek',
author_email='goran.jelic-cizmek@unige.ch',
install_requires=['numpy>=1.19.5'],
ext_modules=cythonize([Extension("coffe", ["coffe.pyx"])])
name="Coffe",
version="3.0",
description="The COrrelation Function Full-sky Estimator code",
url="https://github.com/JCGoran/coffe",
author="Goran Jelic-Cizmek",
author_email="goran.jelic-cizmek@unige.ch",
install_requires=["numpy>=1.19.5"],
packages=["coffe"],
ext_modules=cythonize([Extension("coffe.coffe", ["coffe/*.pyx"])]),
)
......@@ -13,13 +13,13 @@ from coffe import Covariance
def covariance_matrix(
cov : List[Covariance],
l : Optional[List[int]] = None,
z_mean : Optional[List[float]] = None,
deltaz : Optional[List[float]] = None,
rmin : Optional[Union[Callable, float, int]] = None,
rmax : Optional[Union[Callable, float, int]] = None,
rstep : Optional[Union[float, int]] = None,
cov: List[Covariance],
l: Optional[List[int]] = None,
z_mean: Optional[List[float]] = None,
deltaz: Optional[List[float]] = None,
rmin: Optional[Union[Callable, float, int]] = None,
rmax: Optional[Union[Callable, float, int]] = None,
rstep: Optional[Union[float, int]] = None,
) -> np.array:
"""
Converts an array of covariances into a numpy matrix for easy matrix
......@@ -56,16 +56,13 @@ def covariance_matrix(
--------
>>> covariance_matrix(coffe.Coffe(has_density=True).compute_corrfunc_bulk())
"""
def convert_array_to_matrix(
arr
):
def convert_array_to_matrix(arr):
size = round(np.sqrt(len(arr)))
return np.reshape(arr, (size, size))
if not all(isinstance(_, Covariance) for _ in cov):
raise ValueError(
f'{cov} is not an array of covariances'
)
raise ValueError(f"{cov} is not an array of covariances")
df = pd.DataFrame([_.to_dict() for _ in cov])
......@@ -87,7 +84,9 @@ def covariance_matrix(
for z, dz in zip(z_mean, deltaz):
df_rmin = df_rmin.append(
df.loc[
(df.r1 >= func_rmin(z, dz)) & (df.r2 >= func_rmin(z, dz)) & (df.z == z)
(df.r1 >= func_rmin(z, dz))
& (df.r2 >= func_rmin(z, dz))
& (df.z == z)
]
)
df = df_rmin
......@@ -101,7 +100,9 @@ def covariance_matrix(
for z, dz in zip(z_mean, deltaz):
df_rmax = df_rmax.append(
df.loc[
(df.r1 <= func_rmax(z, dz)) & (df.r2 <= func_rmax(z, dz)) & (df.z == z)
(df.r1 <= func_rmax(z, dz))
& (df.r2 <= func_rmax(z, dz))
& (df.z == z)
]
)
df = df_rmax
......@@ -111,8 +112,7 @@ def covariance_matrix(
return block_diag(
*[
convert_array_to_matrix(
df.loc[df.z == z].value.to_numpy(dtype=float)
) for z in z_mean
convert_array_to_matrix(df.loc[df.z == z].value.to_numpy(dtype=float))
for z in z_mean
]
)
......@@ -136,12 +136,12 @@ class TestCoffe:
data = np.loadtxt(os.path.join(DATA_DIR, f'benchmark_integral{index}.dat'))
xarr, yarr = np.transpose(data)
for x, y in zip(xarr, yarr):
if x / coffe._COFFE_HUBBLE > 1 \
and x / coffe._COFFE_HUBBLE < 20000:
if x / coffe.COFFE_HUBBLE > 1 \
and x / coffe.COFFE_HUBBLE < 20000:
assert np.isclose(
y,
cosmo.integral(
r=x / coffe._COFFE_HUBBLE,
r=x / coffe.COFFE_HUBBLE,
l=mapping[index]['l'],
n=mapping[index]['n'],
)
......@@ -317,7 +317,7 @@ class TestRepresentation:
Tests for Corrfunc, Multipoles, and Covariance classes.
"""
def test_representation(self):
with pytest.raises(TypeError):
coffe.Representation()
with pytest.raises(ImportError):
from coffe import Representation
coffe.Multipoles(l=0, r=10, z=1.0, value=1e-3)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment