/* Monte-Carlo simulation code for statistical physics Copyright (C) 2001-2005 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.data; import fr.ensea.Version; import fr.ensea.Localizer; import fr.ensea.chart.*; import fr.ensea.montecarlo.*; import fr.ensea.montecarlo.multicanonical.*; import fr.ensea.montecarlo.model.*; import fr.ensea.montecarlo.misc.*; import java.awt.*; import java.awt.event.*; import java.applet.Applet; import java.text.NumberFormat; import java.util.Locale; /** * Holds thermal averages computed from simulation measurements, as well as graphs to display them. */ public class ThermalAveragesSet implements ActionListener { // --- cached from MCApplet --- private AbstractApplet controller; private SamplesBag samplesBag; private boolean isRGActive; private ILattice lattice; // --- curves --- public DefaultCurve2D meanEnergyVsKTCurve; // public DefaultCurve2D meanMagVsKTCurve; // public DefaultCurve2D susceptibilityVsKTCurve; // chi // RG only: private DefaultCurve2D meanEnergyRGVsKT; // // --- plot2D --- private Plot2D graphMeanEnergyVsKT; // and possibly if applicable private Plot2D graphMeanMagVsKT; // private Plot2D graphFluctuations; // chi private FreeEnergyPanel freeEnergyPanel; // --- widgets --- private Button newAverageCurvesBUT, addAveragesBUT,clearAveragesBUT; // --- misc --- private int averagesSetIdx=0; // index of current averages set (i.e. rightmost charts) private final static int MAX_averagesSetIdx = 8; public ThermalAveragesSet(ILattice lattice, SamplesBag samplesBag, boolean isRGActive){ this.lattice = lattice; this.samplesBag = samplesBag; this.isRGActive = isRGActive; } // --- canonical --- /** * Sauve les moyennes statistiques pour la température courante dans le graphe "/". */ public void storeSimulationResults(double kT){ if (samplesBag.isEmpty()) return; double meanE = samplesBag.computeEnergyMean(); double meanM = samplesBag.computeMagnetizationMean(); double varM = samplesBag.computeMagnetizationVariance(meanM); double chi = lattice.getSpinCount() * varM / kT; meanEnergyVsKTCurve.addXY(kT,meanE); if (isRGActive){ double meanERG = samplesBag.computeEnergyRGMean(); meanEnergyRGVsKT.addXY(kT,meanERG); } meanMagVsKTCurve.addXY(kT,meanM); susceptibilityVsKTCurve.addXY(kT, chi); updateGUI(); //showStatus(Localizer.get("NewPointAdded")+"=" + kT); } // --- multicanonical --- public void storeSimulationResults(WLSimulationThread algoThread){ if (samplesBag.isEmpty()) return; double[] kTarray = algoThread.getKTList(); int VOL = lattice.getSpinCount(); WLDOSHistogram histo = algoThread.getWLDOSHistogram(); new MomentsReweighter(histo, samplesBag, this, kTarray, VOL); // fill meanEnergyVsKTCurve etc... in place //updateGUI(); // done from MomentsReweighter // free energy: if (freeEnergyPanel==null) freeEnergyPanel = new FreeEnergyPanel(kTarray); else freeEnergyPanel.setKTList(kTarray); freeEnergyPanel.backupEnergyHistogram(); // because it will be reset by WLSimulationThread freeEnergyPanel.updateGUI(); // force recomputing F(kT,E) } // --- both --- public void addNewAveragesSet(){ //if (meanEnergyVsKTCurve!=null && meanEnergyVsKTCurve.size()==0) return; // no data => no need to add a new set averagesSetIdx++; if (averagesSetIdx==MAX_averagesSetIdx) { graphMeanEnergyVsKT.removeCurves(); graphMeanMagVsKT.removeCurves(); graphFluctuations.removeCurves(); averagesSetIdx=1; } String idxStr="["+Integer.toString(averagesSetIdx)+"]"; meanEnergyVsKTCurve = new DefaultCurve2D(); if (isRGActive) meanEnergyRGVsKT = new DefaultCurve2D(); meanMagVsKTCurve = new DefaultCurve2D(); susceptibilityVsKTCurve = new DefaultCurve2D(); Color col1 = MCApplet.PREDEFINED_COLORS[averagesSetIdx%MCApplet.PREDEFINED_COLORS.length]; //Color col2 = PREDEFINED_COLORS[(averagesSetIdx+MAX_averagesSetIdx)%PREDEFINED_COLORS.length]; graphMeanMagVsKT.addCurve(meanMagVsKTCurve, idxStr, col1, DecoratedCurve2D.DOTS_LINES); graphMeanEnergyVsKT.addCurve(meanEnergyVsKTCurve, idxStr, col1, DecoratedCurve2D.DOTS_LINES); if (isRGActive) graphMeanEnergyVsKT.addCurve(meanEnergyRGVsKT, idxStr+"RG", col1, DecoratedCurve2D.LINES); graphFluctuations.addCurve(susceptibilityVsKTCurve, idxStr, col1, DecoratedCurve2D.DOTS_LINES); } public void resetAveragesGraphs(){ graphMeanEnergyVsKT.removeCurves(); graphMeanMagVsKT.removeCurves(); graphFluctuations.removeCurves(); averagesSetIdx=0; addNewAveragesSet(); } public void removeLastAverageSet(){ graphMeanEnergyVsKT.removeLastCurve(); // if (isRGActive) graphMeanEnergyVsKT.removeLastCurve(); // graphMeanMagVsKT.removeLastCurve(); graphFluctuations.removeLastCurve(); averagesSetIdx--; if (averagesSetIdx<0) averagesSetIdx=0; //System.out.println("Remove: averagesSetIdx="+averagesSetIdx); if (averagesSetIdx==0) addNewAveragesSet(); } // --- UI --- /** * Create a pane containing graphs of thermodynamic averages */ public Panel createUI(AbstractApplet applet){ this.controller = applet; Dimension graphPreferredSize = new Dimension(applet.getSize().width/4, applet.getSize().height/4); this.graphMeanEnergyVsKT = new Plot2D(AbstractApplet.PANELS_BACKGROUND, AbstractApplet.PLOT2D_FRAME_COLOR2, AbstractApplet.PLOT2D_GRID_COLOR); graphMeanEnergyVsKT.setForeground(Color.white); // title, keys graphMeanEnergyVsKT.setTitle(" vs. kT"); // no x-axis label //if (lattice instanceof AFIsingLattice) graphMeanEnergyVsKT.yAxis().setManualAxisBounds(-0.1,2.1); //else if (lattice instanceof PottsLattice) graphMeanEnergyVsKT.yAxis().setManualAxisBounds(-2.1,0.1); graphMeanEnergyVsKT.setPreferredSize(graphPreferredSize); this.graphMeanMagVsKT = new Plot2D(AbstractApplet.PANELS_BACKGROUND, AbstractApplet.PLOT2D_FRAME_COLOR2, AbstractApplet.PLOT2D_GRID_COLOR); graphMeanMagVsKT.setForeground(Color.white); // title, keys graphMeanMagVsKT.setTitle(" vs. kT"); // no x-axis label //graphMeanMagVsKT.yAxis().setManualAxisBounds(-0.1,1.1); graphMeanMagVsKT.setPreferredSize(graphPreferredSize); this.graphFluctuations = new Plot2D(AbstractApplet.PANELS_BACKGROUND, AbstractApplet.PLOT2D_FRAME_COLOR2, AbstractApplet.PLOT2D_GRID_COLOR); //graphFluctuations.addCurve(susceptibilityVsKTCurve, "chi", Color.cyan, Plot2D.DOTS_LINES); graphFluctuations.setForeground(Color.white); // title, keys graphFluctuations.setTitle(Localizer.get("Susceptibility")+" vs. kT"); graphFluctuations.setPreferredSize(graphPreferredSize); clearAveragesBUT=new Button("-"); newAverageCurvesBUT=new Button("+"); if (applet instanceof MCApplet) addAveragesBUT=new Button(Localizer.get("AddPoint")); else addAveragesBUT=new Button("F(kT,E)"); // positionnement: GridBagLayout gridbag = new GridBagLayout(); GridBagConstraints c = new GridBagConstraints(); Panel graphPanel = new Panel(gridbag); c.fill = GridBagConstraints.BOTH; // resizing beh. c.weightx = 1.0; c.weighty = 1.0; c.gridwidth = 1; c.gridheight = 1; c.gridx=0; gridbag.setConstraints(clearAveragesBUT,c); graphPanel.add(clearAveragesBUT); gridbag.setConstraints(newAverageCurvesBUT,c); graphPanel.add(newAverageCurvesBUT); c.gridheight = GridBagConstraints.REMAINDER; gridbag.setConstraints(addAveragesBUT,c); graphPanel.add(addAveragesBUT); c.gridheight = GridBagConstraints.REMAINDER; c.gridx=GridBagConstraints.RELATIVE; gridbag.setConstraints(graphMeanEnergyVsKT,c); graphPanel.add(graphMeanEnergyVsKT); gridbag.setConstraints(graphMeanMagVsKT,c); graphPanel.add(graphMeanMagVsKT); gridbag.setConstraints(graphFluctuations,c); graphPanel.add(graphFluctuations); // --- listeners --- clearAveragesBUT.addActionListener(this); newAverageCurvesBUT.addActionListener(this); addAveragesBUT.addActionListener(this); clearAveragesBUT.addMouseMotionListener(new StatusHelpMouseHandler(applet, clearAveragesBUT.getLabel()+": "+Localizer.get("HelpStatus3"))); newAverageCurvesBUT.addMouseMotionListener(new StatusHelpMouseHandler(applet, clearAveragesBUT.getLabel()+": "+Localizer.get("HelpStatus4"))); addAveragesBUT.addMouseMotionListener(new StatusHelpMouseHandler(applet, clearAveragesBUT.getLabel()+": "+Localizer.get("HelpStatus5"))); graphMeanEnergyVsKT.addMouseListener(new GraphMouseHandler(applet, this.graphMeanEnergyVsKT)); graphMeanEnergyVsKT.addMouseMotionListener(new StatusHelpMouseHandler(applet, graphMeanEnergyVsKT.getTitle()+": "+Localizer.get("HelpStatus1"))); graphMeanMagVsKT.addMouseListener(new GraphMouseHandler(applet, this.graphMeanMagVsKT)); graphMeanMagVsKT.addMouseMotionListener(new StatusHelpMouseHandler(applet, graphMeanMagVsKT.getTitle()+": "+Localizer.get("HelpStatus1"))); graphFluctuations.addMouseListener(new GraphMouseHandler(applet, this.graphFluctuations)); graphFluctuations.addMouseMotionListener(new StatusHelpMouseHandler(applet, graphFluctuations.getTitle()+": "+Localizer.get("HelpStatus1"))); return graphPanel; } public void actionPerformed(ActionEvent evt){ if (evt.getSource() == clearAveragesBUT){ //resetAveragesGraphs(); removeLastAverageSet(); } else if (evt.getSource() == newAverageCurvesBUT){ addNewAveragesSet(); } else if (evt.getSource() == addAveragesBUT){ // manually add a new set of , and chi /* if (!controller.algoThread.isTemperatureSweep()) { controller.algoThread.kill(); controller.startStopBUT.setLabel(Localizer.get("Start")); } */ if (controller instanceof MCApplet){ double kT = ((MCApplet)controller).getAlgorithm().getTemperature(); storeSimulationResults(kT); controller.showStatus(Localizer.get("NewPointAdded")+"=" + kT); } else if (controller instanceof WLApplet){ if (freeEnergyPanel==null) { controller.showStatus(Localizer.get("NotReadyYet")); return; } freeEnergyPanel.setVisible(!freeEnergyPanel.isVisible()); } } } public void updateGUI(){ graphMeanEnergyVsKT.dataChanged(); graphMeanMagVsKT.dataChanged(); graphFluctuations.dataChanged(); } //////////////////////////////// MuCa only //////////////////////// class FreeEnergyPanel extends Frame implements AdjustmentListener{ DefaultCurve2D freeEnergyCurve; // F(kT,E) Plot2D freeEnergyGraph; Scrollbar kTSB; Label kTLBL; double[] binHeights; double[] kTarray; public FreeEnergyPanel(double[] kTarray){ super("Free energy"); this.kTarray = kTarray; setLayout(new BorderLayout(5,5)); freeEnergyCurve = new DefaultCurve2D(); freeEnergyGraph = new Plot2D(AbstractApplet.PANELS_BACKGROUND, AbstractApplet.PLOT2D_FRAME_COLOR2, AbstractApplet.PLOT2D_GRID_COLOR); freeEnergyGraph.addCurve(freeEnergyCurve, "", AbstractApplet.PLOT2D_CURVE_COLOR1, DecoratedCurve2D.DOTS); freeEnergyGraph.setForeground(Color.white); // title, keys freeEnergyGraph.setTitle("F(kT,E)"); // no x-axis label freeEnergyGraph.setXaxisLabel("E"); //graphMeanMagVsKT.yAxis().setManualAxisBounds(-0.1,1.1); freeEnergyGraph.setPreferredSize(new Dimension(400,400)); add(freeEnergyGraph,"Center"); Panel southPane = new Panel(); int defIdx = kTarray.length/2; kTSB = new Scrollbar(Scrollbar.HORIZONTAL, defIdx, 1, 0, kTarray.length); kTSB.addAdjustmentListener(this); southPane.add(kTSB); kTLBL = new Label("kT="+kTarray[defIdx]); southPane.add(kTLBL); add(southPane,"South"); setSize(400,400); backupEnergyHistogram(); } public void setKTList(double[] kTarray){ this.kTarray=kTarray; kTSB.setMaximum(kTarray.length); } public void adjustmentValueChanged(AdjustmentEvent evt){ if (evt.getSource() == kTSB) updateGUI(); } public void backupEnergyHistogram(){ WLDOSHistogram SE = ((WLSimulationThread)controller.getSimulationThread()).getWLDOSHistogram(); if (SE != null){ this.binHeights = new double[SE.xAxis().bins()]; for (int bin=0; binkTarray.length-1) i=kTarray.length-1; double kT=kTarray[i]; kTLBL.setText("kT="+kT); updateFreeEnergy(kT); } private void updateFreeEnergy(double kT){ if (binHeights==null) backupEnergyHistogram(); freeEnergyCurve.clear(); // remove all points WLDOSHistogram SE = ((WLSimulationThread)controller.getSimulationThread()).getWLDOSHistogram();// only used for w(E), not N(E) MuCaWeighter weighter = new MuCaWeighter(kT, SE); for (int bin=0; bin < SE.xAxis().bins(); bin++){ // for each energy level // Z(kT,E) = N(E)*w(E) = N(E) * exp(Emu(E)/kT0 - E/kT - K) (correct up to a multiplicative constant) double E = SE.binCenter(bin); double WE = weighter.getWeight(E); double NE = binHeights[bin]; // !!! bin height from backup histogram (because SE may have been reset in the meantime) double Z = NE * WE; double F = -Math.log(Z); int VOL = lattice.getSpinCount(); //System.out.println("F("+(E/VOL)+")="+F); if (!Double.isNaN(F) && !Double.isInfinite(F)) freeEnergyCurve.addXY(E/VOL,F); } freeEnergyGraph.dataChanged(); } } }