/** @file monte_carlo.hpp
 *
 *  @author Cory Alexander Balaton (coryab)
 *  @author Janita Ovidie Sandtrøen Willumsen (janitaws)
 *
 *  @version 1.0
 *
 *  @brief Functions for Monte Carlo simulations.
 *
 *  @bug No known bugs
 * */
#ifndef __MONTE_CARLO__
#define __MONTE_CARLO__

#include "IsingModel.hpp"
#include "data_type.hpp"
#include "utils.hpp"

#include <functional>
#include <omp.h>
#include <string>

// #define BURN_IN_TIME 12500
#define BURN_IN_TIME 5000

namespace montecarlo {
/** @brief Write the expected values for each Monte Carlo cycles to file.
 *
 *  @param T Temperature
 *  @param L The size of the lattice
 *  @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);

/** @brief Write the expected values for each Monte Carlo cycles to file.
 *
 *  @param T Temperature
 *  @param L The size of the lattice
 *  @param cycles The amount of Monte Carlo cycles to do
 *  @param value The value to set the elements in the lattice
 *  @param filename The file to write to
 * */
void progression(double T, int L, int cycles, int value,
                                    const std::string filename);

/** @brief Estimate the probability distribution for the energy.
 *
 *  @param T The temperature of the Ising model
 *  @param L The size of the lattice
 *  @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);

/** @brief Execute the Metropolis algorithm for a certain amount of Monte
 *  Carlo cycles.
 *
 *  @param L The size of the lattice
 *  @param T The Temperature for the Ising model
 *  @param cycles The amount of Monte Carlo cycles to do
 *
 *  @return data_t
 * */
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.
 *
 *  @param L The size of the lattice
 *  @param T The Temperature for the Ising model
 *  @param cycles The amount of Monte Carlo cycles to do
 *
 *  @return data_t
 * */
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.
 *
 *  @param L The size of the lattice
 *  @param start_T The start temperature
 *  @param end_T The end temperature
 *  @param point_T The amount of point to measure
 *  @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<data_t(int, double, int, int)> monte_carlo,
                 std::string outfile, int burn_in_time = BURN_IN_TIME);
}; // namespace montecarlo

#endif
