/*+ ARES/HADES/BORG Package -- ./libLSS/tools/array_tools.hpp Copyright (C) 2014-2020 Guilhem Lavaux Copyright (C) 2009-2020 Jens Jasche Additional contributions from: Guilhem Lavaux (2023) +*/ #ifndef __LIBLSS_ARRAY_TOOLS_HPP #define __LIBLSS_ARRAY_TOOLS_HPP #include "libLSS/tools/errors.hpp" #include "libLSS/tools/align_helper.hpp" #include #include #include #include "libLSS/tools/fused_array.hpp" namespace LibLSS { namespace array { typedef boost::multi_array_types::extent_range erange; typedef boost::multi_array_types::index_range irange; template struct EigenMap { typedef typename InArray::element T; typedef Eigen::Array E_Array; typedef Eigen::Map MapArray; static MapArray map(InArray& a) { return MapArray(a.data(), a.num_elements()); } }; template typename EigenMap::MapArray eigen_map(InArray& a) { return EigenMap::map(a); } template void fill(Array& a, typename Array::element val) { using boost::lambda::constant; typedef typename Array::element VArrayType; LibLSS::copy_array(a, b_fused(constant(val))); } template void density_rescale(Array& a, typename Array::element val) { using boost::lambda::_1; LibLSS::copy_array(a, b_fused(a, _1 / val - 1));//omptl::for_each(a.data(), a.data()+a.num_elements(), _1 / val - 1); } template void copyArray3d(OutArray& out, const InArray& in, bool in_padded = false) { if (!in_padded && (out.shape()[0] < in.shape()[0] || out.shape()[1] < in.shape()[1] || out.shape()[2] < in.shape()[2])) { error_helper("Invalid copy shape in copyArray3d"); } LibLSS::copy_array(out, in); } template void scaleArray3d(InOutArray& out, typename InOutArray::element scale) { using boost::lambda::_1; LibLSS::copy_array(out, b_fused(out, _1*scale)); } template T product(std::array const& d) { T a = T(1); for (size_t i = 0; i < n; i++) a *= d[i]; return a; } template())>::type> T product(Iterator b, Iterator e) { T a = T(1); while (b != e) { a *= *b; ++b; } return a; } template void scalePlane(InOutPlane plane, typename InOutPlane::element scale) { const typename InOutPlane::index *base = plane.index_bases(); const typename InOutPlane::size_type *exts = plane.shape(); for (long i = base[0]; i < base[0] + exts[0]; i++) { for (long j = base[1]; j < base[1] + exts[1]; j++) { plane[i][j] *= scale; } } } template void scaleLine(InOutLine line, typename InOutLine::element scale) { const typename InOutLine::index *base = line.index_bases(); const typename InOutLine::size_type *exts = line.shape(); for (long i = base[0]; i < base[0] + exts[0]; i++) { line[i] *= scale; } } template void scaleAndCopyArray3d_rv(OutArray out, const InArray& in, typename OutArray::element scale) { using boost::format; long N0 = out.shape()[0], N1 = out.shape()[1], N2 = out.shape()[2]; Console& cons = Console::instance(); N0 = std::min(N0,long(in.shape()[0])); N1 = std::min(N1,long(in.shape()[1])); N2 = std::min(N2,long(in.shape()[2])); long s0 = out.index_bases()[0], s1 = out.index_bases()[1], s2 = out.index_bases()[2]; long i_s0 = in.index_bases()[0], i_s1 = in.index_bases()[1], i_s2 = in.index_bases()[2]; cons.print(format("Copying (%d-%d, %d-%d, %d-%d) -> (%d-%d, %d-%d, %d-%d)") % i_s0 % (i_s0+N0) % i_s1 % (i_s1+N1) % i_s2 % (i_s2+N2) % s0 % (s0+N0) % s1 % (s1+N1) % s2 % (s2+N2)); #pragma omp parallel for for (long n0 = 0; n0 < N0; n0++) { typename OutArray::reference out0 = out[s0+n0]; typename InArray::const_reference in0 = in[i_s0+n0]; cons.print(format("Line %d") % n0); for (long n1 = 0; n1 < N1; n1++) { typename OutArray::reference::reference out1 = out0[s1+n1]; typename InArray::const_reference::const_reference in1 = in0[i_s1+n1]; for (long n2 = 0; n2 < N2; n2++) { out1[s2+n2] = in1[i_s2+n2]*scale; } } } cons.print("Done copy"); } template void scaleAndCopyArray3d(OutArray& out, const InArray& in, typename OutArray::element scale, bool in_padded = false) { using boost::format; size_t N0 = out.shape()[0], N1 = out.shape()[1], N2 = out.shape()[2]; if (!in_padded && (N0 < in.shape()[0] || N1 < in.shape()[1] || N2 < in.shape()[2])) { error_helper("Invalid copy shape in scaleAndcopyArray3d"); } N0 = std::min(N0,in.shape()[0]); N1 = std::min(N1,in.shape()[1]); N2 = std::min(N2,in.shape()[2]); ssize_t s0 = out.index_bases()[0], s1 = out.index_bases()[1], s2 = out.index_bases()[2]; Console::instance().print(format("Copying (%d-%d, %d-%d, %d-%d)") % s0 % (s0+N0) % s1 % (s1+N1) % s2 % (s2+N2)); #pragma omp parallel for for (size_t n0 = s0; n0 < s0+N0; n0++) { auto out_0 = out[n0]; auto in_0 = in[n0]; for (size_t n1 = s1; n1 < s1+N1; n1++) { auto out_1 = out_0[n1]; auto in_1 = in_0[n1]; for (size_t n2 = s2; n2 < s2+N2; n2++) { out_1[n2] = in_1[n2]*scale; } } } Console::instance().print("Done copy"); } template auto generate_slice(T x[6]) { typedef boost::multi_array_types::index_range i_range; return boost::indices[i_range(x[0], x[1])][i_range(x[2],x[3])][i_range(x[4],x[5])]; } template auto slice_array(A&& a, const RangeList& rlist) -> decltype(a[rlist]) { auto v = a[rlist]; typedef typename std::remove_reference::type A_t; boost::array ids; size_t i = 0 ; for (auto v: rlist.ranges_) { ids[i] = v.get_start(a.index_bases()[i]); i++; } v.reindex(ids); return v; } namespace details { typedef boost::multi_array_types::extent_range range; template struct make_extent { template static inline auto make(E e, IB ib, S s) { return make_extent::make(e[range(*ib, *ib+*s)], ib+1, s+1); } }; template<> struct make_extent<0> { template static inline auto make(E e, IB ib, S s) { return e; } }; } namespace star_index_detail { template auto _make_star_indices(I indices, std::integer_sequence) { return indices; } template auto _make_star_indices(I indices, std::integer_sequence) { typedef boost::multi_array_types::index_range i_range; return _make_star_indices(indices, std::integer_sequence())[i_range()]; } template auto make_star_indices(I indices) { return _make_star_indices(indices, std::make_integer_sequence()); } } using star_index_detail::make_star_indices; template auto make_extent(IB bases, S shape, E e = E()) { return details::make_extent::make( e, bases, shape ); } template auto extent(I... i) { std::array s{i...}; std::array b; std::fill(b.begin(), b.end(), 0); return make_extent(b.data(), s.data()); } /** * @brief build a new extent object from the dimensions of an existing array-like type. * * @return an extent */ template auto make_extent_from(A&& a, E e = E()) { return make_extent::type::dimensionality>(a.index_bases(), a.shape(), e); } template void reorder(const IndexArray& part_idx, SwapFunc func) { size_t numPart = part_idx.shape()[0], i = 0; boost::multi_array sorter(boost::extents[numPart]); LibLSS::copy_array(sorter, part_idx); // Now that partices have been gathered back, we have to reorder them // to "unsort". while (i < numPart) { typename IndexArray::reference swapper = sorter[i]; if (swapper == i) { i++; continue; } func(swapper, i); std::swap(sorter[i], sorter[swapper]); } } }; }; #endif