/*+ ARES/HADES/BORG Package -- ./libLSS/data/projection.hpp Copyright (C) 2014-2020 Guilhem Lavaux Copyright (C) 2009-2020 Jens Jasche Additional contributions from: Guilhem Lavaux (2023) +*/ #ifndef __LIBLSS_PROJECTION_HPP #define __LIBLSS_PROJECTION_HPP #include #include #include #include #include #include "angtools.hpp" #include "postools.hpp" #include "libLSS/tools/array_tools.hpp" #include "libLSS/physics/generic_cic.hpp" namespace LibLSS { enum ProjectionDataModel { NGP_PROJECTION, LUMINOSITY_CIC_PROJECTION }; static const int LSS_DIMENSIONS = 3; static const int NR_CELLS_DIM = 2; static const int NR_CELLS_SLICE = 4; static const int NR_CELLS_TOTAL = 8; static const double TOTAL_WEIGHT = 1.; struct Dimension { union { double length[LSS_DIMENSIONS]; double position[LSS_DIMENSIONS]; }; }; struct Grid { size_t resolution[LSS_DIMENSIONS]; }; namespace details { template struct ProjectionAcceptAll { bool operator()(const typename GSurvey::GalaxyType &g) { return true; } }; }; // namespace details template < typename Kernel, typename Periodic, class GSurvey, typename DensityField, typename Dimension, typename IDimension, typename Condition, typename PreRun = std::function> size_t galaxySurveyToGridGeneric( const GSurvey &survey, DensityField &field, const IDimension &N, const Dimension &corner, const Dimension &L, const Dimension &d, Condition condition, PreRun prerun = PreRun()) { const typename DensityField::size_type *localN = field.shape(); const typename DensityField::index *base = field.index_bases(); using boost::format; using boost::lambda::_1; size_t accepted = 0; double found_corners[LSS_DIMENSIONS][2]; boost::multi_array xyz(boost::extents[survey.surveySize()][3]); boost::multi_array weights(boost::extents[survey.surveySize()]); // prerun must not be empty if (prerun) prerun(); for (int i = 0; i < LSS_DIMENSIONS; i++) { found_corners[i][0] = std::numeric_limits::infinity(); found_corners[i][1] = -std::numeric_limits::infinity(); } array::fill(field, 0); for (long i = 0; i < survey.surveySize(); i++) { typename GSurvey::ConstRefGalaxyType g = survey[i]; boost::array ii; boost::array loc_xyz; if (!condition(g)) continue; ang2vec(g.phi, g.theta, loc_xyz); for (int j = 0; j < LSS_DIMENSIONS; j++) { loc_xyz[j] = loc_xyz[j] * g.r - corner[j]; found_corners[j][0] = std::min(loc_xyz[j], found_corners[j][0]); found_corners[j][1] = std::max(loc_xyz[j], found_corners[j][1]); } std::copy(loc_xyz.begin(), loc_xyz.end(), xyz[accepted].begin()); weights[accepted] = g.final_w; accepted++; } Console::instance().format( "Using type %s for projection", typeid(Periodic).name()); Kernel::projection( xyz, field, L[0], L[1], L[2], N[0], N[1], N[2], Periodic(N[0], N[1], N[2]), weights, accepted); Console::instance().print( format("Project to grid: accepted %d galaxies") % accepted); { std::string cstr; for (int j = 0; j < LSS_DIMENSIONS; j++) cstr += str( format("(%lg - %lg) ") % found_corners[j][0] % found_corners[j][1]); Console::instance().print( "Project to grid: found corners " + cstr); } return accepted; } template < typename Kernel, typename Periodic, class GSurvey, typename DensityField, typename Dimension, typename IDimension> size_t galaxySurveyToGrid_all( const GSurvey &survey, DensityField &field, const IDimension &N, const Dimension &corner, const Dimension &L, const Dimension &d) { details::ProjectionAcceptAll condition; return galaxySurveyToGridGeneric( survey, field, N, corner, L, d, condition); } /* This function create a mock survey based on the selection function hold in survey_in and the full density field in field. */ template void createMockSurvey( const GSurvey &survey_in, GSurvey &survey_out, DensityField &field, const Dimension &corner, const Dimension &L) {} template < class GSurvey, typename DensityField, typename Grid, typename Dimension, typename Condition> size_t haloSimToGridGeneric( const GSurvey &sim, DensityField &field, const Grid &M, const Dimension &corner, const Dimension &L, const Dimension &d, Condition condition) { const typename DensityField::size_type *N = field.shape(); const typename DensityField::index *base = field.index_bases(); using boost::format; using boost::lambda::_1; size_t accepted = 0; double found_corners[LSS_DIMENSIONS][2]; for (auto i = 0; i < LSS_DIMENSIONS; i++) { found_corners[i][0] = std::numeric_limits::infinity(); found_corners[i][1] = -std::numeric_limits::infinity(); } for (auto i = 0; i < sim.surveySize(); i++) { typename GSurvey::ConstRefGalaxyType h = sim[i]; std::array< std::array, NR_CELLS_TOTAL> ii; std::array xyz; bool validLowerSlice = true; bool validUpperSlice = true; if (!condition(h)) continue; loadPosition(h.posx, h.posy, h.posz, xyz); for (int j = 0; j < LSS_DIMENSIONS; j++) { ii[0][j] = (int)std::floor((xyz[j] - corner[j]) / d[j]); found_corners[j][0] = std::min(xyz[j], found_corners[j][0]); found_corners[j][1] = std::max(xyz[j], found_corners[j][1]); } std::array weight; std::array, NR_CELLS_DIM> wxyz; for (auto j = 0; j < LSS_DIMENSIONS; j++) { wxyz[1][j] = ((xyz[j] - corner[j]) / d[j]) - ii[0][j]; wxyz[0][j] = TOTAL_WEIGHT - wxyz[1][j]; } weight[0] = wxyz[0][0] * wxyz[0][1] * wxyz[0][2]; weight[1] = wxyz[0][0] * wxyz[1][1] * wxyz[0][2]; weight[2] = wxyz[0][0] * wxyz[0][1] * wxyz[1][2]; weight[3] = wxyz[0][0] * wxyz[1][1] * wxyz[1][2]; weight[4] = wxyz[1][0] * wxyz[0][1] * wxyz[0][2]; weight[5] = wxyz[1][0] * wxyz[1][1] * wxyz[0][2]; weight[6] = wxyz[1][0] * wxyz[0][1] * wxyz[1][2]; weight[7] = wxyz[1][0] * wxyz[1][1] * wxyz[1][2]; for (auto j = 0; j < LSS_DIMENSIONS; j++) { if ((ii[0][j] == -1) || (ii[0][j] == M[j])) ii[0][j] = M[j] - 1; } for (auto cell = 1; cell < NR_CELLS_TOTAL; cell++) { std::copy(std::begin(ii[0]), std::end(ii[0]), std::begin(ii[cell])); } ii[1][1]++; ii[1][1] = (size_t)std::fmod(ii[1][1], M[1]); ii[2][2]++; ii[2][2] = (size_t)std::fmod(ii[2][2], M[2]); ii[3][1]++; ii[3][1] = (size_t)std::fmod(ii[3][1], M[1]); ii[3][2]++; ii[3][2] = (size_t)std::fmod(ii[3][2], M[2]); ii[4][0]++; ii[4][0] = (size_t)std::fmod(ii[4][0], M[0]); ii[5][0]++; ii[5][0] = (size_t)std::fmod(ii[5][0], M[0]); ii[5][1]++; ii[5][1] = (size_t)std::fmod(ii[5][1], M[1]); ii[6][0]++; ii[6][0] = (size_t)std::fmod(ii[6][0], M[0]); ii[6][2]++; ii[6][2] = (size_t)std::fmod(ii[6][2], M[2]); for (auto j = 0; j < LSS_DIMENSIONS; j++) { ii[7][j]++; ii[7][j] = (size_t)std::fmod(ii[7][j], M[j]); } for (auto j = 0; j < LSS_DIMENSIONS; j++) { validLowerSlice = validLowerSlice && (ii[0][j] >= base[j] && ii[0][j] < (base[j] + N[j])); validUpperSlice = validUpperSlice && (ii[4][j] >= base[j] && ii[4][j] < (base[j] + N[j])); } if (validLowerSlice) { for (auto cell = 0; cell < NR_CELLS_SLICE; cell++) { field(ii[cell]) += weight[cell] * h.w; accepted++; } } if (validUpperSlice) { for (auto cell = NR_CELLS_SLICE; cell < NR_CELLS_TOTAL; cell++) { field(ii[cell]) += weight[cell] * h.w; accepted++; } } } Console::instance().print( format("Project to grid: accept and assign halos to %d cells") % accepted); { std::string cstr; for (auto j = 0; j < LSS_DIMENSIONS; j++) cstr += str( format("(%lg - %lg) ") % found_corners[j][0] % found_corners[j][1]); Console::instance().print( "Project to grid: found corners " + cstr); } return accepted; } template < class GSurvey, typename DensityField, typename Grid, typename Dimension> size_t haloSimToGrid_all( const GSurvey &sim, DensityField &field, const Grid &M, const Dimension &corner, const Dimension &L, const Dimension &d) { details::ProjectionAcceptAll condition; return haloSimToGridGeneric< GSurvey, DensityField, Grid, Dimension, details::ProjectionAcceptAll>( sim, field, M, corner, L, d, condition); } }; // namespace LibLSS CTOOL_ENUM_TYPE( LibLSS::ProjectionDataModel, HDF5T_ProjectionDataModel, (LibLSS::NGP_PROJECTION)(LibLSS::LUMINOSITY_CIC_PROJECTION)) #endif