Initial import

This commit is contained in:
Guilhem Lavaux 2023-05-29 10:41:03 +02:00
commit 56a50eead3
820 changed files with 192077 additions and 0 deletions

View file

@ -0,0 +1,89 @@
[system]
console_output=logares.txt
mask_precision=0.9
VERBOSE_LEVEL = 2
N0 = 16
N1 = 16
N2 = 16
#Ndata0=64
#Ndata1=64
#Ndata2=64
L0 = 200
L1 = 200
L2 = 200
corner0 = 0
corner1 = 0
corner2 = 0
NUM_MODES=100
test_mode=true
# If true, the initial power spectrum of the chain is set to the cosmological one
seed_cpower=true
# Indicate which samplers should be blocked for testing purposes
[block_loop]
# Indicate which samplers should be blocked for testing purposes
bias_sampler_blocked=true
nmean_sampler_blocked=true
hades_sampler_blocked=false
ares_heat=1.0
[gravity]
model=CHAIN
models=PRIMORDIAL,TRANSFER_EHU
[gravity_chain_0]
model=PRIMORDIAL
a_final=1.0
[mcmc]
number_to_generate=1
random_ic=false
init_random_scaling=1.0
[likelihood]
[hades]
algorithm=HMC
max_epsilon=0.01
max_timesteps=50
mixing=1
[run]
NCAT = 1
SIMULATION=true
[cosmology]
omega_r = 0
fnl = 0
omega_k = 0
omega_m = 0.3175
omega_b = 0.049
omega_q = 0.6825
w = -1
wprime = 0
n_s = 0.9624
sigma8 = 0.8344
h100 = 0.6711
beta = 1.5
z0 = 0
# 11.5 mag cut
[catalog_0]
datafile = 2MPP.txt
bias=8,1,0.1,1
halo_selection=none
refbias = false
nmean=10
[python]
likelihood_path=test_likelihood.py
bias_sampler_type=slice

View file

@ -0,0 +1,73 @@
#
# This python script gives an example on using JAX and PyBORG together
#
import jax
import numpy as np
import borg
cons = borg.console()
myprint=lambda x: cons.print_std(x) if type(x) == str else cons.print_std(repr(x))
myprint("Hello!")
@jax.jit
def jax_func(rho):
return rho**2
class MyModel(borg.forward.BaseForwardModel):
def __init__(self, box):
myprint("Start forward model")
super().__init__(box, box)
def getPreferredInput(self):
return borg.forward.PREFERRED_REAL
def getPreferredOutput(self):
return borg.forward.PREFERRED_REAL
def forwardModel_v2_impl(self, input_array):
# Save the input data in a jax array (i.e. upload to accelerator)
self.save = jax.numpy.array(input_array)
def getDensityFinal_impl(self, output_array):
# Run forward, and save the AG function
fwd, self.ag_fun = jax.vjp(jax_func, self.save)
output_array[:] = fwd
def adjointModel_v2_impl(self, input_ag):
# Save the ag vector
self.ag = input_ag
def getAdjointModel_impl(self, output_ag):
# Evaluate the new function with ag_fun
out_ag, = self.ag_fun(self.ag)
output_ag[:] = out_ag
def build_gravity_model(box):
chain = borg.forward.ChainForwardModel(box)
chain.addModel(borg.forward.models.Primordial(box, 1.0))
chain.addModel(borg.forward.models.EisensteinHu(box))
chain.addModel(borg.forward.models.BorgLpt(box, box, ai=1.0))
chain.addModel(MyModel(box))
return chain
if __name__ == "__main__":
box = borg.forward.BoxModel()
cpar = borg.cosmo.CosmologicalParameters()
chain = build_gravity_model(box)
chain.setCosmoParams(cpar)
s_hat = np.fft.rfftn(np.random.randn(*box.N)/np.sqrt(box.N[0]**3))
myprint(np.var(s_hat))
chain.forwardModel_v2(s_hat)
rho = np.zeros(chain.getOutputBoxModel().N)
chain.getDensityFinal(rho)
ag = 2*rho
chain.adjointModel_v2(ag)
chain.getAdjointModel(ag)

View file

@ -0,0 +1,73 @@
#
# Example to run a Altair forward model with PyBORG
#
import borg
import numpy as np
# Setup resolution of the initial mesh
Ng = 64
# Box size in Mpc/h
L = 8000.0
# setup the box
bb = borg.forward.BoxModel()
bb.L = L, L, L
bb.N = Ng, Ng, Ng
bb.xmin = -L/2,-L/2,-L/2
print(bb)
# Initialize some default cosmology
cosmo = borg.cosmo.CosmologicalParameters()
# Fiducial scale factor to express initial conditions
a0 = 0.1
chain = borg.forward.ChainForwardModel(bb)
# Add primordial fluctuations
chain.addModel(borg.forward.models.Primordial(bb, a0))
# Add E&Hu transfer function
chain.addModel(borg.forward.models.EisensteinHu(bb))
# Run an LPT model from a=0.0 to af. The ai=a0 is the scale factor at which the IC are expressed
lpt = borg.forward.models.BorgLpt(bb, bb, ai=a0, af=1.0)
chain.addModel(lpt)
Lz=10000
altair = borg.forward.models.newModel(
"ALTAIR_AP",
bb,
dict(
corner0_z=-Lz/2,
corner1_z=-Lz/2,
corner2_z=-Lz/2,
L0_z=Lz,
L1_z=Lz,
L2_z=Lz,
N0_z=64,
N1_z=64,
N2_z=64,
is_contrast=True
),
)
chain.addModel(altair)
# Set the cosmology
chain.setCosmoParams(cosmo)
# Generate white noise: it has to be scaled by 1/N**(3./2) to be one in Fourier
ic = np.random.randn(Ng, Ng, Ng) / np.sqrt(Ng ** 3)
delta_m = np.zeros(lpt.getOutputBoxModel().N)
delta_m_ap = np.zeros(chain.getOutputBoxModel().N)
# RUN!
chain.forwardModel_v2(ic)
lpt.getDensityFinal(delta_m)
chain.getDensityFinal(delta_m_ap)
# Obtain the particles
pp = np.zeros((lpt.getNumberOfParticles(), 3))
lpt.getParticlePositions(pp)
print(pp)

View file

@ -0,0 +1,49 @@
#
# Example to run a forward model with PyBORG
#
import borg
import numpy as np
# Setup resolution of the initial mesh
Ng=64
# Box size in Mpc/h
L=100.
# setup the box
bb = borg.forward.BoxModel()
bb.L = L,L,L
bb.N = Ng,Ng,Ng
# Initialize some default cosmology
cosmo = borg.cosmo.CosmologicalParameters()
# Fiducial scale factor to express initial conditions
a0=0.1
chain = borg.forward.ChainForwardModel(bb)
# Add primordial fluctuations
chain.addModel(borg.forward.models.Primordial(bb, a0))
# Add E&Hu transfer function
chain.addModel(borg.forward.models.EisensteinHu(bb))
# Run an LPT model from a=0.0 to af. The ai=a0 is the scale factor at which the IC are expressed
lpt = borg.forward.models.BorgLpt(bb, bb, ai=a0, af=1.0)
chain.addModel(lpt)
# Set the cosmology
chain.setCosmoParams(cosmo)
# Generate white noise: it has to be scaled by 1/N**(3./2) to be one in Fourier
ic = np.random.randn(Ng, Ng, Ng)/np.sqrt(Ng**3)
delta_m = np.zeros((Ng,Ng,Ng))
# RUN!
chain.forwardModel_v2(ic)
chain.getDensityFinal(delta_m)
# Obtain the particles
pp = np.zeros((lpt.getNumberOfParticles(),3))
lpt.getParticlePositions(pp)
print(pp)

View file

@ -0,0 +1,87 @@
import itertools
from tqdm import tqdm
import borg
import numpy as np
def build_gravity_model(state, box, cpar):
print(cpar)
lpt = borg.forward.models.BorgLpt(box, box, ai=1.0)
chain = borg.buildDefaultChain(box, cpar, 1.0, lpt)
return chain, lpt
def build_likelihood(state, info):
return borg.likelihood.GaussianLinear(info)
if not borg.EMBEDDED and __name__ == "__main__":
from tqdm import tqdm
Ng = 8
cpar = borg.cosmo.CosmologicalParameters()
state = borg.likelihood.MarkovState()
info = borg.likelihood.LikelihoodInfo()
info["GRID_LENGTH"] = np.array([0, 100., 0, 100., 0, 100.])
info["GRID"] = np.array([Ng, Ng, Ng], dtype=np.uint32)
box = borg.forward.BoxModel(100., Ng)
state.newArray3d("galaxy_data_0", Ng, Ng, Ng)
fwd, lpt = build_gravity_model(state, box, cpar)
state.newForwardModel("BORG_model", fwd)
state.newScalar("corner0", 0.0)
state.newScalar("corner1", 0.0)
state.newScalar("corner2", 0.0)
state.newScalar("localNdata0", 0, False, "L")
state.newScalar("localNdata1", Ng, False, "L")
state.newScalar("localNdata2", 0, False, "L")
state.newScalar("localNdata3", Ng, False, "L")
state.newScalar("localNdata4", 0, False, "L")
state.newScalar("localNdata5", Ng, False, "L")
state.newScalar("ares_heat", 1.0)
state.newScalar("NCAT", 1, False, "L")
state.newScalar("galaxy_bias_ref_0", False)
state.newScalar("cosmology", cpar)
state.newScalar("galaxy_nmean_0", 0.0)
state.newArray1d("galaxy_bias_0", 2)
state.newArray3d("galaxy_synthetic_sel_window_0", Ng, Ng, Ng)
state["galaxy_bias_0"][:] = np.array([1.0, 1.0])
state["galaxy_synthetic_sel_window_0"][:] = 1
like = build_likelihood(state, info)
like.initializeLikelihood(state)
like.updateMetaParameters(state)
s_hat = np.fft.rfftn(np.random.randn(Ng, Ng, Ng) / Ng**(1.5))
like.generateMockData(s_hat, state)
like.logLikelihood(s_hat)
analytic_gradient = like.gradientLikelihood(s_hat)
num_gradient = np.zeros((Ng, Ng, Ng // 2 + 1), dtype=np.complex128)
s_hat_epsilon = s_hat.copy()
epsilon = 0.001
for i, j, k in tqdm(itertools.product(*map(range, [Ng, Ng, Ng // 2 + 1])),
total=Ng * Ng * (Ng // 2 + 1)):
s_hat_epsilon[i, j, k] = s_hat[i, j, k] + epsilon
L = like.logLikelihood(s_hat_epsilon)
s_hat_epsilon[i, j, k] = s_hat[i, j, k] - epsilon
L -= like.logLikelihood(s_hat_epsilon)
QQ = L / (2.0 * epsilon)
s_hat_epsilon[i, j, k] = s_hat[i, j, k] + 1j * epsilon
L = like.logLikelihood(s_hat_epsilon)
s_hat_epsilon[i, j, k] = s_hat[i, j, k] - 1j * epsilon
L -= like.logLikelihood(s_hat_epsilon)
QQ = QQ + L * 1j / (2.0 * epsilon)
s_hat_epsilon[i, j, k] = s_hat[i, j, k]
num_gradient[i, j, k] = QQ
np.savez("gradients.npz", num=num_gradient, ana=analytic_gradient)

View file

@ -0,0 +1,89 @@
import numpy as np
import borg
cons = borg.console()
myprint = lambda x: cons.print_std(x) if type(x) == str else cons.print_std(
repr(x))
sigma_noise = 0.1
class MyLikelihood(borg.likelihood.BaseLikelihood):
def __init__(self, fwd, N, L):
myprint(f" Init {N}, {L}")
super().__init__(fwd, N, L)
self.comm = fwd.getCommunicator()
def initializeLikelihood(self, state):
myprint("Init likelihood")
self.data = state['galaxy_data_0']
state.newArray3d("my_density_field", self.data.shape[0],
self.data.shape[1], self.data.shape[2], True)
def updateMetaParameters(self, state):
cpar = state['cosmology']
myprint(f"Cosmology is {cpar}")
self.getForwardModel().setCosmoParams(cpar)
def generateMockData(self, s_hat, state):
fwd = self.getForwardModel()
output = np.zeros(fwd.getOutputBoxModel().N)
fwd.forwardModel_v2(s_hat)
fwd.getDensityFinal(output)
state['galaxy_data_0'][:] = output + np.random.normal(
size=output.shape) * sigma_noise
state['my_density_field'][:] = output
like = ((state['galaxy_data_0'][:] - output)**2).sum() / sigma_noise**2
myprint(
f"Initial log_likelihood: {like}, var(s_hat) = {np.var(s_hat)}")
def logLikelihoodComplex(self, s_hat, gradientIsNext):
fwd = self.getForwardModel()
output = np.zeros(fwd.getBoxModel().N)
fwd.forwardModel_v2(s_hat)
fwd.getDensityFinal(output)
L = 0.5 * ((output - self.data)**2).sum() / sigma_noise**2
myprint(f"var(s_hat): {np.var(s_hat)}, Call to logLike: {L}")
return self.comm.allreduce(L)
def gradientLikelihoodComplex(self, x_hat):
fwd = self.getForwardModel()
output = np.zeros(fwd.getOutputBoxModel().N)
fwd.forwardModel_v2(x_hat)
fwd.getDensityFinal(output)
mygradient = (output - self.data) / sigma_noise**2
fwd.adjointModel_v2(mygradient)
mygrad_hat = np.zeros(s_hat.shape, dtype=np.complex128)
fwd.getAdjointModel(mygrad_hat)
return mygrad_hat
model = None
@borg.registerGravityBuilder
def build_gravity_model(state, box):
global model
chain = borg.forward.ChainForwardModel(box)
chain.addModel(borg.forward.models.HermiticEnforcer(box))
chain.addModel(borg.forward.models.Primordial(box, 1.0))
chain.addModel(borg.forward.models.EisensteinHu(box))
model = chain
return chain
@borg.registerLikelihoodBuilder
def build_likelihood(state, info):
boxm = model.getBoxModel()
like = MyLikelihood(model, boxm.N, boxm.L)
#like.initializeLikelihood(state)
return like
@borg.registerSamplerBuilder
def build_samplers(state, info):
return []

View file

@ -0,0 +1,84 @@
import itertools
from tqdm import tqdm
import borg
import numpy as np
cons = borg.console()
myprint = lambda x: cons.print_std(x) if type(x) == str else cons.print_std(
repr(x))
def build_gravity_model(box, cpar):
lpt = borg.forward.models.BorgLpt(box, box, ai=1.0)
chain = borg.buildDefaultChain(box, cpar, 1.0, lpt)
vfield = borg.forward.velocity.CICModel(box, lpt)
return chain, lpt, vfield
if not borg.EMBEDDED and __name__ == "__main__":
from tqdm import tqdm
Ng = 8
# Create the auxiliary objects
cpar = borg.cosmo.CosmologicalParameters()
box = borg.forward.BoxModel(100., Ng)
fwd, lpt, vfield = build_gravity_model(box, cpar)
s_hat = np.fft.rfftn(np.random.randn(Ng, Ng, Ng) / Ng**(1.5))
def vfield_like(s_hat):
fwd.forwardModel_v2(s_hat)
rho = np.zeros((Ng, Ng, Ng))
fwd.getDensityFinal(rho)
vgrid = vfield.getVelocityField()
return (vgrid**2).sum()
def vfield_ag(s_hat):
fwd.forwardModel_v2(s_hat)
rho = np.zeros((Ng, Ng, Ng))
fwd.getDensityFinal(rho)
# The derivative of square is 2 * vector
vgrid = 2 * vfield.getVelocityField()
fwd.clearAdjointGradient()
vfield.computeAdjointModel(vgrid)
myprint("Calling adjoint")
# We have to trigger the adjoint computation in any case
fwd.adjointModel_v2(None)
myprint("Done with adjoint")
analytic_gradient = np.zeros((Ng, Ng, Ng // 2 + 1),
dtype=np.complex128)
fwd.getAdjointModel(analytic_gradient)
return analytic_gradient
myprint("Running adjoint")
num_gradient = np.zeros((Ng, Ng, Ng // 2 + 1), dtype=np.complex128)
s_hat_epsilon = s_hat.copy()
cons.setVerboseLevel(5)
analytic_gradient = vfield_ag(s_hat)
cons.setVerboseLevel(1)
epsilon = 0.001
for i, j, k in tqdm(itertools.product(*map(range, [Ng, Ng, Ng // 2 + 1])),
total=Ng * Ng * (Ng // 2 + 1)):
s_hat_epsilon[i, j, k] = s_hat[i, j, k] + epsilon
L = vfield_like(s_hat_epsilon)
s_hat_epsilon[i, j, k] = s_hat[i, j, k] - epsilon
L -= vfield_like(s_hat_epsilon)
QQ = L / (2.0 * epsilon)
s_hat_epsilon[i, j, k] = s_hat[i, j, k] + 1j * epsilon
L = vfield_like(s_hat_epsilon)
s_hat_epsilon[i, j, k] = s_hat[i, j, k] - 1j * epsilon
L -= vfield_like(s_hat_epsilon)
QQ = QQ + L * 1j / (2.0 * epsilon)
s_hat_epsilon[i, j, k] = s_hat[i, j, k]
num_gradient[i, j, k] = QQ
np.savez("gradients.npz", num=num_gradient, ana=analytic_gradient)

View file

@ -0,0 +1 @@
add_subdirectory(${CMAKE_SOURCE_DIR}/extra/python/python)

View file

@ -0,0 +1,118 @@
IF (BUILD_PYTHON_EXTENSION)
function(add_pyborg_doc)
message(STATUS "Docfiles=${docfiles}" )
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/pyborg_doc)
set(generated_headers)
foreach(filename IN LISTS ARGV)
STRING(REGEX REPLACE "^.*/([a-zA-Z0-9_\.]*)\\.rst\$" ${CMAKE_CURRENT_BINARY_DIR}/pyborg_doc/\\1.hpp filename_hpp ${filename})
add_custom_command(
OUTPUT ${filename_hpp}
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/doc/convert.py ${CMAKE_CURRENT_BINARY_DIR}/pyborg_doc ${filename}
DEPENDS ${filename}
)
set(generated_headers ${generated_headers} ${filename_hpp})
endforeach()
target_sources(python_borg PRIVATE ${generated_headers})
endfunction()
message(STATUS "INCLUDE_PATH=${ARES_INCLUDE_PATH}")
include_directories(
${CMAKE_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_SOURCE_DIR}/extra/hades
${CMAKE_SOURCE_DIR}/extra/borg
${ARES_INCLUDE_PATH} ${HDF5_INCLUDE_DIR} ${EIGEN_INCLUDE_DIRS})
set(DEP_LIBS
${COSMOTOOL_LIB}
${BOOST_LIBRARIES}
${HEALPIX_LIBRARIES}
${HDF5_CXX_LIBRARIES}
${HDF5_LIBRARIES}
${FFTW_LIBRARIES}
${GSL_LIBRARY}
${GSL_CBLAS_LIBRARY}
${ZLIB_LIBRARY}
${DL_LIBRARY}
${EXTRA_LIB}
)
add_library(python_borg
base.cpp pycosmo.cpp pyforward.cpp pyforward_borg.cpp
pybias.cpp pyforward_all.cpp bind.cpp pyvelocity.cpp pylikelihood.cpp
pysamplers.cpp any_wrapper.cpp
)
set_property(TARGET python_borg PROPERTY POSITION_INDEPENDENT_CODE ON)
target_link_libraries(python_borg LSS ${DEP_LIBS} pybind11::module)
add_library(_borg MODULE
_borg.cpp
)
target_link_libraries(_borg PRIVATE python_borg LSS ${DEP_LIBS} pybind11::module)
set_target_properties(_borg PROPERTIES PREFIX "${PYTHON_MODULE_PREFIX}" SUFFIX "${PYTHON_MODULE_EXTENSION}")
IF(NOT APPLE)
target_link_options(_borg PRIVATE "LINKER:--version-script=${CMAKE_CURRENT_SOURCE_DIR}/_borg.version")
ENDIF()
file(GLOB PYBORG_DOC_FILE doc/*.rst)
add_pyborg_doc(${PYBORG_DOC_FILE})
#
# Scripting to install the python module at the correct place. By default we install in the local folder
#
# Discover where to put packages
if (NOT PYTHON_SITE_PACKAGES)
execute_process (
COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"
OUTPUT_VARIABLE internal_PYTHON_SITE_PACKAGES
OUTPUT_STRIP_TRAILING_WHITESPACE
)
SET(SYSTEM_PYTHON_SITE_PACKAGES
${internal_PYTHON_SITE_PACKAGES}
CACHE PATH "Path to the target system-wide site-package where to install python modules")
execute_process (
COMMAND ${PYTHON_EXECUTABLE} -c "from site import USER_SITE; print(USER_SITE)"
OUTPUT_VARIABLE internal_PYTHON_SITE_PACKAGES
OUTPUT_STRIP_TRAILING_WHITESPACE
)
SET(USER_PYTHON_SITE_PACKAGES
${internal_PYTHON_SITE_PACKAGES}
CACHE PATH "Path to the target user site-package where to install python modules")
mark_as_advanced(USER_PYTHON_SITE_PACKAGES SYSTEM_PYTHON_SITE_PACKAGES)
endif (NOT PYTHON_SITE_PACKAGES)
message(STATUS "System python site: ${SYSTEM_PYTHON_SITE_PACKAGES}")
message(STATUS "User python site: ${USER_PYTHON_SITE_PACKAGES}")
OPTION(INSTALL_PYTHON_LOCAL "Indicates the destination of the Python installation: User or System" ON)
IF (NOT PYTHON_SITE_PACKAGES)
IF (NOT INSTALL_PYTHON_LOCAL)
SET(PYTHON_SITE_PACKAGES ${SYSTEM_PYTHON_SITE_PACKAGES})
ELSE (NOT INSTALL_PYTHON_LOCAL)
SET(PYTHON_SITE_PACKAGES ${USER_PYTHON_SITE_PACKAGES})
ENDIF(NOT INSTALL_PYTHON_LOCAL)
ENDIF()
cmessage(STATUS "Python install location: ${PYTHON_SITE_PACKAGES}")
INSTALL(TARGETS
_borg
LIBRARY DESTINATION ${PYTHON_SITE_PACKAGES}/aquila_borg
)
OPTION(INSTALL_COMPATIBILITY_PYBORG "Install the borg package as a compatibility package to aquila_borg (conflict with borgbackup)" ON)
IF(INSTALL_COMPATIBILITY_PYBORG)
INSTALL(DIRECTORY borg DESTINATION ${PYTHON_SITE_PACKAGES}
FILES_MATCHING PATTERN "*.py")
ENDIF()
INSTALL(DIRECTORY aquila_borg DESTINATION ${PYTHON_SITE_PACKAGES}
FILES_MATCHING PATTERN "*.py")
ENDIF()

View file

@ -0,0 +1,144 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/_borg.cpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include "libLSS/mpi/generic_mpi.hpp"
#include <memory>
#include <dlfcn.h>
#include <cstring>
#include <cstdlib>
#include <exception>
#include <boost/format.hpp>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <CosmoTool/fourier/fft/fftw_calls.hpp>
#if defined(ARES_MPI_FFTW)
# include <CosmoTool/fourier/fft/fftw_calls_mpi.hpp>
#endif
#include "libLSS/tools/console.hpp"
#include "libLSS/tools/static_init.hpp"
#include "libLSS/tools/cpu/feature_check.hpp"
#include "pyborg.hpp"
namespace py = pybind11;
namespace lss = LibLSS;
namespace {
#if defined(ARES_MPI_FFTW)
lss::RegisterStaticInit reg0(fftw_mpi_init, fftw_mpi_cleanup, 9, "MPI/FFTW");
#endif
// WISDOM must come at the end. Otherwise it is reset
lss::RegisterStaticInit reg1(
CosmoTool::init_fftw_wisdom, CosmoTool::save_fftw_wisdom, 12,
"FFTW/WISDOM");
#if !defined(ARES_MPI_FFTW) && \
defined( \
_OPENMP) // Do not use MPI and Threaded FFTW at the same time for the moment.
lss::RegisterStaticInit
reg2(fftw_init_threads, fftw_cleanup_threads, 11, "FFTW/THREADS");
#endif
} // namespace
static void finalize() {
LibLSS::Python::shuttingDown();
lss::StaticInit::finalize();
}
template <typename Signature>
static std::function<Signature> cast(void *f) {
return reinterpret_cast<Signature *>(f);
}
static void build_argc_argv(int &argc, char **&argv) {
auto sys = py::module::import("sys");
py::list py_argv = sys.attr("argv");
argc = 0;
argv = (char **)::malloc(sizeof(char *) * (py_argv.size()+1));
for (auto &o : py_argv) {
std::string s = py::cast<std::string>(o);
argv[argc++] = ::strdup(s.c_str());
}
argv[argc] = 0;
// Remove all arguments from the argv list.
py_argv.attr("clear")();
}
void free_argc_argv(int &argc, char **&argv) {
auto sys = py::module::import("sys");
py::list py_argv = sys.attr("argv");
for (int i = 0; i < argc; i++) {
py_argv.append(argv[i]);
free(argv[i]);
}
free(argv);
}
PYBIND11_MODULE(_borg, m) {
m.doc() = "ARES/BORG python binding module"; // optional module docstring
lss::Python::setupConsole();
bool foundMPI4PY = true;
// Try to access mpi4py
#if defined(ARES_MPI_FFTW)
try {
py::module mpi4py = py::module::import("mpi4py.MPI");
m.attr("_mpi_addressof") = mpi4py.attr("_addressof");
if (LibLSS::MPI_IS_REAL) {
lss::setupMPI((MPI_Comm)(py::cast<long long>(
mpi4py.attr("_handleof")(mpi4py.attr("COMM_WORLD")))));
lss::Python::mpi4py_available = true;
}
} catch (py::error_already_set &) {
// Ignore mpi4py errors.
// Print a warning though
foundMPI4PY = false;
lss::Python::mpi4py_available = false;
int argc;
char **argv;
// This hack is for IntelMPI. Shame on you.
build_argc_argv(argc, argv);
lss::setupMPI(argc, argv);
free_argc_argv(argc, argv);
}
#endif
lss::StaticInit::execute();
#if defined(ARES_MPI_FFTW)
if (foundMPI4PY)
lss::Console::instance().print<lss::LOG_INFO>("Found MPI4PY.");
else
lss::Console::instance().print<lss::LOG_INFO>(
"Not Found MPI4PY. Starting without MPI.");
#endif
{
std::string cpu_features;
auto &cons = lss::Console::instance();
bool result = lss::check_compatibility(cpu_features);
cons.format<lss::LOG_INFO>("CPU features: %s", cpu_features);
if (!result) {
cons.print<lss::LOG_ERROR>(
"Binary is incompatible with your CPU. Stop here.");
lss::MPI_Communication::instance()->abort();
return;
}
}
lss::Python::bindBORG(m);
// Register LSS cleanup
Py_AtExit(finalize);
/* auto atexit = py::module::import("atexit");
atexit.attr("register")(
py::cpp_function([]() { lss::StaticInit::finalize(); }));*/
}
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1,7 @@
CODEABI_1.0 {
global:
PyInit__borg;
_init;
_fini;
local: *;
};

View file

@ -0,0 +1,182 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/any_wrapper.cpp
Copyright (C) 2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include "libLSS/mpi/generic_mpi.hpp"
#include "libLSS/tools/static_init.hpp"
#include "libLSS/tools/console.hpp"
#include <memory>
#include <exception>
#include <boost/format.hpp>
#include <pybind11/pybind11.h>
#include <pybind11/eval.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include "pyborg.hpp"
#include "pyfuse.hpp"
#include "libLSS/tools/array_tools.hpp"
#include "libLSS/tools/fusewrapper.hpp"
#include "libLSS/samplers/core/types_samplers.hpp"
using namespace LibLSS;
namespace py = pybind11;
using namespace LibLSS;
template <typename A, size_t... I>
auto extents_from_numpy(A const &a, std::integer_sequence<size_t, I...>) {
return array::extent((size_t)a.shape(I)...);
}
struct basic_any_converter {
virtual py::object load(boost::any &) const = 0;
virtual boost::any store(py::object) const = 0;
};
template <typename T>
struct any_scalar_converter : basic_any_converter {
static basic_any_converter *instance() {
static any_scalar_converter<T> obj;
return &obj;
}
py::object load(boost::any &e) const override {
T value = boost::any_cast<T>(e);
return py::cast(value);
}
boost::any store(py::object obj) const override {
return boost::any(obj.cast<T>());
}
};
template <typename T>
struct any_array_converter : basic_any_converter {
static basic_any_converter *instance() {
static any_array_converter<T> obj;
return &obj;
}
py::object load(boost::any &e) const override {
T array = boost::any_cast<T>(e);
typedef typename T::element element;
std::array<ssize_t, T::dimensionality> shapes, strides;
std::copy(array.shape(), array.shape() + shapes.size(), shapes.begin());
for (int i = 0; i < strides.size(); i++)
strides[i] = array.strides()[i] * sizeof(element);
return py::array_t<element>(shapes, strides, array.data());
}
boost::any store(py::object obj) const override {
py::array_t<typename T::element> a = obj;
auto a_u = a.template unchecked<T::dimensionality>();
T tmp(extents_from_numpy(
a_u, std::make_integer_sequence<size_t, T::dimensionality>()));
Python::PyToFuseArray<typename T::element, T::dimensionality, false>
mapped_array(a_u);
fwrap(tmp) = mapped_array;
return boost::any(tmp);
}
};
struct any_to_python_impl {
private:
typedef std::map<std::type_index, basic_any_converter *> Map;
typedef std::map<std::tuple<int, char>, basic_any_converter *> InvMap;
Map any_converter;
InvMap inv_converter;
any_to_python_impl() {
any_converter[typeid(bool)] = any_scalar_converter<bool>::instance();
any_converter[typeid(size_t)] = any_scalar_converter<size_t>::instance();
any_converter[typeid(double)] = any_scalar_converter<double>::instance();
any_converter[typeid(boost::multi_array<size_t, 1>)] =
any_array_converter<boost::multi_array<size_t, 1>>::instance();
any_converter[typeid(LibLSS::multi_array<double, 1>)] =
any_array_converter<LibLSS::multi_array<double, 1>>::instance();
any_converter[typeid(boost::multi_array<double, 1>)] =
any_array_converter<boost::multi_array<double, 1>>::instance();
any_converter[typeid(boost::multi_array<size_t, 2>)] =
any_array_converter<boost::multi_array<size_t, 2>>::instance();
any_converter[typeid(boost::multi_array<double, 2>)] =
any_array_converter<boost::multi_array<double, 2>>::instance();
any_converter[typeid(boost::multi_array<size_t, 3>)] =
any_array_converter<boost::multi_array<size_t, 3>>::instance();
any_converter[typeid(boost::multi_array<double, 3>)] =
any_array_converter<boost::multi_array<double, 3>>::instance();
inv_converter[std::make_tuple(0, 'u')] =
any_scalar_converter<size_t>::instance();
inv_converter[std::make_tuple(0, 'f')] =
any_scalar_converter<double>::instance();
inv_converter[std::make_tuple(1, 'u')] =
any_array_converter<boost::multi_array<size_t, 1>>::instance();
inv_converter[std::make_tuple(1, 'f')] =
any_array_converter<boost::multi_array<double, 1>>::instance();
inv_converter[std::make_tuple(2, 'u')] =
any_array_converter<boost::multi_array<size_t, 2>>::instance();
inv_converter[std::make_tuple(2, 'f')] =
any_array_converter<boost::multi_array<double, 2>>::instance();
inv_converter[std::make_tuple(3, 'u')] =
any_array_converter<boost::multi_array<size_t, 3>>::instance();
inv_converter[std::make_tuple(3, 'f')] =
any_array_converter<boost::multi_array<double, 3>>::instance();
}
public:
static any_to_python_impl *instance() {
static any_to_python_impl cvt;
return &cvt;
}
py::object a2p(boost::any &a) {
if (a.empty())
return py::none();
Map::iterator iter = any_converter.find(a.type());
if (iter == any_converter.end())
throw std::runtime_error("Unknown stored type.");
return iter->second->load(a);
}
boost::any p2a(py::object o) {
basic_any_converter *cvt = 0;
// Handle array objects
if (py::isinstance<py::array>(o)) {
py::array a = o;
auto iter =
inv_converter.find(std::make_tuple(a.ndim(), a.dtype().kind()));
if (iter == inv_converter.end())
throw std::runtime_error("Unknown type to store.");
cvt = iter->second;
} else if (py::isinstance<py::bool_>(o)) {
cvt = any_scalar_converter<bool>::instance();
} else if (py::isinstance<py::float_>(o)) {
cvt = any_scalar_converter<double>::instance();
} else if (py::isinstance<py::int_>(o)) {
cvt = any_scalar_converter<size_t>::instance();
} else {
throw std::runtime_error("Unknown type to store.");
}
return cvt->store(o);
}
};
py::object LibLSS::Python::any_to_python(boost::any &a) {
return any_to_python_impl::instance()->a2p(a);
}
boost::any LibLSS::Python::python_to_any(py::object o) {
return any_to_python_impl::instance()->p2a(o);
}
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: year(0) = 2020
// ARES TAG: email(0) = guilhem.lavaux@iap.fr

View file

@ -0,0 +1,133 @@
#+
# ARES/HADES/BORG Package -- ./extra/python/python/aquila_borg/__init__.py
# Copyright (C) 2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
#
# Additional contributions from:
# Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
#
#+
"""
PyBORG root module
==================
PyBORG is a complete binding of the borg machine to python. The borg
module can be imported either from a normal python interpret or from
the embedded python in hades_python.
Be aware that you cannot import directly any of the native modules. To import
all borg facilities, it is required *and* sufficient to just execute ``import aquila_borg``.
It will provide all the modules such as `aquila_borg.cosmo` or `aquila_borg.samplers`.
*Note:* The `borg` module may be installed as an alias to `aquila_borg`. However the package name
is the same as the one used by BorgBackup. Thus there may be clashes between these two softwares.
It is advised to use `aquila_borg` to avoid conflicts.
"""
import sys
import io
import contextlib
import logging
try:
import mpi4py
MPI4PY_AVAILABLE = True
except:
MPI4PY_AVAILABLE = False
from .borg_native import *
from . import dft
from . import utils
class _RewriteIO(io.IOBase):
def __init__(self, original):
self.original = original
self.newline = False
if MPI4PY_AVAILABLE:
self.comm = mpi4py.MPI.COMM_WORLD
self.prefix = f"[{self.comm.rank} / {self.comm.size}] "
else:
self.prefix = "[0/0]"
def write(self, b):
if b[0] == "\n":
return self.original.write(b)
return self.original.write(self.prefix + b)
def writelines(self, lines):
return self.original.writelines(lines)
class BorgMessageStream(io.IOBase):
def __init__(self, console, level='std'):
super().__init__()
self.console = console
if level == 'std':
self.printer = console.print_std
elif level == 'warn':
self.printer = console.print_warning
elif level == 'error':
self.printer = console.print_error
else:
raise ValueError()
def write(self, b):
for line in b.split(sep="\n"):
self.printer(line)
def writelines(self, lines):
for line in lines:
if line[-1] == '\n':
line = line[:-1]
self.printer(line)
def capture_warnings(logger="py.warnings",level='warn'):
logging.captureWarnings(True)
l = logging.getLogger(logger)
h = logging.StreamHandler(BorgMessageStream(console(), level=level))
l.addHandler(h)
return h
@contextlib.contextmanager
def borgConsole(original=sys.stdout):
"""Setup a clean redirection of BORG output, notably in presence of MPI4PY.
Keyword Arguments:
original (file-like): Where to send the console to (default: :class:`sys.stdout`)
"""
yield contextlib.redirect_stdout(_RewriteIO(original))
def buildDefaultChain(box, cosmo_pars, a_init, model):
"""Build a default BORG chain from a model. This remove the hastle of setting up
a primordial fluctuation generator, and the cosmological parameters.
Args:
box (borg.forward.BoxModel): the specification of the box for the simulation
cosmo_pars (borg.cosmo.CosmologicalParameters): the cosmology chosen
a_init (float): the starting scale factor for `model`
model (borg.forward.BORGForwardModel): the model to be chained with
Returns:
borg.forward.BORGForwardModel: a newly built chain for cosmology
"""
chain = forward.ChainForwardModel(box)
chain.addModel(forward.models.HermiticEnforcer(box))
chain.addModel(forward.models.Primordial(box, a_init))
chain.addModel(forward.models.EisensteinHu(box))
chain.addModel(model)
chain.setCosmoParams(cosmo_pars)
return chain
if EMBEDDED:
capture_warnings()
__all__ = ["borgConsole", "buildDefaultChain", "dft", "utils"] + borg_native.__all__
# ARES TAG: authors_num = 1
# ARES TAG: name(0) = Guilhem Lavaux
# ARES TAG: year(0) = 2020
# ARES TAG: email(0) = guilhem.lavaux@iap.fr

View file

@ -0,0 +1,39 @@
#+
# ARES/HADES/BORG Package -- ./extra/python/python/aquila_borg/borg_native.py
# Copyright (C) 2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
#
# Additional contributions from:
# Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
#
#+
try:
from borg_embed import *
EMBEDDED = True
except ModuleNotFoundError as e:
# If we do not detect the embedded module we add some
# symbols to account for the missing decorator functions
# That way the python code are working both embedded or
# in standalone python.
from ._borg import *
def _warning_function(f):
print("warning! not embedded borg")
return f
registerLikelihoodBuilder = _warning_function
registerGravityBuilder = _warning_function
registerSamplerBuilder = _warning_function
EMBEDDED = False
del _warning_function
__all__ = [
"cosmo", "forward", "bias", "likelihood", "samplers", "Console", "console",
"memoryReport", "registerLikelihoodBuilder", "registerGravityBuilder",
"registerSamplerBuilder", "EMBEDDED"
]
# ARES TAG: authors_num = 1
# ARES TAG: name(0) = Guilhem Lavaux
# ARES TAG: year(0) = 2020
# ARES TAG: email(0) = guilhem.lavaux@iap.fr

View file

@ -0,0 +1,58 @@
import numpy as np
from .borg_native import *
class DFT:
"""This implements an MPI DFT transform which is compatible with the other IO involved
in BORG.
Note that r2c and c2r are inverse and forward transform respectively. They are already
properly normalized with physical units.
TODO: Specify sub-communicators
Arguments:
box (BoxModel): Physical box specifications of the transform
"""
def __init__(self, box):
# We do an abuse of the API here
self._box = box
self._model = forward.models.HadesLinear(box, ai=1.0, af=1.0)
cpar = cosmo.CosmologicalParameters()
self._model.setCosmoParams(cpar)
_, localN0, N1, N2 = self._model.getMPISlice()
self.Nfft = localN0, N1, N2 // 2 + 1
self.Nreal = localN0, N1, N2
def r2c(self, real_array):
"""Execute a real to complex transform
Arguments:
real_array (numpy.ndarray): Input real array
Returns:
numpy.ndarray: A complex array
"""
assert real_array.dtype == np.float64
self._model.forwardModel_v2(real_array)
out = np.empty(self.Nfft, dtype=np.complex128)
self._model.getDensityFinal(out)
return out
def c2r(self, complex_array):
"""Execute a complex to real transform
Arguments:
real_array (numpy.ndarray): Input complex array
Returns:
numpy.ndarray: A real array
"""
assert real_array.dtype == np.complex128
self._model.forwardModel_v2(complex_array)
out = np.empty(self.Nreal, dtype=np.float64)
self._model.getDensityFinal(out)
return out

View file

@ -0,0 +1,7 @@
import numpy as np
from .borg_native import *
def newRealOutput(fwd_model):
startN0,localN0,N1,N2 = fwd_model.getMPISlice()
return np.empty((localN0, N1, N2))

View file

@ -0,0 +1,88 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/base.cpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include <pybind11/stl.h>
#include "libLSS/tools/console.hpp"
#include "libLSS/tools/memusage.hpp"
#include "pyborg.hpp"
namespace py = pybind11;
using namespace pybind11::literals;
static int pythonVerboseLevel = 3;
#include "pyborg_doc.hpp"
#include "pyborg_doc/borg_base.hpp"
#include "pyborg_doc/borg_base.Console.hpp"
void LibLSS::Python::shuttingDown() {
pythonVerboseLevel = -pythonVerboseLevel;
}
void LibLSS::Python::setupConsole() {
Console::instance().setVerboseLevel(0);
Console::instance().setSeparateStream([](int level, std::string const &m) {
if (level < pythonVerboseLevel) {
py::gil_scoped_acquire acquire;
py::print(m);
} else if (pythonVerboseLevel < 0) {
if (level < -pythonVerboseLevel) {
std::cout << m << std::endl;
}
}
});
}
void LibLSS::Python::pyBase(py::module m) {
py::class_<Console>(m, "Console", DOC(borg_base, Console))
.def(
"print_warning",
[](Console *c, std::string const &s) { c->print<LOG_WARNING>(s); })
.def(
"print_std",
[](Console *c, std::string const &s) { c->print<LOG_STD>(s); },
DOC(borg_base, Console, print_std))
.def(
"print_debug",
[](Console *c, std::string const &s) { c->print<LOG_DEBUG>(s); })
.def(
"print_error",
[](Console *c, std::string const &s) { c->print<LOG_ERROR>(s); })
.def(
"setVerboseLevel",
[](Console *c, int level) { pythonVerboseLevel = level; },
"level"_a = 2)
.def("printStackTrace", &Console::print_stack_trace)
.def(
"outputToFile", &Console::outputToFile,
DOC(borg_base, Console, outputToFile));
m.def(
"console", []() -> Console * { return &Console::instance(); },
py::return_value_policy::reference, DOC(borg_base, console));
py::class_<AllocationDetail>(m, "_memoryDetail")
.def_readonly("allocated", &AllocationDetail::allocated)
.def_readonly("freed", &AllocationDetail::freed)
.def_readonly("peak", &AllocationDetail::peak)
.def("__repr__", [](AllocationDetail *detail) {
return boost::str(
boost::format("<AllocationDetail: allocated=%g kB, freed=%g kB, "
"peak=%g kB>") %
(detail->allocated / 1024.) % (detail->freed / 1024.) %
(detail->peak / 1024.));
});
m.def("memoryReport", &memoryReport);
}
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1,50 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/bind.cpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include "libLSS/mpi/generic_mpi.hpp"
#include <memory>
#include <exception>
#include <boost/format.hpp>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include "pyborg.hpp"
#include "pyfuse.hpp"
namespace py = pybind11;
namespace lss = LibLSS;
bool LibLSS::Python::mpi4py_available = false;
void LibLSS::Python::bindBORG(py::module m) {
py::module cosmo = m.def_submodule("cosmo", "Submodule for cosmology");
py::module forward =
m.def_submodule("forward", "Base declaration for forward models");
py::module forward_impl =
forward.def_submodule("models", "Implementation of forward models");
py::module bias = m.def_submodule("bias", "Bias models");
py::module velocity =
forward.def_submodule("velocity", "Velocity forward models");
py::module likelihood = m.def_submodule("likelihood", "Likelihoods");
py::module samplers = m.def_submodule("samplers", "Submodule for samplers algorithm and specifics");
py::class_<pythonHolder, std::shared_ptr<pythonHolder>>(m, "_pythonPointerHolder");
lss::Python::pyBase(m);
lss::Python::pyCosmo(cosmo);
lss::Python::pyForwardBase(forward);
lss::Python::pyForwardBorg(forward_impl);
lss::Python::pyForwardAll(forward_impl);
lss::Python::pyBias(bias);
lss::Python::pyVelocity(velocity);
lss::Python::pyLikelihood(likelihood);
lss::Python::pySamplers(samplers);
}
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1 @@
from aquila_borg import *

View file

@ -0,0 +1,100 @@
@class
Cosmology computations
----------------------
This module includes the basic components to describe and to do
cosmological computations.
.. currentmodule:: aquila_borg.cosmo
.. autosummary::
:toctree: _generate
CosmologicalParameters
Cosmology
CosmoPower
ClassCosmo
@@ ---------------------------------------------------------------------------
@class:CosmologicalParameters
Class that holds the values of all cosmological parameters relevant to the BORG framework.
The constructor setup a sane default LCDM cosmology.
@funcname:default
Reset parameters to default cosmology
@funcname:omega_r
:math:`\Omega_r` cosmological parameter (i.e. redshift 0 normalized radiation density)
@funcname:omega_k
:math:`\Omega_k` cosmological parameter (i.e. redshift 0 normalized curvature)
@funcname:omega_m
:math:`\Omega_m` cosmological parameter (i.e. redshift 0 matter density)
@funcname:omega_b
:math:`\Omega_b` cosmological parameter (i.e. redshift 0 baryon density)
@funcname:omega_q
:math:`\Omega_q` cosmological parameter (i.e. redshift 0 quintescence/dark energy density). Requires extra parameter :math:`w` and :math:`w'`.
@funcname:w
:math:`w` cosmological parameter (i.e. redshift 0 equation of state of quintescence/dark energy).
@funcname:wprime
:math:`w'` cosmological parameter (i.e. redshift 0 time derivative at $a=0$ of the equation of state of quintescence/dark energy).
@funcname:n_s
:math:`n_s` cosmological parameter (i.e. redshift 0, power law index of primordial fluctuations).
@funcname:fnl
:math:`f_\mathrm{NL}`, quadratic type non-gaussianity
@funcname:h
Hubble constant normalized to :math:`100 \mathrm{km s Mpc}^{-1}`.
@funcname:sum_mnu
:math:`\sum m_\nu`, sum of mass of neutrinos in eV
@@ ---------------------------------------------------------------------------
@class:Cosmology
Class to compute different quantities for an homogeneous universe and given cosmological parameters
Arguments:
cosmo_params (CosmologicalParameters): Cosmological parameters to use
to construct the `Cosmology` object
@@ ---------------------------------------------------------------------------
@class:CosmoPower
Construct a new CosmoPower object from the given cosmological parameters.
Arguments:
cosmo_params (CosmologicalParameters): Cosmological parameters to use
to construct the `Cosmology` object
@@ ---------------------------------------------------------------------------
@class:ClassCosmo
Builds a new object ClassCosmo. It relies on the embedded CLASS (https://class-code.net)
to compute the primordial gravitational potential and/or density fluctuations.
Arguments:
params (CosmologicalParameters): The cosmological parameters to use to precompute the
transfer function
@funcname:get_Tk
Arguments:
k (numpy,float,array): Mode where to compute the transfer function at (in h/Mpc)
Returns:
numpy array of the transfer function at each k
Throws:
RuntimeError if beyond range of validity
@funcname:getCosmology
Returns:
dict of string/double pairs, corresponding to each cosmological parameters.

View file

@ -0,0 +1,124 @@
@class
Base class for all forward models.
All forward models derive from this class. However python implemented forward
models must use :obj:`.BaseForwardModel`.
:members:
@funcname:__init__
@funcname:getPreferredOutput
Returns the preferred output format (i.e. the one that incurs less transforms)
for that model.
Returns:
PreferredIO: the preferred format
@funcname:getPreferredInput
@funcname:setCosmoParams
Setup the cosmological parameters that this model requires.
Args:
cosmo_params (:obj:`aquila_borg.cosmo.CosmologicalParameters`): Cosmological parameters
@funcname:getModelParam
This queries the current state of the parameters 'keyname' in model 'model'.
Args:
model (str): sub model name keyname (str): key of the parameter to query
Returns:
object: the value of the parameter
@@ ---------------------------------------------
@funcname:setName
Give a to localize more easily a model instance.
Args:
name (str): string name of the instance
@funcname:setModelParams
Allow changing model parameters for different model indexed by the dictionnary key,
each item is another dictionnary with key/value pairs.
@@ ---------------------------------------------
@funcname:getOutputBoxModel
Return the box on which is defined the output of the model is defined.
Returns:
BoxModel: the box model representing the shape and size of the output of that
forward model.
@@ ---------------------------------------------
@funcname:adjointModel_v2
Pushes the adjoint gradient from a deeper part of the computation.
This function allows to push the adjoint gradient vector for a deeper part of
the computation (like the likelihood) to the forward model. It will not return
the result which has to be query with :func:`~BORGForwardModel.getAdjointModel`.
Args:
adjoint_gradient (numpy.array): A 3d numpy array either real or complex. If
complex it must use the RFFT half-complex representation
Returns:
None
@@ ---------------------------------------------
@funcname:forwardModel_v2
Run the first part of the forward model (v2 API).
Args:
input_array (numpy.array): A 3d numpy array either real or complex. If
complex it must use the RFFT half-complex representation
Returns:
None
@@ ---------------------------------------------
@funcname:setAdjointRequired
Indicate whether the caller require the adjoint gradient to be computed later.
Args:
flag (bool): if True, tape is recorded to compute adjoint
@@ ---------------------------------------------
@funcname:clearAdjointGradient
Clear accumulated information to compute the adjoint gradient vector.
This is automaticalled by getAdjointModelOutput.
@@ ---------------------------------------------
@funcname:getMPISlice
Returns a tuple of integer indicating the way the slab is distributed among
the node.
Returns:
tuple of int: (startN0, localN0, N1, N2)
@@ ---------------------------------------------
@funcname:getCommunicator
Build and return an MPI4PY communicator object that is linked to the internal
MPI communicator of that object.
Returns:
mpi4py.MPI.Comm
@@ ---------------------------------------------
@funcname:accumulateAdjoint
Request the model to accumulate adjoint vectors instead of resetting at each call.
This changes the default behavior of adjointModel_v2. Use with care.
Args:
do_accumulate (bool): If true, request the change of behavior.

View file

@ -0,0 +1,2 @@
@class
Base class for implementing new forward model in python

View file

@ -0,0 +1,28 @@
@funcname:__init__
Create a new BoxModel object.
The constructors builds a cube by default.
However later modifications of the field L and N can give more generally
sized box.
Arguments:
L (float): Physical size of the box
N (int): Grid size of the box
@funcname:xmin
3-tuple with corner at (0,0,0) of the box in each direction
@funcname:volume
The total volume of the box
@funcname:Ntot
The total number of mesh elements
@funcname:copy
Make a new independent copy of the present box
@funcname:L
3-tuple of the side-length of the box
@funcname:N
3-tuple of the grid size of the box

View file

@ -0,0 +1,18 @@
@class
This is a forward model to chain several others. It is based on
:class:`aquila_borg.forward.BORGForwardModel`
The chain is mandatorily linear. In principle several chains could be combined
together with another auxiliary forward model.
@@ ------------------------------------------------------
@funcname:__init__
Construct a new chain forward model, starting with the input box model
corresponding to the first argument
@@ ------------------------------------------------------
@funcname:addModel
Add a new model to the chain
Args:
forward (aquila_borg.forward.BORGForwardModel): a model to add

View file

@ -0,0 +1,162 @@
@class
Standard BORG forward models
----------------------------
This module includes direct access to a number of fundamental forward models.
.. currentmodule:: aquila_borg.forward.models
.. autosummary::
:toctree: _generate
HermiticEnforcer
Primordial
EisensteinHu
Downgrade
Transfer
HadesLinear
HadesLog
BorgLpt
BorgLptOpenMP
BorgLptNGP_Double
BorgLptNGP_Quad
BorgLptSmoothNGP_Quad
Borg2Lpt
BorgPM
newModel
listModels
@funcname:newModel
Builds a new forward model object from its named.
This is a very generic tool to build any forward model built in the borg library.
Being generic means there are some limitations. It relies on the arguments
available to the INI configuration file to build those models.
Args:
name (str): name of the model
box (aquila_borg.forward.BoxModel): Input box for the model
arguments (dict): A key-value pair dictionary. Its context matches the INI file specification
Returns:
aquila_borg.forward.BORGForwardModel: a constructed forward model element
@funcname:listModels
List the available forward models using their internal name.
Returns:
list of str: a list of name
@@ ----------------------------------------------------------
@class:BorgPM
Construct a new BorgPM object.
Arguments:
box (aquila_borg.forward.BoxModel): Box specification of the initial conditions.
box_out (aquila_borg.forward.BoxModel): Output box specification for the final conditions.
Keyword arguments:
supersampling (int): Indicate by how much to supersample the initial conditions with particles.
force_factor (int): Indicate the relative resolution for the computation of the gravitational field.
particle_factor (float): Sets the over-allocation of the particle array on the current task for MPI load balancing
rsd (bool): Add redshift space distortion by displacing particles using their velocities.
ai (float): Scale factor of the initial conditions provided by the previous step.
af (float): Requested scale factor for the output
z_start (float): Redshift at which to switch between LPT and the full particle mesh integration.
tCOLA (bool): Indicate whether to use tCOLA for the integration.
@@ ----------------------------------------------------------
@class:BorgLpt
This class binds the borg LPT forward model (CIC mass assignment).
Arguments:
box (BoxModel): Input box comoving size
Keyword arguments:
box_out (BoxModel): Output box (default is equal to input).
rsd (bool): inject redshift space distortions, default false.
supersampling (int): supersampling factor, i.e. by multiplicative factor, for each side, between particle array and input array [default 1].
particle_factor (float): allocation ratio of the particle arrays (must be > 1) [default 1.1]
ai (float): scale factor used for the input density field (default 0.1)
af (float): scale factor requested for the output (default 1.0)
lightcone (bool): if true, add lightcone effect at order 0, (default false)
lightcone_boost (float): make the structures goes quicker, useful for art drawing of lightcones (default 1.0)
@@ ----------------------------------------------------------
@class:BorgLptOpenMP
This class binds the borg LPT forward model (CIC/OpenMP mass assignment).
@@ ----------------------------------------------------------
@class:BorgLptNGP_Double
This class binds the borg LPT forward model (NGP double mass assignment).
@@ ----------------------------------------------------------
@class:BorgLptNGP_Quad
This class binds the borg LPT forward model (NGP quad mass assignment).
@@ ----------------------------------------------------------
@class:BorgLptSmoothNGP_Quad
This class binds the borg LPT forward model (Smooth NGP quad mass assignment).
@@ ----------------------------------------------------------
@class:Borg2Lpt
Arguments:
box (BoxModel): BORG 3d box descriptor of the input
box_out (BoxMOdel): BORG 3d box descriptor of the output
Keyword arguments:
rsd (bool): Apply redshift distortion at particle level Default to False
supersampling (float): Number of times to supersample the initial condition
before generating Lagrangian particles. (default 1)
particle_factor (float): *For MPI purpose*, memory overallocation per task of the particle arrays (default 1.1)
ai (float): Input scale factor (default 0.1)
af (float): Output scale factor (default 1.0)
lightcone (bool): Whether to generate particle on lightcone at zero order (default False)
@@ ----------------------------------------------------------
@class:Transfer
Forward model to apply a transfer function (not necessarily isotropic) to the input field
@funcname:setupSharpKcut
@funcname:setupInverseCIC
@funcname:setTransfer
@@ ----------------------------------------------------------
@class:HermiticEnforcer
Enforce the hermiticity of the input complex field. If real space data is provided
the adjoint gradient is not guaranteed to be adequate, as it supposes that there are more
degree of freedom in the complex plane.
Arguments:
box (BoxModel): BORG 3d box descriptor
@@ ----------------------------------------------------------
@class:HadesLog
Applies an exponential transform to the real space field. By default it enforces to conserve the mean.
Arguments:
box (BoxModel): BORG 3d box descriptor
ai (float): Input scale factor
@@ ----------------------------------------------------------
@class:HadesLinear
Do nothing but Eulerian linear perturbation scaling
Arguments:
box (BoxModel): BORG 3d box descriptor
ai (float): Input scale factor
af (float): Output scale factor

View file

@ -0,0 +1,51 @@
@class
BORG forward model
------------------
This module includes the basic components to manipulate forward models.
.. currentmodule:: aquila_borg.forward
.. autosummary::
:toctree: _generate
PreferredIO
BoxModel
BORGForwardModel
ParticleBasedForwardModel
BaseForwardModel
ChainForwardModel
@class:PreferredIO
Enumeration to specify the preferred Input/Output of a forward model
@@ ---------------------------------------------------------------------------
@class:ParticleBasedForwardModel
Special abstract class to provide an API to access to particles used in the forward computation of
certain models.
@funcname:getNumberOfParticles
Return the number of particles present on the current MPI task
@funcname:getParticlePositions
Return the positions of the particles in the provided numpy array
Arguments:
positions (np.array): Pre-allocated numpy array `Nx3`. `N` must be at least the number returned by `ref`:getNumberOfParticles
@funcname:getParticleVelocities
Return the velocities of the particles in the provided numpy array
Arguments:
velocities (np.array): Pre-allocated numpy array `Nx3`. `N` must be at least the number returned by `ref`:getNumberOfParticles
@funcname:setStepNotifier
Setup a callback when a new step is being computed for particles.
TODO: The C++ side has access to particles, which has not yet been done for the Python callback
Arguments:
callback (object): A callable object. The object will be called with two arguments: the
time and the number of particles on the current task.

View file

@ -0,0 +1,34 @@
@class
This is the base class for models that compute velocity field from a forward
model output.
This class is abstract and not constructible. The construction of a velocity field
requires that the base formward model has been executed using
`aquila_borg.forward.models.BORGForwardModel.forwardModel_v2`.
@@ -------------------------------------------------------------------------
@funcname:getOutputBox
Return the `aquila_borg.forward.BoxModel` corresponding to the output of this velocity
field model.
@@ -------------------------------------------------------------------------
@funcname:computeAdjointModel
Push the adjoint gradient of the velocity field in the model.
Depending on the specific model used, the produced adjoint gradient is pushed to
the forward model that produced the simulation (e.g.
`aquila_borg.forward.model.BorgLpt`).
Args:
ag (numpy.array): The adjoint gradient with respect to the output of the
velocity model. The adjoint gradient must have a shape 3xN0xN1xN2, where N0
may be MPI-sliced. If the adjoint is not densely packed and double
precision, it will be implicitly force cast to the adequate requirement
(i.e. it may need more memory).
@@ -------------------------------------------------------------------------
@funcname:getVelocityField
Compute and returns the velocity field associated to the base forward model.
Returns:
numpy.array: a 3xN0xN1xN2 velocity field on grid.

View file

@ -0,0 +1,38 @@
@class
Velocity field computations
---------------------------
This module includes the components to compute velocity field from result
of forward models.
.. currentmodule:: aquila_borg.forward.velocity
.. autosummary::
:toctree: _generate
VelocityBase
ParticleBasedModel
CICModel
SICModel
@funcname:getVelocityField
Compute and returns the velocity field from the forward model.
@class:ParticleBasedModel
ParticleBasedModel is the base class for the computation of velocity field
from forward model that are particle based (such as `aquila_borg.forward.models.BorgLpt`
or `aquila_borg.forward.models.BorgPm`).
@class:CICModel
This class implements the Cloud-In-Cell (CIC) model for velocity field computation.
The momentum field is computed by projecting each particle velocities onto a
grid using a CIC kernel. Then the mass field is computed in the same way uses
as divisor of the momentum field.
@class:SICModel
This class implements Simplex-In-Cell (SIC) model for the velocity field computation.
@funcname:__init__
Construct a new SIC forward model element. It relies on the output of the
provided BORG forward model element, which must be particle based.

View file

@ -0,0 +1,114 @@
@class
Likelihood and associated structures
------------------------------------
This module includes the basic components to use BORG likelihoods and develop new likelihoods to mesh with the existing framework.
.. currentmodule:: aquila_borg.likelihood
.. autosummary::
:toctree: _generate
MarkovState
Likelihood3d
ForwardModelLikelihood3d
BaseLikelihood
LikelihoodInfo
GaussianPassthrough
GaussianLinear
PoissonPowerLaw
@@ ---------------------------------------------------------------------------
@class:MarkovState
Create a new MCMC dictionnary.
@@ ---------------------------------------------------------------------------
@funcname:newArray1d
Create and allocate a new 1d array in the dictionnary.
The 1d array holds value in double precision.
Arguments:
name (:obj:`str`):
N (int):
Keyword arguments:
in_mcmc (bool): Default to false.
Raises:
KeyError: if `name` is already present in the MarkovState
@@ ---------------------------------------------------------------------------
@funcname:newArray3d
Create and allocate a new 3d array in the dictionnary.
The 3d array holds value in double precision.
Arguments:
name (:obj:`str`): Requested `name` of the array
N0 (int): First dimension
N1 (int): Second dimension
N2 (int): Third dimension
Keyword arguments:
in_mcmc (bool): Default to false.
Raises:
KeyError: if `name` is already present in the MarkovState
@@ ---------------------------------------------------------------------------
@funcname:newArray3d_slab
Create and allocate a new 3d array, with MPI slabbing, in the dictionnary.
The 3d array holds value in double precision.
Arguments:
name (:obj:`str`): Requested `name` of the array
slab (tuple of 6 int): Slab position and size (start0,local_size0,start1,local_size1,start2,local_size2)
real_size (tuple of 3 int): Real size
Keyword arguments:
in_mcmc (bool): Default to false.
Raises:
KeyError: if `name` is already present in the MarkovState
@@ ---------------------------------------------------------------------------
@funcname:newForwardModel
Create a new entry to hold a forward model in the MarkovState.
The forward model is not saved to disk. This entry is used for legacy that requires
to store a forward model in the MarkovState.
Arguments:
name (str): Name of the entry
forward (BORGForwardModel): A forward model object
@@ ---------------------------------------------------------------------------
@class:Likelihood3d
Base class to represent 3d likelihoods in BORG.
The likelihoods are 3d as they manipulate 3d meshes. This object is abstract and cannot
be directly inherited in Python. Please use :obj:`.BaseLikelihood` to create new likelihood
in Python.
@@ ---------------------------------------------------------------------------
@class:ForwardModelLikelihood3d
@funcname:getForwardModel
@class:BaseLikelihood
@class:GaussianPassthrough
@class:GaussianLinear
@class:PoissonPowerLaw
@class:PoissonPassthrough
@class:LikelihoodInfo

View file

@ -0,0 +1,142 @@
@class
Samplers and sampler algorithms
-------------------------------
This module includes the basic components to generate new samplers in a block sampling
strategy.
.. currentmodule:: aquila_borg.samplers
.. autosummary::
:toctree: _generate
MarkovSampler
PyBaseSampler
slice_sampler
GenericBiasSampler
BiasModelParamsSampler
HMCDensitySampler
ModelParamsSampler
Sigma8Sampler
AltairMetaSampler
@@ ------------------------------------------------
@funcname:slice_sampler
Basic slice_sampler implementation.
This implements a slice sampler without rescaling of the stepper.
Args:
state (MarkovState): A markov state with an initialized random number generation
callback (callable): A callable object, typically a lambda function or a function with one argument
previous_value (float): Previous value of the slice sampler chain
step (float): Step to progress through the posterior
Returns:
float: new position
@@ ------------------------------------------------
@class:PyBaseSampler
PyBaseSampler class to implement MarkovSampler object from python.
The constructor must call super().__init__() to ensure the native part of the object
is well initialized.
Note that three functions must be implemented:
* initialize(state: MarkovState)
* restore(state: MarkovState)
* sample(state: MarkovState)
The first two are hidden from the MarkovSampler interface as being protected in
the native interface.
@@ ------------------------------------------------
@class:GenericBiasSampler
This is a sampler that will run a slice sampler for each bias parameter of catalog.
It basically adapts the standard behavior of hades3 for the python environment.
Arguments:
model (Likelihood3d): A likelihood model to sample the bias parameter from.
@@ ------------------------------------------------
@class:BiasModelParamsSampler
A sampler that sample bias parameters using the borg forward model strategy.
It relies on block sampling and slice sampler approach to be able to do it on anything,
though it is expected to be slow in the end.
The sampler will update the bias parameters using the mechanism of :meth:`aquila_borg.forward.BORGForwardModel.setModelParams`.
It is provided with an update on the key "biasParameters" which is a 1d array of the size as provided
to the constructor.
The array is initialized by introspection by querying :meth:`aquila_borg.forward.BORGForwardModel.getModelParam` on the model
with the nickname "bias" and the parameter "biasParameters". On restart, those parameters will be reset
correctly.
:Example:
For example the following python model would be interrogated by this sampler:
.. code-block:: python
class Model(aquila_borg.forward.BORGForwardModel):
# skip common section
def setModelParams(self, params):
if 'biasParameters' in params:
print(" I am getting some parameters: " + repr(params))
def getModelParam(self, modelname, keyname):
if modelname == 'bias' and keyname == 'biasParameters':
print(" Let's return some numpy array with parameters" )
return np.array([0.0,1.0]) #This array must match the number of parameters
Arguments:
likelihood (Likelihood3d): the likelihood to evaluate the quality of the parameter
model (BORGForwardModel): the forward model element to pass the bias parameter upon
prefix (str): Prefix for the bias parameter array
limiter (callable): Function to be called before trying to sample the bias parameters
unlimited (callable): Function to be called after a new sample of the bias parameters
@@ ------------------------------------------------
@class:HMCDensitySampler
Build a new HMC based density sampler.
Arguments:
likelihood (Likelihood3d): A 3d likelihood object. This is the present restriction of the HMC.
Keyword arguments:
prefix (str): add a prefix to HMC variables. This is useful in case several HMC are running at the same
time to solve the problem.
k_max (float): Only sample the modes up to the provided k_max. The others are frozen.
@@ ------------------------------------------------
@class:Sigma8Sampler
Build a new sigma8 sampler.
It supports three arguments in the `info` object:
* `sigma8_min`: min bound of the prior
* `sigma8_max`: max bound of the prior
* `sigma8_step`: typical step to execute the slice sampler
Arguments:
likelihood (Likelihood3d): A 3d likelihood object.
info (LikelihoodInfo): A LikelihoodInfo dictionnary object.
@@ ------------------------------------------------
@class:ModelParamsSampler
Build a new model params sampler.
Arguments:
prefix (str):
params (list of str):
likelihood (Likelihood3d):
model (BORGForwardModel):
init (dict):
@@ ------------------------------------------------
@class:AltairMetaSampler
Build a new sampler for altair
Arguments:
likelihood (ForwardModelLikelihood3d): A likelihood based on a forward model (required to update it)

View file

@ -0,0 +1,20 @@
@class
This is the Console class. It allows doing pretty printing of the message from
the borg system. It dispatches the message to the appropriate log files and the
adequate level asked by the user. The Console object cannot be constructed from
Python. To get a Console object use `aquila_borg.console`.
@@ -------------------------------------------------
@funcname:outputToFile
Args:
filename (str): the filename to output the full log to
@@ -------------------------------------------------
@funcname:print_std
Prints a message to the console
Args:
message (str): the message to be printed at the Standard level

View file

@ -0,0 +1,2 @@
@funcname:console
This function returns the valid already created Console object.

View file

@ -0,0 +1,95 @@
#+
# ARES/HADES/BORG Package -- ./extra/python/python/doc/convert.py
# Copyright (C) 2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
#
# Additional contributions from:
# Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
#
#+
# This tool transforms the doc rst in python/doc to a bunch
# of hpp header file. They are used to generate the adequate docstring
# for each module/class/function bound with pybind11 from C++ to Python
#
# The text must follow the Google convention for docstrings, formatted with
# RestructuredText markers. In addition to those markers this tool recognize
# the following formatting:
#
# A class/module doc is marked with a line starting by "@class"
# A comment line is a line starting with "@@"
# A function/member "F" is documented by writing the line "@funcname:F" followed
# by its documentation
#
import sys
import os
TAG_FUNCNAME = "@funcname:"
TAG_CLASSNAME = "@class:"
TAG_CLASS = "@class"
TAG_COMMENT = "@@"
def convert_doc(target_dir, fname):
_, fname_base = os.path.split(fname)
fname_header, ext = os.path.splitext(fname_base)
base_prefix = prefix = fname_header.replace(".", "_")
fname_header = os.path.join(target_dir, fname_header + ".hpp")
funcname = None
block_started = False
funcs = {}
with open(fname, mode="rt") as ff, open(fname_header, mode="wt") as gg:
def finish_block():
if block_started:
gg.write(")str\";\n\n")
def begin_block(funcname):
nonlocal block_started
gg.write(f"static const char * __pydocstring_{funcname} = R\"str(")
block_started = True
for l in ff:
if l.startswith(TAG_COMMENT):
continue
if l.startswith(TAG_FUNCNAME):
finish_block()
l.strip()
funcname = l[len(TAG_FUNCNAME):]
funcname = prefix + "_" + funcname
if funcname in funcs:
print(f"{funcname} is already defined")
sys.exit(1)
begin_block(funcname)
funcs[funcname] = True
continue
# Order matter here
if l.startswith(TAG_CLASSNAME):
prefix = base_prefix + "_" + l[len(TAG_CLASSNAME):].strip()
finish_block()
begin_block(prefix)
continue
if l.startswith(TAG_CLASS):
prefix = base_prefix
finish_block()
begin_block(prefix)
continue
if block_started:
gg.write(l)
finish_block()
if __name__ == "__main__":
target_dir = sys.argv[1]
for a in sys.argv[2:]:
convert_doc(target_dir, a)
# ARES TAG: authors_num = 1
# ARES TAG: name(0) = Guilhem Lavaux
# ARES TAG: email(0) = guilhem.lavaux@iap.fr
# ARES TAG: year(0) = 2020

View file

@ -0,0 +1,115 @@
import io
import numpy as np
import sys
import mpi4py
import contextlib
import borg
cons=borg.console()
class RewriteIO(io.IOBase):
def __init__(self, original):
self.original = original
self.newline = False
self.comm = mpi4py.MPI.COMM_WORLD
self.prefix = f'[{self.comm.rank} / {self.comm.size}] '
def write(self, b):
if b[0] == '\n':
return self.original.write(b)
return self.original.write(self.prefix + b)
def writelines(self,lines):
return self.original.writelines(lines)
with contextlib.redirect_stdout(RewriteIO(sys.stdout)):
cons.setVerboseLevel(5)
cosmo_par = borg.cosmo.CosmologicalParameters()
cosmo_par.default()
print(repr(cosmo_par))
cosmo = borg.cosmo.Cosmology(cosmo_par)
cpower = borg.cosmo.CosmoPower(cosmo_par)
box = borg.forward.BoxModel()
box.L = (100,100,100)
box.N = (128,128,128)
print(box)
# Generate random numbers variance 1 in fourier space
indelta = np.random.randn(*box.N)
indelta /= np.sqrt(indelta.size)
delta_hat = np.fft.rfftn(indelta)
comm = mpi4py.MPI.COMM_WORLD
delta_hat = delta_hat[comm.rank*box.N[0]//comm.size : (comm.rank+1)*box.N[0]//comm.size, :, :]
# Generate k grid
ik = np.fft.fftfreq(box.N[0], d=box.L[0]/box.N[0] ) *2*np.pi
kx,ky,kz = np.meshgrid(ik,ik,ik[:(box.N[0]//2 + 1)])
kn = np.sqrt(kx**2 + ky**2 + kz**2)
kn = kn[comm.rank*box.N[0]//comm.size : (comm.rank+1)*box.N[0]//comm.size, :, :]
# Scale and multiply by power spectrum
scale = cosmo.d_plus(0.1)/cosmo.d_plus(1.0)
delta_hat *= scale* np.sqrt(box.L[0]**3 * cpower.power(kn))
outN = (comm.rank+1)*box.N[0]//comm.size - (comm.rank)*box.N[0]//comm.size, box.N[1], box.N[2]
#
# Apply 2LPT
final_delta_2lpt = np.zeros(outN)
model = borg.forward.models.Borg2Lpt(box,ai=0.1, particle_factor=2)
model.setCosmoParams(cosmo_par)
model.forwardModel(delta_hat / box.L[0]**3, final_delta_2lpt)
del model
#
# Apply LPT
final_delta_lpt = np.zeros(outN)
model = borg.forward.models.BorgLpt(box,ai=0.1, particle_factor=2)
model.holdParticles()
model.setCosmoParams(cosmo_par)
model.forwardModel(delta_hat / box.L[0]**3, final_delta_lpt)
print(f"Num particles = {model.getNumberOfParticles()}")
Npart = model.getNumberOfParticles()
print(f"Grid = {Npart**(1./3)}")
x=np.empty((Npart,3),dtype=np.float64)
v=np.empty((Npart,3),dtype=np.float64)
model.getParticlePositions(x)
model.getParticleVelocities(v)
del model
#
# Apply PM
final_delta_pm = np.zeros(outN)
model = borg.forward.models.BorgPM(box,ai=0.1, nsteps=5, particle_factor=2, supersampling=2)
model.setAdjointRequired(False)
model.setCosmoParams(cosmo_par)
model.forwardModel(delta_hat / box.L[0]**3, final_delta_pm)
del model
#
# Apply PM
final_delta_pm2 = np.zeros(outN)
model = borg.forward.models.BorgPM(box,ai=0.1, nsteps=5, particle_factor=2, supersampling=2, force_factor=2)
model.setAdjointRequired(False)
model.setCosmoParams(cosmo_par)
model.forwardModel(delta_hat / box.L[0]**3, final_delta_pm2)
del model
#
# Apply PM-RSD
final_delta_pm_rsd = np.zeros(outN)
model = borg.forward.models.BorgPM(box,ai=0.1, nsteps=5, particle_factor=2,rsd=True)
model.setAdjointRequired(False)
model.setCosmoParams(cosmo_par)
model.forwardModel(delta_hat / box.L[0]**3, final_delta_pm_rsd)
del model
np.savez("results.npz", lpt=final_delta_lpt, tlpt=final_delta_2lpt, pm=final_delta_pm, pm2=final_delta_pm2, pm_rsd=final_delta_pm_rsd)

View file

@ -0,0 +1,41 @@
import numpy as np
import _borg
cosmo_par = _borg.cosmo.CosmologicalParameters()
cosmo_par.default()
print(repr(cosmo_par))
cosmo = _borg.cosmo.Cosmology(cosmo_par)
cpower = _borg.cosmo.CosmoPower(cosmo_par)
box = _borg.forward.BoxModel()
box.L = (100,100,100)
box.N = (128,128,128)
print(box)
# Generate random numbers variance 1 in fourier space
indelta = np.random.randn(*box.N)
indelta /= np.sqrt(indelta.size)
delta_hat = np.fft.rfftn(indelta)
# Generate k grid
ik = np.fft.fftfreq(box.N[0], d=box.L[0]/box.N[0] ) *2*np.pi
kx,ky,kz = np.meshgrid(ik,ik,ik[:(box.N[0]//2 + 1)])
kn = np.sqrt(kx**2 + ky**2 + kz**2)
# Scale and multiply by power spectrum
scale = cosmo.d_plus(0.1)/cosmo.d_plus(1.0)
delta_hat *= scale* np.sqrt(box.L[0]**3 * cpower.power(kn))
#
# Apply LPT
final_delta_lpt = np.zeros(box.N)
model = _borg.forward.models.BorgLpt(box,ai=0.1, particle_factor=2)
model.setCosmoParams(cosmo_par)
model.forwardModel(delta_hat / box.L[0]**3, final_delta_lpt)
biased_density = np.zeros_like(final_delta_lpt)
biased_density_2 = np.zeros_like(final_delta_lpt)
_borg.bias.PowerLawBias().compute(model, 1.0, [1.0,2.0], final_delta_lpt, biased_density)
_borg.bias.BrokenPowerLawBias().compute(model, 1.0, [1.0,2.0,0.1,0.1], final_delta_lpt, biased_density_2)

View file

@ -0,0 +1,205 @@
import matplotlib.pyplot as plt
import numpy as np
import borg
import jax
import jax.numpy as jnp
myprint = lambda s: borg.console().print_std(s if type(s) == str else repr(s))
def get_psi(k2, k, x, L, delta_hat, inv_dVol):
phi_hat = jnp.where(k2 == 0.0, 0.0j, delta_hat * 1j * k / (k2+1e-19))
phi_hat[0,0,0]=0j
p = x + jnp.fft.irfftn(phi_hat) * inv_dVol
return jnp.where(p >= 0, p % L, L - (-p) % L)
def mymodf(x):
ix = jnp.floor(x)
return x - ix, ix
def do_cic(x, y, z, Nx, Ny, Nz, Lx, Ly, Lz):
Ntot = Nx * Ny * Nz
x = x * Nx / Lx
y = y * Ny / Ly
z = z * Nz / Lz
qx, ix = mymodf(x)
qy, iy = mymodf(y)
qz, iz = mymodf(z)
ix = ix.astype(int)
iy = iy.astype(int)
iz = iz.astype(int)
rx = 1.0 - qx
ry = 1.0 - qy
rz = 1.0 - qz
jx = (ix + 1) % Nx
jy = (iy + 1) % Ny
jz = (iz + 1) % Nz
rho = jnp.zeros((Ntot, ))
for a in [False, True]:
for b in [False, True]:
for c in [False, True]:
ax = jx if a else ix
ay = jy if b else iy
az = jz if c else iz
ux = qx if a else rx
uy = qy if b else ry
uz = qz if c else rz
idx = az + Nz * ay + Nz * Ny * ax
rho += jnp.bincount(idx, weights=ux * uy * uz, length=Ntot)
return rho.reshape((Nx, Ny, Nz)) / (x.shape[0] / Ntot) - 1.0
def build_density(delta_hat, ikx, iky, ikz, x, y, z, N0: int, N1: int, N2: int,
L0: float, L1: float, L2: float, inv_dVol: float):
k2 = ikx**2 + iky**2 + ikz**2
return do_cic(
get_psi(k2, ikx, x, L0, delta_hat, inv_dVol).flatten(),
get_psi(k2, iky, y, L1, delta_hat, inv_dVol).flatten(),
get_psi(k2, ikz, z, L2, delta_hat, inv_dVol).flatten(), N0, N1, N2, L0,
L1, L2)
build_density = jax.jit(build_density, (7, 8, 9))
class JaxLpt(borg.forward.BaseForwardModel):
def __init__(self, box):
super().__init__(box, box)
N0, N1, N2 = box.N
L0, L1, L2 = box.L
self.ikx = 2 * np.pi * jnp.fft.fftfreq(N0, d=L0 / N0)[:, jnp.newaxis,
jnp.newaxis]
self.iky = 2 * np.pi * jnp.fft.fftfreq(N1, d=L1 / N1)[jnp.newaxis, :,
jnp.newaxis]
self.ikz = 2 * np.pi * jnp.fft.fftfreq(
N2, d=L2 / N2)[jnp.newaxis, jnp.newaxis, :(N2 // 2 + 1)]
self.x = jnp.arange(N0)[:, jnp.newaxis, jnp.newaxis] * L0 / N0
self.y = jnp.arange(N1)[jnp.newaxis, :, jnp.newaxis] * L1 / N1
self.z = jnp.arange(N2)[jnp.newaxis, jnp.newaxis, :] * L2 / N2
self.inv_dVol = box.Ntot / box.volume
self.L = tuple(box.L)
self.N = tuple(box.N)
def getPreferredInput(self):
return borg.forward.PREFERRED_FOURIER
def getPreferredOutput(self):
return borg.forward.PREFERRED_REAL
def forwardModel_v2_impl(self, input_array):
import jax.numpy as jnp
myprint("In fwdmodel!")
delta_hat = jnp.array(input_array)
self.save_array, self.grad = jax.vjp(
lambda d: build_density(d, self.ikx, self.iky, self.ikz, self.x,
self.y, self.z, self.N[0], self.N[1], self.
N[2], self.L[0], self.L[1], self.L[
2], self.inv_dVol), delta_hat)
def getDensityFinal_impl(self, output_array):
output_array[:] = self.save_array
def adjointModel_v2_impl(self, input_ag):
ag_delta = jnp.array(input_ag)
self.output_ag, = self.grad(ag_delta)
def getAdjointModel_impl(self, output_ag):
output_ag[:] = self.output_ag
def setModelParams(self, myparams):
print(f"setModelParams in python: pars={myparams}")
cons = borg.console()
cons.setVerboseLevel(5)
cosmo_par = borg.cosmo.CosmologicalParameters()
cosmo_par.default()
print(repr(cosmo_par))
cosmo = borg.cosmo.Cosmology(cosmo_par)
box = borg.forward.BoxModel()
box.L = (100, 100, 100)
box.N = (64,64,64)#, 32, 32)
print(box)
rho = np.zeros(box.N)
rho_gpu = np.zeros(box.N)
icplus = np.zeros((box.N[0], box.N[1], box.N[2] // 2 + 1), dtype=np.complex128)
ic = np.fft.rfftn(np.random.randn(*box.N)) / box.N[0]**(1.5)
box2 = borg.forward.BoxModel()
box2.L = box.L
box2.N = tuple(map(lambda x: 2 * x, box.N))
h = borg.forward.models.HermiticEnforcer(box)
primordial = borg.forward.models.Primordial(box, 1.0)
ehu = borg.forward.models.EisensteinHu(box)
chain = borg.forward.ChainForwardModel(box)
chain.addModel(h)
chain.addModel(primordial)
chain.addModel(ehu)
chain.setCosmoParams(cosmo_par)
#lpt_gpu = borg.forward.models.newModel("LPT_GPU", box, {});
lpt = borg.forward.models.newModel(
"LPT_CIC", box,
dict(a_initial=1.0,
a_final=1.0,
do_rsd=False,
supersampling=1,
lightcone=False,
part_factor=1.1,
mul_out=1))
lpt_omp = borg.forward.models.newModel(
"LPT_CIC_OPENMP", box,
dict(a_initial=1.0,
a_final=1.0,
do_rsd=False,
supersampling=1,
lightcone=False,
part_factor=1.1,
mul_out=1))
rho = np.zeros(box.N)
rho_gpu = np.zeros(box.N)
rho_omp = np.zeros(box.N)
icplus = np.zeros(box.N)
#chain.addModel(lpt_gpu)
chain.forwardModel_v2(ic)
chain.getDensityFinal(icplus)
lpt_gpu = JaxLpt(box)
#
lpt.setCosmoParams(cosmo_par)
#lpt_omp.setCosmoParams(cosmo_par)
#ehu.getDensityFinal(icplus)
lpt.forwardModel_v2(icplus)
lpt.getDensityFinal(rho)
lpt_gpu.forwardModel_v2(icplus)
lpt_gpu.getDensityFinal(rho_gpu)
#lpt_omp.forwardModel_v2(icplus)
#lpt_omp.getDensityFinal(rho_omp)
#
#
ag = np.random.uniform(size=box.N)/10.
lpt_gpu.adjointModel_v2(ag)
ag_gpu = np.zeros(box.N)
lpt_gpu.getAdjointModel(ag_gpu)
lpt.adjointModel_v2(ag)
ag_cpu = np.zeros(box.N)
lpt.getAdjointModel(ag_cpu)

View file

@ -0,0 +1,120 @@
from matplotlib import pyplot as plt
import io
import numpy as np
import sys
import mpi4py
import contextlib
import mpi4py.MPI
import _borg
cons=_borg.console()
M = 128
pfact=1.02
class RewriteIO(io.IOBase):
def __init__(self, original):
self.original = original
self.newline = False
self.comm = mpi4py.MPI.COMM_WORLD
self.prefix = f'[{self.comm.rank} / {self.comm.size}] '
def write(self, b):
if b[0] == '\n':
return self.original.write(b)
return self.original.write(self.prefix + b)
def writelines(self,lines):
return self.original.writelines(lines)
def make_P(box, delta):
ik = np.fft.fftfreq(box.N[0], d=box.L[0]/box.N[0] ) *2*np.pi
kx,ky,kz = np.meshgrid(ik,ik,ik[:(box.N[0]//2 + 1)])
kn = np.sqrt(kx**2 + ky**2 + kz**2)
delta_hat = np.fft.rfftn(delta) * box.volume / box.Ntot
P, bins = np.histogram(kn, weights = np.abs(delta_hat)**2, range=(0,1),bins=50)
Pw, _ = np.histogram(kn, range=(0,1),bins=50)
P = P / Pw / box.volume
return bins, P
with contextlib.redirect_stdout(RewriteIO(sys.stdout)):
cons.setVerboseLevel(5)
cosmo_par = _borg.cosmo.CosmologicalParameters()
cosmo_par.default()
print(repr(cosmo_par))
cosmo = _borg.cosmo.Cosmology(cosmo_par)
cpower = _borg.cosmo.CosmoPower(cosmo_par)
box = _borg.forward.BoxModel()
box.L = (600,600,600)
box.N = (M,M,M)
print(box)
# Generate random numbers variance 1 in fourier space
indelta = np.random.randn(*box.N)
indelta /= np.sqrt(indelta.size)
delta_hat = np.fft.rfftn(indelta)
comm = mpi4py.MPI.COMM_WORLD
delta_hat = delta_hat[comm.rank*box.N[0]//comm.size : (comm.rank+1)*box.N[0]//comm.size, :, :]
# Generate k grid
ik = np.fft.fftfreq(box.N[0], d=box.L[0]/box.N[0] ) *2*np.pi
kx,ky,kz = np.meshgrid(ik,ik,ik[:(box.N[0]//2 + 1)])
kn = np.sqrt(kx**2 + ky**2 + kz**2)
kn = kn[comm.rank*box.N[0]//comm.size : (comm.rank+1)*box.N[0]//comm.size, :, :]
# Scale and multiply by power spectrum
scale = cosmo.d_plus(0.1)/cosmo.d_plus(1.0)
delta_hat *= scale* np.sqrt(box.L[0]**3 * cpower.power(kn))
outN = (comm.rank+1)*box.N[0]//comm.size - (comm.rank)*box.N[0]//comm.size, box.N[1], box.N[2]
#
# Apply LPT
final_delta_lpt = np.zeros(outN)
model = _borg.forward.models.BorgLpt(box,ai=0.1, particle_factor=pfact)
model.holdParticles()
model.setCosmoParams(cosmo_par)
model.forwardModel(delta_hat / box.L[0]**3, final_delta_lpt)
del model
final_delta_lpt_ngp_quad = np.zeros(outN)
model = _borg.forward.models.BorgLptNGP_Quad(box,ai=0.1, particle_factor=pfact)
model.holdParticles()
model.setCosmoParams(cosmo_par)
model.forwardModel(delta_hat / box.L[0]**3, final_delta_lpt_ngp_quad)
del model
final_delta_lpt_smooth_ngp_quad = np.zeros(outN)
model = _borg.forward.models.BorgLptSmoothNGP_Quad(box,ai=0.1, particle_factor=pfact)
model.holdParticles()
model.setCosmoParams(cosmo_par)
model.forwardModel(delta_hat / box.L[0]**3, final_delta_lpt_smooth_ngp_quad)
del model
P_cic = make_P(box, final_delta_lpt)
P_ngp_quad = make_P(box, final_delta_lpt_ngp_quad)
P_smooth_ngp_quad = make_P(box, final_delta_lpt_smooth_ngp_quad)
kk = (P_cic[0][1:]+P_cic[0][:-1])/2
fig=plt.figure()
ax = fig.add_subplot(111)
ax.loglog(kk,P_ngp_quad[1],label='MNGP QUAD')
ax.loglog(kk,P_smooth_ngp_quad[1],label='Smooth QUAD')
ax.loglog(kk,P_cic[1],label='CIC')
ax.loglog(kk,cpower.power(kk),label='linear')
ax.legend()
ax.set_xlabel('$k (h/Mpc)$')
ax.set_ylabel("$P(k)$")
ax.set_ylim(1,1e5)
fig.savefig(f"P_{box.N[0]}.pdf")

View file

@ -0,0 +1,45 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/py_mpi.hpp
Copyright (C) 2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __LIBLSS_PYTHON_MPI_HPP
# define __LIBLSS_PYTHON_MPI_HPP
# include "libLSS/mpi/generic_mpi.hpp"
# include "pyborg.hpp"
namespace LibLSS {
namespace Python {
static inline py::object makePythonMPI(MPI_Communication *comm) {
if (!MPI_IS_REAL)
return py::none();
auto mpi_mod = py::module::import("mpi4py.MPI");
py::object m4py_comm = mpi_mod.attr("Comm")();
auto m4py_ptr = (MPI_Comm *)(py::cast<long long>(
mpi_mod.attr("_addressof")(m4py_comm)));
*m4py_ptr = comm->comm();
return m4py_comm;
}
static inline std::shared_ptr<MPI_Communication>
makeMPIFromPython(py::object pycomm) {
if (!MPI_IS_REAL)
return std::shared_ptr<MPI_Communication>(
MPI_Communication::instance(), [](void*) {});
auto mpi_mod = py::module::import("mpi4py.MPI");
auto m4py_ptr = (MPI_Comm *)(py::cast<long long>(
mpi_mod.attr("_addressof")(pycomm)));
return std::make_shared<MPI_Communication>(*m4py_ptr);
}
} // namespace Python
} // namespace LibLSS
#endif
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2020

View file

@ -0,0 +1,98 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pybias.cpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include <iostream>
#include "pyborg.hpp"
#include "pyfuse.hpp"
#include "libLSS/tools/fusewrapper.hpp"
#include "pybias.hpp"
#include "libLSS/physics/bias/linear_bias.hpp"
#include "libLSS/physics/bias/power_law.hpp"
#include "libLSS/physics/bias/double_power_law.hpp"
#include "libLSS/physics/bias/broken_power_law.hpp"
//#include "libLSS/physics/bias/2nd_order_bias.hpp"
#include "libLSS/physics/bias/many_power.hpp"
#include "libLSS/physics/bias/eft_bias.hpp"
namespace py = pybind11;
using namespace pybind11::literals;
void LibLSS::Python::pyBias(py::module m) {
py::class_<BaseBiasModel>(m, "BaseBiasModel")
.def(
"compute", &BaseBiasModel::compute, "borg_model"_a, "nmean"_a,
"bias_params"_a, "density"_a, "biased_density"_a);
py::class_<BiasModel<bias::PowerLaw>, BaseBiasModel>(m, "PowerLawBias")
.def(py::init<>());
py::class_<BiasModel<bias::DoubleBrokenPowerLaw>, BaseBiasModel>(
m, "DoubleBrokenPowerLawBias")
.def(py::init<>());
py::class_<BiasModel<bias::BrokenPowerLaw>, BaseBiasModel>(
m, "BrokenPowerLawBias")
.def(py::init<>());
py::class_<BiasModel<bias::LinearBias>, BaseBiasModel>(m, "LinearBias")
.def(py::init<>());
py::class_<BiasModel<bias::EFTBiasThresh, true>, BaseBiasModel>(
m, "EFTBiasThreshold")
.def(
py::init<>([](double Lambda) {
BiasModel<bias::EFTBiasThresh, true> *bias_model;
bias_model = new BiasModel<bias::EFTBiasThresh, true>();
LikelihoodInfo info;
info["EFT_Lambda"] = Lambda;
bias_model->bias = std::make_unique<bias::EFTBiasThresh>(info);
return bias_model;
}),
"Lambda"_a);
py::class_<BiasModel<bias::EFTBiasDefault, true>, BaseBiasModel>(
m, "EFTBiasDefault")
.def(
py::init<>([](double Lambda) {
BiasModel<bias::EFTBiasDefault, true> *bias_model;
bias_model = new BiasModel<bias::EFTBiasDefault, true>();
LikelihoodInfo info;
info["EFT_Lambda"] = Lambda;
bias_model->bias = std::make_unique<bias::EFTBiasDefault>(info);
return bias_model;
}),
"Lambda"_a);
/*py::class_<BiasModel<bias::SecondOrderBias>, BaseBiasModel>(
m, "SecondOrderBias")
.def(py::init<>());
*/
// py::class_<
// BiasModel<bias::ManyPower<bias::ManyPowerLevels<double, 1>>, true>,
// BaseBiasModel>(m, "MultiScalePowerBias_1")
// .def(py::init<>());
/* py::class_<BiasModel<bias::ManyPower<bias::ManyPowerLevels<double, 1, 1>> >, BaseBiasModel>(
m, "MultiScalePowerBias_1_1")
.def(py::init<>());
py::class_<BiasModel<bias::ManyPower<bias::ManyPowerLevels<double, 2>> >, BaseBiasModel>(
m, "MultiScalePowerBias_2")
.def(py::init<>());
py::class_<BiasModel<bias::ManyPower<bias::ManyPowerLevels<double, 2, 2>> >, BaseBiasModel>(
m, "MultiScalePowerBias_2_2")
.def(py::init<>());
*/
}
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1,138 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pybias.hpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __LIBLSS_PYTHON_BIAS_HPP
# define __LIBLSS_PYTHON_BIAS_HPP
# include <pybind11/pybind11.h>
# include <pybind11/numpy.h>
# include <boost/format.hpp>
# include "libLSS/physics/forward_model.hpp"
# include "pyfuse.hpp"
namespace LibLSS {
namespace Python {
namespace py = pybind11;
class BaseBiasModel {
public:
BaseBiasModel() {}
virtual void compute(
BORGForwardModel *m, double nmean, py::array_t<double> bias_params,
py::array_t<double> density, py::array_t<double> biased_density) = 0;
};
template <typename Bias_t, bool protect = false>
class BiasModel;
template <typename Bias_t>
class BiasModel<Bias_t, false> : public BaseBiasModel {
public:
std::unique_ptr<Bias_t> bias;
virtual void compute(
BORGForwardModel *m, double nmean, py::array_t<double> bias_params,
py::array_t<double> density, py::array_t<double> biased_density) {
if (!bias)
bias = std::make_unique<Bias_t>();
if (bias_params.ndim() != 1 ||
bias_params.shape()[0] != Bias_t::numParams)
throw std::range_error(boost::str(
boost::format("Bias array has invalid dimensions. Expecting %d") %
Bias_t::numParams));
if (density.ndim() != 3 || density.shape(0) != m->lo_mgr->localN0 ||
density.shape(1) != m->lo_mgr->N1 ||
density.shape(2) != m->lo_mgr->N2)
throw std::range_error(boost::str(
boost::format("Input array has invalid dimensions, expecting "
"%dx%dx%d") %
m->lo_mgr->localN0 % m->lo_mgr->N1 % m->lo_mgr->N2));
if (biased_density.ndim() != 3 ||
biased_density.shape(0) != m->lo_mgr->localN0 ||
biased_density.shape(1) != m->lo_mgr->N1 ||
biased_density.shape(2) != m->lo_mgr->N2)
throw std::range_error(boost::str(
boost::format("Output array has invalid dimensions, expecting "
"%dx%dx%d") %
m->lo_mgr->localN0 % m->lo_mgr->N1 % m->lo_mgr->N2));
py::gil_scoped_release release;
PyToFuseArray<double, 1, false> bias_params_a(
bias_params.unchecked<1>());
PyToFuseArray<double, 3, false> in(density.unchecked<3>());
PyToFuseArray<double, 3, true> out(
biased_density.mutable_unchecked<3>());
bias->prepare(*m, in, nmean, bias_params_a, true);
LibLSS::copy_array(out, std::get<0>(bias->compute_density(in)));
bias->cleanup();
}
};
template <typename Bias_t>
class BiasModel<Bias_t, true> : public BaseBiasModel {
public:
std::unique_ptr<Bias_t> bias;
virtual void compute(
BORGForwardModel *m, double nmean, py::array_t<double> bias_params,
py::array_t<double> density, py::array_t<double> biased_density) {
if (!bias)
bias = std::make_unique<Bias_t>();
if (bias_params.ndim() != 1 ||
bias_params.shape()[0] != Bias_t::numParams)
throw std::range_error(boost::str(
boost::format("Bias array has invalid dimensions. Expecting %d") %
Bias_t::numParams));
if (density.ndim() != 3 || density.shape(0) != m->lo_mgr->localN0 ||
density.shape(1) != m->lo_mgr->N1 ||
density.shape(2) != m->lo_mgr->N2)
throw std::range_error(boost::str(
boost::format("Input array has invalid dimensions, expecting "
"%dx%dx%d") %
m->lo_mgr->localN0 % m->lo_mgr->N1 % m->lo_mgr->N2));
if (biased_density.ndim() != 3 ||
biased_density.shape(0) != m->lo_mgr->localN0 ||
biased_density.shape(1) != m->lo_mgr->N1 ||
biased_density.shape(2) != m->lo_mgr->N2)
throw std::range_error(boost::str(
boost::format("Output array has invalid dimensions, expecting "
"%dx%dx%d") %
m->lo_mgr->localN0 % m->lo_mgr->N1 % m->lo_mgr->N2));
{
py::gil_scoped_release release;
PyToFuseArray<double, 1, false> bias_params_a(
bias_params.unchecked<1>());
PyToFuseArray<double, 3, false> in(density.unchecked<3>());
PyToFuseArray<double, 3, true> out(
biased_density.mutable_unchecked<3>());
LibLSS::U_Array<double, 3> tmp_density(m->out_mgr->extents_real_strict());
fwrap(tmp_density.get_array()[m->out_mgr->strict_range()]) = in;
bias->prepare(*m, tmp_density.get_array(), nmean, bias_params_a, true);
LibLSS::copy_array(out, std::get<0>(bias->compute_density(tmp_density.get_array())));
bias->cleanup();
}
}
};
} // namespace Python
} // namespace LibLSS
#endif
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1,46 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pyborg.hpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#pragma once
#ifndef __LIBLSS_PYTHON_BASE_HPP
# define __LIBLSS_PYTHON_BASE_HPP
# include <pybind11/pybind11.h>
# include <boost/any.hpp>
namespace LibLSS {
namespace Python {
namespace py = pybind11;
void setupConsole();
void bindBORG(py::module m);
void pyBase(py::module m);
void pyCosmo(py::module m);
void pyLikelihood(py::module m);
void pyForwardBase(py::module m);
void pyForwardBorg(py::module m);
void pyForwardAll(py::module m);
void pyBias(py::module m);
void pyVelocity(py::module m);
void pySamplers(py::module m);
void shuttingDown();
py::object any_to_python(boost::any &a);
boost::any python_to_any(py::object o);
extern bool mpi4py_available;
} // namespace Python
} // namespace LibLSS
#endif
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1,34 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pyborg_doc.hpp
Copyright (C) 2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
// Strongly inspired from mkdoc.py in pybind11
#ifndef __PYDOC_HPP
#define __PYDOC_HPP
#define __EXPAND(x) x
#define __COUNT(_1, _2, _3, _4, _5, _6, _7, COUNT, ...) COUNT
#define __VA_SIZE(...) __EXPAND(__COUNT(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1))
#define __CAT1(a, b) a ## b
#define __CAT2(a, b) __CAT1(a, b)
#define __DOC1(n1) __pydocstring_##n1
#define __DOC2(n1, n2) __pydocstring_##n1##_##n2
#define __DOC3(n1, n2, n3) __pydocstring_##n1##_##n2##_##n3
#define __DOC4(n1, n2, n3, n4) __pydocstring_##n1##_##n2##_##n3##_##n4
#define __DOC5(n1, n2, n3, n4, n5) __pydocstring_##n1##_##n2##_##n3##_##n4##_##n5
#define __DOC6(n1, n2, n3, n4, n5, n6) __pydocstring_##n1##_##n2##_##n3##_##n4##_##n5##_##n6
#define __DOC7(n1, n2, n3, n4, n5, n6, n7) __pydocstring_##n1##_##n2##_##n3##_##n4##_##n5##_##n6##_##n7
#define DOC(...) __EXPAND(__EXPAND(__CAT2(__DOC, __VA_SIZE(__VA_ARGS__)))(__VA_ARGS__))
#endif
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: year(0) = 2020
// ARES TAG: email(0) = guilhem.lavaux@iap.fr

View file

@ -0,0 +1,167 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pycosmo.cpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include <CosmoTool/cosmopower.hpp>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include "libLSS/physics/cosmo.hpp"
#include "libLSS/tools/console.hpp"
#include "libLSS/physics/cosmo.hpp"
#include "libLSS/physics/class_cosmo.hpp"
#include "pyborg.hpp"
namespace py = pybind11;
using namespace pybind11::literals;
#include "pyborg_doc.hpp"
#include "pyborg_doc/aquila_borg.cosmo.hpp"
void LibLSS::Python::pyCosmo(py::module m) {
m.doc() = DOC(aquila_borg, cosmo);
py::class_<CosmologicalParameters>(
m, "CosmologicalParameters",
DOC(aquila_borg, cosmo, CosmologicalParameters))
.def(py::init<>([]() {
CosmologicalParameters *cpar = new CosmologicalParameters;
cpar->omega_r = 0.0;
cpar->omega_k = 0.0;
cpar->omega_m = 0.30;
cpar->omega_q = 0.70;
cpar->omega_b = 0.049;
cpar->w = -1;
cpar->n_s = 1.0;
cpar->fnl = 0;
cpar->wprime = 0;
cpar->sigma8 = 0.8;
cpar->h = 0.8;
cpar->a0 = 1.0;
cpar->sum_mnu = 0.0;
return cpar;
}))
.def_readwrite("omega_r", &CosmologicalParameters::omega_r, DOC(aquila_borg, cosmo, CosmologicalParameters, omega_r))
.def_readwrite("omega_k", &CosmologicalParameters::omega_k, DOC(aquila_borg, cosmo, CosmologicalParameters, omega_k))
.def_readwrite("omega_m", &CosmologicalParameters::omega_m, DOC(aquila_borg, cosmo, CosmologicalParameters, omega_m))
.def_readwrite("omega_b", &CosmologicalParameters::omega_b, DOC(aquila_borg, cosmo, CosmologicalParameters, omega_b))
.def_readwrite("omega_q", &CosmologicalParameters::omega_q, DOC(aquila_borg, cosmo, CosmologicalParameters, omega_q))
.def_readwrite("w", &CosmologicalParameters::w, DOC(aquila_borg, cosmo, CosmologicalParameters, w))
.def_readwrite("n_s", &CosmologicalParameters::n_s, DOC(aquila_borg, cosmo, CosmologicalParameters, n_s))
.def_readwrite("fnl", &CosmologicalParameters::fnl, DOC(aquila_borg, cosmo, CosmologicalParameters, fnl))
.def_readwrite("wprime", &CosmologicalParameters::wprime, DOC(aquila_borg, cosmo, CosmologicalParameters, wprime))
.def_readwrite("sigma8", &CosmologicalParameters::sigma8)
.def_readwrite("h", &CosmologicalParameters::h, DOC(aquila_borg, cosmo, CosmologicalParameters, h))
.def_readwrite("a0", &CosmologicalParameters::a0)
.def_readwrite("sum_mnu", &CosmologicalParameters::sum_mnu, DOC(aquila_borg, cosmo, CosmologicalParameters, sum_mnu))
.def(
"__copy__",
[](CosmologicalParameters *cpar) {
CosmologicalParameters *newcpar = new CosmologicalParameters;
*newcpar = *cpar;
return newcpar;
})
.def(
"__deepcopy__",
[](CosmologicalParameters *cpar) {
CosmologicalParameters *newcpar = new CosmologicalParameters;
*newcpar = *cpar;
return newcpar;
})
.def(
"default",
[](CosmologicalParameters *cpar) {
cpar->omega_r = 0.0;
cpar->omega_k = 0.0;
cpar->omega_m = 0.30;
cpar->omega_q = 0.70;
cpar->omega_b = 0.049;
cpar->w = -1;
cpar->n_s = 1.0;
cpar->fnl = 0;
cpar->wprime = 0;
cpar->sigma8 = 0.8;
cpar->h = 0.8;
cpar->a0 = 1.0;
cpar->sum_mnu = 0;
},
DOC(aquila_borg, cosmo, CosmologicalParameters, default))
.def("__repr__", [](CosmologicalParameters *m) {
return boost::str(
boost::format("<CosmologicalParameters: omega_r=%g, omega_k=%g, "
"omega_m=%g, omega_b=%g, omega_q=%g, w=%g, n_s=%g, "
"fnl=%g, wprime=%g, sigma8=%g, h=%g, sum_mnu=%g eV>") %
m->omega_r % m->omega_k % m->omega_m % m->omega_b % m->omega_q %
m->w % m->n_s % m->fnl % m->wprime % m->sigma8 % m->h % m->sum_mnu);
});
py::class_<Cosmology>(m, "Cosmology", DOC(aquila_borg, cosmo, Cosmology))
.def(
py::init([](CosmologicalParameters *params) {
return new Cosmology(*params);
}),
"cosmo_params"_a)
.def(
"__copy__",
[](Cosmology const &cosmo) {
return new Cosmology(cosmo.getParameters());
})
.def(
"a2z", &Cosmology::a2z, "a"_a,
"Compute the redshift for the given scale factor")
.def(
"z2a", &Cosmology::z2a, "z"_a,
"Compute the scale factor for the given redshift")
.def(
"d_plus", &Cosmology::d_plus, "a"_a,
"Compute the linear growth factor at a given scale factor")
.def("a2com", &Cosmology::a2com, "a"_a)
.def("com2a", &Cosmology::com2a, "com"_a)
.def("dtr", &Cosmology::dtr, "Delta t_r factor of the PM")
.def("dtv", &Cosmology::dtv, "Delta t_v factor of the PM")
.def("gplus", &Cosmology::g_plus)
.def("comph2com", &Cosmology::comph2com)
.def("com2comph", &Cosmology::com2comph);
py::class_<ClassCosmo>(m, "ClassCosmo", DOC(aquila_borg, cosmo, ClassCosmo))
.def(
py::init([](CosmologicalParameters *params) {
return new ClassCosmo(*params);
}),
"cosmo_params"_a)
.def("get_Tk", py::vectorize(&ClassCosmo::get_Tk), "k"_a, DOC(aquila_borg, cosmo, ClassCosmo, get_Tk))
.def("getCosmology", &ClassCosmo::getCosmology, DOC(aquila_borg, cosmo, ClassCosmo, getCosmology));
py::class_<CosmoTool::CosmoPower>(
m, "CosmoPower", DOC(aquila_borg, cosmo, CosmoPower))
.def(
py::init([](CosmologicalParameters *params) {
auto cpow = new CosmoTool::CosmoPower();
cpow->h = params->h;
cpow->OMEGA_B = params->omega_b;
cpow->OMEGA_C = params->omega_m - params->omega_b;
cpow->SIGMA8 = params->sigma8;
cpow->n = params->n_s;
cpow->updateCosmology();
cpow->setFunction(CosmoTool::CosmoPower::HU_WIGGLES);
cpow->normalize();
return cpow;
}),
"cosmo_params"_a)
.def(
"power", py::vectorize([](CosmoTool::CosmoPower *p, double k) {
return p->power(k * p->h) * p->h * p->h * p->h;
}),
"k"_a,
"Evaluate the power spectrum using Eisentein&Hu formula at a given k "
"in h/Mpc. Returns P(k) in (Mpc/h)^3");
}
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1,850 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pyforward.cpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include <memory>
#include <exception>
#include <boost/format.hpp>
#include <pybind11/pybind11.h>
#include <CosmoTool/cosmopower.hpp>
#include <pybind11/numpy.h>
#include "libLSS/physics/cosmo.hpp"
#include "libLSS/tools/console.hpp"
#include "libLSS/physics/cosmo.hpp"
#include "pyborg.hpp"
#include "libLSS/mpi/generic_mpi.hpp"
#include "libLSS/tools/static_init.hpp"
#include "libLSS/physics/forward_model.hpp"
#include "pyforward.hpp"
#include "pyfuse.hpp"
#include "libLSS/physics/likelihoods/base.hpp"
#include "libLSS/physics/chain_forward_model.hpp"
#include "py_mpi.hpp"
namespace py = pybind11;
using namespace pybind11::literals;
using namespace LibLSS;
typedef boost::multi_array_types::index_range i_range;
template <typename T, typename U>
static inline void transfer_in(
std::shared_ptr<BORGForwardModel::DFT_Manager> &mgr, T &tmp_in, U &in,
bool cplx) {
LIBLSS_AUTO_DEBUG_CONTEXT(ctx);
size_t s0 = mgr->startN0;
Python::PyToFuseArray<typename T::element, 3, false> p_in(in);
auto vv =
tmp_in[boost::indices[i_range(s0, s0 + mgr->localN0)][i_range(0, mgr->N1)]
[i_range(0, cplx ? mgr->N2_HC : mgr->N2)]];
fwrap(vv) = fwrap(p_in);
}
template <typename T, typename U>
static inline void transfer_out(
std::shared_ptr<BORGForwardModel::DFT_Manager> &mgr, T &tmp_out, U &out,
bool cplx) {
size_t s0 = mgr->startN0;
Python::PyToFuseArray<typename T::element, 3, true> p_out(out);
fwrap(p_out) =
fwrap(tmp_out[boost::indices[i_range(s0, s0 + mgr->localN0)][i_range(
0, mgr->N1)][i_range(0, cplx ? mgr->N2_HC : mgr->N2)]]);
}
class BaseForwardModel : public BORGForwardModel {
public:
BaseForwardModel(BaseForwardModel &&other) = default;
BaseForwardModel(BoxModel const &in_box, BoxModel const &out_box)
: BORGForwardModel(MPI_Communication::instance(), in_box, out_box) {}
};
/**
* @brief Class to reverse wrap python object to make them available in C++
*
*/
class PyBaseForwardModel : public BaseForwardModel {
public:
using BaseForwardModel::BaseForwardModel;
PyBaseForwardModel(BaseForwardModel &&other)
: BaseForwardModel(std::move(other)) {}
PreferredIO getPreferredInput() const override {
py::gil_scoped_acquire acquire;
PYBIND11_OVERLOAD_PURE(PreferredIO, BaseForwardModel, getPreferredInput);
}
PreferredIO getPreferredOutput() const override {
py::gil_scoped_acquire acquire;
PYBIND11_OVERLOAD_PURE(PreferredIO, BaseForwardModel, getPreferredOutput);
}
void accumulateAdjoint(bool on) override {
py::gil_scoped_acquire acquire;
PYBIND11_OVERLOAD_PURE(void, BaseForwardModel, accumulateAdjoint, on);
}
void setModelParams(ModelDictionnary const &params) override {
{
py::gil_scoped_acquire acquire;
py::dict pyParams;
for (auto const &k : params) {
if (k.second.type() == typeid(double)) {
pyParams[k.first.c_str()] = boost::any_cast<double>(k.second);
} else if (k.second.type() == typeid(LibLSS::multi_array<double, 1>)) {
auto values =
boost::any_cast<LibLSS::multi_array<double, 1>>(k.second);
py::array_t<double> tmp({values.shape()[0]}, {1}, values.data());
pyParams[k.first.c_str()] = tmp;
} else if (
k.second.type() ==
typeid(std::shared_ptr<LibLSS::CosmologicalParameters>)) {
CosmologicalParameters cosmo =
*boost::any_cast<std::shared_ptr<LibLSS::CosmologicalParameters>>(
k.second);
pyParams[k.first.c_str()] = cosmo;
} else {
error_helper<ErrorParams>(
"Unknown type to be converted to Python in setModelParams");
}
}
auto pythonFunction = py::get_overload(
static_cast<BaseForwardModel const *>(this), "setModelParams");
if (pythonFunction) {
pythonFunction(pyParams);
}
}
BaseForwardModel::setModelParams(params);
}
boost::any
getModelParam(std::string const &name, std::string const &keyname) override {
{
py::gil_scoped_acquire acquire;
py::dict pyParams;
auto pythonFunction = py::get_overload(
static_cast<BaseForwardModel const *>(this), "getModelParam");
if (pythonFunction) {
py::object ret = pythonFunction(name, keyname);
return Python::python_to_any(ret);
}
}
return BaseForwardModel::getModelParam(name, keyname);
}
void forwardModel_v2(ModelInput<3> input) override {
switch (getPreferredInput()) {
case PREFERRED_REAL: {
input.setRequestedIO(PREFERRED_REAL);
auto &x = input.getRealConst();
{
py::gil_scoped_acquire acquire;
py::object h = Python::makeNumpy(x, input.hold_original);
PYBIND11_OVERLOAD_PURE(void, BaseForwardModel, forwardModel_v2_impl, h);
}
break;
}
case PREFERRED_FOURIER: {
input.setRequestedIO(PREFERRED_FOURIER);
auto &x = input.getFourierConst();
{
py::gil_scoped_acquire acquire;
py::object h = Python::makeNumpy(x, input.hold_original);
PYBIND11_OVERLOAD_PURE(void, BaseForwardModel, forwardModel_v2_impl, h);
}
break;
}
default:
error_helper<ErrorNotImplemented>("IO type not implemented.");
break;
}
}
void getDensityFinal(ModelOutput<3> output) override {
switch (getPreferredOutput()) {
case PREFERRED_REAL: {
output.setRequestedIO(PREFERRED_REAL);
auto &x = output.getRealOutput();
{
py::gil_scoped_acquire acquire;
py::object h = Python::makeNumpy(x, output.hold_original);
PYBIND11_OVERLOAD_PURE(void, BaseForwardModel, getDensityFinal_impl, h);
}
break;
}
case PREFERRED_FOURIER: {
output.setRequestedIO(PREFERRED_FOURIER);
auto &x = output.getFourierOutput();
{
py::gil_scoped_acquire acquire;
py::object h = Python::makeNumpy(x, output.hold_original);
PYBIND11_OVERLOAD_PURE(void, BaseForwardModel, getDensityFinal_impl, h);
}
break;
}
default:
error_helper<ErrorNotImplemented>("IO type not implemented.");
break;
}
}
void adjointModel_v2(ModelInputAdjoint<3> input) override {
switch (getPreferredOutput()) {
case PREFERRED_REAL: {
input.setRequestedIO(PREFERRED_REAL);
auto &x = input.getRealConst();
{
py::gil_scoped_acquire acquire;
py::object h = Python::makeNumpy(x, input.hold_original);
PYBIND11_OVERLOAD_PURE(void, BaseForwardModel, adjointModel_v2_impl, h);
}
break;
}
case PREFERRED_FOURIER: {
input.setRequestedIO(PREFERRED_FOURIER);
auto &x = input.getFourierConst();
{
py::gil_scoped_acquire acquire;
py::object h = Python::makeNumpy(x, input.hold_original);
PYBIND11_OVERLOAD_PURE(void, BaseForwardModel, adjointModel_v2_impl, h);
}
break;
}
default:
error_helper<ErrorNotImplemented>("IO type not implemented.");
break;
}
}
void getAdjointModelOutput(ModelOutputAdjoint<3> output) override {
switch (getPreferredInput()) {
case PREFERRED_REAL: {
output.setRequestedIO(PREFERRED_REAL);
auto &x = output.getRealOutput();
{
py::gil_scoped_acquire acquire;
py::object h = Python::makeNumpy(x, output.hold_original);
PYBIND11_OVERLOAD_PURE(void, BaseForwardModel, getAdjointModel_impl, h);
}
break;
}
case PREFERRED_FOURIER: {
output.setRequestedIO(PREFERRED_FOURIER);
auto &x = output.getFourierOutput();
{
py::gil_scoped_acquire acquire;
py::object h = Python::makeNumpy(x, output.hold_original);
PYBIND11_OVERLOAD_PURE(void, BaseForwardModel, getAdjointModel_impl, h);
}
break;
}
default:
error_helper<ErrorNotImplemented>("IO type not implemented.");
break;
}
}
};
static void do_forward_v2(BORGForwardModel *fwd_model, py::array input) {
ModelInput<3> model_input;
if (input.dtype().is(py::dtype::of<double>())) {
auto in = input.unchecked<double, 3>();
check_array_real(in, fwd_model->lo_mgr);
auto tmp_in_p = fwd_model->lo_mgr->allocate_ptr_array();
auto &tmp_in = tmp_in_p->get_array();
transfer_in(fwd_model->lo_mgr, tmp_in, in, false);
model_input = std::move(ModelInput<3>(
fwd_model->lo_mgr, fwd_model->get_box_model(), tmp_in,
std::move(tmp_in_p)));
} else if (input.dtype().is(py::dtype::of<std::complex<double>>())) {
auto in = input.unchecked<std::complex<double>, 3>();
check_array_complex(in, fwd_model->lo_mgr);
auto tmp_in_c_p = fwd_model->lo_mgr->allocate_ptr_complex_array();
auto &tmp_in_c = tmp_in_c_p->get_array();
transfer_in(fwd_model->lo_mgr, tmp_in_c, in, true);
model_input = std::move(ModelInput<3>(
fwd_model->lo_mgr, fwd_model->get_box_model(), tmp_in_c,
std::move(tmp_in_c_p)));
} else {
throw std::runtime_error(
"PyBORGForward only support double and complex double.");
}
{
py::gil_scoped_release release;
fwd_model->forwardModel_v2(std::move(model_input));
}
// If the forward model has put a hold on input, it will not be destroyed till the hold is released.
}
static void do_adjoint_v2(BORGForwardModel *fwd_model, py::object o_input) {
ModelInputAdjoint<3> model_input;
if (o_input.is_none()) {
py::gil_scoped_release release;
// We just a push an empty AG vector.
fwd_model->adjointModel_v2(std::move(model_input));
return;
}
py::array input = o_input;
if (input.dtype().is(py::dtype::of<double>())) {
auto in = input.unchecked<double, 3>();
check_array_real(in, fwd_model->out_mgr);
auto tmp_in_p = fwd_model->lo_mgr->allocate_ptr_array();
auto &tmp_in = tmp_in_p->get_array();
transfer_in(fwd_model->lo_mgr, tmp_in, in, false);
model_input = std::move(ModelInputAdjoint<3>(
fwd_model->out_mgr, fwd_model->get_box_model_output(), tmp_in,
std::move(tmp_in_p)));
} else if (input.dtype().is(py::dtype::of<std::complex<double>>())) {
auto in = input.unchecked<std::complex<double>, 3>();
check_array_complex(in, fwd_model->out_mgr);
auto tmp_in_c_p = fwd_model->out_mgr->allocate_ptr_complex_array();
auto &tmp_in_c = tmp_in_c_p->get_array();
transfer_in(fwd_model->out_mgr, tmp_in_c, in, true);
model_input = std::move(ModelInputAdjoint<3>(
fwd_model->lo_mgr, fwd_model->get_box_model(), tmp_in_c,
std::move(tmp_in_c_p)));
} else {
throw std::runtime_error(
"PyBORGForward only support double and complex double.");
}
{
py::gil_scoped_release release;
fwd_model->adjointModel_v2(std::move(model_input));
}
// If the forward model has put a hold on input, it will not be destroyed till the hold is released.
}
static void
do_get_adjoint_model(BORGForwardModel *fwd_model, py::array output) {
decltype(fwd_model->lo_mgr->allocate_ptr_array()) tmp_in_p;
std::function<void()> do_post_transfer;
std::shared_ptr<void> buf_holder;
ModelOutputAdjoint<3> model_output;
if (output.dtype().is(py::dtype::of<double>())) {
auto out = output.mutable_unchecked<double, 3>();
check_array_real(out, fwd_model->out_mgr);
auto tmp_out_p = fwd_model->lo_mgr->allocate_ptr_array();
auto &tmp_out = tmp_out_p->get_array();
buf_holder = std::move(tmp_out_p);
model_output = std::move(ModelOutputAdjoint<3>(
fwd_model->lo_mgr, fwd_model->get_box_model(), tmp_out, buf_holder));
do_post_transfer = [&]() {
auto out = output.mutable_unchecked<double, 3>();
transfer_out(fwd_model->lo_mgr, tmp_out, out, false);
};
} else if (output.dtype().is(py::dtype::of<std::complex<double>>())) {
auto out = output.mutable_unchecked<std::complex<double>, 3>();
check_array_complex(out, fwd_model->lo_mgr);
auto tmp_out_p = fwd_model->lo_mgr->allocate_ptr_complex_array();
auto &tmp_out = tmp_out_p->get_array();
buf_holder = std::move(tmp_out_p);
model_output = std::move(ModelOutputAdjoint<3>(
fwd_model->lo_mgr, fwd_model->get_box_model(), tmp_out, buf_holder));
do_post_transfer = [&]() {
auto out = output.mutable_unchecked<std::complex<double>, 3>();
transfer_out(fwd_model->lo_mgr, tmp_out, out, true);
};
} else {
throw std::runtime_error(
"PyBORGForward only support double and complex double.");
}
{
py::gil_scoped_release release;
fwd_model->getAdjointModelOutput(std::move(model_output));
do_post_transfer();
}
}
static void
do_get_density_final(BORGForwardModel *fwd_model, py::array output) {
LIBLSS_AUTO_DEBUG_CONTEXT(ctx);
decltype(fwd_model->lo_mgr->allocate_ptr_array()) tmp_in_p;
std::function<void()> do_post_transfer;
std::shared_ptr<void> buf_holder;
ModelOutput<3> model_output;
if (output.dtype().is(py::dtype::of<double>())) {
auto out = output.mutable_unchecked<double, 3>();
check_array_real(out, fwd_model->out_mgr);
auto tmp_out_p = fwd_model->out_mgr->allocate_ptr_array();
auto &tmp_out = tmp_out_p->get_array();
buf_holder = std::move(tmp_out_p);
model_output = std::move(ModelOutput<3>(
fwd_model->out_mgr, fwd_model->get_box_model_output(), tmp_out,
buf_holder));
do_post_transfer = [&]() {
auto out = output.mutable_unchecked<double, 3>();
transfer_out(fwd_model->out_mgr, tmp_out, out, false);
};
} else if (output.dtype().is(py::dtype::of<std::complex<double>>())) {
auto out = output.mutable_unchecked<std::complex<double>, 3>();
check_array_complex(out, fwd_model->out_mgr);
auto tmp_out_p = fwd_model->out_mgr->allocate_ptr_complex_array();
auto &tmp_out = tmp_out_p->get_array();
buf_holder = std::move(tmp_out_p);
model_output = std::move(ModelOutput<3>(
fwd_model->out_mgr, fwd_model->get_box_model_output(), tmp_out,
buf_holder));
do_post_transfer = [&]() {
auto out = output.mutable_unchecked<std::complex<double>, 3>();
transfer_out(fwd_model->out_mgr, tmp_out, out, true);
};
} else {
throw std::runtime_error(
"PyBORGForward only support double and complex double.");
}
{
py::gil_scoped_release release;
fwd_model->getDensityFinal(std::move(model_output));
do_post_transfer();
}
}
#include "pyborg_doc.hpp"
#include "pyborg_doc/aquila_borg.forward.hpp"
#include "pyborg_doc/aquila_borg.forward.BaseForwardModel.hpp"
#include "pyborg_doc/aquila_borg.forward.BORGForwardModel.hpp"
#include "pyborg_doc/aquila_borg.forward.ChainForwardModel.hpp"
#include "pyborg_doc/aquila_borg.forward.BoxModel.hpp"
void LibLSS::Python::pyForwardBase(py::module this_module) {
this_module.doc() = DOC(aquila_borg, forward);
py::enum_<PreferredIO>(
this_module, "PreferredIO", DOC(aquila_borg, forward, PreferredIO))
.value(
"PREFERRED_REAL", PREFERRED_REAL,
"Indicate that real space representation is requested for IO")
.value(
"PREFERRED_FOURIER", PREFERRED_FOURIER,
"Indicate that fourier space representation is requested for IO")
.value(
"PREFERRED_NONE", PREFERRED_NONE,
"None are preferred. It is not supported in python.")
.export_values();
py::class_<BoxModel>(this_module, "BoxModel")
.def(
py::init([](double L, int N) {
BoxModel *boxmodel = new BoxModel;
boxmodel->L0 = boxmodel->L1 = boxmodel->L2 = L;
boxmodel->N0 = boxmodel->N1 = boxmodel->N2 = N;
boxmodel->xmin0 = boxmodel->xmin1 = boxmodel->xmin2 = 0;
return boxmodel;
}),
"L"_a = 100.0, "N"_a = 128,
DOC(aquila_borg, forward, BoxModel, __init__))
.def_property(
"xmin",
[](BoxModel *boxmodel) {
return py::make_tuple(
boxmodel->xmin0, boxmodel->xmin1, boxmodel->xmin2);
},
[](BoxModel *boxmodel, py::tuple t) {
boxmodel->xmin0 = t[0].cast<double>();
boxmodel->xmin1 = t[1].cast<double>();
boxmodel->xmin2 = t[2].cast<double>();
},
DOC(aquila_borg, forward, BoxModel, xmin))
.def_property(
"L",
[](BoxModel *boxmodel) {
return py::make_tuple(boxmodel->L0, boxmodel->L1, boxmodel->L2);
},
[](BoxModel *boxmodel, py::tuple t) {
boxmodel->L0 = t[0].cast<double>();
boxmodel->L1 = t[1].cast<double>();
boxmodel->L2 = t[2].cast<double>();
},
DOC(aquila_borg, forward, BoxModel, L))
.def_property_readonly(
"volume",
[](BoxModel *boxmodel) {
return boxmodel->L0 * boxmodel->L1 * boxmodel->L2;
},
DOC(aquila_borg, forward, BoxModel, volume))
.def_property_readonly(
"Ntot",
[](BoxModel *boxmodel) {
return boxmodel->N0 * boxmodel->N1 * boxmodel->N2;
},
DOC(aquila_borg, forward, BoxModel, Ntot))
.def(
"copy",
[](BoxModel *boxmodel) {
BoxModel *newboxmodel = new BoxModel;
*newboxmodel = *boxmodel;
return newboxmodel;
},
DOC(aquila_borg, forward, BoxModel, copy))
.def_property(
"N",
[](BoxModel *boxmodel) {
return py::make_tuple(boxmodel->N0, boxmodel->N1, boxmodel->N2);
},
[](BoxModel *boxmodel, py::tuple t) {
boxmodel->N0 = t[0].cast<long>();
boxmodel->N1 = t[1].cast<long>();
boxmodel->N2 = t[2].cast<long>();
},
DOC(aquila_borg, forward, BoxModel, N))
.def("__repr__", [](BoxModel *boxmodel) {
return boost::str(
boost::format(
"<BoxModel: xc=[%g,%g,%g], L=[%g,%g,%g], N=[%d,%d,%d]") %
boxmodel->xmin0 % boxmodel->xmin1 % boxmodel->xmin2 % boxmodel->L0 %
boxmodel->L1 % boxmodel->L2 % boxmodel->N0 % boxmodel->N1 %
boxmodel->N2);
});
py::class_<BORGForwardModel, std::shared_ptr<BORGForwardModel>>(
this_module, "BORGForwardModel",
DOC(aquila_borg, forward, BORGForwardModel))
.def(
"getPreferredOutput", &BORGForwardModel::getPreferredOutput,
DOC(aquila_borg, forward, BORGForwardModel, getPreferredOutput))
.def(
"getPreferredInput", &BORGForwardModel::getPreferredInput,
DOC(aquila_borg, forward, BORGForwardModel, getPreferredOutput))
.def(
"setCosmoParams",
[](BORGForwardModel *fwd_model, CosmologicalParameters *cpar) {
Console::instance().print<LOG_DEBUG>(
"setting cosmological parameters");
fwd_model->setCosmoParams(*cpar);
},
"cosmo_params"_a,
DOC(aquila_borg, forward, BORGForwardModel, setCosmoParams))
.def(
"getModelParam",
[](BORGForwardModel *fwd_model, std::string const &model,
std::string const &keyname) {
boost::any ret = fwd_model->getModelParam(model, keyname);
return any_to_python(ret);
},
"model"_a, "keyname"_a,
DOC(aquila_borg, forward, BORGForwardModel, getModelParam))
.def(
"setName", &BORGForwardModel::setName, "name"_a,
DOC(aquila_borg, forward, BORGForwardModel, setName))
.def(
"setModelParams",
[](BORGForwardModel *fwd_model, py::dict d) {
ModelDictionnary params;
for (auto const &kv : d) {
std::string name = py::cast<std::string>(kv.first);
if (py::isinstance<py::array>(kv.second)) {
auto a_typed = kv.second.cast<py::array_t<double>>();
if (a_typed.ndim() != 1)
throw std::runtime_error("Only 1-d arrays are supported.");
LibLSS::multi_array<double, 1> local_values(
boost::extents[a_typed.shape()[0]]);
auto a_direct = a_typed.unchecked<1>();
for (int i = 0; i < local_values.num_elements(); i++)
local_values[i] = a_direct(i);
params.insert({name, local_values});
} else if (py::isinstance<py::float_>(kv.second)) {
double value = kv.second.cast<double>();
params.insert({name, value});
} else if (py::isinstance<py::int_>(kv.second)) {
int value = kv.second.cast<int>();
params.insert({name, value});
} else if (py::isinstance<LikelihoodInfo>(kv.second)) {
std::shared_ptr<LikelihoodInfo> info =
kv.second.cast<std::shared_ptr<LikelihoodInfo>>();
params.insert({name, info});
} else if (py::isinstance<CosmologicalParameters>(kv.second)) {
CosmologicalParameters cosmo = kv.second.cast<CosmologicalParameters>();
params.insert({name, cosmo});
}
}
fwd_model->setModelParams(params);
},
"params"_a,
DOC(aquila_borg, forward, BORGForwardModel, setModelParams))
.def(
"getBoxModel",
[](BORGForwardModel *fwd_model) {
BoxModel *bm = new BoxModel();
*bm = fwd_model->get_box_model();
return bm;
;
},
"Return the box on which is defined the input of the model is "
"defined.")
.def(
"getOutputBoxModel",
[](BORGForwardModel *fwd_model) {
BoxModel *bm = new BoxModel();
*bm = fwd_model->get_box_model_output();
return bm;
;
},
DOC(aquila_borg, forward, BORGForwardModel, getOutputBoxModel))
.def(
"getMPISlice",
[](BORGForwardModel *fwd_model) {
return py::make_tuple(
fwd_model->lo_mgr->startN0, fwd_model->lo_mgr->localN0,
fwd_model->lo_mgr->N1, fwd_model->lo_mgr->N2);
},
DOC(aquila_borg, forward, BORGForwardModel, getMPISlice))
.def(
"getCommunicator",
[](BORGForwardModel *model) {
return makePythonMPI(model->communicator());
},
DOC(aquila_borg, forward, BORGForwardModel, getCommunicator))
.def(
"getOutputMPISlice",
[](BORGForwardModel *fwd_model) {
return py::make_tuple(
fwd_model->out_mgr->startN0, fwd_model->out_mgr->localN0,
fwd_model->out_mgr->N1, fwd_model->out_mgr->N2);
},
"Return a tuple indicating what is the expected output MPI slicing "
"(startN0,localN0,N1,N2) (Warning! unstable API)")
.def("holdParticles", &BORGForwardModel::holdParticles)
.def(
"setAdjointRequired", &BORGForwardModel::setAdjointRequired,
DOC(aquila_borg, forward, BORGForwardModel, setAdjointRequired))
.def(
"forwardModel_v2", do_forward_v2,
DOC(aquila_borg, forward, BORGForwardModel, forwardModel_v2))
.def(
"getDensityFinal", do_get_density_final,
"Obtain the density field produced by the forward model (part 2 of "
"the evaluation, v2 API).")
.def(
"accumulateAdjoint", &BORGForwardModel::accumulateAdjoint,
"do_accumulate"_a,
DOC(aquila_borg, forward, BORGForwardModel, accumulateAdjoint))
.def(
"adjointModel_v2", do_adjoint_v2,
py::arg("adjoint_gradient").none(true),
DOC(aquila_borg, forward, BORGForwardModel, adjointModel_v2))
.def(
"clearAdjointGradient", &BORGForwardModel::clearAdjointGradient,
DOC(aquila_borg, forward, BORGForwardModel, clearAdjointGradient))
.def("getAdjointModel", do_get_adjoint_model)
.def(
"forwardModel", [](BORGForwardModel *fwd_model,
py::array_t<std::complex<double>> in_delta,
py::array_t<double> out_delta) {
auto in = in_delta.unchecked<3>();
auto out = out_delta.mutable_unchecked<3>();
if (in.shape(0) != fwd_model->lo_mgr->localN0 ||
in.shape(1) != fwd_model->lo_mgr->N1 ||
in.shape(2) != fwd_model->lo_mgr->N2_HC)
throw std::range_error(boost::str(
boost::format("Input array has invalid dimensions, expecting "
"%dx%dx%d") %
fwd_model->lo_mgr->localN0 % fwd_model->lo_mgr->N1 %
fwd_model->lo_mgr->N2_HC));
if (out.shape(0) != fwd_model->lo_mgr->localN0 ||
out.shape(1) != fwd_model->lo_mgr->N1 ||
out.shape(2) != fwd_model->lo_mgr->N2)
throw std::range_error(boost::str(
boost::format(
"Output array has invalid dimensions, expecting "
"%dx%dx%d") %
fwd_model->lo_mgr->localN0 % fwd_model->lo_mgr->N1 %
fwd_model->lo_mgr->N2));
py::gil_scoped_release release;
auto tmp_in_p = fwd_model->lo_mgr->allocate_complex_array();
auto &tmp_in = tmp_in_p.get_array();
auto tmp_out_p = fwd_model->lo_mgr->allocate_array();
auto &tmp_out = tmp_out_p.get_array();
size_t s0 = fwd_model->lo_mgr->startN0;
size_t const localN0 = fwd_model->lo_mgr->localN0,
N1 = fwd_model->lo_mgr->N1,
N2_HC = fwd_model->lo_mgr->N2_HC;
#pragma omp parallel for schedule(static) collapse(3)
for (size_t i = 0; i < localN0; i++) {
for (size_t j = 0; j < N1; j++) {
for (size_t k = 0; k < N2_HC; k++) {
tmp_in[i + s0][j][k] = in(i, j, k);
}
}
}
fwd_model->forwardModel(tmp_in, tmp_out, false);
#pragma omp parallel for schedule(static) collapse(3)
for (size_t i = 0; i < localN0; i++) {
for (size_t j = 0; j < N1; j++) {
for (size_t k = 0; k < N2_HC; k++) {
out(i, j, k) = tmp_out[i + s0][j][k];
}
}
}
});
py::class_<
ParticleBasedForwardModel, BORGForwardModel,
std::shared_ptr<ParticleBasedForwardModel>>(
this_module, "ParticleBasedForwardModel",
DOC(aquila_borg, forward, ParticleBasedForwardModel))
.def(
"getNumberOfParticles",
&ParticleBasedForwardModel::getNumberOfParticles,
DOC(aquila_borg, forward, ParticleBasedForwardModel,
getNumberOfParticles))
.def(
"getParticlePositions",
[](ParticleBasedForwardModel *fwd, py::array_t<double> particles) {
PyToFuseArray<double, 2, true> out_p(
particles.mutable_unchecked<2>());
LibLSS::copy_array(out_p, fwd->getParticlePositions());
},
"positions"_a,
DOC(aquila_borg, forward, ParticleBasedForwardModel,
getParticlePositions))
.def(
"setStepNotifier",
[](ParticleBasedForwardModel *fwd, py::object callback) {
fwd->setStepNotifier([callback](
double t, size_t i,
ParticleBasedForwardModel::IdSubArray,
ParticleBasedForwardModel::PhaseSubArray,
ParticleBasedForwardModel::PhaseSubArray) {
py::gil_scoped_acquire acquire;
callback(t, i);
});
},
DOC(aquila_borg, forward, ParticleBasedForwardModel, setStepNotifier))
.def(
"getParticleVelocities",
[](ParticleBasedForwardModel *fwd, py::array_t<double> particles) {
PyToFuseArray<double, 2, true> out_p(
particles.mutable_unchecked<2>());
LibLSS::copy_array(out_p, fwd->getParticleVelocities());
},
"velocities"_a,
DOC(aquila_borg, forward, ParticleBasedForwardModel,
getParticleVelocities));
py::class_<
BaseForwardModel, BORGForwardModel, PyBaseForwardModel,
std::shared_ptr<BaseForwardModel>>(
this_module, "BaseForwardModel",
DOC(aquila_borg, forward, BaseForwardModel))
.def(
py::init<>([](BoxModel *b1, BoxModel *b2) {
return new BaseForwardModel(*b1, *b2);
}),
"box_input"_a, "box_output"_a,
"Construct the C++ side of the forward model with provided input and "
"output boxes.");
py::class_<
ChainForwardModel, BORGForwardModel, std::shared_ptr<ChainForwardModel>>(
this_module, "ChainForwardModel",
DOC(aquila_borg, forward, ChainForwardModel))
.def(
py::init([](BoxModel *box) {
return std::make_unique<ChainForwardModel>(
MPI_Communication::instance(), *box);
}),
"box_model"_a, DOC(aquila_borg, forward, ChainForwardModel, __init__))
.def(
"addModel",
[](ChainForwardModel *fwd_model, py::object fwd_python) {
std::shared_ptr<BORGForwardModel> c =
fwd_python.cast<std::shared_ptr<BORGForwardModel>>();
fwd_python.inc_ref();
// Make a new shared_object which, once ChainForwardModel does not need the model anymore will release
// the reference count on the original object.
fwd_model->addModel(std::shared_ptr<BORGForwardModel>(
c.get(), [c, fwd_python](void *) mutable {
fwd_python.dec_ref();
c.reset();
}));
},
"forward"_a, DOC(aquila_borg, forward, ChainForwardModel, addModel));
}
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1,47 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pyforward.hpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __LIBLSS_PYTHON_FORWARD_HPP
# define __LIBLSS_PYTHON_FORWARD_HPP
# pragma once
# include <memory>
# include <exception>
# include <boost/format.hpp>
# include "libLSS/physics/forward_model.hpp"
namespace LibLSS {
template <typename T>
static inline void
check_array_real(T &in, std::shared_ptr<BORGForwardModel::DFT_Manager> &mgr) {
if (in.shape(0) != mgr->localN0 || in.shape(1) != mgr->N1 ||
in.shape(2) != mgr->N2)
throw std::range_error(boost::str(
boost::format("Input array has invalid dimensions, expecting "
"%dx%dx%d") %
mgr->localN0 % mgr->N1 % mgr->N2));
}
template <typename T>
static inline void check_array_complex(
T &in, std::shared_ptr<BORGForwardModel::DFT_Manager> &mgr) {
if (in.shape(0) != mgr->localN0 || in.shape(1) != mgr->N1 ||
in.shape(2) != mgr->N2_HC)
throw std::range_error(boost::str(
boost::format("Input array has invalid dimensions, expecting "
"%dx%dx%d") %
mgr->localN0 % mgr->N1 % mgr->N2_HC));
}
} // namespace LibLSS
#endif
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1,106 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pyforward_all.cpp
Copyright (C) 2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include <memory>
#include <pybind11/stl.h>
#include "pyforward.hpp"
#include "libLSS/physics/forwards/registry.hpp"
#include "libLSS/tools/ptree_proxy.hpp"
#include "pyborg.hpp"
#include "libLSS/physics/forwards/all_models.hpp"
/**
* @brief This class adapts a Python dictionnary to a PropertyProxy usable by model factories
*
*/
class PyProperty : public LibLSS::PropertyProxy {
protected:
typedef LibLSS::Python::py::dict dict;
typedef LibLSS::Python::py::str str;
dict opts;
std::map<std::type_index, std::function<PropertyType(std::string const &)>>
getters;
template <typename T>
PropertyType _caster(std::string const &n) const {
return PropertyType(opts[str(n)].template cast<T>());
}
template <typename T>
PropertyType
_caster_with_default(std::string const &n, PropertyType v) const {
auto py_n = str(n);
if (!opts.contains(py_n))
return v;
return PropertyType(opts[py_n].cast<T>());
}
virtual PropertyType real_get(std::string const &n, std::type_index v) const {
return getters.find(v)->second(n);
}
virtual PropertyType real_get(std::string const &n, PropertyType v) const {
return boost::apply_visitor(
[&](auto t) { return PropertyType(_caster_with_default<decltype(t)>(n, v)); }, v);
};
virtual boost::optional<PropertyType>
real_get_optional(std::string const &n, std::type_index v) const {
if (opts.contains(n))
return boost::optional<PropertyType>(getters.find(v)->second(n));
return boost::optional<PropertyType>();
};
template <typename U>
inline void setup_getters(boost::variant<U>) {
getters[typeid(U)] =
std::bind(&PyProperty::_caster<U>, this, std::placeholders::_1);
}
template <typename U, typename V, typename... T>
inline void setup_getters(boost::variant<U, V, T...>) {
getters[typeid(U)] =
std::bind(&PyProperty::_caster<U>, this, std::placeholders::_1);
setup_getters(boost::variant<V, T...>());
}
public:
/**
* @brief Construct a new Py Property object
*
* @param opts_ Python dictionnary
*/
PyProperty(dict &opts_) : opts(opts_) { setup_getters(PropertyType()); }
};
#include "pyborg_doc.hpp"
#include "pyborg_doc/aquila_borg.forward.models.hpp"
void LibLSS::Python::pyForwardAll(Python::py::module m) {
using LibLSS::Python::py::dict;
m.def("newModel", [](std::string const &name, BoxModel *box, py::dict opts) {
auto factory = LibLSS::setup_forward_model(name);
return factory(MPI_Communication::instance(), *box, PyProperty(opts));
}, DOC(aquila_borg, forward, models, newModel));
m.def("listModels", []() {
auto all_models = ForwardRegistry::instance().list();
std::vector<std::string> model_names;
for (auto &m : all_models)
model_names.push_back(m.first);
return model_names;
}, DOC(aquila_borg, forward, models, listModels));
}
// ARES TAG: num_authors = 1
// ARES TAG: author(0) = Guilhem Lavaux
// ARES TAG: year(0) = 2020
// ARES TAG: email(0) = guilhem.lavaux@iap.fr

View file

@ -0,0 +1,199 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pyforward_borg.cpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include <memory>
#include <exception>
#include <cstddef>
#include <boost/format.hpp>
#include <pybind11/pybind11.h>
#include <CosmoTool/cosmopower.hpp>
#include <pybind11/numpy.h>
#include "libLSS/physics/cosmo.hpp"
#include "libLSS/tools/console.hpp"
#include "libLSS/physics/cosmo.hpp"
#include "pyborg.hpp"
#include "libLSS/mpi/generic_mpi.hpp"
#include "libLSS/tools/static_init.hpp"
#include "libLSS/physics/forward_model.hpp"
#include "libLSS/physics/hades_pt.hpp"
#include "libLSS/physics/hades_log.hpp"
#include "libLSS/physics/hermitic.hpp"
#include "libLSS/physics/forwards/borg_lpt.hpp"
#include "libLSS/physics/forwards/borg_2lpt.hpp"
#include "libLSS/physics/forwards/deprecated/borg_pm.hpp"
#include "libLSS/physics/forwards/transfer.hpp"
#include "libLSS/physics/forwards/downgrade.hpp"
#include "libLSS/physics/forwards/primordial.hpp"
#include "libLSS/physics/forwards/transfer_ehu.hpp"
#include "libLSS/physics/openmp_cic.hpp"
#include "pyfuse.hpp"
#include "libLSS/physics/modified_ngp.hpp"
#include "libLSS/physics/modified_ngp_smooth.hpp"
#include "pyforward.hpp"
//namespace py = pybind11;
using namespace pybind11::literals;
#include "pyborg_doc.hpp"
#include "pyborg_doc/aquila_borg.forward.models.hpp"
template <typename CIC = LibLSS::ClassicCloudInCell<double>>
void declareLpt(
LibLSS::Python::py::module m, std::string suffix = "",
std::string doc = "") {
using namespace LibLSS;
using namespace LibLSS::Python;
std::string name = "BorgLpt" + suffix;
py::class_<
BorgLptModel<CIC>, ParticleBasedForwardModel,
std::shared_ptr<BorgLptModel<CIC>>>(
m, name.c_str(), doc.c_str(), py::multiple_inheritance())
.def(
py::init([](BoxModel *box, BoxModel *box_out, bool rsd, int ss,
double p_factor, double ai, double af, bool light_cone,
double light_cone_boost) {
py::gil_scoped_release release;
if (box_out == nullptr)
box_out = box;
return std::make_unique<BorgLptModel<CIC>>(
MPI_Communication::instance(), *box, *box_out, rsd, ss,
p_factor, ai, af, light_cone, light_cone_boost);
}),
"box"_a, "box_out"_a = (BoxModel *)nullptr, "rsd"_a = false,
"supersampling"_a = 1, "particle_factor"_a = 1.1, "ai"_a = 0.1,
"af"_a = 1.0, "lightcone"_a = false, "lightcone_boost"_a = 1.0);
}
void LibLSS::Python::pyForwardBorg(py::module m) {
m.doc() = DOC(aquila_borg, forward, models);
py::class_<HadesLinear, BORGForwardModel, std::shared_ptr<HadesLinear>>(
m, "HadesLinear", DOC(aquila_borg, forward, models, HadesLinear))
.def(
py::init([](BoxModel *box, double ai, double af) {
py::gil_scoped_release release;
return std::make_unique<HadesLinear>(
MPI_Communication::instance(), *box, *box, ai, af);
}),
"box"_a, "ai"_a = 0.1, "af"_a = 1.0);
py::class_<HadesLog, BORGForwardModel, std::shared_ptr<HadesLog>>(
m, "HadesLog", DOC(aquila_borg, forward, models, HadesLog))
.def(
py::init([](BoxModel *box, double ai) {
py::gil_scoped_release release;
return std::make_unique<HadesLog>(
MPI_Communication::instance(), *box, ai);
}),
"box"_a, "ai"_a = 0.1);
declareLpt<>(m, "", DOC(aquila_borg, forward, models, BorgLpt));
declareLpt<OpenMPCloudInCell<double>>(
m, "OpenMP", DOC(aquila_borg, forward, models, BorgLptOpenMP));
declareLpt<ModifiedNGP<double, NGPGrid::Double>>(
m, "NGP_Double", DOC(aquila_borg, forward, models, BorgLptNGP_Double));
declareLpt<ModifiedNGP<double, NGPGrid::Quad>>(
m, "NGP_Quad", DOC(aquila_borg, forward, models, BorgLptNGP_Quad));
declareLpt<SmoothModifiedNGP<double, NGPGrid::Quad>>(
m, "SmoothNGP_Quad",
DOC(aquila_borg, forward, models, BorgLptSmoothNGP_Quad));
py::class_<
ForwardHermiticOperation, BORGForwardModel,
std::shared_ptr<ForwardHermiticOperation>>(
m, "HermiticEnforcer",
DOC(aquila_borg, forward, models, HermiticEnforcer))
.def(py::init([](BoxModel *box) {
return std::make_unique<ForwardHermiticOperation>(
MPI_Communication::instance(), *box);
}));
py::class_<
ForwardPrimordial, BORGForwardModel, std::shared_ptr<ForwardPrimordial>>(
m, "Primordial")
.def(py::init([](BoxModel *box, double a) {
py::gil_scoped_release release;
return std::make_unique<ForwardPrimordial>(
MPI_Communication::instance(), *box, a);
}));
py::class_<
ForwardEisensteinHu, BORGForwardModel,
std::shared_ptr<ForwardEisensteinHu>>(m, "EisensteinHu")
.def(py::init([](BoxModel *box) {
py::gil_scoped_release release;
return std::make_unique<ForwardEisensteinHu>(
MPI_Communication::instance(), *box);
}));
py::class_<
ForwardDowngrade, BORGForwardModel, std::shared_ptr<ForwardDowngrade>>(
m, "Downgrade")
.def(py::init([](BoxModel *box) {
py::gil_scoped_release release;
return std::make_unique<ForwardDowngrade>(
MPI_Communication::instance(), *box);
}));
py::class_<
ForwardTransfer, BORGForwardModel, std::shared_ptr<ForwardTransfer>>(
m, "Transfer", DOC(aquila_borg, forward, models, Transfer))
.def(py::init([](BoxModel *box) {
py::gil_scoped_release release;
return std::make_unique<ForwardTransfer>(
MPI_Communication::instance(), *box);
}))
.def(
"setupInverseCIC", &ForwardTransfer::setupInverseCIC,
DOC(aquila_borg, forward, models, Transfer, setupInverseCIC))
.def(
"setupSharpKcut", &ForwardTransfer::setupSharpKcut, "cut"_a,
"reversed"_a = false,
DOC(aquila_borg, forward, models, Transfer, setupSharpKcut))
.def(
"setTransfer",
[](ForwardTransfer *t, py::array_t<std::complex<double>> a) {
PyToFuseArray<std::complex<double>, 3, false> in_Tk(
a.unchecked<3>());
check_array_complex(a, t->lo_mgr);
auto tmp_c = t->lo_mgr->allocate_ptr_complex_array();
fwrap(*tmp_c) = in_Tk;
t->setTransfer(std::move(tmp_c));
},
"transfer"_a,
DOC(aquila_borg, forward, models, Transfer, setTransfer));
py::class_<
Borg2LPTModel<>, ParticleBasedForwardModel,
std::shared_ptr<Borg2LPTModel<>>>(
m, "Borg2Lpt", py::multiple_inheritance(),
DOC(aquila_borg, forward, models, Borg2Lpt))
.def(
py::init([](BoxModel *box, BoxModel *box_out, bool rsd, int ss,
double p_factor, double ai, double af, bool light_cone) {
py::gil_scoped_release release;
if (box_out == nullptr)
box_out = box;
return std::make_unique<Borg2LPTModel<>>(
MPI_Communication::instance(), *box, *box_out, rsd, ss,
p_factor, ai, af, light_cone);
}),
"box"_a, "box_out"_a = (BoxModel *)nullptr, "rsd"_a = false,
"supersampling"_a = 1, "particle_factor"_a = 1.1, "ai"_a = 0.1,
"af"_a = 1.0, "lightcone"_a = false);
}
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1,352 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pyfuse.hpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __LIBLSS_PYTHON_FUSE_ARRAY_HPP
# define __LIBLSS_PYTHON_FUSE_ARRAY_HPP
# include "libLSS/tools/fused_array.hpp"
# include "pyborg.hpp"
# include <pybind11/pybind11.h>
# include <pybind11/numpy.h>
# include "libLSS/tools/string_tools.hpp"
namespace LibLSS {
namespace Python {
template <typename T, typename py_T, size_t order, size_t Nd, bool mut>
class PyToFuseView {
public:
enum { dimensionality = order };
typedef T element;
typedef ArrayTuple_base::size_type size_type;
typedef ArrayTuple_base::index index;
typedef PyToFuseView<
T, py_T, FUSE_detail::NumDimDecrement<order>::value, Nd, mut>
subview;
py_T &array;
std::array<index, Nd> idx;
ssize_t const *bases;
size_t const *shapes;
PyToFuseView(
py_T &a, std::array<index, Nd> idx_, ssize_t const *bases_,
size_t const *shapes_)
: array(a), idx(idx_), bases(bases_), shapes(shapes_) {}
inline const size_type *shape() const { return shapes; }
inline const index *index_bases() const { return bases; }
inline subview operator[](index i) {
std::array<index, Nd> idx_new = idx;
idx_new[Nd - order] = i;
return subview(array, idx_new, bases + 1, shapes + 1);
}
};
template <typename T, typename py_T, size_t Nd>
class PyToFuseView<T, py_T, 1, Nd, false> {
public:
enum { dimensionality = 1 };
typedef T element;
typedef ArrayTuple_base::size_type size_type;
typedef ArrayTuple_base::index index;
typedef element subview;
py_T const &array;
std::array<index, Nd> idx;
ssize_t const *bases;
size_t const *shapes;
PyToFuseView(
py_T const &a, std::array<index, Nd> idx_, ssize_t const *bases_,
size_t const *shapes_)
: array(a), idx(idx_), bases(bases_), shapes(shapes_) {}
inline const size_type *shape() const { return shapes; }
inline const index *index_bases() const { return bases; }
template <size_t... Is>
static inline auto const &_unroll_call(
py_T const &a, std::array<ssize_t, Nd> const &idx,
std::index_sequence<Is...>) {
return a(idx[Is]...);
}
inline element const &operator[](ssize_t i) const {
std::array<index, Nd> idx_new = idx;
idx_new[Nd - 1] = i;
return _unroll_call(array, idx_new, std::make_index_sequence<Nd>());
}
};
template <typename T, typename py_T, size_t Nd>
class PyToFuseView<T, py_T, 1, Nd, true> {
public:
typedef T element;
typedef ArrayTuple_base::size_type size_type;
typedef ArrayTuple_base::index index;
typedef PyToFuseView<
T, py_T, FUSE_detail::NumDimDecrement<Nd>::value, Nd, true>
subview;
py_T &array;
std::array<index, Nd> idx;
ssize_t const *bases;
size_t const *shapes;
PyToFuseView(
py_T &a, std::array<index, Nd> idx_, ssize_t const *bases_,
size_t const *shapes_)
: array(a), idx(idx_), bases(bases_), shapes(shapes_) {}
inline const size_type *shape() const { return shapes; }
inline const index *index_bases() const { return bases; }
template <typename T3, size_t... Is>
static inline auto &_unroll_call(
T3 &a, std::array<ssize_t, Nd> const &idx,
std::index_sequence<Is...>) {
return a(idx[Is]...);
}
inline element const &operator[](ssize_t i) const {
std::array<index, Nd> idx_new = idx;
idx_new[Nd - 1] = i;
return _unroll_call<py_T const>(
array, idx_new, std::make_index_sequence<Nd>());
}
inline element &operator[](ssize_t i) {
std::array<index, Nd> idx_new = idx;
idx_new[Nd - 1] = i;
return _unroll_call<py_T>(
array, idx_new, std::make_index_sequence<Nd>());
}
};
template <typename T, size_t Nd, bool mut>
struct pyArrayType;
template <typename T, size_t Nd>
struct pyArrayType<T, Nd, false> {
typedef decltype(
std::declval<py::array_t<T> &>().template unchecked<Nd>()) const type;
static inline type unchecked(py::array_t<T> &a) {
return a.template unchecked<Nd>();
}
static inline T const *data(type const &a) {
assert(false);
return 0;
} //a.data(0); }
};
template <typename T, size_t Nd>
struct pyArrayType<T, Nd, true> {
typedef decltype(std::declval<py::array_t<T> &>()
.template mutable_unchecked<Nd>()) type;
static inline type unchecked(py::array_t<T> &a) {
return a.template mutable_unchecked<Nd>();
}
// This one is to fool fusewrapper.
static inline T *data(type &a) {
assert(false);
return 0;
} //a.mutable_data(0); }
};
template <typename T, size_t Nd, bool mut>
class PyToFuseArrayBase {
public:
static constexpr bool Shaped = true;
typedef T element;
typedef ArrayTuple_base::size_type size_type;
typedef ArrayTuple_base::index index;
typedef typename pyArrayType<T, Nd, mut>::type py_unchecked_t;
typedef PyToFuseView<
T, py_unchecked_t, FUSE_detail::NumDimDecrement<Nd>::value, Nd, mut>
subview;
py_unchecked_t array;
std::array<index, Nd> static_index_base;
std::array<size_type, Nd> static_shape;
PyToFuseArrayBase(py_unchecked_t a) : array(a) {
if (a.ndim() != Nd) {
throw std::runtime_error("Invalid array number of dimensions");
}
std::fill(static_index_base.begin(), static_index_base.end(), 0);
for (unsigned int i = 0; i < Nd; i++)
static_shape[i] = a.shape(i);
Console::instance().print<LOG_DEBUG>(
"Shape of PyFuse is " + LibLSS::to_string(static_shape));
}
inline const size_type *shape() const { return static_shape.data(); }
inline size_type num_elements() const { return array.size(); }
inline size_type size() const { return shape()[0]; }
inline const index *index_bases() const {
return static_index_base.data();
}
inline auto data() { return pyArrayType<T, Nd, mut>::data(array); }
};
template <typename T, bool mut>
struct maybe_add_const;
template <typename T>
struct maybe_add_const<T, false> {
typedef T const type;
};
template <typename T>
struct maybe_add_const<T, true> {
typedef T type;
};
template <typename T, size_t Nd, bool mut>
class PyToFuseArray : public PyToFuseArrayBase<T, Nd, mut> {
public:
enum { dimensionality = Nd };
typedef PyToFuseArrayBase<T, Nd, mut> super_t;
typedef PyToFuseArrayBase<T, Nd, false> ro_super_t;
typedef typename super_t::element element;
typedef typename super_t::subview subview;
typedef typename ro_super_t::subview ro_subview;
typedef typename super_t::size_type size_type;
typedef typename super_t::index index;
typedef typename maybe_add_const<T, mut>::type ret_element;
using super_t::super_t;
template <bool enabled = mut>
inline typename std::enable_if<enabled, subview>::type
operator[](index i) {
std::array<index, Nd> idx;
idx[0] = i;
return subview(
this->array, idx, this->index_bases() + 1, this->shape() + 1);
}
template <bool enabled = mut>
inline typename std::enable_if<!enabled, ro_subview>::type
operator[](index i) const {
std::array<index, Nd> idx;
idx[0] = i;
return ro_subview(
this->array, idx, this->index_bases() + 1, this->shape() + 1);
}
template <typename T2, size_t... Is>
static inline auto &_unroll_call(
T2 &a, boost::array<index, Nd> const &idx,
std::index_sequence<Is...>) {
return a(idx[Is]...);
}
inline element const &
operator()(boost::array<index, Nd> const &idx) const {
return _unroll_call(this->array, idx, std::make_index_sequence<Nd>());
}
inline ret_element &operator()(boost::array<index, Nd> const &idx) {
return _unroll_call(this->array, idx, std::make_index_sequence<Nd>());
}
};
template <typename T, bool mut>
class PyToFuseArray<T, 1, mut> : public PyToFuseArrayBase<T, 1, mut> {
public:
enum { dimensionality = 1 };
typedef PyToFuseArrayBase<T, 1, mut> super_t;
using super_t::super_t;
typedef typename super_t::element element;
typedef typename super_t::size_type size_type;
typedef typename super_t::index index;
inline element const &operator[](index i) const { return this->array(i); }
inline element &operator[](index i) { return this->array(i); }
inline element const &
operator()(boost::array<index, 1> const &idx) const {
return this->array(idx[0]);
}
inline element &operator()(boost::array<index, 1> const &idx) {
return this->array(idx[0]);
}
inline element const *begin() const { return this->array.data(0); }
inline element const *end() const {
return this->array.data(this->size());
}
};
class pythonHolder {
protected:
std::shared_ptr<void> hold;
public:
pythonHolder(std::shared_ptr<void> hold_) : hold(hold_) {}
};
template <typename T>
py::object make_shared_ptr_hold(std::shared_ptr<T> &ptr) {
return py::capsule(new pythonHolder(ptr), [](void *ptr1) {
delete ((pythonHolder *)ptr1);
});
}
template <typename T, size_t Nd>
py::array makeNumpy(
boost::multi_array_ref<T, Nd> const &x,
std::shared_ptr<void> holder = std::shared_ptr<void>()) {
std::array<ssize_t, Nd> shapes, strides;
std::copy(x.shape(), x.shape() + shapes.size(), shapes.begin());
for (int i = 0; i < Nd; i++)
strides[i] = x.strides()[i] * sizeof(T);
if (holder) {
auto hold = make_shared_ptr_hold(holder);
return py::array_t<T>(shapes, strides, x.data(), hold);
} else {
return py::array_t<T>(shapes, strides, x.data());
}
}
template <typename T, size_t Nd>
py::array makeNumpy(
boost::multi_array_ref<T, Nd> &x,
std::shared_ptr<void> holder = std::shared_ptr<void>()) {
std::array<ssize_t, Nd> shapes, strides;
std::copy(x.shape(), x.shape() + shapes.size(), shapes.begin());
for (int i = 0; i < Nd; i++)
strides[i] = x.strides()[i] * sizeof(T);
if (holder) {
auto hold = make_shared_ptr_hold(holder);
return py::array_t<T>(shapes, strides, x.data(), hold);
} else {
return py::array_t<T>(shapes, strides, x.data());
}
}
} // namespace Python
} // namespace LibLSS
#endif
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1,463 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pylikelihood.cpp
Copyright (C) 2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include "libLSS/cconfig.h"
#include <memory>
#include <exception>
#include <boost/format.hpp>
#include <pybind11/pybind11.h>
#include <pybind11/eval.h>
#include <CosmoTool/cosmopower.hpp>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include "libLSS/physics/cosmo.hpp"
#include "libLSS/tools/console.hpp"
#include "pyborg.hpp"
#include "libLSS/mpi/generic_mpi.hpp"
#include "libLSS/tools/static_init.hpp"
#include "pyfuse.hpp"
#include "libLSS/samplers/core/gridLikelihoodBase.hpp"
#include <typeindex>
#include "libLSS/mcmc/state_element.hpp"
#include "libLSS/samplers/generic/generic_hmc_likelihood.hpp"
#include "libLSS/physics/adapt_classic_to_gauss.hpp"
#include "libLSS/physics/bias/noop.hpp"
#include "libLSS/physics/bias/linear_bias.hpp"
#include "libLSS/physics/bias/power_law.hpp"
#include "libLSS/physics/bias/passthrough.hpp"
#include "libLSS/physics/likelihoods/gaussian.hpp"
#include "libLSS/physics/likelihoods/voxel_poisson.hpp"
#include "libLSS/samplers/core/types_samplers.hpp"
#include "libLSS/samplers/core/random_number.hpp"
#include "libLSS/samplers/rgen/gsl_random_number.hpp"
#include "py_mpi.hpp"
using namespace LibLSS;
namespace py = pybind11;
using namespace pybind11::literals;
PYBIND11_MAKE_OPAQUE(LikelihoodInfo);
template <typename Bias, typename Likelihood>
static void create_generic_bind(
py::module m, std::string const &name, std::string const &doc) {
py::class_<
GenericHMCLikelihood<Bias, Likelihood>, ForwardModelBasedLikelihood,
std::shared_ptr<GenericHMCLikelihood<Bias, Likelihood>>>(
m, name.c_str(), doc.c_str())
.def(py::init([](LikelihoodInfo *info) {
return new GenericHMCLikelihood<Bias, Likelihood>(*info);
}))
.def("numBiasParams", [](py::object o) { return Bias::numParams; });
}
struct basic_scalar_converter {
virtual py::object
load(StateElement *, py::handle _ = py::handle()) const = 0;
virtual void store(StateElement *, py::object) const = 0;
};
template <typename T>
struct scalar_converter : basic_scalar_converter {
static basic_scalar_converter *instance() {
static scalar_converter<T> obj;
return &obj;
}
py::object
load(StateElement *e, py::handle hold = py::handle()) const override {
return py::cast(dynamic_cast<ScalarStateElement<T> *>(e)->value);
}
void store(StateElement *e, py::object obj) const override {
dynamic_cast<ScalarStateElement<T> *>(e)->value = py::cast<T>(obj);
}
};
template <typename T>
struct array_converter : basic_scalar_converter {
static basic_scalar_converter *instance() {
static array_converter<T> obj;
return &obj;
}
py::object
load(StateElement *e, py::handle hold = py::handle()) const override {
T *array = dynamic_cast<T *>(e);
typedef typename T::ArrayType::element element;
auto ref_array = array->array; // this is a shared_ptr with refcount
std::array<ssize_t, T::ArrayType::dimensionality> shapes, strides;
std::copy(
ref_array->shape(), ref_array->shape() + shapes.size(), shapes.begin());
for (int i = 0; i < strides.size(); i++)
strides[i] = ref_array->strides()[i] * sizeof(element);
return py::array_t<element>(shapes, strides, ref_array->data(), hold);
}
void store(StateElement *e, py::object obj) const override {
throw std::runtime_error("Cannot store yet");
}
};
#include "pylikelihood_wrap.hpp"
#include "pyborg_doc.hpp"
#include "pyborg_doc/aquila_borg.likelihood.hpp"
void LibLSS::Python::pyLikelihood(py::module m) {
std::map<std::type_index, basic_scalar_converter *> converter;
m.doc() = DOC(aquila_borg, likelihood);
converter[typeid(ScalarStateElement<float>)] =
scalar_converter<float>::instance();
converter[typeid(ScalarStateElement<double>)] =
scalar_converter<double>::instance();
converter[typeid(ScalarStateElement<int>)] =
scalar_converter<int>::instance();
converter[typeid(ScalarStateElement<long>)] =
scalar_converter<long>::instance();
converter[typeid(ScalarStateElement<bool>)] =
scalar_converter<bool>::instance();
converter[typeid(ScalarStateElement<CosmologicalParameters>)] =
scalar_converter<CosmologicalParameters>::instance();
converter[typeid(ArrayType1d)] = array_converter<ArrayType1d>::instance();
converter[typeid(ArrayType)] = array_converter<ArrayType>::instance();
converter[typeid(CArrayType)] = array_converter<CArrayType>::instance();
auto ares_to_python =
[converter](std::type_index ti, StateElement *elt, py::handle h) {
auto iter = converter.find(ti);
if (iter == converter.end())
throw std::runtime_error("Unknown stored type in global state.");
return iter->second->load(elt, h);
};
auto python_to_ares =
[converter](std::type_index ti, StateElement *elt, py::object obj) {
auto iter = converter.find(ti);
if (iter == converter.end())
throw std::runtime_error("Unknown stored type in global state.");
return iter->second->store(elt, obj);
};
py::class_<MarkovState>(
m, "MarkovState", DOC(aquila_borg, likelihood, MarkovState))
.def(
py::init<>([](int seed) {
MarkovState *s = new MarkovState();
MPI_Communication *comm = MPI_Communication::instance();
if (seed == 0)
seed = 24032015;
typedef RandomNumberMPI<GSL_RandomNumber> RGenType;
auto randgen = std::make_shared<RGenType>(comm, -1);
randgen->seed(seed);
s->newElement(
"random_generator",
new RandomStateElement<RandomNumber>(randgen));
return s;
}),
"seed"_a = 0)
.def(
"__getitem__",
[ares_to_python](py::object o, std::string const &name) {
MarkovState *state = py::cast<MarkovState *>(o);
if (!state->exists(name))
throw py::key_error(name);
return ares_to_python(
state->getStoredType(name), state->get<StateElement>(name), o);
})
.def(
"__setitem__",
[python_to_ares](
MarkovState *state, std::string const &name, py::object obj) {
if (!state->exists(name))
throw py::key_error();
return python_to_ares(
state->getStoredType(name), state->get<StateElement>(name),
obj);
})
.def(
"newScalar",
[](MarkovState *state, std::string const &name, py::object o,
bool in_mcmc, char type_code) {
if (py::isinstance<py::bool_>(o)) {
state->newScalar<bool>(name, py::cast<bool>(o), in_mcmc);
} else if (py::isinstance<py::float_>(o)) {
state->newScalar<double>(name, py::cast<double>(o), in_mcmc);
} else if (py::isinstance<py::int_>(o)) {
if (type_code == 'L')
state->newScalar<long>(name, py::cast<long>(o), in_mcmc);
else if (type_code == ' ')
state->newScalar<int>(name, py::cast<int>(o), in_mcmc);
else
error_helper<ErrorParams>("Unsupported type code for int");
} else if (py::isinstance<CosmologicalParameters>(o)) {
state->newScalar<CosmologicalParameters>(
name, py::cast<CosmologicalParameters>(o), in_mcmc);
} else {
error_helper<ErrorParams>("Unsupported scalar type");
}
},
"name"_a, "object"_a, "in_mcmc"_a = false, "type_code"_a = ' ')
.def(
"newArray1d",
[](MarkovState *state, std::string const &name, size_t N,
bool in_mcmc) {
if (state->exists(name))
throw py::key_error();
state->newElement(
name, new ArrayType1d(boost::extents[N]), in_mcmc);
},
"name"_a, "N"_a, "in_mcmc"_a = false,
DOC(aquila_borg, likelihood, MarkovState, newArray1d))
.def(
"newForwardModel",
[](MarkovState *state, std::string const &name,
std::shared_ptr<BORGForwardModel> model) {
if (state->exists(name))
throw py::key_error();
state->newElement(
name, new SharedObjectStateElement<BORGForwardModel>(model),
false);
},
DOC(aquila_borg, likelihood, MarkovState, newForwardModel))
.def(
"newArray3d",
[](MarkovState *state, std::string const &name, size_t N0, size_t N1,
size_t N2, bool in_mcmc) {
if (state->exists(name))
throw py::key_error();
state
->newElement(
name, new ArrayType(boost::extents[N0][N1][N2]), in_mcmc)
->setRealDims(ArrayDimension(N0, N1, N2));
},
"name"_a, "N0"_a, "N1"_a, "N2"_a, "in_mcmc"_a = false,
DOC(aquila_borg, likelihood, MarkovState, newArray3d))
.def(
"newArray3d_slab",
[](MarkovState *state, std::string const &name,
std::array<size_t, 6> slab, std::array<size_t, 3> real_size,
bool in_mcmc) {
typedef boost::multi_array_types::extent_range e_range;
if (state->exists(name))
throw py::key_error();
size_t startN0, localN0, startN1, localN1, startN2, localN2, N0, N1,
N2;
startN0 = slab[0];
localN0 = slab[1];
startN1 = slab[2];
localN1 = slab[3];
startN2 = slab[4];
localN2 = slab[5];
N0 = real_size[0];
N1 = real_size[1];
N2 = real_size[2];
state
->newElement(
name,
new ArrayType(
boost::extents[e_range(startN0, startN0 + localN0)]
[e_range(startN1, startN1 + localN1)]
[e_range(startN2, startN2 + localN2)]),
in_mcmc)
->setRealDims(ArrayDimension(N0, N1, N2));
},
"name"_a, "slab"_a, "real_size"_a, "in_mcmc"_a = false,
DOC(aquila_borg, likelihood, MarkovState, newArray3d_slab));
py::class_<
GridDensityLikelihoodBase<3>,
std::shared_ptr<GridDensityLikelihoodBase<3>>>(
m, "Likelihood3d", DOC(aquila_borg, likelihood, Likelihood3d))
.def(
"gradientLikelihood",
[](GridDensityLikelihoodBase<3> *likelihood,
py::array_t<
std::complex<double>,
py::array::c_style | py::array::forcecast>
s_hat) {
auto impl_s_hat = s_hat.unchecked<3>();
py::gil_scoped_release release;
// Due to an incorrect API in likelihood we have to const away
// the pointer, though we only require a const access.
boost::multi_array_ref<std::complex<double>, 3> cpp_s_hat(
const_cast<std::complex<double> *>(impl_s_hat.data(0, 0, 0)),
boost::extents[impl_s_hat.shape(0)][impl_s_hat.shape(1)]
[impl_s_hat.shape(2)]);
auto u_gradient =
std::make_shared<LibLSS::U_Array<std::complex<double>, 3>>(
boost::extents[impl_s_hat.shape(0)][impl_s_hat.shape(1)]
[impl_s_hat.shape(2)]);
likelihood->gradientLikelihood(cpp_s_hat, *u_gradient);
return Python::makeNumpy(u_gradient->get_array(), u_gradient);
})
.def(
"logLikelihood",
[](GridDensityLikelihoodBase<3> *likelihood,
py::array_t<
std::complex<double>,
py::array::c_style | py::array::forcecast>
s_hat) {
auto impl_s_hat = s_hat.unchecked<3>();
py::gil_scoped_release release;
auto mgr = likelihood->getManager();
size_t startN0 = mgr->startN0;
size_t localN0 = mgr->localN0;
// Check the array has correct size
if (impl_s_hat.shape(0) != mgr->localN0 ||
impl_s_hat.shape(1) != mgr->N1 ||
impl_s_hat.shape(2) != mgr->N2_HC) {
throw std::invalid_argument("The array has incorrect shape");
}
typedef boost::multi_array_types::extent_range e_range;
// Due to an incorrect API in likelihood we have to const away
// the pointer, though we only require a const access.
boost::multi_array_ref<std::complex<double>, 3> cpp_s_hat(
const_cast<std::complex<double> *>(impl_s_hat.data(0, 0, 0)),
boost::extents[e_range(startN0, startN0+localN0)][mgr->N1][mgr->N2_HC]);
return likelihood->logLikelihood(cpp_s_hat);
})
.def(
"generateMockData",
[](GridDensityLikelihoodBase<3> *likelihood,
py::array_t<
std::complex<double>,
py::array::c_style | py::array::forcecast>
s_hat,
MarkovState *state) {
auto impl_s_hat = s_hat.unchecked<3>();
py::gil_scoped_release release;
// Due to an incorrect API in likelihood we have to const away
// the pointer, though we only require a const access.
boost::multi_array_ref<std::complex<double>, 3> cpp_s_hat(
const_cast<std::complex<double> *>(impl_s_hat.data(0, 0, 0)),
boost::extents[impl_s_hat.shape(0)][impl_s_hat.shape(1)]
[impl_s_hat.shape(2)]);
likelihood->generateMockData(cpp_s_hat, *state);
})
.def(
"updateMetaParameters",
[](GridDensityLikelihoodBase<3> *likelihood, MarkovState *state) {
likelihood->updateMetaParameters(*state);
})
.def(
"initializeLikelihood",
[](GridDensityLikelihoodBase<3> *likelihood, MarkovState *state) {
likelihood->initializeLikelihood(*state);
})
.def(
"getCommunicator",
[](GridDensityLikelihoodBase<3> *likelihood) -> py::object {
if (!mpi4py_available)
return py::none();
return makePythonMPI(likelihood->getManager()->getComm());
});
py::class_<
ForwardModelBasedLikelihood, GridDensityLikelihoodBase<3>,
std::shared_ptr<ForwardModelBasedLikelihood>>(
m, "ForwardModelLikelihood3d",
DOC(aquila_borg, likelihood, ForwardModelLikelihood3d))
.def(
"getForwardModel", &ForwardModelBasedLikelihood::getForwardModel,
DOC(aquila_borg, likelihood, ForwardModelLikelihood3d,
getForwardModel));
py::class_<
BasePyLikelihood, ForwardModelBasedLikelihood, PyLikelihood,
std::shared_ptr<BasePyLikelihood>>(
m, "BaseLikelihood", DOC(aquila_borg, likelihood, BaseLikelihood))
.def(py::init<>([](std::shared_ptr<BORGForwardModel> fwd,
py::array_t<size_t> N, py::array_t<double> L) {
auto v = new PyLikelihood(fwd, N, L);
return v;
}));
py::class_<LikelihoodInfo, std::shared_ptr<LikelihoodInfo>>(
m, "LikelihoodInfo", DOC(aquila_borg, likelihood, LikelihoodInfo))
.def(
py::init<>([]() {
LikelihoodInfo *info = new LikelihoodInfo();
(*info)[Likelihood::MPI] = MPI_Communication::instance();
return info;
}),
"Construct an empty LikelihoodInfo object")
.def(
"items",
[](LikelihoodInfo *info) {
std::vector<std::string> names;
for (auto &x : *info) {
names.push_back(x.first);
}
return names;
},
"Returns:\n list(str): list of strings to give the name of each "
"entry in the dictionnary")
.def(
"__getitem__",
[](LikelihoodInfo *info, std::string const &name) {
auto iter = info->find(name);
if (iter == info->end()) {
throw py::key_error(name);
}
return any_to_python(iter->second);
})
.def(
"__setitem__",
[](LikelihoodInfo *info, std::string const &name, py::object o) {
(*info)[name] = python_to_any(o);
});
create_generic_bind<AdaptBias_Gauss<bias::Passthrough>, GaussianLikelihood>(
m, "GaussianPassthrough",
DOC(aquila_borg, likelihood, GaussianPassthrough));
create_generic_bind<bias::Passthrough, VoxelPoissonLikelihood>(
m, "PoissonPassthrough",
DOC(aquila_borg, likelihood, PoissonPassthrough));
create_generic_bind<AdaptBias_Gauss<bias::LinearBias>, GaussianLikelihood>(
m, "GaussianLinear", DOC(aquila_borg, likelihood, GaussianLinear));
create_generic_bind<bias::PowerLaw, VoxelPoissonLikelihood>(
m, "PoissonPowerLaw", DOC(aquila_borg, likelihood, PoissonPowerLaw));
}
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2020

View file

@ -0,0 +1,169 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pylikelihood_wrap.hpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
// We implement here the thin wrap to be able to call likelihood defined in python.
// The overloading call has to happen explicitly.
// This is the base class first.
class BasePyLikelihood : public ForwardModelBasedLikelihood {
private:
template <typename G, typename T>
static inline G _to_grid(py::array_t<T> a) {
G g;
auto real_a = a.template unchecked<1>();
if (real_a.shape(0) != g.size()) {
throw std::runtime_error("Invalid number of dimensions");
}
for (int i = 0; i < g.size(); i++) {
g[i] = real_a.data(0)[i];
}
return g;
}
public:
// We delete all default constructors to avoid avoid any mistakes.
BasePyLikelihood(BasePyLikelihood &&other) = delete;
BasePyLikelihood(BasePyLikelihood const &other) = delete;
BasePyLikelihood() = delete;
// Setup a general constructor to create the appropriate internal structure
// for a cube with mesh size N and side length L.
BasePyLikelihood(py::array_t<size_t> N, py::array_t<double> L)
: ForwardModelBasedLikelihood(
MPI_Communication::instance(), _to_grid<GridSizes>(N),
_to_grid<GridLengths>(L)) {}
};
// This is the thin wrapper class.
class PyLikelihood : public BasePyLikelihood {
public:
std::shared_ptr<BORGForwardModel> base_fwd;
// Make a constructor that set aside the forward model inside the
// likelihood object for later use.
PyLikelihood(
std::shared_ptr<BORGForwardModel> fwd, py::array_t<size_t> N,
py::array_t<double> L)
: BasePyLikelihood(N, L), base_fwd(fwd) {}
std::shared_ptr<BORGForwardModel> getForwardModel() override {
return base_fwd;
}
// All the following functions are wrappers that follow the same
// basic schema.
void gradientLikelihood(
ArrayRef const &parameters, ArrayRef &gradient_parameters,
bool accumulate = false, double scaling = 1.0) override {
py::gil_scoped_acquire acquire;
py::object py_params = Python::makeNumpy(parameters);
py::function overload = py::get_overload(
static_cast<const BasePyLikelihood *>(this), "gradientLikelihoodReal");
if (overload) {
py::array_t<double> o = overload(py_params);
Python::PyToFuseArray<double, 3, false> boosted_o(o.unchecked<3>());
if (accumulate)
fwrap(gradient_parameters) =
fwrap(gradient_parameters) + fwrap(boosted_o) * scaling;
else
fwrap(gradient_parameters) = fwrap(boosted_o) * scaling;
return;
}
py::pybind11_fail("Tried to call a pure virtual function "
"BasePyLikelihood::gradientLikelihoodReal");
}
void gradientLikelihood(
CArrayRef const &parameters, CArrayRef &gradient_parameters,
bool accumulate = false, double scaling = 1.0) override {
py::gil_scoped_acquire acquire;
py::object py_params = Python::makeNumpy(parameters);
py::function overload = py::get_overload(
static_cast<const BasePyLikelihood *>(this),
"gradientLikelihoodComplex");
if (overload) {
py::array_t<std::complex<double>> o = overload(py_params);
Python::PyToFuseArray<std::complex<double>, 3, false> boosted_o(
o.unchecked<3>());
typedef boost::multi_array_types::index_range i_range;
size_t s0 = mgr->startN0;
auto local_grad = gradient_parameters[boost::indices[i_range(
s0, s0 + mgr->localN0)][i_range(0, mgr->N1)][i_range(0, mgr->N2_HC)]];
if (accumulate)
fwrap(local_grad) = fwrap(local_grad) + fwrap(boosted_o) * scaling;
else
fwrap(local_grad) = fwrap(boosted_o) * scaling;
return;
}
py::pybind11_fail("Tried to call a pure virtual function "
"BasePyLikelihood::gradientLikelihoodComplex");
}
double logLikelihood(
ArrayRef const &parameters, bool gradientIsNext = false) override {
py::gil_scoped_acquire acquire;
py::object py_params = Python::makeNumpy(parameters);
PYBIND11_OVERLOAD_PURE(
double, BasePyLikelihood, logLikelihoodReal, py_params, gradientIsNext);
}
double logLikelihood(
CArrayRef const &parameters, bool gradientIsNext = false) override {
py::gil_scoped_acquire acquire;
py::object py_params = Python::makeNumpy(parameters);
PYBIND11_OVERLOAD_PURE(
double, BasePyLikelihood, logLikelihoodComplex, py_params,
gradientIsNext);
}
void initializeLikelihood(MarkovState &state) override {
PYBIND11_OVERLOAD_PURE(
void, BasePyLikelihood, initializeLikelihood, &state);
}
void updateMetaParameters(MarkovState &state) override {
PYBIND11_OVERLOAD_PURE(
void, BasePyLikelihood, updateMetaParameters, &state);
}
void setupDefaultParameters(MarkovState &state, int catalog) override {
PYBIND11_OVERLOAD_PURE(
void, BasePyLikelihood, setupDefaultParameters, &state);
}
void updateCosmology(CosmologicalParameters const &params) override {
PYBIND11_OVERLOAD_PURE(void, BasePyLikelihood, updateCosmology, &params);
}
void commitAuxiliaryFields(MarkovState &state) override {
PYBIND11_OVERLOAD(void, BasePyLikelihood, commitAuxiliaryFields, state);
}
void
generateMockData(CArrayRef const &parameters, MarkovState &state) override {
py::gil_scoped_acquire acquire;
{
py::object py_params = Python::makeNumpy(parameters);
PYBIND11_OVERLOAD_PURE(
void, BasePyLikelihood, generateMockData, py_params, &state);
}
}
};

View file

@ -0,0 +1,286 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pysamplers.cpp
Copyright (C) 2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include "libLSS/cconfig.h"
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <typeindex>
#include <memory>
#include <boost/format.hpp>
#include "libLSS/tools/console.hpp"
#include "libLSS/mpi/generic_mpi.hpp"
#include "libLSS/tools/static_init.hpp"
#include "libLSS/samplers/rgen/slice_sweep.hpp"
#include "pyfuse.hpp"
#include "pyborg.hpp"
#include "py_mpi.hpp"
#include "libLSS/mcmc/global_state.hpp"
#include "libLSS/samplers/core/markov.hpp"
#include "libLSS/samplers/generic/generic_hmc_likelihood.hpp"
#include "libLSS/samplers/generic/generic_sigma8_second.hpp"
#include "libLSS/samplers/rgen/hmc/hmc_density_sampler.hpp"
#include "libLSS/samplers/altair/altair_meta_sampler.hpp"
#include "libLSS/samplers/bias_model_params.hpp"
#include "libLSS/samplers/model_params.hpp"
using namespace LibLSS;
namespace py = pybind11;
using namespace py::literals;
PYBIND11_MAKE_OPAQUE(LikelihoodInfo);
class PythonGenericBiasSampler : public MarkovSampler {
protected:
MPI_Communication *comm;
std::shared_ptr<AbstractGenericHMCLikelihood> likelihood;
void initialize(MarkovState &state) override;
void restore(MarkovState &state) override;
public:
PythonGenericBiasSampler(
MPI_Communication *comm_,
std::shared_ptr<AbstractGenericHMCLikelihood> likelihood_)
: comm(comm_), likelihood(likelihood_) {}
void sample(MarkovState &state) override;
};
class PyBaseSampler : public MarkovSampler {
using MarkovSampler::MarkovSampler;
};
class PyWrapSampler : public PyBaseSampler {
public:
void initialize(MarkovState &state) override {
PYBIND11_OVERLOAD_PURE(void, PyBaseSampler, initialize, &state);
}
void restore(MarkovState &state) override {
PYBIND11_OVERLOAD_PURE(void, PyBaseSampler, restore, &state);
}
public:
using PyBaseSampler::PyBaseSampler;
void sample(MarkovState &state) override {
PYBIND11_OVERLOAD_PURE(void, PyBaseSampler, sample, &state);
}
};
void PythonGenericBiasSampler::initialize(MarkovState &state) {}
void PythonGenericBiasSampler::restore(MarkovState &state) {}
void PythonGenericBiasSampler::sample(MarkovState &state) {
using boost::format;
typedef ArrayType1d::ArrayType BiasParamArray;
LIBLSS_AUTO_DEBUG_CONTEXT(ctx);
long Ncat = state.getScalar<long>("NCAT");
auto &rgen = state.get<RandomGen>("random_generator")->get();
for (int c = 0; c < Ncat; c++) {
double &nmean =
state.template getScalar<double>(format("galaxy_nmean_%d") % c);
BiasParamArray &bias_params =
*state.template get<ArrayType1d>(format("galaxy_bias_%d") % c)->array;
boost::multi_array<double, 1> current_biases = bias_params;
if (!likelihood->nmeanIsBias()) {
nmean = slice_sweep_double(
comm, rgen,
[&current_biases, c, this](double x) {
return likelihood->logLikelihoodBias(c, x, current_biases);
},
nmean, 0.1);
}
for (int p = 0; p < likelihood->getNumberOfBiasParameters(); p++) {
bias_params[p] = slice_sweep_double(
comm, rgen,
[&current_biases, c, this, nmean, p](double x) {
current_biases[p] = x;
return likelihood->logLikelihoodBias(c, nmean, current_biases);
},
bias_params[p], 0.1);
}
}
}
#include "pyborg_doc.hpp"
#include "pyborg_doc/aquila_borg.samplers.hpp"
void LibLSS::Python::pySamplers(py::module m) {
m.doc() = DOC(aquila_borg, samplers);
py::class_<MarkovSampler, std::shared_ptr<MarkovSampler>>(m, "MarkovSampler")
.def("sample", &MarkovSampler::sample, py::call_guard<py::gil_scoped_release>());
py::class_<
PyBaseSampler, MarkovSampler, PyWrapSampler,
std::shared_ptr<PyBaseSampler>>(
m, "PyBaseSampler", DOC(aquila_borg, samplers, PyBaseSampler))
.def(py::init<>());
m.def(
"slice_sampler",
[](MarkovState *state, py::object callback, double previous_value,
double step) {
auto &rgen = state->get<RandomGen>("random_generator")->get();
return slice_sweep(
rgen,
[&callback](double x) { return py::cast<double>(callback(x)); },
previous_value, step);
},
"state"_a, "callback"_a, "previous_value"_a, "step"_a,
DOC(aquila_borg, samplers, slice_sampler));
m.def(
"mpi_slice_sampler",
[](MarkovState *state, py::object callback, double previous_value,
double step, py::object mpi) {
auto &rgen = state->get<RandomGen>("random_generator")->get();
if (mpi.is_none()) {
auto comm = MPI_Communication::instance();
return slice_sweep(
comm, rgen,
[&callback](double x) { return py::cast<double>(callback(x)); },
previous_value, step);
} else {
auto comm = Python::makeMPIFromPython(mpi);
return slice_sweep(
comm.get(), rgen,
[&callback](double x) { return py::cast<double>(callback(x)); },
previous_value, step);
}
},
"state"_a, "callback"_a, "previous_value"_a, "step"_a,
"mpi"_a = py::none(), DOC(aquila_borg, samplers, slice_sampler));
py::class_<
PythonGenericBiasSampler, MarkovSampler,
std::shared_ptr<PythonGenericBiasSampler>>(
m, "GenericBiasSampler", DOC(aquila_borg, samplers, GenericBiasSampler))
.def(
py::init([](std::shared_ptr<GridDensityLikelihoodBase<3>> model) {
auto abstract_likelihood =
std::dynamic_pointer_cast<AbstractGenericHMCLikelihood>(model);
if (!abstract_likelihood) {
throw std::invalid_argument(
"Likelihood must be of the generic class.");
}
return new PythonGenericBiasSampler(
MPI_Communication::instance(), abstract_likelihood);
}),
"model"_a);
py::class_<
BiasModelParamsSampler, MarkovSampler,
std::shared_ptr<BiasModelParamsSampler>>(
m, "BiasModelParamsSampler",
DOC(aquila_borg, samplers, BiasModelParamsSampler))
.def(
py::init([](std::shared_ptr<GridDensityLikelihoodBase<3>> likelihood,
std::shared_ptr<BORGForwardModel> model, int numBias,
std::set<int> frozen, std::string const &prefix,
py::object limiter, py::object unlimiter) {
auto sampler = new BiasModelParamsSampler(
MPI_Communication::instance(), likelihood, model, numBias,
prefix);
sampler->freezeSet(frozen);
sampler->setLimiterHooks(
[limiter]() {
py::gil_scoped_acquire acquire;
if (!limiter.is_none())
limiter();
},
[unlimiter]() {
py::gil_scoped_acquire acquire;
if (!unlimiter.is_none())
unlimiter();
});
return sampler;
}),
"likelihood"_a, "model"_a, "numBias"_a, "frozen"_a = std::set<int>(),
"prefix"_a = "", "limiter"_a = py::none(),
"unlimiter"_a = py::none());
py::class_<
HMCDensitySampler, MarkovSampler, std::shared_ptr<HMCDensitySampler>>(
m, "HMCDensitySampler", DOC(aquila_borg, samplers, HMCDensitySampler))
.def(
py::init([](std::shared_ptr<GridDensityLikelihoodBase<3>> likelihood,
double k_max, std::string prefix) {
return new HMCDensitySampler(
MPI_Communication::instance(), likelihood, k_max, prefix);
}),
"likelihood"_a, "k_max"_a = 1000, "prefix"_a = "");
py::class_<
GenericSigma8SecondVariantSampler, MarkovSampler,
std::shared_ptr<GenericSigma8SecondVariantSampler>>(
m, "Sigma8Sampler", DOC(aquila_borg, samplers, Sigma8Sampler))
.def(
py::init([](std::shared_ptr<GridDensityLikelihoodBase<3>> likelihood,
std::shared_ptr<LikelihoodInfo> info) {
return new GenericSigma8SecondVariantSampler(
MPI_Communication::instance(), likelihood, *info);
}),
"likelihood"_a, "likelihood_info"_a);
py::class_<
ModelParamsSampler, MarkovSampler, std::shared_ptr<ModelParamsSampler>>(
m, "ModelParamsSampler", DOC(aquila_borg, samplers, ModelParamsSampler))
.def(
py::init([](std::string prefix,
std::vector<std::string> const &params,
std::shared_ptr<GridDensityLikelihoodBase<3>> likelihood_,
std::shared_ptr<BORGForwardModel> model_,
ModelDictionnary init) {
return new ModelParamsSampler(
MPI_Communication::instance(), prefix, params, likelihood_,
model_, init);
}),
"prefix"_a, "params"_a, "likelihood"_a, "model"_a, "init_values"_a);
py::class_<
AltairMetaSampler, MarkovSampler, std::shared_ptr<AltairMetaSampler>>(
m, "AltairMetaSampler", DOC(aquila_borg, samplers, AltairMetaSampler))
.def(
py::init([](std::shared_ptr<GridDensityLikelihoodBase<3>> likelihood,
std::shared_ptr<BORGForwardModel> model,
CosmologicalParameters bound_min,
CosmologicalParameters bound_max, double slice_factor, py::object limiter, py::object unlimiter) {
auto sampler = new AltairMetaSampler(
MPI_Communication::instance(), likelihood, model, bound_min,
bound_max, slice_factor);
sampler->setLimiter(
[limiter]() {
py::gil_scoped_acquire acquire;
if (!limiter.is_none())
limiter();
});
sampler->setUnlimiter(
[unlimiter]() {
py::gil_scoped_acquire acquire;
if (!unlimiter.is_none())
unlimiter();
});
return sampler;
}),
"likelihood"_a, "model"_a, "bound_min"_a, "bound_max"_a, "slice_factor"_a = 0.01, "limiter"_a = py::none(), "unlimiter"_a = py::none());
}
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: year(0) = 2020
// ARES TAG: email(0) = guilhem.lavaux@iap.fr

View file

@ -0,0 +1,199 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pyvelocity.cpp
Copyright (C) 2019-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include <memory>
#include <exception>
#include <boost/format.hpp>
#include <pybind11/pybind11.h>
#include <CosmoTool/cosmopower.hpp>
#include <pybind11/numpy.h>
#include "libLSS/physics/cosmo.hpp"
#include "libLSS/tools/console.hpp"
#include "libLSS/physics/cosmo.hpp"
#include "pyborg.hpp"
#include "libLSS/mpi/generic_mpi.hpp"
#include "libLSS/tools/static_init.hpp"
#include "libLSS/physics/forward_model.hpp"
#include "pyforward.hpp"
#include "pyfuse.hpp"
#include "pyvelocity.hpp"
#include "libLSS/physics/chain_forward_model.hpp"
namespace py = pybind11;
using namespace pybind11::literals;
using namespace LibLSS;
#include "pyborg_doc.hpp"
#include "pyborg_doc/aquila_borg.forward.velocity.hpp"
#include "pyborg_doc/aquila_borg.forward.velocity.VelocityBase.hpp"
void LibLSS::Python::pyVelocity(py::module m) {
m.doc() = DOC(aquila_borg, forward, velocity);
py::class_<VelocityModel::Base, std::shared_ptr<VelocityModel::Base>>(
m, "VelocityBase", DOC(aquila_borg, forward, velocity, VelocityBase))
.def(
"getOutputBox",
[](VelocityModel::Base *vmodel) {
BoxModel *box = new BoxModel;
*box = vmodel->getOutputBox();
return box;
},
DOC(aquila_borg, forward, velocity, VelocityBase, getOutputBox))
.def(
"computeAdjointModel",
[](VelocityModel::Base *vmodel,
py::array_t<double, py::array::c_style | py::array::forcecast>
ag) {
auto input_ag = ag.unchecked<4>();
std::array<ssize_t, 6> local_ext;
typedef boost::multi_array_types::extent_range range;
vmodel->queryLocalExtents(local_ext);
// We have to copy the numpy because of no guarantee of
VelocityModel::Base::arrayVelocityField_const_t cpp_ag(
input_ag.data(0, 0, 0, 0),
boost::extents[3][range(local_ext[0], local_ext[1])]
[range(local_ext[2], local_ext[3])]
[range(local_ext[4], local_ext[5])]);
vmodel->computeAdjointModel_array(cpp_ag);
},
"ag"_a,
DOC(aquila_borg, forward, velocity, VelocityBase, computeAdjointModel))
.def(
"getVelocityField",
[](VelocityModel::Base *vmodel) {
typedef boost::multi_array_types::extent_range range;
py::array_t<double> velocity;
std::array<ssize_t, 6> local_ext;
vmodel->queryLocalExtents(local_ext);
size_t lengths[3] = {
size_t(local_ext[1] - local_ext[0]),
size_t(local_ext[3] - local_ext[2]),
size_t(local_ext[5] - local_ext[4])};
velocity.resize({size_t(3), lengths[2], lengths[1], lengths[0]});
//boost::multi_array_ref<double, 4> arrayVelocityField_t;
auto out = velocity.mutable_unchecked<4>();
VelocityModel::Base::arrayVelocityField_t vel_out(
out.mutable_data(0, 0, 0, 0),
boost::extents[3][range(local_ext[0], local_ext[1])]
[range(local_ext[2], local_ext[3])]
[range(local_ext[4], local_ext[5])]);
{
py::gil_scoped_release release;
vmodel->getVelocityField(vel_out);
}
return velocity;
},
DOC(aquila_borg, forward, velocity, VelocityBase, getVelocityField));
py::class_<
VelocityModel::ParticleBasedModel, VelocityModel::Base,
std::shared_ptr<VelocityModel::ParticleBasedModel>>(
m, "ParticleBasedModel",
DOC(aquila_borg, forward, velocity, ParticleBasedModel));
py::class_<
VelocityModel::CICModel, VelocityModel::ParticleBasedModel,
std::shared_ptr<VelocityModel::CICModel>>(
m, "CICModel", DOC(aquila_borg, forward, velocity, CICModel))
.def(py::init([](BoxModel *box, std::shared_ptr<BORGForwardModel> model) {
auto pmodel =
std::dynamic_pointer_cast<ParticleBasedForwardModel>(model);
if (!pmodel) {
throw std::invalid_argument("Provided model is not particle based");
}
return VelocityModel::CICModel(*box, pmodel);
}));
py::class_<
VelocityModel::SICModel, VelocityModel::ParticleBasedModel,
std::shared_ptr<VelocityModel::SICModel>>(
m, "SICModel", DOC(aquila_borg, forward, velocity, SICModel))
.def(
py::init([](BoxModel *box, std::shared_ptr<BORGForwardModel> model) {
auto pmodel =
std::dynamic_pointer_cast<ParticleBasedForwardModel>(model);
if (!pmodel) {
throw std::invalid_argument(
"Provided model is not particle based");
}
return VelocityModel::SICModel(*box, pmodel);
}),
"box_model"_a, "base_forward_model"_a,
DOC(aquila_borg, forward, velocity, SICModel, __init__));
m.def(
"computeSICVelocityfield",
[](py::array_t<size_t, py::array::c_style> identifiers,
py::array_t<double, py::array::c_style> positions,
py::array_t<double, py::array::c_style> velocities, double L, size_t N,
size_t Ng) {
py::array_t<double> velocity, density;
velocity.resize({size_t(3), Ng, Ng, Ng});
density.resize({Ng, Ng, Ng});
auto velocity_impl = velocity.mutable_unchecked<4>();
auto density_impl = density.mutable_unchecked<3>();
boost::multi_array_ref<double, 3> den_out(
density_impl.mutable_data(0, 0, 0), boost::extents[Ng][Ng][Ng]);
VelocityModel::Base::arrayVelocityField_t vel_out(
velocity_impl.mutable_data(0, 0, 0, 0),
boost::extents[3][Ng][Ng][Ng]);
int Np = identifiers.shape(0);
if (positions.shape(0) != Np || velocities.shape(0) != Np) {
throw std::invalid_argument(
"Invalid size of the array of positions or "
"velocities. Must conform to identifiers.");
}
if (positions.shape(1) != 3 || velocities.shape(1) != 3) {
throw std::invalid_argument(
"Position and velocity arrays must have a shape Nx3");
}
auto identifiers_impl = identifiers.mutable_unchecked<1>();
auto positions_impl = positions.mutable_unchecked<2>();
auto velocities_impl = velocities.mutable_unchecked<2>();
DM_Sheet::arrayID_t ids(
identifiers_impl.mutable_data(0), boost::extents[Np]);
DM_Sheet::arrayPosition_t pos(
positions_impl.mutable_data(0, 0), boost::extents[Np][3]);
DM_Sheet::arrayPosition_t vels(
velocities_impl.mutable_data(0, 0), boost::extents[Np][3]);
{
py::gil_scoped_release release;
computeSICVelocityField(ids, pos, vels, L, N, Ng, den_out, vel_out);
}
py::tuple ret(2);
ret[0] = density;
ret[1] = velocity;
return ret;
},
"ids"_a, "positions"_a, "velocities"_a, "L"_a, "N"_a, "Ng"_a);
}
// ARES TAG: num_authors = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019-2020

View file

@ -0,0 +1,27 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/python/pyvelocity.hpp
Copyright (C) 2019 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __LIBLSS_PYTHON_FORWARD_VELOCITY_HPP
# define __LIBLSS_PYTHON_FORWARD_VELOCITY_HPP
# pragma once
# include <memory>
# include <exception>
# include <boost/format.hpp>
# include "libLSS/physics/forward_model.hpp"
# include "libLSS/physics/velocity/velocity.hpp"
# include "libLSS/physics/velocity/velocity_cic.hpp"
# include "libLSS/physics/velocity/velocity_sic.hpp"
namespace LibLSS {} // namespace LibLSS
#endif
// ARES TAG: authors_num = 1
// ARES TAG: name(0) = Guilhem Lavaux
// ARES TAG: email(0) = guilhem.lavaux@iap.fr
// ARES TAG: year(0) = 2019

View file

@ -0,0 +1,44 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/src/hades_python.cpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#define SAMPLER_DATA_INIT "ares_init.hpp"
#define SAMPLER_BUNDLE "python_bundle.hpp"
#define SAMPLER_BUNDLE_INIT "python_bundle_init.hpp"
#define SAMPLER_NAME "HADES-PYTHON3"
#define SAMPLER_MOCK_GENERATOR "python_mock_gen.hpp"
#include "common/sampler_base.cpp"
#include "libLSS/tools/color_mod.hpp"
using namespace LibLSS::Color;
namespace {
void init_splash() {
static std::vector<std::string> splash_str = {
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~",
" PPPPPPP YY YY TTTTTT HH HH ooo NN N",
" PPP PP YY YY TT HH HH oO Oo NNn N",
" PP PPP YYY TT HH HH oOO OOo N Nn N",
" PPPPPP YYY TT HHHHHHH Oo oO N Nn N",
" PPP iYi ll HH HH oO Oo N nN nN",
" PP Y ii hh hh OO OO N Nn n",
" P Y ii hh hh oooo n NNN",
" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~",
" This is HADES-Python"
};
Console::instance().print<LOG_STD>(splash_str);
}
void close_splash() {}
RegisterStaticInit reg_splash(init_splash, close_splash, 12);
} // namespace

View file

@ -0,0 +1,112 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/src/python_bundle.hpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#pragma once
#ifndef _HADES_PYTHON_BUNDLE_HPP
# define _HADES_PYTHON_BUNDLE_HPP
# include "libLSS/samplers/core/powerspec_tools.hpp"
# include "libLSS/samplers/ares/synthetic_selection.hpp"
# include "libLSS/samplers/rgen/density_sampler.hpp"
# include "libLSS/physics/forward_model.hpp"
# include "libLSS/samplers/rgen/hmc/hmc_density_sampler.hpp"
# include "libLSS/samplers/core/main_loop.hpp"
# include <boost/algorithm/string.hpp>
# include <pybind11/pybind11.h>
#define ARES_EXTRA_CATCH_CLAUSE \
catch (pybind11::error_already_set const& e) { \
Console::instance().print<LOG_ERROR>(LibLSS::tokenize(e.what(),"\n")); \
}
namespace LibLSS {
namespace {
HMCOption::IntegratorScheme get_Scheme(const std::string &s) {
std::string scheme = boost::to_upper_copy<std::string>(s);
using namespace HMCOption;
if (scheme == "SI_2A" || scheme == "LEAP_FROG") {
return SI_2A;
} else if (scheme == "SI_2B") {
return SI_2B;
} else if (scheme == "SI_2C") {
return SI_2C;
} else if (scheme == "SI_3A") {
return SI_3A;
} else if (scheme == "SI_4B") {
return SI_4B;
} else if (scheme == "SI_4C") {
return SI_4C;
} else if (scheme == "SI_4D") {
return SI_4D;
} else if (scheme == "SI_6A") {
return SI_6A;
} else {
error_helper<ErrorBadState>(
boost::format("Invalid integration scheme %s") % scheme);
}
}
} // namespace
class DummyPowerSpectrum : public PowerSpectrumSampler_Base {
public:
DummyPowerSpectrum(MPI_Communication *comm)
: PowerSpectrumSampler_Base(comm) {}
virtual void initialize(MarkovState &state) { initialize_base(state); }
virtual void restore(MarkovState &state) { restore_base(state); }
virtual void sample(MarkovState &state) {}
};
struct SamplerBundle {
//BlockLoop foreground_block;
typedef std::list<MarkovSampler *> SamplerList;
std::function<MarkovSampler *(int, int)> foreground_sampler_generator;
DummyPowerSpectrum dummy_ps;
SamplerList foreground_samplers;
MPI_Communication *comm;
std::shared_ptr<GenericDensitySampler> density_mc;
std::shared_ptr<MarkovSampler> bias;
// std::shared_ptr<JuliaDensityLikelihood> julia_likelihood;
bool delegate_ic_to_python;
std::shared_ptr<LibLSS::GridDensityLikelihoodBase<3>> python_likelihood;
BlockLoop foreground_block;
SyntheticSelectionUpdater sel_updater;
SamplerBundle(MPI_Communication *comm)
: comm(comm), dummy_ps(comm), delegate_ic_to_python(false) {}
void newForeground(int catalog, int fgmap) {
Console::instance().print<LOG_VERBOSE>("Adding new foreground sampler");
MarkovSampler *fgsample = foreground_sampler_generator(catalog, fgmap);
if (fgsample != 0) {
foreground_samplers.push_back(fgsample);
foreground_block << (*fgsample);
}
}
~SamplerBundle() {
Console::instance().print<LOG_VERBOSE>("Begin destroying the bundle");
for (SamplerList::iterator i = foreground_samplers.begin();
i != foreground_samplers.end(); ++i) {
delete (*i);
}
Console::instance().print<LOG_VERBOSE>("Done destroying the bundle");
}
};
} // namespace LibLSS
#endif

View file

@ -0,0 +1,326 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/src/python_bundle_init.cpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include "python_bundle.hpp"
#include "likelihood_info.hpp"
//#include "libLSS/samplers/rgen/qnhmc/qnhmc_density_sampler.hpp"
#include "libLSS/samplers/rgen/frozen/frozen_phase_density_sampler.hpp"
#include "libLSS/samplers/core/generate_random_field.hpp"
#include "common/preparation_types.hpp"
#include "common/preparation_tools.hpp"
#include <pybind11/embed.h>
#include "pyborg.hpp"
#include "libLSS/samplers/core/main_loop.hpp"
#include "python_bundle_init.hpp"
#include "libLSS/borg_version.hpp"
#include "libLSS/ares_version.hpp"
#include "common/foreground.hpp"
#include "libLSS/physics/cosmo_power.hpp"
#include <pybind11/numpy.h>
#include "libLSS/samplers/core/gridLikelihoodBase.hpp"
#include "libLSS/tools/string_tools.hpp"
using namespace LibLSS;
static std::unique_ptr<Python::py::scoped_interpreter> py_interpret;
namespace py = Python::py;
static py::object gravity_setup;
static py::object likelihood_setup;
static py::object sampler_setup;
static py::object ic_setup;
template <typename T>
std::shared_ptr<T> hold_python_with_ref(py::handle o) {
auto original_ref = o.cast<std::shared_ptr<T>>();
// We have to build a new shared_ptr to manage the python reference counting as well
o.inc_ref();
auto new_ref =
std::shared_ptr<T>(original_ref.get(), [original_ref, o](void *) mutable {
// Decrease the python counter
o.dec_ref();
// Decrease the C++ counter
original_ref.reset();
});
return new_ref;
}
PYBIND11_EMBEDDED_MODULE(borg_embed, m) {
Console::instance().print<LOG_INFO>("Start embedded borg module.");
Python::bindBORG(m);
m.def(
"registerGravityBuilder", [](py::object f) { gravity_setup = f; },
"Register the function that builds the gravity model for HADES");
m.def(
"registerLikelihoodBuilder", [](py::object f) { likelihood_setup = f; },
"Register the function that builds the likelihood object");
m.def(
"registerIcBuilder", [](py::object f) { ic_setup = f; },
"Register the function in charge of initial condition of the chain");
m.def(
"registerSamplerBuilder", [](py::object f) { sampler_setup = f; },
"Register the function that returns a list of samplers to execute.");
}
static std::shared_ptr<BORGForwardModel>
build_model_from_python(MarkovState &state, BoxModel &box) {
if (!gravity_setup) {
error_helper<ErrorBadState>("Gravity builder has not been registered");
}
try {
return gravity_setup(&state, &box)
.cast<std::shared_ptr<BORGForwardModel>>();
} catch (pybind11::error_already_set const &e) {
Console::instance().print<LOG_ERROR>(
"An error was thrown by python: " + std::string(e.what()));
error_helper<ErrorBadState>("Python thrown an unrecoverable error.");
}
}
void LibLSS::sampler_bundle_cleanup()
{
gravity_setup.release().dec_ref();
likelihood_setup.release().dec_ref();
sampler_setup.release().dec_ref();
ic_setup.release().dec_ref();
py_interpret.reset();
}
void LibLSS::sampler_bundle_init(
MPI_Communication *mpi_world, LibLSS_prepare::ptree &params,
SamplerBundle &bundle, MainLoop &loop, bool resuming) {
typedef LibLSS_prepare::ptree ptree;
using boost::format;
using CosmoTool::square;
using std::string;
py_interpret =
std::unique_ptr<py::scoped_interpreter>(new py::scoped_interpreter());
py::object scope = py::module::import("__main__").attr("__dict__");
// Make sure the embedded module is loaded to have the class definitions.
py::module::import("borg_embed");
ptree system_params = params.get_child("system");
ptree python_params = params.get_child("python");
auto block_loop_params = params.get_child_optional("block_loop");
int hades_mixing = params.template get<int>("hades.mixing", 20);
std::string lh_type =
params.template get<std::string>("hades.likelihood", "LINEAR");
std::shared_ptr<MarkovSampler> nmean, bias;
typedef GridDensityLikelihoodBase<3> grid_t;
std::shared_ptr<grid_t> likelihood;
MarkovState &state = loop.get_state();
auto &cons = Console::instance();
BorgModelElement *model = new BorgModelElement();
loop.get_state().newElement("BORG_model", model);
loop.get_state().newScalar("BORG_version", BORG_GIT_VERSION);
BoxModel box;
box.xmin0 = state.getScalar<double>("corner0");
box.xmin1 = state.getScalar<double>("corner1");
box.xmin2 = state.getScalar<double>("corner2");
box.L0 = state.getScalar<double>("L0");
box.L1 = state.getScalar<double>("L1");
box.L2 = state.getScalar<double>("L2");
box.N0 = state.getScalar<long>("N0");
box.N1 = state.getScalar<long>("N1");
box.N2 = state.getScalar<long>("N2");
string code_path = python_params.template get<string>("likelihood_path");
auto like_info = std::make_shared<LikelihoodInfo>();
LibLSS_prepare::setupLikelihoodInfo(
mpi_world, loop.get_state(), *like_info, params, resuming);
// Evaluate the python entry point
py::eval_file(code_path, scope);
// Ask python to setup the deterministic forward model chain.
model->obj = build_model_from_python(state, box);
if (!model->obj) {
error_helper<ErrorBadState>("A model needs be setup in python.");
}
if (!likelihood_setup) {
error_helper<ErrorBadState>("Likelihood builder has not been registered");
}
try {
py::object py_likelihood = likelihood_setup(&state, like_info);
likelihood = bundle.python_likelihood =
hold_python_with_ref<grid_t>(py_likelihood);
} catch (pybind11::error_already_set const &e) {
Console::instance().print<LOG_ERROR>(
"An error was thrown by python: ");
Console::instance().print<LOG_ERROR>(LibLSS::tokenize(e.what(), "\n"));
error_helper<ErrorBadState>("Python thrown an unrecoverable error.");
}
bundle.delegate_ic_to_python =
python_params.template get<bool>("ic_in_python", false);
// Initialize foregrounds
LibLSS_prepare::initForegrounds(
mpi_world, loop.get_state(),
[&bundle](int a, int b) { bundle.newForeground(a, b); }, params);
/* if (!system_params.template get<bool>("block_sigma8_sampler", true))
bundle.sigma8_sampler = new GenericSigma8Sampler(bundle.comm);
else
bundle.sigma8_sampler = 0;
*/
std::string algorithm_name =
params.template get<std::string>("hades.algorithm", "HMC");
if (algorithm_name == "HMC") {
// -----------------------------------
// HMC algorithm initialization
double maxEpsilon = params.template get<double>("hades.max_epsilon", 0.02);
int maxTimeSteps = params.template get<int>("hades.max_timesteps", 100);
double kmax = params.template get<double>("hades.kmax", 0);
std::string I_scheme_s =
params.template get<std::string>("hades.scheme", "SI_2A");
HMCOption::IntegratorScheme I_scheme = get_Scheme(I_scheme_s);
auto density_mc =
std::make_unique<HMCDensitySampler>(mpi_world, likelihood, kmax);
density_mc->setIntegratorScheme(I_scheme);
density_mc->setMaxEpsilon(maxEpsilon);
density_mc->setMaxTimeSteps(maxTimeSteps);
// HMC algorithm initialization - end
// -----------------------------------
bundle.density_mc = std::move(density_mc);
// } else if (algorithm_name == "QN-HMC") {
// double maxEpsilon = params.template get<double>("hades.max_epsilon", 0.02);
// int maxTimeSteps = params.template get<int>("hades.max_timesteps", 100);
// std::string I_scheme_s =
// params.template get<std::string>("hades.scheme", "SI_2A");
// HMCOption::IntegratorScheme I_scheme = get_Scheme(I_scheme_s);
// auto density_mc =
// std::make_unique<QNHMCDensitySampler>(mpi_world, likelihood);
// density_mc->setIntegratorScheme(I_scheme);
// density_mc->setMaxEpsilon(maxEpsilon);
// density_mc->setMaxTimeSteps(maxTimeSteps);
// bundle.density_mc = std::move(density_mc);
} else if (algorithm_name == "FROZEN-PHASE") {
auto density_mc =
std::make_unique<FrozenPhaseDensitySampler>(mpi_world, likelihood);
if (auto phase_file =
params.template get_optional<std::string>("hades.phases")) {
// A file containing phases is providing. Schedule for loading.
density_mc->setPhaseFile(
*phase_file,
params.template get<std::string>("hades.phasesDataKey"));
} else {
if (!params.template get<bool>("hades.noPhasesProvided"))
error_helper<ErrorParams>("If no phases are provided, "
"noPhasesProvided must be set to true.");
}
bundle.density_mc = std::move(density_mc);
} else {
error_helper<ErrorBadState>(
"Invalid algorithm name: " + algorithm_name +
" (choice is HMC or QN-HMC)");
}
bool hblock = adapt_optional<bool>(
loop.get_state(), block_loop_params, "hades_sampler_blocked", false,
DO_NOT_RESTORE);
adapt_optional<bool>(
loop.get_state(), block_loop_params, "bias_sampler_blocked", false,
DO_NOT_RESTORE);
adapt_optional<bool>(
loop.get_state(), block_loop_params, "nmean_sampler_blocked", false,
DO_NOT_RESTORE);
Console::instance().print<LOG_INFO_SINGLE>(
format("Hades mixing per mcmc step is %d") % hades_mixing);
Console::instance().print<LOG_INFO_SINGLE>(
format("Hades density is blocked: %s") % (hblock ? "YES" : "NO"));
loop << bundle.dummy_ps << bundle.sel_updater;
py::list samplers;
if (!sampler_setup) {
error_helper<ErrorBadState>(
"Sampler algorithm builder has not been registered");
}
try {
samplers = sampler_setup(&state, like_info);
} catch (pybind11::error_already_set const &e) {
Console::instance().print<LOG_ERROR>(
"An error was thrown by python: ");
Console::instance().print<LOG_ERROR>(LibLSS::tokenize(e.what(), "\n"));
error_helper<ErrorBadState>("Python thrown an unrecoverable error.");
}
// ==================
// MAIN LOOP PROGRAM
if (bias != 0) {
auto bias_loop = new BlockLoop(1);
*bias_loop << *bias;
loop
<< (BlockLoop(hades_mixing)
<< *bundle.density_mc << *bias_loop
<< (BlockLoop(10) << bundle.foreground_block));
delete bias_loop;
} else {
loop
<< (BlockLoop(hades_mixing)
<< *bundle
.density_mc); //<< (BlockLoop(10) << bundle.foreground_block);
}
for (auto &py_sampler : samplers) {
auto new_ref = hold_python_with_ref<MarkovSampler>(py_sampler);
loop << new_ref;
}
// If active, sample sigma8
// if (bundle.sigma8_sampler != 0)
// loop << *bundle.sigma8_sampler;
}
void LibLSS::sampler_setup_ic(
SamplerBundle &bundle, MainLoop &loop,
LibLSS_prepare::ptree const &params) {
MarkovState &state = loop.get_state();
if (bundle.delegate_ic_to_python) {
py::object scope = py::module::import("__main__").attr("__dict__");
try {
ic_setup(&state);
} catch (pybind11::error_already_set const &e) {
Console::instance().print<LOG_ERROR>(
"An error was thrown by python: " + std::string(e.what()));
error_helper<ErrorBadState>("Python thrown an unrecoverable error.");
}
} else {
bool random_ic = params.template get<bool>("mcmc.random_ic", true);
if (random_ic)
generateRandomField(bundle.comm, state);
double initialRandomScaling =
params.template get<double>("mcmc.init_random_scaling", 0.1);
state.get<CArrayType>("s_hat_field")->eigen() *= initialRandomScaling;
state.get<ArrayType>("s_field")->eigen() *= initialRandomScaling;
}
}

View file

@ -0,0 +1,31 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/src/python_bundle_init.hpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#ifndef __HADES_PYTHON_BUNDLE_INIT_HPP
#define __HADES_PYTHON_BUNDLE_INIT_HPP
#include "python_bundle.hpp"
#include "likelihood_info.hpp"
#include "setup_models.hpp"
#include "common/preparation_types.hpp"
namespace LibLSS {
void sampler_bundle_init(
MPI_Communication *mpi_world, LibLSS_prepare::ptree &params, SamplerBundle &bundle,
MainLoop &loop, bool resuming);
void
sampler_setup_ic(SamplerBundle &bundle, MainLoop &loop, LibLSS_prepare::ptree const &params);
void sampler_bundle_cleanup();
} // namespace LibLSS
#endif

View file

@ -0,0 +1,47 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/src/python_mock_gen.cpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#include "libLSS/cconfig.h"
#include <CosmoTool/algo.hpp>
#include "libLSS/tools/string_tools.hpp"
#include <cmath>
#include "python_bundle.hpp"
#include "python_mock_gen.hpp"
#include "libLSS/physics/cosmo_power.hpp"
#include <pybind11/pybind11.h>
using namespace LibLSS;
void LibLSS::prepareMockData(
LibLSS_prepare::ptree &ptree, MPI_Communication *comm, MarkovState &state,
CosmologicalParameters &cosmo_params, SamplerBundle &bundle) {
ConsoleContext<LOG_INFO_SINGLE> ctx("prepareMockData");
using boost::format;
using CosmoTool::square;
createCosmologicalPowerSpectrum(state, cosmo_params);
bundle.sel_updater.sample(state);
try {
bundle.density_mc->generateMockData(state);
} catch (pybind11::error_already_set const &e) {
Console::instance().print<LOG_ERROR>("An error was thrown by python:");
Console::instance().print<LOG_ERROR>(LibLSS::tokenize(e.what(), "\n"));
error_helper<ErrorBadState>("Python thrown an unrecoverable error.");
}
{
std::shared_ptr<H5::H5File> f;
if (comm->rank() == 0)
f = std::make_shared<H5::H5File>("mock_data.h5", H5F_ACC_TRUNC);
state.mpiSaveState(f, comm, false);
}
}

View file

@ -0,0 +1,25 @@
/*+
ARES/HADES/BORG Package -- ./extra/python/src/python_mock_gen.hpp
Copyright (C) 2014-2020 Guilhem Lavaux <guilhem.lavaux@iap.fr>
Copyright (C) 2009-2020 Jens Jasche <jens.jasche@fysik.su.se>
Additional contributions from:
Guilhem Lavaux <guilhem.lavaux@iap.fr> (2023)
+*/
#pragma once
#ifndef __HADES_PYTHON_MOCK_GEN_HPP
#define __HADES_PYTHON_MOCK_GEN_HPP
#include <CosmoTool/algo.hpp>
#include <cmath>
#include "common/preparation_types.hpp"
namespace LibLSS {
void prepareMockData(
LibLSS_prepare::ptree &ptree, MPI_Communication *comm, MarkovState &state,
CosmologicalParameters &cosmo_params, SamplerBundle &bundle);
} // namespace LibLSS
#endif

View file

@ -0,0 +1,23 @@
option(BUILD_PYTHON_EMBEDDER OFF)
if (BUILD_PYTHON_EXTENSION AND BUILD_PYTHON_EMBEDDER)
cmessage(STATUS "Activate Hades_python")
include_directories(${ARES_MODULE_DIR}/src ${ARES_MODULE_DIR}/python)
find_library(UTIL_LIBRARY util)
add_executable(hades_python ${ARES_MODULE_DIR}/src/hades_python.cpp ${ARES_MODULE_DIR}/src/python_bundle_init.cpp ${ARES_MODULE_DIR}/src/python_mock_gen.cpp)
target_link_libraries(hades_python python_borg hades borg_models LSS ${DEP_LIBS} pybind11::embed ${UTIL_LIBRARY} ${DL_LIBRARY})
add_dependencies(hades_python ${ares_DEPS})
if (NOT APPLE)
target_link_options(hades_python PUBLIC -export-dynamic)
endif()
set_property(SOURCE ${extra_hmclet}/hades_julia3.cpp APPEND PROPERTY OBJECT_DEPENDS
${ARES_MODULE_DIR}/src/python_mock_gen.hpp
${ARES_MODULE_DIR}/src/python_bundle.hpp
${ARES_MODULE_DIR}/src/python_bundle_init.hpp
${CMAKE_SOURCE_DIR}/src/ares_init.hpp)
endif()