/******************************************************************************* * This file is part of SWIFT. * Copyright (C) 2017 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 . * ******************************************************************************/ /* Some standard headers. */ #include // MATTHIEU fix this test #if 1 || !defined(HAVE_FFTW) int main(int argc, char *argv[]) { return 0; } #else /* Some standard headers. */ #include #include #include /* Includes. */ #include "runner_doiact_fft.h" #include "swift.h" __attribute__((always_inline)) INLINE static int row_major_id(int i, int j, int k, int N) { return (((i + N) % N) * N * N + ((j + N) % N) * N + ((k + N) % N)); } int is_close(double x, double y, double abs_err) { return (abs(x - y) < abs_err); } int main(int argc, char *argv[]) { /* Initialize CPU frequency, this also starts time. */ unsigned long long cpufreq = 0; clocks_set_cpufreq(cpufreq); /* Choke on FP-exceptions */ #ifdef HAVE_FE_ENABLE_EXCEPT feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW); #endif /* Make one particle */ int nr_gparts = 1; struct gpart *gparts = NULL; if (posix_memalign((void **)&gparts, gpart_align, nr_gparts * sizeof(struct gpart)) != 0) error("Impossible to allocate memory for gparts."); bzero(gparts, nr_gparts * sizeof(struct gpart)); gparts[0].x[0] = 0.3; gparts[0].x[1] = 0.8; gparts[0].x[2] = 0.2; gparts[0].mass = 1.f; /* Read the parameter file */ struct swift_params *params = (struct swift_params *)malloc(sizeof(struct swift_params)); parser_read_file("fft_params.yml", params); struct cosmology cosmo; cosmology_init_no_cosmo(&cosmo); /* Initialise the gravity properties */ struct gravity_props gravity_properties; gravity_props_init(&gravity_properties, params, &cosmo); /* Build the infrastructure */ struct space space; double dim[3] = {1., 1., 1.}; space_init(&space, params, &cosmo, dim, NULL, gparts, NULL, 0, nr_gparts, 0, 1, 1, 0, 0, 1, 1, 0); struct engine engine; engine.s = &space; space.e = &engine; engine.time = 0.1f; engine.ti_current = 0; engine.ti_old = 0; engine.max_active_bin = num_time_bins; engine.gravity_properties = &gravity_properties; engine.nr_threads = 1; engine.nodeID = 0; engine_rank = 0; engine.verbose = 1; struct runner runner; runner.e = &engine; /* Initialize the threadpool. */ threadpool_init(&engine.threadpool, engine.nr_threads); /* Construct the space and all the multipoles. */ space_rebuild(&space, 1); /* Initialise the Ewald correction table */ #ifdef SWIFT_GRAVITY_FORCE_CHECKS gravity_exact_force_ewald_init(dim[0]); #endif /* Run the FFT task */ runner_do_grav_fft(&runner, 1); /* Now check that we got the right answer */ int nr_cells = space.nr_cells; double *r = (double *)malloc(nr_cells * sizeof(double)); double *m = (double *)malloc(nr_cells * sizeof(double)); double *pot = (double *)malloc(nr_cells * sizeof(double)); double *pot_exact = (double *)malloc(nr_cells * sizeof(double)); FILE *file = fopen("potential.dat", "w"); for (int i = 0; i < nr_cells; ++i) { pot[i] = space.multipoles_top[i].pot.F_000; m[i] = space.multipoles_top[i].m_pole.M_000; double dx = nearest(space.multipoles_top[i].CoM[0] - gparts[0].x[0], dim[0]); double dy = nearest(space.multipoles_top[i].CoM[1] - gparts[0].x[1], dim[1]); double dz = nearest(space.multipoles_top[i].CoM[2] - gparts[0].x[2], dim[2]); /* Distance */ r[i] = sqrt(dx * dx + dy * dy + dz * dz); /* Potential with correction */ if (r[i] > 0) pot_exact[i] = 1. / r[i]; #ifdef SWIFT_GRAVITY_FORCE_CHECKS /* Get Ewald periodic correction */ double f_corr[3], pot_corr; gravity_exact_force_ewald_evaluate(dx, dy, dz, f_corr, &pot_corr); pot_exact[i] -= pot_corr; #endif fprintf(file, "%e %e %e %e\n", r[i], m[i], pot[i], pot_exact[i]); } fclose(file); /* Let's now check the interpolation functions */ int cdim[3] = {space.cdim[0], space.cdim[1], space.cdim[2]}; /* Constant function --> Derivatives must be 0 */ for (int i = 0; i < cdim[0]; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 0; k < cdim[2]; ++k) { pot[row_major_id(i, j, k, cdim[0])] = 1.; } } } for (int i = 0; i < nr_cells; ++i) gravity_field_tensors_init(&space.multipoles_top[i].pot, engine.ti_current); for (int i = 0; i < nr_cells; ++i) mesh_to_multipole_CIC(&space.multipoles_top[i], pot, cdim[0], cdim[0], dim); for (int i = 0; i < cdim[0]; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 0; k < cdim[2]; ++k) { const struct grav_tensor *f = &space.multipoles_top[row_major_id(i, j, k, cdim[0])].pot; if (!is_close(f->F_000, -1., 1e-10)) error("Invalid value for (%d %d %d) F_000 (%e)", i, j, k, f->F_000); if (!is_close(f->F_100, 0., 1e-10)) error("Invalid value for (%d %d %d) F_100 (%e)", i, j, k, f->F_100); if (!is_close(f->F_010, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_010 (%e)", i, j, k, f->F_010); if (!is_close(f->F_001, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_001 (%e)", i, j, k, f->F_001); if (!is_close(f->F_200, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_200 (%e)", i, j, k, f->F_200); if (!is_close(f->F_020, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_020 (%e)", i, j, k, f->F_020); if (!is_close(f->F_002, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_002 (%e)", i, j, k, f->F_002); if (!is_close(f->F_011, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_011 (%e)", i, j, k, f->F_011); if (!is_close(f->F_101, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_101 (%e)", i, j, k, f->F_101); if (!is_close(f->F_110, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_110 (%e)", i, j, k, f->F_110); } } } /* Linear function in x --> Derivatives must be 1 */ for (int i = 0; i < cdim[0]; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 0; k < cdim[2]; ++k) { pot[row_major_id(i, j, k, cdim[0])] = i / ((double)cdim[0]); } } } for (int i = 0; i < nr_cells; ++i) gravity_field_tensors_init(&space.multipoles_top[i].pot, engine.ti_current); for (int i = 0; i < nr_cells; ++i) mesh_to_multipole_CIC(&space.multipoles_top[i], pot, cdim[0], cdim[0], dim); for (int i = 2; i < cdim[0] - 3; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 0; k < cdim[2]; ++k) { const struct grav_tensor *f = &space.multipoles_top[row_major_id(i, j, k, cdim[0])].pot; if (!is_close(f->F_000, -i / ((double)cdim[0]), 1e-10)) error("Invalid value for (%d %d %d) F_000 (%e)", i, j, k, f->F_000); if (!is_close(f->F_100, -1., 1e-10)) error("Invalid value for (%d %d %d) F_100 (%e)", i, j, k, f->F_100); if (!is_close(f->F_010, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_010 (%e)", i, j, k, f->F_010); if (!is_close(f->F_001, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_001 (%e)", i, j, k, f->F_001); if (!is_close(f->F_200, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_200 (%e)", i, j, k, f->F_200); if (!is_close(f->F_020, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_020 (%e)", i, j, k, f->F_020); if (!is_close(f->F_002, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_002 (%e)", i, j, k, f->F_002); if (!is_close(f->F_011, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_011 (%e)", i, j, k, f->F_011); if (!is_close(f->F_101, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_101 (%e)", i, j, k, f->F_101); if (!is_close(f->F_110, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_110 (%e)", i, j, k, f->F_110); } } } /* Linear function in y --> Derivatives must be 1 */ for (int i = 0; i < cdim[0]; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 0; k < cdim[2]; ++k) { pot[row_major_id(i, j, k, cdim[0])] = j / ((double)cdim[0]); } } } for (int i = 0; i < nr_cells; ++i) gravity_field_tensors_init(&space.multipoles_top[i].pot, engine.ti_current); for (int i = 0; i < nr_cells; ++i) mesh_to_multipole_CIC(&space.multipoles_top[i], pot, cdim[0], cdim[0], dim); for (int i = 0; i < cdim[0]; ++i) { for (int j = 2; j < cdim[1] - 3; ++j) { for (int k = 0; k < cdim[2]; ++k) { const struct grav_tensor *f = &space.multipoles_top[row_major_id(i, j, k, cdim[0])].pot; if (!is_close(f->F_000, -j / ((double)cdim[0]), 1e-10)) error("Invalid value for (%d %d %d) F_000 (%e)", i, j, k, f->F_000); if (!is_close(f->F_100, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_100 (%e)", i, j, k, f->F_100); if (!is_close(f->F_010, -1., 1e-10)) error("Invalid value for (%d %d %d) F_010 (%e)", i, j, k, f->F_010); if (!is_close(f->F_001, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_001 (%e)", i, j, k, f->F_001); if (!is_close(f->F_200, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_200 (%e)", i, j, k, f->F_200); if (!is_close(f->F_020, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_020 (%e)", i, j, k, f->F_020); if (!is_close(f->F_002, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_002 (%e)", i, j, k, f->F_002); if (!is_close(f->F_011, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_011 (%e)", i, j, k, f->F_011); if (!is_close(f->F_101, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_101 (%e)", i, j, k, f->F_101); if (!is_close(f->F_110, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_110 (%e)", i, j, k, f->F_110); } } } /* Linear function in z --> Derivatives must be 1 */ for (int i = 0; i < cdim[0]; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 0; k < cdim[2]; ++k) { pot[row_major_id(i, j, k, cdim[0])] = k / ((double)cdim[0]); } } } for (int i = 0; i < nr_cells; ++i) gravity_field_tensors_init(&space.multipoles_top[i].pot, engine.ti_current); for (int i = 0; i < nr_cells; ++i) mesh_to_multipole_CIC(&space.multipoles_top[i], pot, cdim[0], cdim[0], dim); for (int i = 0; i < cdim[0]; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 2; k < cdim[2] - 3; ++k) { const struct grav_tensor *f = &space.multipoles_top[row_major_id(i, j, k, cdim[0])].pot; if (!is_close(f->F_000, -k / ((double)cdim[0]), 1e-10)) error("Invalid value for (%d %d %d) F_000 (%e)", i, j, k, f->F_000); if (!is_close(f->F_100, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_100 (%e)", i, j, k, f->F_100); if (!is_close(f->F_010, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_010 (%e)", i, j, k, f->F_010); if (!is_close(f->F_001, -1., 1e-10)) error("Invalid value for (%d %d %d) F_001 (%e)", i, j, k, f->F_001); if (!is_close(f->F_200, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_200 (%e)", i, j, k, f->F_200); if (!is_close(f->F_020, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_020 (%e)", i, j, k, f->F_020); if (!is_close(f->F_002, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_002 (%e)", i, j, k, f->F_002); if (!is_close(f->F_011, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_011 (%e)", i, j, k, f->F_011); if (!is_close(f->F_101, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_101 (%e)", i, j, k, f->F_101); if (!is_close(f->F_110, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_110 (%e)", i, j, k, f->F_110); } } } /* Quadratic function in x --> Derivatives must be 2 */ for (int i = 0; i < cdim[0]; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 0; k < cdim[2]; ++k) { pot[row_major_id(i, j, k, cdim[0])] = i * i / ((double)cdim[0] * cdim[0]); } } } for (int i = 0; i < nr_cells; ++i) gravity_field_tensors_init(&space.multipoles_top[i].pot, engine.ti_current); for (int i = 0; i < nr_cells; ++i) mesh_to_multipole_CIC(&space.multipoles_top[i], pot, cdim[0], cdim[0], dim); for (int i = 2; i < cdim[0] - 3; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 0; k < cdim[2]; ++k) { const struct grav_tensor *f = &space.multipoles_top[row_major_id(i, j, k, cdim[0])].pot; const double val = i / ((double)cdim[0]); const double val2 = val * val; if (!is_close(f->F_000, -val2, 1e-10)) error("Invalid value for (%d %d %d) F_000 (%e)", i, j, k, f->F_000); if (!is_close(f->F_100, -2 * val, 1e-10)) error("Invalid value for (%d %d %d) F_100 (%e)", i, j, k, f->F_100); if (!is_close(f->F_010, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_010 (%e)", i, j, k, f->F_010); if (!is_close(f->F_001, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_001 (%e)", i, j, k, f->F_001); if (!is_close(f->F_200, 2.f, 1e-10)) error("Invalid value for (%d %d %d) F_200 (%e)", i, j, k, f->F_200); if (!is_close(f->F_020, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_020 (%e)", i, j, k, f->F_020); if (!is_close(f->F_002, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_002 (%e)", i, j, k, f->F_002); if (!is_close(f->F_011, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_011 (%e)", i, j, k, f->F_011); if (!is_close(f->F_101, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_101 (%e)", i, j, k, f->F_101); if (!is_close(f->F_110, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_110 (%e)", i, j, k, f->F_110); } } } /* Quadratic function in y --> Derivatives must be 2 */ for (int i = 0; i < cdim[0]; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 0; k < cdim[2]; ++k) { pot[row_major_id(i, j, k, cdim[0])] = j * j / ((double)cdim[0] * cdim[0]); } } } for (int i = 0; i < nr_cells; ++i) gravity_field_tensors_init(&space.multipoles_top[i].pot, engine.ti_current); for (int i = 0; i < nr_cells; ++i) mesh_to_multipole_CIC(&space.multipoles_top[i], pot, cdim[0], cdim[0], dim); for (int i = 0; i < cdim[0]; ++i) { for (int j = 2; j < cdim[1] - 3; ++j) { for (int k = 0; k < cdim[2]; ++k) { const struct grav_tensor *f = &space.multipoles_top[row_major_id(i, j, k, cdim[0])].pot; const double val = j / ((double)cdim[0]); const double val2 = val * val; if (!is_close(f->F_000, -val2, 1e-10)) error("Invalid value for (%d %d %d) F_000 (%e)", i, j, k, f->F_000); if (!is_close(f->F_100, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_100 (%e)", i, j, k, f->F_100); if (!is_close(f->F_010, -2 * val, 1e-10)) error("Invalid value for (%d %d %d) F_010 (%e)", i, j, k, f->F_010); if (!is_close(f->F_001, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_001 (%e)", i, j, k, f->F_001); if (!is_close(f->F_200, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_200 (%e)", i, j, k, f->F_200); if (!is_close(f->F_020, 2.f, 1e-10)) error("Invalid value for (%d %d %d) F_020 (%e)", i, j, k, f->F_020); if (!is_close(f->F_002, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_002 (%e)", i, j, k, f->F_002); if (!is_close(f->F_011, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_011 (%e)", i, j, k, f->F_011); if (!is_close(f->F_101, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_101 (%e)", i, j, k, f->F_101); if (!is_close(f->F_110, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_110 (%e)", i, j, k, f->F_110); } } } /* Quadratic function in z --> Derivatives must be 2 */ for (int i = 0; i < cdim[0]; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 0; k < cdim[2]; ++k) { pot[row_major_id(i, j, k, cdim[0])] = k * k / ((double)cdim[0] * cdim[0]); } } } for (int i = 0; i < nr_cells; ++i) gravity_field_tensors_init(&space.multipoles_top[i].pot, engine.ti_current); for (int i = 0; i < nr_cells; ++i) mesh_to_multipole_CIC(&space.multipoles_top[i], pot, cdim[0], cdim[0], dim); for (int i = 0; i < cdim[0]; ++i) { for (int j = 0; j < cdim[1]; ++j) { for (int k = 2; k < cdim[2] - 3; ++k) { const struct grav_tensor *f = &space.multipoles_top[row_major_id(i, j, k, cdim[0])].pot; const double val = k / ((double)cdim[0]); const double val2 = val * val; if (!is_close(f->F_000, -val2, 1e-10)) error("Invalid value for (%d %d %d) F_000 (%e)", i, j, k, f->F_000); if (!is_close(f->F_100, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_100 (%e)", i, j, k, f->F_100); if (!is_close(f->F_010, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_010 (%e)", i, j, k, f->F_010); if (!is_close(f->F_001, -2 * val, 1e-10)) error("Invalid value for (%d %d %d) F_001 (%e)", i, j, k, f->F_001); if (!is_close(f->F_200, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_200 (%e)", i, j, k, f->F_200); if (!is_close(f->F_020, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_020 (%e)", i, j, k, f->F_020); if (!is_close(f->F_002, 2.f, 1e-10)) error("Invalid value for (%d %d %d) F_002 (%e)", i, j, k, f->F_002); if (!is_close(f->F_011, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_011 (%e)", i, j, k, f->F_011); if (!is_close(f->F_101, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_101 (%e)", i, j, k, f->F_101); if (!is_close(f->F_110, 0.f, 1e-10)) error("Invalid value for (%d %d %d) F_110 (%e)", i, j, k, f->F_110); } } } /* Clean up */ free(r); free(m); free(pot); free(pot_exact); free(params); free(gparts); return 0; } #endif