Volume optimization of Ag

Volume optimization is a simple case of an aggregation property. This example shows how to set up the inputs for the data points with the help of a template and how to determine the optimal volume by fitting the corresponding total energies.

We are going to use a simple inputxml template to generate the input files for the total-energies calculations.

inputtemplate.png

Experiment description

In order to vary the scale of the unit cell by +/- 5% we need a description of our experiment:

File: scale.xml

<?xml version="1.0" encoding="UTF-8" ?>
 <experiment>
    <set unicellscaling="0.95" path="unicellscaling_0.95"/>
    <set unicellscaling="0.975" path="unicellscaling_0.975" />
    <set unicellscaling="1" path="unicellscaling_1"/>
    <set unicellscaling="1.025" path="unicellscaling_1.025"/>
    <set unicellscaling="1.05" path="unicellscaling_1.05"/>
 </experiment>

This quasi format is referred to as experiment-list and used in various other examples.

The template

In order to generate the input files we use XSLT templating-tools. The corresponding template:

File:evTemplate.xsl

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" />
<xsl:template match="/">
 
<!-- Authors: chm, jus, sag -->
 
<!-- Loop over all elements named "set" from reference xml-file -->
<xsl:for-each select = "/experiment/set">
<xsl:variable name="path">
<xsl:value-of select="@path"/>
<xsl:text>/imput.xml</xsl:text>
</xsl:variable> 
 
 <!-- Write document at Path $path -->
 <xsl:document href="{$path}" method="xml" indent="yes">
 <xsl:comment>
 This file is generated with XSLTPROC using a template file and a reference file
</xsl:comment>
<!-- ////////////////////////////////////////////////////////////////////////-->
<!-- /// The input file begins here /////////////////////////////////////////-->
<!-- ////////////////////////////////////////////////////////////////////////-->
<input xsi:noNamespaceSchemaLocation="excitinginput.xsd"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsltpath="../../../xml/"
  scratchpath="/tmp/chm/1">
  <title>Ag Energy-Volume</title>
  <structure speciespath="../../../species/">
    <crystal >
    <xsl:attribute name="scale">
    <xsl:value-of select="3.86*@unicellscaling"/>
    </xsl:attribute>
 
      <basevect>1.0 1.0 0.0</basevect>
      <basevect>1.0 0.0 1.0</basevect>
      <basevect>0.0 1.0 1.0</basevect>
    </crystal>
    <species speciesfile="Ag.xml">
      <atom coord="0.0  0.0  0.0" />
    </species>
  </structure>
  <groundstate ngridk="8 8 8" rgkmax="8" />
</input>
 
<!-- ////////////////////////////////////////////////////////////////////////-->
<!-- /// The input file ends here ///////////////////////////////////////////-->
<!-- ////////////////////////////////////////////////////////////////////////-->
 
</xsl:document>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

It looks quite complicated, but it consists only of a generic part (which can be used for all cases with a similar experiment description) and the Ag input file, where in the latter the @scale attribute of the <crystal> element is expressed in XSLT:

<crystal>
    <xsl:attribute name="scale">
    <xsl:value-of select="3.86*@unicellscaling"/>
    </xsl:attribute>
    [...]
</crystal>

To apply this template, execute:

xsltproc  evTemplate.xsl  scales.xml

Then xsltproc will create the five directories with the proper input file therein.

Execution

Here we have to run 5 self-consistent calculations. You may start them by hand. For more complex examples one could use templates to create scripts of all kind like: loadleveler-multistep-job-template

Analysis

In order to get the energy-volume curve we have to collect the data, which are the volumes and corresponding total-energy values. They are saved among many other values in info.xml. To collect them into one file we use getev.xsl to get:

<?xml version="1.0"?>
<graph xmlns:math="http://exslt.org/math" xmlns:str="http://exslt.org/strings">
  <point volume="139.469011682385" scale="3.667" totalEnergy="-5312.439270664138"/>
  <point volume="150.772020410909" scale="3.7635" totalEnergy="-5312.4416556378"/>
  <point volume="162.669790561172" scale="3.86" totalEnergy="-5312.440895946467"/>
  <point volume="175.177572426039" scale="3.9565" totalEnergy="-5312.437999079701"/>
  <point volume="188.310616298377" scale="4.053" totalEnergy="-5312.433397077082"/>
</graph>
xsltproc getev.xsl scales.xml >eV.xml

The script EV.py fits the data points, gets the minimum and plots the corresponding graphics:

import numpy as nm
import libxml2
from array import *
from libxml2 import xmlAttr
import matplotlib.pyplot as plt
# read data
eVdoc = libxml2.parseFile("./eV.xml")
ctxt = eVdoc.xpathNewContext()
Volume=nm.array(map(float,map(xmlAttr.getContent,ctxt.xpathEval("//@volume"))))
totalEnergy=nm.array(map(float,map(xmlAttr.getContent,ctxt.xpathEval("//@totalEnergy"))))
# make parabular fit
p=nm.polyfit(Volume,totalEnergy,2)
curve=nm.poly1d(p)
# find root of derivative to get minimum
min=nm.roots(nm.polyder(p))
# x values for plotting polynomial
xa = nm.linspace(Volume[0],Volume[-1],100)
#plot
plt.figure(1)
plt.title('Ag')
plt.ylabel(r'Total energy $[Ha]$')
plt.xlabel(r'Volume $[bohr]^3$')
plt.plot(xa,curve(xa),'-')
plt.plot(Volume,totalEnergy,'o')
plt.plot(min,curve(min),'o')
plt.annotate('optimal volume '+str(min[0]), xy=(min,curve(min)), xycoords='data' ,
              xytext=(min-10,curve(min)+0.002) ,  arrowprops=dict(arrowstyle="->"))
print 'optimal volume '+str(min[0])
 
plt.savefig('EV.png')
 
plt.show()

To execute this script, call:

python EV.py

EV.png

Additional excercises

  • Improve the accuracy of the fit by adding an additional data point.
  • Calculate the lattice constant of the optimal volume.
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License