12#include "gadgetconfig.h"
22#include "../data/allvars.h"
23#include "../data/dtypes.h"
24#include "../data/intposconvert.h"
25#include "../data/mymalloc.h"
26#include "../domain/domain.h"
27#include "../fof/fof.h"
28#include "../logs/timer.h"
29#include "../main/simulation.h"
30#include "../mpi_utils/generic_comm.h"
31#include "../mpi_utils/mpi_utils.h"
32#include "../ngbtree/ngbtree.h"
33#include "../sort/cxxsort.h"
34#include "../system/system.h"
39#if defined(LIGHTCONE_PARTICLES_GROUPS)
40 double DistanceOrigin;
55template <
typename T_tree,
typename T_domain,
typename T_partset>
56class foffind_comm :
public generic_comm<foffind_in, foffind_out, T_tree, T_domain, T_partset>
66 foffind_comm(T_domain *dptr, T_tree *tptr, T_partset *pptr) : gcomm(dptr, tptr, pptr) {}
70 for(
int k = 0; k < 3; k++)
71 in->IntPos[k] = Tp->P[i].IntPos[k];
73 in->MinID = Tp->MinID[Tp->Head[i]];
74 in->MinIDTask = Tp->MinIDTask[Tp->Head[i]];
76#
if defined(LIGHTCONE_PARTICLES_GROUPS)
77 in->DistanceOrigin = Tp->DistanceOrigin[Tp->Head[i]];
81 void out2particle(foffind_out *out,
int i,
int mode)
override
89 if(out->link_count_flag)
90 Tp->Flags[i].Marked = 1;
94 int evaluate(
int target,
int mode,
int thread_id,
int action, foffind_in *in,
int numnodes,
node_info *firstnode,
95 foffind_out &out)
override
97 memset(&out, 0,
sizeof(out));
99#if defined(LIGHTCONE_PARTICLES_GROUPS)
100 double target_DistanceOrigin = in->DistanceOrigin;
102 double target_DistanceOrigin = 0;
105 int numngb = Tree->treefind_fof_primary(in->IntPos, Tp->LinkL, target, mode, &Thread, numnodes, firstnode, Thread.Ngblist,
106 in->MinID, in->MinIDTask, target_DistanceOrigin);
111 out.link_count_flag = 1;
113 out.link_count_flag = 0;
120template <
typename partset>
121double fof<partset>::fof_find_groups(
void)
127 Tp->Flags = (
typename partset::bit_flags *)
Mem.mymalloc_clear(
"Flags", Tp->NumPart *
sizeof(
typename partset::bit_flags));
129 FoFNgbTree.FullyLinkedNodePIndex = (
int *)
Mem.mymalloc(
"FullyLinkedNodePIndex", FoFNgbTree.NumNodes *
sizeof(
int));
130 FoFNgbTree.FullyLinkedNodePIndex -= FoFNgbTree.MaxPart;
132 for(
int i = 0; i < FoFNgbTree.NumNodes; i++)
134 int no = i + FoFNgbTree.MaxPart;
135 FoFNgbTree.FullyLinkedNodePIndex[no] = -1;
140 for(
int i = 0; i < FoFNgbTree.NumNodes; i++)
142 int no = i + FoFNgbTree.MaxPart;
144 if(FoFNgbTree.FullyLinkedNodePIndex[no] < 0)
146 if(FoFNgbTree.get_nodep(no)->level > 0)
151 int q = FoFNgbTree.treefind_fof_return_a_particle_in_cell_recursive(no);
154 FoFNgbTree.fof_link_particles_in_cell_recursive(no, q);
160 mpi_printf(
"FOF: linking of small cells took %g sec\n",
Logs.
timediff(taa, tbb));
163 int *targetlist = (
int *)
Mem.mymalloc(
"targetlist", Tp->NumPart *
sizeof(
int));
166 for(
int i = 0; i < Tp->NumPart; i++)
168 if(is_type_primary_link_type(Tp->P[i].getType()))
169 targetlist[npart++] = i;
173 foffind_comm<foftree<partset>,
domain<partset>, partset> commpattern(FoFDomain, &FoFNgbTree, Tp);
179 commpattern.execute(npart, targetlist,
MODE_LOCAL_NO_EXPORT, logs::CPU_FOFWALK, logs::CPU_FOFWALK, logs::CPU_FOFIMBAL);
184 for(
int i = 0; i < Tp->NumPart; i++)
186 if(is_type_primary_link_type(Tp->P[i].getType()))
188 if(Tp->Flags[i].Nonlocal)
189 targetlist[marked++] = i;
193 double dt =
TIMER_DIFF(CPU_FOFWALK), dtmax, dtsum;
194 MPI_Allreduce(&dt, &dtmax, 1, MPI_DOUBLE, MPI_MAX, Communicator);
195 MPI_Allreduce(&dt, &dtsum, 1, MPI_DOUBLE, MPI_SUM, Communicator);
197 long long totmarked, totnpart;
201 "FOF: local links done (took %g sec, avg-work=%g, imbalance=%g).\nFOF: Marked=%lld out of the %lld primaries "
204 Logs.
timediff(t0, t1), dtsum / NTask, dtmax / (dtsum / NTask), totmarked, totnpart);
210 for(
int i = 0; i < Tp->NumPart; i++)
211 Tp->Flags[i].Marked = 1;
213 long long link_across_tot;
220 for(
int i = 0; i < Tp->NumPart; i++)
222 if(is_type_primary_link_type(Tp->P[i].getType()))
224 if(Tp->Flags[i].Nonlocal && Tp->Flags[i].Marked)
225 targetlist[npart++] = i;
228 Tp->Flags[i].MinIDChanged = 0;
229 Tp->Flags[i].Marked = 0;
232 commpattern.execute(npart, targetlist,
MODE_DEFAULT, logs::CPU_FOFWALK, logs::CPU_FOFWALK, logs::CPU_FOFIMBAL);
234 int link_across = commpattern.Thread.Interactions;
243 mpi_printf(
"FOF: have done %15lld cross links (processed %14lld, took %g sec)\n", link_across_tot, ntot,
Logs.
timediff(t0, t1));
247 for(
int i = 0; i < Tp->NumPart; i++)
249 if(Tp->Flags[i].Nonlocal)
251 if(Tp->Flags[Tp->Head[i]].MinIDChanged)
252 Tp->Flags[i].Marked = 1;
256 while(link_across_tot > 0);
258 Mem.myfree(targetlist);
259 Mem.myfree(FoFNgbTree.FullyLinkedNodePIndex + FoFNgbTree.MaxPart);
260 Mem.myfree(Tp->Flags);
262 mpi_printf(
"FOF: Local groups found.\n");
273template <
typename partset>
276 int target_MinIDTask,
double target_DistanceOrigin)
279 Tp->Flags[target].Nonlocal = 0;
286 for(
int i = 0; i < 3; i++)
288 search_min[i] = searchcenter[i] - inthsml;
289 search_range[i] = inthsml + inthsml;
294 for(
int k = 0; k < numnodes; k++)
304 no = firstnode[k].
Node;
305 no = get_nodep(no)->nextnode;
308 int shmrank = TreeSharedMem_ThisTask;
314 if(shmrank != TreeSharedMem_ThisTask)
315 Terminate(
"unexpected because in the present algorithm we are only allowed walk local branches");
318 auto P = get_Pp(no, shmrank);
320 no = get_nextnodep(shmrank)[no];
325 double dx = ((
MySignedIntPosType)(P->IntPos[0] - searchcenter[0])) * Tp->FacIntToCoord;
330 double dy = ((
MySignedIntPosType)(P->IntPos[1] - searchcenter[1])) * Tp->FacIntToCoord;
335 double dz = ((
MySignedIntPosType)(P->IntPos[2] - searchcenter[2])) * Tp->FacIntToCoord;
342#if defined(LIGHTCONE_PARTICLES_GROUPS)
343 if(Tp->DistanceOrigin[Tp->Head[p]] > target_DistanceOrigin)
345 Tp->DistanceOrigin[Tp->Head[p]] = target_DistanceOrigin;
346 Tp->Flags[Tp->Head[p]].MinIDChanged = 1;
350 if(Tp->MinID[Tp->Head[p]].get() > target_MinID.
get())
352 Tp->MinID[Tp->Head[p]] = target_MinID;
353 Tp->MinIDTask[Tp->Head[p]] = target_MinIDTask;
354 Tp->Flags[Tp->Head[p]].MinIDChanged = 1;
360 if(Tp->Head[target] != Tp->Head[p])
362 int no_target = Father[target];
363 int no_p = Father[p];
365 Tp->link_two_particles(target, p);
369 if(FullyLinkedNodePIndex[no_target] >= 0)
371 if(Tp->Head[FullyLinkedNodePIndex[no_target]] != Tp->Head[target])
372 Terminate(
"how come that the node is fully linked, but not to us");
378 while(treefind_fof_check_single_node_for_full_linking(no_target))
379 no_target = get_nodep(no_target)->father;
385 if(FullyLinkedNodePIndex[no_p] >= 0)
387 if(Tp->Head[FullyLinkedNodePIndex[no_p]] != Tp->Head[p])
388 Terminate(
"how come that the node is fully linked, but not to us");
394 while(treefind_fof_check_single_node_for_full_linking(no_p))
395 no_p = get_nodep(no_p)->father;
403 else if(no < MaxPart + MaxNodes)
405 fofnode *current = get_nodep(no, shmrank);
418 if(no < FirstNonTopLevelNode)
421 if(FullyLinkedNodePIndex[no] >= 0)
423 int head = Tp->Head[FullyLinkedNodePIndex[no]];
426 if(Tp->MinID[head].get() <= target_MinID.
get())
428#if defined(LIGHTCONE_PARTICLES_GROUPS)
429 if(Tp->DistanceOrigin[FullyLinkedNodePIndex[no]] <= target_DistanceOrigin)
445 if(p < MaxPart || (p >= FirstNonTopLevelNode && p < MaxPart + MaxNodes))
449 int task = D->ThisTask + current->
nextnode_shmrank - TreeSharedMem_ThisTask;
452 tree_export_node_threads_by_task_and_node(task, no, target, thread);
460 if(no >= FirstNonTopLevelNode)
474 if(p < MaxPart || (p >= FirstNonTopLevelNode && p < MaxPart + MaxNodes))
483 left[0] = current->
range_min[0] - search_min[0];
484 right[0] = current->
range_max[0] - search_min[0];
487 if(left[0] > search_range[0] && right[0] > left[0])
490 left[1] = current->
range_min[1] - search_min[1];
491 right[1] = current->
range_max[1] - search_min[1];
494 if(left[1] > search_range[1] && right[1] > left[1])
497 left[2] = current->
range_min[2] - search_min[2];
498 right[2] = current->
range_max[2] - search_min[2];
501 if(left[2] > search_range[2] && right[2] > left[2])
504 Tp->Flags[target].Nonlocal = 1;
509 if(FullyLinkedNodePIndex[no] >= 0)
510 if(Tp->Head[target] == Tp->Head[FullyLinkedNodePIndex[no]])
520 left[0] = current->
range_min[0] - search_min[0];
521 right[0] = current->
range_max[0] - search_min[0];
524 if(left[0] > search_range[0] && right[0] > left[0])
531 left[1] = current->
range_min[1] - search_min[1];
532 right[1] = current->
range_max[1] - search_min[1];
535 if(left[1] > search_range[1] && right[1] > left[1])
542 left[2] = current->
range_min[2] - search_min[2];
543 right[2] = current->
range_max[2] - search_min[2];
546 if(left[2] > search_range[2] && right[2] > left[2])
561 tree_export_node_threads(no, target, thread);
565 Tp->Flags[target].Nonlocal = 1;
568 no = get_nextnodep(shmrank)[no - MaxNodes];
579template <
typename partset>
582 if(no >= MaxPart && no < MaxPart + MaxNodes)
584 FullyLinkedNodePIndex[no] = q;
586 int p = get_nodep(no)->nextnode;
590 if(p < MaxPart || (p >= FirstNonTopLevelNode && p < MaxPart + MaxNodes))
592 if(get_nodep(no)->nextnode_shmrank != TreeSharedMem_ThisTask)
596 while(p != get_nodep(no)->sibling)
602 Tp->link_two_particles(p, q);
607 else if(p < MaxPart + MaxNodes)
609 fof_link_particles_in_cell_recursive(p, q);
611 p = get_nodep(p)->sibling;
614 p = Nextnode[p - MaxNodes];
619template <
typename partset>
622 if(no >= MaxPart && no < MaxPart + MaxNodes)
624 int p = get_nodep(no)->nextnode;
628 if(p < MaxPart || (p >= FirstNonTopLevelNode && p < MaxPart + MaxNodes))
630 if(get_nodep(no)->nextnode_shmrank != TreeSharedMem_ThisTask)
634 while(p != get_nodep(no)->sibling)
642 else if(p < MaxPart + MaxNodes)
644 int ret = treefind_fof_return_a_particle_in_cell_recursive(p);
649 p = get_nodep(p)->sibling;
652 p = Nextnode[p - MaxNodes];
659template <
typename partset>
662 if(no >= MaxPart && no < MaxPart + MaxNodes)
664 if(FullyLinkedNodePIndex[no] >= 0)
669 int p = get_nodep(no)->nextnode;
673 if(p < MaxPart || (p >= FirstNonTopLevelNode && p < MaxPart + MaxNodes))
675 if(get_nodep(no)->nextnode_shmrank != TreeSharedMem_ThisTask)
679 while(p != get_nodep(no)->sibling)
687 if(head != Tp->Head[p])
696 else if(p < MaxPart + MaxNodes)
698 if(FullyLinkedNodePIndex[p] >= 0)
701 head = Tp->Head[FullyLinkedNodePIndex[p]];
704 if(head != Tp->Head[FullyLinkedNodePIndex[p]])
713 if(treefind_fof_return_a_particle_in_cell_recursive(no) >= 0)
720 p = get_nodep(p)->sibling;
723 p = Nextnode[p - MaxNodes];
728 FullyLinkedNodePIndex[no] = treefind_fof_return_a_particle_in_cell_recursive(no);
730 if(Tp->Head[FullyLinkedNodePIndex[no]] != head)
731 Terminate(
"no=%d FullyLinkedNodePIndex[no]=%d Tp->Head[FullyLinkedNodePIndex[no]]=%d head=%d \n", no,
732 FullyLinkedNodePIndex[no], Tp->Head[FullyLinkedNodePIndex[no]], head);
742#include "../data/simparticles.h"
743template class fof<simparticles>;
745#if defined(LIGHTCONE) && defined(LIGHTCONE_PARTICLES_GROUPS)
746#include "../data/lcparticles.h"
747template class fof<lcparticles>;
void fof_link_particles_in_cell_recursive(int no, int q)
int treefind_fof_return_a_particle_in_cell_recursive(int no)
int treefind_fof_check_single_node_for_full_linking(int no)
int treefind_fof_primary(MyIntPosType *searchcenter, MyNgbTreeFloat hsml, int target, int mode, thread_data *thread, int numnodes, node_info *firstnode, int *ngblist, MyIDStorage target_MinID, int target_MinIDTask, double target_DistanceOrigin)
virtual void out2particle(T_out *out, int i, int mode)=0
virtual void particle2in(T_in *in, int i)=0
virtual int evaluate(int target, int mode, int thread_id, int action, T_in *in, int numnodes, node_info *firstnode, T_out &out)=0
double timediff(double t0, double t1)
double getAllocatedBytesInMB(void)
#define MODE_IMPORTED_PARTICLES
#define MODE_LOCAL_NO_EXPORT
#define MODE_LOCAL_PARTICLES
#define LEVEL_ALWAYS_OPEN
int32_t MySignedIntPosType
#define BITS_FOR_POSITIONS
#define TIMER_STORE
Copies the current value of CPU times to a stored variable, such that differences with respect to thi...
#define TIMER_DIFF(counter)
Returns amount elapsed for the timer since last save with TIMER_STORE.
void sumup_large_ints(int n, int *src, long long *res, MPI_Comm comm)
unsigned char nextnode_shmrank
unsigned char sibling_shmrank
MyIntPosType range_max[3]
MyIntPosType range_min[3]