logger.c 22 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*******************************************************************************
 * This file is part of SWIFT.
 * Copyright (c) 2017 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 ******************************************************************************/

/* Config parameters. */
#include "../config.h"

23
#ifdef HAVE_POSIX_FALLOCATE /* Are we on a sensible platform? */
lhausamm's avatar
lhausamm committed
24
#ifdef WITH_LOGGER
25

26
/* Some standard headers. */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
27
#include <hdf5.h>
28
#include <math.h>
29
#include <stdint.h>
30
31
32
33
34
35
36
37
38
#include <stdlib.h>
#include <string.h>

/* This object's header. */
#include "logger.h"

/* Local headers. */
#include "atomic.h"
#include "dump.h"
Loic Hausammann's avatar
Format    
Loic Hausammann committed
39
#include "engine.h"
40
41
#include "error.h"
#include "part.h"
lhausamm's avatar
lhausamm committed
42
#include "units.h"
43

44
/*
45
46
 * Thoses are definitions from the format and therefore should not be changed!
 */
47
/* number of bytes for a mask */
48
// TODO change this to number of bits
49
50
#define logger_mask_size 1

51
52
53
/* number of bits for chunk header */
#define logger_header_bytes 8

54
/* number bytes for an offset */
55
#define logger_offset_size logger_header_bytes - logger_mask_size
56

57
/* number of bytes for the version information */
58
59
#define logger_version_size 20

60
61
/* number of bytes for the labels in the header */
#define logger_label_size 20
62

63
64
/* number of bytes for the number in the header */
#define logger_number_size 4
65

66
char logger_version[logger_version_size] = "0.1";
lhausamm's avatar
lhausamm committed
67

68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
const struct mask_data
    logger_mask_data[logger_count_mask] =
        {
            /* Particle's position */
            {3 * sizeof(double), 1 << logger_x, "positions"},
            /* Particle's velocity */
            {3 * sizeof(float), 1 << logger_v, "velocities"},
            /* Particle's acceleration */
            {3 * sizeof(float), 1 << logger_a, "accelerations"},
            /* Particle's entropy */
            {sizeof(float), 1 << logger_u, "entropy"},
            /* Particle's smoothing length */
            {sizeof(float), 1 << logger_h, "smoothing length"},
            /* Particle's density */
            {sizeof(float), 1 << logger_rho, "density"},
            /* Particle's constants: mass (float) and ID (long long) */
            {sizeof(float) + sizeof(long long), 1 << logger_consts, "consts"},
            /* Simulation time stamp: integertime and double time (e.g. scale
               factor or time) */
            {sizeof(integertime_t) + sizeof(double), 1 << logger_timestamp,
             "timestamp"}};
89

lhausamm's avatar
lhausamm committed
90
/**
91
92
93
 * @brief Write the header of a chunk (offset + mask).
 *
 * This is maybe broken for big(?) endian.
lhausamm's avatar
lhausamm committed
94
95
96
97
98
99
100
101
 *
 * @param buff The writing buffer
 * @param mask The mask to write
 * @param offset The old offset
 * @param offset_new The new offset
 *
 * @return updated buff
 */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
102
103
char *logger_write_chunk_header(char *buff, const unsigned int *mask,
                                const size_t *offset, const size_t offset_new) {
lhausamm's avatar
lhausamm committed
104
  /* write mask */
105
106
  memcpy(buff, mask, logger_mask_size);
  buff += logger_mask_size;
lhausamm's avatar
lhausamm committed
107
108

  /* write offset */
lhausamm's avatar
lhausamm committed
109
  size_t diff_offset = offset_new - *offset;
110
111
  memcpy(buff, &diff_offset, logger_offset_size);
  buff += logger_offset_size;
lhausamm's avatar
lhausamm committed
112
113
114
115
116

  return buff;
}

/**
lhausamm's avatar
lhausamm committed
117
 * @brief Write to the dump
lhausamm's avatar
lhausamm committed
118
119
 *
 * @param d #dump file
lhausamm's avatar
lhausamm committed
120
 * @param offset (return) offset of the data
lhausamm's avatar
lhausamm committed
121
122
123
 * @param size number of bytes to write
 * @param p pointer to the data
 */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
124
125
void logger_write_data(struct dump *d, size_t *offset, size_t size,
                       const void *p) {
lhausamm's avatar
lhausamm committed
126
  /* get buffer */
lhausamm's avatar
lhausamm committed
127
  char *buff = dump_get(d, size, offset);
lhausamm's avatar
lhausamm committed
128
129

  /* write data to the buffer */
130
  memcpy(buff, p, size);
131

132
  /* Update offset to end of chunk */
133
  *offset += size;
134
135
}

136
137
/**
 * @brief Compute the size of a message given its mask.
138
139
140
141
 *
 * @param mask The mask that will be used to dump a #part or #gpart.
 *
 * @return The size of the logger message in bytes.
142
 */
lhausamm's avatar
lhausamm committed
143
int logger_compute_chunk_size(unsigned int mask) {
144
145

  /* Start with 8 bytes for the header. */
lhausamm's avatar
lhausamm committed
146
  int size = logger_mask_size + logger_offset_size;
147
148

  /* Is this a particle or a timestep? */
149
  if (mask & logger_mask_data[logger_timestamp].mask) {
150
151

    /* The timestamp should not contain any other bits. */
152
    if (mask != logger_mask_data[logger_timestamp].mask)
153
154
155
      error("Timestamps should not include any other data.");

    /* A timestamp consists of an unsigned long long int. */
156
    size += logger_mask_data[logger_timestamp].size;
157
158
159

  } else {

160
161
162
163
164
    for(int i=0; i < logger_count_mask; i++) {
      if (mask & logger_mask_data[i].mask) {
	size += logger_mask_data[i].size;
      }
    }      
165
166
167
168
  }

  return size;
}
169

lhausamm's avatar
lhausamm committed
170
/**
lhausamm's avatar
lhausamm committed
171
 * @brief log all particles in the engine.
lhausamm's avatar
lhausamm committed
172
 *
lhausamm's avatar
lhausamm committed
173
174
 * @param log The #logger
 * @param e The #engine
lhausamm's avatar
lhausamm committed
175
 */
lhausamm's avatar
lhausamm committed
176
void logger_log_all(struct logger *log, const struct engine *e) {
177
178
179
180
181
182
183

  /* Ensure that enough space is available */
  logger_ensure_size(log, e->total_nr_parts, e->total_nr_gparts, 0);
#ifdef SWIFT_DEBUG_CHECKS
  message("Need to implement stars");
#endif

lhausamm's avatar
lhausamm committed
184
  /* some constants */
lhausamm's avatar
lhausamm committed
185
  const struct space *s = e->s;
186
187
188
189
190
  const unsigned int mask =
      logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask |
      logger_mask_data[logger_a].mask | logger_mask_data[logger_u].mask |
      logger_mask_data[logger_h].mask | logger_mask_data[logger_rho].mask |
      logger_mask_data[logger_consts].mask;
lhausamm's avatar
lhausamm committed
191
192

  /* loop over all parts */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
193
194
195
  for (long long i = 0; i < e->total_nr_parts; i++) {
    logger_log_part(log, &s->parts[i], mask,
                    &s->xparts[i].logger_data.last_offset);
196
    s->xparts[i].logger_data.steps_since_last_output = 0;
lhausamm's avatar
lhausamm committed
197
  }
lhausamm's avatar
lhausamm committed
198

lhausamm's avatar
lhausamm committed
199
  /* loop over all gparts */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
200
  if (e->total_nr_gparts > 0) error("Not implemented");
lhausamm's avatar
lhausamm committed
201

lhausamm's avatar
lhausamm committed
202
203
  /* loop over all sparts */
  // TODO
lhausamm's avatar
lhausamm committed
204
205
}

206
207
208
/**
 * @brief Dump a #part to the log.
 *
lhausamm's avatar
lhausamm committed
209
 * @param log The #logger
Pedro Gonnet's avatar
Pedro Gonnet committed
210
 * @param p The #part to dump.
211
 * @param mask The mask of the data to dump.
Loic Hausammann's avatar
Format    
Loic Hausammann committed
212
213
 * @param offset Pointer to the offset of the previous log of this particle;
 * (return) offset of this log.
214
 */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
215
216
void logger_log_part(struct logger *log, const struct part *p,
                     unsigned int mask, size_t *offset) {
217
218

  /* Make sure we're not writing a timestamp. */
219
  if (mask & logger_mask_data[logger_timestamp].mask)
220
221
222
    error("You should not log particles as timestamps.");

  /* Start by computing the size of the message. */
lhausamm's avatar
lhausamm committed
223
  const int size = logger_compute_chunk_size(mask);
224
225
226

  /* Allocate a chunk of memory in the dump of the right size. */
  size_t offset_new;
227
  char *buff = (char *)dump_get(&log->dump, size, &offset_new);
228
229

  /* Write the header. */
lhausamm's avatar
lhausamm committed
230
  buff = logger_write_chunk_header(buff, &mask, offset, offset_new);
231
232

  /* Particle position as three doubles. */
233
  if (mask & logger_mask_data[logger_x].mask) {
234
235
    memcpy(buff, p->x, logger_mask_data[logger_x].size);
    buff += logger_mask_data[logger_x].size;
236
237
238
  }

  /* Particle velocity as three floats. */
239
  if (mask & logger_mask_data[logger_v].mask) {
240
241
    memcpy(buff, p->v, logger_mask_data[logger_v].size);
    buff += logger_mask_data[logger_v].size;
242
243
244
  }

  /* Particle accelleration as three floats. */
245
  if (mask & logger_mask_data[logger_a].mask) {
246
247
    memcpy(buff, p->a_hydro, logger_mask_data[logger_a].size);
    buff += logger_mask_data[logger_a].size;
248
249
  }

250
251
#if defined(GADGET2_SPH)

252
  /* Particle internal energy as a single float. */
253
  if (mask & logger_mask_data[logger_u].mask) {
254
255
    memcpy(buff, &p->entropy, logger_mask_data[logger_u].size);
    buff += logger_mask_data[logger_u].size;
256
257
258
  }

  /* Particle smoothing length as a single float. */
259
  if (mask & logger_mask_data[logger_h].mask) {
260
261
    memcpy(buff, &p->h, logger_mask_data[logger_h].size);
    buff += logger_mask_data[logger_h].size;
262
263
264
  }

  /* Particle density as a single float. */
265
  if (mask & logger_mask_data[logger_rho].mask) {
266
267
    memcpy(buff, &p->rho, logger_mask_data[logger_rho].size);
    buff += logger_mask_data[logger_rho].size;
268
269
270
  }

  /* Particle constants, which is a bit more complicated. */
271
  if (mask & logger_mask_data[logger_consts].mask) {
272
    // TODO make it dependent of logger_mask_data
273
274
275
276
277
278
    memcpy(buff, &p->mass, sizeof(float));
    buff += sizeof(float);
    memcpy(buff, &p->id, sizeof(long long));
    buff += sizeof(long long);
  }

279
280
#endif

281
282
283
  /* Update the log message offset. */
  *offset = offset_new;
}
284
285
286
287

/**
 * @brief Dump a #gpart to the log.
 *
lhausamm's avatar
lhausamm committed
288
 * @param log The #logger
Pedro Gonnet's avatar
Pedro Gonnet committed
289
 * @param p The #gpart to dump.
290
 * @param mask The mask of the data to dump.
Loic Hausammann's avatar
Format    
Loic Hausammann committed
291
292
 * @param offset Pointer to the offset of the previous log of this particle;
 * (return) offset of this log.
293
 */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
294
295
void logger_log_gpart(struct logger *log, const struct gpart *p,
                      unsigned int mask, size_t *offset) {
296
297

  /* Make sure we're not writing a timestamp. */
298
  if (mask & logger_mask_data[logger_timestamp].mask)
299
300
301
    error("You should not log particles as timestamps.");

  /* Make sure we're not looging fields not supported by gparts. */
302
303
  if (mask &
      (logger_mask_data[logger_u].mask | logger_mask_data[logger_rho].mask))
304
305
306
    error("Can't log SPH quantities for gparts.");

  /* Start by computing the size of the message. */
lhausamm's avatar
lhausamm committed
307
  const int size = logger_compute_chunk_size(mask);
308
309
310

  /* Allocate a chunk of memory in the dump of the right size. */
  size_t offset_new;
311
  char *buff = (char *)dump_get(&log->dump, size, &offset_new);
312
313

  /* Write the header. */
lhausamm's avatar
lhausamm committed
314
  buff = logger_write_chunk_header(buff, &mask, offset, offset_new);
315
316

  /* Particle position as three doubles. */
317
  if (mask & logger_mask_data[logger_x].mask) {
318
319
    memcpy(buff, p->x, logger_mask_data[logger_x].size);
    buff += logger_mask_data[logger_x].size;
320
321
322
  }

  /* Particle velocity as three floats. */
323
  if (mask & logger_mask_data[logger_v].mask) {
324
325
    memcpy(buff, p->v_full, logger_mask_data[logger_v].size);
    buff += logger_mask_data[logger_v].size;
326
327
328
  }

  /* Particle accelleration as three floats. */
329
  if (mask & logger_mask_data[logger_a].mask) {
330
331
    memcpy(buff, p->a_grav, logger_mask_data[logger_a].size);
    buff += logger_mask_data[logger_a].size;
332
333
334
  }

  /* Particle constants, which is a bit more complicated. */
335
  if (mask & logger_mask_data[logger_consts].mask) {
336
    // TODO make it dependent of logger_mask_data
337
338
339
340
341
342
343
344
345
346
    memcpy(buff, &p->mass, sizeof(float));
    buff += sizeof(float);
    memcpy(buff, &p->id_or_neg_offset, sizeof(long long));
    buff += sizeof(long long);
  }

  /* Update the log message offset. */
  *offset = offset_new;
}

lhausamm's avatar
lhausamm committed
347
348
349
/**
 * @brief write a timestamp
 *
lhausamm's avatar
lhausamm committed
350
 * @param log The #logger
lhausamm's avatar
lhausamm committed
351
 * @param timestamp time to write
352
 * @param time time or scale factor
Loic Hausammann's avatar
Format    
Loic Hausammann committed
353
354
 * @param offset Pointer to the offset of the previous log of this particle;
 * (return) offset of this log.
lhausamm's avatar
lhausamm committed
355
 */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
356
void logger_log_timestamp(struct logger *log, integertime_t timestamp,
357
                          double time, size_t *offset) {
358
  struct dump *dump = &log->dump;
Loic Hausammann's avatar
Format    
Loic Hausammann committed
359

360
  /* Start by computing the size of the message. */
361
362
  const int size =
      logger_compute_chunk_size(logger_mask_data[logger_timestamp].mask);
363
364
365

  /* Allocate a chunk of memory in the dump of the right size. */
  size_t offset_new;
366
  char *buff = (char *)dump_get(dump, size, &offset_new);
367
368

  /* Write the header. */
369
  unsigned int mask = logger_mask_data[logger_timestamp].mask;
lhausamm's avatar
lhausamm committed
370
  buff = logger_write_chunk_header(buff, &mask, offset, offset_new);
Pedro Gonnet's avatar
Pedro Gonnet committed
371

372
  /* Store the timestamp. */
373
  // TODO make it dependent of logger_mask_data
374
  memcpy(buff, &timestamp, sizeof(integertime_t));
375
376
377
378
  buff += sizeof(integertime_t);

  /* Store the time */
  memcpy(buff, &time, sizeof(double));
379
380
381
382

  /* Update the log message offset. */
  *offset = offset_new;
}
Pedro Gonnet's avatar
Pedro Gonnet committed
383

lhausamm's avatar
lhausamm committed
384
/**
lhausamm's avatar
lhausamm committed
385
 * @brief Ensure that the buffer is large enough for a step.
lhausamm's avatar
lhausamm committed
386
387
 *
 * Check if logger parameters are large enough to write all particles
lhausamm's avatar
lhausamm committed
388
 * and ensure that enough space is available in the buffer.
lhausamm's avatar
lhausamm committed
389
 *
390
 * @param log The #logger
lhausamm's avatar
lhausamm committed
391
392
393
 * @param total_nr_parts total number of part
 * @param total_nr_gparts total number of gpart
 * @param total_nr_sparts total number of spart
lhausamm's avatar
lhausamm committed
394
 */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
395
396
void logger_ensure_size(struct logger *log, size_t total_nr_parts,
                        size_t total_nr_gparts, size_t total_nr_sparts) {
lhausamm's avatar
lhausamm committed
397
398

  /* count part memory */
399
  size_t limit = log->max_chunk_size;
lhausamm's avatar
lhausamm committed
400
401
402

  limit *= total_nr_parts;

lhausamm's avatar
lhausamm committed
403
  /* count gpart memory */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
404
  if (total_nr_gparts > 0) error("Not implemented");
405

lhausamm's avatar
lhausamm committed
406
  /* count spart memory */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
407
  if (total_nr_sparts > 0) error("Not implemented");
lhausamm's avatar
lhausamm committed
408
409

  /* ensure enough space in dump */
410
  dump_ensure(&log->dump, limit, log->buffer_scale * limit);
lhausamm's avatar
lhausamm committed
411
412
413
414
415
416
}

/**
 * @brief intialize the logger structure
 *
 * @param log The #logger
417
 * @param params The #swift_params
lhausamm's avatar
lhausamm committed
418
 */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
419
void logger_init(struct logger *log, struct swift_params *params) {
lhausamm's avatar
lhausamm committed
420
421
  /* read parameters */
  log->delta_step = parser_get_param_int(params, "Logger:delta_step");
Loic Hausammann's avatar
Loic Hausammann committed
422
  size_t buffer_size =
Loic Hausammann's avatar
Loic Hausammann committed
423
424
      parser_get_opt_param_float(params, "Logger:initial_buffer_size", 0.5) *
      1e9;
Loic Hausammann's avatar
Format    
Loic Hausammann committed
425
  log->buffer_scale =
426
      parser_get_opt_param_float(params, "Logger:buffer_scale", 10);
lhausamm's avatar
lhausamm committed
427
428
  parser_get_param_string(params, "Logger:basename", log->base_name);

lhausamm's avatar
lhausamm committed
429
430
431
  /* set initial value of parameters */
  log->timestamp_offset = 0;

lhausamm's avatar
lhausamm committed
432
433
434
435
436
  /* generate dump filename */
  char logger_name_file[PARSER_MAX_LINE_SIZE];
  strcpy(logger_name_file, log->base_name);
  strcat(logger_name_file, ".dump");

437
438
439
440
441
442
443
444
  /* Compute max size for a particle chunk */
  int max_size = logger_offset_size + logger_mask_size;

  /* Loop over all fields except timestamp */
  for (int i = 0; i < logger_count_mask - 1; i++) {
    max_size += logger_mask_data[i].size;
  }
  log->max_chunk_size = max_size;
445

lhausamm's avatar
lhausamm committed
446
  /* init dump */
447
  dump_init(&log->dump, logger_name_file, buffer_size);
lhausamm's avatar
lhausamm committed
448
449
450
451
452
453
454
}

/**
 * @brief Close dump file and desallocate memory
 *
 * @param log The #logger
 */
455
void logger_clean(struct logger *log) { dump_close(&log->dump); }
lhausamm's avatar
lhausamm committed
456

457
458
459
/**
 * @brief Write a file header to a logger file
 *
460
 * @param log The #logger
461
462
463
 * @param dump The #dump in which to log the particle data.
 *
 */
464
void logger_write_file_header(struct logger *log, const struct engine *e) {
lhausamm's avatar
lhausamm committed
465

lhausamm's avatar
lhausamm committed
466
  /* get required variables */
467
  struct dump *dump = &log->dump;
Loic Hausammann's avatar
Format    
Loic Hausammann committed
468

lhausamm's avatar
lhausamm committed
469
  size_t file_offset = dump->file_offset;
Loic Hausammann's avatar
Format    
Loic Hausammann committed
470

lhausamm's avatar
lhausamm committed
471
  if (file_offset != 0)
Loic Hausammann's avatar
Format    
Loic Hausammann committed
472
473
474
    error(
        "The logger is not empty."
        "This function should be called before writing anything in the logger");
475
476

  /* Write version information */
lhausamm's avatar
lhausamm committed
477
  logger_write_data(dump, &file_offset, logger_version_size, &logger_version);
Loic Hausammann's avatar
Format    
Loic Hausammann committed
478

lhausamm's avatar
lhausamm committed
479
  /* write offset direction */
480
  const int reversed = 0;
481
  logger_write_data(dump, &file_offset, logger_number_size, &reversed);
lhausamm's avatar
lhausamm committed
482

483
  /* placeholder to write the offset of the first log here */
484
  char *skip_header = dump_get(dump, logger_offset_size, &file_offset);
485
486

  /* write number of bytes used for names */
487
  const int label_size = logger_label_size;
488
  logger_write_data(dump, &file_offset, logger_number_size, &label_size);
lhausamm's avatar
lhausamm committed
489
490

  /* write number of masks */
491
  int count_mask = logger_count_mask;
492
  logger_write_data(dump, &file_offset, logger_number_size, &count_mask);
493

lhausamm's avatar
lhausamm committed
494
  /* write masks */
lhausamm's avatar
lhausamm committed
495
  // loop over all mask type
496
  for (int i = 0; i < logger_count_mask; i++) {
497
    // mask name
498
    logger_write_data(dump, &file_offset, logger_label_size,
499
                      &logger_mask_data[i].name);
500
501

    // mask size
502
    logger_write_data(dump, &file_offset, logger_number_size,
503
                      &logger_mask_data[i].size);
504
  }
505

lhausamm's avatar
lhausamm committed
506
  /* last step: write first offset */
507
  memcpy(skip_header, &file_offset, logger_offset_size);
lhausamm's avatar
lhausamm committed
508
}
509

lhausamm's avatar
lhausamm committed
510
511
512
513
514
/**
 * @brief read chunk header
 *
 * @param buff The reading buffer
 * @param mask The mask to read
lhausamm's avatar
lhausamm committed
515
 * @param offset (return) the offset pointed by this chunk (absolute)
lhausamm's avatar
lhausamm committed
516
517
518
519
 * @param offset_cur The current chunk offset
 *
 * @return Number of bytes read
 */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
520
521
__attribute__((always_inline)) INLINE static int logger_read_chunk_header(
    const char *buff, unsigned int *mask, size_t *offset, size_t cur_offset) {
lhausamm's avatar
lhausamm committed
522
523
  memcpy(mask, buff, logger_mask_size);
  buff += logger_mask_size;
lhausamm's avatar
lhausamm committed
524
525

  *offset = 0;
lhausamm's avatar
lhausamm committed
526
  memcpy(offset, buff, logger_offset_size);
lhausamm's avatar
lhausamm committed
527
  *offset = cur_offset - *offset;
Loic Hausammann's avatar
Format    
Loic Hausammann committed
528

lhausamm's avatar
lhausamm committed
529
  return logger_mask_size + logger_offset_size;
lhausamm's avatar
lhausamm committed
530
531
}

Pedro Gonnet's avatar
Pedro Gonnet committed
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
/**
 * @brief Read a logger message and store the data in a #part.
 *
 * @param p The #part in which to store the values.
 * @param offset Pointer to the offset of the logger message in the buffer,
 *        will be overwritten with the offset of the previous message.
 * @param buff Pointer to the start of an encoded logger message.
 *
 * @return The mask containing the values read.
 */
int logger_read_part(struct part *p, size_t *offset, const char *buff) {

  /* Jump to the offset. */
  buff = &buff[*offset];

  /* Start by reading the logger mask for this entry. */
lhausamm's avatar
lhausamm committed
548
549
550
  const size_t cur_offset = *offset;
  unsigned int mask = 0;
  buff += logger_read_chunk_header(buff, &mask, offset, cur_offset);
Pedro Gonnet's avatar
Pedro Gonnet committed
551
552

  /* We are only interested in particle data. */
553
  if (mask & logger_mask_data[logger_timestamp].mask)
Pedro Gonnet's avatar
Pedro Gonnet committed
554
555
556
    error("Trying to read timestamp as particle.");

  /* Particle position as three doubles. */
557
  if (mask & logger_mask_data[logger_x].mask) {
558
559
    memcpy(p->x, buff, logger_mask_data[logger_x].size);
    buff += logger_mask_data[logger_x].size;
Pedro Gonnet's avatar
Pedro Gonnet committed
560
561
562
  }

  /* Particle velocity as three floats. */
563
  if (mask & logger_mask_data[logger_v].mask) {
564
565
    memcpy(p->v, buff, logger_mask_data[logger_v].size);
    buff += logger_mask_data[logger_v].size;
Pedro Gonnet's avatar
Pedro Gonnet committed
566
567
568
  }

  /* Particle accelleration as three floats. */
569
  if (mask & logger_mask_data[logger_a].mask) {
570
571
    memcpy(p->a_hydro, buff, logger_mask_data[logger_a].size);
    buff += logger_mask_data[logger_a].size;
Pedro Gonnet's avatar
Pedro Gonnet committed
572
573
  }

574
575
#if defined(GADGET2_SPH)

Pedro Gonnet's avatar
Pedro Gonnet committed
576
  /* Particle internal energy as a single float. */
577
  if (mask & logger_mask_data[logger_u].mask) {
578
579
    memcpy(&p->entropy, buff, logger_mask_data[logger_u].size);
    buff += logger_mask_data[logger_u].size;
Pedro Gonnet's avatar
Pedro Gonnet committed
580
581
582
  }

  /* Particle smoothing length as a single float. */
583
  if (mask & logger_mask_data[logger_h].mask) {
584
585
    memcpy(&p->h, buff, logger_mask_data[logger_h].size);
    buff += logger_mask_data[logger_h].size;
Pedro Gonnet's avatar
Pedro Gonnet committed
586
587
588
  }

  /* Particle density as a single float. */
589
  if (mask & logger_mask_data[logger_rho].mask) {
590
591
    memcpy(&p->rho, buff, logger_mask_data[logger_rho].size);
    buff += logger_mask_data[logger_rho].size;
Pedro Gonnet's avatar
Pedro Gonnet committed
592
593
594
  }

  /* Particle constants, which is a bit more complicated. */
595
  if (mask & logger_mask_data[logger_rho].mask) {
596
    // TODO make it dependent of logger_mask_data
Pedro Gonnet's avatar
Pedro Gonnet committed
597
598
599
600
601
602
    memcpy(&p->mass, buff, sizeof(float));
    buff += sizeof(float);
    memcpy(&p->id, buff, sizeof(long long));
    buff += sizeof(long long);
  }

603
604
#endif

Pedro Gonnet's avatar
Pedro Gonnet committed
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
  /* Finally, return the mask of the values we just read. */
  return mask;
}

/**
 * @brief Read a logger message and store the data in a #gpart.
 *
 * @param p The #gpart in which to store the values.
 * @param offset Pointer to the offset of the logger message in the buffer,
 *        will be overwritten with the offset of the previous message.
 * @param buff Pointer to the start of an encoded logger message.
 *
 * @return The mask containing the values read.
 */
int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) {

  /* Jump to the offset. */
  buff = &buff[*offset];

  /* Start by reading the logger mask for this entry. */
lhausamm's avatar
lhausamm committed
625
626
627
  const size_t cur_offset = *offset;
  unsigned int mask = 0;
  buff += logger_read_chunk_header(buff, &mask, offset, cur_offset);
Pedro Gonnet's avatar
Pedro Gonnet committed
628
629

  /* We are only interested in particle data. */
630
  if (mask & logger_mask_data[logger_timestamp].mask)
Pedro Gonnet's avatar
Pedro Gonnet committed
631
    error("Trying to read timestamp as particle.");
Pedro Gonnet's avatar
Pedro Gonnet committed
632

Pedro Gonnet's avatar
Pedro Gonnet committed
633
  /* We can't store all part fields in a gpart. */
634
635
  if (mask &
      (logger_mask_data[logger_u].mask | logger_mask_data[logger_rho].mask))
Pedro Gonnet's avatar
Pedro Gonnet committed
636
637
638
    error("Trying to read SPH quantities into a gpart.");

  /* Particle position as three doubles. */
639
  if (mask & logger_mask_data[logger_x].mask) {
640
641
    memcpy(p->x, buff, logger_mask_data[logger_x].size);
    buff += logger_mask_data[logger_x].size;
Pedro Gonnet's avatar
Pedro Gonnet committed
642
643
644
  }

  /* Particle velocity as three floats. */
645
  if (mask & logger_mask_data[logger_v].mask) {
646
647
    memcpy(p->v_full, buff, logger_mask_data[logger_v].size);
    buff += logger_mask_data[logger_v].size;
Pedro Gonnet's avatar
Pedro Gonnet committed
648
649
650
  }

  /* Particle accelleration as three floats. */
651
  if (mask & logger_mask_data[logger_a].mask) {
652
653
    memcpy(p->a_grav, buff, logger_mask_data[logger_a].size);
    buff += logger_mask_data[logger_a].size;
Pedro Gonnet's avatar
Pedro Gonnet committed
654
655
656
  }

  /* Particle constants, which is a bit more complicated. */
657
  if (mask & logger_mask_data[logger_rho].mask) {
658
    // TODO make it dependent of logger_mask_data
Pedro Gonnet's avatar
Pedro Gonnet committed
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
    memcpy(&p->mass, buff, sizeof(float));
    buff += sizeof(float);
    memcpy(&p->id_or_neg_offset, buff, sizeof(long long));
    buff += sizeof(long long);
  }

  /* Finally, return the mask of the values we just read. */
  return mask;
}

/**
 * @brief Read a logger message for a timestamp.
 *
 * @param t The timestamp in which to store the value.
 * @param offset Pointer to the offset of the logger message in the buffer,
 *        will be overwritten with the offset of the previous message.
 * @param buff Pointer to the start of an encoded logger message.
 *
 * @return The mask containing the values read.
 */
679
680
int logger_read_timestamp(unsigned long long int *t, double *time,
                          size_t *offset, const char *buff) {
Pedro Gonnet's avatar
Pedro Gonnet committed
681
682
683
684
685

  /* Jump to the offset. */
  buff = &buff[*offset];

  /* Start by reading the logger mask for this entry. */
lhausamm's avatar
lhausamm committed
686
687
688
  const size_t cur_offset = *offset;
  unsigned int mask = 0;
  buff += logger_read_chunk_header(buff, &mask, offset, cur_offset);
Pedro Gonnet's avatar
Pedro Gonnet committed
689
690

  /* We are only interested in timestamps. */
691
  if (!(mask & logger_mask_data[logger_timestamp].mask))
Pedro Gonnet's avatar
Pedro Gonnet committed
692
    error("Trying to read timestamp from a particle.");
Pedro Gonnet's avatar
Pedro Gonnet committed
693

Pedro Gonnet's avatar
Pedro Gonnet committed
694
  /* Make sure we don't have extra fields. */
695
  if (mask != logger_mask_data[logger_timestamp].mask)
Pedro Gonnet's avatar
Pedro Gonnet committed
696
697
698
    error("Timestamp message contains extra fields.");

  /* Copy the timestamp value from the buffer. */
699
  // TODO make it dependent of logger_mask_data
Pedro Gonnet's avatar
Pedro Gonnet committed
700
  memcpy(t, buff, sizeof(unsigned long long int));
701
702
703
  buff += sizeof(unsigned long long int);

  /* Copy the timestamp value from the buffer. */
704
  memcpy(time, buff, sizeof(double));
Pedro Gonnet's avatar
Pedro Gonnet committed
705
706
707
708

  /* Finally, return the mask of the values we just read. */
  return mask;
}
709

lhausamm's avatar
lhausamm committed
710
711
#endif /* WITH_LOGGER */

712
#endif /* HAVE_POSIX_FALLOCATE */