Initial import

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

View file

@ -0,0 +1,42 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/ares_bias.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 __LIBLSS_ARES_BIAS_HPP
#define __LIBLSS_ARES_BIAS_HPP
#include "libLSS/tools/console.hpp"
#include "libLSS/samplers/core/types_samplers.hpp"
#include "libLSS/mcmc/global_state.hpp"
#include <boost/format.hpp>
namespace LibLSS {
namespace ARES {
inline double& extract_bias(MarkovState& state, int c)
{
using boost::format;
return (*state.get<ArrayType1d>(format("galaxy_bias_%d") % c)->array)[0];
}
template<typename InitializerArray>
void ensure_bias_size(MarkovState& state, unsigned int c, const InitializerArray& init_a)
{
using boost::format;
auto& a = (*state.get<ArrayType1d>(format("galaxy_bias_%d") % c)->array);
size_t old_sz = a.size();
if (old_sz < init_a.size()) {
a.resize(boost::extents[init_a.size()]);
for (size_t i = old_sz; i < init_a.size(); i++)
a[i] = init_a[i];
}
}
}
}
#endif

View file

@ -0,0 +1,536 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/gibbs_messenger.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 <Eigen/Core>
#include <cmath>
#include <boost/format.hpp>
#include <CosmoTool/fourier/fft/fftw_calls.hpp>
#include "libLSS/samplers/core/random_number.hpp"
#include "libLSS/samplers/ares/gibbs_messenger.hpp"
#include "libLSS/tools/mpi_fftw_helper.hpp"
#include "libLSS/samplers/ares/ares_bias.hpp"
#include "libLSS/tools/fused_array.hpp"
#include "libLSS/tools/fused_assign.hpp"
#include "libLSS/tools/array_tools.hpp"
using namespace LibLSS;
using boost::format;
using boost::extents;
using LibLSS::ARES::extract_bias;
typedef boost::multi_array_types::extent_range range;
typedef Eigen::Map<Eigen::ArrayXd, Eigen::Aligned> MappedArray;
/* (data,s) -> t sampler
*/
MessengerSampler::MessengerSampler(MPI_Communication * comm_)
: comm(comm_), constrainedGeneration(true), mgr(0)
{
}
MessengerSampler::~MessengerSampler()
{
if (mgr != 0)
delete mgr;
}
void MessengerSampler::restore(MarkovState& state)
{
initialize(state);
}
void MessengerSampler::initialize(MarkovState& state)
{
ArrayType *messenger;
Console& cons = Console::instance();
cons.print<LOG_INFO>("Initialize Messenger sampler");
cons.indent();
N0 = state.get<SLong>("N0")->value;
N1 = state.get<SLong>("N1")->value;
N2 = state.get<SLong>("N2")->value;
mgr = new FFTMgr(N0, N1, N2, comm);
startN0 = mgr->startN0;
localN0 = mgr->localN0;
Ntot = N0*N1*N2;
localNtot = localN0*N1*N2;
N_k = state.get<SLong>("NUM_MODES")->value;
rng = state.get<RandomGen>("random_generator");
cons.print<LOG_DEBUG>("Allocating messenger field");
messenger = new ArrayType(extents[range(startN0,startN0+localN0)][N1][N2]);
messenger->setRealDims(ArrayDimension(N0, N1, N2));
cons.print<LOG_DEBUG>(format("Allocated messenger_field %p") % messenger->array->data());
cons.print<LOG_DEBUG>("Allocating messenger field");
messenger_mask = new ArrayType(extents[range(startN0,startN0+localN0)][N1][N2]);
messenger_mask->setRealDims(ArrayDimension(N0, N1, N2));
cons.print<LOG_DEBUG>("Allocating mixed data field");
data_field = new ArrayType(extents[range(startN0,startN0+localN0)][N1][N2]);
data_field->setRealDims(ArrayDimension(N0, N1, N2));
state.newElement("messenger_field", messenger);
state.newElement("messenger_mask", messenger_mask);
state.newElement("messenger_tau", messenger_tau = new SDouble());
state.newElement("data_field", data_field);
cons.unindent();
cons.print<LOG_INFO>("Done");
}
void MessengerSampler::sample(MarkovState& state)
{
ConsoleContext<LOG_DEBUG> ctx("MessengerSampler::sample");
ArrayType& s_field = static_cast<ArrayType&>(state["s_field"]);
ArrayType::ArrayType& m_field = *state.get<ArrayType>("messenger_field")->array;
ArrayType& data_field = static_cast<ArrayType&>(state["data_field"]);
// We need the 3d messenger mask/window
ArrayType& W = *messenger_mask;
// We need the random generator
SDouble& tau = *messenger_tau;
double sqrt_tau = std::sqrt(tau);
if (constrainedGeneration) {
#pragma omp parallel
{
auto &rng_g = rng->get();
const auto &W_tmp = W.array->data();
const auto &s_tmp = s_field.array->data();
const auto &d_tmp = data_field.array->data();
const auto &m_tmp = m_field.data();
#pragma omp for schedule(static)
for (long i = 0; i < localNtot; i++) {
double A = rng_g.gaussian();
double Wi = W_tmp[i];
double si = s_tmp[i];
double di = d_tmp[i];
double mu, sigma;
if (Wi > 0) {
mu = (si * Wi + tau * di) / (Wi + tau);
sigma = std::sqrt( (Wi*tau) / (Wi + tau) );
} else if (Wi < 0){
mu = si;
sigma = sqrt_tau;
} else {
mu = di;
sigma = 0;
}
m_tmp[i] = mu + sigma * A;
}
} // end of parallel region
} else {
for (long i = 0; i < localNtot; i++) {
double A = rng->get().gaussian();
double Wi = W.array->data()[i];
double m_i = m_field.data()[i];
double& di = data_field.array->data()[i];
if (Wi > 0)
di = m_i + std::sqrt(Wi)*A;
else
di = 0;
Console::instance().c_assert(!std::isnan(di), "Data is a NaN");
}
}
}
/* t-> s sampler
*/
MessengerSignalSampler::MessengerSignalSampler(MPI_Communication* comm)
: flat_key(0), tmp_fourier(0), tmp_fourier_m(0), tmp_m_field(0), tmp_real_field(0), analysis_plan(0), synthesis_plan(0),
constrainedGeneration(true), comm(comm), mgr(0)
{
}
void MessengerSignalSampler::restore(MarkovState& state)
{
initialize(state);
}
void MessengerSignalSampler::initialize(MarkovState& state)
{
Console& cons = Console::instance();
ConsoleContext<LOG_INFO> ctx("Messenger-Signal sampler");
N0 = static_cast<SLong&>(state["N0"]);
N1 = static_cast<SLong&>(state["N1"]);
N2 = static_cast<SLong&>(state["N2"]);
mgr = new FFTMgr(N0, N1, N2, comm);
// This for MPI support
startN0 = mgr->startN0;
localN0 = mgr->localN0;
fourierLocalSize = mgr->allocator_real.minAllocSize;
N_k = state.get<SLong>("NUM_MODES")->value;
L0 = static_cast<SDouble&>(state["L0"]);
L1 = static_cast<SDouble&>(state["L1"]);
L2 = static_cast<SDouble&>(state["L2"]);
if (tmp_fourier) {
error_helper<ErrorBadState>("MessengerSignalSampler has already been initialized.");
}
cons.print<LOG_DEBUG>("Allocating x field");
x_field = new ArrayType(extents[range(startN0,startN0+localN0)][N1][N2]);
x_field->setRealDims(ArrayDimension(N0, N1, N2));
cons.print<LOG_DEBUG>("Allocating s field");
s_field = new ArrayType(extents[range(startN0,startN0+localN0)][N1][N2]);
s_field->setRealDims(ArrayDimension(N0, N1, N2));
state.newElement("x_field", x_field);
state.newElement("s_field", s_field, true);
s_field->eigen().fill(0);
x_field->eigen().fill(0);
Ntot = N0*N1*N2;
Ntot_k = N0*N1*(N2/2+1);
localNtot = localN0*N1*N2;
localNtot_k = localN0*N1*(N2/2+1);
volume = L0*L1*L2;
volNorm = volume/Ntot;
ctx.print(format("fourierLocalSize = %d") % fourierLocalSize);
tmp_fourier = MFCalls::alloc_complex(fourierLocalSize);
tmp_fourier_m = MFCalls::alloc_complex(fourierLocalSize);
#ifndef ARES_MPI_FFTW
ctx.print("Creating FFTW plans for Messenger-Signal");
tmp_m_field = new ArrayType(boost::extents[range(startN0,startN0+localN0)][N1][N2]);
ctx.print(format("Allocated tmp_m_field %p") % tmp_m_field->array->origin());
analysis_plan = MFCalls::plan_dft_r2c_3d(
N0, N1, N2,
x_field->array->data(),
tmp_fourier,
FFTW_DESTROY_INPUT|FFTW_MEASURE);
synthesis_plan = MFCalls::plan_dft_c2r_3d(
N0, N1, N2,
tmp_fourier,
x_field->array->data(),
FFTW_DESTROY_INPUT|FFTW_MEASURE);
#else
ctx.print("Creating MPI/FFTW plans for Messenger-Signal");
tmp_real_field = MFCalls::alloc_real(fourierLocalSize*2);
analysis_plan = MFCalls::plan_dft_r2c_3d(
N0, N1, N2,
tmp_real_field,
tmp_fourier,
comm->comm(),
// FFTW_MPI_TRANSPOSED_OUT|
FFTW_DESTROY_INPUT|FFTW_MEASURE);
synthesis_plan = MFCalls::plan_dft_c2r_3d(
N0, N1, N2,
tmp_fourier,
tmp_real_field,
comm->comm(),
//FFTW_MPI_TRANSPOSED_IN|
FFTW_DESTROY_INPUT|FFTW_MEASURE);
#endif
ctx.print(format("allocated tmp_fourier(%p) tmp_fourier_m(%p) and tmp_real_field(%p)") % tmp_fourier % tmp_fourier_m% tmp_real_field);
ctx.print("Done creating FFTW plans for Messenger-Signal");
}
MessengerSignalSampler::~MessengerSignalSampler()
{
if (tmp_fourier) {
Console::instance().print<LOG_INFO>("Cleaning up Messenger-Signal");
#ifdef ARES_MPI_FFTW
delete tmp_m_field;
#endif
if (flat_key)
delete flat_key;
if (tmp_fourier)
MFCalls::free(tmp_fourier);
if (tmp_fourier_m)
MFCalls::free(tmp_fourier_m);
if (tmp_real_field)
MFCalls::free(tmp_real_field);
if (analysis_plan)
MFCalls::destroy_plan(analysis_plan);
if (synthesis_plan)
MFCalls::destroy_plan(synthesis_plan);
if (mgr)
delete mgr;
}
}
void MessengerSignalSampler::sample(MarkovState& state)
{
ConsoleContext<LOG_DEBUG> ctx("MessengerSignalSampler::sample");
RandomGen& rng = static_cast<RandomGen&>(state["random_generator"]);
ArrayType& m_field = *state.get<ArrayType>("messenger_field");
ArrayType1d::ArrayType& P_info = *state.get<ArrayType1d>("powerspectrum")->array;
SDouble& tau = static_cast<SDouble&>(state["messenger_tau"]);
IArrayType::ArrayType& P_key = *state.get<IArrayType>("k_keys")->array; // Built by powerspec_tools
ArrayType& x = *x_field;
ArrayType& s = *s_field;
double alpha = 1/std::sqrt(double(Ntot));
Console& cons = Console::instance();
ctx.print("Sample messenger-signal");
if (state.get<SBool>("messenger_signal_blocked")->value && constrainedGeneration)
return;
// We have to initialize this lazily. k_keys is created by powerspectrum samplers.
if (flat_key == 0) {
IArrayType *keys = state.get<IArrayType>("k_keys");
flat_key = new FlatIntType( keys->array->data(), boost::extents[keys->array->num_elements()] );
}
#pragma omp parallel
{
auto &rng_g = rng.get();
const auto &data = x.array->data();
#pragma omp for schedule(static)
for (long i = 0; i < localNtot; i++) {
data[i] = rng_g.gaussian()*alpha;
}
}
copy_padded_data(*x.array, tmp_real_field, true);
// This destroy the x_field. Not a problem. synthesis is regenerating it
MFCalls::execute(analysis_plan);
#ifdef ARES_MPI_FFTW
copy_padded_data(*m_field.array, tmp_real_field);
MFCalls::execute_r2c(analysis_plan, tmp_real_field, tmp_fourier_m);
#else
// This destroy the m_field. Could be annoying.
tmp_m_field->eigen() = m_field.eigen();
FCalls::execute_r2c(analysis_plan, m_field.array->data(), tmp_fourier_m);
#endif
if (constrainedGeneration) {
double scaler = 1/volNorm;
double T = tau * volume;
boost::multi_array<double, 1> sqrtP(boost::extents[N_k]);
boost::multi_array<double, 1> A1(boost::extents[N_k]);
boost::multi_array<double, 1> A2(boost::extents[N_k]);
LibLSS::copy_array(sqrtP,
b_fused<double>(P_info,
[this,scaler](double x)->double const { return x < 0 ? 0 : std::sqrt(x*volume);}
)
);
LibLSS::copy_array(A1,
b_fused<double>(P_info, sqrtP,
[this,scaler,T](double x,double y)->double const { return x < 0 ? 0 : y/(T+x*volume*scaler); })
);
LibLSS::copy_array(A2,
b_fused<double>(P_info,
[this,scaler,T](double x)->double const { return x < 0 ? 0 : std::sqrt(T/(T+x*volume*scaler)); })
);
#pragma omp parallel for schedule(static)
for (long i = 0; i < localNtot_k; i++) {
long key = (*flat_key)[i];
double color_P = sqrtP[key];
double aux1 = A1[key];
double aux2 = A2[key];
MFCalls::complex_type& white_phase = tmp_fourier_m[i];
MFCalls::complex_type& random_phase = tmp_fourier[i];
MFCalls::complex_type& colored_phase = tmp_fourier_m[i];
random_phase[0] = aux1 * white_phase[0] + aux2 * random_phase[0];
random_phase[1] = aux1 * white_phase[1] + aux2 * random_phase[1];
colored_phase[0] = color_P * random_phase[0];
colored_phase[1] = color_P * random_phase[1];
}
if (startN0 == 0 && localN0 > 1) {
tmp_fourier[0][0] = 0;
tmp_fourier[0][1] = 0;
tmp_fourier_m[0][0] = 0;
tmp_fourier_m[0][1] = 0;
}
} else {
#pragma omp parallel for schedule(static)
for (long i = 0; i < localNtot_k; i++) {
double P = P_info[(*flat_key)[i]] * volume;
double color_P = std::sqrt(P);
MFCalls::complex_type& white_phase = tmp_fourier_m[i];
MFCalls::complex_type& random_phase = tmp_fourier[i];
MFCalls::complex_type& colored_phase = tmp_fourier_m[i];
colored_phase[0] = color_P * random_phase[0];
colored_phase[1] = color_P * random_phase[1];
}
}
ctx.print("Fourier synthesis of phases");
// Regenerate a correct x_field
MFCalls::execute(synthesis_plan);
copy_unpadded_data(tmp_real_field, *x.array, true);
ctx.print("Fourier synthesis of signal");
// Generate the colored s field
#ifdef ARES_MPI_FFTW
MFCalls::execute_c2r(synthesis_plan, tmp_fourier_m, tmp_real_field);
copy_unpadded_data(tmp_real_field, *s.array);
#else
FCalls::execute_c2r(synthesis_plan, tmp_fourier_m, s.array->data());
if (constrainedGeneration) {
// Restore m_field
m_field.eigen() = tmp_m_field->eigen();
}
#endif
// Just renormalize
array::scaleArray3d(*s.array, 1.0/volume);
array::scaleArray3d(*x.array, 1.0/volume);
// Generate m_field in mock mode
if (!constrainedGeneration) {
double sq_tau = sqrt(tau);
// Populate m_field
for (long i = 0; i < localNtot; i++)
m_field.array->data()[i] = s.array->data()[i] + rng.get().gaussian()*sq_tau;
}
}
/*
* (catalog,meta) -> data
*/
void CatalogProjectorSampler::initialize(MarkovState& state)
{
Ncat = static_cast<SLong&>(state["NCAT"]);
}
void CatalogProjectorSampler::restore(MarkovState& state)
{
Ncat = static_cast<SLong&>(state["NCAT"]);
}
void CatalogProjectorSampler::sample(MarkovState& state)
{
RandomGen& rng = static_cast<RandomGen&>(state["random_generator"]);
ArrayType& W = *state.get<ArrayType>("messenger_mask");
SDouble *messenger_tau = state.get<SDouble>("messenger_tau");
ArrayType& G = *state.get<ArrayType>("growth_factor");
ArrayType& data_field = *state.get<ArrayType>("data_field");
// Just do vectorized operation here
MappedArray map_W = W.eigen();
MappedArray growth = G.eigen();
MappedArray map_data = data_field.eigen();
ConsoleContext<LOG_DEBUG> ctx("regenerate_W");
double heat = state.getScalar<double>("ares_heat");
ctx.print("Rebuild the projected data and covariance matrix");
// Clear up W first
map_W.fill(0);
if (!mockGeneration)
map_data.fill(0);
for (int c = 0; c < Ncat; c++) {
ctx.print(format("Looking at catalog %d") % c);
SelArrayType& sel_field = *state.get<SelArrayType>(format("galaxy_synthetic_sel_window_%d") % c);
ArrayType& g_field = *state.get<ArrayType>(format("galaxy_data_%d") % c);
double& bias = extract_bias(state, c);
double nmean = state.get<SDouble>(format("galaxy_nmean_%d") % c)->value;
MappedArray g_data = g_field.eigen();
MappedArray map_sel = sel_field.eigen();
if (!mockGeneration)
map_data += (g_data - nmean * map_sel) * bias * growth;
map_W += map_sel * nmean * bias*bias * growth * growth;
}
map_W /= heat;
ctx.print("Finish weights");
// Hmm... I cannot use the vectorized instruction here as it depends on the positivity of map_W[i]. Just do a loop
double tau_inverse = 0; // This is the inverse of minimum covariance
#pragma omp parallel for schedule(static)
for (long n = 0; n < map_W.size(); n++) {
double& val = map_W[n];
if (val > 0) {
if (val > tau_inverse)
tau_inverse = val;
val = 1/val;
} else
val = 0;
}
ctx.print(format("Got partial_tau = %lg") % (1/tau_inverse));
comm->all_reduce(MPI_IN_PLACE, &tau_inverse, 1, translateMPIType<double>(), MPI_MAX);
double tau = 1/tau_inverse;
messenger_tau->value = tau;
if (!mockGeneration)
map_data *= map_W;
else {
for (int c = 0; c < Ncat; c++) {
SelArrayType& sel_field = *state.get<SelArrayType>(format("galaxy_synthetic_sel_window_%d") % c);
double& bias = extract_bias(state, c);
double nmean = state.get<SDouble>(format("galaxy_nmean_%d") % c)->value;
MappedArray map_sel = sel_field.eigen();
ArrayType& s_field = *state.get<ArrayType>("s_field");
ArrayType& g_field = *state.get<ArrayType>(format("galaxy_data_%d") % c);
MappedArray s_data = s_field.eigen();
MappedArray g_data = g_field.eigen();
Eigen::ArrayXd err(map_sel.size());
ctx.print(format("Catalog %d: Generate mock data with nmean = %lg, bias = %lg") % c % nmean % bias);
err = map_sel * nmean;
g_data = err*(1+bias*growth*s_data);
#pragma omp parallel for schedule(static)
for (long i = 0; i < err.size(); i++) {
double E = err[i];
if (E > 0) {
g_data[i] += rng.get().gaussian() * sqrt(E);
} else {
g_data[i] = 0;
}
}
}
}
#pragma omp parallel for schedule(static)
for (long n = 0; n < map_W.size(); n++) {
if (map_W[n] > 0)
map_W[n] = std::max(double(0), map_W[n] - tau);
else
map_W[n] = -1;
}
ctx.print(format("Got tau = %lg") % tau );
}

View file

@ -0,0 +1,102 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/gibbs_messenger.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 __LIBLSS_GIBBS_MESSENGER_HPP
#define __LIBLSS_GIBBS_MESSENGER_HPP
#include <CosmoTool/fourier/fft/fftw_calls.hpp>
#include "libLSS/mpi/generic_mpi.hpp"
#include "libLSS/mcmc/global_state.hpp"
#include "libLSS/tools/fftw_allocator.hpp"
#include "libLSS/samplers/core/markov.hpp"
#include "libLSS/samplers/core/random_number.hpp"
#include "libLSS/samplers/core/types_samplers.hpp"
#include "libLSS/tools/mpi_fftw_helper.hpp"
namespace LibLSS {
namespace GibbsMessenger {
namespace details {
typedef FFTW_Manager_3d<double> FFTMgr;
class MessengerSampler: public MarkovSampler {
protected:
long N0, N1, N2, Ntot, N_k;
long localN0, startN0, localNtot;
ArrayType *messenger_mask, *data_field;
SDouble *messenger_tau;
RandomGen *rng;
bool constrainedGeneration;
MPI_Communication *comm;
FFTMgr *mgr;
public:
MessengerSampler(MPI_Communication *comm);
virtual ~MessengerSampler();
virtual void restore(MarkovState& state);
virtual void initialize(MarkovState& state);
virtual void sample(MarkovState& state);
void setMockGeneration(bool b) { constrainedGeneration = !b; }
};
class MessengerSignalSampler: public MarkovSampler {
protected:
typedef boost::multi_array_ref< IArrayType::ArrayType::element, 1> FlatIntType;
long fourierLocalSize;
FCalls::plan_type analysis_plan, synthesis_plan;
FCalls::complex_type *tmp_fourier, *tmp_fourier_m;
FlatIntType *flat_key;
double volNorm;
long N0, N1, N2, Ntot, Ntot_k, N_k;
long startN0, localN0, localNtot, localNtot_k;
double L0, L1, L2, volume;
ArrayType *tmp_m_field, *x_field, *s_field;
bool constrainedGeneration;
MPI_Communication *comm;
FCalls::real_type *tmp_real_field;
FFTMgr *mgr;
public:
MessengerSignalSampler(MPI_Communication* comm);
virtual ~MessengerSignalSampler();
virtual void restore(MarkovState& state);
virtual void initialize(MarkovState& state);
virtual void sample(MarkovState& state);
void setMockGeneration(bool b) { constrainedGeneration = !b; }
};
class CatalogProjectorSampler: public MarkovSampler {
protected:
int Ncat;
MPI_Communication *comm;
bool mockGeneration;
public:
CatalogProjectorSampler(MPI_Communication *comm0): comm(comm0), mockGeneration(false) {}
virtual void restore(MarkovState& state);
virtual void initialize(MarkovState& state);
virtual void sample(MarkovState& state);
void setMockGeneration(bool b) { mockGeneration = b; }
};
}
}
using GibbsMessenger::details::MessengerSampler;
using GibbsMessenger::details::MessengerSignalSampler;
using GibbsMessenger::details::CatalogProjectorSampler;
}
#endif

View file

@ -0,0 +1,266 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/linbias_sampler.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 <boost/format.hpp>
#include <functional>
#include <cmath>
#include <CosmoTool/algo.hpp>
#include "libLSS/tools/errors.hpp"
#include "libLSS/samplers/core/gig_sampler.hpp"
#include "libLSS/samplers/ares/linbias_sampler.hpp"
#include "libLSS/samplers/rgen/slice_sweep.hpp"
#include "libLSS/samplers/ares/ares_bias.hpp"
#include "libLSS/tools/array_tools.hpp"
#include "boost/lambda/lambda.hpp"
using namespace LibLSS;
using boost::format;
using LibLSS::ARES::extract_bias;
using LibLSS::ARES::ensure_bias_size;
namespace ph = std::placeholders;
void LinearBiasSampler::initialize(MarkovState& state)
{
long N0, N1, N2;
long localN0, startN0;
ConsoleContext<LOG_DEBUG> ctx("initialization of LinearBiasSampler");
// This sampler depends heavily on the rest of the model.
// First grab the number of catalogs available in the markov chain
Ncat = static_cast<SLong&>(state["NCAT"]);
N0 = static_cast<SLong&>(state["N0"]);
localN0 = static_cast<SLong&>(state["localN0"]);
startN0 = static_cast<SLong&>(state["startN0"]);
N1 = static_cast<SLong&>(state["N1"]);
N2 = static_cast<SLong&>(state["N2"]);
Ntot = N0*N1*N2;
localNtot = localN0*N1*N2;
// Ensure that the bias is at least size 1
for (unsigned int c = 0; c < Ncat; c++)
ensure_bias_size(state, c, boost::array<double,1>({1}));
}
void LinearBiasSampler::restore(MarkovState& state)
{
ConsoleContext<LOG_DEBUG> ctx("restoration of LinearBiasSampler");
initialize(state);
}
static inline double logPosteriorBias(double b, double mean, double dev, double heat)
{
if (b < 0)
return -std::numeric_limits<double>::infinity();
double delta = (b-mean)/dev;
return -0.5*delta*delta*heat;
}
void LinearBiasSampler::sample(MarkovState& state)
{
ConsoleContext<LOG_DEBUG> ctx("sampling of mean and bias");
ArrayType& data_field = *state.get<ArrayType>("data_field");
ArrayType& W = *state.get<ArrayType>("messenger_mask");
double *G = state.get<ArrayType>("growth_factor")->array->data();
double *s_field = state.get<ArrayType>("s_field")->array->data();
RandomGen *rng = state.get<RandomGen>("random_generator");
double heat = state.getScalar<double>("ares_heat");
using boost::extents;
using CosmoTool::square;
if (state.get<SBool>("bias_sampler_blocked")->value)
return;
auto ext_Ncat = extents[Ncat];
boost::multi_array<double, 1>
alphas(ext_Ncat), betas(ext_Ncat),
chis(ext_Ncat), psis(ext_Ncat), Npixs(ext_Ncat);
// ---------------------------------------------------------
// Time consuming part, do data reduction per sub-catalog
// We are only computing alphas and betas here.
for (int c = 0; c < Ncat; c++) {
SelArrayType& sel_field = *state.get<SelArrayType>(format("galaxy_synthetic_sel_window_%d") % c);
double *g_field = state.get<ArrayType>(format("galaxy_data_%d") % c)->array->data();
double& bias = extract_bias(state, c);
SDouble *g_nmean = state.get<SDouble>(format("galaxy_nmean_%d") % c);
double nmean = g_nmean->value;
const auto &sel_array = sel_field.array->data();
double loc_alpha = 0, loc_beta = 0, loc_psi = 0, loc_chi = 0, loc_Npix = 0, alpha = 0, beta = 0;
#pragma omp parallel for schedule(dynamic, 1024) reduction(+:loc_alpha,loc_beta,loc_chi,loc_psi,loc_Npix)
for (long i = 0; i < localNtot; i++) {
double selection = sel_array[i];
if (selection > 0) {
double Nobs = g_field[i];
double Dplus = G[i];
double density = s_field[i];
double aux_gamma = 1 + bias * Dplus * density;
loc_beta += selection * nmean * Dplus * Dplus * density * density;
loc_alpha += (Nobs - selection*nmean) * Dplus * density;
loc_chi += Nobs*Nobs/selection;
loc_psi += selection * aux_gamma * aux_gamma;
loc_Npix++;
}
}
// Store the partial result and continue
alphas[c] = loc_alpha;
betas[c] = loc_beta;
chis[c] = loc_chi;
psis[c] = loc_psi;
Npixs[c] = loc_Npix;
}
// Final reduction
ctx.print("Reducing result");
comm->all_reduce_t(MPI_IN_PLACE, alphas.data(), Ncat, MPI_SUM);
comm->all_reduce_t(MPI_IN_PLACE, betas.data(), Ncat, MPI_SUM);
comm->all_reduce_t(MPI_IN_PLACE, chis.data(), Ncat, MPI_SUM);
comm->all_reduce_t(MPI_IN_PLACE, psis.data(), Ncat, MPI_SUM);
comm->all_reduce_t(MPI_IN_PLACE, Npixs.data(), Ncat, MPI_SUM);
ctx.print("Done");
for (int c = 0; c < Ncat; c++) {
double& bias = extract_bias(state, c);
double& nmean = state.get<SDouble>(format("galaxy_nmean_%d") % c)->value;
double alpha = alphas[c], beta = betas[c];
bool biasRef = state.get<SBool>(format("galaxy_bias_ref_%d") % c )->value;
if (comm->rank() == 0 ) {// || comm->size() == 1 ) { // Use another node */
double lambda = 1 - 0.5*Npixs[c];
nmean = GIG_sampler_3params(heat*psis[c],heat*chis[c],lambda,
rng->get());
ctx.print(format("Npix = %d, chi = %lg, psi = %lg") % Npixs[c] % chis[c] % psis[c]);
ctx.print(format("Broadcast value -> nmean = %lg") % nmean);
}
if (!biasRef && comm->rank() == 0) {
double mean_bias = alpha/beta;
double dev_bias = sqrt(1/beta);
Console::instance().c_assert(!std::isinf(mean_bias) && !std::isnan(mean_bias), "Mean is NaN or infinite");
ctx.print(format("bias = %lg, mean_bias = %lg, dev_bias = %lg") % bias % mean_bias % dev_bias);
bias = slice_sweep(rng->get(), std::bind(logPosteriorBias, ph::_1, mean_bias, dev_bias, heat), bias, dev_bias);
Console::instance().c_assert(bias > 0, "Negative bias (0). Ouch!");
}
ctx.print("Sync bias");
// Synchronize all nodes with the new bias value
comm->broadcast_t(&bias, 1, 0);
ctx.print("Sync nmean");
// Synchronize all nodes with the new mean value
comm->broadcast_t(&nmean, 1, 0 );
}
///now improve sampling efficiency by performing a joint step in s,P(k) and biases
///NOTE: the following algorithm MUST be executed in sequence
///get RNG
//only update if power-spectrum is sampled
if (state.getScalar<bool>("power_sampler_a_blocked") &&
state.getScalar<bool>("power_sampler_b_blocked") &&
state.getScalar<bool>("power_sampler_c_blocked"))
return;
RandomGen *rgen = state.get<RandomGen>("random_generator");
double factor = 1.;
if (comm->rank() == 0) {
for (int c = 0; c < Ncat; c++) {
bool biasRef = state.get<SBool>(format("galaxy_bias_ref_%d") % c )->value;
//Don't sample the reference bias
if (biasRef)
continue;
//1) draw random bias realization (b1) for the first catalog
double mean_bias = alphas[c]/betas[c];
double dev_bias = sqrt(1./betas[c]);
double& b0 = extract_bias(state, c);
double b1=b0;
ctx.print(boost::format("Slice sweeping[%d]: mean_bias = %lg, dev_bias = %lg") % c % mean_bias % dev_bias);
b1 = slice_sweep(rng->get(), std::bind(logPosteriorBias, ph::_1, mean_bias, dev_bias, heat), b1, dev_bias);
double fact_virt = b0/b1;
//Now calculate hastings value for the all catalogs but the current one (this sum can be done in parallel)
double dH=0.;
for (int cc = 0; cc < Ncat; cc++) {
if(c!=cc) {
double bb = extract_bias(state, cc);
//Note that we need to operate with the updated density field
//we calculate the metropolis factor of remaining likelihoods with respect to jumps in bias and density field
dH += 2 * (1-fact_virt) * alphas[cc] * factor * bb -
(1-fact_virt*fact_virt) * betas[cc]*square(factor*bb);
}
}
dH *= 0.5*heat;
//now do Metropolis step
double log_u = log(rgen->get().uniform());
if (log_u <= -dH) {
//update accepted bias
b0 = b1;
//also update the density factor
//this accounts for updating the density and power-spectrum fields deterministically
factor *= fact_virt;
// ctx.print(format("Sample accepted for catalog nr. %lg! New bias = %lg , New density factor = %lg") %c % b0 % factor);
}
//if sample is rejected then simply continue
comm->broadcast_t(&b0, 1, 0);
}
} else {
// We are not root, just gather the biases as they are updated
for (int c = 0; c < Ncat; c++) {
bool biasRef = state.get<SBool>(format("galaxy_bias_ref_%d") % c )->value;
//Don't sample the reference bias
if (!biasRef) {
double& b0 = extract_bias(state, c);
// Update from Root rank the value of bias
comm->broadcast_t(&b0, 1, 0);
}
}
}
// Broadcast and gather the scaling factor
comm->broadcast_t(&factor, 1, 0);
//Finally we just need to rescale the density and power-spectrum fields by "factor"
//1) scale density field in real and Fourier space
array::scaleArray3d(*state.get<ArrayType>("s_field")->array, factor);
//2) scale power-spectrum
ArrayType1d::ArrayType& P_info = *state.get<ArrayType1d>("powerspectrum")->array;
LibLSS::copy_array(P_info, b_fused<double>(P_info, (factor*factor)*boost::lambda::_1));
}

View file

@ -0,0 +1,36 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/linbias_sampler.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 __LIBLSS_LINEAR_BIAS_SAMPLER_HPP
#define __LIBLSS_LINEAR_BIAS_SAMPLER_HPP
#include <boost/multi_array.hpp>
#include "libLSS/samplers/core/markov.hpp"
#include "libLSS/samplers/core/types_samplers.hpp"
namespace LibLSS {
class LinearBiasSampler: public MarkovSampler {
protected:
int Ncat;
long Ntot, localNtot;
boost::multi_array<SDouble *, 1> biases;
MPI_Communication *comm;
public:
LinearBiasSampler(MPI_Communication *comm0) : comm(comm0) {}
virtual ~LinearBiasSampler() {}
virtual void initialize(MarkovState& state);
virtual void restore(MarkovState& state);
virtual void sample(MarkovState& state);
};
}
#endif

View file

@ -0,0 +1,142 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/powerspectrum_a_sampler.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 <cmath>
#include "libLSS/tools/console.hpp"
#include "libLSS/samplers/ares/powerspectrum_a_sampler.hpp"
#include "libLSS/mcmc/state_element.hpp"
#include "libLSS/samplers/core/powerspec_tools.hpp"
#include "libLSS/tools/mpi_fftw_helper.hpp"
using namespace LibLSS;
void PowerSpectrumSampler_a::base_init()
{
ConsoleContext<LOG_DEBUG> ctx("base_init");
ctx.print(boost::format("Allocating Fourier buffer %dx%dx%d") % N0 % N1 % N2_HC);
tmp_fourier = MFCalls::alloc_complex(fourierLocalSize);
tmp_s = MFCalls::alloc_real(2*fourierLocalSize);
assert(tmp_fourier != 0);
ctx.print(boost::format("Fourier buffer %p") % tmp_fourier);
ctx.print(boost::format("Allocating plan %dx%dx%d") % N0 % N1 % N2);
analysis_plan = MFCalls::plan_dft_r2c_3d(
N0, N1, N2,
tmp_s,
(FCalls::complex_type *)tmp_fourier,
#ifdef ARES_MPI_FFTW
comm->comm(),
#endif
//FFTW_MPI_TRANSPOSED_OUT|
FFTW_DESTROY_INPUT|FFTW_MEASURE);
flat_keys = new FlatIntType(keys->array->data(), boost::extents[keys->array->num_elements()] );
}
void PowerSpectrumSampler_a::restore(MarkovState& state)
{
ConsoleContext<LOG_INFO> ctx("restoration of power spectrum sampler (a)");
restore_base(state);
base_init();
}
void PowerSpectrumSampler_a::initialize(MarkovState& state)
{
ConsoleContext<LOG_INFO> ctx("initialization of power spectrum sampler (a)");
initialize_base(state);
base_init();
}
PowerSpectrumSampler_a::PowerSpectrumSampler_a(MPI_Communication *comm0)
: PowerSpectrumSampler_Base(comm0), tmp_fourier(0), flat_keys(0), tmp_s(0)
{
}
PowerSpectrumSampler_a::~PowerSpectrumSampler_a()
{
if (tmp_fourier) {
Console::instance().print<LOG_INFO>("Cleaning up Powerspectrum sampler (a)");
MFCalls::free(tmp_fourier);
MFCalls::destroy_plan(analysis_plan);
delete flat_keys;
}
if (tmp_s)
MFCalls::free(tmp_s);
}
void PowerSpectrumSampler_a::sample(MarkovState& state)
{
// Grab the messenger field
ConsoleContext<LOG_DEBUG> ctx("PowerSpectrumSampler_a::sample");
Console& cons = Console::instance();
ArrayType& s_field = static_cast<ArrayType&>(state["s_field"]);
//return;
IArrayType1d::ArrayType& nmode_array = *nmode->array;
ArrayType1d::ArrayType& P_array = *P->array;
if (state.get<SBool>("power_sampler_a_blocked")->value)
return;
copy_padded_data(*s_field.array, tmp_s);
MFCalls::execute(analysis_plan);
ctx.print("Compute inverse-gamma parameter");
std::fill(P_array.begin(), P_array.end(), 0);
ctx.print(boost::format("N_fourier_elements = %d") % N_fourier_elements);
int *adjust = adjustMul->array->data();
//#pragma omp parallel for schedule(static)
for (long i = 0; i < local_fourier_elements; i++) {
FCalls::complex_type& m_hat = tmp_fourier[i];
double Pelt = m_hat[0]*m_hat[0] + m_hat[1]*m_hat[1];
// adjust increase memory bandwidth consumption. Not great...
// OTOH it is very convenient and this loop is not the most time consuming aspect
P_array[ (*flat_keys)[i] ] += adjust[i] * Pelt;
}
P_sync.mpiAllSum(*comm);
ctx.print("Sample new power spectrum");
const int alpha=1; ///Jeffreys prior
// Only compute random numbers on rank==0, broadcast after
if (comm->rank() == 0) {
#pragma omp parallel for schedule(static)
for(long l = 0; l < N_k; l++) {
if(nmode_array[l] > 0) {
int beta = (2*alpha-2) + nmode_array[l];
///generate CHi-SQUARE sample
double z2 = 0.;
for(int j = 0; j < beta; j++) {
double aux=rgen->get().gaussian();
z2 += aux*aux;
}
///calculate power-spectrum sample
P_array[l] = (P_array[l]/z2) * volNorm / Ntot;
}
}
}
P_sync.mpiBroadcast(*comm);
}

View file

@ -0,0 +1,41 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/powerspectrum_a_sampler.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 __LIBLSS_POWERSPECTRUM_A_SAMPLER_HPP
#define __LIBLSS_POWERSPECTRUM_A_SAMPLER_HPP
#include "libLSS/mpi/generic_mpi.hpp"
#include "libLSS/samplers/core/markov.hpp"
#include "libLSS/samplers/core/types_samplers.hpp"
#include "libLSS/samplers/core/powerspec_tools.hpp"
namespace LibLSS {
class PowerSpectrumSampler_a: public PowerSpectrumSampler_Base {
protected:
typedef boost::multi_array_ref< IArrayType::ArrayType::element, 1> FlatIntType;
FCalls::complex_type *tmp_fourier;
FCalls::plan_type analysis_plan;
FlatIntType *flat_keys;
MFCalls::real_type *tmp_s;
void base_init();
public:
PowerSpectrumSampler_a(MPI_Communication *comm);
virtual ~PowerSpectrumSampler_a();
virtual void restore(MarkovState& state);
virtual void initialize(MarkovState& state);
virtual void sample(MarkovState& state);
};
}
#endif

View file

@ -0,0 +1,217 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/powerspectrum_b_sampler.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 <CosmoTool/algo.hpp>
#include <cmath>
#include "libLSS/tools/console.hpp"
#include "libLSS/mcmc/state_element.hpp"
#include "libLSS/samplers/core/powerspec_tools.hpp"
#include "libLSS/samplers/ares/powerspectrum_b_sampler.hpp"
#include "libLSS/tools/mpi_fftw_helper.hpp"
using boost::format;
using namespace LibLSS;
PowerSpectrumSampler_b::PowerSpectrumSampler_b(MPI_Communication *comm0)
: PowerSpectrumSampler_Coloring(comm0),
tmp_fourier(0), P0_array(boost::extents[0]), P1_array(boost::extents[0]),
tmp_x(0), tmp_t(0), total_accepted(0), total_tried(0), flat_keys(0)
{
}
PowerSpectrumSampler_b::~PowerSpectrumSampler_b()
{
if (tmp_fourier) {
Console::instance().print<LOG_INFO>("Cleaning up Powerspectrum sampler (b)");
Console::instance().print<LOG_DEBUG>(format("tmp_fourier=%p tmp_fourier=%p") % tmp_fourier % tmp_fourier_t);
FCalls::free(tmp_fourier);
FCalls::free(tmp_fourier_t);
FCalls::destroy_plan(analysis_plan);
}
if (tmp_x)
MFCalls::free(tmp_x);
if (tmp_t)
MFCalls::free(tmp_t);
if (flat_keys)
delete flat_keys;
}
void PowerSpectrumSampler_b::base_init(MarkovState& state)
{
ConsoleContext<LOG_DEBUG> ctx("base init");
ctx.print(boost::format("Allocating Fourier buffer %dx%dx%d (sz=%d)") % localN0 % N1 % N2_HC % fourierLocalSize);
tmp_fourier = MFCalls::alloc_complex(fourierLocalSize);
tmp_fourier_t = MFCalls::alloc_complex(fourierLocalSize);
tmp_x = MFCalls::alloc_real(2*fourierLocalSize);
tmp_t = MFCalls::alloc_real(2*fourierLocalSize);
P0_array.resize(boost::extents[N_k]);
P1_array.resize(boost::extents[N_k]);
ctx.print(boost::format("Fourier buffer %p") % tmp_fourier);
ctx.print(boost::format("Allocating plan %dx%dx%d") % N0 % N1 % N2);
analysis_plan = MFCalls::plan_dft_r2c_3d(
N0, N1, N2,
tmp_x,
tmp_fourier,
#ifdef ARES_MPI_FFTW
comm->comm(),
#endif
//FFTW_MPI_TRANSPOSED_OUT|
FFTW_DESTROY_INPUT|FFTW_MEASURE);
flat_keys = new FlatIntType(keys->array->data(), boost::extents[keys->array->num_elements()] );
state.newElement("sampler_b_accepted", new SLong());
state.newElement("sampler_b_tried", new SLong());
}
void PowerSpectrumSampler_b::restore(MarkovState& state)
{
ConsoleContext<LOG_INFO> ctx("restoration of power spectrum sampler (b)");
ctx.print("Restoring power spectrum sampler (b)");
restore_base(state);
restore_coloring(state);
base_init(state);
}
void PowerSpectrumSampler_b::initialize(MarkovState& state)
{
ConsoleContext<LOG_INFO> ctx("initialization of power spectrum sampler (b)");
Console& cons = Console::instance();
initialize_base(state);
initialize_coloring(state);
base_init(state);
state.get<SLong>("sampler_b_accepted")->value = 0;
state.get<SLong>("sampler_b_tried")->value = 0;
}
void PowerSpectrumSampler_b::sample(MarkovState& state)
{
// Grab the messenger field
ConsoleContext<LOG_DEBUG> ctx("sampling of power spectrum (b)");
Console& cons = Console::instance();
ArrayType& x_field = static_cast<ArrayType&>(state["x_field"]);
ArrayType& t_field = static_cast<ArrayType&>(state["messenger_field"]);
RandomGen *rng = state.get<RandomGen>("random_generator");
IArrayType1d::ArrayType& nmode_array = *nmode->array;
ArrayType1d::ArrayType& P_array = *P->array;
SDouble *messenger_tau = state.get<SDouble>("messenger_tau");
double tau = messenger_tau->value;
long localNtot = localN0*N1*N2;
if (state.get<SBool>("power_sampler_b_blocked")->value)
return;
#ifdef ARES_MPI_FFTW
copy_padded_data(*x_field.array, tmp_x);
copy_padded_data(*t_field.array, tmp_t);
#else
::memcpy(tmp_x, x_field.array->data(), Ntot * sizeof(MFCalls::real_type));
::memcpy(tmp_t, t_field.array->data(), Ntot * sizeof(MFCalls::real_type));
#endif
ctx.print("Fourier analysis (1)");
MFCalls::execute(analysis_plan);
ctx.print("Fourier analysis (2)");
MFCalls::execute_r2c(analysis_plan, tmp_t, tmp_fourier_t);
ctx.print("Compute inverse-gamma parameter");
ctx.print(boost::format("local_fourier_elements = %d") % local_fourier_elements);
int *adjust = adjustMul->array->data();
std::fill(P0_array.begin(), P0_array.end(), 0);
std::fill(P1_array.begin(), P1_array.end(), 0);
//#pragma omp parallel for schedule(static)
for (long i = 0; i < local_fourier_elements; i++) {
FCalls::complex_type& x_hat = tmp_fourier[i];
FCalls::complex_type& t_hat = tmp_fourier_t[i];
double Pelt_cross = x_hat[0]*t_hat[0] + x_hat[1]*t_hat[1];
double Pelt_auto = x_hat[0]*x_hat[0] + x_hat[1]*x_hat[1];
// adjust increase memory bandwidth consumption. Not great...
// OTOH it is very convenient and this loop is not the most time consuming aspect
P0_array[ (*flat_keys)[i] ] += adjust[i] * Pelt_cross;
P1_array[ (*flat_keys)[i] ] += adjust[i] * Pelt_auto;
}
// No helper function written here. Ask MPI to reduce the arrays in-place.
comm->all_reduce_t(MPI_IN_PLACE, P0_array.data(), P0_array.num_elements(),
MPI_SUM);
comm->all_reduce_t(MPI_IN_PLACE, P1_array.data(), P1_array.num_elements(),
MPI_SUM);
int accepted = 0, tried = 0;
double normalization = tau * Ntot;
if (comm->rank() == 0) {
ctx.print("Accumulated, now create plausible sample");
#pragma omp parallel for schedule(static) reduction(+:accepted,tried)
for (int i = 0; i < N_k; i++) {
if (P1_array[i] > 0) {
double s = 1/P1_array[i];
P0_array[i] *= s;
P1_array[i] = sqrt(s * normalization);
} else {
continue;
}
double u0 = sqrt(P_array[i] * volume);
double u1 = -1;
double mean = P0_array[i];
double sigma = P1_array[i];
assert(!std::isnan(u0));
assert(!std::isnan(mean));
assert(!std::isnan(sigma));
ctx.print(format(" k = %lg, mean = %lg, sigma = %lg") % (*k->array)[i]% mean % sigma);
if (mean < 0) mean = 0;
while(u1 < 0)
u1 = mean + sigma*rng->get().gaussian(); ///NOTE: sample from truncated Gaussian
double PA = u1/u0;
if(PA>1.)
PA=1.;
double u = rng->get().uniform();
if (u < PA) {
P_array[i] = u1*u1 / volume;
accepted++;
}
tried++;
}
}
ctx.print("Broadcast data");
P_sync.mpiBroadcast(*comm);
total_accepted += accepted;
total_tried += tried;
// Force update s_field with the new P
update_s_field_from_x(state);
state.get<SLong>("sampler_b_accepted")->value = total_accepted;
state.get<SLong>("sampler_b_tried")->value = total_tried;
if (comm->rank() == 0)
Console::instance().print<LOG_VERBOSE>(format("PSpec sampler (b) total acceptance ratio: %2.0f %%") % (double(total_accepted)*100/total_tried));
}

View file

@ -0,0 +1,44 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/powerspectrum_b_sampler.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 __LIBLSS_POWERSPECTRUM_B_SAMPLER_HPP
#define __LIBLSS_POWERSPECTRUM_B_SAMPLER_HPP
#include "libLSS/mpi/generic_mpi.hpp"
#include "libLSS/samplers/core/markov.hpp"
#include "libLSS/samplers/core/types_samplers.hpp"
#include "libLSS/samplers/core/powerspec_tools.hpp"
namespace LibLSS {
class PowerSpectrumSampler_b: public PowerSpectrumSampler_Coloring {
protected:
typedef boost::multi_array_ref< IArrayType::ArrayType::element, 1> FlatIntType;
MFCalls::complex_type *tmp_fourier, *tmp_fourier_t;
MFCalls::real_type *tmp_x, *tmp_t;
MFCalls::plan_type analysis_plan;
FlatIntType *flat_keys;
int total_accepted, total_tried;
ArrayType1d::ArrayType P0_array, P1_array;
void base_init(MarkovState& state);
public:
PowerSpectrumSampler_b(MPI_Communication *comm);
virtual ~PowerSpectrumSampler_b();
virtual void restore(MarkovState& state);
virtual void initialize(MarkovState& state);
virtual void sample(MarkovState& state);
};
}
#endif

View file

@ -0,0 +1,196 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/powerspectrum_c_sampler.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 <sstream>
#include <fstream>
#include <iostream>
#include <CosmoTool/algo.hpp>
#include <functional>
#include <cmath>
#include "libLSS/tools/console.hpp"
#include "libLSS/mcmc/state_element.hpp"
#include "libLSS/samplers/core/powerspec_tools.hpp"
#include "libLSS/samplers/ares/powerspectrum_c_sampler.hpp"
#include "libLSS/tools/mpi_fftw_helper.hpp"
#include "libLSS/samplers/rgen/slice_sweep.hpp"
#include "libLSS/samplers/ares/ares_bias.hpp"
static const int ROOT = 0;
static const size_t LARGE_SCALE_MODE_COUNT=14;
using boost::format;
using namespace LibLSS;
using LibLSS::ARES::extract_bias;
namespace ph = std::placeholders;
PowerSpectrumSampler_c::PowerSpectrumSampler_c(MPI_Communication *comm0)
: PowerSpectrumSampler_Coloring(comm0), counter_evaluations(0)
{
}
PowerSpectrumSampler_c::~PowerSpectrumSampler_c()
{
}
void PowerSpectrumSampler_c::base_init(MarkovState& state)
{
ConsoleContext<LOG_DEBUG> ctx("base init");
Ncatalog = state.get<SLong>("NCAT")->value;
localNtot = localN0 * N1 * N2;
// Create a counter reinitialized at each save that look at the number of posterior evaluation
// required for each mode
counter_evaluations = new IArrayType1d(boost::extents[P->array->num_elements()]);
state.newElement("spectrum_c_eval_counter", counter_evaluations, true);
counter_evaluations->setResetOnSave(0);
counter_evaluations->fill(0);
sigma_init = new ArrayType1d(boost::extents[P->array->num_elements()]);
state.newElement("spectrum_c_init_sigma", sigma_init);
sigma_init->fill(0);
}
void PowerSpectrumSampler_c::restore(MarkovState& state)
{
ConsoleContext<LOG_INFO> ctx("restoration of power spectrum sampler (b)");
ctx.print("Restoring power spectrum sampler (b)");
restore_base(state);
restore_coloring(state);
base_init(state);
init_sampler = false;
}
void PowerSpectrumSampler_c::initialize(MarkovState& state)
{
ConsoleContext<LOG_INFO> ctx("initialization of power spectrum sampler (c)");
Console& cons = Console::instance();
initialize_base(state);
initialize_coloring(state);
base_init(state);
init_sampler = true;
}
double PowerSpectrumSampler_c::log_likelihood(MarkovState& state, int k, double P_trial)
{
// Reuse system power spectrum
//
if (P_trial < 0)
return -std::numeric_limits<double>::infinity();
(*P->array)[k] = P_trial;
update_s_field_from_x(state, (*P));
// Now compute full likelihood
double *s = state.get<ArrayType>("s_field")->array->data();
double heat = state.getScalar<double>("ares_heat");
double L = 0, loc_L = 0;
for (int c = 0; c < Ncatalog; c++) {
double Lc = 0;
SelArrayType& sel_field = *state.get<SelArrayType>(format("galaxy_synthetic_sel_window_%d") % c);
ArrayType& g_field = *state.get<ArrayType>(format("galaxy_data_%d") % c);
double bias = extract_bias(state, c);
double nmean = state.get<SDouble>(format("galaxy_nmean_%d") % c)->value;
double *R = sel_field.array->data();
double *gdata = g_field.array->data();
//#pragma omp simd aligned(s,R,gdata)
#pragma omp parallel for schedule(static) reduction(+:Lc)
for (long i = 0; i < localNtot; i++) {
if (R[i] <= 0)
continue;
Lc += CosmoTool::square(gdata[i] - nmean * R[i] * (1 + bias * s[i])) / (R[i]*nmean);
}
loc_L += Lc;
}
comm->reduce_t(&loc_L, &L, 1, MPI_SUM, ROOT);
// if (comm->rank() == 0)
// Console::instance().print<LOG_INFO>(format("Likelihood(P=%lg) = %lg") % P_trial % L);
// o << format("%15.15lg %15.15lg")%P_trial %L<< std::endl;
(*counter_evaluations->array)[k]++;
return -0.5*heat*L - std::log(P_trial);
}
void PowerSpectrumSampler_c::sample(MarkovState& state)
{
// Grab the messenger field
ConsoleContext<LOG_INFO_SINGLE> ctx("sampling of power spectrum (c)");
Console& cons = Console::instance();
ArrayType& x_field = static_cast<ArrayType&>(state["x_field"]);
RandomGen *rng = state.get<RandomGen>("random_generator");
IArrayType1d::ArrayType& nmode_array = *nmode->array;
ArrayType1d::ArrayType& P_array = *P->array;
long localNtot = localN0*N1*N2;
long step = state.get<SLong>("MCMC_STEP")->value;
if (state.get<SBool>("power_sampler_c_blocked")->value)
return;
if ((step % 10) != 0) {
return;
}
ctx.print("Fourier analysis (1)");
copy_padded_data(*x_field.array, tmp_real);
MFCalls::execute_r2c(analysis_plan, tmp_real, tmp_fourier);
int *counts = key_counts->array->data();
ArrayType1d::ArrayType& sigma_init_array = *sigma_init->array;
if (init_sampler) {
ctx.print("initial guess for the step for slice sampler...");
for (long i = 0 ; i < P_array.size() ; i++) {
if (counts[i] == 0)
sigma_init_array[i] = 0;
else
sigma_init_array[i] = (P_array[i]) / std::sqrt(double(counts[i]));
}
init_sampler = false;
}
for (int i = 0; i < std::min(LARGE_SCALE_MODE_COUNT, P_array.size()); i++) {
// std::string fname = str(format("P_k_%d.txt") % i);
// std::ofstream f(fname.c_str());
// Skip zero mode
if (counts[i] == 0)
continue;
double cosmic_var = sigma_init_array[i];
ctx.print(format("Finding P_array(k=%d / %d) cvar=%g") % i % P_array.size() % cosmic_var);
auto posterior_fun =
std::bind(&PowerSpectrumSampler_c::log_likelihood,
this, boost::ref(state), i, ph::_1);
// We need the slice_sweep_double algo here. Cosmic var tends to quite underestimate
// the width of the posterior
if (cosmic_var >0)
P_array[i] =
slice_sweep_double(comm, rng->get(),
posterior_fun,
P_array[i], cosmic_var);
comm->broadcast_t(&P_array[i], 1, ROOT);
}
update_s_field_from_x(state);
}

View file

@ -0,0 +1,47 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/powerspectrum_c_sampler.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 __LIBLSS_POWERSPECTRUM_C_SAMPLER_HPP
#define __LIBLSS_POWERSPECTRUM_C_SAMPLER_HPP
#include <iostream>
#include "libLSS/mpi/generic_mpi.hpp"
#include "libLSS/samplers/core/markov.hpp"
#include "libLSS/samplers/core/types_samplers.hpp"
#include "libLSS/samplers/core/powerspec_tools.hpp"
namespace LibLSS {
class PowerSpectrumSampler_c: public PowerSpectrumSampler_Coloring {
protected:
typedef boost::multi_array_ref< IArrayType::ArrayType::element, 1> FlatIntType;
long localNtot;
int total_accepted, total_tried;
bool init_sampler;
IArrayType1d *counter_evaluations;
ArrayType1d *sigma_init;
void base_init(MarkovState& state);
double log_likelihood(MarkovState& state, int k, double P_trial);
public:
PowerSpectrumSampler_c(MPI_Communication *comm);
virtual ~PowerSpectrumSampler_c();
virtual void restore(MarkovState& state);
virtual void initialize(MarkovState& state);
virtual void sample(MarkovState& state);
};
}
#endif

View file

@ -0,0 +1,102 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/synthetic_selection.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 <boost/format.hpp>
#include "libLSS/tools/errors.hpp"
#include "libLSS/samplers/core/gig_sampler.hpp"
#include "libLSS/samplers/ares/synthetic_selection.hpp"
#include "libLSS/tools/fused_array.hpp"
#include "libLSS/tools/fused_assign.hpp"
using namespace LibLSS;
using boost::format;
using boost::extents;
typedef boost::multi_array_types::extent_range range;
void SyntheticSelectionUpdater::initialize(MarkovState& state)
{
long N0, N1, N2;
long localN0, startN0;
long localNdata[6], Ndata[3];
ConsoleContext<LOG_DEBUG> ctx("initialization of Selection updater");
Ncat = static_cast<SLong&>(state["NCAT"]);
N0 = static_cast<SLong&>(state["N0"]);
localN0 = static_cast<SLong&>(state["localN0"]);
startN0 = static_cast<SLong&>(state["startN0"]);
N1 = static_cast<SLong&>(state["N1"]);
N2 = static_cast<SLong&>(state["N2"]);
state.getScalarArray<long,3>("Ndata", Ndata);
state.getScalarArray<long,6>("localNdata", localNdata);
Ntot = N0*N1*N2;
localNtot = localN0*N1*N2;
for (int c = 0; c < Ncat; c++) {
SelArrayType *sel_window;
state.newElement(format("galaxy_synthetic_sel_window_%d") % c,
sel_window = new SelArrayType(extents[range(localNdata[0],localNdata[1])][range(localNdata[2],localNdata[3])][range(localNdata[4],localNdata[5])]));
sel_window->setRealDims(ArrayDimension(Ndata[0], Ndata[1], Ndata[2]));
}
}
void SyntheticSelectionUpdater::restore(MarkovState& state)
{
initialize(state);
}
void SyntheticSelectionUpdater::sample(MarkovState& state)
{
ConsoleContext<LOG_VERBOSE> ctx("processing of 3d selection (including foregrounds)");
for (int c = 0; c < Ncat; c++) {
SelArrayType *original_selection_grid = state.get<SelArrayType>(format("galaxy_sel_window_%d") % c);
SelArrayType *sel_grid = state.get<SelArrayType>(format("galaxy_synthetic_sel_window_%d") % c);
IArrayType1d *fgmap = state.get<IArrayType1d>(format("catalog_foreground_maps_%d") % c);
ArrayType1d *fgvals = state.get<ArrayType1d>(format("catalog_foreground_coefficient_%d") % c);
int NcatForegrounds = fgmap->array->num_elements();
ctx.format("Copy initial selection for catalog %d", c);
sel_grid->eigen() = original_selection_grid->eigen();
for (int f = 0; f < NcatForegrounds; f++) {
int c = (*fgmap->array)[f];
double val = (*fgvals->array)[f];
ctx.print(format("Applying foreground %d (value %lg) to selection of catalog %d") % f % val % c);
ArrayType *fgField = state.get<ArrayType>(format("foreground_3d_%d") % (c));
auto mergingFunction = [val](double s,double f) { return s*(1 - f * val); };
// copy_array is parallelized, hopefully later vectorized
if (f == 0) {
LibLSS::copy_array(*sel_grid->array,
b_fused<double>(*original_selection_grid->array,
*fgField->array,
mergingFunction
)
);
} else {
LibLSS::copy_array(*sel_grid->array,
b_fused<double>(*sel_grid->array,
*fgField->array,
mergingFunction
)
);
}
}
}
}

View file

@ -0,0 +1,33 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/ares/synthetic_selection.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 __LIBLSS_SYNTHETIC_SELECTION_UPDATER_HPP
#define __LIBLSS_SYNTHETIC_SELECTION_UPDATER_HPP
#include <boost/multi_array.hpp>
#include "libLSS/samplers/core/markov.hpp"
#include "libLSS/samplers/core/types_samplers.hpp"
namespace LibLSS {
class SyntheticSelectionUpdater: public MarkovSampler {
protected:
int Ncat;
long Ntot, localNtot;
public:
virtual void initialize(MarkovState& state);
virtual void restore(MarkovState& state);
virtual void sample(MarkovState& state);
};
};
#endif

View file

@ -0,0 +1,25 @@
inline double RandomNumber::gaussian_ratio()
{
double u, v, x, y, Q;
const double s = 0.449871; /* Constants from Leva */
const double t = -0.386595;
const double a = 0.19600;
const double b = 0.25472;
const double r1 = 0.27597;
const double r2 = 0.27846;
do {
u = 1 - uniform();
v = uniform() - 0.5;
v *= 1.7156;
x = u - s;
y = std::abs(v) - t;
Q = x * x + y * (a * y - b * x);
}
while (Q >= r1 && (Q > r2 || (v*v) > (-4*u*u*log(u)) ) );
return v/u;
}

View file

@ -0,0 +1,105 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iomanip>
#include <math.h>
#include <cassert>
#include <iostream>
#include <fstream>
#include <cfloat>
#include <string>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include "gig_sampler.hpp"
using namespace std;
using namespace LibLSS;
static double psi(double x, double alpha, double lambd)
{
return (-alpha*(cosh(x) -1.)-lambd*(exp(x)-x-1.));
}
static double psi_prime(double x, double alpha,double lambd)
{
return (-alpha*sinh(x)-lambd*(exp(x)-1.));
}
static double GIG_sampler_Devroy(double lambd, double omega, RandomNumber& rng)
{
double alpha=sqrt(omega*omega+lambd*lambd)-lambd;
double psi0=psi(1.,alpha,lambd);
double psi1=psi(-1.,alpha,lambd);
double rho=4.;
double t=sqrt(2.*rho/(alpha+lambd));
rho=psi(t,alpha,lambd);
double taux=t;
taux=(-taux+(rho-psi(-taux,alpha,lambd))/psi_prime(-taux,alpha,lambd))*(-1.);
taux=(-taux+(rho-psi(-taux,alpha,lambd))/psi_prime(-taux,alpha,lambd))*(-1.);
taux=(-taux+(rho-psi(-taux,alpha,lambd))/psi_prime(-taux,alpha,lambd))*(-1.);
taux=(-taux+(rho-psi(-taux,alpha,lambd))/psi_prime(-taux,alpha,lambd))*(-1.);
double s=(-taux+(rho-psi(-taux,alpha,lambd))/psi_prime(-taux,alpha,lambd))*(-1.);
double eta = -psi(t,alpha,lambd);
double theta = -psi_prime(t,alpha,lambd);
double phi = -psi(-s,alpha,lambd);
double xi = psi_prime(-s,alpha,lambd);
double p = 1./xi;
double r = 1./theta;
double t_prime = t-r*eta;
double s_prime = s-p*phi;
double q = t_prime+s_prime;
double X=0.;
double chi=0.;
while(true)
{
double U=rng.uniform();
double V=rng.uniform();
double W=rng.uniform();
if(U<q/(p+q+r))
{
X=-s_prime+q*V;
chi=0.;
}
else if (U<(q+r)/(p+q+r))
{
X=t_prime+r*log(1./V);
chi=(-eta-theta*(X-t));
}
else
{
X=-s_prime-p*log(1./V);
chi=(-phi+xi*(X+s));
}
if (log(W)+chi <= (psi(X,alpha,lambd))) break;
}
return ((lambd/omega+sqrt(1.+lambd*lambd/omega/omega))*exp(X));
}
double LibLSS::GIG_sampler_3params(double a,double b,double p, RandomNumber& rng)
{
///this routine provides samples of the three parameter Generalized Inverse Gaussian (GIG) distribution
/// log(P)=-1./2.*(x*a+b*power(x,-1.)) + (p-1.)*log(x)
double lambd=p;
double omega=sqrt(b*a);
//one only needs to draw for lambda>0 see Devroy 2014
double X=0.;
if(lambd>0.)
X=GIG_sampler_Devroy(lambd,omega,rng);
else
X=1./GIG_sampler_Devroy(-lambd,omega,rng);
return sqrt(b/a)*X;
}

View file

@ -0,0 +1,19 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/core/gig_sampler.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 __LSS_GIG_SAMPLER_HPP
#define __LSS_GIG_SAMPLER_HPP
#include "random_number.hpp"
namespace LibLSS {
double GIG_sampler_3params(double a,double b,double p, RandomNumber& rng);
}
#endif

View file

@ -0,0 +1,122 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/core/main_loop.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/tools/console.hpp"
#include "libLSS/samplers/core/main_loop.hpp"
#include "libLSS/tools/timing_db.hpp"
using namespace LibLSS;
using std::string;
MainLoop::MainLoop() {
show_splash();
mcmc_id = 0;
}
MainLoop::~MainLoop() {}
void MainLoop::show_splash() {}
void MainLoop::initialize() {
Console &cons = Console::instance();
cons.print<LOG_STD>("Initializing samplers");
cons.indent();
for (MCList::iterator i = mclist.begin(); i != mclist.end(); ++i) {
i->first->init_markov(state);
}
cons.unindent();
cons.print<LOG_STD>("Done");
}
void MainLoop::snap() {
using boost::format;
using boost::str;
MPI_Communication *comm = MPI_Communication::instance();
std::shared_ptr<H5::H5File> f;
if (comm->rank() == 0) {
f = std::make_shared<H5::H5File>(
str(format("mcmc_%d.h5") % mcmc_id), H5F_ACC_TRUNC);
}
state.mpiSaveState(f, comm, false, true);
mcmc_id++;
}
void MainLoop::save() {
using boost::format;
using boost::str;
MPI_Communication *comm = MPI_Communication::instance();
string fname_final = str(format("restart.h5_%d") % comm->rank());
string fname_build = fname_final + "_build";
{
H5::H5File f(fname_build, H5F_ACC_TRUNC);
state.saveState(f);
timings::save(f);
}
comm->barrier();
rename(fname_build.c_str(), fname_final.c_str());
}
void MainLoop::save_crash() {
using boost::format;
using boost::str;
MPI_Communication *comm = MPI_Communication::instance();
string fname_final = str(format("crash_file.h5_%d") % comm->rank());
string fname_build = fname_final + "_build";
{
H5::H5File f(fname_build, H5F_ACC_TRUNC);
state.saveState(f);
}
rename(fname_build.c_str(), fname_final.c_str());
}
void MainLoop::run() {
ConsoleContext<LOG_STD> ctx("MainLoop::run");
int count = 0;
Progress<LOG_STD> progress = Console::instance().start_progress<LOG_STD>(
"Main loop iteration", mclist.size(), 30);
for (MCList::iterator i = mclist.begin(); i != mclist.end(); ++i) {
int looping = i->second;
for (int j = 0; j < looping; j++)
i->first->sample(state);
count++;
progress.update(count);
}
progress.destroy();
}
void MainLoop::restore(const std::string &fname, bool flexible) {
Console &cons = Console::instance();
MPI_Communication *comm = MPI_Communication::instance();
string fname_full =
flexible ? fname
: (boost::str(boost::format("%s_%d") % fname % comm->rank()));
H5::H5File f(fname_full, 0);
ConsoleContext<LOG_INFO> ctx("restoration of MCMC state");
if (flexible)
Console::instance().print<LOG_WARNING>("Using flexible mechanism");
ctx.print("Initialize variables");
for (MCList::iterator i = mclist.begin(); i != mclist.end(); ++i) {
i->first->restore_markov(state);
}
ctx.print("Load markov state from file");
{ state.restoreState(f, flexible); }
timings::load(f);
}

View file

@ -0,0 +1,109 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/core/main_loop.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 __LIBLSS_SAMPLERS_MAINLOOP_HPP
#define __LIBLSS_SAMPLERS_MAINLOOP_HPP
#include <utility>
#include <list>
#include "libLSS/tools/console.hpp"
#include "libLSS/samplers/core/markov.hpp"
#include "libLSS/mcmc/global_state.hpp"
namespace LibLSS {
class BlockLoop;
class BlockSampler {
public:
typedef std::list<std::pair<std::shared_ptr<MarkovSampler>,int> > MCList;
protected:
MCList mclist;
friend class BlockLoop;
public:
virtual void adder(BlockSampler& s) const {
ConsoleContext<LOG_DEBUG> ctx("adder classic");
s.mclist.insert(s.mclist.end(), mclist.begin(), mclist.end());
}
BlockSampler& operator<<(std::shared_ptr<MarkovSampler>&& s) {
ConsoleContext<LOG_DEBUG> ctx("inserter shared_ptr");
mclist.push_back(std::make_pair(s,1));
return *this;
}
BlockSampler& operator<<(std::shared_ptr<MarkovSampler>& s) {
ConsoleContext<LOG_DEBUG> ctx("inserter shared_ptr");
mclist.push_back(std::make_pair(s,1));
return *this;
}
BlockSampler& operator<<(MarkovSampler& s) {
ConsoleContext<LOG_DEBUG> ctx("inserter");
mclist.push_back(std::make_pair(std::shared_ptr<MarkovSampler>(&s, [](void *) {}), 1));
return *this;
}
BlockSampler& operator<<(const BlockSampler& l) {
ConsoleContext<LOG_DEBUG> ctx("adding block");
l.adder(*this);
return *this;
}
};
class BlockLoop: public BlockSampler {
private:
int num_loop;
protected:
friend class BlockSampler;
// Prevent any copy.
BlockLoop(const BlockLoop& l) {
num_loop = l.num_loop;
}
BlockLoop& operator=(const BlockLoop& l) { return *this; }
public:
BlockLoop(int loop = 1) : num_loop(loop) {}
void setLoop(int loop) { num_loop = loop; }
virtual void adder(BlockSampler& s) const {
ConsoleContext<LOG_DEBUG> ctx("adder blockloop");
ctx.print(boost::format("num_loop = %d") % num_loop);
for (int l = 0; l < num_loop; l++)
s.mclist.insert(s.mclist.end(), mclist.begin(), mclist.end());
}
~BlockLoop() {}
};
class MainLoop: public BlockSampler {
protected:
MarkovState state;
int mcmc_id;
void show_splash();
public:
MainLoop();
~MainLoop();
void initialize();
void restore(const std::string& fname, bool flexible = false);
void run();
void save();
void save_crash();
void snap();
MarkovState& get_state() { return state; }
const MarkovState& get_state() const { return state; }
void setStepID(int i) { mcmc_id = i; }
};
}
#endif

View file

@ -0,0 +1,48 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/core/markov.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 __LIBLSS_MARKOV_SAMPLER_HPP
#define __LIBLSS_MARKOV_SAMPLER_HPP
#include "libLSS/mcmc/global_state.hpp"
namespace LibLSS {
class MarkovSampler {
protected:
virtual void initialize(MarkovState& state) = 0;
virtual void restore(MarkovState& state) = 0;
private:
bool yet_init;
public:
MarkovSampler() : yet_init(false) {}
virtual ~MarkovSampler() {}
virtual void sample(MarkovState& state) = 0;
void init_markov(MarkovState& state) {
if (!yet_init) {
yet_init = true;
initialize(state);
}
}
void restore_markov(MarkovState& state) {
if (!yet_init) {
yet_init = true;
restore(state);
}
}
};
}
#endif

View file

@ -0,0 +1,241 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/core/powerspec_tools.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/tools/console.hpp"
#include "libLSS/samplers/core/powerspec_tools.hpp"
using namespace LibLSS;
using boost::format;
typedef boost::multi_array_types::extent_range range;
PowerSpectrumSampler_Base::~PowerSpectrumSampler_Base()
{
if (mgr != 0)
delete mgr;
}
bool PowerSpectrumSampler_Base::restore_base(MarkovState& state)
{
Console& cons = Console::instance();
ConsoleContext<LOG_INFO> ctx("power spectrum sampler (common)");
bool build_keys;
L0 = *state.get<SDouble>("L0");
L1 = *state.get<SDouble>("L1");
L2 = *state.get<SDouble>("L2");
N0 = *state.get<SLong>("N0");
N1 = *state.get<SLong>("N1");
N2 = *state.get<SLong>("N2");
N2_HC = *state.get<SLong>("N2_HC");
// Creates a manager. Then we get access to all derived quantities
// for parallelism.
mgr = new FFTMgr(N0, N1, N2, comm);
Ntot = N0*N1*N2;
volNorm = L0*L1*L2/Ntot;
volume = L0*L1*L2;
ctx.print(format("Power spectrum (%dx%dx%d), box (%gx%gx%g)") % N0 % N1 % N2 % L0 % L1 % L2);
N_k = *state.get<SLong>("NUM_MODES");
kmin = *state.get<SDouble>("K_MIN");
kmax = *state.get<SDouble>("K_MAX");
startN0 = mgr->startN0;
localN0 = mgr->localN0;
fourierLocalSize = mgr->allocator_real.minAllocSize;
ctx.print(format("Num modes = %d, kmin = %lg, kmax = %lg") % N_k % kmin % kmax);
rgen = state.get<RandomGen>("random_generator");
if (state.exists("powerspectrum")) {
k = state.get<ArrayType1d>("k_modes");
keys = state.get<IArrayType>("k_keys");
nmode = state.get<IArrayType1d>("k_nmodes");
key_counts = state.get<IArrayType1d>("key_counts");
P_sync += (P = state.get<ArrayType1d>("powerspectrum"));
adjustMul = state.get<IArrayType>("adjust_mode_multiplier");
build_keys = false;
} else {
cons.print<LOG_DEBUG>("Allocating power spectrum array");
P = new ArrayType1d(boost::extents[N_k]);
cons.print<LOG_DEBUG>("Allocating number of stacked modes array");
nmode = new IArrayType1d(boost::extents[N_k]);
cons.print<LOG_DEBUG>("Allocating key counts array");
key_counts = new IArrayType1d(boost::extents[N_k]);
cons.print<LOG_DEBUG>("Allocating mode list");
k = new ArrayType1d(boost::extents[N_k]);
cons.print<LOG_DEBUG>("Allocating mode keys array");
keys = new IArrayType(mgr->extents_complex());
keys->setRealDims(ArrayDimension(N0, N1, N2_HC));
cons.print<LOG_DEBUG>("Mode multiplier adjustment");
adjustMul = new IArrayType(mgr->extents_complex());
adjustMul->setRealDims(ArrayDimension(N0, N1, N2_HC));
state.newElement("k_modes", k);
state.newElement("k_keys", keys);
state.newElement("k_nmodes", nmode);
state.newElement("key_counts", key_counts);
P_sync += state.newElement("powerspectrum", P, true);
state.newElement("adjust_mode_multiplier", adjustMul);
build_keys = true;
}
{
ArrayType1d::ArrayType& P_array = *P->array;
for (long i = 0; i < N_k; i++)
P_array[i] = 1e6;
}
N_fourier_elements = N0*N1*N2_HC;
local_fourier_elements = localN0*N1*N2_HC;
ctx.print(boost::format("N0 = %d, N1 = %d, N2 = %d, N2_HC=%d, localN0=%d, startN0=%d") % N0 % N1 % N2 % N2_HC % localN0 % startN0);
return build_keys;
}
void PowerSpectrumSampler_Base::initialize_base(MarkovState& state)
{
Console& cons = Console::instance();
bool build_keys;
build_keys = restore_base(state);
if (!build_keys) {
cons.print<LOG_INFO>("Keys already built. Returning.");
return;
}
{
ArrayType1d::ArrayType& k_array = *k->array;
ArrayType1d::ArrayType& P_array = *P->array;
for (long i = 0; i < N_k; i++) {
k_array[i] = (kmax-kmin)/N_k * double(i);
P_array[i] = 1e-6;
}
}
// Build the powerspectrum keys
cons.print<LOG_INFO>("Building keys");
IArrayType::ArrayType& array_key = *keys->array;
IArrayType1d::ArrayType& nmode_array = *nmode->array;
IArrayType1d::ArrayType& array_key_counts = *key_counts->array;
IArrayType::ArrayType& adjust = *adjustMul->array;
boost::array<double, 3> L = { L0, L1, L2 };
init_helpers::initialize_powerspectrum_keys(
*mgr, array_key, array_key_counts, adjust, nmode_array,
L, kmin, kmax, N_k);
}
PowerSpectrumSampler_Coloring::~PowerSpectrumSampler_Coloring()
{
if (tmp_fourier != 0) {
MFCalls::free(tmp_fourier);
MFCalls::free(tmp_real);
MFCalls::destroy_plan(analysis_plan);
MFCalls::destroy_plan(synthesis_plan);
}
}
bool PowerSpectrumSampler_Coloring::initialize_coloring(MarkovState& state)
{
ConsoleContext<LOG_INFO> ctx("coloring initialization");
tmp_fourier = MFCalls::alloc_complex(fourierLocalSize);
tmp_real = MFCalls::alloc_real(fourierLocalSize*2);
ctx.print("Creating MPI/FFTW plans for Messenger-Signal");
analysis_plan = MFCalls::plan_dft_r2c_3d(
N0, N1, N2,
tmp_real,
tmp_fourier,
#ifdef ARES_MPI_FFTW
comm->comm(),
#endif
// FFTW_MPI_TRANSPOSED_OUT|
FFTW_DESTROY_INPUT|FFTW_MEASURE);
synthesis_plan = MFCalls::plan_dft_c2r_3d(
N0, N1, N2,
tmp_fourier,
tmp_real,
#ifdef ARES_MPI_FFTW
comm->comm(),
#endif
//FFTW_MPI_TRANSPOSED_IN|
FFTW_DESTROY_INPUT|FFTW_MEASURE);
sqrt_P_info.array->resize(boost::extents[P->array->num_elements()]);
return true;
}
bool PowerSpectrumSampler_Coloring::restore_coloring(MarkovState& state)
{
return initialize_coloring(state);
}
void PowerSpectrumSampler_Coloring::update_s_field_from_x(MarkovState& state, const ArrayType1d& powerSpec)
{
ConsoleContext<LOG_DEBUG> ctx("update of s_field from x_field");
ArrayType& x_field = *state.get<ArrayType>("x_field");
ArrayType& s_field = *state.get<ArrayType>("s_field");
ctx.print(format("%p") % P);
Console::instance().c_assert(powerSpec.array->num_elements() == P->array->size(), "coloring works only on similar powerspectrum as the system one");
// Overwrite s
ctx.print("Copying x_field");
copy_padded_data(*x_field.array, tmp_real);
ctx.print("Analyzing");
MFCalls::execute_r2c(analysis_plan, tmp_real, tmp_fourier);
long P_size = powerSpec.array->num_elements();
for (long i = 0; i < P_size; i++) {
(*sqrt_P_info.array)[i] = std::sqrt((*powerSpec.array)[i] * volume) / (Ntot);
}
int *flat_keys = keys->array->data();
ctx.print("Coloring");
#pragma omp parallel for schedule(static)
for (long i = 0; i < local_fourier_elements; i++) {
double sqrt_P = (*sqrt_P_info.array)[flat_keys[i]];
tmp_fourier[i][0] *= sqrt_P;
tmp_fourier[i][1] *= sqrt_P;
}
ctx.print("Synthesis");
MFCalls::execute_c2r(synthesis_plan, tmp_fourier, tmp_real);
copy_unpadded_data(tmp_real, *s_field.array);
}
void PowerSpectrumSampler_Coloring::update_s_field_from_x(MarkovState& state)
{
update_s_field_from_x(state, *P);
}

View file

@ -0,0 +1,206 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/core/powerspec_tools.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 __LIBLSS_POWER_SPECTRUM_TOOLS_HPP
#define __LIBLSS_POWER_SPECTRUM_TOOLS_HPP
#include "libLSS/samplers/core/markov.hpp"
#include "libLSS/mcmc/state_sync.hpp"
#include "libLSS/samplers/core/types_samplers.hpp"
#include "libLSS/tools/mpi_fftw_helper.hpp"
#include "libLSS/tools/array_tools.hpp"
namespace LibLSS {
template <typename ArrayType>
typename ArrayType::value_type norm_v(const ArrayType &x) {
typename ArrayType::value_type ret = 0;
for (size_t i = 0; i < x.size(); i++)
ret += x[i] * x[i];
return std::sqrt(ret);
}
static inline int ifftfreq(int i, int N) {
return ((i > N / 2) ? (i - N) : i);
}
template <typename T>
T kmode(int i, int N, T L) {
return 2 * M_PI / L * ifftfreq(i, N);
}
template <typename IKArray, typename LArray>
int power_key(
const IKArray &N, const IKArray &ik, const LArray &L, double kmin,
double dk, int Nbin) {
///calculate kmodes
boost::array<double, 3> k;
double kmod;
// 0 mode is specific
if (ik[0] == 0 && ik[1] == 0 && ik[2] == 0)
return 0;
for (int i = 0; i < 3; i++)
k[i] = kmode(ik[i], N[i], L[i]);
kmod = norm_v(k); /// units k [h/Mpc]
int ll = 1 + int(std::floor((kmod - kmin) / dk));
Console::instance().c_assert(
(ll >= 0) && (ll < Nbin), "Over/Underflow binning in powerspectrum");
return ll;
}
namespace init_helpers {
template <
typename Manager, typename ArrayKey, typename ArrayKeyCounts,
typename ArrayAdjust, typename ArrayNmode>
void initialize_powerspectrum_keys(
Manager &manager, ArrayKey &array_key, ArrayKeyCounts &array_key_counts,
ArrayAdjust &adjust, ArrayNmode &nmode_array,
boost::array<double, 3> const &L, double kmin, double kmax,
size_t N_k) {
using boost::format;
Console &cons = Console::instance();
size_t N0 = manager.N0;
size_t startN0 = manager.startN0;
size_t localN0 = manager.localN0;
size_t N1 = manager.N1;
size_t N2_HC = manager.N2_HC;
// FIX: Manager sizes should size_t.
boost::array<size_t, 3> iN{N0, N1, size_t(manager.N2)};
array::fill(nmode_array, 0);
array::fill(array_key_counts, 0);
for (size_t ikx = startN0; ikx < startN0 + localN0; ikx++) {
for (size_t iky = 0; iky < N1; iky++) {
for (size_t ikz = 0; ikz < N2_HC; ikz++) {
boost::array<size_t, 3> ik{ikx, iky, ikz};
int p_key = power_key(iN, ik, L, kmin, (kmax - kmin) / N_k, N_k);
array_key_counts[p_key]++;
array_key[ikx][iky][ikz] = p_key;
assert(p_key < N_k);
nmode_array[p_key] +=
2; // Put everybody at 2. There will be a fix after the loop.
adjust[ikx][iky][ikz] = 2;
}
}
}
// Only one mode and it is not sampling.
array_key_counts[0] = 0;
if (startN0 == 0 && localN0 > 0) {
adjust[0][0][0] = 0;
adjust[0][N1 / 2][0] = 1;
adjust[0][0][N2_HC - 1] = 1;
adjust[0][N1 / 2][N2_HC - 1] = 1;
nmode_array[array_key[0][0][0]] -= 2; // No mode for k=0
nmode_array[array_key[0][N1 / 2][0]] -= 1;
nmode_array[array_key[0][0][N2_HC - 1]] -= 1;
nmode_array[array_key[0][N1 / 2][N2_HC - 1]] -= 1;
}
if (startN0 <= N0 / 2 && localN0 + startN0 > N0 / 2) {
adjust[N0 / 2][0][0] = 1;
adjust[N0 / 2][N1 / 2][0] = 1;
adjust[N0 / 2][0][N2_HC - 1] = 1;
adjust[N0 / 2][N1 / 2][N2_HC - 1] = 1;
nmode_array[array_key[N0 / 2][0][0]] -=
1; // Hermiticity removes one free mode
nmode_array[array_key[N0 / 2][N1 / 2][0]] -= 1;
nmode_array[array_key[N0 / 2][0][N2_HC - 1]] -= 1;
nmode_array[array_key[N0 / 2][N1 / 2][N2_HC - 1]] -= 1;
}
cons.template print<LOG_DEBUG>(
format("Reducing mode counting: num_elements=%d") %
nmode_array.num_elements());
manager.getComm()->all_reduce_t(
MPI_IN_PLACE, nmode_array.data(), nmode_array.num_elements(),
MPI_SUM);
cons.template print<LOG_DEBUG>(
format("Reducing key counting: num_elements=%d") %
array_key_counts.num_elements());
manager.getComm()->all_reduce_t(
MPI_IN_PLACE, array_key_counts.data(),
array_key_counts.num_elements(), MPI_SUM);
}
} // namespace init_helpers
class PowerSpectrumSampler_Base : public MarkovSampler {
protected:
typedef FFTW_Manager_3d<double> FFTMgr;
long N0, N1, N2, N2_HC;
long fourierLocalSize;
long startN0, localN0;
long N_fourier_elements, local_fourier_elements;
long Ntot;
int N_k;
double kmin, kmax;
double volNorm, volume;
double L0, L1, L2;
FFTMgr *mgr;
IArrayType *keys, *adjustMul;
IArrayType1d *key_counts, *nmode;
ArrayType1d *P, *k;
RandomGen *rgen;
MPI_SyncBundle P_sync;
MPI_Communication *comm;
public:
PowerSpectrumSampler_Base(MPI_Communication *lcomm)
: mgr(0), keys(0), key_counts(0), nmode(0), P(0), k(0), rgen(0),
comm(lcomm) {}
virtual ~PowerSpectrumSampler_Base();
bool restore_base(MarkovState &state);
void initialize_base(MarkovState &state);
};
class PowerSpectrumSampler_Coloring : public PowerSpectrumSampler_Base {
protected:
MFCalls::plan_type analysis_plan, synthesis_plan;
MFCalls::complex_type *tmp_fourier;
MFCalls::real_type *tmp_real;
ArrayType1d sqrt_P_info;
int Ncatalog;
public:
PowerSpectrumSampler_Coloring(MPI_Communication *comm)
: PowerSpectrumSampler_Base(comm), tmp_fourier(0), tmp_real(0),
sqrt_P_info(boost::extents[0]) {}
virtual ~PowerSpectrumSampler_Coloring();
bool initialize_coloring(MarkovState &state);
bool restore_coloring(MarkovState &state);
void update_s_field_from_x(MarkovState &state);
void
update_s_field_from_x(MarkovState &state, const ArrayType1d &powerSpectrum);
};
} // namespace LibLSS
#endif

View file

@ -0,0 +1,214 @@
#include <math.h>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <string>
#include <cassert>
#include <cfloat>
#include <float.h>
#include <stdlib.h>
#include <stdio.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include "libLSS/samplers/core/ran_gig.h"
#define EPSILON 1e-10
using namespace std;
/* R_zeroin2() is faster for "expensive" f(), in those typical cases where
* f(ax) and f(bx) are available anyway : */
double R_zeroin2( /* An estimate of the root */
double ax, /* Left border | of the range */
double bx, /* Right border| the root is seeked*/
double fa, double fb, /* f(a), f(b) */
double (*f)(double x, void *info), /* Function under investigation */
void *info, /* Add'l info passed on to f */
double *Tol, /* Acceptable tolerance */
int *Maxit) /* Max # of iterations */
{
double a,b,c, fc; /* Abscissae, descr. see above, f(c) */
double tol;
int maxit;
a = ax; b = bx;
c = a; fc = fa;
maxit = *Maxit + 1; tol = * Tol;
/* First test if we have found a root at an endpoint */
if(fa == 0.0) {
*Tol = 0.0;
*Maxit = 0;
return a;
}
if(fb == 0.0) {
*Tol = 0.0;
*Maxit = 0;
return b;
}
while(maxit--) /* Main iteration loop */
{
double prev_step = b-a; /* Distance from the last but one
to the last approximation */
double tol_act; /* Actual tolerance */
double p; /* Interpolation step is calcu- */
double q; /* lated in the form p/q; divi-
* sion operations is delayed
* until the last moment */
double new_step; /* Step at this iteration */
if( fabs(fc) < fabs(fb) )
{ /* Swap data for b to be the */
a = b; b = c; c = a; /* best approximation */
fa=fb; fb=fc; fc=fa;
}
tol_act = 2.*EPSILON*fabs(b) + tol/2.;
new_step = (c-b)/2.;
if( fabs(new_step) <= tol_act || fb == (double)0 )
{
*Maxit -= maxit;
*Tol = fabs(c-b);
return b; /* Acceptable approx. is found */
}
/* Decide if the interpolation can be tried */
if( fabs(prev_step) >= tol_act /* If prev_step was large enough*/
&& fabs(fa) > fabs(fb) ) { /* and was in true direction,
* Interpolation may be tried */
register double t1,cb,t2;
cb = c-b;
if( a==c ) { /* If we have only two distinct */
/* points linear interpolation */
t1 = fb/fa; /* can only be applied */
p = cb*t1;
q = 1.0 - t1;
}
else { /* Quadric inverse interpolation*/
q = fa/fc; t1 = fb/fc; t2 = fb/fa;
p = t2 * ( cb*q*(q-t1) - (b-a)*(t1-1.0) );
q = (q-1.0) * (t1-1.0) * (t2-1.0);
}
if( p>(double)0 ) /* p was calculated with the */
q = -q; /* opposite sign; make p positive */
else /* and assign possible minus to */
p = -p; /* q */
if( p < (0.75*cb*q-fabs(tol_act*q)/2.) /* If b+p/q falls in [b,c]*/
&& p < fabs(prev_step*q/2.) ) /* and isn't too large */
new_step = p/q; /* it is accepted
* If p/q is too large then the
* bisection procedure can
* reduce [b,c] range to more
* extent */
}
if( fabs(new_step) < tol_act) { /* Adjust the step to be not less*/
if( new_step > (double)0 ) /* than tolerance */
new_step = tol_act;
else
new_step = -tol_act;
}
a = b; fa = fb; /* Save the previous approx. */
b += new_step; fb = (*f)(b, info); /* Do step to a new approxim. */
if( (fb > 0. && fc > 0.) || (fb < 0. && fc < 0.) ) {
/* Adjust c for it to have a sign opposite to that of b */
c = a; fc = fa;
}
}
/* failed! */
*Tol = fabs(c-b);
*Maxit = -1;
return b;
}
double R_zeroin( /* An estimate of the root */
double ax, /* Left border | of the range */
double bx, /* Right border| the root is seeked*/
double (*f)(double x, void *info), /* Function under investigation */
void *info, /* Add'l info passed on to f */
double *Tol, /* Acceptable tolerance */
int *Maxit) /* Max # of iterations */
{
double fa = (*f)(ax, info);
double fb = (*f)(bx, info);
return R_zeroin2(ax, bx, fa, fb, f, info, Tol, Maxit);
}
double g(double y, void *params)
{
double *aux = (double *)params;
double beta=aux[0];
double lambda=aux[1];
double m=aux[2];
return(0.5*beta*y*y*y - y*y*(0.5*beta*m+lambda+1) + y*((lambda-1)*m-0.5*beta) + 0.5*beta*m);
}
double LibLSS::ran_gig(double chi, double psi, double lambda,gsl_rng * SEED)
{
// Function to generate random observations from a
// generalized inverse Gaussian distribution. The
// algorithm is based on that given by Dagpunar (1989)
if(chi<0.) {cout << "chi can not be negative"<<endl; return 0.;}
if(psi<0.) {cout << "psi can not be negative"<<endl; return 0.;}
if((lambda>=0.)&&(psi==0.))
{
cout << "When lambda >= 0, psi must be > 0"<<endl;
return 0.;
}
if((lambda<=0.)&(chi==0.))
{
cout <<"When lambda <= 0, chi must be > 0"<<endl;
return 0.;
}
if(chi==0.) {cout <<"chi = 0, use rgamma"<<endl; return 0.;}
if(psi==0.) {cout <<"algorithm only valid for psi > 0"<<endl; return 0.;}
double alpha=sqrt(psi/chi);
double beta=sqrt(psi*chi);
double m=(lambda-1.+sqrt((lambda-1.)*(lambda-1.)+beta*beta))/beta;
double upper = m;
double params[3];
params[0]=beta;
params[1]=lambda;
params[2]=m;
while(g(upper,params)<=0.) upper = 2.*upper;
double tol=1e-10;
int maxit=10000;
double yM =R_zeroin(0.,m,&g, &params,&tol,&maxit);// uniroot(g,interval=c(0,m))$root
double yP =R_zeroin(m,upper,&g, &params,&tol,&maxit);// uniroot(g,interval=c(m,upper))$root
double a = (yP-m)*exp(-0.25*beta*(yP+1./yP-m-1./m)+(log(yP) -log(m))*(0.5*(lambda-1.)) );
double b = (yM-m)*exp(-0.25*beta*(yM+1./yM-m-1./m)+(log(yM) -log(m))*(0.5*(lambda-1.)) );
double c = -0.25*beta*(m+1./m) + 0.5*(lambda-1.)*log(m);
double y=0;
while(true){
double R1 = gsl_rng_uniform (SEED);
double R2 = gsl_rng_uniform (SEED);
y= m + a*R2/R1 + b*(1.-R2)/R1;
if((y>0.) && (-log(R1)>=-0.5*(lambda-1.)*log(y)+0.25*beta*(y+1./y)+c)) break;
}
return(y/alpha);
}

View file

@ -0,0 +1,19 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/core/ran_gig.h
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 __LIBLSS_RANGIG_H
#define __LIBLSS_RANGIG_H
namespace LibLSS {
double ran_gig(double chi, double psi, double lambda,gsl_rng * SEED);
}
#endif

View file

@ -0,0 +1,392 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/core/random_number.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 __RANDOM_NUMBER_HPP
#define __RANDOM_NUMBER_HPP
#include <cmath>
#include <boost/format.hpp>
#include <functional>
#include "libLSS/tools/console.hpp"
#include "libLSS/tools/errors.hpp"
#include "libLSS/tools/openmp.hpp"
#include <H5Cpp.h>
#include <CosmoTool/hdf5_array.hpp>
#include <iostream>
#include "libLSS/tools/array_concepts.hpp"
#include "libLSS/tools/fusewrapper.hpp"
#include "libLSS/tools/fused_array.hpp"
#include "libLSS/tools/hdf5_type.hpp"
namespace LibLSS {
class RandomNumber;
namespace Random_details {
// This is a workaround for a bug in GCC compiler which
// has a problem using boost::bind on member function in declspec.
inline unsigned int real_poisson(RandomNumber *rgen, double nmean);
inline double real_gaussian(RandomNumber *rgen, double dev);
inline unsigned int real_gamma(RandomNumber *rgen, double a, double b);
inline unsigned int real_negative_binomial(RandomNumber *rgen, double p, double n);
}
/**
* Fundamental class to provide random number generation.
*/
class RandomNumber
{
public:
virtual ~RandomNumber() {}
/**
* This returns a random 32-bit integer, uniformly distributed.
* @return a random integer
*/
virtual unsigned long int get() = 0;
/**
* This returns a uniformly distributed double precision floating point.
* @param a random floating point.
*/
virtual double uniform() = 0;
/**
* Provide a seed to initialize the Pseudo Random Number Generator.
* @param s a seed value
*/
virtual void seed(unsigned long int s) = 0;
/**
* Save the internal state of the PRNG into the provided HDF5 group.
* @param s an HDF5 group.
*/
virtual void save(H5_CommonFileGroup& s) = 0;
/**
* Restore the internal state of the PRNG from the provided HDF5 group.
* @param s an HDF5 group.
* @param flexible specify if we accept some inconsistency in the input group (i.e. different thread count).
*/
virtual void restore(H5_CommonFileGroup& s, bool flexible = false) = 0;
double gaussian_ratio();
/**
* Generate a Poisson distributed random integer with the specified intensity.
* @param mean Poisson intensity
*/
virtual unsigned int poisson(double mean) = 0;
virtual unsigned int negative_binomial(double p, double n) = 0;
/**
* Generate numbers that are uniformly distributed. The actual value in wrap is ignored. It is only
* used to determine the rank of the required array.
* @param wrap a wrapped expression to provide the rank of the output array.
*/
template<typename Array, bool copy>
void uniform(LibLSS::FuseWrapper_detail::Wrapper<Array,copy> wrap) {
wrap = b_va_fused<double,Array::dimensionality>([this](int, ...)->double { return this->uniform(); });
}
// Only activate this overload if the type looks like an array
template<typename Array, bool copy, typename Array2, bool copy2>
auto gamma(LibLSS::FuseWrapper_detail::Wrapper<Array,copy> wrap, LibLSS::FuseWrapper_detail::Wrapper<Array2,copy2> wrap2)
{
return LibLSS::fwrap(
LibLSS::b_va_fused<unsigned int>(
std::bind(&LibLSS::Random_details::real_gamma,
this, std::placeholders::_1, std::placeholders::_2),
wrap.forward_wrap(),
wrap2.forward_wrap()
)
);
}
/**
* Build an expression that generate random number that are distributed as a Negative Binomial
* with an intensity as provided by the wrap expression, and an additional miss term with the second
* expression.
* @param wrap the expression providing the Poisson intensity.
* @param wrap2 the expression providing the missed intensity.
*/
template<typename Array, bool copy, typename Array2, bool copy2>
auto negative_binomial(LibLSS::FuseWrapper_detail::Wrapper<Array,copy> wrap, LibLSS::FuseWrapper_detail::Wrapper<Array2,copy2> wrap2)
{
return LibLSS::fwrap(
LibLSS::b_va_fused<unsigned int>(
std::bind(&LibLSS::Random_details::real_negative_binomial,
this, std::placeholders::_1, std::placeholders::_2),
wrap.forward_wrap(),
wrap2.forward_wrap()
)
);
}
/**
* Build an expression that generate random number that are Poisson distributed
* with an intensity as provided by the wrap expression.
* @param wrap the expression providing the Poisson intensity.
*/
template<typename Array, bool copy>
auto poisson(LibLSS::FuseWrapper_detail::Wrapper<Array,copy> wrap)
{
return LibLSS::fwrap(
LibLSS::b_va_fused<unsigned int>(
std::bind(&LibLSS::Random_details::real_poisson,
this, std::placeholders::_1),
wrap.forward_wrap()
)
);
}
/**
* Build an expression that generate gaussian random number whose standard deviation is determined
* by the input wrapped expression. The mean is set to zero.
* @param wrap the expression providing the standard deviation.
*/
template<typename Array, bool copy>
auto gaussian(LibLSS::FuseWrapper_detail::Wrapper<Array,copy> wrap)
{
return LibLSS::fwrap(
LibLSS::b_va_fused<typename Array::element>(
std::bind(&LibLSS::Random_details::real_gaussian,
this, std::placeholders::_1),
wrap.forward_wrap()
)
);
}
/**
* Return a single random number gaussian distributed
*/
double gaussian() { return gaussian_ratio(); }
virtual double gamma(double a, double b) = 0;
};
namespace Random_details {
inline unsigned int real_poisson(RandomNumber *rgen, double nmean) {
return rgen->poisson(nmean);
}
inline unsigned int real_gamma(RandomNumber *rgen, double a, double b) {
return rgen->gamma(a, b);
}
inline unsigned int real_negative_binomial(RandomNumber *rgen, double a, double b) {
return rgen->negative_binomial(a, b);
}
inline double real_gaussian(RandomNumber *rgen, double a) {
return rgen->gaussian()*a;
}
}
/**
* A Random number generator that works in multi-threaded environment.
* The base class is provided through a template argument.
*/
template<typename BaseGenerator>
class RandomNumberThreaded: public RandomNumber {
protected:
RandomNumberThreaded()
: gens(0), numGenerators(0) {
}
public:
typedef BaseGenerator base_type;
BaseGenerator *gens;
int numGenerators;
void realInit(BaseGenerator& b, int force_max) {
using boost::format;
numGenerators = (force_max < 0) ? smp_get_max_threads() : force_max;
Console::instance().format<LOG_INFO>(
"Initializing %d threaded random number generators", numGenerators
);
gens = new BaseGenerator[numGenerators];
// Not great entropy
for (int i = 0; i < numGenerators; i++)
gens[i].seed(b.get());
}
/**
* Constructor.
* @param force_max an argument to specific the maximum number of threads that will
* be used. If equal to -1, it will get the current limit from OpenMP.
*/
RandomNumberThreaded(int force_max) {
BaseGenerator b;
realInit(b, force_max);
}
/**
* Return the base generator for the current thread
* @return the fundamental generator for the current thread.
*/
BaseGenerator &base() {
return gens[smp_get_thread_id()];
}
/**
* Destructor.
*/
virtual ~RandomNumberThreaded() {
if (gens == 0)
return;
Console::instance().print<LOG_INFO>(
"Cleaning up parallel random number generators"
);
delete[] gens;
}
virtual void seed(unsigned long s) {
BaseGenerator b;
Console::instance().format<LOG_VERBOSE>("THREADED: Changing random number generation seed with %ld", s);
b.seed(s);
for (int i = 0; i < numGenerators; i++)
gens[i].seed(b.get());
}
virtual unsigned long get() {
return base().get();
}
virtual double uniform() {
return base().uniform();
}
virtual unsigned int poisson(double mean) {
return base().poisson(mean);
}
virtual double gamma(double a, double b) {
return base().gamma(a, b);
}
virtual unsigned int negative_binomial(double p, double n) {
return base().negative_binomial(p, n);
}
using RandomNumber::poisson;
using RandomNumber::gamma;
using RandomNumber::negative_binomial;
using RandomNumber::gaussian;
using RandomNumber::uniform;
virtual void save(H5_CommonFileGroup& g) {
using boost::str;
using boost::format;
boost::multi_array<int, 1> gen_array(boost::extents[1]);
gen_array[0] = numGenerators;
CosmoTool::hdf5_write_array(g, "num_generators", gen_array);
for (int i = 0; i < numGenerators; i++) {
H5::Group subg = g.createGroup(str(format("generator_%d") % i));
gens[i].save(subg);
}
}
virtual void restore(H5_CommonFileGroup& g, bool flexible = false) {
using boost::str;
using boost::format;
boost::multi_array<int, 1> gen_array;
CosmoTool::hdf5_read_array(g, "num_generators", gen_array);
if (gen_array[0] != numGenerators) {
std::string s = str(boost::format(
"The current number of threads (%d) is not compatible with file state (%d)")
% numGenerators % gen_array[0]);
if (!flexible) {
error_helper<ErrorBadState>(s);
} else {
Console::instance().print<LOG_WARNING>(s);
}
}
int num_to_read = std::min(numGenerators, gen_array[0]);
for (int i = 0; i < num_to_read; i++) {
H5::Group subg = g.openGroup(str(format("generator_%d") % i));
gens[i].restore(subg, flexible);
}
}
};
/**
* A random number generator that works in MPI environment.
*/
template<typename BaseGenerator>
class RandomNumberMPI: public RandomNumberThreaded<BaseGenerator> {
public:
typedef RandomNumberThreaded<BaseGenerator> BaseClass;
MPI_Communication *comm;
/**
* Constructor.
* @param comm an MPI communicator over which the PRNG must work.
* @param force_max sets the maximum number of threads per MPI task that will in parallel.
*/
RandomNumberMPI(MPI_Communication *_comm, int force_max)
: BaseClass(), comm(_comm) {
BaseGenerator b;
unsigned long int seedVal = 0;
if (comm->rank() == 0) {
for (int r = 1; r < comm->size(); r++) {
seedVal = b.get();
comm->send(&seedVal, 1, translateMPIType<unsigned long int>(), r, 0);
}
} else {
comm->recv(&seedVal, 1, translateMPIType<unsigned long int>(), 0, 0);
}
b.seed(seedVal);
this->realInit(b, force_max);
}
virtual void seed(unsigned long s) {
BaseGenerator b;
unsigned long int seedVal;
Console::instance().format<LOG_VERBOSE>("MPI: Changing random number generation seed with %ld", s);
b.seed(s);
if (comm->rank() == 0) {
for (int r = 1; r < comm->size(); r++) {
seedVal = b.get();
comm->send(&seedVal, 1, translateMPIType<unsigned long int>(), r, 0);
}
seedVal = b.get();
} else {
comm->recv(&seedVal, 1, translateMPIType<unsigned long int>(), 0, 0);
}
BaseClass::seed(seedVal);
}
};
#include "gaussian_ratio.tcc"
};
#endif

View file

@ -0,0 +1,94 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/core/types_samplers.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 __LIBLSS_TYPES_SAMPLERS_HPP
#define __LIBLSS_TYPES_SAMPLERS_HPP
#include "libLSS/mpi/generic_mpi.hpp"
#include <CosmoTool/fourier/fft/fftw_calls.hpp>
#ifdef ARES_MPI_FFTW
# include <CosmoTool/fourier/fft/fftw_calls_mpi.hpp>
#endif
#include "libLSS/tools/fftw_allocator.hpp"
#include "libLSS/tools/uninitialized_type.hpp"
#include "libLSS/mcmc/state_element.hpp"
#include "libLSS/samplers/core/random_number.hpp"
#include <boost/multi_array/storage_order.hpp>
#include "libLSS/tools/memusage.hpp"
namespace LibLSS {
template <typename T, size_t N>
using multi_array = boost::multi_array<T, N, LibLSS::track_allocator<T>>;
template <typename T, size_t N>
using const_multi_array_ref = boost::const_multi_array_ref<T, N>;
template <typename T, size_t N>
using multi_array_ref = boost::multi_array_ref<T, N>;
typedef CosmoTool::FFTW_Calls<double> FCalls;
#ifdef ARES_MPI_FFTW
typedef CosmoTool::FFTW_MPI_Calls<double> MPI_FCalls;
typedef MPI_FCalls MFCalls;
#else
typedef FCalls MFCalls;
#endif
typedef ScalarStateElement<long> SLong;
typedef ScalarStateElement<double> SDouble;
typedef ScalarStateElement<bool> SBool;
typedef ArrayStateElement<double, 3, FFTW_Allocator<double>, true> ArrayType;
typedef ArrayStateElement<
std::complex<double>, 3, FFTW_Allocator<std::complex<double>>, true>
CArrayType;
typedef ArrayStateElement<int, 3, LibLSS::track_allocator<int>, true>
IArrayType;
typedef ArrayStateElement<double, 1, LibLSS::track_allocator<double>>
ArrayType1d;
typedef ArrayStateElement<int, 1, LibLSS::track_allocator<int>> IArrayType1d;
typedef RandomStateElement<RandomNumber> RandomGen;
typedef ArrayStateElement<double, 3, FFTW_Allocator<double>, true>
SelArrayType;
typedef CArrayType::ArrayType FFTW_Complex_Array;
typedef ArrayType::ArrayType FFTW_Real_Array;
typedef CArrayType::RefArrayType FFTW_Complex_Array_ref;
typedef ArrayType::RefArrayType FFTW_Real_Array_ref;
typedef UninitializedArray<
FFTW_Complex_Array, FFTW_Allocator<std::complex<double>>>
Uninit_FFTW_Complex_Array;
typedef UninitializedArray<FFTW_Real_Array, FFTW_Allocator<double>>
Uninit_FFTW_Real_Array;
namespace init_helpers {
// This is a noop when no argument is given
template <size_t i, typename Array>
void ArrayDimension_adder(Array &A) {}
// Fill the i-th value of the array recursively.
template <size_t i, typename Array, typename... Ntype>
void ArrayDimension_adder(Array &A, size_t iN, Ntype... Ns) {
A[i] = iN;
ArrayDimension_adder<i + 1>(A, Ns...);
}
} // namespace init_helpers
template <typename... Ntype>
inline boost::array<size_t, sizeof...(Ntype)> ArrayDimension(Ntype... Ns) {
boost::array<size_t, sizeof...(Ntype)> A;
init_helpers::ArrayDimension_adder<0>(A, Ns...);
return A;
}
} // namespace LibLSS
#endif

View file

@ -0,0 +1,124 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/rgen/gsl_miser.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 __GSL_RANDOM_NUMBER_MISER_HPP
#define __GSL_RANDOM_NUMBER_MISER_HPP
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_monte.h>
#include <gsl/gsl_monte_miser.h>
#include <cstring>
#include "libLSS/tools/errors.hpp"
#include "libLSS/samplers/core/random_number.hpp"
#include "libLSS/samplers/rgen/gsl_random_number.hpp"
namespace LibLSS {
/**
* This is an adaptor class for the MISER integrator in GSL.
* It handles the life cycle of the MISER object, and support for a generic
* functor for the integrand.
*/
class GSL_Miser {
protected:
gsl_monte_miser_state *state;
size_t Nd;
template<typename Functor>
struct MiserCall {
Functor f;
MiserCall(Functor g) : f(g) {}
};
template<typename Functor>
static double adaptor_functor(double *x, size_t, void *params)
{
MiserCall<Functor> *c = (MiserCall<Functor> *) params;
return c->f(x);
}
public:
/**
* Constructor.
* @param dim number of dimensions over which the integration will occur.
*/
GSL_Miser(size_t dim)
: state(0), Nd(dim) {
state = gsl_monte_miser_alloc(dim);
}
/**
* Destructor.
*/
~GSL_Miser() {
gsl_monte_miser_free(state);
}
/**
* Integrate the provided integrand over some range, with a maximum number of calls. A bound
* on the maximum error is returned.
* Here is a use example:
*
* @code
* // ...
* size_t calls = 10;
* double xl[2] = {0, 0};
* double xu[2] = {1, 2};
* double value;
*
* GSL_Miser miser(2); // 2-dimensions
* value = miser.integrate(rng, [](double *x) {
* // do something with x[0], x[1]
* return x[0]*x[0] + x[1]*x[1]; // for example sum(x^2)
* }, xl, xu, calls, abserr);
* //...
* @endcode
*
* @param rng Class adapting the GSL random number generator
* @param f Functor representing the integrand. It must have one pointer to double and return a double.
* @param xl lower bound for integration (N-dimension contiguous C-array)
* @param xu upper bound for integration
* @param calls maximum number of calls
* @param abserr return medium for estimated maximum absolute error
*
*/
// Only valid for GSL
template<typename Functor,typename A>
double integrate(GSL_RandomNumber& rng, Functor f, A& xl, A& xu, size_t calls, double &abserr) {
gsl_monte_function mf;
MiserCall<Functor> call(f);
double result;
int err;
mf.f = &adaptor_functor<Functor>;
mf.dim = Nd;
mf.params = &call;
if ((err = gsl_monte_miser_integrate(&mf, &xl[0], &xu[0], Nd, calls, rng.rng, state, &result, &abserr)) != GSL_SUCCESS)
error_helper<ErrorGSL>(boost::format("Error while doing monte carlo integration: error code = %d ") % err);
return result;
}
/**
* Use a multi-threaded random number generator deriving from a base "Rng".
* This is a helper class to unwrap the GSL base class for the random number generation.
* @see integrate(GSL_RandomNumber& rng, Functor f, A& xl, A& xu, size_t calls, double &abserr)
*/
template<typename Rng, typename Functor, typename A>
double integrate(RandomNumberThreaded<Rng>& rng, Functor f, A& xl, A& xu, size_t calls, double &abserr) {
return integrate(rng.base(), f, xl, xu, calls, abserr);
}
};
}
#endif

View file

@ -0,0 +1,91 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/rgen/gsl_random_number.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 __GSL_RANDOM_NUMBER_HPP
#define __GSL_RANDOM_NUMBER_HPP
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <cstring>
#include "libLSS/tools/errors.hpp"
#include "libLSS/samplers/core/random_number.hpp"
namespace LibLSS {
class GSL_RandomNumber: public RandomNumber
{
public:
gsl_rng *rng;
GSL_RandomNumber() :
rng(gsl_rng_alloc(gsl_rng_mt19937)) {
}
~GSL_RandomNumber() {
gsl_rng_free(rng);
}
virtual double uniform() {
return gsl_rng_uniform(rng);
}
virtual double unitexp() {
return gsl_ran_exponential(rng, 1.);
}
virtual void seed(unsigned long i) {
Console::instance().print<LOG_DEBUG>(boost::format("GSL: Changing random number generation seed with %ld") % i);
gsl_rng_set(rng, i);
}
virtual unsigned long get() {
return gsl_rng_get(rng);
}
using RandomNumber::poisson;
using RandomNumber::gaussian;
using RandomNumber::gamma;
using RandomNumber::negative_binomial;
virtual unsigned int poisson(double mean) {
return gsl_ran_poisson(rng, mean);
}
virtual unsigned int negative_binomial(double p, double n) {
return gsl_ran_negative_binomial(rng, p, n);
}
virtual double gamma(double a, double b) {
return gsl_ran_gamma(rng, a, b);
}
virtual void save(H5_CommonFileGroup& g) {
boost::multi_array<char, 1> out(boost::extents[gsl_rng_size(rng)]);
::memcpy(out.origin(), gsl_rng_state(rng), gsl_rng_size(rng));
CosmoTool::hdf5_write_array(g, "state", out);
}
virtual void restore(H5_CommonFileGroup& g, bool flexible) {
size_t sz = gsl_rng_size(rng);
boost::multi_array<char, 1> in;
CosmoTool::hdf5_read_array(g, "state", in);
if (in.shape()[0] != sz) {
error_helper<ErrorIO>("Could not read state in GSL_RandomNumber");
}
memcpy(gsl_rng_state(rng), in.origin(), sz);
}
};
};
#endif

View file

@ -0,0 +1,231 @@
/*+
ARES/HADES/BORG Package -- ./libLSS/samplers/rgen/slice_sweep.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 _LIBLSS_SLICE_SWEEP_HPP
#define _LIBLSS_SLICE_SWEEP_HPP
#include "libLSS/mpi/generic_mpi.hpp"
#include <cmath>
// These algorithms are described in https://www.aquila-consortium.org/wiki/index.php/File:Slice_sampling_Neal_97.pdf
namespace LibLSS {
namespace slice_details {
template<typename LogLikelihood>
double request(MPI_Communication *comm, LogLikelihood lh, double a, int ROOT) {
int job = 1;
comm->broadcast_t(&job, 1, ROOT);
comm->broadcast_t(&a, 1, ROOT);
return lh(a);
}
inline void shutdown(MPI_Communication *comm, double a, int ROOT) {
int job = 0;
comm->broadcast_t(&job, 1, ROOT);
comm->broadcast_t(&a, 1, ROOT);
}
inline int grab_job(MPI_Communication *comm, double& a, int ROOT) {
int job;
comm->broadcast_t(&job, 1, ROOT);
comm->broadcast_t(&a, 1, ROOT);
return job;
}
}
template<typename Random, typename LogLikelihood>
double slice_sweep(MPI_Communication *comm, Random& rng, LogLikelihood lh, double a0, double step, int ROOT = 0)
{
Console::instance().print<LOG_DEBUG>("Doing slicesweep EARLY init");
if (comm->rank() != ROOT) {
double v;
while (slice_details::grab_job(comm, v, ROOT)) {
lh(v);
}
return v;
}
Console::instance().print<LOG_DEBUG>("Doing slicesweep init");
double logp0 = slice_details::request(comm, lh, a0, ROOT);
double logu = logp0 + std::log(1-rng.uniform());//draw from (0,1], to avoid log(0)
Console::instance().c_assert(!std::isnan(logu), "logu must not be a NaN");
double rr = rng.uniform();
double al = a0 - rr*step;
double ar = a0 + (1-rr)*step;
Console::instance().print<LOG_DEBUG>(boost::format("First loop (logu = %lg)") % logu);
while (true) {
double logpl = slice_details::request(comm, lh, al, ROOT);
if (logpl < logu)
break;
al -= step;
}
Console::instance().print<LOG_DEBUG>("Second loop");
while (true) {
double logpr = slice_details::request(comm, lh, ar, ROOT);
if (logpr < logu)
break;
ar += step;
}
Console::instance().print<LOG_DEBUG>("Last loop");
while (true) {
double a1 = rng.uniform() * (ar - al) + al;
double logp1 = slice_details::request(comm, lh, a1, ROOT);
if (logp1 > logu) {
slice_details::shutdown(comm, a1, ROOT);
return a1;
} else {
// Shrink bracket
if (a1 > a0)
ar = a1;
else
al = a1;
}
}
}
template<typename Random, typename LogLikelihood>
double slice_sweep(Random& rng, LogLikelihood lh, double a0, double step)
{
double logp0 = lh(a0);
double logu = logp0 + std::log(1-rng.uniform());//draw from (0,1], to avoid log(0)
Console::instance().c_assert(!std::isnan(logu), "logu must not be a NaN");
double rr = rng.uniform();
double al = a0 - rr*step;
double ar = a0 + (1-rr)*step;
while (true) {
double logpl = lh(al);
if (logpl < logu)
break;
al -= step;
}
while (true) {
double logpr = lh(ar);
if (logpr < logu)
break;
ar += step;
}
while (true) {
double a1 = rng.uniform() * (ar - al) + al;
double logp1 = lh(a1);
if (logp1 > logu) {
return a1;
} else {
// Shrink bracket
if (a1 > a0)
ar = a1;
else
al = a1;
}
}
}
template<typename Random, typename LogLikelihood>
double slice_sweep_double(MPI_Communication *comm, Random& rng, LogLikelihood lh, double a0, double step, int ROOT = 0)
{
ConsoleContext<LOG_DEBUG> ctx("slicesweep_double");
if (comm->rank() != ROOT) {
double v;
while (slice_details::grab_job(comm, v, ROOT)) {
lh(v);
}
return v;
}
ctx.print("INIT");
// Find the initial likelihood and the slice level
double logp0 = slice_details::request(comm, lh, a0, ROOT);
double logu = logp0 + std::log(1-rng.uniform());//draw from (0,1], to avoid log(0)
Console::instance().c_assert(!std::isnan(logu), "logu must not be a NaN");
double rr = rng.uniform();
double al = a0 - rr*step;
double ar = a0 + (1-rr)*step;
ctx.print(boost::format("Step defining loop (logu = %lg)") % logu);
double logpl = slice_details::request(comm, lh, al, ROOT);
double logpr = slice_details::request(comm, lh, ar, ROOT);
while (logpl >= logu || logpr >= logu) {
double v= rng.uniform();
if (v < 0.5) {
al -= (ar - al);
logpl = slice_details::request(comm, lh, al, ROOT);
ctx.print(boost::format("new al=%g, logpl = %g") % al % logpl);
} else {
ar += (ar - al);
logpr = slice_details::request(comm, lh, ar, ROOT);
ctx.print(boost::format("new ar=%g, logpr = %g") % ar % logpr);
}
}
ctx.print("Sampling loop");
while (true) {
double a1 = rng.uniform() * (ar - al) + al;
double logp1 = slice_details::request(comm, lh, a1, ROOT);
if (logp1 > logu) {
double ar_hat = ar;
double al_hat = al;
double logpl_hat = slice_details::request(comm, lh, al_hat, ROOT);
double logpr_hat = slice_details::request(comm, lh, ar_hat, ROOT);
bool not_accepted = false;
ctx.print(boost::format("Got a candidate at a1=%g") % a1);
while ((ar_hat - al_hat) > (1.1*step) && !not_accepted) {
double am = 0.5 * (ar_hat+al_hat);
bool D = ((a0 < am && a1 >= am) || (a0 >= am && a1 < am));
if (a1 < am) {
ar_hat = am;
logpr_hat = slice_details::request(comm, lh, ar_hat, ROOT);
} else {
al_hat = am;
logpl_hat = slice_details::request(comm, lh, al_hat, ROOT);
}
ctx.print(boost::format("ar_hat=%lg, al_hat=%lg, logpl_hat=%lg, logpr_hat=%lg, D=%d") % ar_hat % al_hat % logpl_hat % logpr_hat % D);
if (D && logu >= logpl_hat && logu >= logpr_hat) {
// Not acceptable. Try again.
ctx.print("Not good");
not_accepted = true;
}
}
// Go back outside
if (not_accepted)
continue;
slice_details::shutdown(comm, a1, ROOT);
return a1;
} else {
// Shrink bracket
if (a1 > a0)
ar = a1;
else
al = a1;
}
}
}
}
#endif