# First, if you haven't SWIGGed your code yet, you'll need to use a # newer version of mine. Copy my new version of MDSolution into your directory, # replacing the old one. (I hadn't put in the shifted energy when # I added the cutoff!) Swig the new code. # Second, make sure that Exceed is running import sys sys.path.append("K:\\Simulations\\xmgr") import xmgr graph = xmgr.WindowsXMGRInterface() graph.StartXMGR() import math import Numeric # Efficient numerical arrays package: NumPy SinX = Numeric.array([[0.0, math.sin(0.0)], [1.5708, math.sin(1.5708), [3.1416, math.sin(3.1416)]]) SinX # Just an array graph.Plot(SinX) X = Numeric.arrayrange(0, 3.1416, 0.31416) Y = Numeric.sin(X) # Fast array version # [X,Y] is transpose of array we need SinX = Numeric.transpose([X,Y]) sys.path.append("K:\\Simulations\\MDPython") # Your path here import MD atoms = MD.Atoms() rand = MD.Rand() nonOverlapRandom = MD.RandomPositionStrategy(1.0,rand) nonOverlapRandom.Move(atoms) thermalize = MD.ThermalizeVelocityStrategy(1,rand) thermalize.Move(atoms) dt = 0.01 verlet = MD.UpdateStrategy(dt) # Plot trajectory of atom #3 x3 = Numeric.zeros((100,2), Numeric.Float) # Allocate array for i in xrange(Numeric.shape(x3)[0]): for j in xrange(10): verlet.Move(atoms) x3[i][0] = atoms.X(3,0) x3[i][1] = atoms.X(3,1) x3 graph.Plot(x3) # Notice, the periodic boundary conditions make for ugly trajectories # Plot energy versus time times = Numeric.arrayrange(0,10,dt) e = Numeric.zeros(len(times), Numeric.Float) # Just to allocate space for i in xrange(len(times)): e[i] = atoms.TotalEnergy() verlet.Move(atoms) e_vs_t = Numeric.transpose([times,e]) graph.SendCommand("flush") graph.Plot(e_vs_t) verlet.SetDt(0.001) e2 = Numeric.zeros(len(times), Numeric.Float) for i in xrange(len(times)): for j in xrange(10): verlet.Move(atoms) e2[i] = atoms.TotalEnergy() e2_vs_t = Numeric.transpose([times, e2]) graph.Plot(e_vs_t, e2_vs_t) # Zoom in with the magnifying glass to see the fluctuations # Measuring the Specific Heat # Copy your EnergyObserver.py file into a new file, KineticEnergyObserver.py # Edit it to calculate the mean and fluctuations in the kinetic energy # Also, define functions which # calculate the temperature from the kinetic energy # Kinetic Energy = nAtoms * DIMENSION * kT/2 # (assume Boltzmann's constant k = 1) # calculate the total specific heat C from the fluctuations in the kinetic energy # <(Delta T)^2> = k T^2 [ 2 / (DIMENSION * k * numAtoms) - 1/C] # Observer the kinetic energy while storing it import KineticEnergyObserver keObs = KineticEnergyObserver.KineticEnergyObserver() # Test your new routine: if it isn't right, edit, reload(KineticEnergyObserver), and repeat reload(KineticEnergyObserver) keObs = KineticEnergyObserver.KineticEnergyObserver() atoms.KineticEnergy() keObs.Update(atoms) keObs.numKE keObs.KEtot keObs.KEbar() keObs.KineticTemperature() verlet.Move(atoms) keObs.Update(atoms) keObs.SpecificHeatPerAtom() # Average over time interval of 100, using every tenth time step keObs.Reset() dt = 0.01 verlet.SetDt(dt) times = Numeric.arrayrange(0,100,10*dt) ke = Numeric.zeros(len(times), Numeric.Float) for i in xrange(len(times)): for j in xrange(10): verlet.Move(atoms) ke[i] = atoms.KineticEnergy() keObs.Update(atoms) keObs.KineticTemperature() keObs.SpecificHeatPerAtom() ke_vs_t = Numeric.transpose([times, ke]) graph.SendCommand("flush") graph.Plot(ke_vs_t) # Let's look at the temperature-dependent specific heat # Make a few more atoms atoms = MD.Atoms(50) nonOverlapRandom.Move(atoms) # Define a couple of functions for averaging def Relax(atoms, nRelax, nSkip): for i in xrange(nRelax): for j in xrange(nSkip): verlet.Move(atoms) thermalize.Move(atoms) # Allows thermalization with heat bath def KEAve(atoms, nAverage, nSkip): keObs.Reset() for i in xrange(nAverage): for j in xrange(nSkip): verlet.Move(atoms) keObs.Update(atoms) # Specific heat at high temperature thermalize.SetTemperature(3.0) Relax(atoms,100,10) KEAve(atoms,100,10) keObs.KineticTemperature() keObs.SpecificHeatPerAtom() # Should be kT/2 per important DOF: how many DOF per atom? # Quench slowly to zero temperature coolingTemperatures = Numeric.arrayrange(1, 0, -0.1) conjugateGradient = MD.CGStrategy() # Before conjugate gradient, quench slowly so atoms # don't get caught in bad metastable states def Quench(atoms): for i in xrange(len(coolingTemperatures)): thermalize.SetTemperature(coolingTemperatures[i]) thermalize.Move(atoms) Relax(atoms,10,10) print atoms.TotalEnergy() conjugateGradient.Move(atoms) thermalize.SetTemperature(0.0) thermalize.Move(atoms) print atoms.TotalEnergy() # The best energy I've gotten was -119.4 # You may want to shake it around some if you're energy is much higher # What's the specific heat per atom at low temperatures? thermalize.SetTemperature(0.05) Relax(atoms,100,10) KEAve(atoms,100,10) keObs.KineticTemperature() # Not quite the same? keObs.SpecificHeatPerAtom() # Should be 1/2 kT per DOF: how many DOF per atom? # Now, let's measure the specific heat on heating heatingTemperatures = Numeric.arrayrange(0.1,1,0.1) T = Numeric.zeros(len(heatingTemperatures), Numeric.Float) C = Numeric.zeros(len(T), Numeric.Float) def Heat(atoms): for i in xrange(len(heatingTemperatures)): thermalize.SetTemperature(heatingTemperatures[i]) thermalize.Move(atoms) Relax(atoms,10,10) KEAve(atoms, 100, 10) T[i] = keObs.KineticTemperature() C[i] = keObs.SpecificHeatPerAtom() print i, T[i], C[i] C_vs_T = Numeric.transpose([T,C]) graph.Plot(C_vs_T) # Quench and heat a few times. You'll find large fluctuations # from one run to the next. What do you think might be happening? # Try higher temperatures thermalize.SetTemperature(10.0)
Statistical Mechanics: Entropy, Order Parameters, and Complexity,
now available at
Oxford University Press
(USA,
Europe).