Page MenuHomec4science

misc.cpp
No OneTemporary

File Metadata

Created
Tue, Aug 27, 23:51

misc.cpp

#include "catch.hpp"
#include "utils/log.hpp"
#include "utils/timer.hpp"
#include "physics/maths.hpp"
#include "utils/moving_average.hpp"
#include "utils/perfs_handler.hpp"
#include "utils/options_handler.hpp"
#include "utils/scope_guard.hpp"
#include "utils/pimpl_ptr.hpp"
#include "utils/cached_vector.hpp"
#include <sstream>
using namespace specmicp;
// TOC
// =======================
//
// 1 - Logger
// 2 - Timer
// 3 - Average
// 4 - Moving Average
// 5 - Performance handler
// 6 - Options handler
// 7 - Scope guard
// 8 - Pimpl pointer
// 9 - Cached Vector
// 10 - Named Cached Vector
// Logger
// =======================
TEST_CASE("Logger", "[io],[log]") {
SECTION("Non init logging") {
init_logger(nullptr, logger::LogLevel::Warning);
// compilation test, and runtime test of not failling nullptr
SPAM << "Spam";
DEBUG << "Debug";
INFO << "Info";
WARNING << "Warning";
ERROR << "Error";
CRITICAL << "Critical";
}
SECTION("Level test") {
std::stringstream stream_log;
init_logger(&stream_log, logger::LogLevel::Warning);
SPAM << "Spam";
REQUIRE(stream_log.str().size() == 0);
DEBUG << "Debug";
REQUIRE(stream_log.str().size() == 0);
INFO << "Info";
REQUIRE(stream_log.str().size() == 0);
WARNING << "Warning";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
ERROR << "Error";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
CRITICAL << "Critical";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
init_logger(&stream_log, logger::LogLevel::Debug);
SPAM << "Spam";
REQUIRE(stream_log.str().size() == 0);
DEBUG << "Debug";
#ifdef NDEBUG
REQUIRE(stream_log.str().size() == 0);
#else
REQUIRE(stream_log.str().size() != 0);
#endif
stream_log.str("");
INFO << "Info";
#ifdef NDEBUG
REQUIRE(stream_log.str().size() == 0);
#else
REQUIRE(stream_log.str().size() != 0);
#endif
stream_log.str("");
WARNING << "Warning";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
ERROR << "Error";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
CRITICAL << "Critical";
REQUIRE(stream_log.str().size() != 0);
stream_log.str("");
}
}
// Timer
// =======================
TEST_CASE("Timer", "[time],[CPU]") {
SECTION("Timer test") {
Timer timer;
timer.stop();
CHECK(timer.elapsed_time() >= 0.0);
timer.start();
timer.stop();
CHECK(timer.elapsed_time() >= 0.0);
CHECK(timer.get_stop() >= timer.get_start());
CHECK(timer.get_ctime_start() != nullptr);
CHECK(timer.get_ctime_stop() != nullptr);
}
}
// Average
// ====================
#define test_average(method, a, b, sol) \
CHECK(average<method>(a, b) == Approx(sol).epsilon(1e-10));
#define test_average_vector(method, vector, sol) \
CHECK(average<method>(vector) == Approx(sol).epsilon(1e-10));
TEST_CASE("Average", "[average],[maths]") {
Vector test_vector(4);
test_vector << 1.0, 2.0, 3.0, 4.0;
SECTION("Arithmetic average") {
test_average(Average::arithmetic, 1.0, 1.0, 1.0);
test_average(Average::arithmetic, 2.0, 1.0, 1.5);
test_average(Average::arithmetic, -1.0, 1.0, 0.0);
test_average_vector(Average::arithmetic, test_vector, 10.0/4);
}
SECTION("Harmonic average") {
test_average(Average::harmonic, 1.0, 1.0, 1.0);
test_average(Average::harmonic, 2.0, 1.0, 2.0/(1+0.5));
test_average_vector(Average::harmonic, test_vector, 1.92);
}
SECTION("Geometric average") {
test_average(Average::geometric, 1.0, 1.0, 1.0);
test_average(Average::geometric, 1.0, 2.0, std::sqrt(2.0));
test_average_vector(Average::geometric, test_vector, std::pow(24.0, 1.0/4.0));
}
}
#undef test_average
#undef test_average_vector
// Moving Average
// =======================
TEST_CASE("Moving average", "[average],[timestep]") {
SECTION("Moving average test") {
utils::ExponentialMovingAverage moving_average(0.1, 1.0);
REQUIRE(moving_average.current_value() == 1.0);
CHECK(moving_average.add_point(1.0) == 1.0);
CHECK(moving_average.add_point(2.0) == 1.1);
REQUIRE(moving_average.add_point(3.0) == 0.9*1.1+0.3);
moving_average.reset(1.0);
REQUIRE(moving_average.current_value() == 1.0);
moving_average.set_alpha(0.2);
REQUIRE(moving_average.add_point(2.0) == Approx(0.8+0.4));
}
}
// Performance handler
// =======================
struct MockPerf
{
scalar_t residuals {-1};
index_t nb_iterations {-1};
};
class MockSolverPerf:
public PerformanceHandler<MockPerf>
{
public:
MockSolverPerf() {}
void do_stuff() {
get_perfs().residuals = 1e-6;
get_perfs().nb_iterations = 10;
}
void reset_solver() {
reset_perfs();
}
};
TEST_CASE("PerformanceHandler", "[performance],[base]") {
SECTION("Performance handler test") {
auto my_solver = MockSolverPerf();
const auto& perfs = my_solver.get_perfs();
CHECK(perfs.nb_iterations == -1);
CHECK(perfs.residuals == -1);
my_solver.do_stuff();
CHECK(perfs.nb_iterations == 10);
CHECK(perfs.residuals == 1e-6);
my_solver.reset_solver();
CHECK(perfs.nb_iterations == -1);
CHECK(perfs.residuals == -1);
}
}
// Options handler
// =======================
struct MockOptions
{
MockOptions()
{}
MockOptions(scalar_t res, index_t max_iter):
residuals(res),
max_iterations(max_iter)
{}
scalar_t residuals {1e-6};
index_t max_iterations {100};
};
class MockSolverOptions:
public OptionsHandler<MockOptions>
{
public:
MockSolverOptions() {}
MockSolverOptions(scalar_t res, index_t max_iter):
OptionsHandler(res, max_iter)
{}
};
TEST_CASE("Options handler", "[options],[base]") {
SECTION("Options handler test") {
auto my_solver_default = MockSolverOptions();
const auto& ro_options = my_solver_default.get_options();
CHECK(ro_options.max_iterations == 100);
CHECK(ro_options.residuals == 1e-6);
auto& rw_options = my_solver_default.get_options();
rw_options.max_iterations = 10;
rw_options.residuals = 1e-4;
CHECK(ro_options.max_iterations == 10);
CHECK(ro_options.residuals == 1e-4);
}
SECTION("Options handler - non default initialization") {
auto my_solver = MockSolverOptions(1e-4, 10);
const auto& ro_options = my_solver.get_options();
CHECK(ro_options.max_iterations == 10);
CHECK(ro_options.residuals == 1e-4);
}
}
// ScopeGuard
// ==========
static void will_fail(bool& hop) {
auto guard = utils::make_scope_guard([&hop]{hop=true;});
throw std::runtime_error("fail on purpose");
guard.release();
}
static void dont_fail(bool& hop) {
auto guard = utils::make_scope_guard([&hop]{hop=true;});
hop = false;
guard.release();
}
TEST_CASE("Scope guard", "[utils]") {
SECTION("Catch error") {
bool hop = false;
REQUIRE_THROWS_AS(will_fail(hop), std::runtime_error);
CHECK(hop == true);
dont_fail(hop);
CHECK(hop == false);
}
}
// pimpl_ptr
// =========
// simple Interface + Implementation to test pimpl_ptr
class MockImplementation
{
public:
MockImplementation(double a):
m_a(a)
{}
double add(double b) const {return m_a + b;}
// Compilation should failed if this one is activated
//double add(double b) {return m_a + b;}
void set(double new_a) { m_a = new_a;}
private:
double m_a;
};
class MockInterface
{
public:
MockInterface(double a):
m_impl(utils::make_pimpl<MockImplementation>(a))
{}
double add(double b) const {return m_impl->add(b);}
void set(double new_a) {return m_impl->set(new_a);}
private:
utils::pimpl_ptr<MockImplementation> m_impl;
};
TEST_CASE("pimpl_ptr", "[utils],[pointer],[const]") {
SECTION("Test mock") {
auto hop = MockImplementation(1.0);
CHECK(hop.add(2.0) == Approx(3.0));
hop.set(2.0);
CHECK(hop.add(2.0) == Approx(4.0));
}
//SECTION("compilation fail") {
// const MockInterface fail1(2.0);
// fail1.set(3.0);
//}
}
// Cached Vector
//
TEST_CASE("Cached vector", "[utils],[container],[cache]")
{
SECTION("Default") {
utils::CachedVector<std::string> cached;
cached.push_back("value0");
cached.push_back(0);
CHECK(cached.size() == 2);
CHECK(cached.size_cache() == 1);
CHECK(cached[0] == "value0");
CHECK(cached[1] == "value0");
for (auto& it: cached) {
CHECK(it == "value0");
}
cached.emplace_back("truc");
CHECK(cached[2] == "truc");
cached.emplace_back("other");
CHECK(cached[3] == "other");
cached.push_back(2);
CHECK(cached.at(4) == "other");
CHECK(cached.size() == 5);
CHECK(cached.size_cache() == 3);
auto& new_val = cached.fork(1);
new_val = "plop";
CHECK(cached[1] == "plop");
for (auto it=cached.begin_index(); it!=cached.cend_index();++it)
{
CHECK(*it < cached.size());
CHECK(*it >= 0);
}
//! it's possible, absolutely not a good idea
for (auto& value: cached) {
value = "reinit";
}
CHECK(cached[2] == "reinit");
}
SECTION("Default constructor") {
static_assert(std::is_default_constructible<std::string>::value,
"String is default constructible"
);
utils::CachedVector<std::string> cached(5);
CHECK(cached[4] == "");
}
}
// Named Cached Vector
TEST_CASE("NamedCachedVector", "[utils],[container],[cache]")
{
SECTION("Default") {
utils::NameCachedVector<std::string> cached(
5, "default_name", "default_value");
CHECK(cached.size_cache() == 1);
CHECK(cached.size() == 5);
CHECK(cached.get("default_name") == "default_value");
auto& forked = cached.fork(2, "new name");
forked = "new value";
CHECK(cached.size_cache() == 2);
CHECK(cached.size() == 5);
CHECK(cached[2] == "new value");
CHECK(cached.get("new name") == "new value");
CHECK(cached.has_value("new name"));
CHECK(not cached.has_value("not a name"));
cached.push_back_cache("another name", "another value");
CHECK(cached.get("another name") == "another value");
CHECK(cached.size_cache() == 3);
CHECK(cached.size() == 5);
for (auto& value: cached)
{
CHECK(value != "another value");
}
}
SECTION("Default constructor") {
static_assert(std::is_default_constructible<std::string>::value,
"String is default constructible"
);
utils::NameCachedVector<std::string> cached(5, "default");
CHECK(cached[4] == "");
}
}

Event Timeline