/** @file test_suite.cpp * * @author Cory Alexander Balaton (coryab) * @author Janita Ovidie Sandtrøen Willumsen (janitaws) * * @version 1.0 * * @brief Sweep over different temperatures and generate data. * * @bug No known bugs * */ #include "IsingModel.hpp" #include "testlib.hpp" #include #define EPS_2 (-2 * std::sinh(8.)) / (std::cosh(8.) + 3) #define MAG_2 (std::exp(8.) + 1) / (2 * (cosh(8.) + 3)) #define CV_2 \ 16 * (3 * std::cosh(8.) + 1) / ((std::cosh(8.) + 3) * (std::cosh(8.) + 3)) #define X_2 \ (3 * std::exp(8.) + std::exp(-8.) + 3) \ / ((std::cosh(8.) + 3) * (std::cosh(8.) + 3)) /** @brief Test class for the Ising model * */ class IsingModelTest { public: /** @brief Test That initializing works as intended. * */ void test_init_functions() { IsingModel test; test.L = 3; test.T = 1.; // Test that initializing the lattice only yields 1s and -1s. test.initialize_lattice(); std::function f = [](int x) { return x == 1 || x == -1; }; ASSERT(testlib::assert_each(f, test.lattice), "Test lattice initialization."); test.initialize_neighbors(); arma::Mat neighbor_matrix("2, 1 ; 0, 2 ; 1, 0"); ASSERT(testlib::is_equal(neighbor_matrix, test.neighbors), "Test neighbor matrix."); // Fill the lattice with 1s to be able to test the next functions. test.lattice.fill(1); // Test the initial magnetization. test.initialize_magnetization(); ASSERT(std::fabs(test.M - 9.) < 1e-8, "Test intial magnetization"); // Test that the initial energy is correct test.initialize_energy(); ASSERT(std::fabs(test.E - (-18)) < 1e-8, "Test initial energy."); } /** @brief Test numerical data with analytical data. * * @param tol The tolerance between the analytical and numerical solution. * @param max_cycles The max number of Monte Carlo cycles. * * return int * */ int test_2x2_lattice(double tol, int max_cycles) { data_t data, tmp; size_t L = 2; size_t n_spins = L * L; double T = 1.; size_t cycles = 0; // Create random engine using the mersenne twister std::random_device rd; std::mt19937 engine(rd()); IsingModel test(L, T); int arr[]{0, 0, 0, 0}; // Loop through cycles //std::ofstream ofile; //ofile.open("output/test_2x2.txt"); while (cycles++ < max_cycles) { data += test.Metropolis(); tmp = data / cycles; //ofile << cycles << ',' << tmp.E / n_spins << ',' //<< tmp.M_abs / n_spins << ',' //<< (tmp.E2 - tmp.E * tmp.E) / (T * T) / n_spins << ',' //<< (tmp.M2 - tmp.M_abs * tmp.M_abs) / T / n_spins << '\n'; if (testlib::close_to(EPS_2, tmp.E / n_spins, tol) && testlib::close_to(MAG_2, tmp.M_abs / n_spins, tol) && testlib::close_to(CV_2, (tmp.E2 - tmp.E * tmp.E) / (T * T) / n_spins, tol) && testlib::close_to(X_2, (tmp.M2 - tmp.M_abs * tmp.M_abs) / T / n_spins, tol)) { return cycles; } } //std::cout << EPS_2 << ',' << MAG_2 << ',' << CV_2 << ',' << X_2 //<< std::endl; //ofile.close(); // cycles = 0; // data = 0; // IsingModel test_mag(L, T); // while (cycles++ < max_cycles) { // data += test.Metropolis(); // tmp = data / (cycles * n_spins); // if (testlib::close_to(MAG_2, tmp.M, tol)) { // arr[1] = cycles; // break; //} //} // cycles = 0; // data = 0; // IsingModel test_CV(L, T); // while (cycles++ < max_cycles) { // data += test.Metropolis(); // tmp = data / (cycles * n_spins); // if (testlib::close_to(CV_2, (tmp.E2 - tmp.E * tmp.E) / (T * T), // tol)) { // arr[2] = cycles; // break; //} //} // cycles = 0; // data = 0; // IsingModel test_X(L, T); // while (cycles++ < max_cycles) { // data += test.Metropolis(); // tmp = data / (cycles * n_spins); // if (testlib::close_to(X_2, (tmp.M2 - tmp.M_abs * tmp.M_abs) / T, // tol)) { // arr[3] = cycles; // break; //} //} return 0; } }; /** @brief The main function.*/ int main() { IsingModelTest test; test.test_init_functions(); int res = 0; int tmp; for (size_t i=0; i < 1000; i++) { tmp = test.test_2x2_lattice(1e-2, 1e5); if (tmp == 0) { std::cout << "not enough cycles\n"; break; } res += tmp; } std::cout << "Res: " << res / 1000 << std::endl; return 0; }