Initial import
This commit is contained in:
commit
56a50eead3
820 changed files with 192077 additions and 0 deletions
89
extra/python/example/2mpp-chain.ini.txt
Normal file
89
extra/python/example/2mpp-chain.ini.txt
Normal 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
|
73
extra/python/example/model/example_jax.py
Normal file
73
extra/python/example/model/example_jax.py
Normal 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)
|
73
extra/python/example/run_altair.py
Normal file
73
extra/python/example/run_altair.py
Normal 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)
|
49
extra/python/example/run_forward.py
Normal file
49
extra/python/example/run_forward.py
Normal 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)
|
87
extra/python/example/test_gradient_cic.py
Normal file
87
extra/python/example/test_gradient_cic.py
Normal 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)
|
89
extra/python/example/test_likelihood.py
Normal file
89
extra/python/example/test_likelihood.py
Normal 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 []
|
84
extra/python/example/velocity/test_gradient_cic.py
Normal file
84
extra/python/example/velocity/test_gradient_cic.py
Normal 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)
|
1
extra/python/python.cmake
Normal file
1
extra/python/python.cmake
Normal file
|
@ -0,0 +1 @@
|
|||
add_subdirectory(${CMAKE_SOURCE_DIR}/extra/python/python)
|
118
extra/python/python/CMakeLists.txt
Normal file
118
extra/python/python/CMakeLists.txt
Normal 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()
|
144
extra/python/python/_borg.cpp
Normal file
144
extra/python/python/_borg.cpp
Normal 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
|
7
extra/python/python/_borg.version
Normal file
7
extra/python/python/_borg.version
Normal file
|
@ -0,0 +1,7 @@
|
|||
CODEABI_1.0 {
|
||||
global:
|
||||
PyInit__borg;
|
||||
_init;
|
||||
_fini;
|
||||
local: *;
|
||||
};
|
182
extra/python/python/any_wrapper.cpp
Normal file
182
extra/python/python/any_wrapper.cpp
Normal 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
|
133
extra/python/python/aquila_borg/__init__.py
Normal file
133
extra/python/python/aquila_borg/__init__.py
Normal 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
|
39
extra/python/python/aquila_borg/borg_native.py
Normal file
39
extra/python/python/aquila_borg/borg_native.py
Normal 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
|
58
extra/python/python/aquila_borg/dft.py
Normal file
58
extra/python/python/aquila_borg/dft.py
Normal 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
|
7
extra/python/python/aquila_borg/utils.py
Normal file
7
extra/python/python/aquila_borg/utils.py
Normal 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))
|
88
extra/python/python/base.cpp
Normal file
88
extra/python/python/base.cpp
Normal 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
|
50
extra/python/python/bind.cpp
Normal file
50
extra/python/python/bind.cpp
Normal 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
|
1
extra/python/python/borg/__init__.py
Normal file
1
extra/python/python/borg/__init__.py
Normal file
|
@ -0,0 +1 @@
|
|||
from aquila_borg import *
|
100
extra/python/python/doc/aquila_borg.cosmo.rst
Normal file
100
extra/python/python/doc/aquila_borg.cosmo.rst
Normal 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.
|
124
extra/python/python/doc/aquila_borg.forward.BORGForwardModel.rst
Normal file
124
extra/python/python/doc/aquila_borg.forward.BORGForwardModel.rst
Normal 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.
|
|
@ -0,0 +1,2 @@
|
|||
@class
|
||||
Base class for implementing new forward model in python
|
28
extra/python/python/doc/aquila_borg.forward.BoxModel.rst
Normal file
28
extra/python/python/doc/aquila_borg.forward.BoxModel.rst
Normal 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
|
|
@ -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
|
162
extra/python/python/doc/aquila_borg.forward.models.rst
Normal file
162
extra/python/python/doc/aquila_borg.forward.models.rst
Normal 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
|
51
extra/python/python/doc/aquila_borg.forward.rst
Normal file
51
extra/python/python/doc/aquila_borg.forward.rst
Normal 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.
|
|
@ -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.
|
38
extra/python/python/doc/aquila_borg.forward.velocity.rst
Normal file
38
extra/python/python/doc/aquila_borg.forward.velocity.rst
Normal 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.
|
114
extra/python/python/doc/aquila_borg.likelihood.rst
Normal file
114
extra/python/python/doc/aquila_borg.likelihood.rst
Normal 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
|
142
extra/python/python/doc/aquila_borg.samplers.rst
Normal file
142
extra/python/python/doc/aquila_borg.samplers.rst
Normal 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)
|
20
extra/python/python/doc/borg_base.Console.rst
Normal file
20
extra/python/python/doc/borg_base.Console.rst
Normal 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
|
||||
|
2
extra/python/python/doc/borg_base.rst
Normal file
2
extra/python/python/doc/borg_base.rst
Normal file
|
@ -0,0 +1,2 @@
|
|||
@funcname:console
|
||||
This function returns the valid already created Console object.
|
95
extra/python/python/doc/convert.py
Normal file
95
extra/python/python/doc/convert.py
Normal 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
|
115
extra/python/python/example/test_borg.py
Normal file
115
extra/python/python/example/test_borg.py
Normal 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)
|
41
extra/python/python/example/test_borg2.py
Normal file
41
extra/python/python/example/test_borg2.py
Normal 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)
|
205
extra/python/python/example/test_borg_gpu.py
Normal file
205
extra/python/python/example/test_borg_gpu.py
Normal 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)
|
120
extra/python/python/example/test_borg_proj.py
Normal file
120
extra/python/python/example/test_borg_proj.py
Normal 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")
|
||||
|
45
extra/python/python/py_mpi.hpp
Normal file
45
extra/python/python/py_mpi.hpp
Normal 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
|
98
extra/python/python/pybias.cpp
Normal file
98
extra/python/python/pybias.cpp
Normal 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
|
138
extra/python/python/pybias.hpp
Normal file
138
extra/python/python/pybias.hpp
Normal 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
|
46
extra/python/python/pyborg.hpp
Normal file
46
extra/python/python/pyborg.hpp
Normal 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
|
34
extra/python/python/pyborg_doc.hpp
Normal file
34
extra/python/python/pyborg_doc.hpp
Normal 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
|
167
extra/python/python/pycosmo.cpp
Normal file
167
extra/python/python/pycosmo.cpp
Normal 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
|
850
extra/python/python/pyforward.cpp
Normal file
850
extra/python/python/pyforward.cpp
Normal 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 ¶ms) 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
|
47
extra/python/python/pyforward.hpp
Normal file
47
extra/python/python/pyforward.hpp
Normal 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
|
106
extra/python/python/pyforward_all.cpp
Normal file
106
extra/python/python/pyforward_all.cpp
Normal 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
|
199
extra/python/python/pyforward_borg.cpp
Normal file
199
extra/python/python/pyforward_borg.cpp
Normal 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
|
352
extra/python/python/pyfuse.hpp
Normal file
352
extra/python/python/pyfuse.hpp
Normal 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
|
463
extra/python/python/pylikelihood.cpp
Normal file
463
extra/python/python/pylikelihood.cpp
Normal 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
|
169
extra/python/python/pylikelihood_wrap.hpp
Normal file
169
extra/python/python/pylikelihood_wrap.hpp
Normal 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 ¶meters, 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 ¶meters, 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 ¶meters, 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 ¶meters, 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 ¶ms) override {
|
||||
PYBIND11_OVERLOAD_PURE(void, BasePyLikelihood, updateCosmology, ¶ms);
|
||||
}
|
||||
|
||||
void commitAuxiliaryFields(MarkovState &state) override {
|
||||
PYBIND11_OVERLOAD(void, BasePyLikelihood, commitAuxiliaryFields, state);
|
||||
}
|
||||
|
||||
void
|
||||
generateMockData(CArrayRef const ¶meters, MarkovState &state) override {
|
||||
py::gil_scoped_acquire acquire;
|
||||
{
|
||||
py::object py_params = Python::makeNumpy(parameters);
|
||||
|
||||
PYBIND11_OVERLOAD_PURE(
|
||||
void, BasePyLikelihood, generateMockData, py_params, &state);
|
||||
}
|
||||
}
|
||||
};
|
286
extra/python/python/pysamplers.cpp
Normal file
286
extra/python/python/pysamplers.cpp
Normal 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,
|
||||
[¤t_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,
|
||||
[¤t_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 ¶ms,
|
||||
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
|
199
extra/python/python/pyvelocity.cpp
Normal file
199
extra/python/python/pyvelocity.cpp
Normal 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
|
27
extra/python/python/pyvelocity.hpp
Normal file
27
extra/python/python/pyvelocity.hpp
Normal 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
|
44
extra/python/src/hades_python.cpp
Normal file
44
extra/python/src/hades_python.cpp
Normal 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
|
112
extra/python/src/python_bundle.hpp
Normal file
112
extra/python/src/python_bundle.hpp
Normal 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
|
326
extra/python/src/python_bundle_init.cpp
Normal file
326
extra/python/src/python_bundle_init.cpp
Normal 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 ¶ms,
|
||||
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 ¶ms) {
|
||||
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;
|
||||
}
|
||||
}
|
31
extra/python/src/python_bundle_init.hpp
Normal file
31
extra/python/src/python_bundle_init.hpp
Normal 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 ¶ms, SamplerBundle &bundle,
|
||||
MainLoop &loop, bool resuming);
|
||||
|
||||
void
|
||||
sampler_setup_ic(SamplerBundle &bundle, MainLoop &loop, LibLSS_prepare::ptree const ¶ms);
|
||||
|
||||
void sampler_bundle_cleanup();
|
||||
|
||||
} // namespace LibLSS
|
||||
|
||||
#endif
|
47
extra/python/src/python_mock_gen.cpp
Normal file
47
extra/python/src/python_mock_gen.cpp
Normal 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);
|
||||
}
|
||||
}
|
25
extra/python/src/python_mock_gen.hpp
Normal file
25
extra/python/src/python_mock_gen.hpp
Normal 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
|
23
extra/python/src/tools.cmake
Normal file
23
extra/python/src/tools.cmake
Normal 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()
|
Loading…
Add table
Add a link
Reference in a new issue