From 8bac1857b1585793b03b272882f1acc98fb86ec5 Mon Sep 17 00:00:00 2001 From: Cory Date: Wed, 6 Dec 2023 11:49:25 +0100 Subject: [PATCH] Initial commit --- .gitignore | 52 ++++++++++++ Makefile | 98 ++++++++++++++++++++++ README.md | 4 +- include/testlib.hpp | 140 +++++++++++++++++++++++++++++++ include/utils.hpp | 134 +++++++++++++++++++++++++++++ latex/Makefile | 14 ++++ latex/schrodinger_simulation.tex | 0 lib/testlib.cpp | 42 ++++++++++ lib/utils.cpp | 73 ++++++++++++++++ requirements.txt | 2 + src/main.cpp | 0 src/test_suite.cpp | 0 12 files changed, 558 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 include/testlib.hpp create mode 100644 include/utils.hpp create mode 100644 latex/Makefile create mode 100644 latex/schrodinger_simulation.tex create mode 100644 lib/testlib.cpp create mode 100644 lib/utils.cpp create mode 100644 requirements.txt create mode 100644 src/main.cpp create mode 100644 src/test_suite.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..90f5ec8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,52 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Latex +*.aux +*.log +*.out +*.synctex.gz +*.bbl +*.blg +latex/*.pdf +latex/*Notes.bib + +# C++ +build +bin +prof +debug +test + +# Score-p +scorep* diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..79ee877 --- /dev/null +++ b/Makefile @@ -0,0 +1,98 @@ +# The compiler +CC=mpicxx + +# Flags +CFLAGS=-Wall -larmadillo -std=c++11 -O3 -fopenmp +PROFFLAGS=-fno-inline-functions +DBGFLAGS=-DDBG -g + +MKDIR=mkdir -p +RMDIR=rm -rf +INSTRUMENT=scorep + +# Directories for binaries +BINDIR=./bin +PROFDIR=./prof +DEBUGDIR=./debug + +# Directories for object files +BUILDDIR=./build +BINOBJDIR=$(BUILDDIR)/objs +PROFOBJDIR=$(BUILDDIR)/prof +DEBUGOBJDIR=$(BUILDDIR)/debug + +# Directory for latex source +LATEXDIR=./latex + +# Source directories +SRC=./src +INCLUDE=./include + +# Source files and object file locations +SRCFILES=utils.cpp testlib.cpp data_type.cpp IsingModel.cpp monte_carlo.cpp +SRCS=$(addprefix $(SRC)/, $(SRCS)) +BINOBJS=$(addprefix $(BINOBJDIR)/, $(SRCFILES:.cpp=.o)) +PROFOBJS=$(addprefix $(PROFOBJDIR)/, $(SRCFILES:.cpp=.o)) +DEBUGOBJS=$(addprefix $(DEBUGOBJDIR)/, $(SRCFILES:.cpp=.o)) + +# Location for Binaries +EXEC=main test_suite phase_transition phase_transition_mpi time pd_estimate mcmc_progression +BINS=$(addprefix $(BINDIR)/, $(EXEC)) +PROFBINS=$(PROFDIR)/phase_transition_mpi +DEBUGBINS=$(addprefix $(DEBUGDIR)/, $(EXEC)) + +# List phony targets +.PHONY: all profile debug latex clean binclean objclean latexclean + +# "Commands" +all: $(BINS) + +profile: $(PROFBINS) + +debug: $(DEBUGBINS) + +# build latex file +latex: + $(MAKE) -C $(LATEXDIR) + +# Rule for binaries +$(BINDIR)/%: $(BINOBJDIR)/%.o $(BINOBJS) + $(MKDIR) $(BINDIR) + $(CC) $^ -o $@ $(CFLAGS) -I$(INCLUDE) + +# Rule for profiling binaries +$(PROFDIR)/%: $(PROFOBJDIR)/%.o $(PROFOBJS) + $(MKDIR) $(PROFDIR) + $(INSTRUMENT) $(CC) $^ -o $@ $(CFLAGS) $(PROFFLAGS) -I$(INCLUDE) + +# Rule for debug binaries +$(DEBUGDIR)/%: $(DEBUGOBJDIR)/%.o $(DEBUGOBJS) + $(MKDIR) $(DEBUGDIR) + $(CC) $^ -o $@ $(CFLAGS) $(DBGFLAGS) -I$(INCLUDE) + +# Rule for object files +$(BINOBJDIR)/%.o: $(SRC)/%.cpp + $(MKDIR) $(BINOBJDIR) + $(CC) -c $^ -o $@ $(CFLAGS) -I$(INCLUDE) + +# Rule for instrumented object files +$(PROFOBJDIR)/%.o: $(SRC)/%.cpp + $(MKDIR) $(PROFOBJDIR) + $(INSTRUMENT) $(CC) -c $^ -o $@ $(CFLAGS) $(PROFFLAGS) -I$(INCLUDE) + +# Rule for debug object files +$(DEBUGOBJDIR)/%.o: $(SRC)/%.cpp + $(MKDIR) $(DEBUGOBJDIR) + $(CC) -c $^ -o $@ $(CFLAGS) $(DBGFLAGS) -I$(INCLUDE) + +# Cleaning +clean: objclean binclean latexclean + +latexclean: + $(MAKE) -C $(LATEXDIR) clean + +objclean: + $(RMDIR) $(BUILDDIR) + +binclean: + $(RMDIR) $(BINDIR) $(PROFDIR) $(DEBUGDIR) diff --git a/README.md b/README.md index ad07343..a739fc9 100644 --- a/README.md +++ b/README.md @@ -1 +1,3 @@ -# Project-5 \ No newline at end of file +# Simulating the Schrödinger wave equation using the Crank-Nicolson method in 2 dimensions + + diff --git a/include/testlib.hpp b/include/testlib.hpp new file mode 100644 index 0000000..84f6418 --- /dev/null +++ b/include/testlib.hpp @@ -0,0 +1,140 @@ +/** @file testlib.hpp + * + * @author Cory Alexander Balaton (coryab) + * @author Janita Ovidie Sandtrøen Willumsen (janitaws) + * + * @version 1.0 + * + * @brief A small test library. + * + * @details This a small testing library that is tailored for the needs of the + * project. Anything that is in the details namespace should not be used + * directly, or else it might cause undefined behavior if not used correctly. + * + * @bug No known bugs + * */ +#ifndef __TESTLIB__ +#define __TESTLIB__ + +#include "utils.hpp" + +#include +#include +#include + +/** @def ASSERT(expr) + * @brief A prettier assertion function. + * + * This macro calls the m_assert function which is a more informative + * assertion function than the regular assert function from cassert. + * */ +#define ASSERT(expr, msg) \ + details::m_assert(expr, #expr, __METHOD_NAME__, __FILE__, __LINE__, msg) + +namespace details { + +/** @brief Test an expression, confirm that test is ok, or abort execution. + * + * @details This function takes in an expression and prints an OK message if + * it's true, or it prints a fail message and aborts execution if it fails. + * + * @param expr The expression to be evaluated + * @param expr_str The stringified version of the expression + * @param func The function name of the caller + * @param file The file of the caller + * @param line The line number where this function is called from + * @param msg The message to be displayed + * */ +void m_assert(bool expr, std::string expr_str, std::string func, + std::string file, int line, std::string msg); +} // namespace details + +namespace testlib { + +/** @brief Test if two armadillo matrices/vectors are close to each other. + * + * @details This function takes in 2 matrices/vectors and checks if they are + * approximately equal to each other given a tolerance. + * + * @param a Matrix/vector a + * @param b Matrix/vector b + * @param tol The tolerance + * + * @return bool + * */ +template ::value>::type> +static bool close_to(arma::Mat &a, arma::Mat &b, double tol = 1e-8) +{ + if (a.n_elem != b.n_elem) { + return false; + } + + for (size_t i = 0; i < a.n_elem; i++) { + if (!close_to(a(i), b(i))) { + return false; + } + } + return true; +} + +/** @brief Test if two numbers are close to each other. + * + * @details This function takes in 2 matrices/vectors and checks if they are + * approximately equal to each other given a tolerance. + * + * @param a Matrix/vector a + * @param b Matrix/vector b + * @param tol The tolerance + * + * @return bool + * */ +template ::value>::type> +static bool close_to(T a, T b, double tol = 1e-8) +{ + return std::fabs(a - b) < tol; +} + +/** @brief Test if two armadillo matrices/vectors are equal. + * + * @details This function takes in 2 matrices/vectors and checks if they are + * equal to each other. This should only be used for integral types. + * + * @param a Matrix/vector a + * @param b Matrix/vector b + * + * @return bool + * */ +template ::value>::type> +static bool is_equal(arma::Mat &a, arma::Mat &b) +{ + for (size_t i = 0; i < a.n_elem; i++) { + if (!(a(i) == b(i))) { + return false; + } + } + return true; +} + +/** @brief Test that all elements fulfill the condition. + * + * @param expr The boolean expression to apply to each element + * @param M The matrix/vector to iterate over + * + * @return bool + * */ +template ::value>::type> +static bool assert_each(std::function expr, arma::Mat &M) +{ + for (size_t i = 0; i < M.n_elem; i++) { + if (!expr(M(i))) { + return false; + } + } + return true; +} +} // namespace testlib +#endif diff --git a/include/utils.hpp b/include/utils.hpp new file mode 100644 index 0000000..0618908 --- /dev/null +++ b/include/utils.hpp @@ -0,0 +1,134 @@ +/** @file utils.hpp + * + * @author Cory Alexander Balaton (coryab) + * @author Janita Ovidie Sandtrøen Willumsen (janitaws) + * + * @version 1.0 + * + * @brief Function prototypes and macros that are useful. + * + * These utility function are mainly for convenience and aren't directly + * related to the project. Anything that is in the details namespace should + * not be used directly, or else it might cause undefined behavior if not used + * correctly. + * + * @bug No known bugs + * */ +#ifndef __UTILS__ +#define __UTILS__ + +#include +#include +#include +#include +#include +#include + +/** @def DEBUG(msg) + * @brief Writes a debug message + * + * This macro writes a debug message that includes the filename, + * line number, and a custom message. The function is wrapped in an ifdef + * that checks if DBG is defined, so one can choose to display the debug + * messages by adding the -DDBG flag when compiling. + * */ +#ifdef DBG +#define DEBUG(msg) \ + std::cout << __FILE__ << " " << __LINE__ << ": " << msg << std::endl +#else +#define DEBUG(msg) +#endif + +/** @def __METHOD_NAME__ + * @brief Get the name of the current method/function without the return type. + * */ +#define __METHOD_NAME__ details::methodName(__PRETTY_FUNCTION__) + +namespace details { +/** @brief Takes in the __PRETTY_FUNCTION__ string and removes the return type. + * + * @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. + * + * @param pretty_function The string from __PRETTY_FUNCTION__ + * + * @return std::string + * */ +inline std::string methodName(const std::string &pretty_function) +{ + size_t colons = pretty_function.find("::"); + size_t begin = pretty_function.substr(0, colons).rfind(" ") + 1; + size_t end = pretty_function.rfind("(") - begin; + + return pretty_function.substr(begin, end) + "()"; +} + +} // namespace details + +namespace utils { + +/** @brief Turns a double into a string written in scientific format. + * + * @details The code is stolen from https://github.com/anderkve/FYS3150. + * + * @param d The number to stringify + * @param width The reserved width of the string + * @param prec The precision of the stringified number + * + * @return std::string + * */ +std::string scientific_format(double d, int width = 20, int prec = 10); + +/** @brief Turns a vector of doubles into a string written in scientific + * format. + * + * @details The code is stolen from https://github.com/anderkve/FYS3150. + * + * @param v The vector to stringify + * @param width The reserved width of the string + * @param prec The precision of the stringified number + * + * @return std::string + * */ +std::string scientific_format(const std::vector &v, int width = 20, + int prec = 10); + +/** @brief Make path given. + * + * @details This tries to be the equivalent to "mkdir -p" and creates a new + * directory whenever it needs to. + * + * @param path The path to be created + * @param mode The mode/permissions for all the new directories + * + * @return bool Success/Fail + * */ +bool mkpath(std::string path, int mode = 0777); + +/** @brief Get the directory name of the path + * + * @param path The path to use. + * + * @return string + * */ +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/latex/Makefile b/latex/Makefile new file mode 100644 index 0000000..77f8d57 --- /dev/null +++ b/latex/Makefile @@ -0,0 +1,14 @@ +SRC=ising_model +PDFLATEX=pdflatex +BIBTEX=bibtex + +.PHONY: clean + +all: + $(PDFLATEX) $(SRC) + $(BIBTEX) $(SRC) + $(PDFLATEX) $(SRC) + $(PDFLATEX) $(SRC) + +clean: + $(RM) *.aux *.log *.out *Notes.bib diff --git a/latex/schrodinger_simulation.tex b/latex/schrodinger_simulation.tex new file mode 100644 index 0000000..e69de29 diff --git a/lib/testlib.cpp b/lib/testlib.cpp new file mode 100644 index 0000000..1027b24 --- /dev/null +++ b/lib/testlib.cpp @@ -0,0 +1,42 @@ +/** @file testlib.cpp + * + * @author Cory Alexander Balaton (coryab) + * @author Janita Ovidie Sandtrøen Willumsen (janitaws) + * + * @version 1.0 + * + * @brief Implementation of the testing library + * + * @bug No known bugs + * */ +#include "testlib.hpp" + +namespace details { +void m_assert(bool expr, std::string expr_str, std::string f, std::string file, + int line, std::string msg) +{ + std::function print_message = + [](const std::string &msg) { + if (msg.size() > 0) { + std::cout << "message: " << msg << "\n\n"; + } + else { + std::cout << "\n"; + } + }; + std::string new_assert(f.size() + (expr ? 4 : 6), '-'); + std::cout << "\x1B[36m" << new_assert << "\033[0m\n"; + std::cout << f << ": "; + if (expr) { + std::cout << "\x1B[32mOK\033[0m\n"; + print_message(msg); + } + else { + std::cout << "\x1B[31mFAIL\033[0m\n"; + print_message(msg); + std::cout << file << " " << line << ": Assertion \"" << expr_str + << "\" Failed\n\n"; + abort(); + } +} +} // namespace details diff --git a/lib/utils.cpp b/lib/utils.cpp new file mode 100644 index 0000000..554ee31 --- /dev/null +++ b/lib/utils.cpp @@ -0,0 +1,73 @@ +/** @file utils.cpp + * + * @author Cory Alexander Balaton (coryab) + * @author Janita Ovidie Sandtrøen Willumsen (janitaws) + * + * @version 1.0 + * + * @brief Implementation of the utils + * + * @bug No known bugs + * */ +#include "utils.hpp" + +namespace utils { + +std::string scientific_format(double d, int width, int prec) +{ + std::stringstream ss; + ss << std::setw(width) << std::setprecision(prec) << std::scientific << d; + return ss.str(); +} + +std::string scientific_format(const std::vector &v, int width, int prec) +{ + std::stringstream ss; + for (double elem : v) { + ss << scientific_format(elem, width, prec); + } + return ss.str(); +} + +bool mkpath(std::string path, int mode) +{ + std::string cur_dir; + std::string::size_type pos = -1; + struct stat buf; + + if (path.back() != '/') { + path += '/'; + } + while (true) { + pos++; + pos = path.find('/', pos); + if (pos != std::string::npos) { + cur_dir = path.substr(0, pos); + if (mkdir(cur_dir.c_str(), mode) != 0 + && stat(cur_dir.c_str(), &buf) != 0) { + return -1; + } + } + else { + break; + } + } + return 0; +} + +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 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..fc0ed43 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +matplotlib +seaborn diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/test_suite.cpp b/src/test_suite.cpp new file mode 100644 index 0000000..e69de29