diff --git a/src/const.h b/src/const.h index daa573db25c0b554d5b0f62598682111dc9aa640..9693aebb4f15d969ed80d2f501cc2a7b6b21b0d3 100644 --- a/src/const.h +++ b/src/const.h @@ -37,9 +37,9 @@ #define const_max_u_change 0.1f /* Dimensionality of the problem */ -//#define HYDRO_DIMENSION_3D +#define HYDRO_DIMENSION_3D //#define HYDRO_DIMENSION_2D -#define HYDRO_DIMENSION_1D +//#define HYDRO_DIMENSION_1D /* Hydrodynamical adiabatic index. */ #define HYDRO_GAMMA_5_3 diff --git a/src/hydro/Shadowswift/hydro_gradients_shadowfax.h b/src/hydro/Shadowswift/hydro_gradients_shadowfax.h index 9977c36d94d9647da071b867de5a8d101457de6d..9ca40a604da3dc12bbb48ac033cd078f0561d8ab 100644 --- a/src/hydro/Shadowswift/hydro_gradients_shadowfax.h +++ b/src/hydro/Shadowswift/hydro_gradients_shadowfax.h @@ -86,15 +86,14 @@ __attribute__((always_inline)) INLINE void hydro_gradients_single_quantity( __attribute__((always_inline)) INLINE static void hydro_gradients_collect( float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { - float A[3], midpoint[3]; + float A, midpoint[3]; - if (!voronoi_get_face(&pi->cell, pj->id, A, midpoint)) { + A = voronoi_get_face(&pi->cell, pj->id, midpoint); + if (!A) { /* particle is not a cell neighbour: do nothing */ return; } - float Anorm = sqrtf(A[0] * A[0] + A[1] * A[1] + A[2] * A[2]); - float c[3]; /* midpoint is relative w.r.t. pi->x, as is dx */ /* c is supposed to be the vector pointing from the midpoint of pi and pj to @@ -108,15 +107,15 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( float r = sqrtf(r2); hydro_gradients_single_quantity(pi->primitives.rho, pj->primitives.rho, c, dx, - r, Anorm, pi->primitives.gradients.rho); + r, A, pi->primitives.gradients.rho); hydro_gradients_single_quantity(pi->primitives.v[0], pj->primitives.v[0], c, - dx, r, Anorm, pi->primitives.gradients.v[0]); + dx, r, A, pi->primitives.gradients.v[0]); hydro_gradients_single_quantity(pi->primitives.v[1], pj->primitives.v[1], c, - dx, r, Anorm, pi->primitives.gradients.v[1]); + dx, r, A, pi->primitives.gradients.v[1]); hydro_gradients_single_quantity(pi->primitives.v[2], pj->primitives.v[2], c, - dx, r, Anorm, pi->primitives.gradients.v[2]); + dx, r, A, pi->primitives.gradients.v[2]); hydro_gradients_single_quantity(pi->primitives.P, pj->primitives.P, c, dx, r, - Anorm, pi->primitives.gradients.P); + A, pi->primitives.gradients.P); hydro_slope_limit_cell_collect(pi, pj, r); @@ -125,19 +124,15 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_collect( mindx[1] = -dx[1]; mindx[2] = -dx[2]; hydro_gradients_single_quantity(pj->primitives.rho, pi->primitives.rho, c, - mindx, r, Anorm, - pj->primitives.gradients.rho); + mindx, r, A, pj->primitives.gradients.rho); hydro_gradients_single_quantity(pj->primitives.v[0], pi->primitives.v[0], c, - mindx, r, Anorm, - pj->primitives.gradients.v[0]); + mindx, r, A, pj->primitives.gradients.v[0]); hydro_gradients_single_quantity(pj->primitives.v[1], pi->primitives.v[1], c, - mindx, r, Anorm, - pj->primitives.gradients.v[1]); + mindx, r, A, pj->primitives.gradients.v[1]); hydro_gradients_single_quantity(pj->primitives.v[2], pi->primitives.v[2], c, - mindx, r, Anorm, - pj->primitives.gradients.v[2]); + mindx, r, A, pj->primitives.gradients.v[2]); hydro_gradients_single_quantity(pj->primitives.P, pi->primitives.P, c, mindx, - r, Anorm, pj->primitives.gradients.P); + r, A, pj->primitives.gradients.P); hydro_slope_limit_cell_collect(pj, pi, r); } @@ -156,15 +151,14 @@ __attribute__((always_inline)) INLINE static void hydro_gradients_nonsym_collect(float r2, float *dx, float hi, float hj, struct part *pi, struct part *pj) { - float A[3], midpoint[3]; + float A, midpoint[3]; - if (!voronoi_get_face(&pi->cell, pj->id, A, midpoint)) { + A = voronoi_get_face(&pi->cell, pj->id, midpoint); + if (!A) { /* particle is not a cell neighbour: do nothing */ return; } - float Anorm = sqrtf(A[0] * A[0] + A[1] * A[1] + A[2] * A[2]); - float c[3]; /* midpoint is relative w.r.t. pi->x, as is dx */ /* c is supposed to be the vector pointing from the midpoint of pi and pj to @@ -178,15 +172,15 @@ hydro_gradients_nonsym_collect(float r2, float *dx, float hi, float hj, float r = sqrtf(r2); hydro_gradients_single_quantity(pi->primitives.rho, pj->primitives.rho, c, dx, - r, Anorm, pi->primitives.gradients.rho); + r, A, pi->primitives.gradients.rho); hydro_gradients_single_quantity(pi->primitives.v[0], pj->primitives.v[0], c, - dx, r, Anorm, pi->primitives.gradients.v[0]); + dx, r, A, pi->primitives.gradients.v[0]); hydro_gradients_single_quantity(pi->primitives.v[1], pj->primitives.v[1], c, - dx, r, Anorm, pi->primitives.gradients.v[1]); + dx, r, A, pi->primitives.gradients.v[1]); hydro_gradients_single_quantity(pi->primitives.v[2], pj->primitives.v[2], c, - dx, r, Anorm, pi->primitives.gradients.v[2]); + dx, r, A, pi->primitives.gradients.v[2]); hydro_gradients_single_quantity(pi->primitives.P, pj->primitives.P, c, dx, r, - Anorm, pi->primitives.gradients.P); + A, pi->primitives.gradients.P); hydro_slope_limit_cell_collect(pi, pj, r); } diff --git a/src/hydro/Shadowswift/hydro_iact.h b/src/hydro/Shadowswift/hydro_iact.h index 1c1ec9e1ad1f833d3bf73986026d7d0c96d8ff5f..8997155a0cb30848a74b220811970421b6d3396a 100644 --- a/src/hydro/Shadowswift/hydro_iact.h +++ b/src/hydro/Shadowswift/hydro_iact.h @@ -134,8 +134,7 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( float r = sqrtf(r2); int k; - float A[3]; - float Anorm; + float A; float xij_i[3]; float vmax, dvdotdx; float vi[3], vj[3], vij[3]; @@ -143,7 +142,8 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( float dti, dtj, mindt; float n_unit[3]; - if (!voronoi_get_face(&pi->cell, pj->id, A, xij_i)) { + A = voronoi_get_face(&pi->cell, pj->id, xij_i); + if (!A) { /* this neighbour does not share a face with the cell, return */ return; } @@ -190,11 +190,10 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( dti = mindt; dtj = mindt; - Anorm = A[0] * A[0] + A[1] * A[1] + A[2] * A[2]; - /* compute the normal vector of the interface */ - Anorm = sqrtf(Anorm); - for (k = 0; k < 3; k++) n_unit[k] = A[k] / Anorm; + for (k = 0; k < 3; ++k) { + n_unit[k] = -dx[k] / r; + } /* Compute interface velocity */ float fac = (vi[0] - vj[0]) * (xij_i[0] + 0.5f * dx[0]) + @@ -261,19 +260,19 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( /* Update conserved variables */ /* eqn. (16) */ - pi->conserved.flux.mass -= dti * Anorm * totflux[0]; - pi->conserved.flux.momentum[0] -= dti * Anorm * totflux[1]; - pi->conserved.flux.momentum[1] -= dti * Anorm * totflux[2]; - pi->conserved.flux.momentum[2] -= dti * Anorm * totflux[3]; - pi->conserved.flux.energy -= dti * Anorm * totflux[4]; + pi->conserved.flux.mass -= dti * A * totflux[0]; + pi->conserved.flux.momentum[0] -= dti * A * totflux[1]; + pi->conserved.flux.momentum[1] -= dti * A * totflux[2]; + pi->conserved.flux.momentum[2] -= dti * A * totflux[3]; + pi->conserved.flux.energy -= dti * A * totflux[4]; float ekin = 0.5f * (pi->primitives.v[0] * pi->primitives.v[0] + pi->primitives.v[1] * pi->primitives.v[1] + pi->primitives.v[2] * pi->primitives.v[2]); - pi->conserved.flux.energy += dti * Anorm * totflux[1] * pi->primitives.v[0]; - pi->conserved.flux.energy += dti * Anorm * totflux[2] * pi->primitives.v[1]; - pi->conserved.flux.energy += dti * Anorm * totflux[3] * pi->primitives.v[2]; - pi->conserved.flux.energy -= dti * Anorm * totflux[0] * ekin; + pi->conserved.flux.energy += dti * A * totflux[1] * pi->primitives.v[0]; + pi->conserved.flux.energy += dti * A * totflux[2] * pi->primitives.v[1]; + pi->conserved.flux.energy += dti * A * totflux[3] * pi->primitives.v[2]; + pi->conserved.flux.energy -= dti * A * totflux[0] * ekin; /* here is how it works: Mode will only be 1 if both particles are ACTIVE and they are in the same @@ -288,19 +287,19 @@ __attribute__((always_inline)) INLINE static void runner_iact_fluxes_common( ==> we update particle j if (MODE IS 1) OR (j IS INACTIVE) */ if (mode == 1 || pj->ti_end > pi->ti_end) { - pj->conserved.flux.mass += dtj * Anorm * totflux[0]; - pj->conserved.flux.momentum[0] += dtj * Anorm * totflux[1]; - pj->conserved.flux.momentum[1] += dtj * Anorm * totflux[2]; - pj->conserved.flux.momentum[2] += dtj * Anorm * totflux[3]; - pj->conserved.flux.energy += dtj * Anorm * totflux[4]; + pj->conserved.flux.mass += dtj * A * totflux[0]; + pj->conserved.flux.momentum[0] += dtj * A * totflux[1]; + pj->conserved.flux.momentum[1] += dtj * A * totflux[2]; + pj->conserved.flux.momentum[2] += dtj * A * totflux[3]; + pj->conserved.flux.energy += dtj * A * totflux[4]; ekin = 0.5f * (pj->primitives.v[0] * pj->primitives.v[0] + pj->primitives.v[1] * pj->primitives.v[1] + pj->primitives.v[2] * pj->primitives.v[2]); - pj->conserved.flux.energy -= dtj * Anorm * totflux[1] * pj->primitives.v[0]; - pj->conserved.flux.energy -= dtj * Anorm * totflux[2] * pj->primitives.v[1]; - pj->conserved.flux.energy -= dtj * Anorm * totflux[3] * pj->primitives.v[2]; - pj->conserved.flux.energy += dtj * Anorm * totflux[0] * ekin; + pj->conserved.flux.energy -= dtj * A * totflux[1] * pj->primitives.v[0]; + pj->conserved.flux.energy -= dtj * A * totflux[2] * pj->primitives.v[1]; + pj->conserved.flux.energy -= dtj * A * totflux[3] * pj->primitives.v[2]; + pj->conserved.flux.energy += dtj * A * totflux[0] * ekin; } } diff --git a/src/hydro/Shadowswift/voronoi1d_algorithm.h b/src/hydro/Shadowswift/voronoi1d_algorithm.h index 222c97b617512b4fcaa1bfd935674bd5b7d8eca5..e8a6ccd61cdf90f4887028fa042fde93ecd90d5e 100644 --- a/src/hydro/Shadowswift/voronoi1d_algorithm.h +++ b/src/hydro/Shadowswift/voronoi1d_algorithm.h @@ -128,43 +128,37 @@ __attribute__((always_inline)) INLINE float voronoi_cell_finalize( * deal with it appropriately. * * For this specific case, we simply check if the neighbour is the left or - * right neighbour and set the surface area to the unit vector pointing either - * to the right or to the left. The midpoint is set to the relative position - * vector of the appropriate face. + * right neighbour and set the surface area to 1. The midpoint is set to the + * relative position vector of the appropriate face. * * @param cell 1D Voronoi cell. * @param ngb ID of a particle that is possibly a neighbour of this cell. - * @param A Array to store the oriented surface area in. * @param midpoint Array to store the relative position of the face in. - * @return 0 if the given neighbour is not a neighbour, 1 otherwise. + * @return 0 if the given neighbour is not a neighbour, surface area 1.0f + * otherwise. */ -__attribute__((always_inline)) INLINE int voronoi_get_face( - struct voronoi_cell *cell, unsigned long long ngb, float *A, - float *midpoint) { +__attribute__((always_inline)) INLINE float voronoi_get_face( + struct voronoi_cell *cell, unsigned long long ngb, float *midpoint) { if (ngb != cell->idL && ngb != cell->idR) { /* this is perfectly possible: we interact with all particles within the smoothing length, and they do not need to be all neighbours. If this happens, we return 0, so that the flux method can return */ - return 0; + return 0.0f; } if (ngb == cell->idL) { /* Left face */ - A[0] = -1.0f; midpoint[0] = cell->xL; } else { /* Right face */ - A[0] = 1.0f; midpoint[0] = cell->xR; } - /* The other components of A and midpoint are just zero */ - A[1] = 0.0f; - A[2] = 0.0f; + /* The other components of midpoint are just zero */ midpoint[1] = 0.0f; midpoint[2] = 0.0f; - return 1; + return 1.0f; } /** diff --git a/src/hydro/Shadowswift/voronoi3d_algorithm.h b/src/hydro/Shadowswift/voronoi3d_algorithm.h index 165798bad1584173cb0df42894a1ca01091e2c0a..253db7e54fd7ea832924f93d4369eb32bc759fcf 100644 --- a/src/hydro/Shadowswift/voronoi3d_algorithm.h +++ b/src/hydro/Shadowswift/voronoi3d_algorithm.h @@ -21,6 +21,9 @@ #define SWIFT_VORONOI3D_ALGORITHM_H #include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include "error.h" #include "inline.h" #include "voronoi3d_cell.h" @@ -1219,6 +1222,13 @@ __attribute__((always_inline)) INLINE void voronoi_calculate_cell( cell->centroid[0] += cell->x[0]; cell->centroid[1] += cell->x[1]; cell->centroid[2] += cell->x[2]; + + /* Reset the edges: we still need them for the face calculation */ + for (i = 0; i < VORONOI3D_MAXNUMEDGE; ++i) { + if (cell->edges[i] < 0) { + cell->edges[i] = -1 - cell->edges[i]; + } + } } /** @@ -1389,24 +1399,36 @@ __attribute__((always_inline)) INLINE float voronoi_cell_finalize( } max_radius = sqrtf(max_radius); - return max_radius; + return 2.0f * max_radius; } /** - * @brief Get the oriented surface area and midpoint of the face between a - * 3D Voronoi cell and the given neighbour + * @brief Get the surface area and midpoint of the face between a 3D Voronoi + * cell and the given neighbour * * @param cell 3D Voronoi cell. * @param ngb ID of a particle that is possibly a neighbour of this cell-> - * @param A Array to store the oriented surface area in. * @param midpoint Array to store the relative position of the face in. - * @return 0 if the given neighbour is not a neighbour, 1 otherwise. + * @return 0 if the given neighbour is not a neighbour, the surface area of + * the face otherwise. */ -__attribute__((always_inline)) INLINE int voronoi_get_face( - struct voronoi_cell *cell, unsigned long long ngb, float *A, - float *midpoint) { +__attribute__((always_inline)) INLINE float voronoi_get_face( + struct voronoi_cell *cell, unsigned long long ngb, float *midpoint) { - return 0; + int i = 0; + while (i < cell->nface && cell->ngbs[i] != ngb) { + i++; + } + if (i == cell->nface) { + /* Ngb not found */ + return 0.0f; + } + + midpoint[0] = cell->face_midpoints[i][0]; + midpoint[1] = cell->face_midpoints[i][1]; + midpoint[2] = cell->face_midpoints[i][2]; + + return cell->face_areas[i]; } /** diff --git a/tests/testVoronoi1D.c b/tests/testVoronoi1D.c index 1b96dc1d1d98f8a7d7ce3044822631c1c4515496..dfc0d77b35d83976cfeeb4aed68f9c69d5ed395d 100644 --- a/tests/testVoronoi1D.c +++ b/tests/testVoronoi1D.c @@ -55,18 +55,18 @@ int main() { } /* Check face method */ - float A[3]; + float A; float midpoint[3]; - voronoi_get_face(&cell, 1, A, midpoint); - if (A[0] != -1.0f) { - error("Wrong surface normal returned for left neighbour!"); + A = voronoi_get_face(&cell, 1, midpoint); + if (A != 1.0f) { + error("Wrong surface area returned for left neighbour!"); } if (midpoint[0] != -0.25f) { error("Wrong midpoint returned for left neighbour!"); } - voronoi_get_face(&cell, 2, A, midpoint); - if (A[0] != 1.0f) { - error("Wrong surface normal returned for right neighbour!"); + A = voronoi_get_face(&cell, 2, midpoint); + if (A != 1.0f) { + error("Wrong surface area returned for right neighbour!"); } if (midpoint[0] != 0.25f) { error("Wrong midpoint returned for right neighbour!"); diff --git a/tests/testVoronoi3D.c b/tests/testVoronoi3D.c index 644a9508af2c8b4e1c2630367f972e8af5f40ee4..87c6def86a2a90ee94e6300b89660764667bc272 100644 --- a/tests/testVoronoi3D.c +++ b/tests/testVoronoi3D.c @@ -64,12 +64,54 @@ void test_calculate_cell() { voronoi_initialize(&cell); /* Calculate the volume and centroid of the large cube. */ voronoi_calculate_cell(&cell); + /* Calculate the faces. */ + voronoi_calculate_faces(&cell); /* Update these values if you ever change to another large cube! */ assert(cell.volume == 27.0f); assert(cell.centroid[0] = 0.5f); assert(cell.centroid[1] = 0.5f); assert(cell.centroid[2] = 0.5f); + + /* Check cell neighbours. */ + assert(cell.nface == 6); + assert(cell.ngbs[0] == VORONOI3D_BOX_FRONT); + assert(cell.ngbs[1] == VORONOI3D_BOX_LEFT); + assert(cell.ngbs[2] == VORONOI3D_BOX_BOTTOM); + assert(cell.ngbs[3] == VORONOI3D_BOX_TOP); + assert(cell.ngbs[4] == VORONOI3D_BOX_BACK); + assert(cell.ngbs[5] == VORONOI3D_BOX_RIGHT); + + /* Check cell faces */ + assert(cell.face_areas[0] == 9.0f); + assert(cell.face_midpoints[0][0] == 0.5f); + assert(cell.face_midpoints[0][1] == -1.0f); + assert(cell.face_midpoints[0][2] == 0.5f); + + assert(cell.face_areas[1] == 9.0f); + assert(cell.face_midpoints[1][0] == -1.0f); + assert(cell.face_midpoints[1][1] == 0.5f); + assert(cell.face_midpoints[1][2] == 0.5f); + + assert(cell.face_areas[2] == 9.0f); + assert(cell.face_midpoints[2][0] == 0.5f); + assert(cell.face_midpoints[2][1] == 0.5f); + assert(cell.face_midpoints[2][2] == -1.0f); + + assert(cell.face_areas[3] == 9.0f); + assert(cell.face_midpoints[3][0] == 0.5f); + assert(cell.face_midpoints[3][1] == 0.5f); + assert(cell.face_midpoints[3][2] == 2.0f); + + assert(cell.face_areas[4] == 9.0f); + assert(cell.face_midpoints[4][0] == 0.5f); + assert(cell.face_midpoints[4][1] == 2.0f); + assert(cell.face_midpoints[4][2] == 0.5f); + + assert(cell.face_areas[5] == 9.0f); + assert(cell.face_midpoints[5][0] == 2.0f); + assert(cell.face_midpoints[5][1] == 0.5f); + assert(cell.face_midpoints[5][2] == 0.5f); } int main() { @@ -116,14 +158,22 @@ int main() { error("Wrong centroid: %g %g %g!", cell.centroid[0], cell.centroid[1], cell.centroid[2]); } - /* Check neighbour order */ - // TODO - - /* Check face method */ - float A[3]; - float midpoint[3]; - voronoi_get_face(&cell, 1, A, midpoint); - // TODO + + /* Check faces. */ + float A, midpoint[3]; + A = voronoi_get_face(&cell, 1, midpoint); + if (A) { + if (A != 0.25f) { + error("Wrong surface area: %g!", A); + } + if (fabs(midpoint[0] - 0.25f) > 1.e-5 || fabs(midpoint[1] - 0.5f) > 1.e-5 || + fabs(midpoint[2] - 0.5f) > 1.e-5) { + error("Wrong face midpoint: %g %g %g!", midpoint[0], midpoint[1], + midpoint[2]); + } + } else { + error("Neighbour not found!"); + } return 0; }