12#include "gadgetconfig.h"
16#include <gsl/gsl_rng.h>
27#include "../data/allvars.h"
28#include "../data/dtypes.h"
29#include "../data/mymalloc.h"
30#include "../fof/fof.h"
31#include "../fof/fof_io.h"
32#include "../io/hdf5_util.h"
34#include "../logs/timer.h"
35#include "../main/main.h"
36#include "../main/simulation.h"
37#include "../mergertree/io_readsnap.h"
38#include "../mergertree/mergertree.h"
39#include "../mpi_utils/mpi_utils.h"
40#include "../sort/parallel_sort.h"
41#include "../subfind/subfind.h"
42#include "../system/system.h"
45void mergertree::get_previous_size_of_subhalo_for_each_particle(
int num)
50 "SUBFIND / MERGERTREE: We are loading the previous group catalogue to set the size of previous subhalos for each "
54 fof<simparticles> FoF{Communicator, Sp, &Domain};
58 FoF_IO.fof_subfind_load_groups(num);
60 readsnap_io Snap_IO{
this, this->Communicator,
All.
SnapFormat};
61 Snap_IO.mergertree_read_snap_ids(num);
65 mycxxsort_parallel(FoF.Group, FoF.Group + FoF.Ngroups, compare_Group_FileOffset, Communicator);
66 mycxxsort_parallel(FoF.Subhalo, FoF.Subhalo + FoF.Nsubhalos, compare_Subhalo_FileOffset, Communicator);
69 mergertree_assign_group_numbers(&FoF);
71 Mem.myfree_movable(FoF.Subhalo);
72 Mem.myfree_movable(FoF.Group);
75 mergertree_match_ids_of_current_snap();
79 for(
int i = 0; i < Sp->NumPart; i++)
82 Sp->P[i].PrevSizeOfSubhalo.set(0);
87void mergertree::descendants_in_postprocessing(
int num)
90 Terminate(
"cannot execute for the given snapnum");
93 fof<simparticles> FoF{Communicator, Sp, &Domain};
98 FoF_IO.fof_subfind_load_groups(num - 1);
100 readsnap_io Snap_IO{
this, this->Communicator,
All.
SnapFormat};
101 Snap_IO.mergertree_read_snap_ids(num - 1);
105 mycxxsort_parallel(FoF.Group, FoF.Group + FoF.Ngroups, compare_Group_FileOffset, Communicator);
106 mycxxsort_parallel(FoF.Subhalo, FoF.Subhalo + FoF.Nsubhalos, compare_Subhalo_FileOffset, Communicator);
108 if(FoF_IO.LegacyFormat)
110 mpi_printf(
"\nFOF/SUBFIND: Legacy format from Arepo detected, trying to adjust for this.\n");
111 FoF.subfind_redetermine_groupnr();
115 mergertree_assign_group_numbers(&FoF);
117 Mem.myfree_movable(FoF.Subhalo);
118 Mem.myfree_movable(FoF.Group);
121 PrevTotNsubhalos = FoF.TotNsubhalos;
122 PrevNsubhalos = FoF.Nsubhalos;
124 PrevMtrP_NumPart = MtrP_NumPart;
127 (mergertree_particle_data *)
Mem.mymalloc_movable(&PrevMtrP,
"PrevMtrP", PrevMtrP_NumPart *
sizeof(mergertree_particle_data));
128 memcpy(PrevMtrP, MtrP, PrevMtrP_NumPart *
sizeof(mergertree_particle_data));
129 Mem.myfree_movable(MtrP);
132 FoF_IO.fof_subfind_load_groups(num);
133 CurrTotNsubhalos = FoF.TotNsubhalos;
134 CurrNsubhalos = FoF.Nsubhalos;
136 Snap_IO.mergertree_read_snap_ids(num);
140 mycxxsort_parallel(FoF.Group, FoF.Group + FoF.Ngroups, compare_Group_FileOffset, Communicator);
141 mycxxsort_parallel(FoF.Subhalo, FoF.Subhalo + FoF.Nsubhalos, compare_Subhalo_FileOffset, Communicator);
143 if(FoF_IO.LegacyFormat)
145 mpi_printf(
"\nFOF/SUBFIND: Legacy format from Arepo detected, trying to adjust for this.\n");
146 FoF.subfind_redetermine_groupnr();
150 mergertree_assign_group_numbers(&FoF);
152 Mem.myfree_movable(FoF.Subhalo);
153 Mem.myfree_movable(FoF.Group);
156 for(
int i = 0; i < MtrP_NumPart; i++)
158 MtrP[i].SubhaloNr = MtrP[i].PrevSubhaloNr;
159 MtrP[i].SubhaloLen = MtrP[i].PrevSubhaloLen;
160 MtrP[i].GroupNr = MtrP[i].PrevGroupNr;
161 MtrP[i].RankInSubhalo = MtrP[i].PrevRankInSubhalo;
164 MtrP[i].PrevSubhaloLen = 0;
165 MtrP[i].PrevRankInSubhalo = 0;
169 mergertree_match_ids_of_previous_snap();
171 mergertree_determine_descendants_postproc(num);
174void mergertree::mergertree_match_ids_of_previous_snap(
void)
176 int *Send_count = (
int *)
Mem.mymalloc(
"Send_count",
sizeof(
int) * NTask);
177 int *Send_offset = (
int *)
Mem.mymalloc(
"Send_offset",
sizeof(
int) * NTask);
178 int *Recv_count = (
int *)
Mem.mymalloc(
"Recv_count",
sizeof(
int) * NTask);
179 int *Recv_offset = (
int *)
Mem.mymalloc(
"Recv_offset",
sizeof(
int) * NTask);
182 mycxxsort_parallel(PrevMtrP, PrevMtrP + PrevMtrP_NumPart, compare_MtrP_ID, Communicator);
186 int *list_numpart = (
int *)
Mem.mymalloc(
"list_mumpart", NTask *
sizeof(
int));
188 MPI_Allgather(&MtrP[0].ID,
sizeof(
MyIDType), MPI_BYTE, list_min_id,
sizeof(
MyIDType), MPI_BYTE, Communicator);
189 MPI_Allgather(&MtrP[MtrP_NumPart > 0 ? MtrP_NumPart - 1 : 0].ID,
sizeof(
MyIDType), MPI_BYTE, list_max_id,
sizeof(
MyIDType), MPI_BYTE,
191 MPI_Allgather(&MtrP_NumPart,
sizeof(
int), MPI_BYTE, list_numpart,
sizeof(
int), MPI_BYTE, Communicator);
193 int nexport = 0, nimport = 0;
194 mergertree_particle_data *import_data = NULL, *export_data = NULL;
196 for(
int mode = 0; mode < 2; mode++)
198 for(
int i = 0; i < NTask; i++)
203 for(
int i = 0; i < PrevMtrP_NumPart; i++)
205 while(target < NTask - 1 && (list_numpart[target] == 0 || PrevMtrP[i].ID > list_max_id[target]))
208 if(list_numpart[target] != 0)
209 if(PrevMtrP[i].ID >= list_min_id[target] && PrevMtrP[i].ID <= list_max_id[target])
212 Send_count[target]++;
215 int off = Send_offset[target] + Send_count[target]++;
216 export_data[off] = PrevMtrP[i];
223 myMPI_Alltoall(Send_count, 1, MPI_INT, Recv_count, 1, MPI_INT, Communicator);
224 Recv_offset[0] = Send_offset[0] = 0;
225 for(
int j = 0; j < NTask; j++)
227 nimport += Recv_count[j];
228 nexport += Send_count[j];
231 Send_offset[j] = Send_offset[j - 1] + Send_count[j - 1];
232 Recv_offset[j] = Recv_offset[j - 1] + Recv_count[j - 1];
236 export_data = (mergertree_particle_data *)
Mem.mymalloc(
"export_data", nexport *
sizeof(mergertree_particle_data));
237 import_data = (mergertree_particle_data *)
Mem.mymalloc(
"import_data", nimport *
sizeof(mergertree_particle_data));
241 for(
int ngrp = 0; ngrp < (1 << PTask); ngrp++)
243 int recvTask = ThisTask ^ ngrp;
245 if(Send_count[recvTask] > 0 || Recv_count[recvTask] > 0)
246 myMPI_Sendrecv(&export_data[Send_offset[recvTask]], Send_count[recvTask] *
sizeof(mergertree_particle_data), MPI_BYTE,
247 recvTask,
TAG_DENS_B, &import_data[Recv_offset[recvTask]],
248 Recv_count[recvTask] *
sizeof(mergertree_particle_data), MPI_BYTE, recvTask,
TAG_DENS_B, Communicator,
254 for(
int i = 0, j = 0; i < MtrP_NumPart && j < nimport;)
256 if(MtrP[i].ID < import_data[j].ID)
258 else if(MtrP[i].ID > import_data[j].ID)
262 MtrP[i].PrevSubhaloNr = import_data[j].PrevSubhaloNr;
263 MtrP[i].PrevSubhaloLen = import_data[j].PrevSubhaloLen;
264 MtrP[i].PrevGroupNr = import_data[j].PrevGroupNr;
265 MtrP[i].PrevRankInSubhalo = import_data[j].PrevRankInSubhalo;
271 Mem.myfree(import_data);
272 Mem.myfree(export_data);
273 Mem.myfree(list_numpart);
274 Mem.myfree(list_max_id);
275 Mem.myfree(list_min_id);
277 Mem.myfree(Recv_offset);
278 Mem.myfree(Recv_count);
279 Mem.myfree(Send_offset);
280 Mem.myfree(Send_count);
283void mergertree::mergertree_assign_group_numbers(fof<simparticles> *FoF)
285 int *Send_count = (
int *)
Mem.mymalloc(
"Send_count",
sizeof(
int) * NTask);
286 int *Send_offset = (
int *)
Mem.mymalloc(
"Send_offset",
sizeof(
int) * NTask);
287 int *Recv_count = (
int *)
Mem.mymalloc(
"Recv_count",
sizeof(
int) * NTask);
288 int *Recv_offset = (
int *)
Mem.mymalloc(
"Recv_offset",
sizeof(
int) * NTask);
292 FoF->fof_assign_group_offset();
293 FoF->subfind_assign_subhalo_offsettype();
296 long long ntype_tot[
NTYPES];
297 long long ntype_previous[
NTYPES];
299 for(
int i = 0; i <
NTYPES; i++)
302 for(
int i = 0; i < MtrP_NumPart; i++)
303 ntype_loc[MtrP[i].Type]++;
306 int *ntype_all = (
int *)
Mem.mymalloc(
"ntype_all",
NTYPES * NTask *
sizeof(
int));
307 MPI_Allgather(ntype_loc,
NTYPES, MPI_INT, ntype_all,
NTYPES, MPI_INT, Communicator);
309 for(
int i = 0; i <
NTYPES; i++)
312 for(
int i = 0; i < NTask; i++)
313 for(
int j = 0; j <
NTYPES; j++)
314 ntype_tot[j] += ntype_all[i *
NTYPES + j];
316 for(
int i = 0; i <
NTYPES; i++)
317 ntype_previous[i] = 0;
319 for(
int i = 0; i < ThisTask; i++)
320 for(
int j = 0; j <
NTYPES; j++)
321 ntype_previous[j] += ntype_all[i *
NTYPES + j];
325 int *gcount = (
int *)
Mem.mymalloc(
"gcount", NTask *
sizeof(
int));
326 MPI_Allgather(&FoF->Ngroups, 1, MPI_INT, gcount, 1, MPI_INT, Communicator);
329 long long first_groupnr = 0;
330 for(
int i = 0; i < ThisTask; i++)
331 first_groupnr += gcount[i];
335 int *scount = (
int *)
Mem.mymalloc(
"scount", NTask *
sizeof(
int));
336 MPI_Allgather(&FoF->Nsubhalos, 1, MPI_INT, scount, 1, MPI_INT, Communicator);
339 long long first_subhalonr = 0;
340 for(
int i = 0; i < ThisTask; i++)
341 first_subhalonr += scount[i];
351 group_info *export_group_data = NULL, *import_group_data = NULL;
353 for(
int type = 0; type <
NTYPES; type++)
355 int nexport = 0, nimport = 0;
357 for(
int mode = 0; mode < 2; mode++)
359 for(
int i = 0; i < NTask; i++)
363 long long first_in_target = 0;
365 for(
int i = 0; i < FoF->Ngroups && target < NTask;)
370 if(FoF->Group[i].OffsetType[type] + FoF->Group[i].LenType[type] > first_in_target &&
371 FoF->Group[i].OffsetType[type] < (first_in_target + ntype_all[target *
NTYPES + type]))
376 Send_count[target]++;
379 int off = Send_offset[target] + Send_count[target]++;
380 export_group_data[off].GroupNr = first_groupnr + i;
381 export_group_data[off].First = FoF->Group[i].OffsetType[type];
382 export_group_data[off].Len = FoF->Group[i].LenType[type];
386 if(FoF->Group[i].OffsetType[type] + FoF->Group[i].LenType[type] > first_in_target + ntype_all[target *
NTYPES + type])
388 first_in_target += ntype_all[target *
NTYPES + type];
393 if(i < FoF->Ngroups && flag == 0 && FoF->Group[i].LenType[type] > 0)
396 "strange: type=%d mode=%d i=%d first_in_target=%lld target=%d FoF->Group[i].LenType[type]=%lld "
398 type, mode, i, first_in_target, target, (
long long)FoF->Group[i].LenType[type], FoF->Ngroups);
407 myMPI_Alltoall(Send_count, 1, MPI_INT, Recv_count, 1, MPI_INT, Communicator);
408 Recv_offset[0] = Send_offset[0] = 0;
409 for(
int j = 0; j < NTask; j++)
411 nimport += Recv_count[j];
412 nexport += Send_count[j];
415 Send_offset[j] = Send_offset[j - 1] + Send_count[j - 1];
416 Recv_offset[j] = Recv_offset[j - 1] + Recv_count[j - 1];
420 export_group_data = (group_info *)
Mem.mymalloc(
"export_group_data", nexport *
sizeof(group_info));
421 import_group_data = (group_info *)
Mem.mymalloc(
"import_group_data", nimport *
sizeof(group_info));
425 for(
int ngrp = 0; ngrp < (1 << PTask); ngrp++)
427 int recvTask = ThisTask ^ ngrp;
429 if(Send_count[recvTask] > 0 || Recv_count[recvTask] > 0)
430 myMPI_Sendrecv(&export_group_data[Send_offset[recvTask]], Send_count[recvTask] *
sizeof(group_info), MPI_BYTE, recvTask,
431 TAG_DENS_B, &import_group_data[Recv_offset[recvTask]], Recv_count[recvTask] *
sizeof(group_info), MPI_BYTE,
432 recvTask,
TAG_DENS_B, Communicator, MPI_STATUS_IGNORE);
437 int p = ntype_previous[type];
440 for(
int i = 0; i < MtrP_NumPart; i++)
442 if(MtrP[i].Type == type)
446 while(gr < nimport && p > import_group_data[gr].First + import_group_data[gr].Len - 1)
449 if(gr < nimport && p >= import_group_data[gr].First && p < import_group_data[gr].First + import_group_data[gr].Len)
450 MtrP[i].PrevGroupNr = import_group_data[gr].GroupNr;
456 Mem.myfree(import_group_data);
457 Mem.myfree(export_group_data);
469 subhalo_info *export_subhalo_data = NULL, *import_subhalo_data = NULL;
471 for(
int type = 0; type <
NTYPES; type++)
473 int nexport = 0, nimport = 0;
475 for(
int mode = 0; mode < 2; mode++)
477 for(
int i = 0; i < NTask; i++)
481 long long first_in_target = 0;
483 for(
int i = 0; i < FoF->Nsubhalos && target < NTask;)
486 if(FoF->Subhalo[i].OffsetType[type] + FoF->Subhalo[i].LenType[type] > first_in_target &&
487 FoF->Subhalo[i].OffsetType[type] < (first_in_target + ntype_all[target *
NTYPES + type]))
490 Send_count[target]++;
493 int off = Send_offset[target] + Send_count[target]++;
494 export_subhalo_data[off].SubhaloNr = first_subhalonr + i;
495 export_subhalo_data[off].First = FoF->Subhalo[i].OffsetType[type];
496 export_subhalo_data[off].Len = FoF->Subhalo[i].LenType[type];
497 export_subhalo_data[off].SubhaloLen = FoF->Subhalo[i].Len;
501 if(FoF->Subhalo[i].OffsetType[type] + FoF->Subhalo[i].LenType[type] >
502 first_in_target + ntype_all[target *
NTYPES + type])
504 first_in_target += ntype_all[target *
NTYPES + type];
513 myMPI_Alltoall(Send_count, 1, MPI_INT, Recv_count, 1, MPI_INT, Communicator);
514 Recv_offset[0] = Send_offset[0] = 0;
515 for(
int j = 0; j < NTask; j++)
517 nimport += Recv_count[j];
518 nexport += Send_count[j];
521 Send_offset[j] = Send_offset[j - 1] + Send_count[j - 1];
522 Recv_offset[j] = Recv_offset[j - 1] + Recv_count[j - 1];
526 export_subhalo_data = (subhalo_info *)
Mem.mymalloc(
"export_subhalo_data", nexport *
sizeof(subhalo_info));
527 import_subhalo_data = (subhalo_info *)
Mem.mymalloc(
"import_subhalo_data", nimport *
sizeof(subhalo_info));
531 for(
int ngrp = 0; ngrp < (1 << PTask); ngrp++)
533 int recvTask = ThisTask ^ ngrp;
535 if(Send_count[recvTask] > 0 || Recv_count[recvTask] > 0)
536 myMPI_Sendrecv(&export_subhalo_data[Send_offset[recvTask]], Send_count[recvTask] *
sizeof(subhalo_info), MPI_BYTE,
537 recvTask,
TAG_DENS_B, &import_subhalo_data[Recv_offset[recvTask]],
538 Recv_count[recvTask] *
sizeof(subhalo_info), MPI_BYTE, recvTask,
TAG_DENS_B, Communicator,
544 int p = ntype_previous[type];
547 for(
int i = 0; i < MtrP_NumPart; i++)
549 if(MtrP[i].Type == type)
552 MtrP[i].PrevSubhaloLen = 0;
554 while(gr < nimport && p > import_subhalo_data[gr].First + import_subhalo_data[gr].Len - 1)
557 if(gr < nimport && p >= import_subhalo_data[gr].First && p < import_subhalo_data[gr].First + import_subhalo_data[gr].Len)
559 MtrP[i].PrevSubhaloNr = import_subhalo_data[gr].SubhaloNr;
560 MtrP[i].PrevSubhaloLen = import_subhalo_data[gr].SubhaloLen;
562 int rank = p - import_subhalo_data[gr].First;
567 MtrP[i].PrevRankInSubhalo =
static_cast<unsigned short>(rank);
573 Mem.myfree(import_subhalo_data);
574 Mem.myfree(export_subhalo_data);
579 Mem.myfree(ntype_all);
581 Mem.myfree(Recv_offset);
582 Mem.myfree(Recv_count);
583 Mem.myfree(Send_offset);
584 Mem.myfree(Send_count);
587void mergertree::mergertree_match_ids_of_current_snap(
void)
589 int *Send_count = (
int *)
Mem.mymalloc(
"Send_count",
sizeof(
int) * NTask);
590 int *Send_offset = (
int *)
Mem.mymalloc(
"Send_offset",
sizeof(
int) * NTask);
591 int *Recv_count = (
int *)
Mem.mymalloc(
"Recv_count",
sizeof(
int) * NTask);
592 int *Recv_offset = (
int *)
Mem.mymalloc(
"Recv_offset",
sizeof(
int) * NTask);
594 assign_particle_data *AsP = (assign_particle_data *)
Mem.mymalloc(
"AsP",
sizeof(assign_particle_data) * (Sp->NumPart + 1));
596 for(
int i = 0; i < Sp->NumPart; i++)
598 AsP[i].OriginTask = ThisTask;
599 AsP[i].OriginIndex = i;
600 AsP[i].ID = Sp->P[i].ID.get();
608 int *list_numpart = (
int *)
Mem.mymalloc(
"list_mumpart", NTask *
sizeof(
int));
610 MPI_Allgather(&AsP[0].ID,
sizeof(
MyIDType), MPI_BYTE, list_min_id,
sizeof(
MyIDType), MPI_BYTE, Communicator);
611 MPI_Allgather(&AsP[Sp->NumPart > 0 ? Sp->NumPart - 1 : 0].ID,
sizeof(
MyIDType), MPI_BYTE, list_max_id,
sizeof(
MyIDType), MPI_BYTE,
613 MPI_Allgather(&Sp->NumPart,
sizeof(
int), MPI_BYTE, list_numpart,
sizeof(
int), MPI_BYTE, Communicator);
615 int nexport = 0, nimport = 0;
616 mergertree_particle_data *import_data = NULL, *export_data = NULL;
618 for(
int mode = 0; mode < 2; mode++)
620 for(
int i = 0; i < NTask; i++)
625 for(
int i = 0; i < MtrP_NumPart; i++)
627 while(target < NTask - 1 && (list_numpart[target] == 0 || MtrP[i].ID > list_max_id[target]))
630 if(list_numpart[target] != 0)
631 if(MtrP[i].ID >= list_min_id[target] && MtrP[i].ID <= list_max_id[target])
634 Send_count[target]++;
637 int off = Send_offset[target] + Send_count[target]++;
638 export_data[off] = MtrP[i];
645 myMPI_Alltoall(Send_count, 1, MPI_INT, Recv_count, 1, MPI_INT, Communicator);
646 Recv_offset[0] = Send_offset[0] = 0;
647 for(
int j = 0; j < NTask; j++)
649 nimport += Recv_count[j];
650 nexport += Send_count[j];
653 Send_offset[j] = Send_offset[j - 1] + Send_count[j - 1];
654 Recv_offset[j] = Recv_offset[j - 1] + Recv_count[j - 1];
658 export_data = (mergertree_particle_data *)
Mem.mymalloc(
"export_data", nexport *
sizeof(mergertree_particle_data));
659 import_data = (mergertree_particle_data *)
Mem.mymalloc(
"import_data", nimport *
sizeof(mergertree_particle_data));
663 for(
int ngrp = 0; ngrp < (1 << PTask); ngrp++)
665 int recvTask = ThisTask ^ ngrp;
667 if(Send_count[recvTask] > 0 || Recv_count[recvTask] > 0)
668 myMPI_Sendrecv(&export_data[Send_offset[recvTask]], Send_count[recvTask] *
sizeof(mergertree_particle_data), MPI_BYTE,
669 recvTask,
TAG_DENS_B, &import_data[Recv_offset[recvTask]],
670 Recv_count[recvTask] *
sizeof(mergertree_particle_data), MPI_BYTE, recvTask,
TAG_DENS_B, Communicator,
676 for(
int i = 0, j = 0; i < Sp->NumPart && j < nimport;)
678 if(AsP[i].ID < import_data[j].ID)
680 else if(AsP[i].ID > import_data[j].ID)
684 AsP[i].PrevSubhaloNr = import_data[j].PrevSubhaloNr;
685 AsP[i].PrevSubhaloLen = import_data[j].PrevSubhaloLen;
693 for(
int i = 0; i < Sp->NumPart; i++)
695 Sp->P[i].PrevSizeOfSubhalo.set(AsP[i].PrevSubhaloLen);
696 Sp->P[i].PrevSubhaloNr.set(AsP[i].PrevSubhaloNr);
699 Mem.myfree(import_data);
700 Mem.myfree(export_data);
701 Mem.myfree(list_numpart);
702 Mem.myfree(list_max_id);
703 Mem.myfree(list_min_id);
707 Mem.myfree(Recv_offset);
708 Mem.myfree(Recv_count);
709 Mem.myfree(Send_offset);
710 Mem.myfree(Send_count);
global_data_all_processes All
int myMPI_Alltoall(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm)
int myMPI_Sendrecv(void *sendbuf, size_t sendcount, MPI_Datatype sendtype, int dest, int sendtag, void *recvbuf, size_t recvcount, MPI_Datatype recvtype, int source, int recvtag, MPI_Comm comm, MPI_Status *status)
double mycxxsort_parallel(T *begin, T *end, Comp comp, MPI_Comm comm)