Commit 11584bce authored by Marco Govoni's avatar Marco Govoni
Browse files

Updated documentation

parent dae0792e
#!/usr/bin/python3
from time import sleep, perf_counter as pc
from os import path, remove
from abc import ABC, abstractmethod
##############
# SUPERCLASS #
##############
class ClientServer(ABC):
#
def __init__(self,client_lockfile,maxsec=21600,sleepsec=10):
#
self.client_lockfile = client_lockfile
self.maxsec = maxsec
self.sleepsec = sleepsec
super().__init__()
#
@abstractmethod
def before_sleep(self): # subclass needs to implement this method
pass
#
@abstractmethod
def after_sleep(self): # subclass needs to implement this method
pass
#
@abstractmethod
def awake_condition(self): # subclass needs to implement this method
pass
#
def start(self):
#
# ====================================
self.before_sleep()
# ====================================
#
awake = 1 # I am awake if this is zero
t0 = pc()
while (pc()-t0 <= self.maxsec) :
#
# =================================
self.awake_condition()
# =================================
#
exists = path.exists(self.client_lockfile)
if (not exists) :
awake = 0
break
else :
sleep(self.sleepsec)
#
# ====================================
self.after_sleep()
# ====================================
return awake
###############
# SERVERCLASS #
###############
class QboxServer(ClientServer) :
#
def before_sleep(self):
#
# Determine the name of the server file
#
client_image = self.client_lockfile.split(".")[1]
self.server_inputfile = f"qb.{client_image}.in" # we assume that server_number = client_image
#
# List of perturbation files
#
perturbation_list = []
with open(self.client_lockfile,"r") as f:
for cnt, line in enumerate(f):
perturbation_list.append(line.replace("\n",""))
#
# Create the input file for the server
#
with open(self.server_inputfile,"w") as f:
f.write("load gs.xml\n")
f.write("set xc PBE\n")
f.write("set wf_dyn PSDA\n")
f.write("set scf_tol 1.e-8\n")
for pert in perturbation_list :
f.write(f"response -vext {pert} -IPA -amplitude 0 20\n")
#
# Awake server, by removing its lockfile
#
if(path.exists(self.server_inputfile+".lock")) :
remove(self.server_inputfile+".lock")
#
def awake_condition(self):
#
# If server gets to sleeps, awake the client
#
if( path.exists(self.server_inputfile+".lock")) :
remove(self.client_lockfile)
#
def after_sleep(self):
pass
#############
# INTERFACE #
#############
def sleep_and_wait(*args, **kwargs):
#
client_lockfile = args[0] # name of client lockfile
maxsec = 12 * 60 * 60 # 12 hours, Max sleep time (in s)
sleepsec = 1 # 1 second, Sleep interval (in s)
#
# change defaults
#
if "maxsec" in kwargs.keys() :
maxsec = kwargs["maxsec"]
if "sleepsec" in kwargs.keys() :
sleepsec = kwargs["sleepsec"]
#
server = QboxServer(client_lockfile,maxsec,sleepsec)
return_int = server.start()
#
return return_int
########
# TEST #
########
def test() :
with open("I.1.lock","w") as f :
f.write(" ")
sleep_and_wait("I.1.lock",maxsec=60,sleepsec=2)
if __name__ == "__main__":
# execute only if run as a script
test()
#!/usr/bin/python3
from __future__ import print_function
import sys
from os import path, remove
import yaml
import json
rytoev = 13.6056980659
#########################
# STATIC DEFAULT VALUES #
#########################
default = {}
# input_west
default["input_west"] = {}
default["input_west"]["qe_prefix"] = "pwscf"
default["input_west"]["west_prefix"] = "west"
default["input_west"]["outdir"] = "./"
# wstat_control
default["wstat_control"] = {}
default["wstat_control"]["wstat_calculation"] = "S"
default["wstat_control"]["n_pdep_eigen"] = 1 # dynamically set to the number of electrons
default["wstat_control"]["n_pdep_times"] = 4
default["wstat_control"]["n_pdep_maxiter"] = 100
default["wstat_control"]["n_dfpt_maxiter"] = 250
default["wstat_control"]["n_pdep_read_from_file"] = 0
default["wstat_control"]["trev_pdep"] = 1.e-3
default["wstat_control"]["trev_pdep_rel"] = 1.e-1
default["wstat_control"]["tr2_dfpt"] = 1.e-12
default["wstat_control"]["l_kinetic_only"] = False
default["wstat_control"]["l_minimize_exx_if_active"] = False
default["wstat_control"]["l_use_ecutrho"] = False
default["wstat_control"]["qlist"] = [ 1 ] # dynamically set to the actual number of q
# wfreq_control
default["wfreq_control"] = {}
default["wfreq_control"]["wfreq_calculation"] = "XWGQ"
default["wfreq_control"]["n_pdep_eigen_to_use"] = 1 # dynamically set to the number of electrons
default["wfreq_control"]["qp_bandrange"] = [1, 2]
default["wfreq_control"]["macropol_calculation"] = 'N'
default["wfreq_control"]["n_lanczos"] = 30
default["wfreq_control"]["n_imfreq"] = 128
default["wfreq_control"]["n_refreq"] = 272
default["wfreq_control"]["ecut_imfreq"] = 25. # dynamically set to ecutrho
default["wfreq_control"]["ecut_refreq"] = 2.
default["wfreq_control"]["wfreq_eta"] = 0.05 / rytoev
default["wfreq_control"]["n_secant_maxiter"] = 21
default["wfreq_control"]["trev_secant"] = 0.05 / rytoev
default["wfreq_control"]["l_enable_lanczos"] = True
default["wfreq_control"]["l_enable_gwetot"] = False
default["wfreq_control"]["o_restart_time"] = 0.
default["wfreq_control"]["ecut_spectralf"] = [-2., 1.]
default["wfreq_control"]["n_spectralf"] = 204
# westpp_control
default["westpp_control"] = {}
default["westpp_control"]["westpp_calculation"] = "r"
default["westpp_control"]["westpp_range"] = [1, 2]
default["westpp_control"]["westpp_format"] = "C"
default["westpp_control"]["westpp_sign"] = False
default["westpp_control"]["westpp_n_pdep_eigen_to_use"] = 1
default["westpp_control"]["westpp_r0"] = [0., 0., 0.]
default["westpp_control"]["westpp_nr"] = 100
default["westpp_control"]["westpp_rmax"] = 1.
default["westpp_control"]["westpp_epsinfty"] = 1.
############################
# DYNAMICAL DEFAULT VALUES #
############################
def update_default_values(key,kwargs) :
assert key in default.keys()
#
if key == "wstat_control" :
#
assert("nq") in kwargs.keys()
nq = kwargs["nq"]
default[key]["qlist"] = [ i+1 for i in range(nq) ]
#
assert("nelec") in kwargs.keys()
nelec = kwargs["nelec"]
default[key]["n_pdep_eigen"] = int(nelec)
#
if key == "wfreq_control" :
#
assert("nelec") in kwargs.keys()
nelec = kwargs["nelec"]
default[key]["n_pdep_eigen_to_use"] = int(nelec)
#
assert("ecutrho") in kwargs.keys()
ecutrho = kwargs["ecutrho"]
default[key]["ecut_imfreq"] = ecutrho
################
# OPEN & PARSE #
################
def open_and_parse_file(fileName="west.in") :
"""Opens a file and parses it using the YAML sintax
:param fileName: name of the file
:type fileName: ``string``
:return: parsed data
:rtype: ``dict``
"""
data = {}
try :
with open(fileName, 'r') as stream:
try:
data = yaml.load(stream,Loader=yaml.SafeLoader)
except:
print("Cannot parse file")
except :
print("Cannot open file : ",fileName)
#
return data
##############
# CHECK DICT #
##############
def check_dict(parsed_data={}, default_data={}) :
"""Check data: returns a dictionary with the same keys of default_data. If keys are matching, values of default_data are replaced with those of parsed_data.
:param parsed_data: parsed data
:type parsed_data: ``dict``
:param default_data: default data
:type default_data: ``dict``
:return: checked data
:rtype: ``dict``
"""
#
data = {}
#
for key in default_data.keys() :
if key in parsed_data.keys() :
data[key] = parsed_data[key]
else :
data[key] = default_data[key]
#
return data
###########
# SUPPORT #
###########
def print_bar(prefix="",nmarks=92) :
"""Prints bar.
:param prefix: prefix
:type prefix: ``string``
:param nmarks: number of marks
:type nmarks: ``int``
"""
#
s = prefix
for i in range(nmarks) :
s+="-"
print(s)
#########
# PRINT #
#########
def print_dict(title="input_west", data={}) :
"""Prints data.
:param title: title
:type title: ``string``
:param data: data to print
:type default_data: ``dict``
"""
#
nmarks = 92
nspaces = 5
s = ""
for i in range(nspaces) :
s+=" "
#
print_bar(s,nmarks)
print(s+"I/O Summary : "+str(title))
print_bar(s,nmarks)
for key in data.keys() :
print(s+key,"=",data[key])
print_bar(s,nmarks)
sys.stdout.flush()
#############
# INTERFACE #
#############
def read_keyword_from_file(*args, **kwargs):
"""Read keyword from file
:return: read data
:rtype: ``dict``
"""
#
fileName = args[0]
keyword = args[1]
verbose = args[2]
#
# Assign static & dynamical defaults
#
default_data = default[keyword]
update_default_values(keyword,kwargs)
#
# Read input file
#
input_data = open_and_parse_file(fileName)
if keyword in input_data.keys() :
parsed_data = input_data[keyword]
else :
parsed_data = {}
#
# Compare defaults and input variables
#
data = check_dict( parsed_data, default_data )
#
# Print
#
if (verbose) :
print_dict(keyword, data)
#
return data
########
# TEST #
########
def test() :
#
fileName = "west.in"
#
with open(fileName, "w") as file :
file.write("""
input_west :
qe_prefix : molecule
west_prefix : molecule
outdir : "./"
wstat_control :
wstat_calculation : R # this is a comment
unknown_key : value # this line will be read but not passed
""")
#
read_keyword_from_file(fileName,"input_west",True)
read_keyword_from_file(fileName,"wstat_control",True,nq=20,nelec=10)
read_keyword_from_file(fileName,"wfreq_control",True,nelec=10,ecutrho=30.)
read_keyword_from_file(fileName,"westpp_control",True)
#
remove(fileName)
if __name__ == "__main__":
# execute only if run as a script
test()
#!/usr/bin/python3
import json
from xml.etree import ElementTree as ET
def jsonString2data(jsonString):
try :
data = json.loads(jsonString)
except :
print("Cannot convert jsonString to data: ",jsonString)
return data
def function3D_to_base64(*args, **kwargs):
#
fileName = args[0]
#
data = {}
#
root = ET.parse(fileName)
grid_function = root.find("grid_function")
data["grid_function"] = grid_function.text.replace('\n','')
assert( grid_function.attrib["type"] in ['double','complex'] )
data["dtype"] = grid_function.attrib["type"]
grid = root.find("grid")
data["grid"] = [ int(grid.attrib["nx"]), int(grid.attrib["ny"]), int(grid.attrib["nz"])]
domain = root.find("domain")
data["domain"] = { "a" : [ float(f) for f in domain.attrib["a"].split()], "b" : [ float(f) for f in domain.attrib["b"].split()], "c" : [ float(f) for f in domain.attrib["c"].split()]}
#
return data
def base64_to_function3D(*args, **kwargs):
#
fileName = args[0]
#
# root
attrib = {}
attrib["name"] = kwargs["name"]
attrib["xmlns:xsi"] = "http://www.w3.org/2001/XMLSchema-instance"
attrib["xsi:schemaLocation"] = "http://www.quantum-simulation.org/ns/fpmd/fpmd-1.0 function3d.xsd"
root = ET.Element('{http://www.quantum-simulation.org/ns/fpmd/fpmd-1.0}function3d',attrib=attrib)
# domain
data=jsonString2data(kwargs["domain"])
attrib={}
for l in ["a","b","c"] :
attrib[l] = f"{data[l][0]} {data[l][1]} {data[l][2]}"
ET.SubElement(root, "domain", attrib=attrib)
# grid
data=jsonString2data(kwargs["grid"])
attrib={}
attrib["nx"] = f"{data[0]}"
attrib["ny"] = f"{data[1]}"
attrib["nz"] = f"{data[2]}"
ET.SubElement(root, "grid", attrib=attrib)
# grid_function
attrib={}
assert( kwargs["dtype"] in ['double','complex'] )
attrib["type"] = kwargs["dtype"]
attrib["nx"] = f"{data[0]}"
attrib["ny"] = f"{data[1]}"
attrib["nz"] = f"{data[2]}"
attrib["encoding"] = "base64"
ET.SubElement(root, "grid_function", attrib=attrib).text = kwargs["grid_function"]
# write
ET.ElementTree(root).write(fileName,encoding='UTF-8',xml_declaration=True)
#
return 0
def test() :
#
base64_to_function3D('vext.xml',name='delta_v',domain='{"a":[1,0,0],"b":[0,1,0],"c":[0,0,1]}',grid='[2,3,3]',grid_function='encoded\nfunction\ngoes\nhere\n',dtype="double")
print(function3D_to_base64('vext.xml'))
if __name__ == "__main__":
# execute only if run as a script
test()
#!/usr/bin/python3
from __future__ import print_function
from os import mkdir
import sys
#############
# INTERFACE #
#############
def my_mkdir(*args, **kwargs):
#
path = args[0]
#
try:
mkdir(path)
except OSError:
#print (f"Creation of the directory {path} failed")
pass
else:
#print (f"Successfully created the directory {path} ")
pass
sys.stdout.flush()
########
# TEST #
########
def test() :
#
dirname = "./wstat.save"
#
my_mkdir(dirname)
if __name__ == "__main__":
# execute only if run as a script
test()
......@@ -56,7 +56,7 @@ master_doc = 'index'
# General information about the project.
project = u'west'
copyright = u'2018, Marco Govoni'
copyright = u'2019, Marco Govoni'
author = u'Marco Govoni'
# The version info for the project you're documenting, acts as replacement for
......@@ -64,7 +64,7 @@ author = u'Marco Govoni'
# built documents.
#
# The short X.Y version.
version = '3.1.1'
version = '4.0.0'
# The full version, including alpha/beta/rc tags.
release = version
......
......@@ -13,8 +13,8 @@ Configure QuantumEspresso by running the ``configure`` script that comes with th
$ git clone -b 'qe-6.1.0' --single-branch --depth 1 https://gitlab.com/QEF/q-e.git QEdir
$ cd QEdir
$ git clone -b 'v3.1.1' --single-branch --depth 1 http://greatfire.uchicago.edu/west-public/West.git West
$ ./configure
$ git clone -b 'v4.0.0' --single-branch --depth 1 http://greatfire.uchicago.edu/west-public/West.git West
$ ./configure LD_LIBS="`python3-config --ldflags`"
It's now time to create the ``pw.x``, ``wstat.x``, ``wfreq.x``, and ``westpp.x`` executables by doing:
......
......@@ -15,7 +15,7 @@ The complete **WEST** reference for input parameters.
**WESTpy** is a Python package, designed to assist users of the WEST code in pre- and post-process massively parallel calculations. Click `here <http://www.west-code.org/doc/westpy/latest/>`_ to know more.
.. seealso::
The input file is given according to the JavaScript Object Notation (`www.json.org <http://www.json.org/>`_).
The input file is given according to the YAML Notation (`https://yaml.org/ <https://yaml.org//>`_).
|
......@@ -56,6 +56,7 @@ wstat_control
- "S" : Start from scratch
- "R" : Restart from an interrupted run. You should restart with the same number of cores, and images.
- "E" : Calculation is outsourced to a server
.. data:: n_pdep_eigen
......@@ -108,20 +109,20 @@ wstat_control
.. data:: l_minimize_exx_if_active
:type: boolean
:default: false
:description: If (true), then the exact-exchange term in the Hamiltonian is computed with the cutoff of the wavefunction.
:default: False
:description: If (True), then the exact-exchange term in the Hamiltonian is computed with the cutoff of the wavefunction.
.. data:: l_kinetic_only
:type: boolean
:default: false
:description: If (true), then only the kinetic term in the Hamiltonian is kept.
:default: False
:description: If (True), then only the kinetic term in the Hamiltonian is kept.
.. data:: l_use_ecutrho
:type: boolean
:default: false
:description: If (true), then the eigenpotentials are represented with ecutrho instead of ecutwfc.
:default: False
:description: If (True), then the eigenpotentials are represented with ecutrho instead of ecutwfc.
.. data:: qlist
......@@ -221,13 +222,13 @@ wfreq_control
.. data:: l_enable_lanczos
:type: boolean
:default: true
:description: If (false), then Lanczos solvers are turned off.
:default: True
:description: If (False), then Lanczos solvers are turned off.
.. data:: l_enable_gwetot
:type: boolean
:default: false
:default: False
:description: Deprecated parameter.
.. data:: o_restart_time
......@@ -290,8 +291,8 @@ westpp_control
.. data:: westpp_sign
:type: boolean
:default: false
:description: If (true), then the sign of the wavefunction/eigenpotential is kept in the output file.
:default: False
:description: If (True), then the sign of the wavefunction/eigenpotential is kept in the output file.
.. data:: westpp_n_pdep_eigen_to_use
......
......@@ -5,9 +5,6 @@ Quick Reference
These are quick references for **WEST** input file examples.
.. note::