/** * \file GridClosePairsFinder.cpp * \brief Test all pairs. * * Copyright 2007-2010 IMP Inventors. All rights reserved. * */ #include "IMP/core/GridClosePairsFinder.h" #include "IMP/core/QuadraticClosePairsFinder.h" #include "IMP/core/XYZR.h" #include #include IMPCORE_BEGIN_NAMESPACE namespace { inline bool get_interiors_intersect(const algebra::Vector3D &v, double ra, double rb) { double sr= ra+rb; for (unsigned int i=0; i< 3; ++i) { double a=std::abs(v[i]); if (a >= sr) return false; } return v*v < square(sr); } inline bool get_is_wrapped(unsigned int merged, unsigned int k) { IMP_USAGE_CHECK(k<=2, "bad k"); return merged& (1 << k); } struct ParticleID { typedef Particle* result_type; Particle* operator()(Particle *p) const {return p;} }; struct ParticleCenter { algebra::Vector3D operator()(Particle *p) const { return XYZ(p).get_coordinates(); } }; struct ParticleRadius { double operator()(Particle *p) const { return XYZR(p).get_radius(); } }; struct ParticleClose { double d_; ParticleClose(double d): d_(d){} double operator()(Particle *a, Particle *b) const { return get_interiors_intersect(XYZR(a).get_coordinates() -XYZR(b).get_coordinates(), XYZR(b).get_radius()+d_, XYZR(a).get_radius()); } }; struct PeriodicParticleClose { algebra::Vector3D uc_; unsigned int merged_; double d_; PeriodicParticleClose(const algebra::BoundingBox3D &bb, unsigned int merged, double d): uc_(bb.get_corner(1)- bb.get_corner(0)), merged_(merged), d_(d){} double operator()(Particle *a, Particle *b) const { algebra::Vector3D diff = XYZR(a).get_coordinates()- XYZR(b).get_coordinates(); for (unsigned int i=0; i< 3; ++i) { if (get_is_wrapped(merged_, i)) { if (diff[i] > .5*uc_[i]) diff[i]-=uc_[i]; else if (diff[i] < -.5*uc_[i]) diff[i]+=uc_[i]; } } return get_interiors_intersect(diff, XYZR(a).get_radius(), XYZR(b).get_radius()+d_); } }; struct BBID { algebra::BoundingBox3Ds::const_iterator it_; BBID(algebra::BoundingBox3Ds::const_iterator it): it_(it){} typedef unsigned int result_type; unsigned int operator()(const algebra::BoundingBox3D &bb) const { return &bb-&*it_; } }; struct BBRadius { algebra::BoundingBox3Ds::const_iterator it_; BBRadius(algebra::BoundingBox3Ds::const_iterator it): it_(it){} double operator()(unsigned int i) const { return algebra::get_maximum_length(*(it_+i)); } }; struct BBCenter { algebra::BoundingBox3Ds::const_iterator it_; BBCenter(algebra::BoundingBox3Ds::const_iterator it): it_(it){} algebra::Vector3D operator()(unsigned int i) const { return algebra::Vector3D(.5*((it_+i)->get_corner(0) +(it_+i)->get_corner(1))); } }; struct PeriodicBBClose { double d_; algebra::Vector3D uc_; unsigned int merged_; algebra::BoundingBox3Ds::const_iterator it0_, it1_; PeriodicBBClose(algebra::BoundingBox3Ds::const_iterator it0, algebra::BoundingBox3Ds::const_iterator it1, const algebra::BoundingBox3D &bb, unsigned int merged, double d): d_(d), uc_(bb.get_corner(1) - bb.get_corner(0)), merged_(merged), it0_(it0), it1_(it1){} double operator()(unsigned int a, unsigned int b) const { for (unsigned int i=0; i< 3; ++i) { if (get_is_wrapped(merged_, i)) { bool ok=false; for (int o=-1; o < 2; ++o) { double ub0= uc_[i]*o + (it1_+b)->get_corner(1)[i]+d_; if ((it0_+a)->get_corner(0)[i] > ub0) { continue; } double ub1= uc_[i]*o + (it0_+1)->get_corner(1)[i]+d_; if ((it1_+b)->get_corner(0)[i] > ub1) { continue; } ok=true; break; } if (!ok) return false; } else { if ((it0_+a)->get_corner(0)[i] > (it1_+b)->get_corner(1)[i]+d_) return false; if ((it0_+a)->get_corner(1)[i]+d_ < (it1_+b)->get_corner(0)[i]) return false; } } return true; } }; struct BBClose { double d_; algebra::BoundingBox3Ds::const_iterator it0_, it1_; BBClose(algebra::BoundingBox3Ds::const_iterator it0, algebra::BoundingBox3Ds::const_iterator it1, double d): d_(d), it0_(it0), it1_(it1){} double operator()(unsigned int a, unsigned int b) const { algebra::BoundingBox3D ag= *(it0_+a)+d_; return algebra::get_interiors_intersect(ag, *(it1_+b)); } }; double get_side(const algebra::BoundingBox3D &bb, unsigned int nump, double r, double d, double maxr) { return 1.1*(r+maxr+d); } std::string do_show(Particle*p) { return p->get_name(); } algebra::BoundingBox3D do_show(algebra::BoundingBox3D bb) { return bb; } unsigned int do_show(unsigned int i) { return i; } template struct Helper { typedef typename IDF::result_type ID; typedef std::vector IDs; typedef typename algebra::SparseGrid3D Grid; typedef std::vector Grids; template struct ParticleSet { It b_, e_; IDF id_; CenterF c_; RadiusF r_; ParticleSet(It b, It e, IDF id, CenterF c, RadiusF r): b_(b), e_(e), id_(id), c_(c), r_(r){} }; template static ParticleSet get_particle_set(It b, It e, IDF id, CenterF c, RadiusF r) { return ParticleSet(b,e,id, c,r); } template struct IDSet { It b_, e_; CenterF c_; RadiusF r_; IDSet(It b, It e, CenterF c, RadiusF r): b_(b), e_(e), c_(c), r_(r){} }; template static IDSet get_id_set(It b, It e, CenterF c, RadiusF r) { return IDSet(b,e,c,r); } static int get_index(int ii, int which, int lb, int ub) { if (which==1) { if (ii== lb) ii= ub; else if (ii == ub) ii= lb; } return ii; } template static void fill_copies_periodic(const Grid &g, Index cur, unsigned int merged, typename Grid::ExtendedIndex bblb, typename Grid::ExtendedIndex bbub, bool half, std::vector &out) { typename Grid::ExtendedIndex curei(cur[0], cur[1], cur[2]); for (int io=-1; io < 2; ++io) { if ((!(merged &GridClosePairsFinder::X)) && io != 0) continue; int ii=cur[0]+io*(bbub[0]-bblb[0]-1); if (ii < 0 || ii >= static_cast(g.get_number_of_voxels(0))) continue; for (int jo=-1; jo < 2; ++jo) { if ((!(merged &GridClosePairsFinder::Y)) && jo != 0) continue; int ij=cur[1]+jo*(bbub[1]-bblb[1]-1); if (ij < 0 || ij >= static_cast(g.get_number_of_voxels(1))) continue; for (int ko=-1; ko < 2; ++ko) { if ((!(merged &GridClosePairsFinder::Z)) && ko != 0) continue; int ik=cur[2]+ko*(bbub[2]-bblb[2]-1); if (ik < 0 || ik >= static_cast(g.get_number_of_voxels(2))) continue; typename Grid::ExtendedIndex cei(ii, ij, ik); if (!g.get_has_index(cei)) continue; // make sure equivalent voxels are only added once if ((half && cei < curei) || (!half && curei != cei)) { out.push_back(g.get_index(cei)); } } } } } static std::vector get_nearby(const Grid &g, typename Grid::ExtendedIndex center, typename Grid::ExtendedIndex bblb, typename Grid::ExtendedIndex bbub, unsigned int merged, bool half) { std::vector out; typename Grid::ExtendedIndex lb(center.get_offset(-1, -1, -1)), ub(center.get_offset(1, 1, 1)); if (half) { IMP_GRID3D_FOREACH_SMALLER_EXTENDED_INDEX_RANGE(g, center, lb, ub, { fill_copies_periodic(g, voxel_index, merged, bblb, bbub, true, out); typename Grid::ExtendedIndex ei(voxel_index[0], voxel_index[1], voxel_index[2]); if (g.get_has_index(ei)) { out.push_back(g.get_index(ei)); } }); fill_copies_periodic(g, center, merged, bblb, bbub, true, out); } else { for (typename Grid::ExtendedIndexIterator it = g.extended_indexes_begin(lb, ub); it != g.extended_indexes_end(lb, ub); ++it) { fill_copies_periodic(g, *it,merged, bblb, bbub, false, out); if (g.get_has_index(*it)) { out.push_back(g.get_index(*it)); } } // skipped in there out.push_back(g.get_index(center)); } // would be nice to not have duplicates std::sort(out.begin(), out.end()); out.erase(std::unique(out.begin(), out.end()), out.end()); return out; } static std::vector get_nearby(const Grid &g, typename Grid::ExtendedIndex center, double half) { std::vector out; typename Grid::ExtendedIndex lb(center.get_offset(-1, -1, -1)), ub(center.get_offset(1, 1, 1)); if (half) { IMP_GRID3D_FOREACH_SMALLER_EXTENDED_INDEX_RANGE(g, center, lb, ub, { typename Grid::ExtendedIndex ei(voxel_index[0], voxel_index[1], voxel_index[2]); if (g.get_has_index(ei)) { out.push_back(g.get_index(ei)); } } ); } else { for (typename Grid::ExtendedIndexIterator it = g.extended_indexes_begin(lb, ub); it != g.extended_indexes_end(lb, ub); ++it) { if (g.get_has_index(*it)) { out.push_back(g.get_index(*it)); } } } return out; } template static double get_max_radius(const ParticleSet &ps0) { double maxr=0; for (It c= ps0.b_; c != ps0.e_; ++c) { maxr=std::max(ps0.r_(ps0.id_(*c))+0, maxr); } return maxr; } static algebra::BoundingBox3D get_bb(const IDs& ids, CenterF cc) { algebra::BoundingBox3D bb; for (typename IDs::const_iterator c= ids.begin(); c != ids.end(); ++c) { bb+=cc(*c); } return bb; } template static void partition_points(const ParticleSet &ps, double distance, typename std::vector &bin_contents, typename std::vector &bin_ubs) { bin_contents.push_back(IDs()); for (It c= ps.b_; c != ps.e_; ++c) { double cr= ps.r_(ps.id_(*c))+0; while (cr < std::max(.5*bin_ubs.back()-.5*distance, 0.0)) { double v=std::max(.5*bin_ubs.back()-.5*distance, 0.1); if (v > .1) { bin_ubs.push_back(v); } else break; } for ( int i=bin_ubs.size()-1; i >=0; --i) { if (cr <= bin_ubs[i] || i==0) { while (static_cast(bin_contents.size()) < i+1) { bin_contents.push_back(IDs()); } bin_contents[i].push_back(ps.id_(*c)); break; } } } IMP_IF_CHECK(USAGE_AND_INTERNAL) { int total=0; for (unsigned int i=0; i< bin_contents.size(); ++i) { total+= bin_contents[i].size(); } IMP_INTERNAL_CHECK(total == std::distance(ps.b_, ps.e_), "Lost points " << total << " " << std::distance(ps.b_, ps.e_)); } } static Grid create_grid(const algebra::BoundingBox3D &bb, double side) { return Grid(side, bb); } static void fill_grid(const IDs &ids, CenterF cf, Grid &g) { for (typename IDs::const_iterator c= ids.begin(); c != ids.end(); ++c) { algebra::Vector3D v= cf(*c); typename Grid::ExtendedIndex ind =g.get_nearest_extended_index(v); if (g.get_has_index(ind)) { g[g.get_index(ind)].push_back(*c); } else { g.add_voxel(ind, IDs(1, *c)); } } IMP_IF_LOG(VERBOSE) { IMP_LOG(VERBOSE, "Grid built" << std::endl); for (typename Grid::AllConstIterator it= g.all_begin(); it != g.all_end(); ++it) { IMP_INTERNAL_CHECK(it->second.size() >0, "Empty voxel"); IMP_LOG(VERBOSE, "Voxel " << it->first << " has "); for (unsigned int i=0; i< it->second.size(); ++i) { IMP_LOG(VERBOSE, do_show(it->second[i]) << " "); } IMP_LOG(VERBOSE, std::endl); } } } template static void do_fill_close_pairs_from_list(It b, It e, CloseF close, Out &out) { for (It c= b; c != e; ++c) { for (It cp= b; cp != c; ++cp) { if (close(*c, *cp)) { IMP_LOG(VERBOSE, "Found pair " << do_show(*c) << " " << do_show(*cp) << std::endl); out.push_back( typename Out::value_type(*c, *cp)); } } } } template static void do_fill_close_pairs_from_lists(ItA ab, ItA ae, ItB bb, ItB be, CloseF close, Out &out) { for (ItA c= ab; c != ae; ++c) { for (ItB cp= bb; cp != be; ++cp) { if (close(*c, *cp)) { IMP_LOG(VERBOSE, "Found pair " << do_show(*c) << " " << do_show(*cp) << std::endl); out.push_back( typename Out::value_type(*c, *cp)); } } } } static void do_fill_close_pairs(const Grid &gg, typename Grid::Index index, const IDs &qps, bool half, CloseF close, Out& out) { const std::vector ids = get_nearby(gg, gg.get_extended_index(index), half); for (unsigned int i=0; i< ids.size(); ++i) { IMP_LOG(VERBOSE, "Checking pair " << ids[i] << " " << index << std::endl); do_fill_close_pairs_from_lists(gg[ids[i]].begin(), gg[ids[i]].end(), qps.begin(), qps.end(), close, out); } if (half) { IMP_LOG(VERBOSE, "Checking pair " << index << " " << index << std::endl); do_fill_close_pairs_from_list(gg[index].begin(), gg[index].end(), close, out); } } static void do_fill_close_pairs(const Grid &gg, typename Grid::Index index, const IDs &qps, const algebra::BoundingBox3D &bb, unsigned int merged, bool half, CloseF close, Out& out) { typename Grid::ExtendedIndex bblb = gg.get_extended_index(bb.get_corner(0)); typename Grid::ExtendedIndex bbub = gg.get_extended_index(bb.get_corner(1)); const std::vector ids = get_nearby(gg, gg.get_extended_index(index), bblb, bbub, merged, half); for (unsigned int i=0; i< ids.size(); ++i) { IMP_LOG(VERBOSE, "Checking pair " << ids[i] << " " << index << std::endl); do_fill_close_pairs_from_lists(gg[ids[i]].begin(), gg[ids[i]].end(), qps.begin(), qps.end(), close, out); } if (half) { IMP_LOG(VERBOSE, "Checking pair " << index << " " << index << std::endl); do_fill_close_pairs_from_list(gg[index].begin(), gg[index].end(), close, out); } } template static void fill_close_pairs(const ParticleSet &ps, CloseF close, double distance, const algebra::BoundingBox3D& bb, unsigned int merged, Out &out) { double maxr=get_max_radius(ps); std::vector bin_contents_g; std::vector bin_ubs; bin_ubs.push_back(maxr); partition_points(ps, distance, bin_contents_g, bin_ubs); IMP_LOG(VERBOSE, "Divided points into " << bin_contents_g.size() << " bins (" << bin_ubs.size() << ") " << maxr << std::endl); IMP_IF_LOG(VERBOSE) { IMP_LOG(VERBOSE, "For G, contents are " << std::endl); for (unsigned int i=0; i< bin_contents_g.size(); ++i) { IMP_LOG(VERBOSE, i << " " << bin_ubs[i] << " " << bin_contents_g[i].size() << std::endl); } } std::vector bbs(bin_contents_g.size()); for (unsigned int i=0; i< bin_contents_g.size(); ++i) { bbs[i]= get_bb(bin_contents_g[i], ps.c_); } for (unsigned int i=0; i< bin_contents_g.size(); ++i) { if (bin_contents_g[i].empty()) continue; if (bin_contents_g[i].size() < 5) { do_fill_close_pairs_from_list(bin_contents_g[i].begin(), bin_contents_g[i].end(), close, out); } else { Grid gg = create_grid(bbs[i], distance+2*bin_ubs[i]); fill_grid(bin_contents_g[i], ps.c_, gg); for (typename Grid::AllConstIterator it = gg.all_begin(); it != gg.all_end(); ++it) { if (merged) { do_fill_close_pairs(gg, it->first, it->second, bb, merged, true, close, out); } else { do_fill_close_pairs(gg, it->first, it->second,true, close, out); } } } for (unsigned int j=0; j< i; ++j) { if (bin_contents_g[j].empty()) continue; algebra::BoundingBox3D bb= bbs[i]+bbs[j]; IMP_LOG(VERBOSE, "Building grids for " << i << " and " << j << " with bb " << bb << " and side " << distance+bin_ubs[i]+bin_ubs[j] << std::endl); Grid ggi, ggj; ggi= create_grid(bb, distance+bin_ubs[i]+bin_ubs[j]); ggj=ggi; fill_grid(bin_contents_g[i], ps.c_, ggi); fill_grid(bin_contents_g[j], ps.c_, ggj); for (typename Grid::AllConstIterator it = ggj.all_begin(); it != ggj.all_end(); ++it) { if (merged) { do_fill_close_pairs(ggi, it->first, it->second, bb, merged, false, close, out); } else { do_fill_close_pairs(ggi, it->first, it->second, false, close, out); } } } } } template static void fill_close_pairs(const ParticleSet &psg, const ParticleSet &psq, CloseF close, double distance, const algebra::BoundingBox3D& bb, unsigned int merged, Out &out) { double maxr=std::max(get_max_radius(psg), get_max_radius(psq)); std::vector bin_contents_g, bin_contents_q; std::vector bin_ubs; bin_ubs.push_back(maxr); partition_points(psg, distance, bin_contents_g, bin_ubs); partition_points(psq, distance, bin_contents_q, bin_ubs); IMP_LOG(VERBOSE, "Divided pints into " << bin_contents_g.size() << " and " << bin_contents_q.size() << " bins (" << bin_ubs.size() << ") " << maxr << std::endl); IMP_IF_LOG(VERBOSE) { IMP_LOG(VERBOSE, "For G, contents are " << std::endl); for (unsigned int i=0; i< bin_contents_g.size(); ++i) { IMP_LOG(VERBOSE, i << " " << bin_ubs[i] << " " << bin_contents_g[i].size() << std::endl); } IMP_LOG(VERBOSE, "For Q, contents are " << std::endl); for (unsigned int i=0; i< bin_contents_q.size(); ++i) { IMP_LOG(VERBOSE, i << " " << bin_ubs[i] << " " << bin_contents_q[i].size() << std::endl); } } std::vector bbs_g(bin_contents_g.size()); for (unsigned int i=0; i< bin_contents_g.size(); ++i) { bbs_g[i]= get_bb(bin_contents_g[i], psg.c_); } std::vector bbs_q(bin_contents_q.size()); for (unsigned int i=0; i< bin_contents_q.size(); ++i) { bbs_q[i]= get_bb(bin_contents_q[i], psq.c_); } for (unsigned int i=0; i< bin_contents_g.size(); ++i) { if (bin_contents_g[i].empty()) continue; for (unsigned int j=0; j< bin_contents_q.size(); ++j) { if (bin_contents_q[j].empty()) continue; algebra::BoundingBox3D bb= bbs_g[i]+bbs_q[j]; if (bin_contents_g[i].size() < 5 && bin_contents_q[j].size() < 5) { do_fill_close_pairs_from_lists(bin_contents_g[i].begin(), bin_contents_g[i].end(), bin_contents_q[j].begin(), bin_contents_q[j].end(), close, out); } else { IMP_LOG(VERBOSE, "Building grids for " << i << " and " << j << " with bb " << bb << " and side " << distance+bin_ubs[i]+bin_ubs[j] << std::endl); Grid gg, gq; gg= create_grid(bb, distance+bin_ubs[i]+bin_ubs[j]); gq= gg; fill_grid(bin_contents_g[i], psg.c_, gg); fill_grid(bin_contents_q[j], psq.c_, gq); IMP_IF_CHECK(USAGE) { for (unsigned int i=0; i< 3; ++i) { IMP_USAGE_CHECK(gg.get_number_of_voxels(i) == gq.get_number_of_voxels(i), "Do not match on dimension i " << gg.get_number_of_voxels(i) << " vs " << gq.get_number_of_voxels(i)); } } for (typename Grid::AllConstIterator it = gq.all_begin(); it != gq.all_end(); ++it) { if (merged) { do_fill_close_pairs(gg, it->first, it->second, bb, merged, false, close, out); } else { do_fill_close_pairs(gg, it->first, it->second, false, close, out); } } } } } } }; typedef Helper ParticleHelper; typedef Helper BBHelper; typedef Helper PParticleHelper; typedef Helper PBBHelper; } GridClosePairsFinder::GridClosePairsFinder(): ClosePairsFinder("GridCPF"), merged_(0) {} GridClosePairsFinder::GridClosePairsFinder(const algebra::BoundingBox3D &bb, unsigned int merged_boundaries): ClosePairsFinder("PeriodicGridCPF"), bb_(bb), merged_(merged_boundaries) {} ParticlePairsTemp GridClosePairsFinder ::get_close_pairs(const ParticlesTemp &ca, const ParticlesTemp &cb) const { IMP_OBJECT_LOG; set_was_used(true); ParticlePairsTemp out; if (merged_) { PParticleHelper ::fill_close_pairs(PParticleHelper ::get_particle_set(ca.begin(), ca.end(), ParticleID(), ParticleCenter(), ParticleRadius()), PParticleHelper ::get_particle_set(cb.begin(), cb.end(), ParticleID(), ParticleCenter(), ParticleRadius()), PeriodicParticleClose(bb_, merged_, get_distance()), get_distance(), bb_, merged_, out); } else { ParticleHelper ::fill_close_pairs(ParticleHelper ::get_particle_set(ca.begin(), ca.end(), ParticleID(), ParticleCenter(), ParticleRadius()), ParticleHelper ::get_particle_set(cb.begin(), cb.end(), ParticleID(), ParticleCenter(), ParticleRadius()), ParticleClose(get_distance()), get_distance(), bb_, merged_, out); } return out; } ParticlePairsTemp GridClosePairsFinder ::get_close_pairs(const ParticlesTemp &c) const { IMP_OBJECT_LOG; set_was_used(true); IMP_LOG(TERSE, "Rebuilding NBL with Grid and cutoff " << get_distance() << std::endl ); ParticlePairsTemp out; if (merged_) { PParticleHelper ::fill_close_pairs(PParticleHelper::get_particle_set(c.begin(), c.end(), ParticleID(), ParticleCenter(), ParticleRadius()), PeriodicParticleClose(bb_, merged_, get_distance()), get_distance(), bb_, merged_, out); } else { ParticleHelper ::fill_close_pairs(ParticleHelper::get_particle_set(c.begin(), c.end(), ParticleID(), ParticleCenter(), ParticleRadius()), ParticleClose(get_distance()), get_distance(), bb_, merged_, out); } return out; } IntPairs GridClosePairsFinder ::get_close_pairs(const algebra::BoundingBox3Ds &bas, const algebra::BoundingBox3Ds &bbs) const { IMP_OBJECT_LOG; set_was_used(true); IntPairs out; if (merged_) { PBBHelper:: fill_close_pairs(PBBHelper::get_particle_set(bas.begin(), bas.end(), BBID(bas.begin()), BBCenter(bas.begin()), BBRadius(bas.begin())), PBBHelper::get_particle_set(bbs.begin(), bbs.end(), BBID(bbs.begin()), BBCenter(bbs.begin()), BBRadius(bbs.begin())), PeriodicBBClose(bas.begin(), bbs.begin(), bb_, merged_, get_distance()), get_distance(), bb_, merged_, out); } else { BBHelper:: fill_close_pairs(BBHelper::get_particle_set(bas.begin(), bas.end(), BBID(bas.begin()), BBCenter(bas.begin()), BBRadius(bas.begin())), BBHelper::get_particle_set(bbs.begin(), bbs.end(), BBID(bbs.begin()), BBCenter(bbs.begin()), BBRadius(bbs.begin())), BBClose(bas.begin(), bbs.begin(), get_distance()), get_distance(), bb_, merged_, out); } return out; } IntPairs GridClosePairsFinder ::get_close_pairs(const algebra::BoundingBox3Ds &bas) const { IMP_OBJECT_LOG; set_was_used(true); IntPairs out; if (merged_) { PBBHelper ::fill_close_pairs(PBBHelper::get_particle_set(bas.begin(), bas.end(), BBID(bas.begin()), BBCenter(bas.begin()), BBRadius(bas.begin())), PeriodicBBClose(bas.begin(), bas.begin(), bb_, merged_, get_distance()), get_distance(), bb_, merged_, out); } else { BBHelper ::fill_close_pairs(BBHelper::get_particle_set(bas.begin(), bas.end(), BBID(bas.begin()), BBCenter(bas.begin()), BBRadius(bas.begin())), BBClose(bas.begin(), bas.begin(), get_distance()), get_distance(), bb_, merged_, out); } return out; } void GridClosePairsFinder::do_show(std::ostream &out) const { out << "distance " << get_distance() << std::endl; } ParticlesTemp GridClosePairsFinder::get_input_particles(const ParticlesTemp &ps) const { return ps; } ContainersTemp GridClosePairsFinder::get_input_containers(const ParticlesTemp &ps) const { return ContainersTemp(); } IMPCORE_END_NAMESPACE