diff --git a/.gitignore b/.gitignore index eda8362a8ef05892b2d01eca81b972010da069a6..0259c3bb057d5193fb1a73a916e8410c35b34a5d 100644 --- a/.gitignore +++ b/.gitignore @@ -179,6 +179,7 @@ tests/testHashmap tests/testNeutrinoCosmology tests/testNeutrinoFermiDirac tests/testLog +tests/testTimeline tests/*.png tests/*.txt @@ -378,4 +379,4 @@ sympy-plots-for-*.tex/ black_formatting_env # vscode -*.json \ No newline at end of file +*.json diff --git a/src/timeline.h b/src/timeline.h index b035280d4cc729e70d6e26501b51945650d5ea7c..d3fd9d2e44ac536b06fdc44155134a3758db81ab 100644 --- a/src/timeline.h +++ b/src/timeline.h @@ -56,7 +56,7 @@ typedef int8_t timebin_t; * @param bin The time bin of interest. */ __attribute__((const)) static INLINE integertime_t -get_integer_timestep(timebin_t bin) { +get_integer_timestep(const timebin_t bin) { if (bin <= 0) return 0; return 1LL << (bin + 1); @@ -71,9 +71,11 @@ get_integer_timestep(timebin_t bin) { * We use a fast (but exact for any non-zero value) logarithm in base 2 * calculation based on the bit representation of the number: * log_2(x) = (number of bits in the type) - (number of leading 0-bits in x) - 1 + * + * @param time_step An integer time-step length. */ __attribute__((const)) static INLINE timebin_t -get_time_bin(integertime_t time_step) { +get_time_bin(const integertime_t time_step) { /* ((int) log_2(time_step)) - 1 */ return (timebin_t)((8 * sizeof(integertime_t) - 2) - @@ -86,8 +88,8 @@ get_time_bin(integertime_t time_step) { * @param bin The time bin of interest. * @param time_base the minimal time-step size of the simulation. */ -__attribute__((const)) static INLINE double get_timestep(timebin_t bin, - double time_base) { +__attribute__((const)) static INLINE double get_timestep( + const timebin_t bin, const double time_base) { return get_integer_timestep(bin) * time_base; } @@ -95,12 +97,14 @@ __attribute__((const)) static INLINE double get_timestep(timebin_t bin, /** * @brief Returns the integer time corresponding to the start of the time-step * given by a time-bin. + * If the current time is a possible beginning for the given time-bin, return + * the current time minus the time-step size. * * @param ti_current The current time on the integer time line. * @param bin The time bin of interest. */ __attribute__((const)) static INLINE integertime_t -get_integer_time_begin(integertime_t ti_current, timebin_t bin) { +get_integer_time_begin(const integertime_t ti_current, const timebin_t bin) { const integertime_t dti = get_integer_timestep(bin); if (dti == 0) @@ -110,20 +114,27 @@ get_integer_time_begin(integertime_t ti_current, timebin_t bin) { } /** - * @brief Returns the integer time corresponding to the start of the time-step + * @brief Returns the integer time corresponding to the end of the time-step * given by a time-bin. + * If the current time is a possible end for the given time-bin, return the + * current time. * * @param ti_current The current time on the integer time line. * @param bin The time bin of interest. */ __attribute__((const)) static INLINE integertime_t -get_integer_time_end(integertime_t ti_current, timebin_t bin) { +get_integer_time_end(const integertime_t ti_current, const timebin_t bin) { const integertime_t dti = get_integer_timestep(bin); if (dti == 0) return 0; - else - return dti * ceil((double)ti_current / (double)dti); + else { + const integertime_t mod = ti_current % dti; + if (mod == 0) + return ti_current; + else + return ti_current - mod + dti; + } } /** @@ -132,7 +143,7 @@ get_integer_time_end(integertime_t ti_current, timebin_t bin) { * @param time The current point on the time line. */ __attribute__((const)) static INLINE timebin_t -get_max_active_bin(integertime_t time) { +get_max_active_bin(const integertime_t time) { if (time == 0) return num_time_bins; @@ -149,7 +160,7 @@ get_max_active_bin(integertime_t time) { * @param ti_old The last synchronisation point on the time line. */ __attribute__((const)) static INLINE timebin_t -get_min_active_bin(integertime_t ti_current, integertime_t ti_old) { +get_min_active_bin(const integertime_t ti_current, const integertime_t ti_old) { const timebin_t min_bin = get_max_active_bin(ti_current - ti_old); return min_bin; diff --git a/src/tools.c b/src/tools.c index d066d81dfeabd60914081e2519e90bf39c347303..875043bcbc7d0f97a347d1ec0fae7398162daebb 100644 --- a/src/tools.c +++ b/src/tools.c @@ -793,7 +793,9 @@ void engine_single_force(double *dim, long long int pid, } /** - * Returns a random number (uniformly distributed) in [a,b[ + * Returns a random number (uniformly distributed) in [a,b) + * + * This function is *not* thread-safe. */ double random_uniform(double a, double b) { return (rand() / (double)RAND_MAX) * (b - a) + a; diff --git a/tests/Makefile.am b/tests/Makefile.am index ee7a4cac028436da717b4928114661f3e2565e37..663defb9c368bff4615f7535842be44fadd12353 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -35,7 +35,7 @@ TESTS = testGreetings testMaths testReading.sh testKernel testKernelLongGrav \ testCbrt testCosmology testOutputList testFormat.sh \ test27cellsStars.sh test27cellsStarsPerturbed.sh testHydroMPIrules \ testAtomic testGravitySpeed testNeutrinoCosmology.sh testNeutrinoFermiDirac \ - testLog testDistance + testLog testDistance testTimeline # List of test programs to compile check_PROGRAMS = testGreetings testReading testTimeIntegration testKernelLongGrav \ @@ -49,7 +49,7 @@ check_PROGRAMS = testGreetings testReading testTimeIntegration testKernelLongGra testSelectOutput testCbrt testCosmology testOutputList test27cellsStars \ test27cellsStars_subset testCooling testComovingCooling testFeedback testHashmap \ testAtomic testHydroMPIrules testGravitySpeed testNeutrinoCosmology \ - testNeutrinoFermiDirac testLog + testNeutrinoFermiDirac testLog testTimeline # Rebuild tests when SWIFT is updated. $(check_PROGRAMS): ../src/.libs/libswiftsim.a @@ -162,6 +162,8 @@ testHashmap_SOURCES = testHashmap.c testLog_SOURCES = testLog.c +testTimeline_SOURCES = testTimeline.c + testHydroMPIrules = testHydroMPIrules.c # Files necessary for distribution diff --git a/tests/testTimeline.c b/tests/testTimeline.c new file mode 100644 index 0000000000000000000000000000000000000000..921f08b03c31bfba6a21ce597dbf04f74ceaa2b8 --- /dev/null +++ b/tests/testTimeline.c @@ -0,0 +1,551 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (C) 2022 Mladen Ivkovic (mladen.ivkovic@hotmail.com) + * + * 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/>. + * + ******************************************************************************/ +#include "../config.h" +#include "timeline.h" +#include "tools.h" + +/* How many times to repeat randomly drawn tests. */ +#define NREPEAT 1048576 + +/** + * @brief test get_integer_time_end() function. + * For each particle time bin, pick a random valid time_end for + * the dt given by the particle bin; then set a random ti_current + * by subtracting some time interval < dt from the expected time_end + * and see whether the recovered time_end matches up. + * + * @param bin_min lowest bin to start test from + * @param bin_max highest bin to run test with + * @param max_nr_timesteps_test maximal number of timesteps for a sim + */ +void test_get_integer_time_end(timebin_t bin_min, timebin_t bin_max, + integertime_t max_nr_timesteps_test) { + + integertime_t dti, step, max_step, set_time_end, ti_current, displacement; + integertime_t time_end_recovered; + + for (timebin_t bin = bin_min; bin < bin_max; bin++) { + + dti = get_integer_timestep(bin); + + /* Check random state in timeline */ + /* ------------------------------ */ + + for (int r = 0; r < NREPEAT; r++) { + /* First pick a place to set this time_end on the timeline. */ + + /* we can't have more than this many steps of this size */ + max_step = max_nr_timesteps_test / dti; + if (max_step == 0) + error("max step == 0? bin %d max_nr_steps %lld", bin, + max_nr_timesteps_test); + + /* Set the time_end at any step in between there */ + step = (integertime_t)(random_uniform(1., max_step)); + set_time_end = step * dti; + + /* Do some safety checks */ + if (set_time_end % dti != 0) error("time_end not divisible by dti?"); + if (set_time_end > max_nr_timesteps_test) + error("Time end > max_nr_timesteps?"); + if (set_time_end < (integertime_t)0) error("Time end < 0?"); + + /* Now mimick a "current time" by removing a fraction of dti from + * the step, and see whether we recover the correct time_end */ + displacement = (integertime_t)(random_uniform(0., 1. - 1e-12) * dti); + ti_current = set_time_end - displacement; + + /* Another round of safety checks */ + if (ti_current > set_time_end) + error( + "current>time_end? current=%lld time_end=%lld dti=%lld " + "displacement=%lld bin=%d\n", + ti_current, set_time_end, dti, displacement, bin); + if (ti_current < 0) + error( + "current<0? current=%lld time_end=%lld dti=%lld " + "displacement=%lld bin=%d\n", + ti_current, set_time_end, dti, displacement, bin); + + /* Now the actual check. */ + time_end_recovered = get_integer_time_end(ti_current, bin); + + if (time_end_recovered != set_time_end) { + error( + "time_end incorrect: expect=%lld got=%lld diff=%lld; current=%lld " + "displacement=%lld, dti=%lld, bin=%d", + set_time_end, time_end_recovered, set_time_end - time_end_recovered, + ti_current, displacement, dti, bin); + } + } + + /* Check time_end = 0 */ + /* ------------------ */ + set_time_end = 0; + ti_current = 0; + time_end_recovered = get_integer_time_end(ti_current, bin); + if (time_end_recovered != set_time_end) { + error( + "time_end incorrect: expect=%lld got=%lld diff=%lld; current=%lld " + "bin=%d", + set_time_end, time_end_recovered, set_time_end - time_end_recovered, + ti_current, bin); + } + + /* Check time_end = final_step */ + /* --------------------------- */ + set_time_end = max_nr_timesteps_test; + + if (dti < NREPEAT) { + /* Check all possible time states before the end */ + for (integertime_t delta = 1; delta < dti; delta++) { + ti_current = max_nr_timesteps_test - delta; + time_end_recovered = get_integer_time_end(ti_current, bin); + if (time_end_recovered != set_time_end) { + error( + "time_end incorrect: expect=%lld got=%lld diff=%lld; " + "current=%lld bin=%d", + set_time_end, time_end_recovered, + set_time_end - time_end_recovered, ti_current, bin); + } + } + } else { + /* Draw random states again */ + for (int r = 0; r < NREPEAT; r++) { + /* Do some safety checks */ + if (set_time_end % dti != 0) error("time_end not divisible by dti?"); + + /* Now mimick a "current time" by removing a fraction of dti from + * the step, and see whether we recover the correct time_end */ + displacement = (integertime_t)(random_uniform(0., 1. - 1e-12) * dti); + ti_current = set_time_end - displacement; + + /* Another round of safety checks */ + if (ti_current > set_time_end) + error( + "current>time_end? current=%lld time_end=%lld dti=%lld " + "displacement=%lld bin=%d\n", + ti_current, set_time_end, dti, displacement, bin); + if (ti_current < 0) + error( + "current<0? current=%lld time_end=%lld dti=%lld " + "displacement=%lld bin=%d\n", + ti_current, set_time_end, dti, displacement, bin); + + /* Now the actual check. */ + time_end_recovered = get_integer_time_end(ti_current, bin); + + if (time_end_recovered != set_time_end) { + error( + "time_end incorrect: expect=%lld got=%lld diff=%lld; " + "current=%lld " + "displacement=%lld, dti=%lld, bin=%d", + set_time_end, time_end_recovered, + set_time_end - time_end_recovered, ti_current, displacement, dti, + bin); + } + } + } + } + + printf("Passed %s\n", __func__); +} + +/** + * @brief test get_time_bin by converting all possible bins + * into timesteps and trying to recover the initial bin + * by calling get_time_bin() + * @param bin_min lowest bin to start test from + * @param bin_max highest bin to run test with + * + **/ +void test_get_time_bin(timebin_t bin_min, timebin_t bin_max) { + + for (timebin_t bin = bin_min; bin < bin_max; bin++) { + integertime_t dti = get_integer_timestep(bin); + timebin_t bin_recovered = get_time_bin(dti); + if (bin != bin_recovered) { + error("Expected bin=%d, got=%d", bin, bin_recovered); + } + } + + printf("Passed %s\n", __func__); +} + +/** + * @brief test get_integer_time_begin() function. + * For each particle time bin, pick a random valid time_begin for + * the dt given by the particle bin; then set a random ti_current + * by adding some time interval < dt to the expected time_begin + * and see whether the recovered time_begin matches up. + * + * @param bin_min lowest bin to start test from + * @param bin_max highest bin to run test with + * @param max_nr_timesteps_test maximal number of timesteps for a sim + */ +void test_get_integer_time_begin(timebin_t bin_min, timebin_t bin_max, + integertime_t max_nr_timesteps_test) { + + integertime_t dti, step, max_step, set_time_begin, ti_current, displacement; + integertime_t time_begin_recovered; + + for (timebin_t bin = bin_min; bin < bin_max; bin++) { + + dti = get_integer_timestep(bin); + + /* Check random state in timeline */ + /* ------------------------------ */ + + for (int r = 0; r < NREPEAT; r++) { + /* First pick a place to set this time_end on the timeline. */ + + /* we can't have more than this many steps of this size */ + max_step = max_nr_timesteps_test / dti; + if (max_step == 0) + error("max step == 0? bin %d max_nr_steps %lld", bin, + max_nr_timesteps_test); + + /* Set the time_end at any step in between there */ + step = (integertime_t)(random_uniform(0., max_step)); + set_time_begin = step * dti; + + /* Do some safety checks */ + if (set_time_begin % dti != 0) + error("set time_begin not divisible by dti?"); + if (set_time_begin >= max_nr_timesteps_test) + error("Time begin %lld >= max_nr_timesteps %lld?", set_time_begin, + max_nr_timesteps); + if (set_time_begin < (integertime_t)0) error("Time begin < 0?"); + + /* Now mimick a "current time" by removing a fraction of dti from + * the step, and see whether we recover the correct time_end */ + displacement = (integertime_t)(random_uniform(0., 1.) * dti); + ti_current = set_time_begin + displacement; + + /* Another round of safety checks */ + if (ti_current < set_time_begin) + printf( + "current<time_begin? current=%lld time_end=%lld dti=%lld " + "displacement=%lld bin=%d\n", + ti_current, set_time_begin, dti, displacement, bin); + + /* Now the actual check. */ + time_begin_recovered = get_integer_time_begin(ti_current, bin); + + if (ti_current == set_time_begin) { + /* If the displacement was zero, then the function shall return + * the beginning of the timestep that ends at ti_current */ + if (time_begin_recovered + dti != set_time_begin) + error( + "time_begin incorrect: expect=%lld got=%lld diff=%lld; " + "current=%lld " + "displacement=%lld, dti=%lld", + /*expect=*/set_time_begin - dti, + /*got=*/time_begin_recovered, + /*diff=*/set_time_begin - dti - time_begin_recovered, ti_current, + displacement, dti); + } else { + if (time_begin_recovered != set_time_begin) + error( + "time_begin incorrect: expect=%lld got=%lld diff=%lld; " + "current=%lld displacement=%lld, dti=%lld", + set_time_begin, time_begin_recovered, + set_time_begin - time_begin_recovered, ti_current, displacement, + dti); + } + } + + /* Check time_begin = 0 */ + /* ------------------ */ + set_time_begin = 0; + ti_current = 0; + time_begin_recovered = get_integer_time_begin(ti_current, bin); + if (time_begin_recovered != set_time_begin) + error( + "time_begin incorrect: expect=%lld got=%lld diff=%lld; " + "current=%lld dti=%lld", + set_time_begin, time_begin_recovered, + set_time_begin - time_begin_recovered, ti_current, dti); + + /* Check time_begin = final_step */ + /* ----------------------------- */ + /* This is a tad nonsensial since in this scenario, we're + * at an integer time > max_nr_timesteps */ + set_time_begin = max_nr_timesteps_test; + + if (dti < NREPEAT) { + /* Check all possible time states before the end */ + for (integertime_t delta = 1; delta < dti; delta++) { + ti_current = max_nr_timesteps_test + delta; + time_begin_recovered = get_integer_time_begin(ti_current, bin); + if (time_begin_recovered != set_time_begin) + error( + "time_begin incorrect: expect=%lld got=%lld diff=%lld; " + "current=%lld displacement=%lld, dti=%lld", + set_time_begin, time_begin_recovered, + set_time_begin - time_begin_recovered, ti_current, displacement, + dti); + } + } else { + /* Draw random states again */ + for (int r = 0; r < NREPEAT; r++) { + + /* Now mimick a "current time" by removing a fraction of dti from + * the step, and see whether we recover the correct time_end */ + displacement = (integertime_t)(random_uniform(0., 1.) * dti); + ti_current = set_time_begin + displacement; + + /* Another round of safety checks */ + if (ti_current < set_time_begin) + error( + "current>time_begin? current=%lld time_begin=%lld dti=%lld " + "displacement=%lld bin=%d\n", + ti_current, set_time_begin, dti, displacement, bin); + if (ti_current < 0) + error( + "current<0? current=%lld time_begin=%lld dti=%lld " + "displacement=%lld bin=%d\n", + ti_current, set_time_begin, dti, displacement, bin); + + /* Now the actual check. */ + time_begin_recovered = get_integer_time_begin(ti_current, bin); + + if (ti_current == set_time_begin) { + /* If the displacement was zero, then the function shall return + * the beginning of the timestep that ends at ti_current */ + if (time_begin_recovered + dti != set_time_begin) + error( + "time_begin incorrect: expect=%lld got=%lld diff=%lld; " + "current=%lld " + "displacement=%lld, dti=%lld", + /*expect=*/set_time_begin - dti, + /*got=*/time_begin_recovered, + /*diff=*/set_time_begin - dti - time_begin_recovered, + ti_current, displacement, dti); + } else { + if (time_begin_recovered != set_time_begin) + error( + "time_begin incorrect: expect=%lld got=%lld diff=%lld; " + "current=%lld displacement=%lld, dti=%lld", + set_time_begin, time_begin_recovered, + set_time_begin - time_begin_recovered, ti_current, displacement, + dti); + } + } + } + } + + printf("Passed %s\n", __func__); +} + +/** + * @brief test get_max_active_bin by randomly choosing current times + * and manually checking whether a higher bin could be active + * + * @param bin_max highest bin to run test with + * @param max_nr_timesteps_test maximal number of timesteps for a sim + **/ +void test_get_max_active_bin(timebin_t bin_max, + integertime_t max_nr_timesteps_test) { + + integertime_t ti_current, dti; + timebin_t max_active_bin, testbin; + + /* Test random ti_currents */ + /* ----------------------- */ + for (int r = 0; r < NREPEAT; r++) { + /* test time 0 later, so use time >= 1 */ + ti_current = (integertime_t)(random_uniform(1., max_nr_timesteps_test)); + + max_active_bin = get_max_active_bin(ti_current); + testbin = 0; + dti = get_integer_timestep(max_active_bin); + for (timebin_t bin = max_active_bin; bin < bin_max && dti <= ti_current; + bin++) { + if (ti_current % dti == 0) testbin = bin; + /* update dti here for exit condition */ + dti = get_integer_timestep(bin + 1); + } + if (testbin > max_active_bin) + error("Found higher active bin: time=%lld max_active_bin=%d found=%d", + ti_current, max_active_bin, testbin); + } + + /* Test first 2^bin_max integertimes */ + /* --------------------------------- */ + for (timebin_t bin = 1; bin < bin_max; bin++) { + ti_current = get_integer_timestep(bin); + max_active_bin = get_max_active_bin(ti_current); + + if (max_active_bin != bin) + error("Got wrong max_active_bin: Expect=%d got=%d time=%lld", bin, + max_active_bin, ti_current); + } + + /* Test final 2^bin_max integertimes */ + /* --------------------------------- */ + for (timebin_t bin = 1; bin < bin_max; bin++) { + dti = get_integer_timestep(bin); + ti_current = max_nr_timesteps_test - dti; + if (ti_current == 0) + error("Testing bin which only fits in once into entire timeline"); + max_active_bin = get_max_active_bin(ti_current); + + if (max_active_bin != bin) { + error("Got wrong max_active_bin: Expect=%d got=%d time=%lld", bin, + max_active_bin, ti_current); + } + } + + /* Make sure everything is active at time zero */ + /* ------------------------------------------- */ + max_active_bin = get_max_active_bin(0); + /* Note: this should be num_time_bins, not bin_max! */ + if (max_active_bin != num_time_bins) + error("Didn't get max_active_bin = num_time_bins at t=0"); + + printf("Passed %s\n", __func__); +} + +/** + * @brief test get_min_active_bin by randomly choosing current times + * for a pair of small and big bins + * + * @param bin_min smallest bin to run test with + * @param bin_max highest bin to run test with + * @param max_nr_timesteps_test maximal number of timesteps for a sim + **/ +void test_get_min_active_bin(timebin_t bin_min, timebin_t bin_max, + integertime_t max_nr_timesteps_test) { + + integertime_t dti_lo, dti_hi; + integertime_t step, max_step; + integertime_t ti_old, ti_current; + timebin_t min_active_bin; + + /* Test random ti_currents */ + /* ----------------------- */ + + for (timebin_t bin_lo = bin_min; bin_lo < bin_max - 1; bin_lo++) { + dti_lo = get_integer_timestep(bin_lo); + + for (timebin_t bin_hi = bin_lo + 1; bin_hi < bin_max; bin_hi++) { + dti_hi = get_integer_timestep(bin_hi); + max_step = (max_nr_timesteps_test / dti_hi); + + if (NREPEAT / bin_max < max_step) { + /* Do random draws */ + for (int r = 0; r < NREPEAT / bin_max; r++) { + + step = (integertime_t)(random_uniform(0., max_step)); + ti_current = step * dti_hi; + ti_old = ti_current - dti_lo; + + if (ti_current % dti_hi != 0) + error("Time current not divisible by dti_hi"); + if (ti_current % dti_lo != 0) + error("Time current not divisible by dti_lo"); + if (ti_current <= ti_old) + error("ti_current=%lld <= ti_old=%lld | bins %d %d; ", ti_current, + ti_old, bin_lo, bin_hi); + + min_active_bin = get_min_active_bin(ti_current, ti_old); + if (min_active_bin != bin_lo) + error("Got wrong min active bin. Expect=%d got=%d", bin_lo, + min_active_bin); + } + } else { + /* systematically check every possibility */ + for (step = 0; step <= max_step; step++) { + + ti_current = step * dti_hi; + ti_old = ti_current - dti_lo; + + if (ti_current % dti_hi != 0) + error("Time current not divisible by dti_hi"); + if (ti_current % dti_lo != 0) + error("Time current not divisible by dti_lo"); + if (ti_current <= ti_old) + error("ti_current=%lld <= ti_old=%lld | bins %d %d; ", ti_current, + ti_old, bin_lo, bin_hi); + + min_active_bin = get_min_active_bin(ti_current, ti_old); + if (min_active_bin != bin_lo) + error("Got wrong min active bin. Expect=%d got=%d", bin_lo, + min_active_bin); + } + } + } + } + + printf("Passed %s\n", __func__); +} + +/** + * @brief Check the timeline functions. + */ +int main(int argc, char* argv[]) { + + /* Initialize CPU frequency, this also starts time. */ + unsigned long long cpufreq = 0; + clocks_set_cpufreq(cpufreq); + + /* Get some randomness going */ + const int seed = time(NULL); + message("Seed = %d", seed); + srand(seed); + + /* run test with the limits we use in SWIFT */ + /* ---------------------------------------- */ + test_get_time_bin(1, num_time_bins); + test_get_integer_time_begin(1, num_time_bins, max_nr_timesteps); + test_get_integer_time_end(1, num_time_bins, max_nr_timesteps); + test_get_max_active_bin(num_time_bins, max_nr_timesteps); + test_get_min_active_bin(1, num_time_bins, max_nr_timesteps); + + /* run test beyond the limits we use in SWIFT */ + /* ------------------------------------------ */ + /* Get maximal bin and number of timesteps based on type size */ + size_t timebin_bits = sizeof(timebin_t) * 8; + timebin_t max_num_time_bins = 0; + for (size_t i = 0; i < timebin_bits - 1; i++) { + max_num_time_bins |= (1 << i); + } + size_t timestep_bits = sizeof(integertime_t) * 8; + + /* timestep_bits -1 because of how << works, + * additional -1 because integertime_t is signed + * additional -1 so we can do any timestep at least twice */ + max_num_time_bins = min((size_t)max_num_time_bins, timestep_bits - 3); + + if (num_time_bins < max_num_time_bins) { + /* Use analogous definition as in timeline.h here */ + integertime_t max_nr_timesteps_test = (1LL << (max_num_time_bins + 1)); + + test_get_time_bin(num_time_bins, max_num_time_bins); + test_get_integer_time_begin(num_time_bins, max_num_time_bins, + max_nr_timesteps_test); + test_get_integer_time_end(num_time_bins, max_num_time_bins, + max_nr_timesteps_test); + test_get_max_active_bin(max_num_time_bins, max_nr_timesteps_test); + test_get_min_active_bin(1, max_num_time_bins, max_nr_timesteps_test); + } + + return 0; +}