#! /usr/bin/env python3
#
# Copyright 2009-2019 The VOTCA Development Team (http://www.votca.org)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import sys
import os
import time
import numpy as np
import argparse
import h5py
import shutil
import json
VERSION = '@PROJECT_VERSION@ #CSG_GIT_ID#'
PROGTITLE = 'THE VOTCA::XTP Benchmark'
PROGDESCR = 'Runs a Thiel set benchmark'
VOTCAHEADER = '''\
==================================================
======== VOTCA (http://www.votca.org) ========
==================================================
{progtitle}
please submit bugs to bugs@votca.org
benchmark, version {version}
'''.format(version=VERSION, progtitle=PROGTITLE)
def xxquit(what=''):
if what != '':
print("ERROR: {what}".format(what=what))
sys.exit(1)
def ReadEnergyFromHDF5(filename):
orb = h5py.File(filename, 'r')
a = orb['QMdata']['BSE_singlet']['eigenvalues'].value
a.flatten()
return a.flatten()
def CheckforXMLFile(filename):
print("Checking for '{}' file".format(filename))
if not os.path.isfile(filename):
xxquit("'{}' file not found".format(filename))
class cd:
"""Context manager for changing the current working directory"""
def __init__(self, newPath):
self.newPath = os.path.expanduser(newPath)
def __enter__(self):
self.savedPath = os.getcwd()
os.chdir(self.newPath)
def __exit__(self, etype, value, traceback):
os.chdir(self.savedPath)
# =============================================================================
# PROGRAM OPTIONS
# =============================================================================
class XtpHelpFormatter(argparse.HelpFormatter):
def _format_usage(self, usage, action, group, prefix):
return VOTCAHEADER
progargs = argparse.ArgumentParser(prog='xtp_benchmark',
formatter_class=lambda prog: XtpHelpFormatter(
prog, max_help_position=70),
description=PROGDESCR)
progargs.add_argument('-t', '--threads',
required=False,
type=int,
default=1,
help='Number of OPENMP threads')
progargs.add_argument('-r', '--run',
action='store_const',
const=1,
default=0,
help='Run benchmark')
progargs.add_argument('-a', '--analyze',
action='store_const',
const=1,
default=0,
help='Show results')
progargs.add_argument('--reset',
action='store_const',
const=1,
default=0,
help='Delete all benchmark run data')
progargs.add_argument('--update',
action='store_const',
const=1,
default=0,
help='Update references')
OPTIONS = progargs.parse_args()
if OPTIONS.reset:
print("Deleting 'RUN' directory")
try:
shutil.rmtree("RUN")
except OSError as e:
print("Error: %s - %s." % (e.filename, e.strerror))
if OPTIONS.run:
print("Creating run directory")
if os.path.isdir('RUN'):
xxquit("Folder 'RUN' already exists")
os.mkdir("RUN")
CheckforXMLFile('dftgwbse.xml')
CheckforXMLFile('gwbse.xml')
CheckforXMLFile('xtpdft.xml')
molecules = []
for folder in os.listdir("Geometries_ThielSet"):
print("Reading geometries from folder '{}'".format(folder))
for geo in os.listdir("Geometries_ThielSet/"+folder):
if os.path.splitext("Geometries_ThielSet/"+folder+"/"+geo)[1] == ".xyz":
molname = os.path.splitext(geo)[0]
print("Creating subfolder '{}'".format(molname))
dest = "RUN/{}".format(molname)
molecules.append(molname)
os.mkdir(dest)
shutil.copyfile("Geometries_ThielSet/"+folder +
"/"+geo, dest+"/system.xyz")
shutil.copyfile('dftgwbse.xml', dest+'/dftgwbse.xml')
shutil.copyfile('gwbse.xml', dest+'/gwbse.xml')
shutil.copyfile('xtpdft.xml', dest+'/xtpdft.xml')
print("\nStarting benchmark with {} threads".format(OPTIONS.threads))
print(30*"-")
moldata = {}
totaltime = time.time()
referencedata = {}
if os.path.isfile("references.json"):
print("Loading reference data from 'references.json'")
with open("references.json", 'r') as fp:
referencedata = json.load(fp)
for mol in molecules:
print("Running {}".format(mol).ljust(30), end="\r")
with cd("RUN/{}".format(mol)):
start = time.time()
cmd = 'xtp_tools -e dftgwbse -o dftgwbse.xml -t {} > dftgwbse.log'.format(OPTIONS.threads)
os.system(cmd)
dt = time.time() - start
molinfo = {}
molinfo["duration[s]"] = dt
print("{}".format(mol).ljust(30)+" Duration: \t{:8.2f} seconds.".format(dt), end='')
if not os.path.isfile("system.orb"):
print(" Computation Failed")
molinfo["Status"] = "Failed"
else:
S = ReadEnergyFromHDF5("system.orb")
print(" S1 = {:3.6f}[Hrt]".format(S[0]))
molinfo["Status"] = "Success"
molinfo["S1[Hrt]"] = S[0]
if referencedata and referencedata[mol]["Status"] == "Success":
print(" S1_ref = {:3.6f}[Hrt]".format(
referencedata[mol]["S1[Hrt]"]))
moldata[mol] = molinfo
print(30*"-")
dttotal = time.time() - totaltime
print("Total time: {:8.2f}".format(dttotal))
goodruns = 0
for _, result in moldata.items():
if result["Status"] == "Success":
goodruns += 1
print("{:1.2f}% of runs completed successfully".format(
float(goodruns)/float(len(moldata))*100.0))
print("Writing benchmark data to 'result.json'")
with open('result.json', 'w') as fp:
json.dump(moldata, fp, sort_keys=True, indent=4)