From 1762fc87adbae3c48c58e929ccd9adbea401abbc Mon Sep 17 00:00:00 2001 From: Cory Date: Mon, 4 Dec 2023 12:36:29 +0100 Subject: [PATCH] Make some changes - Add new programs - Add command line args - Add Usage to guide user on how to use programs --- include/monte_carlo.hpp | 24 ++++----- include/utils.hpp | 17 ++++++- src/main.cpp | 96 +++++++++++++++++++++++++----------- src/mcmc_progression.cpp | 79 +++++++++++++++++++++++++++++ src/monte_carlo.cpp | 20 ++++++-- src/pd_estimate.cpp | 79 +++++++++++++++++++++++++++++ src/phase_transition.cpp | 84 +++++++++++++++++++++++++++++++ src/phase_transition_mpi.cpp | 53 +++++++++++++++++--- src/time.cpp | 61 ++++++++++++++++++++--- src/utils.cpp | 10 ++++ 10 files changed, 464 insertions(+), 59 deletions(-) create mode 100644 src/mcmc_progression.cpp create mode 100644 src/pd_estimate.cpp create mode 100644 src/phase_transition.cpp diff --git a/include/monte_carlo.hpp b/include/monte_carlo.hpp index 6fc2544..f865565 100644 --- a/include/monte_carlo.hpp +++ b/include/monte_carlo.hpp @@ -31,8 +31,8 @@ namespace montecarlo { * @param cycles The amount of Monte Carlo cycles to do * @param filename The file to write to * */ -void progression(double T, int L, int cycles, - const std::string filename); +void progression(double T, int L, int cycles, const std::string filename, + int burn_in_time = BURN_IN_TIME); /** @brief Write the expected values for each Monte Carlo cycles to file. * @@ -43,7 +43,7 @@ void progression(double T, int L, int cycles, * @param filename The file to write to * */ void progression(double T, int L, int cycles, int value, - const std::string filename); + const std::string filename, int burn_in_time = BURN_IN_TIME); /** @brief Estimate the probability distribution for the energy. * @@ -52,8 +52,8 @@ void progression(double T, int L, int cycles, int value, * @param cycles The amount of Monte Carlo cycles to do * @param filename The file to write to * */ -void pd_estimate(double T, int L, int cycles, - const std::string filename); +void pd_estimate(double T, int L, int cycles, const std::string filename, + int burn_in_time = BURN_IN_TIME); /** @brief Execute the Metropolis algorithm for a certain amount of Monte * Carlo cycles. @@ -64,7 +64,8 @@ void pd_estimate(double T, int L, int cycles, * * @return data_t * */ -data_t mcmc_serial(int L, double T, int cycles, int burn_in_time = BURN_IN_TIME); +data_t mcmc_serial(int L, double T, int cycles, + int burn_in_time = BURN_IN_TIME); /** @brief Execute the Metropolis algorithm for a certain amount of Monte * Carlo cycles in parallel. @@ -75,7 +76,8 @@ data_t mcmc_serial(int L, double T, int cycles, int burn_in_time = BURN_IN_TIME) * * @return data_t * */ -data_t mcmc_parallel(int L, double T, int cycles, int burn_in_time = BURN_IN_TIME); +data_t mcmc_parallel(int L, double T, int cycles, + int burn_in_time = BURN_IN_TIME); /** @brief Perform the MCMC algorithm using a range of temperatures. * @@ -86,10 +88,10 @@ data_t mcmc_parallel(int L, double T, int cycles, int burn_in_time = BURN_IN_TIM * @param monte_carlo Which Monte Carlo implementation to use * @param outfile The file to write the data to * */ -void -phase_transition(int L, double start_T, double end_T, int points_T, int cycles, - std::function monte_carlo, - std::string outfile, int burn_in_time = BURN_IN_TIME); +void phase_transition(int L, double start_T, double end_T, int points_T, + int cycles, + std::function monte_carlo, + std::string outfile, int burn_in_time = BURN_IN_TIME); }; // namespace montecarlo #endif diff --git a/include/utils.hpp b/include/utils.hpp index d9a99fd..0618908 100644 --- a/include/utils.hpp +++ b/include/utils.hpp @@ -49,7 +49,7 @@ namespace details { * * @details This function should only be used for the __METHOD_NAME__ macro, * since it takes the output from __PRETTY_FUNCTION__ and strips the return - * type. + * type. * * @param pretty_function The string from __PRETTY_FUNCTION__ * @@ -114,6 +114,21 @@ bool mkpath(std::string path, int mode = 0777); * */ std::string dirname(const std::string &path); +/** @brief Take 2 strings and concatenate them and make sure there is a + * directory separator (/) between them. + * + * @details This function doesn't care whether or not the values given as + * parameters are valid path strings. It is the responsibility of the user to make + * sure that the values given are valid path strings. + * The function only guarantees that the output string is a valid path string. + * + * @param left The left hand side of the result string + * @param right The right hand side of the result string + * + * @return string + * */ +std::string concatpath(const std::string &left, const std::string &right); + } // namespace utils #endif diff --git a/src/main.cpp b/src/main.cpp index 4d9c1d0..1d307ba 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -13,6 +13,8 @@ #include "monte_carlo.hpp" #include "utils.hpp" +#include + /** @brief Create the data for the burn-in time for temperatures 1.0 and 2.4 * for both unordered and ordered initial states. * */ @@ -43,10 +45,12 @@ void create_pd_estimate_data() void test_burn_in_time() { - montecarlo::phase_transition(100, 2.1, 2.4, 40, 1e5, montecarlo::mcmc_serial, - "../output/test_burn_in_time/no_burn_in.txt", 0); - montecarlo::phase_transition(100, 2.1, 2.4, 40, 1e5, montecarlo::mcmc_serial, - "../output/test_burn_in_time/burn_in.txt", 5000); + montecarlo::phase_transition( + 100, 2.1, 2.4, 40, 1e5, montecarlo::mcmc_serial, + "../output/test_burn_in_time/no_burn_in.txt", 0); + montecarlo::phase_transition( + 100, 2.1, 2.4, 40, 1e5, montecarlo::mcmc_serial, + "../output/test_burn_in_time/burn_in.txt", 5000); } /** @brief Test how much Openmp speeds up.*/ @@ -99,36 +103,70 @@ void create_phase_transition_data() std::cout << "Time: " << t1 - t0 << std::endl; } +void usage(std::string filename) +{ + std::cout << "Usage: " << filename << " OPTION ...\n" + << "At least one option should be used.\n\n" + << "\t[ -h | --help ]\n" + << "\t[ --all ]\n" + << "\t[ --create-burn-in-data ]\n" + << "\t[ --create-pd-estimate-data ]\n" + << "\t[ --create-phase-transition-data ]\n" + << "\t[ --test-parallel-speedup ]\n" + << "\t[ --test-burn-in-time ]\n"; + exit(-1); +} + /** @brief The main function.*/ int main(int argc, char **argv) { - if (argc < 2) { - std::cout << "Need at least 1 argument, got " << argc - 1 - << " arguments." << std::endl; - abort(); - } + static struct option long_options[] = { + {"all", no_argument, 0, 0}, + {"create-burn-in-data", no_argument, 0, 0}, + {"create-pd-estimate-data", no_argument, 0, 0}, + {"test-parallel-speedup", no_argument, 0, 0}, + {"create-phase-transition-data", no_argument, 0, 0}, + {"test-burn-in-time", no_argument, 0, 0}, + {"help", no_argument, 0, 0}}; - int arg = atoi(argv[1]); + int option_index = -1; + int c; - switch (arg) { - case 1: - create_burn_in_time_data(); - break; - case 2: - create_pd_estimate_data(); - break; - case 3: - test_parallel_speedup(); - break; - case 4: - create_phase_transition_data(); - break; - case 5: - test_burn_in_time(); - break; - default: - std::cout << "Not a valid option!" << std::endl; - abort(); + while (true) { + c = getopt_long(argc, argv, "h", long_options, &option_index); + + if (c == -1) + break; + else if (c == 'h') + usage(argv[0]); + + switch (option_index) { + case 0: + create_burn_in_time_data(); + create_pd_estimate_data(); + test_parallel_speedup(); + create_phase_transition_data(); + test_burn_in_time(); + break; + case 1: + create_burn_in_time_data(); + break; + case 2: + create_pd_estimate_data(); + break; + case 3: + test_parallel_speedup(); + break; + case 4: + create_phase_transition_data(); + break; + case 5: + test_burn_in_time(); + break; + case 6: // Not a mistake. This just goes to the default. + default: + usage(argv[0]); + } } return 0; diff --git a/src/mcmc_progression.cpp b/src/mcmc_progression.cpp new file mode 100644 index 0000000..e6982d5 --- /dev/null +++ b/src/mcmc_progression.cpp @@ -0,0 +1,79 @@ +/** @file mcmc_progression.cpp + * + * @author Cory Alexander Balaton (coryab) + * @author Janita Ovidie Sandtrøen Willumsen (janitaws) + * + * @version 1.0 + * + * @brief Execute the mcmc algorithm and write data to file after each + * Monte Carlo cycle. + * + * @bug No known bugs + * */ +#include "data_type.hpp" +#include "monte_carlo.hpp" +#include "utils.hpp" + +#include +#include +#include + +void usage(std::string filename) +{ + std::cout << "Usage: " << filename + << " " + " \n\n" + << "\t[ -h | --help ]\n"; + exit(-1); +} + +/** @brief The main function + * + * */ +int main(int argc, char **argv) +{ + // Command options + struct option long_options[] = {{"help", 0, 0, 0}, {NULL, 0, NULL, 0}}; + + int option_index = -1; + int c; + + while (true) { + c = getopt_long(argc, argv, "h", long_options, &option_index); + + if (c == -1) + break; + + switch (c) { + case 0: + switch (option_index) { + case 0: // Not a mistake. This just goes to the default. + default: + usage(argv[0]); + } + break; + case 'h': + default: + usage(argv[0]); + } + } + // Check that the number of arguments is at least 8. + if (argc < 6) { + usage(argv[0]); + } + + // Timing variables + double t0, t1; + t0 = omp_get_wtime(); + + // Define/initialize variables + double temp = atoi(argv[1]); + int L = atoi(argv[2]), cycles = atoi(argv[3]), burn_in_time = atoi(argv[4]); + std::string outfile = argv[5]; + + montecarlo::progression(temp, L, cycles, outfile, burn_in_time); + + t1 = omp_get_wtime(); + + std::cout << "Time: " << t1 - t0 << " seconds\n"; +} diff --git a/src/monte_carlo.cpp b/src/monte_carlo.cpp index efe5113..1cbcc8a 100644 --- a/src/monte_carlo.cpp +++ b/src/monte_carlo.cpp @@ -12,7 +12,8 @@ #include "monte_carlo.hpp" namespace montecarlo { -void progression(double T, int L, int cycles, const std::string filename) +void progression(double T, int L, int cycles, const std::string filename, + int burn_in_time) { // Set some variables data_t data, tmp; @@ -35,6 +36,10 @@ void progression(double T, int L, int cycles, const std::string filename) utils::mkpath(directory); ofile.open(filename); + for (size_t i = 0; i < burn_in_time; i++) { + ising.Metropolis(); + } + // Loop through cycles for (size_t i = 1; i <= cycles; i++) { data += ising.Metropolis(); @@ -46,7 +51,7 @@ void progression(double T, int L, int cycles, const std::string filename) } void progression(double T, int L, int cycles, int value, - const std::string filename) + const std::string filename, int burn_in_time) { // Set some variables data_t data, tmp; @@ -65,6 +70,10 @@ void progression(double T, int L, int cycles, int value, IsingModel ising(L, T, value); + for (size_t i = 0; i < burn_in_time; i++) { + ising.Metropolis(); + } + // Create path and open file utils::mkpath(directory); ofile.open(filename); @@ -79,7 +88,8 @@ void progression(double T, int L, int cycles, int value, ofile.close(); } -void pd_estimate(double T, int L, int cycles, const std::string filename) +void pd_estimate(double T, int L, int cycles, const std::string filename, + int burn_in_time) { // Set some variables data_t data, tmp; @@ -91,6 +101,10 @@ void pd_estimate(double T, int L, int cycles, const std::string filename) IsingModel ising(L, T); + for (size_t i = 0; i < burn_in_time; i++) { + ising.Metropolis(); + } + // Create path and open file utils::mkpath(directory); ofile.open(filename); diff --git a/src/pd_estimate.cpp b/src/pd_estimate.cpp new file mode 100644 index 0000000..0ed73c7 --- /dev/null +++ b/src/pd_estimate.cpp @@ -0,0 +1,79 @@ +/** @file pd_estimate.cpp + * + * @author Cory Alexander Balaton (coryab) + * @author Janita Ovidie Sandtrøen Willumsen (janitaws) + * + * @version 1.0 + * + * @brief execute the mcmc algorithm and write data to file after each + * Monte Carlo cycles. + * + * @bug No known bugs + * */ +#include "data_type.hpp" +#include "monte_carlo.hpp" +#include "utils.hpp" + +#include +#include +#include + +void usage(std::string filename) +{ + std::cout << "Usage: " << filename + << " " + " \n\n" + << "\t[ -h | --help ]\n"; + exit(-1); +} + +/** @brief The main function + * + * */ +int main(int argc, char **argv) +{ + // Command options + struct option long_options[] = {{"help", 0, 0, 0}, {NULL, 0, NULL, 0}}; + + int option_index = -1; + int c; + + while (true) { + c = getopt_long(argc, argv, "h", long_options, &option_index); + + if (c == -1) + break; + + switch (c) { + case 0: + switch (option_index) { + case 0: // Not a mistake. This just goes to the default. + default: + usage(argv[0]); + } + break; + case 'h': + default: + usage(argv[0]); + } + } + // Check that the number of arguments is at least 8. + if (argc < 6) { + usage(argv[0]); + } + + // Timing variables + double t0, t1; + t0 = omp_get_wtime(); + + // Define/initialize variables + double temp = atoi(argv[1]); + int L = atoi(argv[2]), cycles = atoi(argv[3]), burn_in_time = atoi(argv[4]); + std::string outfile = argv[5]; + + montecarlo::pd_estimate(temp, L, cycles, outfile, burn_in_time); + + t1 = omp_get_wtime(); + + std::cout << "Time: " << t1 - t0 << " seconds\n"; +} diff --git a/src/phase_transition.cpp b/src/phase_transition.cpp new file mode 100644 index 0000000..8df0e55 --- /dev/null +++ b/src/phase_transition.cpp @@ -0,0 +1,84 @@ +/** @file phase_transition.cpp + * + * @author Cory Alexander Balaton (coryab) + * @author Janita Ovidie Sandtrøen Willumsen (janitaws) + * + * @version 1.0 + * + * @brief Sweep over different temperatures and generate data. + * + * @details This program takes in 4 arguments: the start temperature, + * the end temperature, the amount of temperature points to simulate, and + * the amount of monte carlo samples to collect, in that order. + * + * @bug No known bugs + * */ +#include "data_type.hpp" +#include "monte_carlo.hpp" +#include "utils.hpp" + +#include +#include +#include + +void usage(std::string filename) +{ + std::cout << "Usage: " << filename + << " " + " \n\n" + << "\t[ -h | --help ]\n"; + exit(-1); +} + +/** @brief The main function + * + * */ +int main(int argc, char **argv) +{ + // Command options + struct option long_options[] = {{"help", 0, 0, 0}, {NULL, 0, NULL, 0}}; + + int option_index = -1; + int c; + + while (true) { + c = getopt_long(argc, argv, "h", long_options, &option_index); + + if (c == -1) + break; + + switch (c) { + case 0: + switch (option_index) { + case 0: // Not a mistake. This just goes to the default. + default: + usage(argv[0]); + } + break; + case 'h': + default: + usage(argv[0]); + } + } + // Check that the number of arguments is at least 8. + if (argc < 8) { + usage(argv[0]); + } + + // Timing variables + double t0, t1; + t0 = omp_get_wtime(); + + // Define/initialize variables + double start = atof(argv[1]), end = atof(argv[2]); + int points = atoi(argv[3]), cycles = atoi(argv[5]), L = atoi(argv[4]), + burn_in_time = atoi(argv[6]), N = L * L; + std::string outfile = argv[7]; + + montecarlo::phase_transition(L, start, end, points, cycles, + montecarlo::mcmc_parallel, outfile); + + t1 = omp_get_wtime(); + + std::cout << "Time: " << t1 - t0 << " seconds\n"; +} diff --git a/src/phase_transition_mpi.cpp b/src/phase_transition_mpi.cpp index 720e672..e5fa30e 100644 --- a/src/phase_transition_mpi.cpp +++ b/src/phase_transition_mpi.cpp @@ -17,17 +17,55 @@ #include "monte_carlo.hpp" #include "utils.hpp" +#include #include +#include + +void usage(std::string filename) +{ + std::cout + << "Usage: " << filename + << " " + " \n" + << "This should be used with mpiexec or mpirun for maximum " + "performance\n\n" + << "\t[ -h | --help ]\n"; + exit(-1); +} /** @brief The main function * * */ int main(int argc, char **argv) { - // Check that the number of arguments is at least 4. - if (argc < 7) { - std::cout << "You need at least 6 arguments" << std::endl; - abort(); + // Command options + struct option long_options[] = {{"help", 0, 0, 0}, {NULL, 0, NULL, 0}}; + + int option_index = -1; + int c; + + while (true) { + c = getopt_long(argc, argv, "h", long_options, &option_index); + + if (c == -1) + break; + + switch (c) { + case 0: + switch (option_index) { + case 0: // Not a mistake. This just goes to the default. + default: + usage(argv[0]); + } + break; + case 'h': + default: + usage(argv[0]); + } + } + // Check that the number of arguments is at least 8. + if (argc < 8) { + usage(argv[0]); } // Timing variables @@ -40,6 +78,7 @@ int main(int argc, char **argv) burn_in_time = atoi(argv[6]), N = L * L; double dt = (end - start) / points; std::ofstream ofile; + std::string outfile = argv[7]; data_t data[points]; // MPI specific variables @@ -100,10 +139,8 @@ int main(int argc, char **argv) } // Write everything from data to file - std::stringstream outfile; - outfile << "../output/phase_transition/mpi/size_" << L << ".txt"; - utils::mkpath(utils::dirname(outfile.str())); - ofile.open(outfile.str()); + utils::mkpath(utils::dirname(outfile)); + ofile.open(outfile); double temp, CV, X; diff --git a/src/time.cpp b/src/time.cpp index dc18ca0..afbb8bd 100644 --- a/src/time.cpp +++ b/src/time.cpp @@ -13,6 +13,7 @@ #include "monte_carlo.hpp" #include "utils.hpp" +#include #include #include @@ -29,8 +30,7 @@ void time_lattice_sizes() for (int L : lattice_sizes) { t0 = omp_get_wtime(); montecarlo::phase_transition(L, 2.1, 2.4, 40, 100000, - montecarlo::mcmc_parallel, - "/dev/null"); + montecarlo::mcmc_parallel, "/dev/null"); t1 = omp_get_wtime(); ofile << utils::scientific_format(L) << ',' << utils::scientific_format(t1 - t0) << '\n'; @@ -51,8 +51,7 @@ void time_sample_sizes() for (int samples : sample_sizes) { t0 = omp_get_wtime(); montecarlo::phase_transition(20, 2.1, 2.4, 40, samples, - montecarlo::mcmc_parallel, - "/dev/null"); + montecarlo::mcmc_parallel, "/dev/null"); t1 = omp_get_wtime(); ofile << utils::scientific_format(samples) << ',' << utils::scientific_format(t1 - t0) << '\n'; @@ -60,9 +59,57 @@ void time_sample_sizes() ofile.close(); } -int main() +void usage(std::string filename) { - time_lattice_sizes(); - time_sample_sizes(); + std::cout << "Usage: " << filename << " OPTION ...\n" + << "At least one option should be used.\n\n" + << "\t[ -h | --help ]\n" + << "\t[ --all ]\n" + << "\t[ --time-lattice-sizes ]\n" + << "\t[ --time-sample-sizes ]\n"; + exit(-1); +} + +int main(int argc, char **argv) +{ + struct option long_options[] = {{"all", 0, 0, 0}, + {"time-lattice-sizes", 0, 0, 0}, + {"time-sample-sizes", 0, 0, 0}, + {"help", 0, 0, 0}, + {NULL, 0, NULL, 0}}; + + int option_index = -1; + int c; + + while (true) { + c = getopt_long(argc, argv, "h", long_options, &option_index); + + if (c == -1) + break; + + switch (c) { + case 0: + switch (option_index) { + case 0: + time_lattice_sizes(); + time_sample_sizes(); + break; + case 1: + time_lattice_sizes(); + break; + case 2: + time_sample_sizes(); + break; + case 3: // Not a mistake. This just goes to the default. + default: + usage(argv[0]); + } + break; + case 'h': + default: + usage(argv[0]); + } + } + return 0; } diff --git a/src/utils.cpp b/src/utils.cpp index b51fa72..554ee31 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -60,4 +60,14 @@ std::string dirname(const std::string &path) return path.substr(0, path.find_last_of("/")); } +std::string concatpath(const std::string &left, const std::string &right) +{ + if (left.back() != '/' and right.front() != '/') { + return left + '/' + right; + } + else { + return left + right; + } +} + } // namespace utils