Commit 7787786c authored by Marco Govoni's avatar Marco Govoni
Browse files

Added documentation, units, geometry, groundState

parent 3f749052
......@@ -12,3 +12,6 @@ To quickly install **westpy**, execute :
Alternatively you can execute :
python setup.py install --user
## Development
The **westpy** package is hosted on `GitLab <http://greatfire.uchicago.edu/west-public/westpy>`_, mirrored to `GitHub <https://github.com/west-code-development/westpy>`_, and licensed under the open-source GPLv3 license.
.. _acknowledge:
List of Contributors
====================
Credits
=======
Marco Govoni (Argonne National Laboratory)
Acknowledgements
================
The development of **westpy** is funded by `MICCoM <http://miccom-center.org/>`_, as part of the CMS Program funded by the U.S. DOE-BES.
......@@ -7,7 +7,12 @@ Installation
The recommendend installation method for **westpy** is via python install.
The software is tested for python version 3.x and has the following dependencies:
- ``ase``
- ``numpy``
- ``scipy``
- ``matplotlib``
- ``datetime``
- ``requests``
- ``mendeleev``
Source Code Installation
========================
......
......@@ -14,7 +14,27 @@ Module contents
:undoc-members:
:show-inheritance:
.. automodule:: westpy.units
:members:
:undoc-members:
:show-inheritance:
.. automodule:: westpy.utils
:members:
:undoc-members:
:show-inheritance:
.. automodule:: westpy.atom
:members:
:undoc-members:
:show-inheritance:
.. automodule:: westpy.geometry
:members:
:undoc-members:
:show-inheritance:
.. automodule:: westpy.groundState
:members:
:undoc-members:
:show-inheritance:
......@@ -4,3 +4,9 @@ Overview
========
**westpy** is designed to assist users of the WEST code in pre- and post-process massively parallel calculations.
Features:
- Guided generation of input files for ground state density functional theory calculations (Qbox, QuantumEspresso)
- Guided generation of input filed for WEST
- Plot of DOS, LDOS, full-frequency self-energy
%% Cell type:markdown id: tags:
# 1.1 Getting Started
%% Cell type:markdown id: tags:
We are going to generate an input file for the code QuantumEspresso, that computes the ground state electronic stucture for the methane molecule.
%% Cell type:markdown id: tags:
## Step 1: Load westpy
%% Cell type:code id: tags:
``` python
from westpy import *
```
%%%% Output: stream
_ _ _____ _____ _____
| | | | ___/ ___|_ _|
| | | | |__ \ `--. | |_ __ _ _
| |/\| | __| `--. \ | | '_ \| | | |
\ /\ / |___/\__/ / | | |_) | |_| |
\/ \/\____/\____/ \_/ .__/ \__, |
| | __/ |
|_| |___/
WEST version : 3.1.0
Today : 2018-06-24 17:42:02.396114
%% Cell type:markdown id: tags:
## Step 1: Geometry
%% Cell type:code id: tags:
``` python
geom = Geometry()
```
%% Cell type:markdown id: tags:
Let's define a cubic cell of edge 25 Bohr.
%% Cell type:code id: tags:
``` python
geom.setCell((25,0,0),(0,25,0),(0,0,25))
```
%% Cell type:markdown id: tags:
We load the atomic positions from a XYZ file, available online.
%% Cell type:code id: tags:
``` python
geom.addAtomsFromOnlineXYZ( "http://www.west-code.org/database/gw100/xyz/CH4.xyz" )
```
%% Cell type:markdown id: tags:
We associate pseudopotential files to each species.
%% Cell type:code id: tags:
``` python
geom.addSpecies( "C", "C_ONCV_PBE-1.0.upf", "http://www.quantum-simulation.org/potentials/sg15_oncv/upf/C_ONCV_PBE-1.0.upf")
geom.addSpecies( "H", "H_ONCV_PBE-1.0.upf", "http://www.quantum-simulation.org/potentials/sg15_oncv/upf/H_ONCV_PBE-1.0.upf")
```
%% Cell type:markdown id: tags:
We can optionally download locally the pseudopotential files.
%% Cell type:code id: tags:
``` python
geom.downloadPseudopotentials()
```
%%%% Output: stream
Downloaded file: C_ONCV_PBE-1.0.upf , from url: http://www.quantum-simulation.org/potentials/sg15_oncv/upf/C_ONCV_PBE-1.0.upf
Downloaded file: H_ONCV_PBE-1.0.upf , from url: http://www.quantum-simulation.org/potentials/sg15_oncv/upf/H_ONCV_PBE-1.0.upf
%% Cell type:markdown id: tags:
## Step 2: Ground State
%% Cell type:markdown id: tags:
The ground state calculation is defined by the geometry, a choice of the exchange-correlation functional, and by setting an energy cutoff for the wavefunctions.
%% Cell type:code id: tags:
``` python
gs = GroundState(geom,xc="PBE",ecut=40.0)
```
%% Cell type:markdown id: tags:
We are now able to generate the input file for QuantumEspresso.
%% Cell type:code id: tags:
``` python
gs.generateInputPW()
```
%%%% Output: stream
Generated file: pw.in
%% Cell type:markdown id: tags:
We can inspect the file pw.in
%% Cell type:code id: tags:
``` python
!cat pw.in
```
%%%% Output: stream
&CONTROL
calculation = 'scf'
restart_mode = 'from_scratch'
pseudo_dir = './'
outdir = './'
prefix = 'calc'
wf_collect = .TRUE.
/
&SYSTEM
ibrav = 0
nat = 5
ntyp = 2
ecutwfc = 40.0
nbnd = 8
input_dft = 'PBE'
nosym = .TRUE.
noinv = .TRUE.
/
&ELECTRONS
diago_full_acc = .TRUE.
conv_tol = 1.d-8
/
ATOMIC_SPECIES
C 12.011 C_ONCV_PBE-1.0.upf
H 1.008 H_ONCV_PBE-1.0.upf
ATOMIC_POSITIONS {bohr}
C 0.0 0.0 0.0
H 1.185992116575257 -1.185803143962673 1.185992116575257
H -1.185992116575257 1.185992116575257 1.185992116575257
H -1.185992116575257 -1.185992116575257 -1.185992116575257
H 1.185992116575257 1.185992116575257 -1.185992116575257
K_POINTS {gamma}
CELL_PARAMETERS {bohr}
25.0 0.0 0.0
0.0 25.0 0.0
0.0 0.0 25.0
......
......@@ -12,9 +12,9 @@ setup(name='westpy',
'numpy',
'scipy',
'matplotlib',
'ase',
'datetime',
'requests'
'requests',
'mendeleev'
],
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, <4',
zip_safe=True)
from __future__ import print_function
from westpy.units import *
from westpy.utils import *
from westpy.atom import *
from westpy.geometry import *
from westpy.species import *
from westpy.groundState import *
from westpy.plot import *
__version__ = '3.1.0'
def header() :
"""Prints welcome header."""
import datetime
print(" ")
print(" _ _ _____ _____ _____ ")
......
from __future__ import print_function
class Atom(object):
"""Class for representing a single atom.
:param symbol: chemical symbol
:type symbol: string
:param position: position
:type position: 3-dim tuple
:param units: Units, optional
:type units: "Bohr" or "Angstrom"
:Example:
>>> from westpy import *
>>> atom = Atom("Si",(0.,0.,0.))
.. note:: Positions are set in a.u. by default. If you set units=Angstrom a coversion to a.u. will be made.
"""
from westpy.units import Bohr
#
def __init__(self, symbol='X', position=(0, 0, 0), units=Bohr) :
#
from mendeleev import element
import numpy as np
#
el = element(symbol)
#
self.symbol = el.symbol
self.position = np.array(position, float) * units
from __future__ import print_function
class Geometry(object) :
"""Class for representing a set of atoms in a periodic cell.
:Example:
>>> from westpy import *
>>> geom = Geometry()
>>> geom.setCell( (1,0,0), (0,1,0), (0,0,1) )
>>> geom.addAtom( "Si", (0,0,0) )
>>> geom.addSpecies( "Si", "Si_ONCV_PBE-1.1.upf", "http://www.quantum-simulation.org/potentials/sg15_oncv/upf/Si_ONCV_PBE-1.1.upf" )
.. note:: Vectors are set in a.u. by default. If you set units=Angstrom a coversion to a.u. will be made.
"""
#
from westpy import Bohr
#
def __init__(self,cell=None) :
self.cell = []
self.atoms = []
self.species = {}
self.isSet = {}
self.isSet["cell"] = False
self.isSet["atoms"] = False
self.isSet["species"] = False
self.pseudoFormat = None
#
def __atomsMatchSpecies(self) :
"""Checks if atoms match species"""
matches = self.isSet["species"] and self.isSet["atoms"]
for atom in self.atoms :
matches = matches and atom.symbol in self.species.keys()
return matches
#
def isValid(self) :
"""Checks if geometry is valid
The method checks that:
- the cell is set
- at least one atom has been added
- the pseudopotentials of all species are defined
"""
isValid = True
for key in self.isSet.keys() :
isValid = isValid and self.isSet[key]
if( not self.isSet[key] ) :
print("ERR: set "+key)
isValid = isValid and self.__atomsMatchSpecies()
return isValid
#
def addSpecies(self, symbol, fname, url) :
"""Adds a species.
:param symbol: chemical symbol
:type symbol: string
:param fname: file name
:type fname: string
:param url: url
:type url: units
:Example:
>>> from westpy import *
>>> geom = Geometry()
>>> geom.addSpecies( "Si", "Si_ONCV_PBE-1.1.upf", "http://www.quantum-simulation.org/potentials/sg15_oncv/upf/Si_ONCV_PBE-1.1.upf" )
.. note:: You can use this method to add either upf or xml pseudopotentials. However it is forbidded to mix them.
"""
this_pseudo_format = None
if( fname.endswith("upf") or fname.endswith("UPF")) :
this_pseudo_format = "upf"
if( fname.endswith("xml") or fname.endswith("XML")) :
this_pseudo_format = "xml"
assert( this_pseudo_format in ["upf","xml"] )
if self.pseudoFormat is None :
self.pseudoFormat = this_pseudo_format
else :
assert( self.pseudoFormat == this_pseudo_format )
from mendeleev import element
el = element(symbol)
self.species[symbol] = {}
self.species[symbol]["fname"] = fname
self.species[symbol]["url"] = url
self.species[symbol]["symbol"] = el.symbol
self.species[symbol]["atomic_number"] = el.atomic_number
self.species[symbol]["name"] = el.name
self.species[symbol]["mass"] = el.mass
self.isSet["species"] = True
#
def setCell(self, a1=(0, 0, 0), a2=(0, 0, 0), a3=(0, 0, 0), units=Bohr ) :
"""Sets cell, given the three vectors :math:`a_1`, :math:`a_2`, :math:`a_3`.
:param a1: :math:`a_1`
:type a1: 3-dim tuple
:param a2: :math:`a_2`
:type a2: 3-dim tuple
:param a3: :math:`a_3`
:type a3: 3-dim tuple
:param units: Units, optional
:type units: "Bohr" or "Angstrom"
:Example:
>>> from westpy import *
>>> geom = Geometry()
>>> geom.setCell( (1,0,0), (0,1,0), (0,0,1) )
"""
import numpy as np
#
self.cell.append( np.array(a1, float) * units )
self.cell.append( np.array(a2, float) * units )
self.cell.append( np.array(a3, float) * units )
self.isSet["cell"] = True
#
def addAtom(self, symbol, position, units=Bohr) :
"""Adds a single atom.
:param symbol: chemical symbol
:type symbol: string
:param position: position
:type position: 3-dim tuple
:param units: Units, optional
:type units: "Bohr" or "Angstrom"
:Example:
>>> from westpy import *
>>> geom = Geometry()
>>> geom.addAtom( "Si", (0,0,0) )
"""
from westpy import Atom
self.atoms.append( Atom(symbol, position, units) )
self.isSet["atoms"] = True
#
def __addAtomsFromXYZLines(self, lines ) :
"""Adds atoms from XYZ lines.
:param lines: lines read from XYZ file (only one image)
:type lines: list of string
"""
#
from westpy import Angstrom
natoms = int(lines[0])
for line in lines[2:2+natoms] :
symbol, x, y, z = line.split()[:4]
self.addAtom( symbol.decode("utf-8"), (float(x), float(y), float(z)), units=Angstrom )
#
def addAtomsFromXYZFile(self, fname ) :
"""Adds atoms from XYZ file (only one image).
:param fname: file name
:type fname: string
:Example:
>>> from westpy import *
>>> geom = Geometry()
>>> geom.addAtomFromXYZFile( "CH4.xyz" )
"""
#
with open(fname,'r') as file:
lines = file.readlines()
self.__addAtomsFromXYZLines(lines)
#
def addAtomsFromOnlineXYZ(self, url ) :
"""Adds atoms from XYZ file (only one image) located at url.
:param url: url
:type url: string
:Example:
>>> from westpy import *
>>> geom = Geometry()
>>> geom.addAtomsFromOnlineXYZ( "http://www.west-code.org/database/gw100/xyz/CH4.xyz" )
"""
#
import urllib.request
with urllib.request.urlopen(url) as response :
lines = response.readlines()
self.__addAtomsFromXYZLines(lines)
#
def getNumberOfAtoms(self) :
"""Returns number of atoms.
:returns: number of atoms
:rtype: int
:Example:
>>> from westpy import *
>>> geom = Geometry()
>>> geom.addAtomsFromOnlineXYZ( "http://www.west-code.org/database/gw100/xyz/CH4.xyz" )
>>> nat = geom.getNumberOfAtoms()
>>> print( nat )
5
"""
nat = len(self.atoms)
return nat
#
def getNumberOfSpecies(self) :
"""Returns number of species.
:returns: number of species
:rtype: int
:Example:
>>> from westpy import *
>>> geom = Geometry()
>>> geom.addAtomsFromOnlineXYZ( "http://www.west-code.org/database/gw100/xyz/CH4.xyz" )
>>> ntyp = geom.getNumberOfSpecies()
>>> print( ntyp )
2
"""
sp = []
for atom in self.atoms :
if atom.symbol not in sp :
sp.append(atom.symbol)
ntyp = len(sp)
return ntyp
#
def getNumberOfElectrons(self) :
"""Returns number of electrons.
:returns: number of electrons
:rtype: int
:Example:
>>> from westpy import *
>>> geom = Geometry()
>>> geom.addAtomsFromOnlineXYZ( "http://www.west-code.org/database/gw100/xyz/CH4.xyz" )
>>> geom.addSpecies( "C", "C_ONCV_PBE-1.0.xml", "http://www.quantum-simulation.org/potentials/sg15_oncv/xml/C_ONCV_PBE-1.0.xml")
>>> geom.addSpecies( "H", "H_ONCV_PBE-1.0.xml", "http://www.quantum-simulation.org/potentials/sg15_oncv/xml/H_ONCV_PBE-1.0.xml")
>>> nelec = geom.getNumberOfElectrons()
>>> print( nelec )
8
"""
assert( self.__atomsMatchSpecies() )
#
nelec = 0
if self.pseudoFormat in ["upf"] :
from westpy import listLinesWithKeyfromOnlineText
for atom in self.atoms :
symbol = atom.symbol
url = self.species[symbol]["url"]
resp = listLinesWithKeyfromOnlineText(url,"z_valence")[0]
this_valence = float(resp.decode("utf-8").split('"')[1])
nelec += this_valence
if self.pseudoFormat in ["xml"] :
from westpy import listValuesWithKeyFromOnlineXML
for atom in self.atoms :
symbol = atom.symbol
url = self.species[symbol]["url"]
this_valence = float(listValuesWithKeyFromOnlineXML(url,"valence_charge")[0])
nelec += this_valence
return int(nelec)
#
def downloadPseudopotentials(self) :
"""Download Pseudopotentials.
:Example:
>>> from westpy import *
>>> geom = Geometry()
>>> geom.addAtomsFromOnlineXYZ( "http://www.west-code.org/database/gw100/xyz/CH4.xyz" )
>>> geom.addSpecies( "C", "C_ONCV_PBE-1.0.xml", "http://www.quantum-simulation.org/potentials/sg15_oncv/xml/C_ONCV_PBE-1.0.xml")
>>> geom.addSpecies( "H", "H_ONCV_PBE-1.0.xml", "http://www.quantum-simulation.org/potentials/sg15_oncv/xml/H_ONCV_PBE-1.0.xml")
>>> geom.downloadPseudopotentials()
.. note:: Pseudopotential files will be downloaded in the current directory.
"""
assert( self.__atomsMatchSpecies() )
#
from westpy import download
for key in self.species.keys() :
download( self.species[key]["fname"], self.species[key]["url"])
from __future__ import print_function
class GroundState :
"""Class for representing a ground state calculation with DFT.
:param geom: geometry (cell, atoms, species)
:type geom: Class(Geometry)
:param xc: exchange-correlation functional
:type xc: string
:param ecut: energy cutoff for the wavefunction (in Rydberg units)
:type ecut: float
:Example:
>>> from westpy import *
>>> geom = Geometry()
>>> geom.setCell( (1,0,0), (0,1,0), (0,0,1) )
>>> geom.addAtom( "Si", (0,0,0) )
>>> geom.addSpecies( "Si", "Si_ONCV_PBE-1.1.upf", "http://www.quantum-simulation.org/potentials/sg15_oncv/upf/Si_ONCV_PBE-1.1.upf" )
>>> gs = GroundState(geom,"PBE",30.0)
.. note:: Vectors are set in a.u. by default. If you set units=Angstrom a coversion to a.u. will be made.
"""
#
def __init__(self,geom,xc,ecut) :
from westpy import Geometry
assert( isinstance(geom,Geometry) )
assert( geom.isValid() )
self.geom = geom
self.xc = xc
self.ecut = ecut
self.nempty = 0
self.kmesh = "gamma"
self.isolated = False
self.spin = {}
#
def setNempty(self,nempty) :
"""Sets the number of empty bands.
:param nempty: number of empty bands
:type nempty: int
:Example:
>>> gs.setNempty(10)