/*  Monte-Carlo simulation code for statistical physics
    Copyright (C) 2001-2004  Sylvain Reynal
    
    Département de Physique
    Ecole Nationale Supérieure de l'Electronique et de ses Applications (ENSEA)
    6, avenue du Ponceau,    
    F-95014 CERGY CEDEX

    et
    
    Laboratoire de Physique Théorique et Modélisation (LPTM)
    Université de Cergy-Pontoise - Site de Neuville
    F-95031 CERGY CEDEX
    
	
    Tel : 00 +33 130 736 245
    Fax : 00 +33 130 736 667
    e-mail : reynal@ensea.fr
    web page : http://www.ensea.fr/staff/reynal/
*/

package fr.ensea.montecarlo.canonical;

import java.io.*;
import java.awt.Color;
import java.text.*;

import fr.ensea.Localizer;
import fr.ensea.montecarlo.model.*;
import fr.ensea.montecarlo.data.*;
import fr.ensea.montecarlo.canonical.*;
import fr.ensea.montecarlo.misc.*;

/**
 * Algorithme de Montecarlo pour le modèle d'Ising AF
 */
public class AFIsingMetropolis extends AbstractMetropolis  {

	private AFIsingLattice lattice;
	
	private double[] probas; // tableau contenant les probabilités d'acceptance lorsque dE <= 0
	// (les variations négatives donnant de toute façon une probabilité égale 1, il est inutile de les précalculer)
	// exemple :
	//       3                   3
	//   1   2   2     =>    1   3   2        donne dE = -1
	//       3                   3
	//
	
	/**
	 * Initialise un nouvel algorithm de Montecarlo attaché au réseau fourni en paramètre.
	 * @param energySamples liste pour les mesures de l'énergie
	 * @param magnetizationSamples liste pour les mesures de l'aimantation
	 * @param lattice le réseau à simuler
	 * @param kT la température par défaut
	 */
	public AFIsingMetropolis(AFIsingLattice lattice, SamplesBag bag, double kT) {
		super(bag, kT);
		this.lattice = lattice;
	}

	/**
	 * Modifie la température courante et remet les compteurs à zéro.
	 */
	public synchronized void setTemperature(double kT){
		super.setTemperature(kT);
		this.probas=new double[5];
		if (kT>0) for (int dE=1; dE<5; dE++) probas[dE] = Math.exp(-(double)dE/kT);
		// sinon, si kT=0, les probabilités sont nulles pour une mise-à-jour avec augmentation de l'énergie
	}
	
	/**
	 * Réalise un sweep de l'ensemble du réseau, i.e. tente de mettre à jour L*L spins.
	 */
	public void sweep(){

		int row,col, valeurVoisin, dE;
		final int L = lattice.size;
		final int L2 = lattice.size2;

		for (int pas=0; pas < L2; pas++){

			attemptedMoves++;

			// on choisit au hasard un spin à modifier parmi L^2 :
			row = (int)(L * createRandomNumber());
			col = (int)(L * createRandomNumber());

			dE = lattice.getEnergyChange(row,col); // basculement spin (row,col)

			if (DEBUG) {
				System.out.println(lattice.toString());
				System.out.println("row=" + row);
				System.out.println("col=" + col);
				System.out.println("dE=" + dE);
				System.out.println("proba=" + (dE > 0 ? probas[dE] : 1.0));
			}

			// attempt move:
			if (dE <= 0.0 || createRandomNumber() <= probas[dE]){
				acceptedMoves++;
				lattice.toggleSpin(row,col);
				lattice.energy += dE;
				if (DEBUG) System.out.println("Acceptée !\n"+lattice.toString());
			}
			if (DEBUG) {
				System.out.println("=======================================================");
				pause();
			}
		}
		samplesBag.addEnergySample(lattice.getEnergy()/lattice.size2);
		samplesBag.addMagnetizationSample(lattice.getMagnetization());
	}

	///////////////////////////////////////////////////////////
	/// Statistiques
	///////////////////////////////////////////////////////////

	
	
	/////////////////////////////////////////////////////////////////////////////////
	// TEST
	/////////////////////////////////////////////////////////////////////////////////

}

