% MC_NVT_sim1.m
% This MATLAB program performs NVT Monte Carlo
% simulation of a single particle in a potential
% field U(x).
% The inputs are:
% N_eq, the number of equilibration MC moves
% N_samples, the number of samples
% freq_sample, the number of MC steps between samples
% dx_max, the max. displacement during a MC move
% K. Beers. MIT ChE. 10/28/03
function iflag_main = MC_NVT_sim1(N_eq,N_samples,freq_sample,dx_max);
iflag_main = 0;

k_sp = 1;  % set spring constant value
kb_T = 1;  % value of thermal energy

% First, perform an equilirbiation run
x = 0;  % set initial state
U_pot = 0.5*k_sp*x^2;  % current poential energy
prob = exp(-U_pot / kb_T);  % calculate Boltzmann weight
for iter_MC = 1:N_eq    
    % propose MC move (random displacement)
    rand_var = rand;
    dx_rand = dx_max*(rand_var - 0.5);
    x_new = x + dx_rand;  % proposed new state
    % calculate potential energy and Boltzmann weight of new state
    U_pot_new = 0.5*k_sp*x_new^2;
    prob_new = exp(-U_pot_new / kb_T);    
    % calculate acceptance probability from Metropolis rule
    alpha = min(1, prob_new/prob);    
    % check to see if we accept MC move
    rand_var = rand;
    if(rand_var <= alpha)  % accept move
        x = x_new;
        U_pot = U_pot_new;  prob = prob_new;
    end    
end    

% ----- Now, we perform sampling run.
% allocate space to store sampled values
x_traj = zeros(1,N_samples);  count_samples = 0;
num_MC_steps = round(1.1*N_samples*freq_sample);
% perform sampling MC simulation
for iter_MC=1:num_MC_steps
    % check to see if it is time to report results
    if(~mod(iter_MC,freq_sample))
        count_samples = count_samples + 1;
        x_traj(count_samples) = x;
    end    
    % end simulation when # of samples is performed
    if(count_samples >= N_samples)
        break;
    end
    % propose MC move (random displacement)
    rand_var = rand;
    dx_rand = dx_max*(rand_var - 0.5);
    x_new = x + dx_rand;  % proposed new state    
    % calculate potential energy and Boltzmann weight of new state
    U_pot_new = 0.5*k_sp*x_new^2;
    prob_new = exp(-U_pot_new/kb_T);    
    % calculate acceptance probability from Metropolis rule
    alpha = min(1, prob_new/prob);    
    % check to see if we accept MC move
    rand_var = rand;
    if(rand_var <= alpha)  % accept move
        x = x_new;
        U_pot = U_pot_new;  prob = prob_new;
    end    
end

% Now, plot sampled MC trajectory
figure;  plot(x_traj);
xlabel('MC sample');  ylabel('x');
title('NVT-MC trajectory of particle in 1-D quadratic energy well');

% Now, we compute the histogram of the trajectory, and plot this in
% comparison to the Boltzmann distribution with kT = 1
figure; num_bins = 50;
[n_hist,x_hist] = hist(x_traj,num_bins);
var1 = trapz(x_hist,n_hist);  n_hist = n_hist ./ var1;
bar(x_hist,n_hist);
x_plot = linspace(-3,3,500);  V_plot = 0.5*k_sp.*(x_plot.^2);
kb_T = 1;  p_Boltzmann = exp(-V_plot/kb_T);
var1 = trapz(x_plot,p_Boltzmann);  p_Boltzmann = p_Boltzmann ./ var1;
hold on;  plot(x_plot,p_Boltzmann);
xlabel('x');  ylabel('p(x)');
title('NVT probability distribution of particle in 1-D quadratic energy well');
% add text with simulation parameters
gtext({  ['N_{eq} = ', int2str(N_eq)] , ...
    ['N_{samples} = ', int2str(N_samples)], ...
    ['sampling freq = ', int2str(freq_sample)], ...
    ['\Deltax_{max} = ', num2str(dx_max)] } );
    
iflag_main = 1;
return;
