part.c 20.7 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 23 24 25 26 27 28
/*******************************************************************************
 * This file is part of SWIFT.
 * Copyright (c) 2016 Matthieu Schaller (matthieu.schaller@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"

/* MPI headers. */
#ifdef WITH_MPI
#include <mpi.h>
#endif

/* This object's header. */
Matthieu Schaller's avatar
Matthieu Schaller committed
29
#include "part.h"
30 31 32

/* Local headers */
#include "error.h"
33
#include "hydro.h"
34
#include "threadpool.h"
35

36
/**
Matthieu Schaller's avatar
Matthieu Schaller committed
37
 * @brief Re-link the #gpart%s associated with the list of #part%s.
38 39 40
 *
 * @param parts The list of #part.
 * @param N The number of particles to re-link;
Matthieu Schaller's avatar
Matthieu Schaller committed
41
 * @param offset The offset of #part%s relative to the global parts list.
42
 */
43 44
void part_relink_gparts_to_parts(struct part *parts, const size_t N,
                                 const ptrdiff_t offset) {
45
  for (size_t k = 0; k < N; k++) {
46 47 48
    if (parts[k].gpart) {
      parts[k].gpart->id_or_neg_offset = -(k + offset);
    }
49 50 51 52
  }
}

/**
53 54 55 56 57 58
 * @brief Re-link the #gpart%s associated with the list of #spart%s.
 *
 * @param sparts The list of #spart.
 * @param N The number of s-particles to re-link;
 * @param offset The offset of #spart%s relative to the global sparts list.
 */
59 60
void part_relink_gparts_to_sparts(struct spart *sparts, const size_t N,
                                  const ptrdiff_t offset) {
61 62 63 64 65 66 67
  for (size_t k = 0; k < N; k++) {
    if (sparts[k].gpart) {
      sparts[k].gpart->id_or_neg_offset = -(k + offset);
    }
  }
}

Loic Hausammann's avatar
Loic Hausammann committed
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
/**
 * @brief Re-link the #gpart%s associated with the list of #sink%s.
 *
 * @param sinks The list of #sink.
 * @param N The number of sink-particles to re-link;
 * @param offset The offset of #sink%s relative to the global sinks list.
 */
void part_relink_gparts_to_sinks(struct sink *sinks, const size_t N,
                                 const ptrdiff_t offset) {
  for (size_t k = 0; k < N; k++) {
    if (sinks[k].gpart) {
      sinks[k].gpart->id_or_neg_offset = -(k + offset);
    }
  }
}

84 85 86 87 88 89 90
/**
 * @brief Re-link the #gpart%s associated with the list of #bpart%s.
 *
 * @param bparts The list of #bpart.
 * @param N The number of s-particles to re-link;
 * @param offset The offset of #bpart%s relative to the global bparts list.
 */
91 92
void part_relink_gparts_to_bparts(struct bpart *bparts, const size_t N,
                                  const ptrdiff_t offset) {
93 94 95 96 97 98 99
  for (size_t k = 0; k < N; k++) {
    if (bparts[k].gpart) {
      bparts[k].gpart->id_or_neg_offset = -(k + offset);
    }
  }
}

100 101
/**
 * @brief Re-link the #part%s associated with the list of #gpart%s.
102 103 104
 *
 * @param gparts The list of #gpart.
 * @param N The number of particles to re-link;
105
 * @param parts The global #part array in which to find the #gpart offsets.
106
 */
107
void part_relink_parts_to_gparts(struct gpart *gparts, const size_t N,
108
                                 struct part *parts) {
109
  for (size_t k = 0; k < N; k++) {
110
    if (gparts[k].type == swift_type_gas) {
111 112 113 114 115
      parts[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
    }
  }
}

116 117 118 119 120 121 122
/**
 * @brief Re-link the #spart%s associated with the list of #gpart%s.
 *
 * @param gparts The list of #gpart.
 * @param N The number of particles to re-link;
 * @param sparts The global #spart array in which to find the #gpart offsets.
 */
123
void part_relink_sparts_to_gparts(struct gpart *gparts, const size_t N,
124 125
                                  struct spart *sparts) {
  for (size_t k = 0; k < N; k++) {
126
    if (gparts[k].type == swift_type_stars) {
127 128 129 130 131
      sparts[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
    }
  }
}

132 133 134 135 136 137 138
/**
 * @brief Re-link the #bpart%s associated with the list of #gpart%s.
 *
 * @param gparts The list of #gpart.
 * @param N The number of particles to re-link;
 * @param bparts The global #bpart array in which to find the #gpart offsets.
 */
139
void part_relink_bparts_to_gparts(struct gpart *gparts, const size_t N,
140 141 142 143 144 145 146 147
                                  struct bpart *bparts) {
  for (size_t k = 0; k < N; k++) {
    if (gparts[k].type == swift_type_black_hole) {
      bparts[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
    }
  }
}

Loic Hausammann's avatar
Loic Hausammann committed
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
/**
 * @brief Re-link the #sink%s associated with the list of #gpart%s.
 *
 * @param gparts The list of #gpart.
 * @param N The number of particles to re-link;
 * @param sinks The global #sink array in which to find the #gpart offsets.
 */
void part_relink_sinks_to_gparts(struct gpart *gparts, const size_t N,
                                 struct sink *sinks) {
  for (size_t k = 0; k < N; k++) {
    if (gparts[k].type == swift_type_sink) {
      sinks[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
    }
  }
}

164 165 166 167 168 169
/**
 * @brief Helper structure to pass data to the liking mapper functions.
 */
struct relink_data {
  struct part *const parts;
  struct gpart *const garts;
Loic Hausammann's avatar
Loic Hausammann committed
170
  struct sink *const sinks;
171 172 173 174 175 176 177 178 179 180 181 182
  struct spart *const sparts;
  struct bpart *const bparts;
};

/**
 * @brief #threadpool mapper function for the linking of all particle types
 * to the #gpart array.
 *
 * @brief map_data The array of #gpart.
 * @brief count The number of #gpart.
 * @brief extra_data the #relink_data containing pointer to the other arrays.
 */
183 184 185 186 187 188 189 190 191
void part_relink_all_parts_to_gparts_mapper(void *restrict map_data, int count,
                                            void *restrict extra_data) {

  /* Un-pack the data */
  struct relink_data *data = (struct relink_data *)extra_data;
  struct part *const parts = data->parts;
  struct spart *const sparts = data->sparts;
  struct bpart *const bparts = data->bparts;
  struct gpart *const gparts = (struct gpart *)map_data;
Loic Hausammann's avatar
Loic Hausammann committed
192
  struct sink *const sinks = data->sinks;
193 194 195 196 197 198 199 200

  for (int k = 0; k < count; k++) {
    if (gparts[k].type == swift_type_gas) {
      parts[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
    } else if (gparts[k].type == swift_type_stars) {
      sparts[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
    } else if (gparts[k].type == swift_type_black_hole) {
      bparts[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
Loic Hausammann's avatar
Loic Hausammann committed
201 202
    } else if (gparts[k].type == swift_type_sink) {
      sinks[-gparts[k].id_or_neg_offset].gpart = &gparts[k];
203 204 205 206
    }
  }
}

207
/**
Loic Hausammann's avatar
Loic Hausammann committed
208
 * @brief Re-link both the #part%s, #sink%s, #spart%s and #bpart%s associated
209
 * with the list of #gpart%s.
210
 *
211 212 213 214
 * This function uses thread parallelism and should not be called inside
 * an already threaded section (unlike the functions linking individual arrays
 * that are designed to be called in thread-parallel code).
 *
215 216 217
 * @param gparts The list of #gpart.
 * @param N The number of particles to re-link;
 * @param parts The global #part array in which to find the #gpart offsets.
Loic Hausammann's avatar
Loic Hausammann committed
218
 * @param sinks The global #sink array in which to find the #gpart offsets.
219
 * @param sparts The global #spart array in which to find the #gpart offsets.
220
 * @param bparts The global #bpart array in which to find the #gpart offsets.
Matthieu Schaller's avatar
Matthieu Schaller committed
221
 * @param tp The #threadpool object.
222
 */
223
void part_relink_all_parts_to_gparts(struct gpart *gparts, const size_t N,
Loic Hausammann's avatar
Loic Hausammann committed
224 225
                                     struct part *parts, struct sink *sinks,
                                     struct spart *sparts, struct bpart *bparts,
226
                                     struct threadpool *tp) {
227

Loic Hausammann's avatar
Loic Hausammann committed
228
  struct relink_data data = {parts, /*gparts=*/NULL, sinks, sparts, bparts};
229 230
  threadpool_map(tp, part_relink_all_parts_to_gparts_mapper, gparts, N,
                 sizeof(struct gpart), 0, &data);
231 232
}

233
/**
Loic Hausammann's avatar
Loic Hausammann committed
234 235
 * @brief Verifies that the #gpart, #part, #sink, #spart and #bpart are
 * correctly linked together and that the particle positions match.
236 237 238 239 240
 *
 * This is a debugging function.
 *
 * @param parts The #part array.
 * @param gparts The #gpart array.
Loic Hausammann's avatar
Loic Hausammann committed
241
 * @param sinks The #sink array.
242
 * @param sparts The #spart array.
243
 * @param bparts The #bpart array.
244 245
 * @param nr_parts The number of #part in the array.
 * @param nr_gparts The number of #gpart in the array.
Loic Hausammann's avatar
Loic Hausammann committed
246
 * @param nr_sinks The number of #sink in the array.
247
 * @param nr_sparts The number of #spart in the array.
248
 * @param nr_bparts The number of #bpart in the array.
249
 * @param verbose Do we report verbosely in case of success ?
250 251
 */
void part_verify_links(struct part *parts, struct gpart *gparts,
Loic Hausammann's avatar
Loic Hausammann committed
252 253 254 255
                       struct sink *sinks, struct spart *sparts,
                       struct bpart *bparts, size_t nr_parts, size_t nr_gparts,
                       size_t nr_sinks, size_t nr_sparts, size_t nr_bparts,
                       int verbose) {
256

257 258
  ticks tic = getticks();

259 260
  for (size_t k = 0; k < nr_gparts; ++k) {

261 262 263
    /* We have a real DM particle */
    if (gparts[k].type == swift_type_dark_matter &&
        gparts[k].time_bin != time_bin_not_created) {
264 265

      /* Check that it's not linked */
266
      if (gparts[k].id_or_neg_offset <= 0)
267 268 269
        error("DM gpart particle linked to something !");
    }

270 271 272 273 274 275
    /* We have a background DM particle */
    if (gparts[k].type == swift_type_dark_matter_background &&
        gparts[k].time_bin != time_bin_not_created) {

      /* Check that it's not linked */
      if (gparts[k].id_or_neg_offset <= 0)
276
        error("Background DM gpart particle linked to something !");
277 278
    }

279 280 281 282 283
    /* We have a gas particle */
    else if (gparts[k].type == swift_type_gas) {

      /* Check that it is linked */
      if (gparts[k].id_or_neg_offset > 0)
284
        error("Gas gpart not linked to anything!");
285 286 287 288 289

      /* Find its link */
      const struct part *part = &parts[-gparts[k].id_or_neg_offset];

      /* Check the reverse link */
290
      if (part->gpart != &gparts[k]) error("Linking problem!");
291 292 293 294

      /* Check that the particles are at the same place */
      if (gparts[k].x[0] != part->x[0] || gparts[k].x[1] != part->x[1] ||
          gparts[k].x[2] != part->x[2])
295
        error(
296
            "Linked particles are not at the same position!\n"
297 298 299 300
            "gp->x=[%e %e %e] p->x=[%e %e %e] diff=[%e %e %e]",
            gparts[k].x[0], gparts[k].x[1], gparts[k].x[2], part->x[0],
            part->x[1], part->x[2], gparts[k].x[0] - part->x[0],
            gparts[k].x[1] - part->x[1], gparts[k].x[2] - part->x[2]);
301

302 303 304 305 306 307 308
      /* Check that the particles have the same mass */
      if (gparts[k].mass != hydro_get_mass(part))
        error(
            "Linked particles do not have the same mass!\n"
            "gp->m=%e p->m=%e",
            gparts[k].mass, hydro_get_mass(part));

309
      /* Check that the particles are at the same time */
Matthieu Schaller's avatar
Matthieu Schaller committed
310
      if (gparts[k].time_bin != part->time_bin)
311
        error("Linked particles are not at the same time !");
312 313
    }

314
    else if (gparts[k].type == swift_type_stars) {
315 316 317

      /* Check that it is linked */
      if (gparts[k].id_or_neg_offset > 0)
318
        error("Stars gpart not linked to anything !");
319 320 321 322 323 324 325 326 327 328

      /* Find its link */
      const struct spart *spart = &sparts[-gparts[k].id_or_neg_offset];

      /* Check the reverse link */
      if (spart->gpart != &gparts[k]) error("Linking problem !");

      /* Check that the particles are at the same place */
      if (gparts[k].x[0] != spart->x[0] || gparts[k].x[1] != spart->x[1] ||
          gparts[k].x[2] != spart->x[2])
329 330 331 332 333 334
        error(
            "Linked particles are not at the same position !\n"
            "gp->x=[%e %e %e] sp->x=[%e %e %e] diff=[%e %e %e]",
            gparts[k].x[0], gparts[k].x[1], gparts[k].x[2], spart->x[0],
            spart->x[1], spart->x[2], gparts[k].x[0] - spart->x[0],
            gparts[k].x[1] - spart->x[1], gparts[k].x[2] - spart->x[2]);
335

336 337 338 339 340 341 342
      /* Check that the particles have the same mass */
      if (gparts[k].mass != spart->mass)
        error(
            "Linked particles do not have the same mass!\n"
            "gp->m=%e sp->m=%e",
            gparts[k].mass, spart->mass);

343
      /* Check that the particles are at the same time */
Matthieu Schaller's avatar
Matthieu Schaller committed
344
      if (gparts[k].time_bin != spart->time_bin)
345
        error("Linked particles are not at the same time !");
346
    }
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364

    else if (gparts[k].type == swift_type_black_hole) {

      /* Check that it is linked */
      if (gparts[k].id_or_neg_offset > 0)
        error("Black holes gpart not linked to anything !");

      /* Find its link */
      const struct bpart *bpart = &bparts[-gparts[k].id_or_neg_offset];

      /* Check the reverse link */
      if (bpart->gpart != &gparts[k]) error("Linking problem !");

      /* Check that the particles are at the same place */
      if (gparts[k].x[0] != bpart->x[0] || gparts[k].x[1] != bpart->x[1] ||
          gparts[k].x[2] != bpart->x[2])
        error(
            "Linked particles are not at the same position !\n"
365
            "gp->x=[%e %e %e] bp->x=[%e %e %e] diff=[%e %e %e]",
366 367 368 369
            gparts[k].x[0], gparts[k].x[1], gparts[k].x[2], bpart->x[0],
            bpart->x[1], bpart->x[2], gparts[k].x[0] - bpart->x[0],
            gparts[k].x[1] - bpart->x[1], gparts[k].x[2] - bpart->x[2]);

370 371 372 373 374 375 376
      /* Check that the particles have the same mass */
      if (gparts[k].mass != bpart->mass)
        error(
            "Linked particles do not have the same mass!\n"
            "gp->m=%e sp->m=%e",
            gparts[k].mass, bpart->mass);

377 378 379 380
      /* Check that the particles are at the same time */
      if (gparts[k].time_bin != bpart->time_bin)
        error("Linked particles are not at the same time !");
    }
Loic Hausammann's avatar
Loic Hausammann committed
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414

    else if (gparts[k].type == swift_type_sink) {

      /* Check that it is linked */
      if (gparts[k].id_or_neg_offset > 0)
        error("Sink gpart not linked to anything !");

      /* Find its link */
      const struct sink *sink = &sinks[-gparts[k].id_or_neg_offset];

      /* Check the reverse link */
      if (sink->gpart != &gparts[k]) error("Linking problem !");

      /* Check that the particles are at the same place */
      if (gparts[k].x[0] != sink->x[0] || gparts[k].x[1] != sink->x[1] ||
          gparts[k].x[2] != sink->x[2])
        error(
            "Linked particles are not at the same position !\n"
            "gp->x=[%e %e %e] sink->x=[%e %e %e] diff=[%e %e %e]",
            gparts[k].x[0], gparts[k].x[1], gparts[k].x[2], sink->x[0],
            sink->x[1], sink->x[2], gparts[k].x[0] - sink->x[0],
            gparts[k].x[1] - sink->x[1], gparts[k].x[2] - sink->x[2]);

      /* Check that the particles have the same mass */
      if (gparts[k].mass != sink->mass)
        error(
            "Linked particles do not have the same mass!\n"
            "gp->m=%e sink->m=%e",
            gparts[k].mass, sink->mass);

      /* Check that the particles are at the same time */
      if (gparts[k].time_bin != sink->time_bin)
        error("Linked particles are not at the same time !");
    }
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432
  }

  /* Now check that all parts are linked */
  for (size_t k = 0; k < nr_parts; ++k) {

    /* Ok, there is a link */
    if (parts[k].gpart != NULL) {

      /* Check the link */
      if (parts[k].gpart->id_or_neg_offset != -(ptrdiff_t)k) {
        error("Linking problem !");
      }

      /* Check that the particles are at the same place */
      if (parts[k].x[0] != parts[k].gpart->x[0] ||
          parts[k].x[1] != parts[k].gpart->x[1] ||
          parts[k].x[2] != parts[k].gpart->x[2])
        error("Linked particles are not at the same position !");
433

434 435 436 437
      /* Check that the particles have the same mass */
      if (hydro_get_mass(&parts[k]) != parts[k].gpart->mass)
        error("Linked particles do not have the same mass!\n");

438 439
      /* Check that the particles are at the same time */
      if (parts[k].time_bin != parts[k].gpart->time_bin)
Matthieu Schaller's avatar
Matthieu Schaller committed
440
        error("Linked particles are not at the same time !");
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
    }
  }

  /* Now check that all sparts are linked */
  for (size_t k = 0; k < nr_sparts; ++k) {

    /* Ok, there is a link */
    if (sparts[k].gpart != NULL) {

      /* Check the link */
      if (sparts[k].gpart->id_or_neg_offset != -(ptrdiff_t)k) {
        error("Linking problem !");

        /* Check that the particles are at the same place */
        if (sparts[k].x[0] != sparts[k].gpart->x[0] ||
            sparts[k].x[1] != sparts[k].gpart->x[1] ||
            sparts[k].x[2] != sparts[k].gpart->x[2])
          error("Linked particles are not at the same position !");
459

460 461 462 463
        /* Check that the particles have the same mass */
        if (sparts[k].mass != sparts[k].gpart->mass)
          error("Linked particles do not have the same mass!\n");

Matthieu Schaller's avatar
Matthieu Schaller committed
464 465 466
        /* Check that the particles are at the same time */
        if (sparts[k].time_bin != sparts[k].gpart->time_bin)
          error("Linked particles are not at the same time !");
467 468 469
      }
    }
  }
470

471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
  /* Now check that all bparts are linked */
  for (size_t k = 0; k < nr_bparts; ++k) {

    /* Ok, there is a link */
    if (bparts[k].gpart != NULL) {

      /* Check the link */
      if (bparts[k].gpart->id_or_neg_offset != -(ptrdiff_t)k) {
        error("Linking problem !");

        /* Check that the particles are at the same place */
        if (bparts[k].x[0] != bparts[k].gpart->x[0] ||
            bparts[k].x[1] != bparts[k].gpart->x[1] ||
            bparts[k].x[2] != bparts[k].gpart->x[2])
          error("Linked particles are not at the same position !");

487 488 489 490
        /* Check that the particles have the same mass */
        if (bparts[k].mass != bparts[k].gpart->mass)
          error("Linked particles do not have the same mass!\n");

491 492 493 494 495 496 497
        /* Check that the particles are at the same time */
        if (bparts[k].time_bin != bparts[k].gpart->time_bin)
          error("Linked particles are not at the same time !");
      }
    }
  }

Loic Hausammann's avatar
Loic Hausammann committed
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
  /* Now check that all sinks are linked */
  for (size_t k = 0; k < nr_sinks; ++k) {

    /* Ok, there is a link */
    if (sinks[k].gpart != NULL) {

      /* Check the link */
      if (sinks[k].gpart->id_or_neg_offset != -(ptrdiff_t)k) {
        error("Linking problem !");

        /* Check that the particles are at the same place */
        if (sinks[k].x[0] != sinks[k].gpart->x[0] ||
            sinks[k].x[1] != sinks[k].gpart->x[1] ||
            sinks[k].x[2] != sinks[k].gpart->x[2])
          error("Linked particles are not at the same position !");

        /* Check that the particles have the same mass */
        if (sinks[k].mass != sinks[k].gpart->mass)
          error("Linked particles do not have the same mass!\n");

        /* Check that the particles are at the same time */
        if (sinks[k].time_bin != sinks[k].gpart->time_bin)
          error("Linked particles are not at the same time !");
      }
    }
  }

525
  if (verbose) message("All links OK");
526 527 528
  if (verbose)
    message("took %.3f %s.", clocks_from_ticks(getticks() - tic),
            clocks_getunit());
529 530
}

531
#ifdef WITH_MPI
532 533 534 535
/* MPI data type for the particle transfers */
MPI_Datatype part_mpi_type;
MPI_Datatype xpart_mpi_type;
MPI_Datatype gpart_mpi_type;
536
MPI_Datatype spart_mpi_type;
537
MPI_Datatype bpart_mpi_type;
rttw52's avatar
rttw52 committed
538
MPI_Datatype lospart_mpi_type;
539 540

/**
541
 * @brief Registers MPI particle types.
542
 */
543
void part_create_mpi_types(void) {
544

545
  /* This is not the recommended way of doing this.
546 547 548 549
     One should define the structure field by field
     But as long as we don't do serialization via MPI-IO
     we don't really care.
     Also we would have to modify this function everytime something
550
     is added to the part structure. */
551 552 553 554 555
  if (MPI_Type_contiguous(sizeof(struct part) / sizeof(unsigned char), MPI_BYTE,
                          &part_mpi_type) != MPI_SUCCESS ||
      MPI_Type_commit(&part_mpi_type) != MPI_SUCCESS) {
    error("Failed to create MPI type for parts.");
  }
556 557
  if (MPI_Type_contiguous(sizeof(struct xpart) / sizeof(unsigned char),
                          MPI_BYTE, &xpart_mpi_type) != MPI_SUCCESS ||
558 559 560
      MPI_Type_commit(&xpart_mpi_type) != MPI_SUCCESS) {
    error("Failed to create MPI type for xparts.");
  }
561 562
  if (MPI_Type_contiguous(sizeof(struct gpart) / sizeof(unsigned char),
                          MPI_BYTE, &gpart_mpi_type) != MPI_SUCCESS ||
563 564 565
      MPI_Type_commit(&gpart_mpi_type) != MPI_SUCCESS) {
    error("Failed to create MPI type for gparts.");
  }
566 567 568 569 570
  if (MPI_Type_contiguous(sizeof(struct spart) / sizeof(unsigned char),
                          MPI_BYTE, &spart_mpi_type) != MPI_SUCCESS ||
      MPI_Type_commit(&spart_mpi_type) != MPI_SUCCESS) {
    error("Failed to create MPI type for sparts.");
  }
571 572 573 574 575
  if (MPI_Type_contiguous(sizeof(struct bpart) / sizeof(unsigned char),
                          MPI_BYTE, &bpart_mpi_type) != MPI_SUCCESS ||
      MPI_Type_commit(&bpart_mpi_type) != MPI_SUCCESS) {
    error("Failed to create MPI type for bparts.");
  }
576
}
577 578 579 580 581 582 583 584

void part_free_mpi_types(void) {

  MPI_Type_free(&part_mpi_type);
  MPI_Type_free(&xpart_mpi_type);
  MPI_Type_free(&gpart_mpi_type);
  MPI_Type_free(&spart_mpi_type);
  MPI_Type_free(&bpart_mpi_type);
585
  MPI_Type_free(&lospart_mpi_type);
586
}
587
#endif