Make changes

This commit is contained in:
Cory Balaton 2023-12-03 13:33:48 +01:00
parent 84692040d3
commit 237bd37184
No known key found for this signature in database
GPG Key ID: 3E5FCEBFD80F432B
13 changed files with 377 additions and 207 deletions

View File

@ -18,6 +18,7 @@
#include "utils.hpp" #include "utils.hpp"
#include <armadillo> #include <armadillo>
#include <cstdint>
#include <random> #include <random>
#include <unordered_map> #include <unordered_map>
@ -53,7 +54,8 @@ private:
/** @brief A hash map containing all possible energy changes. /** @brief A hash map containing all possible energy changes.
* */ * */
std::unordered_map<int, double> energy_diff; //std::unordered_map<int, double> energy_diff;
double energy_diff[17];
/** @brief The temperature of the model. /** @brief The temperature of the model.
* */ * */
@ -65,12 +67,15 @@ private:
/** @brief The current energy state. unit: \f$ J \f$. /** @brief The current energy state. unit: \f$ J \f$.
* */ * */
int E; int64_t E;
/** @brief The current magnetic strength. unit: Unitless. /** @brief The current magnetic strength. unit: Unitless.
* */ * */
int M; int64_t M;
std::mt19937 engine;
void initialize_engine();
/** @brief Initialize the lattice with a random distribution of 1s and /** @brief Initialize the lattice with a random distribution of 1s and
* -1s. * -1s.
* */ * */

View File

@ -49,7 +49,7 @@ public:
return res; return res;
} }
template <class T> data_t& operator/=(T num) template <class T> data_t &operator/=(T num)
{ {
this->E /= (double)num; this->E /= (double)num;
this->E2 /= (double)num; this->E2 /= (double)num;
@ -72,7 +72,7 @@ public:
return res; return res;
} }
template <class T> data_t& operator*=(T num) template <class T> data_t &operator*=(T num)
{ {
this->E *= (double)num; this->E *= (double)num;
this->E2 *= (double)num; this->E2 *= (double)num;
@ -95,7 +95,7 @@ public:
return res; return res;
} }
data_t& operator+=(const data_t &b) data_t &operator+=(const data_t &b)
{ {
this->E += b.E; this->E += b.E;
this->E2 += b.E2; this->E2 += b.E2;
@ -116,4 +116,6 @@ public:
} }
}; };
#pragma omp declare reduction(+ : data_t : omp_out += omp_in)
#endif #endif

View File

@ -5,7 +5,7 @@
* *
* @version 1.0 * @version 1.0
* *
* @brief Functions for monte carlo simulations. * @brief Functions for Monte Carlo simulations.
* *
* @bug No known bugs * @bug No known bugs
* */ * */
@ -17,23 +17,13 @@
#include "utils.hpp" #include "utils.hpp"
#include <functional> #include <functional>
#include <string>
#include <omp.h> #include <omp.h>
#include <string>
//#define BURN_IN_TIME 12500 // #define BURN_IN_TIME 12500
#define BURN_IN_TIME 5000 #define BURN_IN_TIME 5000
#pragma omp declare reduction(+: data_t: omp_out += omp_in) namespace montecarlo {
/** @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);
/** @brief Write the expected values for each Monte Carlo cycles to file. /** @brief Write the expected values for each Monte Carlo cycles to file.
* *
* @param T Temperature * @param T Temperature
@ -41,7 +31,7 @@ int test_2x2_lattice(double tol, int max_cycles);
* @param cycles The amount of Monte Carlo cycles to do * @param cycles The amount of Monte Carlo cycles to do
* @param filename The file to write to * @param filename The file to write to
* */ * */
void monte_carlo_progression(double T, int L, int cycles, void progression(double T, int L, int cycles,
const std::string filename); const std::string filename);
/** @brief Write the expected values for each Monte Carlo cycles to file. /** @brief Write the expected values for each Monte Carlo cycles to file.
@ -52,7 +42,7 @@ void monte_carlo_progression(double T, int L, int cycles,
* @param value The value to set the elements in the lattice * @param value The value to set the elements in the lattice
* @param filename The file to write to * @param filename The file to write to
* */ * */
void monte_carlo_progression(double T, int L, int cycles, int value, void progression(double T, int L, int cycles, int value,
const std::string filename); const std::string filename);
/** @brief Estimate the probability distribution for the energy. /** @brief Estimate the probability distribution for the energy.
@ -62,7 +52,8 @@ void monte_carlo_progression(double T, int L, int cycles, int value,
* @param cycles The amount of Monte Carlo cycles to do * @param cycles The amount of Monte Carlo cycles to do
* @param filename The file to write to * @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);
/** @brief Execute the Metropolis algorithm for a certain amount of Monte /** @brief Execute the Metropolis algorithm for a certain amount of Monte
* Carlo cycles. * Carlo cycles.
@ -73,7 +64,7 @@ void pd_estimate(double T, int L, int cycles, const std::string filename);
* *
* @return data_t * @return data_t
* */ * */
data_t monte_carlo_serial(int L, double T, int cycles); 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 /** @brief Execute the Metropolis algorithm for a certain amount of Monte
* Carlo cycles in parallel. * Carlo cycles in parallel.
@ -84,7 +75,7 @@ data_t monte_carlo_serial(int L, double T, int cycles);
* *
* @return data_t * @return data_t
* */ * */
data_t monte_carlo_parallel(int L, double T, int cycles); 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. /** @brief Perform the MCMC algorithm using a range of temperatures.
* *
@ -95,9 +86,10 @@ data_t monte_carlo_parallel(int L, double T, int cycles);
* @param monte_carlo Which Monte Carlo implementation to use * @param monte_carlo Which Monte Carlo implementation to use
* @param outfile The file to write the data to * @param outfile The file to write the data to
* */ * */
void phase_transition( void
int L, double start_T, double end_T, int points_T, phase_transition(int L, double start_T, double end_T, int points_T, int cycles,
std::function<data_t(int, double, int)> monte_carlo, std::function<data_t(int, double, int, int)> monte_carlo,
std::string outfile); std::string outfile, int burn_in_time = BURN_IN_TIME);
}; // namespace montecarlo
#endif #endif

64
slurm_scripts/execute.script Executable file
View File

@ -0,0 +1,64 @@
#!/bin/bash
usage() {
>&2 cat << EOF
Usage: $0
[ -h | --help ]
[ --start-temp input ]
[ --end-temp input ]
[ --points input ]
[ --samples input ]
EOF
exit 1
}
# Defaults
start_temp=2.1
end_temp=2.4
points_temp=40
samples=1000000
array_arg=20
time_arg="0-00:30:00"
VALID_ARGS=$(getopt -o h --long help,start-temp:,end-temp:,points:,samples:,array:,time: -- "$@")
if [[ $? -ne 0 ]]; then
usage
fi
eval set -- ${VALID_ARGS}
while :
do
case "$1" in
-h | --help)
usage
shift
;;
--start-temp)
start_temp=$2
shift 2
;;
--end-temp)
end_temp=$2
shift 2
;;
--points)
points=$2
shift 2
;;
--samples)
samples=$2
shift 2
;;
--array)
array_arg=$(echo "${2// /}")
shift 2
;;
--time)
time_arg=$2
shift 2
;;
--) shift; break ;;
esac
done
sbatch --array=$array_arg --time=$time_arg ./jobs/pt.script $start_temp $end_temp $points_temp $samples

22
slurm_scripts/pt.script Executable file
View File

@ -0,0 +1,22 @@
#!/bin/bash
#SBATCH --account=ec54
#SBATCH --job-name=pt
#SBATCH --ntasks=10
#SBATCH --mem-per-cpu=1G
#SBATCH --cpus-per-task=10
set -o errexit # Exit the script on any error
set -o nounset # Treat any unset variables as an error
module --quiet purge # Reset the modules to the system default
module load Armadillo/11.4.3-foss-2022b
module load OpenMPI/4.1.5-GCC-12.3.0
# Args
start_temp=$1
end_temp=$2
points_temp=$3
samples=$4
srun ./phase_transition_mpi $start_temp $end_temp $points_temp ${SLURM_ARRAY_TASK_ID} $samples 0

View File

@ -0,0 +1,17 @@
#!/bin/bash
#SBATCH --account=ec54
#SBATCH --job-name=pt_narrow
#SBATCH --time=0-02:00:00
#SBATCH --ntasks=8
#SBATCH --mem-per-cpu=1G
#SBATCH --cpus-per-task=10
set -o errexit # Exit the script on any error
set -o nounset # Treat any unset variables as an error
module --quiet purge # Reset the modules to the system default
module load Armadillo/11.4.3-foss-2022b
module load OpenMPI/4.1.5-GCC-12.3.0
srun ./phase_transition_mpi 2.25 2.35 40 10000000

View File

@ -10,18 +10,18 @@
* @bug No known bugs * @bug No known bugs
* */ * */
#include "IsingModel.hpp" #include "IsingModel.hpp"
#include <cmath>
#include <random> #include <random>
IsingModel::IsingModel() IsingModel::IsingModel()
{ {
this->initialize_engine();
} }
IsingModel::IsingModel(int L, double T) IsingModel::IsingModel(int L, double T)
{ {
this->L = L; this->L = L;
this->T = T; this->T = T;
this->initialize_engine();
this->initialize_lattice(); this->initialize_lattice();
this->initialize_neighbors(); this->initialize_neighbors();
this->initialize_energy_diff(); this->initialize_energy_diff();
@ -33,6 +33,7 @@ IsingModel::IsingModel(int L, double T, int val)
{ {
this->L = L; this->L = L;
this->T = T; this->T = T;
this->initialize_engine();
this->lattice.set_size(this->L, this->L); this->lattice.set_size(this->L, this->L);
this->lattice.fill(val); this->lattice.fill(val);
this->initialize_neighbors(); this->initialize_neighbors();
@ -41,16 +42,20 @@ IsingModel::IsingModel(int L, double T, int val)
this->initialize_energy(); this->initialize_energy();
} }
void IsingModel::initialize_engine()
{
std::random_device rd{};
this->engine = std::mt19937{rd()};
}
void IsingModel::initialize_lattice() void IsingModel::initialize_lattice()
{ {
this->lattice.set_size(this->L, this->L); this->lattice.set_size(this->L, this->L);
std::random_device rd{};
std::mt19937 engine{rd()};
std::uniform_int_distribution<> coin_flip(0, 1); std::uniform_int_distribution<> coin_flip(0, 1);
for (size_t i = 0; i < this->lattice.n_elem; i++) for (size_t i = 0; i < this->lattice.n_elem; i++)
this->lattice(i) = 2 * coin_flip(engine) - 1; this->lattice(i) = 2 * coin_flip(this->engine) - 1;
} }
void IsingModel::initialize_neighbors() void IsingModel::initialize_neighbors()
@ -67,7 +72,7 @@ void IsingModel::initialize_neighbors()
void IsingModel::initialize_energy_diff() void IsingModel::initialize_energy_diff()
{ {
for (int i = -8; i <= 8; i += 4) { for (int i = -8; i <= 8; i += 4) {
this->energy_diff.insert({i, std::exp(-(double)i / this->T)}); this->energy_diff[i+8] = std::exp(-(double)i / this->T);
} }
} }
@ -95,9 +100,6 @@ void IsingModel::initialize_energy()
data_t IsingModel::Metropolis() data_t IsingModel::Metropolis()
{ {
std::random_device rd{};
std::mt19937_64 engine{rd()};
int ri, rj; int ri, rj;
int dE; int dE;
@ -120,7 +122,7 @@ data_t IsingModel::Metropolis()
+ this->lattice(this->neighbors(ri, DOWN), rj)); + this->lattice(this->neighbors(ri, DOWN), rj));
// Choose whether or not to accept the new configuration // Choose whether or not to accept the new configuration
if (random_number(engine) <= this->energy_diff[dE]) { if (random_number(engine) <= this->energy_diff[dE+8]) {
// Update if the configuration is accepted // Update if the configuration is accepted
this->lattice(ri, rj) *= -1; this->lattice(ri, rj) *= -1;
this->M += 2 * this->lattice(ri, rj); this->M += 2 * this->lattice(ri, rj);

View File

@ -3,9 +3,11 @@ CC=mpic++
LIBSRCS=utils.cpp testlib.cpp data_type.cpp LIBSRCS=utils.cpp testlib.cpp data_type.cpp
LIBOBJS=$(LIBSRCS:.cpp=.o) LIBOBJS=$(LIBSRCS:.cpp=.o)
LIBPROFOBJS=$(addprefix prof/, $(LIBOBJS))
CLASSSRCS=IsingModel.cpp monte_carlo.cpp CLASSSRCS=IsingModel.cpp monte_carlo.cpp
CLASSOBJS=$(CLASSSRCS:.cpp=.o) CLASSOBJS=$(CLASSSRCS:.cpp=.o)
CLASSPROFOBJS=$(addprefix prof/, $(CLASSOBJS))
INCLUDE=../include INCLUDE=../include
@ -29,16 +31,14 @@ else
PROFFLAG= PROFFLAG=
endif endif
.PHONY: clean .PHONY: clean instrument
all: main phase_transition_mpi test_suite all: main phase_transition_mpi test_suite time
#all: main #all: main
# Instrumentation using scorep for parallel analysis # Instrumentation using scorep for parallel analysis
instrument: instrument: prof/phase_transition_mpi.o $(LIBPROFOBJS) $(CLASSPROFOBJS)
scorep $(CC) -c utils.cpp -o utils.o $(CFLAGS) $(DBGFLAG) $(PROFFLAG) -I$(INCLUDE) $(OPENMP) scorep $(CC) $(LIBPROFOBJS) $(CLASSPROFOBJS) $< -o phase_transition_mpi_prof $(CFLAGS) $(DBGFLAG) $(PROFFLAG) -I$(INCLUDE) $(OPENMP)
scorep $(CC) -c main.cpp -o main.o $(CFLAGS) $(DBGFLAG) $(PROFFLAG) -I$(INCLUDE) $(OPENMP)
scorep $(CC) $(LIBOBJS) $(CLASSOBJS) main.o -o main $(CFLAGS) $(DBGFLAG) $(PROFFLAG) -I$(INCLUDE) $(OPENMP)
# Rules for executables # Rules for executables
main: main.o $(LIBOBJS) $(CLASSOBJS) main: main.o $(LIBOBJS) $(CLASSOBJS)
@ -50,10 +50,17 @@ phase_transition_mpi: phase_transition_mpi.o $(LIBOBJS) $(CLASSOBJS)
test_suite: test_suite.o $(LIBOBJS) $(CLASSOBJS) test_suite: test_suite.o $(LIBOBJS) $(CLASSOBJS)
$(CC) $^ -o $@ $(CFLAGS) $(DBGFLAG) $(PROFFLAG) -I$(INCLUDE) $(OPENMP) $(CC) $^ -o $@ $(CFLAGS) $(DBGFLAG) $(PROFFLAG) -I$(INCLUDE) $(OPENMP)
time: time.o $(LIBOBJS) $(CLASSOBJS)
$(CC) $^ -o $@ $(CFLAGS) $(DBGFLAG) $(PROFFLAG) -I$(INCLUDE) $(OPENMP)
# Rule for object files # Rule for object files
%.o: %.cpp %.o: %.cpp
$(CC) -c $^ -o $@ $(CFLAGS) $(DBGFLAG) $(PROFFLAG) -I$(INCLUDE) $(OPENMP) $(CC) -c $^ -o $@ $(CFLAGS) $(DBGFLAG) $(PROFFLAG) -I$(INCLUDE) $(OPENMP)
# Rule for instrumented object files
prof/%.o: %.cpp
scorep $(CC) -c $^ -o $@ $(CFLAGS) $(DBGFLAG) $(PROFFLAG) -I$(INCLUDE) $(OPENMP)
clean: clean:
rm *.o find . -maxdepth 2 -name "*.o" -type f -delete
rm test_suite main rm test_suite main phase_transition_mpi phase_transition_mpi_prof time

View File

@ -13,31 +13,43 @@
#include "monte_carlo.hpp" #include "monte_carlo.hpp"
#include "utils.hpp" #include "utils.hpp"
#include <csignal> /** @brief Create the data for the burn-in time for temperatures 1.0 and 2.4
#include <cstdlib> * for both unordered and ordered initial states.
#include <iostream> * */
#include <omp.h>
void create_burn_in_time_data() void create_burn_in_time_data()
{ {
// Test burn-in time // Test burn-in time
monte_carlo_progression(1.0, 20, 20000, montecarlo::progression(1.0, 20, 20000,
"output/burn_in_time/unordered_1_0.txt"); "../output/burn_in_time/unordered_1_0.txt");
monte_carlo_progression(1.0, 20, 20000, 1, montecarlo::progression(1.0, 20, 20000, 1,
"output/burn_in_time/ordered_1_0.txt"); "../output/burn_in_time/ordered_1_0.txt");
monte_carlo_progression(2.4, 20, 20000, montecarlo::progression(2.4, 20, 20000,
"output/burn_in_time/unordered_2_4.txt"); "../output/burn_in_time/unordered_2_4.txt");
monte_carlo_progression(2.4, 20, 20000, 1, montecarlo::progression(2.4, 20, 20000, 1,
"output/burn_in_time/ordered_2_4.txt"); "../output/burn_in_time/ordered_2_4.txt");
} }
/** @brief Create the data used to estimate the probability distribution
* for tempratures 1.0 anbd 2.4.
* */
void create_pd_estimate_data() void create_pd_estimate_data()
{ {
// Estimate pd // Estimate pd
pd_estimate(1.0, 20, 1000000, "output/pd_estimate/estimate_1_0.txt"); montecarlo::pd_estimate(1.0, 20, 1000000,
pd_estimate(2.4, 20, 1000000, "output/pd_estimate/estimate_2_4.txt"); "../output/pd_estimate/estimate_1_0.txt");
montecarlo::pd_estimate(2.4, 20, 1000000,
"../output/pd_estimate/estimate_2_4.txt");
} }
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);
}
/** @brief Test how much Openmp speeds up.*/
void test_parallel_speedup() void test_parallel_speedup()
{ {
// Test the openmp speedup // Test the openmp speedup
@ -46,10 +58,10 @@ void test_parallel_speedup()
int tries = 5; int tries = 5;
t0 = omp_get_wtime(); t0 = omp_get_wtime();
for (size_t i = 0; i < tries; i++) for (size_t i = 0; i < tries; i++)
monte_carlo_serial(20, 1.0, 10000); montecarlo::mcmc_serial(20, 1.0, 10000);
t1 = omp_get_wtime(); t1 = omp_get_wtime();
for (size_t i = 0; i < tries; i++) for (size_t i = 0; i < tries; i++)
monte_carlo_parallel(20, 1.0, 10000); montecarlo::mcmc_parallel(20, 1.0, 10000);
t2 = omp_get_wtime(); t2 = omp_get_wtime();
std::cout << "Time serial : " << (t1 - t0) / tries << " seconds" std::cout << "Time serial : " << (t1 - t0) / tries << " seconds"
@ -59,22 +71,29 @@ void test_parallel_speedup()
std::cout << "Speedup parallel: " << (t1 - t0) / (t2 - t1) << '\n'; std::cout << "Speedup parallel: " << (t1 - t0) / (t2 - t1) << '\n';
} }
/** @brief Create data for studying phase transition.
* */
void create_phase_transition_data() void create_phase_transition_data()
{ {
double t0, t1; double t0, t1;
t0 = omp_get_wtime(); t0 = omp_get_wtime();
// Phase transition // Phase transition
phase_transition(20, 2.1, 2.4, 40, monte_carlo_parallel, montecarlo::phase_transition(20, 2.1, 2.4, 40, 1e4,
"output/phase_transition/size_20.txt"); montecarlo::mcmc_parallel,
phase_transition(40, 2.1, 2.4, 40, monte_carlo_parallel, "../output/phase_transition/size_20.txt");
"output/phase_transition/size_40.txt"); montecarlo::phase_transition(40, 2.1, 2.4, 40, 1e4,
phase_transition(60, 2.1, 2.4, 40, monte_carlo_parallel, montecarlo::mcmc_parallel,
"output/phase_transition/size_60.txt"); "../output/phase_transition/size_40.txt");
phase_transition(80, 2.1, 2.4, 40, monte_carlo_parallel, montecarlo::phase_transition(60, 2.1, 2.4, 40, 1e4,
"output/phase_transition/size_80.txt"); montecarlo::mcmc_parallel,
phase_transition(100, 2.1, 2.4, 40, monte_carlo_parallel, "../output/phase_transition/size_60.txt");
"output/phase_transition/size_100.txt"); montecarlo::phase_transition(80, 2.1, 2.4, 40, 1e4,
montecarlo::mcmc_parallel,
"../output/phase_transition/size_80.txt");
montecarlo::phase_transition(100, 2.1, 2.4, 40, 1e4,
montecarlo::mcmc_parallel,
"../output/phase_transition/size_100.txt");
t1 = omp_get_wtime(); t1 = omp_get_wtime();
std::cout << "Time: " << t1 - t0 << std::endl; std::cout << "Time: " << t1 - t0 << std::endl;
@ -104,6 +123,9 @@ int main(int argc, char **argv)
case 4: case 4:
create_phase_transition_data(); create_phase_transition_data();
break; break;
case 5:
test_burn_in_time();
break;
default: default:
std::cout << "Not a valid option!" << std::endl; std::cout << "Not a valid option!" << std::endl;
abort(); abort();

View File

@ -11,11 +11,8 @@
* */ * */
#include "monte_carlo.hpp" #include "monte_carlo.hpp"
#include <cmath> namespace montecarlo {
#include <cstdint> void progression(double T, int L, int cycles, const std::string filename)
void monte_carlo_progression(double T, int L, int cycles,
const std::string filename)
{ {
// Set some variables // Set some variables
data_t data, tmp; data_t data, tmp;
@ -48,7 +45,7 @@ void monte_carlo_progression(double T, int L, int cycles,
ofile.close(); ofile.close();
} }
void monte_carlo_progression(double T, int L, int cycles, int value, void progression(double T, int L, int cycles, int value,
const std::string filename) const std::string filename)
{ {
// Set some variables // Set some variables
@ -108,7 +105,7 @@ void pd_estimate(double T, int L, int cycles, const std::string filename)
} }
// Code for seeing phase transitions. // Code for seeing phase transitions.
data_t monte_carlo_serial(int L, double T, int cycles) data_t mcmc_serial(int L, double T, int cycles, int burn_in_time)
{ {
data_t data; data_t data;
IsingModel model(L, T); IsingModel model(L, T);
@ -122,10 +119,12 @@ data_t monte_carlo_serial(int L, double T, int cycles)
data += model.Metropolis(); data += model.Metropolis();
} }
return data; double norm = 1. / (double)cycles;
return data * norm;
} }
data_t monte_carlo_parallel(int L, double T, int cycles) data_t mcmc_parallel(int L, double T, int cycles, int burn_in_time)
{ {
data_t data; data_t data;
#pragma omp parallel #pragma omp parallel
@ -153,12 +152,11 @@ data_t monte_carlo_parallel(int L, double T, int cycles)
return data * norm; return data * norm;
} }
void phase_transition(int L, double start, double end, int points, void phase_transition(int L, double start, double end, int points, int cycles,
std::function<data_t(int, double, int)> monte_carlo, std::function<data_t(int, double, int, int)> monte_carlo,
std::string outfile) std::string outfile, int burn_in_time)
{ {
double dt = (end - start) / (double)points; double dt = (end - start) / (double)points;
int cycles = 10000;
int N = L * L; int N = L * L;
std::ofstream ofile; std::ofstream ofile;
@ -172,7 +170,7 @@ void phase_transition(int L, double start, double end, int points,
using utils::scientific_format; using utils::scientific_format;
for (size_t i = 0; i < points; i++) { for (size_t i = 0; i < points; i++) {
temp = start + dt * i; temp = start + dt * i;
data = monte_carlo(L, temp, cycles); data = monte_carlo(L, temp, cycles, burn_in_time);
E_var = (data.E2 - data.E * data.E) / (double)N; E_var = (data.E2 - data.E * data.E) / (double)N;
M_var = (data.M2 - data.M_abs * data.M_abs) / (double)N; M_var = (data.M2 - data.M_abs * data.M_abs) / (double)N;
@ -184,3 +182,4 @@ void phase_transition(int L, double start, double end, int points,
} }
ofile.close(); ofile.close();
} }
} // namespace montecarlo

View File

@ -7,38 +7,42 @@
* *
* @brief Sweep over different temperatures and generate data. * @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 * @bug No known bugs
* */ * */
#include "data_type.hpp" #include "data_type.hpp"
#include "monte_carlo.hpp" #include "monte_carlo.hpp"
#include "utils.hpp" #include "utils.hpp"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <iterator>
#include <mpi.h> #include <mpi.h>
#include <sstream>
/** @brief The main function*/ /** @brief The main function
*
* */
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
if (argc < 5) { // Check that the number of arguments is at least 4.
std::cout << "You need at least 4 arguments" << std::endl; if (argc < 7) {
std::cout << "You need at least 6 arguments" << std::endl;
abort(); abort();
} }
// Timing variables
double t0, t1; double t0, t1;
t0 = MPI_Wtime(); t0 = MPI_Wtime();
double start = atof(argv[1]), end = atof(argv[2]);
int points = atoi(argv[3]), N;
int lattice_sizes[] = {20, 40, 60, 80, 100};
double dt = (end - start) / points;
int cycles = atoi(argv[4]);
std::ofstream ofile;
// 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;
double dt = (end - start) / points;
std::ofstream ofile;
data_t data[points]; data_t data[points];
// MPI stuff // MPI specific variables
int rank, cluster_size; int rank, cluster_size;
// Initialize MPI // Initialize MPI
@ -49,8 +53,9 @@ int main(int argc, char **argv)
MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int remainder = points % cluster_size; int remainder = points % cluster_size;
double i_start; double i_start; // What temperature to start from
int i_points; int i_points; // How many points to simulate
// Distribute temperature points // Distribute temperature points
if (rank < remainder) { if (rank < remainder) {
i_points = points / cluster_size + 1; i_points = points / cluster_size + 1;
@ -61,36 +66,42 @@ int main(int argc, char **argv)
i_start = start + dt * (i_points * rank + remainder); i_start = start + dt * (i_points * rank + remainder);
} }
// Initialize array to contains data for each temperature point
data_t i_data[i_points]; data_t i_data[i_points];
std::cout << "Rank " << rank << ": " << i_points << ',' << i_start << '\n';
for (int L : lattice_sizes) { // Simulate and save data to array
N = L * L;
for (size_t i = 0; i < i_points; i++) { for (size_t i = 0; i < i_points; i++) {
i_data[i] = monte_carlo_parallel(L, i_start + dt * i, cycles); i_data[i] = montecarlo::mcmc_parallel(L, i_start + dt * i, cycles,
burn_in_time);
} }
// Rank 0 collects all the data and copies it to the "master"
// data array.
if (rank == 0) { if (rank == 0) {
// Copy its own i_data to the data array
std::copy_n(i_data, i_points, data); std::copy_n(i_data, i_points, data);
// Collect i_data from other ranks in order and copy to data.
for (size_t i = 1; i < cluster_size; i++) { for (size_t i = 1; i < cluster_size; i++) {
if (rank < remainder) { if (rank < remainder) {
MPI_Recv((void *)i_data, MPI_Recv((void *)i_data,
sizeof(data_t) * (points / cluster_size + 1), sizeof(data_t) * (points / cluster_size + 1), MPI_CHAR,
MPI_CHAR, i, MPI_ANY_TAG, MPI_COMM_WORLD, i, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
MPI_STATUS_IGNORE);
std::copy_n(i_data, points / cluster_size + 1, std::copy_n(i_data, points / cluster_size + 1,
data + (points / cluster_size) * i); data + (points / cluster_size) * i);
} }
else { else {
MPI_Recv((void *)i_data, MPI_Recv((void *)i_data,
sizeof(data_t) * (points / cluster_size), MPI_CHAR, sizeof(data_t) * (points / cluster_size), MPI_CHAR, i,
i, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
std::copy_n(i_data, points / cluster_size, std::copy_n(i_data, points / cluster_size,
data + (points / cluster_size) * i + remainder); data + (points / cluster_size) * i + remainder);
} }
} }
// Write everything from data to file
std::stringstream outfile; std::stringstream outfile;
outfile << "output/phase_transition/size_" << L << ".txt"; outfile << "../output/phase_transition/mpi/size_" << L << ".txt";
utils::mkpath(utils::dirname(outfile.str())); utils::mkpath(utils::dirname(outfile.str()));
ofile.open(outfile.str()); ofile.open(outfile.str());
@ -112,11 +123,11 @@ int main(int argc, char **argv)
} }
ofile.close(); ofile.close();
} }
// For all other ranks, send the data to rank 0
else { else {
MPI_Send(i_data, i_points * sizeof(data_t), MPI_CHAR, 0, rank, MPI_Send(i_data, i_points * sizeof(data_t), MPI_CHAR, 0, rank,
MPI_COMM_WORLD); MPI_COMM_WORLD);
} }
}
t1 = MPI_Wtime(); t1 = MPI_Wtime();

View File

@ -12,8 +12,6 @@
#include "IsingModel.hpp" #include "IsingModel.hpp"
#include "testlib.hpp" #include "testlib.hpp"
#include <fstream>
#define EPS_2 (-2 * std::sinh(8.)) / (std::cosh(8.) + 3) #define EPS_2 (-2 * std::sinh(8.)) / (std::cosh(8.) + 3)
#define MAG_2 (std::exp(8.) + 1) / (2 * (cosh(8.) + 3)) #define MAG_2 (std::exp(8.) + 1) / (2 * (cosh(8.) + 3))
@ -29,7 +27,7 @@
* */ * */
class IsingModelTest { class IsingModelTest {
public: public:
/** @brief Test That initializing works as intended. /** @brief Test that initializing works as intended.
* */ * */
void test_init_functions() void test_init_functions()
{ {
@ -84,15 +82,9 @@ public:
int arr[]{0, 0, 0, 0}; int arr[]{0, 0, 0, 0};
// Loop through cycles // Loop through cycles
//std::ofstream ofile;
//ofile.open("output/test_2x2.txt");
while (cycles++ < max_cycles) { while (cycles++ < max_cycles) {
data += test.Metropolis(); data += test.Metropolis();
tmp = data / cycles; 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) 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(MAG_2, tmp.M_abs / n_spins, tol)
&& testlib::close_to(CV_2, (tmp.E2 - tmp.E * tmp.E) / (T * T) && testlib::close_to(CV_2, (tmp.E2 - tmp.E * tmp.E) / (T * T)
@ -102,44 +94,6 @@ public:
return cycles; 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; return 0;
} }
}; };
@ -150,18 +104,23 @@ int main()
IsingModelTest test; IsingModelTest test;
test.test_init_functions(); test.test_init_functions();
int res = 0; int res = 0;
int tmp; int tmp;
for (size_t i=0; i < 1000; i++) { int iterations = 10000;
int accepted_values = 0;
// Run through the test multiple times to get a better estimate.
for (size_t i=0; i < iterations; i++) {
tmp = test.test_2x2_lattice(1e-2, 1e5); tmp = test.test_2x2_lattice(1e-2, 1e5);
if (tmp == 0) { if (tmp == 0) {
std::cout << "not enough cycles\n"; continue;
break;
} }
accepted_values++;
res += tmp; res += tmp;
} }
std::cout << "Res: " << res / 1000 << std::endl; std::cout << "Res: " << res / accepted_values << std::endl;
return 0; return 0;
} }

68
src/time.cpp Normal file
View File

@ -0,0 +1,68 @@
/** @file time.cpp
*
* @author Cory Alexander Balaton (coryab)
* @author Janita Ovidie Sandtrøen Willumsen (janitaws)
*
* @version 0.1
*
* @brief Timing various things
*
* @bug No known bugs
* */
#include "data_type.hpp"
#include "monte_carlo.hpp"
#include "utils.hpp"
#include <omp.h>
#include <ostream>
void time_lattice_sizes()
{
std::string outfile = "output/timing/lattice_sizes.txt";
std::ofstream ofile;
int lattice_sizes[] = {20, 40, 60, 80, 100};
utils::mkpath(utils::dirname(outfile));
ofile.open(outfile);
double t0, t1;
for (int L : lattice_sizes) {
t0 = omp_get_wtime();
montecarlo::phase_transition(L, 2.1, 2.4, 40, 100000,
montecarlo::mcmc_parallel,
"output/garbage/null.txt");
t1 = omp_get_wtime();
ofile << utils::scientific_format(L) << ','
<< utils::scientific_format(t1 - t0) << '\n';
}
ofile.close();
}
void time_sample_sizes()
{
std::string outfile = "output/timing/sample_sizes.txt";
std::ofstream ofile;
int sample_sizes[] = {1000, 10000, 100000};
utils::mkpath(utils::dirname(outfile));
ofile.open(outfile);
double t0, t1;
for (int samples : sample_sizes) {
t0 = omp_get_wtime();
montecarlo::phase_transition(20, 2.1, 2.4, 40, samples,
montecarlo::mcmc_parallel,
"output/garbage/null.txt");
t1 = omp_get_wtime();
ofile << utils::scientific_format(samples) << ','
<< utils::scientific_format(t1 - t0) << '\n';
}
ofile.close();
}
int main()
{
time_lattice_sizes();
time_sample_sizes();
return 0;
}