diff --git a/Tests/NumLib/TestTimeSteppingFixed.cpp b/Tests/NumLib/TestTimeSteppingFixed.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6e77838b74e5688e8a5cd1a49269aedcc8d250c0 --- /dev/null +++ b/Tests/NumLib/TestTimeSteppingFixed.cpp @@ -0,0 +1,72 @@ +/** + * \author Norihiro Watanabe + * \date 2012-08-03 + * + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + */ + +#include <gtest/gtest.h> + +#include <vector> + +#include "logog/include/logog.hpp" + +#include "NumLib/TimeStepping/TimeStep.h" +#include "NumLib/TimeStepping/Algorithms/FixedTimeStepping.h" + +#include "../TestTools.h" +#include "TimeSteppingTestingTools.h" + +TEST(NumLib, TimeSteppingFixed) +{ + // homogeneous dt + { + NumLib::FixedTimeStepping fixed(1, 31, 10); + const std::vector<double> expected_vec_t = {1, 11, 21, 31}; + + std::vector<double> vec_t = timeStepping(fixed); + + ASSERT_EQ(expected_vec_t.size(), vec_t.size()); + ASSERT_ARRAY_NEAR(expected_vec_t, vec_t, expected_vec_t.size(), std::numeric_limits<double>::epsilon()); + } + + // dt vector (t_end == t0 + sum(dt)) + { + const std::vector<double> fixed_dt = {10, 10, 10}; + NumLib::FixedTimeStepping fixed(1, 31, 10); + const std::vector<double> expected_vec_t = {1, 11, 21, 31}; + + std::vector<double> vec_t = timeStepping(fixed); + + ASSERT_EQ(expected_vec_t.size(), vec_t.size()); + ASSERT_ARRAY_NEAR(expected_vec_t, vec_t, expected_vec_t.size(), std::numeric_limits<double>::epsilon()); + } + + // dt vector (t_end < t0 + sum(dt)) + { + const std::vector<double> fixed_dt = {5, 10, 20}; + NumLib::FixedTimeStepping fixed(1, 31, fixed_dt); + const std::vector<double> expected_vec_t = {1, 6, 16, 31}; + + std::vector<double> vec_t = timeStepping(fixed); + + ASSERT_EQ(expected_vec_t.size(), vec_t.size()); + ASSERT_ARRAY_NEAR(expected_vec_t, vec_t, expected_vec_t.size(), std::numeric_limits<double>::epsilon()); + } + + // dt vector (t_end > t0 + sum(dt)) + { + const std::vector<double> fixed_dt = {5, 10, 10}; + NumLib::FixedTimeStepping fixed(1, 31, fixed_dt); + const std::vector<double> expected_vec_t = {1, 6, 16, 26}; + + std::vector<double> vec_t = timeStepping(fixed); + + ASSERT_EQ(expected_vec_t.size(), vec_t.size()); + ASSERT_ARRAY_NEAR(expected_vec_t, vec_t, expected_vec_t.size(), std::numeric_limits<double>::epsilon()); + } +} diff --git a/Tests/NumLib/TestTimeSteppingIterationNumber.cpp b/Tests/NumLib/TestTimeSteppingIterationNumber.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7b2927c0f600b60f64c556e12181930102186a78 --- /dev/null +++ b/Tests/NumLib/TestTimeSteppingIterationNumber.cpp @@ -0,0 +1,122 @@ +/** + * \author Norihiro Watanabe + * \date 2012-08-03 + * + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + */ + +#include <gtest/gtest.h> + +#include <vector> + +#include "logog/include/logog.hpp" + +#include "BaseLib/DebugTools.h" +#include "NumLib/TimeStepping/TimeStep.h" +#include "NumLib/TimeStepping/Algorithms/IterationNumberBasedAdaptiveTimeStepping.h" + +#include "../TestTools.h" +#include "TimeSteppingTestingTools.h" + +TEST(NumLib, TimeSteppingIterationNumberBased1) +{ + std::vector<std::size_t> iter_times_vector = {0, 3, 5, 7}; + std::vector<double> multiplier_vector = {2.0, 1.0, 0.5, 0.25}; + NumLib::IterationNumberBasedAdaptiveTimeStepping alg(1, 31, 1, 10, 1, iter_times_vector, multiplier_vector); + + ASSERT_TRUE(alg.next()); // t=2, dt=1 + NumLib::TimeStep ts = alg.getTimeStep(); + ASSERT_EQ(1u, ts.steps()); + ASSERT_EQ(1., ts.previous()); + ASSERT_EQ(2., ts.current()); + ASSERT_EQ(1., ts.dt()); + ASSERT_TRUE(alg.accepted()); + + ASSERT_TRUE(alg.next()); // t=4, dt=2 + + // dt*=2 + alg.setNIterations(3); + ASSERT_TRUE(alg.next()); // t=8, dt=4 + ts = alg.getTimeStep(); + ASSERT_EQ(3u, ts.steps()); + ASSERT_EQ(4., ts.previous()); + ASSERT_EQ(8., ts.current()); + ASSERT_EQ(4., ts.dt()); + ASSERT_TRUE(alg.accepted()); + + // dt*=1 + alg.setNIterations(5); + ASSERT_TRUE(alg.next()); // t=12, dt=4 + ts = alg.getTimeStep(); + ASSERT_EQ(4u, ts.steps()); + ASSERT_EQ(8., ts.previous()); + ASSERT_EQ(12., ts.current()); + ASSERT_EQ(4., ts.dt()); + ASSERT_TRUE(alg.accepted()); + + // dt*=0.5 + alg.setNIterations(7); + ASSERT_TRUE(alg.next()); // t=14, dt=2 + ts = alg.getTimeStep(); + ASSERT_EQ(5u, ts.steps()); + ASSERT_EQ(12., ts.previous()); + ASSERT_EQ(14., ts.current()); + ASSERT_EQ(2., ts.dt()); + ASSERT_TRUE(alg.accepted()); + + // dt*=0.25 but dt_min = 1 + alg.setNIterations(8); // exceed max + ASSERT_TRUE(alg.next()); // t=13, dt=1 + ts = alg.getTimeStep(); + ASSERT_EQ(5u, ts.steps()); + ASSERT_EQ(12., ts.previous()); + ASSERT_EQ(13, ts.current()); + ASSERT_EQ(1., ts.dt()); + ASSERT_FALSE(alg.accepted()); + + // restart, dt*=1 + alg.setNIterations(4); + ASSERT_TRUE(alg.next()); // t=14, dt=1 + ts = alg.getTimeStep(); + ASSERT_EQ(6u, ts.steps()); + ASSERT_EQ(13., ts.previous()); + ASSERT_EQ(14, ts.current()); + ASSERT_EQ(1., ts.dt()); + ASSERT_TRUE(alg.accepted()); +} + +TEST(NumLib, TimeSteppingIterationNumberBased2) +{ + std::vector<std::size_t> iter_times_vector = {0, 3, 5, 7}; + std::vector<double> multiplier_vector = {2.0, 1.0, 0.5, 0.25}; + NumLib::IterationNumberBasedAdaptiveTimeStepping alg(1, 31, 1, 10, 1, iter_times_vector, multiplier_vector); + + std::vector<std::size_t> nr_iterations = {2, 2, 2, 4, 6, 8, 4, 4, 2, 2}; + const std::vector<double> expected_vec_t = {1, 2, 4, 8, 16, 24, 26, 28, 30, 31}; + + struct IterationNumberUpdate + { + IterationNumberUpdate(const std::vector<std::size_t> &vec) : _nr_iterations(vec) {} + std::vector<std::size_t> _nr_iterations; + void operator()(NumLib::IterationNumberBasedAdaptiveTimeStepping &obj) + { + static std::size_t i = 0; + std::size_t n = (i<_nr_iterations.size()) ? _nr_iterations[i++] : 0; + //INFO("-> NR-iterations=%d", n); + obj.setNIterations(n); + } + }; + + IterationNumberUpdate update(nr_iterations); + + std::vector<double> vec_t = timeStepping(alg, &update); + //std::cout << vec_t; + + ASSERT_EQ(expected_vec_t.size(), vec_t.size()); + ASSERT_EQ(1u, alg.getNRepeatedSteps()); + ASSERT_ARRAY_NEAR(expected_vec_t, vec_t, expected_vec_t.size(), std::numeric_limits<double>::epsilon()); +} diff --git a/Tests/NumLib/TimeSteppingTestingTools.h b/Tests/NumLib/TimeSteppingTestingTools.h new file mode 100644 index 0000000000000000000000000000000000000000..2f5d11e9f49bfe98a8fe1fdc0c5419c2a39f600f --- /dev/null +++ b/Tests/NumLib/TimeSteppingTestingTools.h @@ -0,0 +1,51 @@ +/** + * \author Norihiro Watanabe + * \date 2012-08-03 + * + * \copyright + * Copyright (c) 2013, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + */ + +#ifndef TIMESTEPPINGTESTINGTOOLS_H_ +#define TIMESTEPPINGTESTINGTOOLS_H_ + +#include "logog/include/logog.hpp" + +#include "NumLib/TimeStepping/TimeStep.h" + + +namespace +{ + +struct Dummy +{ + template <class T> + void operator()(T &/*obj*/) {} +}; + +template <class T_TIME_STEPPING, class T=Dummy> +std::vector<double> timeStepping(T_TIME_STEPPING &algorithm, T* obj=nullptr) +{ + std::vector<double> vec_t; + vec_t.push_back(algorithm.begin()); + + while (algorithm.next()) { + NumLib::TimeStep t = algorithm.getTimeStep(); + //INFO("t: n=%d,t=%g,dt=%g", t.steps(), t.current(), t.dt()); + if (obj) + (*obj)(algorithm); // do something + if (algorithm.accepted()) { + vec_t.push_back(t.current()); + } else { + //INFO("*** rejected."); + } + } + + return vec_t; +} +} // namespace + +#endif // TIMESTEPPINGTESTINGTOOLS_H_