/******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2016 Matthieu Schaller (schaller@strw.leidenuniv.nl) * * 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 . * ******************************************************************************/ /* Config parameters. */ #include /* System includes. */ #include /* This object's header. */ #include "mesh_gravity_patch.h" /* Local includes. */ #include "atomic.h" #include "cell.h" #include "error.h" #include "row_major_id.h" /** * @brief Initialize a mesh patch to cover a cell * * @param patch A pointer to the mesh patch * @param cell The cell which the mesh should cover * @param fac Inverse of the FFT mesh size * @param dim Size of the full volume in each dimension * @param boundary_size Size of the boundary layer to include */ void pm_mesh_patch_init(struct pm_mesh_patch *patch, const struct cell *cell, const int N, const double fac, const double dim[3], const int boundary_size) { const int gcount = cell->grav.count; const struct gpart *gparts = cell->grav.parts; patch->N = N; patch->fac = fac; /* Will need to wrap particles to position nearest the cell centre */ double wrap_min[3]; double wrap_max[3]; for (int i = 0; i < 3; i++) { wrap_min[i] = cell->loc[i] + 0.5 * cell->width[i] - 0.5 * dim[i]; wrap_max[i] = cell->loc[i] + 0.5 * cell->width[i] + 0.5 * dim[i]; } /* Store the wraps */ for (int i = 0; i < 3; i++) { patch->wrap_min[i] = wrap_min[i]; patch->wrap_max[i] = wrap_max[i]; } /* Find the extent of the particle distribution in the cell */ double pos_min[3]; double pos_max[3]; for (int i = 0; i < 3; i++) { pos_min[i] = patch->wrap_max[i]; pos_max[i] = patch->wrap_min[i]; } for (int ipart = 0; ipart < gcount; ipart++) { const struct gpart *gp = &gparts[ipart]; if (gp->time_bin == time_bin_inhibited) continue; for (int i = 0; i < 3; i++) { const double pos_wrap = box_wrap(gp->x[i], wrap_min[i], wrap_max[i]); if (pos_wrap < pos_min[i]) pos_min[i] = pos_wrap; if (pos_wrap > pos_max[i]) pos_max[i] = pos_wrap; } } /* Determine the integer size and coordinates of the mesh */ int num_cells = 1; for (int i = 0; i < 3; i++) { patch->mesh_min[i] = floor(pos_min[i] * fac) - boundary_size; /* CIC interpolation requires one extra element in the positive direction */ patch->mesh_max[i] = floor(pos_max[i] * fac) + boundary_size + 1; patch->mesh_size[i] = patch->mesh_max[i] - patch->mesh_min[i] + 1; num_cells *= patch->mesh_size[i]; } /* Allocate the mesh */ if (swift_memalign("mesh_patch", (void **)&patch->mesh, SWIFT_CACHE_ALIGNMENT, num_cells * sizeof(double)) != 0) error("Failed to allocate array for mesh patch!"); } /** * @brief Write the content of a mesh patch back to the global mesh * using atomic operations. * * @param global_mesh The global mesh to write to. * @param patch The #pm_mesh_patch object to write from. */ void pm_add_patch_to_global_mesh(double *const global_mesh, const struct pm_mesh_patch *patch) { const int N = patch->N; const int size_i = patch->mesh_size[0]; const int size_j = patch->mesh_size[1]; const int size_k = patch->mesh_size[2]; const int mesh_min_i = patch->mesh_min[0]; const int mesh_min_j = patch->mesh_min[1]; const int mesh_min_k = patch->mesh_min[2]; /* Remind the compiler that the arrays are nicely aligned */ swift_declare_aligned_ptr(const double, mesh, patch->mesh, SWIFT_CACHE_ALIGNMENT); for (int i = 0; i < size_i; ++i) { for (int j = 0; j < size_j; ++j) { for (int k = 0; k < size_k; ++k) { const int ii = i + mesh_min_i; const int jj = j + mesh_min_j; const int kk = k + mesh_min_k; const int patch_index = pm_mesh_patch_index(patch, i, j, k); const int mesh_index = row_major_id_periodic(ii, jj, kk, N); atomic_add_d(&global_mesh[mesh_index], mesh[patch_index]); } } } } /** * @brief Set all values in a mesh patch to zero * * @param patch A pointer to the mesh patch */ void pm_mesh_patch_zero(struct pm_mesh_patch *patch) { /* Remind the compiler that the arrays are nicely aligned */ swift_declare_aligned_ptr(double, mesh, patch->mesh, SWIFT_CACHE_ALIGNMENT); const int num = patch->mesh_size[0] * patch->mesh_size[1] * patch->mesh_size[2]; memset(mesh, 0, num * sizeof(double)); } /** * @brief Free the memory associated with a mesh patch. * * @param patch A pointer to the mesh patch */ void pm_mesh_patch_clean(struct pm_mesh_patch *patch) { if (patch->mesh) swift_free("mesh_patch", patch->mesh); /* Zero everything and give a silly mesh size to help debugging */ memset(patch, 0, sizeof(struct pm_mesh_patch)); patch->N = -1; }