GADGET-4
io_halotrees.cc
Go to the documentation of this file.
1 /*******************************************************************************
2  * \copyright This file is part of the GADGET4 N-body/SPH code developed
3  * \copyright by Volker Springel. Copyright (C) 2014-2020 by Volker Springel
4  * \copyright (vspringel@mpa-garching.mpg.de) and all contributing authors.
5  *******************************************************************************/
6 
12 #include "gadgetconfig.h"
13 
14 #ifdef MERGERTREE
15 
16 #include <gsl/gsl_rng.h>
17 #include <hdf5.h>
18 #include <math.h>
19 #include <mpi.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 
27 #include "../data/allvars.h"
28 #include "../data/dtypes.h"
29 #include "../data/mymalloc.h"
30 #include "../fof/fof.h"
31 #include "../io/hdf5_util.h"
32 #include "../io/io.h"
33 #include "../logs/timer.h"
34 #include "../main/simulation.h"
35 #include "../mergertree/io_halotrees.h"
36 #include "../mergertree/mergertree.h"
37 #include "../mpi_utils/mpi_utils.h"
38 #include "../sort/parallel_sort.h"
39 #include "../subfind/subfind.h"
40 #include "../system/system.h"
41 
42 halotrees_io::halotrees_io(mergertree *MergerTree_ptr, MPI_Comm comm, int format) : IO_Def(comm, format)
43 {
44  MergerTree = MergerTree_ptr;
45 
46  this->N_IO_Fields = 0;
47  this->N_DataGroups = 3;
48  this->header_size = sizeof(header);
49  this->header_buf = &header;
50  this->type_of_file = FILE_IS_TREECAT;
51  sprintf(this->info, "MERGERTREE: writing mergertrees");
52 
53  /* overview table for trees in the file */
54 
55  init_field("MTRL", "Length", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_TT, &MergerTree->TreeTable[0].HaloCount, NULL, TREELENGTH, 0, 0,
56  0, 0, 0, 0, 0);
57  init_field("MTRS", "StartOffset", MEM_INT64, FILE_INT64, SKIP_ON_READ, 1, A_TT, &MergerTree->TreeTable[0].FirstHalo, NULL,
58  TREELENGTH, 0, 0, 0, 0, 0, 0, 0);
59  init_field("MTRI", "TreeID", MEM_INT64, FILE_INT64, SKIP_ON_READ, 1, A_TT, &MergerTree->TreeTable[0].TreeID, NULL, TREELENGTH, 0, 0,
60  0, 0, 0, 0, 0);
61 
62  /* link pointers of each subhalo in the trees */
63 
64  init_field("TMPR", "TreeMainProgenitor", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].TreeMainProgenitor, NULL,
65  TREEHALOS, 0, 0, 0, 0, 0, 0, 0, true);
66  init_field("TDES", "TreeDescendant", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].TreeDescendant, NULL, TREEHALOS,
67  0, 0, 0, 0, 0, 0, 0, true);
68  init_field("TFPR", "TreeFirstProgenitor", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].TreeFirstProgenitor, NULL,
69  TREEHALOS, 0, 0, 0, 0, 0, 0, 0, true);
70  init_field("TNPR", "TreeNextProgenitor", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].TreeNextProgenitor, NULL,
71  TREEHALOS, 0, 0, 0, 0, 0, 0, 0, true);
72  init_field("TFHF", "TreeFirstHaloInFOFgroup", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].TreeFirstHaloInFOFgroup,
73  NULL, TREEHALOS, 0, 0, 0, 0, 0, 0, 0, true);
74  init_field("TNHF", "TreeNextHaloInFOFgroup", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].TreeNextHaloInFOFgroup,
75  NULL, TREEHALOS, 0, 0, 0, 0, 0, 0, 0);
76  init_field("TPRO", "TreeProgenitor", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].TreeProgenitor, NULL, TREEHALOS,
77  0, 0, 0, 0, 0, 0, 0, true);
78  init_field("TFDE", "TreeFirstDescendant", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].TreeFirstDescendant, NULL,
79  TREEHALOS, 0, 0, 0, 0, 0, 0, 0, true);
80  init_field("TNDE", "TreeNextDescendant", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].TreeNextDescendant, NULL,
81  TREEHALOS, 0, 0, 0, 0, 0, 0, 0, true);
82 
83  /* properties of each subhalo in the trees */
84 
85  init_field("SLEN", "SubhaloLen", mem_len_type, file_len_type, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].SubProp.Len, NULL,
86  SUBGROUPS, 0, 0, 0, 0, 0, 0, 0, true);
87  init_field("MASS", "SubhaloMass", MEM_MY_FLOAT, FILE_MY_IO_FLOAT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].SubProp.Mass, NULL,
88  TREEHALOS, 0, 0, 0, 0, 0, 0, 0);
89  init_field("FMC2", "Group_M_Crit200", MEM_MY_FLOAT, FILE_MY_IO_FLOAT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].SubProp.M_Crit200,
90  NULL, TREEHALOS, 0, 0, 0, 0, 0, 0, 0);
91  init_field("SPOS", "SubhaloPos", MEM_MY_FLOAT, FILE_MY_IO_FLOAT, SKIP_ON_READ, 3, A_H, &MergerTree->Halos[0].SubProp.Pos[0], NULL,
92  TREEHALOS, 0, 0, 0, 0, 0, 0, 0);
93  init_field("SVEL", "SubhaloVel", MEM_MY_FLOAT, FILE_MY_IO_FLOAT, SKIP_ON_READ, 3, A_H, &MergerTree->Halos[0].SubProp.Vel[0], NULL,
94  TREEHALOS, 0, 0, 0, 0, 0, 0, 0);
95  init_field("SSPI", "SubhaloVelDisp", MEM_MY_FLOAT, FILE_MY_IO_FLOAT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].SubProp.SubVelDisp,
96  NULL, TREEHALOS, 0, 0, 0, 0, 0, 0, 0);
97  init_field("SVMX", "SubhaloVmax", MEM_MY_FLOAT, FILE_MY_IO_FLOAT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].SubProp.SubVmax, NULL,
98  TREEHALOS, 0, 0, 0, 0, 0, 0, 0);
99  init_field("SVRX", "SubhaloVmaxRad", MEM_MY_FLOAT, FILE_MY_IO_FLOAT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].SubProp.SubVmaxRad,
100  NULL, TREEHALOS, 0, 0, 0, 0, 0, 0, 0);
101  init_field("SHMR", "SubhaloHalfmassRad", MEM_MY_FLOAT, FILE_MY_IO_FLOAT, SKIP_ON_READ, 1, A_H,
102  &MergerTree->Halos[0].SubProp.SubHalfMassRad, NULL, TREEHALOS, 0, 0, 0, 0, 0, 0, 0);
103  init_field("SSPI", "SubhaloSpin", MEM_MY_FLOAT, FILE_MY_IO_FLOAT, SKIP_ON_READ, 3, A_H, &MergerTree->Halos[0].SubProp.Spin[0], NULL,
104  TREEHALOS, 0, 0, 0, 0, 0, 0, 0);
105  init_field("SIDM", "SubhaloIDMostbound", MEM_MY_ID_TYPE, FILE_MY_ID_TYPE, READ_IF_PRESENT, 1, A_H,
106  &MergerTree->Halos[0].SubProp.SubMostBoundID, NULL, TREEHALOS, 0, 0, 0, 0, 0, 0, 0, true);
107 
108  /* where this subhalo came from */
109 
110  init_field("TSNP", "SnapNum", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].SnapNum, NULL, TREEHALOS, 0, 0, 0, 0, 0,
111  0, 0, true);
112  init_field("TSNR", "SubhaloNr", MEM_INT64, FILE_INT64, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].SubhaloNr, NULL, TREEHALOS, 0, 0,
113  0, 0, 0, 0, 0, true);
114  init_field("GRNR", "GroupNr", MEM_INT64, FILE_INT64, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].GroupNr, NULL, TREEHALOS, 0, 0, 0,
115  0, 0, 0, 0, true);
116 
117  /* the fields TreeID and TreeIndex are in principle redundant but kept for convenience */
118 
119  init_field("TRID", "TreeID", MEM_INT64, FILE_INT64, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].TreeID, NULL, TREEHALOS, 0, 0, 0, 0,
120  0, 0, 0, true);
121  init_field("TRIX", "TreeIndex", MEM_INT, FILE_INT, SKIP_ON_READ, 1, A_H, &MergerTree->Halos[0].TreeIndex, NULL, TREEHALOS, 0, 0, 0,
122  0, 0, 0, 0, true);
123 
124  /**** output times */
125 
126  init_field("REDS", "Redshift", MEM_DOUBLE, FILE_DOUBLE, SKIP_ON_READ, 1, A_CT, &MergerTree->CatTimes[0].Redshift, NULL, TREETIMES, 0,
127  0, 0, 0, 0, 0, 0);
128 
129  init_field("OUTT", "Time", MEM_DOUBLE, FILE_DOUBLE, SKIP_ON_READ, 1, A_CT, &MergerTree->CatTimes[0].Time, NULL, TREETIMES, 0, 0, 0,
130  0, 0, 0, 0);
131 }
132 
133 void halotrees_io::halotrees_save_trees(void)
134 {
135  char buf[MAXLEN_PATH_EXTRA];
136 
137  /* write trees */
138  if(All.NumFilesPerSnapshot > 1)
139  {
140  if(ThisTask == 0)
141  {
142  sprintf(buf, "%s/treedata", All.OutputDir);
143  mkdir(buf, 02755);
144  }
145  MPI_Barrier(Communicator);
146  }
147 
148  if(All.NumFilesPerSnapshot > 1)
149  sprintf(buf, "%s/treedata/%s", All.OutputDir, "trees");
150  else
151  sprintf(buf, "%s%s", All.OutputDir, "trees");
152 
153  write_multiple_files(buf, All.NumFilesPerSnapshot);
154 }
155 
156 void halotrees_io::fill_file_header(int writeTask, int lastTask, long long *n_type, long long *ntot_type)
157 {
158  /* determine group/id numbers of each type in file */
159 
160  n_type[0] = MergerTree->Ntrees;
161  n_type[1] = MergerTree->Nhalos;
162  if(ThisTask == writeTask)
163  n_type[2] = MergerTree->LastSnapShotNr + 1;
164  else
165  n_type[2] = 0;
166 
167  if(ThisTask == writeTask)
168  {
169  for(int n = 0; n < N_DataGroups; n++)
170  ntot_type[n] = n_type[n];
171 
172  for(int task = writeTask + 1; task <= lastTask; task++)
173  {
174  long long nn[N_DataGroups];
175  MPI_Recv(&nn[0], N_DataGroups, MPI_LONG_LONG, task, TAG_LOCALN, Communicator, MPI_STATUS_IGNORE);
176  for(int n = 0; n < N_DataGroups; n++)
177  ntot_type[n] += nn[n];
178  }
179 
180  for(int task = writeTask + 1; task <= lastTask; task++)
181  MPI_Send(&ntot_type[0], N_DataGroups, MPI_LONG_LONG, task, TAG_N, Communicator);
182  }
183  else
184  {
185  MPI_Send(&n_type[0], N_DataGroups, MPI_LONG_LONG, writeTask, TAG_LOCALN, Communicator);
186  MPI_Recv(&ntot_type[0], N_DataGroups, MPI_LONG_LONG, writeTask, TAG_N, Communicator, MPI_STATUS_IGNORE);
187  }
188 
189  /* fill file header */
190  header.Ntrees = ntot_type[0];
191  header.Nhalos = ntot_type[1];
192 
193  header.TotNtrees = MergerTree->TotNtrees;
194  header.TotNhalos = MergerTree->TotNhalos;
195 
196  header.lastsnapshotnr = MergerTree->LastSnapShotNr;
197 
198  header.num_files = All.NumFilesPerSnapshot;
199 }
200 
201 void halotrees_io::write_header_fields(hid_t handle)
202 {
203  write_scalar_attribute(handle, "Ntrees_ThisFile", &header.Ntrees, H5T_NATIVE_UINT64);
204  write_scalar_attribute(handle, "Ntrees_Total", &header.TotNtrees, H5T_NATIVE_UINT64);
205 
206  write_scalar_attribute(handle, "Nhalos_ThisFile", &header.Nhalos, H5T_NATIVE_UINT64);
207  write_scalar_attribute(handle, "Nhalos_Total", &header.TotNhalos, H5T_NATIVE_UINT64);
208 
209  write_scalar_attribute(handle, "NumFiles", &header.num_files, H5T_NATIVE_INT);
210 
211  write_scalar_attribute(handle, "LastSnapShotNr", &header.lastsnapshotnr, H5T_NATIVE_INT);
212 }
213 
214 int halotrees_io::get_filenr_from_header(void) { return header.num_files; }
215 
216 void halotrees_io::set_filenr_in_header(int numfiles) { header.num_files = numfiles; }
217 
218 void halotrees_io::read_increase_numbers(int type, int n_for_this_task)
219 {
220  switch(type)
221  {
222  case 0:
223  MergerTree->Ntrees += n_for_this_task;
224  break;
225  case 1:
226  MergerTree->Nhalos += n_for_this_task;
227  break;
228  case 2:
229  MergerTree->CatTimes += n_for_this_task;
230  break;
231 
232  default:
233  Terminate("wrong group");
234  break;
235  }
236 }
237 
238 void halotrees_io::read_file_header(const char *fname, int filenr, int readTask, int lastTask, long long *n_type, long long *ntot_type,
239  int *nstart)
240 {
241  if(ThisTask == readTask)
242  {
243  if(filenr == 0 && nstart == NULL)
244  {
245  mpi_printf(
246  "\nREAD-TREES: filenr=%d, '%s' contains %lld trees out of a total of %lld, and %lld halos out of a total of %lld\n",
247  filenr, fname, header.Ntrees, header.TotNtrees, header.Nhalos, header.TotNhalos);
248  }
249  }
250 
251  if(MergerTree->TotNtrees == 0)
252  {
253  MergerTree->TotNtrees = header.TotNtrees;
254  MergerTree->TotNhalos = header.TotNhalos;
255  }
256 
257  for(int k = 0; k < 2; k++)
258  n_type[k] = ntot_type[k] = 0;
259 
260  {
261  ntot_type[0] = header.Ntrees;
262  long long n_in_file = header.Ntrees;
263  int ntask = lastTask - readTask + 1;
264  int n_for_this_task = n_in_file / ntask;
265  if((ThisTask - readTask) < (n_in_file % ntask))
266  n_for_this_task++;
267  n_type[0] = n_for_this_task;
268 
269  if(nstart)
270  memmove(&MergerTree->TreeTable[n_for_this_task], &MergerTree->TreeTable[0], MergerTree->Ntrees * sizeof(halotrees_table));
271  }
272 
273  {
274  ntot_type[1] = header.Nhalos;
275  long long n_in_file = header.Nhalos;
276  int ntask = lastTask - readTask + 1;
277  int n_for_this_task = n_in_file / ntask;
278  if((ThisTask - readTask) < (n_in_file % ntask))
279  n_for_this_task++;
280  n_type[1] = n_for_this_task;
281 
282  if(nstart)
283  memmove(&MergerTree->Halos[n_for_this_task], &MergerTree->Halos[0], MergerTree->Nhalos * sizeof(treehalo_type));
284  }
285 
286  if(nstart)
287  *nstart = 0;
288 }
289 
290 void halotrees_io::read_header_fields(const char *fname)
291 {
292  memset(&header, 0, sizeof(header));
293 
294  hid_t hdf5_file = my_H5Fopen(fname, H5F_ACC_RDONLY, H5P_DEFAULT);
295  hid_t handle = my_H5Gopen(hdf5_file, "/Header");
296 
297  read_scalar_attribute(handle, "Ntrees_ThisFile", &header.Ntrees, H5T_NATIVE_UINT64);
298  read_scalar_attribute(handle, "Ntrees_Total", &header.TotNtrees, H5T_NATIVE_UINT64);
299 
300  read_scalar_attribute(handle, "Nhalos_ThisFile", &header.Nhalos, H5T_NATIVE_UINT64);
301  read_scalar_attribute(handle, "Nhalos_Total", &header.TotNhalos, H5T_NATIVE_UINT64);
302 
303  read_scalar_attribute(handle, "NumFiles", &header.num_files, H5T_NATIVE_INT);
304 
305  read_scalar_attribute(handle, "LastSnapShotNr", &header.lastsnapshotnr, H5T_NATIVE_INT);
306 
307  my_H5Gclose(handle, "/Header");
308  my_H5Fclose(hdf5_file, fname);
309 }
310 
311 void halotrees_io::get_datagroup_name(int type, char *buf)
312 {
313  switch(type)
314  {
315  case 0:
316  sprintf(buf, "/TreeTable");
317  break;
318  case 1:
319  sprintf(buf, "/TreeHalos");
320  break;
321  case 2:
322  sprintf(buf, "/TreeTimes");
323  break;
324  default:
325  Terminate("wrong group");
326  break;
327  }
328 }
329 
330 int halotrees_io::get_type_of_element(int index)
331 {
332  /* empty */
333  return 0;
334 }
335 
336 void halotrees_io::set_type_of_element(int index, int type)
337 { /* empty */
338 }
339 
340 void *halotrees_io::get_base_address_of_structure(enum arrays array, int index)
341 {
342  switch(array)
343  {
344  case A_TT:
345  return (void *)(MergerTree->TreeTable + index);
346  case A_H:
347  return (void *)(MergerTree->Halos + index);
348  case A_CT:
349  return (void *)(MergerTree->CatTimes + index);
350  default:
351  Terminate("strange, we don't expect to get here");
352  }
353 }
354 
355 #endif
global_data_all_processes All
Definition: main.cc:40
Definition: io.h:129
#define MAXLEN_PATH_EXTRA
Definition: constants.h:301
hid_t my_H5Gopen(hid_t loc_id, const char *groupname)
Definition: hdf5_util.cc:311
hid_t my_H5Fopen(const char *fname, unsigned int flags, hid_t fapl_id)
Definition: hdf5_util.cc:297
herr_t my_H5Gclose(hid_t group_id, const char *groupname)
Definition: hdf5_util.cc:457
herr_t my_H5Fclose(hid_t file_id, const char *fname)
Definition: hdf5_util.cc:482
void write_scalar_attribute(hid_t handle, const char *attr_name, const void *buf, hid_t mem_type_id)
Definition: hdf5_util.cc:621
void read_scalar_attribute(hid_t handle, const char *attr_name, void *buf, hid_t mem_type_id)
Definition: hdf5_util.cc:589
const types_in_memory mem_len_type
Definition: io.h:94
@ READ_IF_PRESENT
Definition: io.h:124
@ SKIP_ON_READ
Definition: io.h:125
@ TREELENGTH
Definition: io.h:112
@ TREETIMES
Definition: io.h:117
@ SUBGROUPS
Definition: io.h:108
@ TREEHALOS
Definition: io.h:113
arrays
Definition: io.h:30
@ A_H
Definition: io.h:41
@ A_TT
Definition: io.h:42
@ A_CT
Definition: io.h:43
@ FILE_DOUBLE
Definition: io.h:73
@ FILE_MY_IO_FLOAT
Definition: io.h:69
@ FILE_INT64
Definition: io.h:68
@ FILE_MY_ID_TYPE
Definition: io.h:71
@ FILE_INT
Definition: io.h:67
const types_in_file file_len_type
Definition: io.h:95
@ MEM_INT
Definition: io.h:79
@ MEM_DOUBLE
Definition: io.h:84
@ MEM_MY_FLOAT
Definition: io.h:85
@ MEM_MY_ID_TYPE
Definition: io.h:81
@ MEM_INT64
Definition: io.h:80
@ FILE_IS_TREECAT
Definition: io.h:57
#define Terminate(...)
Definition: macros.h:19
#define TAG_LOCALN
Definition: mpi_utils.h:52
#define TAG_N
Definition: mpi_utils.h:25
char OutputDir[MAXLEN_PATH]
Definition: allvars.h:272