Commits (1)
...@@ -18,28 +18,32 @@ import gzip ...@@ -18,28 +18,32 @@ import gzip
import bz2 import bz2
import lzma import lzma
from nomadcore.baseclasses import ParserInterface from .metainfo import m_env
import nomadcore.baseclasses from vaspparser.parser_vasprun import VasprunContext, XmlParser, parser_info
from nomad.parsing.parser import MatchingParser
from vaspparser.parser_vasprun import parserInfo
from vaspparser.parser_vasprun import VasprunContext, XmlParser, parserInfo
from vaspparser.parser_outcar import VaspOutcarParser from vaspparser.parser_outcar import VaspOutcarParser
from nomad.parsing.legacy import CoEInterfaceParser
class VASPRunMainParser: class VASPParser(MatchingParser):
""" def __init__(self):
The main parser class that is called for all run types. Parses the VASP super().__init__(
.xml output files. name='parsers/vasp', code_name='VASP', code_homepage='https://www.vasp.at/',
""" mainfile_mime_re=r'(application/.*)|(text/.*)',
def __init__(self, parser_context): mainfile_contents_re=(
self.parser_context = parser_context r'^\s*<\?xml version="1\.0" encoding="ISO-8859-1"\?>\s*'
r'?\s*<modeling>'
r'?\s*<generator>'
r'?\s*<i name="program" type="string">\s*vasp\s*</i>'
r'?'),
supported_compressions=['gz', 'bz2', 'xz']
)
def run(self, filepath, logger=None):
self._metainfo_env = m_env
super_context = VasprunContext(logger=logger)
def parse(self, filepath): parser = XmlParser(parser_info, super_context, metainfo_env=m_env)
# the nomadcore.baseclasses.logger is set for each parsing run
superContext = VasprunContext(logger=nomadcore.baseclasses.logger)
parser = XmlParser(parserInfo, superContext)
backend = self.parser_context.super_backend
open_file = open open_file = open
if filepath.endswith('.gz'): if filepath.endswith('.gz'):
...@@ -49,46 +53,5 @@ class VASPRunMainParser: ...@@ -49,46 +53,5 @@ class VASPRunMainParser:
elif filepath.endswith('.xz'): elif filepath.endswith('.xz'):
open_file = lzma.open open_file = lzma.open
parser.parse(os.path.abspath(filepath), open_file(filepath, 'rt'), backend) parser.parse(os.path.abspath(filepath), open_file(filepath, 'rt'))
return parser.root_section
class VASPRunParserInterface(ParserInterface):
"""
This class handles the initial setup before any parsing can happen. It
determines which version of BigDFT was used to generate the output and then
sets up a correct main parser.
After the implementation has been setup, you can parse the files with
parse().
"""
def __init__(
self,
metainfo_to_keep=None, backend=None, default_units=None,
metainfo_units=None, debug=True, log_level=logging.ERROR, store=True):
super(VASPRunParserInterface, self).__init__(
metainfo_to_keep, backend, default_units, metainfo_units, debug, log_level, store)
def setup_version(self):
"""
Setups the version by looking at the output file and the version
specified in it.
"""
# Setup the root folder to the fileservice that is used to access files
dirpath, filename = os.path.split(self.parser_context.main_file)
dirpath = os.path.abspath(dirpath)
self.parser_context.file_service.setup_root_folder(dirpath)
self.parser_context.file_service.set_file_id(filename, "output")
self.main_parser = VASPRunMainParser(self.parser_context)
def get_metainfo_filename(self):
return "vasp.nomadmetainfo.json"
def get_parser_info(self):
return parserInfo
class VASPRunParser(CoEInterfaceParser):
def __init__(self):
super().__init__(VASPRunParserInterface)
...@@ -17,23 +17,39 @@ from builtins import range ...@@ -17,23 +17,39 @@ from builtins import range
from builtins import object from builtins import object
import xml.etree.ElementTree import xml.etree.ElementTree
from xml.etree.ElementTree import ParseError from xml.etree.ElementTree import ParseError
import sys
import bisect import bisect
from datetime import datetime from datetime import datetime
import os
import re import re
import traceback import traceback
import numpy as np import numpy as np
import ase.geometry import ase.geometry
import ase.data import ase.data
from math import pi
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
import logging import logging
from nomadcore.local_meta_info import loadJsonFile, InfoKindEl
from nomadcore.unit_conversion.unit_conversion import convert_unit_function from nomadcore.unit_conversion.unit_conversion import convert_unit_function
from nomadcore.unit_conversion.unit_conversion import convert_unit from nomadcore.unit_conversion.unit_conversion import convert_unit
from nomad.metainfo import Quantity
from nomad.datamodel.metainfo.public import section_run as msection_run
from nomad.datamodel.metainfo.public import section_method as msection_method
from nomad.datamodel.metainfo.public import section_sampling_method as msection_sampling_method
from nomad.datamodel.metainfo.public import section_frame_sequence as msection_frame_sequence
from nomad.datamodel.metainfo.public import section_workflow as msection_workflow
from nomad.datamodel.metainfo.public import section_single_configuration_calculation as msection_single_configuration_calculation
from nomad.datamodel.metainfo.public import section_basis_set as msection_basis_set
from nomad.datamodel.metainfo.public import section_XC_functionals as msection_XC_functionals
from nomad.datamodel.metainfo.public import section_system as msection_system
from nomad.datamodel.metainfo.public import section_k_band as msection_k_band
from nomad.datamodel.metainfo.public import section_k_band_segment as msection_k_band_segment
from nomad.datamodel.metainfo.public import section_k_band_normalized as msection_k_band_normalized
from nomad.datamodel.metainfo.public import section_k_band_segment_normalized as msection_k_band_segment_normalized
from nomad.datamodel.metainfo.public import section_eigenvalues as msection_eigenvalues
from nomad.datamodel.metainfo.public import section_method_atom_kind as msection_method_atom_kind
from nomad.datamodel.metainfo.public import section_basis_set_cell_dependent as msection_basis_set_cell_dependent
from nomad.datamodel.metainfo.public import section_dos as msection_dos
from nomad.datamodel.metainfo.common import section_method_basis_set as msection_method_basis_set
eV2J = convert_unit_function("eV", "J") eV2J = convert_unit_function("eV", "J")
eV2JV = np.vectorize(eV2J) eV2JV = np.vectorize(eV2J)
...@@ -53,10 +69,10 @@ special_paths = { ...@@ -53,10 +69,10 @@ special_paths = {
'monoclinic': 'ΓYHCEM1AXH1,MDZ,YD'} 'monoclinic': 'ΓYHCEM1AXH1,MDZ,YD'}
def secondsFromEpoch(date): def seconds_from_epoch(date):
epoch = datetime(1970, 1, 1) epoch = datetime(1970, 1, 1)
ts = date-epoch ts = date - epoch
return ts.seconds + ts.microseconds/1000.0 return ts.seconds + ts.microseconds / 1000.0
trueRe = re.compile( trueRe = re.compile(
...@@ -65,20 +81,20 @@ falseRe = re.compile( ...@@ -65,20 +81,20 @@ falseRe = re.compile(
r"\s*(?:\.?[fF](?:[Aa][Ll][Ss][Ee])?\.?|0|[Nn](?:[Oo]|[Ee][Ii][Nn])?)\s*$") r"\s*(?:\.?[fF](?:[Aa][Ll][Ss][Ee])?\.?|0|[Nn](?:[Oo]|[Ee][Ii][Nn])?)\s*$")
def toBool(value): def to_bool(value):
if falseRe.match(value): if falseRe.match(value):
return False return False
elif trueRe.match(value): elif trueRe.match(value):
return True return True
else: else:
backend.pwarn("Unexpected value for boolean field: %s" % (value))
return None return None
metaTypeTransformers = {
meta_type_transformers = {
'C': lambda x: x.strip(), 'C': lambda x: x.strip(),
'i': lambda x: int(float(x.strip())), 'i': lambda x: int(float(x.strip())),
'f': lambda x: float(x.strip()), 'f': lambda x: float(x.strip()),
'b': toBool, 'b': to_bool,
} }
...@@ -94,8 +110,9 @@ class MyXMLParser(ET.XMLParser): ...@@ -94,8 +110,9 @@ class MyXMLParser(ET.XMLParser):
num = int(target) num = int(target)
else: else:
num = int(m.group(2), 16) num = int(m.group(2), 16)
if not(num in (0x9, 0xA, 0xD) or 0x20 <= num <= 0xD7FF if not(
or 0xE000 <= num <= 0xFFFD or 0x10000 <= num <= 0x10FFFF): num in (0x9, 0xA, 0xD) or 0x20 <= num <= 0xD7FF or 0xE000 <= num <= 0xFFFD
or 0x10000 <= num <= 0x10FFFF):
# is invalid xml character, cut it out of the stream # is invalid xml character, cut it out of the stream
mstart, mend = m.span() mstart, mend = m.span()
mydata = data[:mstart] + data[mend:] mydata = data[:mstart] + data[mend:]
...@@ -111,7 +128,7 @@ def transform2(y): ...@@ -111,7 +128,7 @@ def transform2(y):
return y return y
def getVector(el, transform=float, field="v"): def get_vector(el, transform=float, field="v"):
""" returns the vasp style vector contained in the element el (using field v). """ returns the vasp style vector contained in the element el (using field v).
single elements are converted using the function convert""" single elements are converted using the function convert"""
# #
...@@ -127,7 +144,7 @@ class VasprunContext(object): ...@@ -127,7 +144,7 @@ class VasprunContext(object):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
self.logger = logger self.logger = logger
self.parser = None self._parser = None
self.bands = None self.bands = None
self.kpoints = None self.kpoints = None
self.weights = None self.weights = None
...@@ -135,124 +152,132 @@ class VasprunContext(object): ...@@ -135,124 +152,132 @@ class VasprunContext(object):
self.tetrahedronVolume = None self.tetrahedronVolume = None
self.ispin = None self.ispin = None
self.ibrion = None self.ibrion = None
self.lastSystemDescription = None
self.labels = None self.labels = None
self.singleConfCalcs = []
self.vbTopE = None self.vbTopE = None
self.ebMinE = None self.ebMinE = None
self.eFermi = None self.e_fermi = None
self.cell = None self.cell = None
self.angstrom_cell = None self.angstrom_cell = None
self.unknown_incars = {} self.unknown_incars = {}
self._energies = []
sectionMap = { section_map = {
"modeling": ["section_run", "section_method"], "modeling": ["section_run", "section_method"],
"structure": ["section_system"], "structure": ["section_system"],
"calculation": ["section_single_configuration_calculation"] "calculation": ["section_single_configuration_calculation"]
} }
def startedParsing(self, parser): @property
self.parser = parser def parser(self):
return self._parser
def onEnd_generator(self, parser, event, element, pathStr): @parser.setter
backend = parser.backend def parser(self, name):
self._parser = name
def on_end_generator(self, element, path_str):
root_section = self.parser.root_section
program_name = g(element, "i/[@name='program']") program_name = g(element, "i/[@name='program']")
if program_name.strip().upper() == "VASP": if program_name.strip().upper() == 'VASP':
backend.addValue("program_name", "VASP") root_section.program_name = 'VASP'
else: else:
raise Exception("unexpected program name: %s" % program_name) raise Exception('unexpected program name: %s' % program_name)
version = (g(element, "i/[@name='version']", "") + " " +
g(element, "i/[@name='subversion']", "") + " " + version = (
g(element, "i/[@name='platform']", "")) g(element, "i/[@name='version']", "") + " " +
g(element, "i/[@name='subversion']", "") + " " +
g(element, "i/[@name='platform']", ""))
if not version.isspace(): if not version.isspace():
backend.addValue("program_version", version) root_section.program_version = version
backend.addValue("program_basis_set_type", "plane waves")
root_section.program_basis_set_type = "plane waves"
date = g(element, "i/[@name='date']") date = g(element, "i/[@name='date']")
pdate = None pdate = None
time = g(element, "i/[@name='time']") time = g(element, "i/[@name='time']")
if date: if date:
pdate = datetime.strptime(date.strip(), "%Y %m %d") pdate = datetime.strptime(date.strip(), "%Y %m %d")
if pdate and time: if pdate and time:
pdate = datetime.combine(pdate.date(), datetime.strptime( pdate = datetime.combine(pdate.date(), datetime.strptime(
time.strip(), "%H:%M:%S").timetz()) time.strip(), "%H:%M:%S").timetz())
if pdate: if pdate:
backend.addValue("program_compilation_datetime", root_section.program_compilation_datetime = seconds_from_epoch(pdate)
secondsFromEpoch(pdate))
for i in element: for i in element:
if i.tag != "i" or not i.attrib.get("name") in set(["program", "version", "subversion", "platform", "program_version", "date", "time"]): if i.tag != "i" or not i.attrib.get("name") in set(
backend.pwarn("unexpected tag %s %s %r in generator" % [
(i.tag, i.attrib, i.text)) 'program', 'version', 'subversion', 'platform', 'program_version',
'date', 'time']):
pass
def onEnd_incar(self, parser, event, element, pathStr): def on_end_incar(self, element, path_str):
backend = parser.backend root_section = self.parser.root_section
metaEnv = parser.backend.metaInfoEnv() m_env = self.parser.metainfo_env
section_method = root_section.m_create(msection_method)
dft_plus_u = False dft_plus_u = False
ibrion = None ibrion = None
nsw = 0 nsw = 0
for el in element: for el in element:
if el.tag == "v": if el.tag == "v":
name = el.attrib.get("name", None) name = el.attrib.get("name", None)
meta = metaEnv['x_vasp_incar_' + name] meta = m_env.resolve_definition('x_vasp_incar_' + name, Quantity)
if not meta: if not meta:
backend.pwarn("Unknown INCAR parameter (not registered in the meta data): %s %s %r" % ( self.logger.warn(
el.tag, el.attrib, el.text)) "Unknown INCAR parameter (not registered in the meta data): %s %s %r" % (
el.tag, el.attrib, el.text))
continue continue
#- - vector_val = np.asarray(get_vector(el))
vector_val = np.asarray(getVector(el)) setattr(section_method, meta.get('name'), vector_val)
backend.addArrayValues(meta.get('name'), vector_val)
elif el.tag == "i": elif el.tag == "i":
name = el.attrib.get("name", None) name = el.attrib.get("name", None)
meta = metaEnv['x_vasp_incar_' + name] meta = m_env.resolve_definition('x_vasp_incar_' + name, Quantity)
valType = el.attrib.get("type") val_type = el.attrib.get("type")
if not meta: if not meta:
backend.pwarn("Unknown INCAR parameter (not registered in the meta data): %s %s %r" % ( self.logger.warn(
el.tag, el.attrib, el.text)) "Unknown INCAR parameter (not registered in the meta data): %s %s %r" % (
elif valType: el.tag, el.attrib, el.text))
expectedMetaType = { elif val_type:
expected_meta_type = {
'string': ['C'], 'string': ['C'],
'int': ['i'], 'int': ['i'],
'logical': ['b', 'C'] 'logical': ['b', 'C']
}.get(valType) }.get(val_type)
if not expectedMetaType: metainfo_type = self._metainfo_type(meta)
backend.pwarn("Unknown value type %s encountered in INCAR: %s %s %r" % ( if not expected_meta_type:
valType, el.tag, el.attrib, el.text)) self.logger.warn("Unknown value type %s encountered in INCAR: %s %s %r" % (
elif not meta.get('dtypeStr') in expectedMetaType: val_type, el.tag, el.attrib, el.text))
backend.pwarn("type mismatch between meta data %s and INCAR type %s for %s %s %r" % ( elif not metainfo_type in expected_meta_type:
meta.get('dtypeStr'), valType, el.tag, el.attrib, el.text)) self.logger.warn("type mismatch between meta data %s and INCAR type %s for %s %s %r" % (
metainfo_type, val_type, el.tag, el.attrib, el.text))
else: else:
shape = meta.get("shape", None) shape = meta.get("shape")
dtypeStr = meta.get("dtypeStr", None) converter = meta_type_transformers.get(metainfo_type)
converter = metaTypeTransformers.get(dtypeStr)
if not converter: if not converter:
backend.pwarn( self.logger.warn(
"could not find converter for dtypeStr %s when handling meta info %s" % (dtypeStr, )) "could not find converter for %s when handling meta info %s" % (
metainfo_type, meta))
elif shape: elif shape:
vals = re.split("\s+", el.text.strip()) vals = re.split(r"\s+", el.text.strip())
backend.addValue( setattr(section_method, meta['name'], [converter(x) for x in vals])
meta["name"], [converter(x) for x in vals])
else: else:
backend.addValue(meta["name"], converter(el.text)) setattr(section_method, meta["name"], converter(el.text))
if name == 'GGA': if name == 'GGA':
# FIXME tmk: many options are not coded yet. See # FIXME tmk: many options are not coded yet. See
# https://www.vasp.at/wiki/index.php/GGA # https://www.vasp.at/wiki/index.php/GGA
fMap = { f_map = {
'91': ['GGA_X_PW91', 'GGA_C_PW91'], '91': ['GGA_X_PW91', 'GGA_C_PW91'],
'PE': ['GGA_X_PBE', 'GGA_C_PBE'], 'PE': ['GGA_X_PBE', 'GGA_C_PBE'],
'RP': ['GGA_X_RPBE', 'GGA_C_PBE'], 'RP': ['GGA_X_RPBE', 'GGA_C_PBE'],
'PS': ['GGA_C_PBE_SOL', 'GGA_X_PBE_SOL'], 'PS': ['GGA_C_PBE_SOL', 'GGA_X_PBE_SOL'],
'MK': ['GGA_X_OPTB86_VDW'] 'MK': ['GGA_X_OPTB86_VDW']
} }
functs = fMap.get(el.text.strip(), None) functs = f_map.get(el.text.strip(), None)
if not functs: if not functs:
backend.pwarn("Unknown XC functional %s" % self.logger.warn("Unknown XC functional %s" % el.text.strip())
el.text.strip())
else: else:
for f in functs: for f in functs:
backend.openNonOverlappingSection( section_XC_functionals = section_method.m_create(msection_XC_functionals)
"section_XC_functionals") section_XC_functionals.XC_functional_name = f
backend.addValue("XC_functional_name", f)
backend.closeNonOverlappingSection(
"section_XC_functionals")
elif name == "ISPIN": elif name == "ISPIN":
self.ispin = int(el.text.strip()) self.ispin = int(el.text.strip())
elif name == "LDAU": elif name == "LDAU":
...@@ -263,35 +288,32 @@ class VasprunContext(object): ...@@ -263,35 +288,32 @@ class VasprunContext(object):
elif name == "NSW": elif name == "NSW":
nsw = int(el.text.strip()) nsw = int(el.text.strip())
else: else:
backend.pwarn("unexpected tag %s %s %r in incar" % self.logger.warn(
(el.tag, el.attrib, el.text)) "unexpected tag %s %s %r in incar" % (el.tag, el.attrib, el.text))
if ibrion is None: if ibrion is None:
ibrion = -1 if nsw == 0 or nsw == 1 else 0 ibrion = -1 if nsw == 0 or nsw == 1 else 0
if nsw == 0: if nsw == 0:
ibrion = -1 ibrion = -1
self.ibrion = ibrion self.ibrion = ibrion
if dft_plus_u: section_method.electronic_structure_method = 'DFT+U' if dft_plus_u else 'DFT'
backend.addValue("electronic_structure_method", "DFT+U")
else:
backend.addValue("electronic_structure_method", "DFT")
def onEnd_kpoints(self, parser, event, element, pathStr): def on_end_kpoints(self, element, path_str):
backend = parser.backend root_section = self.parser.root_section
self.bands = None self.bands = None
self.kpoints = None self.kpoints = None
self.weights = None self.weights = None
for el in element: for el in element:
if el.tag == "generation": if el.tag == "generation":
param = el.attrib.get("param", None) # eg. listgenerated, Monkhorst-Pack, Gamma param = el.attrib.get("param", None) # eg. listgenerated, Monkhorst-Pack, Gamma
if param: if param:
backend.addValue( root_section.section_method[-1].x_vasp_k_points_generation_method = param
"x_vasp_k_points_generation_method", param)
if param == "listgenerated": if param == "listgenerated":
# This implies a path on k-space, potentially a bandstructure calculation # This implies a path on k-space, potentially a bandstructure calculation
# Save k-path info into a dictionary # Save k-path info into a dictionary
self.bands = { self.bands = {
"divisions": g(el, "i/[@name='divisions']", None), "divisions": g(el, "i/[@name='divisions']", None),
"points": getVector(el) "points": get_vector(el)
} }
elif param in ["Monkhorst-Pack", "Gamma"]: elif param in ["Monkhorst-Pack", "Gamma"]:
...@@ -299,22 +321,20 @@ class VasprunContext(object): ...@@ -299,22 +321,20 @@ class VasprunContext(object):
# Hence, do nothing: k-points will be stored in the `varray` if-block # Hence, do nothing: k-points will be stored in the `varray` if-block
pass pass
else: else:
backend.pwarn("Unknown k point generation method '%s'" %(param)) self.logger.warn("Unknown k point generation method '%s'" % param)
elif el.tag == "varray": elif el.tag == "varray":
name = el.attrib.get("name", None) name = el.attrib.get("name", None)
if name == "kpointlist": if name == "kpointlist":
self.kpoints = np.asarray(getVector(el)) self.kpoints = np.asarray(get_vector(el))
backend.addArrayValues("k_mesh_points", self.kpoints) root_section.section_method[-1].k_mesh_points = self.kpoints
elif name == "weights": elif name == "weights":
self.weights = np.asarray(getVector(el)) self.weights = np.asarray(get_vector(el))
backend.addArrayValues( root_section.section_method[-1].k_mesh_weights = self.weights.flatten()
"k_mesh_weights", self.weights.flatten())
elif name == "tetrahedronlist": elif name == "tetrahedronlist":
self.tetrahedrons = np.asarray(getVector(el), dtype=np.int) self.tetrahedrons = np.asarray(get_vector(el), dtype=np.int)
backend.addArrayValues( root_section.section_method[-1].x_vasp_tetrahedrons_list = self.tetrahedrons
"x_vasp_tetrahedrons_list", self.tetrahedrons)
else: else:
backend.pwarn("Unknown array %s in kpoints" % name) self.logger.warn("Unknown array %s in kpoints" % name)
elif el.tag == "i": elif el.tag == "i":
name = el.attrib.get("name", None) name = el.attrib.get("name", None)
if name == "volumeweight": if name == "volumeweight":
...@@ -324,105 +344,98 @@ class VasprunContext(object): ...@@ -324,105 +344,98 @@ class VasprunContext(object):
vol_cubic_angs = float(el.text.strip()) vol_cubic_angs = float(el.text.strip())
vol_cubic_meters = ang2m(ang2m(ang2m(vol_cubic_angs))) vol_cubic_meters = ang2m(ang2m(ang2m(vol_cubic_angs)))
backend.addArrayValues("x_vasp_tetrahedron_volume", root_section.section_method[-1].x_vasp_tetrahedron_volume = vol_cubic_meters
vol_cubic_meters)
else: else:
backend.pwarn("Unknown tag %s in kpoints" % el.tag) self.logger.pwarn("Unknown tag %s in kpoints" % el.tag)
def onEnd_structure(self, parser, event, element, pathStr): def on_end_structure(self, element, path_str):
backend = parser.backend root_section = self.parser.root_section
gIndexes = parser.tagSections[pathStr] section_system = root_section.m_create(msection_system)
self.lastSystemDescription = gIndexes["section_system"]
self.cell = None self.cell = None
for el in element: for el in element:
if (el.tag == "crystal"): if (el.tag == "crystal"):
for cellEl in el: for cell_el in el:
if cellEl.tag == "varray": if cell_el.tag == "varray":
name = cellEl.attrib.get("name", None) name = cell_el.attrib.get("name", None)
if name == "basis": if name == "basis":
conv = convert_unit_function("angstrom", "m") conv = convert_unit_function("angstrom", "m")
self.cell = getVector( self.cell = get_vector(
cellEl, lambda x: conv(float(x))) cell_el, lambda x: conv(float(x)))
self.angstrom_cell = np.array(getVector(cellEl)) self.angstrom_cell = np.array(get_vector(cell_el))
backend.addArrayValues( section_system.simulation_cell = np.asarray(self.cell)
"simulation_cell", np.asarray(self.cell)) section_system.configuration_periodic_dimensions = np.ones(3, dtype=bool)
backend.addArrayValues(
"configuration_periodic_dimensions", np.ones(3, dtype=bool))
elif name == "rec_basis": elif name == "rec_basis":
pass pass
else: else:
backend.pwarn( self.logger.warn(
"Unexpected varray %s in crystal" % name) "Unexpected varray %s in crystal" % name)
elif cellEl.tag == "i": elif cell_el.tag == "i":
if cellEl.attrib.get("name") != "volume": if cell_el.attrib.get("name") != "volume":
backend.pwarn( self.logger.warn(
"Unexpected i value %s in crystal" % cellEl.attrib) "Unexpected i value %s in crystal" % cell_el.attrib)
else: else:
backend.pwarn("Unexpected tag %s %s %r in crystal" % ( self.logger.warn("Unexpected tag %s %s %r in crystal" % (
cellEl.tag, cellEl.attrib, cellEl.text)) cell_el.tag, cell_el.attrib, cell_el.text))
elif el.tag == "varray": elif el.tag == "varray":
name = el.attrib.get("name", None) name = el.attrib.get("name", None)
if name == "positions": if name == "positions":
pos = getVector(el) pos = get_vector(el)
backend.addArrayValues( section_system.atom_positions = np.dot(np.asarray(pos), self.cell)
"atom_positions", np.dot(np.asarray(pos), self.cell))
elif name == "selective": elif name == "selective":
atom_sel = getVector(el, transform=lambda item: item == 'T') atom_sel = get_vector(el, transform=lambda item: item == 'T')
backend.addArrayValues( section_system.x_vasp_selective_dynamics = np.asarray(atom_sel, dtype=np.bool)
"x_vasp_selective_dynamics", np.asarray(atom_sel, dtype=np.bool))
else: else:
backend.pwarn( self.logger.warn(
"Unexpected varray in structure %s" % el.attrib) "Unexpected varray in structure %s" % el.attrib)
elif el.tag == "nose": elif el.tag == "nose":
nose = getVector(el) nose = get_vector(el)
backend.addArrayValues("x_vasp_nose_thermostat", nose) section_system.x_vasp_nose_thermostat = nose
else: else:
backend.pwarn("Unexpected tag in structure %s %s %r" % self.logger.warn(
(el.tag, el.attrib, el.text)) "Unexpected tag in structure %s %s %r" % (el.tag, el.attrib, el.text))
if self.labels is not None: if self.labels is not None:
backend.addArrayValues("atom_labels", self.labels) section_system.atom_labels = self.labels
def onEnd_eigenvalues(self, parser, event, element, pathStr): def on_end_eigenvalues(self, element, path_str):
if pathStr != "modeling/calculation/eigenvalues": if path_str != "modeling/calculation/eigenvalues":
return True return True
backend = parser.backend root_section = self.parser.root_section
eigenvalues = None eigenvalues = None
occupation = None occupation = None
for el in element: for el in element:
if el.tag == "array": if el.tag == "array":
for arrEl in el: for arrray_el in el:
if arrEl.tag == "dimension": if arrray_el.tag == "dimension":
pass pass
elif arrEl.tag == "field": elif arrray_el.tag == "field":
pass pass
elif arrEl.tag == "set": elif arrray_el.tag == "set":
isp = -1 isp = -1
for spinEl in arrEl: for spin_el in arrray_el:
if spinEl.tag == "set": if spin_el.tag == "set":
ik = -1 ik = -1
isp += 1 isp += 1
for kEl in spinEl: for kEl in spin_el:
if kEl.tag == "set": if kEl.tag == "set":
ik += 1 ik += 1
bands = np.asarray( bands = np.asarray(
getVector(kEl, field="r")) get_vector(kEl, field="r"))
if eigenvalues is None: if eigenvalues is None:
eigenvalues = np.zeros( eigenvalues = np.zeros(
(self.ispin, self.kpoints.shape[0], bands.shape[0]), dtype=float) (self.ispin, self.kpoints.shape[0], bands.shape[0]), dtype=float)
occupation = np.zeros( occupation = np.zeros(
(self.ispin, self.kpoints.shape[0], bands.shape[0]), dtype=float) (self.ispin, self.kpoints.shape[0], bands.shape[0]), dtype=float)
eigenvalues[isp, ik] = bands[:, 0] eigenvalues[isp, ik] = bands[:, 0]
occupation[isp, ik] = bands[:, 1] occupation[isp, ik] = bands[:, 1]
else: else:
backend.pwarn( self.logger.warn(
"unexpected tag %s in k array of the eigenvalues" % kEl.tag) "unexpected tag %s in k array of the eigenvalues" % kEl.tag)
else: else:
backend.pwarn( self.logger.warn(
"unexpected tag %s in spin array of the eigenvalues" % spinEl.tag) "unexpected tag %s in spin array of the eigenvalues" % spin_el.tag)
else: else:
backend.pwarn( self.logger.warn(
"unexpected tag %s in array of the eigenvalues" % arrEl.tag) "unexpected tag %s in array of the eigenvalues" % arrray_el.tag)
if eigenvalues is not None: if eigenvalues is not None:
ev = eV2JV(eigenvalues) ev = eV2JV(eigenvalues)
...@@ -445,13 +458,11 @@ class VasprunContext(object): ...@@ -445,13 +458,11 @@ class VasprunContext(object):
ebMinE[ispin] = ebMinK ebMinE[ispin] = ebMinK
self.vbTopE = vbTopE self.vbTopE = vbTopE
self.ebMinE = ebMinE self.ebMinE = ebMinE
backend.addArrayValues( root_section.section_single_configuration_calculation[-1].energy_reference_highest_occupied = np.array(vbTopE)
"energy_reference_highest_occupied", np.array(vbTopE)) root_section.section_single_configuration_calculation[-1].energy_reference_lowest_unoccupied = np.array(ebMinE)
backend.addArrayValues(
"energy_reference_lowest_unoccupied", np.array(ebMinE))
if self.bands: if self.bands:
divisions = int(self.bands['divisions']) divisions = int(self.bands['divisions'])
backend.openNonOverlappingSection("section_k_band") section_k_band = root_section.section_single_configuration_calculation[-1].m_create(msection_k_band)
nsegments = self.kpoints.shape[0] // divisions nsegments = self.kpoints.shape[0] // divisions
kpt = np.reshape( kpt = np.reshape(
self.kpoints, (nsegments, divisions, 3)) self.kpoints, (nsegments, divisions, 3))
...@@ -460,257 +471,230 @@ class VasprunContext(object): ...@@ -460,257 +471,230 @@ class VasprunContext(object):
occ = np.reshape( occ = np.reshape(
occupation, (self.ispin, nsegments, divisions, bands.shape[0])) occupation, (self.ispin, nsegments, divisions, bands.shape[0]))
for isegment in range(nsegments): for isegment in range(nsegments):
backend.openNonOverlappingSection( section_k_band_segment = section_k_band.m_create(msection_k_band_segment)
"section_k_band_segment") section_k_band_segment.band_energies = energies[:, isegment, :, :]
backend.addArrayValues( section_k_band_segment.band_occupations = occ[:, isegment, :, :]
"band_energies", energies[:, isegment, :, :]) section_k_band_segment.band_k_points = kpt[isegment]
backend.addArrayValues(
"band_occupations", occ[:, isegment, :, :])
backend.addArrayValues(
"band_k_points", kpt[isegment])
# "band_segm_labels" # "band_segm_labels"
backend.addArrayValues("band_segm_start_end", np.asarray( section_k_band_segment.band_segm_start_end = np.asarray(
[kpt[isegment, 0], kpt[isegment, divisions - 1]])) [kpt[isegment, 0], kpt[isegment, divisions - 1]])
backend.closeNonOverlappingSection(
"section_k_band_segment") section_k_band_normalized = root_section.section_single_configuration_calculation[-1].m_create(msection_k_band_normalized)
backend.closeNonOverlappingSection("section_k_band")
backend.openNonOverlappingSection(
"section_k_band_normalized")
for isegment in range(nsegments): for isegment in range(nsegments):
backend.openNonOverlappingSection( section_k_band_segment_normalized = section_k_band_normalized.m_create(msection_k_band_segment_normalized)
"section_k_band_segment_normalized") section_k_band_segment_normalized.band_energies_normalized = energies[:, isegment, :, :] - max(self.vbTopE)
backend.addArrayValues( section_k_band_segment_normalized.band_occupations_normalized = occ[:, isegment, :, :]
"band_energies_normalized", energies[:, isegment, :, :] - max(self.vbTopE)) section_k_band_segment_normalized.band_k_points_normalized = kpt[isegment]
backend.addArrayValues( section_k_band_segment_normalized.band_segm_start_end_normalized = np.asarray(
"band_occupations_normalized", occ[:, isegment, :, :]) [kpt[isegment, 0], kpt[isegment, divisions - 1]])
backend.addArrayValues(
"band_k_points_normalized", kpt[isegment])
backend.addArrayValues("band_segm_start_end_normalized", np.asarray(
[kpt[isegment, 0], kpt[isegment, divisions - 1]]))
backend.closeNonOverlappingSection(
"section_k_band_segment_normalized")
backend.closeNonOverlappingSection(
"section_k_band_normalized")
else: else:
backend.openNonOverlappingSection( section_eigenvalues = root_section.section_single_configuration_calculation[-1].m_create(msection_eigenvalues)
"section_eigenvalues") section_eigenvalues.eigenvalues_values = ev
backend.addArrayValues("eigenvalues_values", ev) section_eigenvalues.eigenvalues_occupation = occupation
backend.addArrayValues(
"eigenvalues_occupation", occupation)
backend.closeNonOverlappingSection(
"section_eigenvalues")
else: else:
backend.pwarn("unexpected tag %s in the eigenvalues" % el.tag) self.logger.warn("unexpected tag %s in the eigenvalues" % el.tag)
def onEnd_scstep(self, parser, event, element, pathStr):
pass
def onStart_calculation(self, parser, event, element, pathStr): def on_start_calculation(self, element, path_str):
backend = parser.backend root_section = self.parser.root_section
gIndexes = parser.tagSections[pathStr] sscc = root_section.m_create(msection_single_configuration_calculation)
self.singleConfCalcs.append(
gIndexes["section_single_configuration_calculation"])
if self.waveCut: if self.waveCut:
backend.openNonOverlappingSection("section_basis_set") section_basis_set = sscc.m_create(msection_basis_set)
backend.addValue( section_basis_set.mapping_section_basis_set_cell_dependent = self.waveCut
"mapping_section_basis_set_cell_dependent", self.waveCut)
backend.closeNonOverlappingSection("section_basis_set") def on_end_modeling(self, element, path_str):
root_section = self.parser.root_section
def onEnd_modeling(self, parser, event, element, pathStr): root_section.section_method[-1].x_vasp_unknown_incars = self.unknown_incars
backend = parser.backend
backend.addValue("x_vasp_unknown_incars", self.unknown_incars)
if self.ibrion is None or self.ibrion == -1: if self.ibrion is None or self.ibrion == -1:
return return
samplingGIndex = backend.openSection("section_sampling_method") section_sampling_method = root_section.m_create(msection_sampling_method)
if self.ibrion == 0: if self.ibrion == 0:
sampling_method = "molecular_dynamics" sampling_method = "molecular_dynamics"
else: else:
sampling_method = "geometry_optimization" sampling_method = "geometry_optimization"
backend.addValue("sampling_method", sampling_method) section_sampling_method.sampling_method = sampling_method
backend.closeSection("section_sampling_method", samplingGIndex) section_frame_sequence = root_section.m_create(msection_frame_sequence)
frameSequenceGIndex = backend.openSection("section_frame_sequence") section_frame_sequence.frame_sequence_to_sampling_ref = section_sampling_method
backend.addValue("frame_sequence_to_sampling_ref", samplingGIndex) section_frame_sequence.frame_sequence_local_frames_ref = root_section.section_single_configuration_calculation[-1]
backend.addArrayValues( section_workflow = root_section.m_create(msection_workflow)
"frame_sequence_local_frames_ref", np.asarray(self.singleConfCalcs)) section_workflow.workflow_type = sampling_method
backend.closeSection("section_frame_sequence", frameSequenceGIndex) section_workflow.workflow_final_calculation_ref = root_section.section_single_configuration_calculation[-1]
if len(self._energies) > 1:
delta_energy = abs(self._energies[-1] - self._energies[-2])
def onEnd_calculation(self, parser, event, element, pathStr): section_workflow.relaxation_energy_tolerance = delta_energy
eConv = eV2J
fConv = convert_unit_function("eV/angstrom", "N") def on_end_calculation(self, element, path_str):
pConv = convert_unit_function("eV/angstrom^3", "Pa") e_conv = eV2J
backend = parser.backend f_conv = convert_unit_function("eV/angstrom", "N")
backend.addValue( p_conv = convert_unit_function("eV/angstrom^3", "Pa")
"single_configuration_calculation_to_system_ref", self.lastSystemDescription) root_section = self.parser.root_section
gIndexes = parser.tagSections["/modeling"] sscc = root_section.section_single_configuration_calculation[-1]
backend.addValue( sscc.single_configuration_calculation_to_system_ref = root_section.section_system[-1]
"single_configuration_to_calculation_method_ref", gIndexes["section_method"]) sscc.single_configuration_to_calculation_method_ref = root_section.section_method[-1]
for el in element: for el in element:
if el.tag == "energy": if el.tag == "energy":
for enEl in el: for en_el in el:
if enEl.tag == "i": if en_el.tag == "i":
name = enEl.attrib.get("name", None) name = en_el.attrib.get("name", None)
if name == "e_fr_energy": if name == "e_fr_energy":
value = eConv(float(enEl.text.strip())) value = e_conv(float(en_el.text.strip()))
backend.addValue("energy_free", value) sscc.energy_free = value
elif name == "e_wo_entrp": elif name == "e_wo_entrp":
value = eConv(float(enEl.text.strip())) value = e_conv(float(en_el.text.strip()))
backend.addValue("energy_total", value) sscc.energy_total = value
elif name == "e_0_energy": elif name == "e_0_energy":
value = eConv(float(enEl.text.strip())) value = e_conv(float(en_el.text.strip()))
backend.addValue("energy_total_T0", value) sscc.energy_total_T0 = value
else: self._energies.append(value)
backend.pwarn( elif en_el.tag == "varray":
"Unexpected i tag with name %s in energy section" % name) name = en_el.attrib.get("name", None)
elif enEl.tag == "varray":
name = enEl.attrib.get("name", None)
if name == "forces": if name == "forces":
f = getVector(enEl, lambda x: fConv(float(x))) f = get_vector(en_el, lambda x: f_conv(float(x)))
backend.addValue("atom_forces", f) sscc.atom_forces = f
elif name == 'stress': elif name == 'stress':
f = getVector(enEl, lambda x: pConv(float(x))) f = get_vector(en_el, lambda x: p_conv(float(x)))
backend.addValue("stress_tensor", f) sscc.stress_tensor = f
def onEnd_atominfo(self, parser, event, element, pathStr): def on_end_atominfo(self, element, path_str):
nAtoms = None root_section = self.parser.root_section
nAtomTypes = None atom_types = []
atomTypes = []
labels = [] labels = []
labels2 = None labels2 = None
atomTypesDesc = [] atom_types_desc = []
backend = parser.backend
for el in element: for el in element:
if el.tag == "atoms": if el.tag in ['atoms', 'types']:
nAtoms = int(el.text.strip()) pass
elif el.tag == "types":
nAtomTypes = int(el.text.strip())
elif el.tag == "array": elif el.tag == "array":
name = el.attrib.get("name", None) name = el.attrib.get("name", None)
if name == "atoms": if name == "atoms":
for atomsEl in el: for atoms_el in el:
if atomsEl.tag == "dimension": if atoms_el.tag == "dimension":
pass pass
elif atomsEl.tag == "field": elif atoms_el.tag == "field":
pass pass
elif atomsEl.tag == "set": elif atoms_el.tag == "set":
for atomsLine in atomsEl: for atoms_line in atoms_el:
if atomsLine.tag != "rc": if atoms_line.tag != "rc":
backend.pwarn( self.logger.warn(
"unexpected tag %s in atoms array in atominfo" % atomsLine.tag) "unexpected tag %s in atoms array in atominfo" % atoms_line.tag)
else: else:
line = atomsLine.findall("c") line = atoms_line.findall("c")
labels.append(line[0].text.strip()) labels.append(line[0].text.strip())
atomTypes.append(int(line[1].text.strip())) atom_types.append(int(line[1].text.strip()))
else: else:
backend.pwarn( self.logger.warn(
"unexpected tag %s in atoms array in atominfo" % atomsEl.tag) "unexpected tag %s in atoms array in atominfo" % atoms_el.tag)
elif name == "atomtypes": elif name == "atomtypes":
keys = [] keys = []
fieldTypes = [] field_types = []
for atomsEl in el: for atoms_el in el:
if atomsEl.tag == "dimension": if atoms_el.tag == "dimension":
pass pass
elif atomsEl.tag == "field": elif atoms_el.tag == "field":
keys.append(atomsEl.text.strip()) keys.append(atoms_el.text.strip())
fieldTypes.append( field_types.append(
atomsEl.attrib.get("type", "float")) atoms_el.attrib.get("type", "float"))
elif atomsEl.tag == "set": elif atoms_el.tag == "set":
expectedKeys = ["atomspertype", "element", expected_keys = [
"mass", "valence", "pseudopotential"] "atomspertype", "element", "mass", "valence", "pseudopotential"]
if keys != expectedKeys: if keys != expected_keys:
backend.pwarn( self.logger.warn(
"unexpected fields in atomtype: %s vs %s" % (keys, expectedKeys)) "unexpected fields in atomtype: %s vs %s" % (keys, expected_keys))
for atomsLine in atomsEl: for atoms_line in atoms_el:
if atomsLine.tag != "rc": if atoms_line.tag != "rc":
backend.pwarn( self.logger.warn(
"unexpected tag %s in atoms array in atominfo" % atomsLine.tag) "unexpected tag %s in atoms array in atominfo" % atoms_line.tag)
else: else:
line = atomsLine.findall("c") line = atoms_line.findall("c")
typeDesc = {} type_desc = {}
for i, k in enumerate(keys): for i, k in enumerate(keys):
fieldType = fieldTypes[i] field_type = field_types[i]
value = line[i].text value = line[i].text
if fieldType == "float": if field_type == "float":
value = float(value) value = float(value)
elif fieldType == "int": elif field_type == "int":
value = int(value) value = int(value)
else: else:
pass pass
typeDesc[k] = value type_desc[k] = value
atomTypesDesc.append(typeDesc) atom_types_desc.append(type_desc)
else: else:
backend.pwarn( self.logger.warn(
"unexpected tag %s in atomtypes array in atominfo" % atomsEl.tag) "unexpected tag %s in atomtypes array in atominfo" % atoms_el.tag)
kindIds = [] n_el = {}
nEl = {} kind_labels = []
kindLabels = [] for atom_desc in atom_types_desc:
for atomDesc in atomTypesDesc: section_method_atom_kind = root_section.section_method[-1].m_create(msection_method_atom_kind)
kindId = backend.openSection( if 'element' in atom_desc:
"section_method_atom_kind") elName = atom_desc['element'].strip()
if 'element' in atomDesc:
elName = atomDesc['element'].strip()
try: try:
elNr = ase.data.chemical_symbols.index(elName) elNr = ase.data.chemical_symbols.index(elName)
backend.addValue( section_method_atom_kind.method_atom_kind_atom_number = elNr
"method_atom_kind_atom_number", elNr)
except Exception as e: except Exception as e:
self.logger.error( self.logger.error(
"error finding element number for %r" % atomDesc['element'].strip(), "error finding element number for %r" % atom_desc['element'].strip(),
exc_info=e) exc_info=e)
nElNow = 1 + nEl.get(elName, 0) n_el_now = 1 + n_el.get(elName, 0)
nEl[elName] = nElNow n_el[elName] = n_el_now
elLabel = elName + \ el_label = elName + \
(str(nElNow) if nElNow > 1 else "") (str(n_el_now) if n_el_now > 1 else "")
kindLabels.append(elLabel) kind_labels.append(el_label)
backend.addValue("method_atom_kind_label", elLabel) section_method_atom_kind.method_atom_kind_label = el_label
if "mass" in atomDesc: if "mass" in atom_desc:
backend.addValue( section_method_atom_kind.method_atom_kind_mass = atom_desc["mass"]
"method_atom_kind_mass", atomDesc["mass"]) if "valence" in atom_desc:
if "valence" in atomDesc: section_method_atom_kind.method_atom_kind_explicit_electrons = atom_desc["valence"]
backend.addValue( if "pseudopotential" in atom_desc:
"method_atom_kind_explicit_electrons", atomDesc["valence"]) section_method_atom_kind.method_atom_kind_pseudopotential_name = atom_desc["pseudopotential"]
if "pseudopotential" in atomDesc: root_section.section_method[-1].x_vasp_atom_kind_refs = root_section.section_method[-1].section_method_atom_kind
backend.addValue( labels2 = [kind_labels[i - 1] for i in atom_types]
"method_atom_kind_pseudopotential_name", atomDesc["pseudopotential"])
kindIds.append(kindId)
backend.closeSection(
"section_method_atom_kind", kindId)
backend.addArrayValues("x_vasp_atom_kind_refs", np.asarray(
[kindIds[i-1] for i in atomTypes]))
labels2 = [kindLabels[i-1] for i in atomTypes]
else: else:
backend.pwarn( self.logger.warn(
"unexpected array named %s in atominfo" % name) "unexpected array named %s in atominfo" % name)
else: else:
backend.pwarn("unexpected tag %s in atominfo" % el.tag) self.logger.warn("unexpected tag %s in atominfo" % el.tag)
self.labels = np.asarray(labels2) if labels2 else np.asarray(labels) self.labels = np.asarray(labels2) if labels2 else np.asarray(labels)
def incarOutTag(self, el): def _metainfo_type(self, meta):
backend = self.parser.backend dtype = meta.type
metaEnv = self.parser.backend.metaInfoEnv() if dtype == str:
if (el.tag != "i"): return 'C'
backend.pwarn("unexpected tag %s %s %r in incar" % elif dtype == bool:
(el.tag, el.attrib, el.text)) return 'b'
elif dtype == int or type(dtype) == np.dtype:
return 'i'
elif dtype == float:
return 'f'
else: else:
name = el.attrib.get("name", None) return
valType = el.attrib.get("type")
meta = metaEnv['x_vasp_incarOut_' + name] def _incar_out_tag(self, el):
if (el.tag != "i"):
self.logger.warn("unexpected tag %s %s %r in incar" % (el.tag, el.attrib, el.text))
else:
root_section = self.parser.root_section
name = el.attrib.get("name", None)
val_type = el.attrib.get("type")
try:
meta = self.parser.metainfo_env.resolve_definition('x_vasp_incarOut_' + name, Quantity)
except Exception:
return
if not meta: if not meta:
# Unknown_Incars_Begin: storage into a dictionary # Unknown_Incars_Begin: storage into a dictionary
if not valType: if not val_type:
# On vasp's xml files, valType *could* be absent if incar value is float # On vasp's xml files, val_type *could* be absent if incar value is float
valType = 'float' val_type = 'float'
# map vasp's datatype to nomad's datatype [b, f, i, C, D, R] # map vasp's datatype to nomad's datatype [b, f, i, C, D, R]
nomad_dtypeStr = vasp_to_metainfo_type_mapping[valType][0] nomad_dtype_str = vasp_to_metainfo_type_mapping[val_type][0]
converter = metaTypeTransformers.get(nomad_dtypeStr) converter = meta_type_transformers.get(nomad_dtype_str)
text_value = el.text.strip() # text representation of incar value text_value = el.text.strip() # text representation of incar value
try: try:
pyvalue = converter(text_value) # python data type pyvalue = converter(text_value) # python data type
except Exception: except Exception:
pyvalue = text_value pyvalue = text_value
...@@ -718,42 +702,42 @@ class VasprunContext(object): ...@@ -718,42 +702,42 @@ class VasprunContext(object):
self.unknown_incars[name] = pyvalue self.unknown_incars[name] = pyvalue
# Unknown_Incars_end # Unknown_Incars_end
else: else:
if not valType: if not val_type:
valType = 'float' val_type = 'float'
vasp_metainfo_type = vasp_to_metainfo_type_mapping.get(valType)[0] vasp_metainfo_type = vasp_to_metainfo_type_mapping.get(val_type)[0]
metainfo_type = meta.get('dtypeStr') metainfo_type = self._metainfo_type(meta)
if not vasp_metainfo_type: if not vasp_metainfo_type:
backend.pwarn("Unknown value type %s encountered in INCAR out: %s %s %r" % ( self.logger.warn("Unknown value type %s encountered in INCAR out: %s %s %r" % (
valType, el.tag, el.attrib, el.text)) val_type, el.tag, el.attrib, el.text))
elif metainfo_type != vasp_metainfo_type: elif metainfo_type != vasp_metainfo_type:
if (metainfo_type == 'C' and vasp_metainfo_type == 'b'): if (metainfo_type == 'C' and vasp_metainfo_type == 'b'):
pass pass
elif (metainfo_type == 'i' and vasp_metainfo_type == 'f'): elif (metainfo_type == 'i' and vasp_metainfo_type == 'f'):
pass pass
else: else:
backend.pwarn("Data type mismatch: %s. Vasp_type: %s, metainfo_type: %s " % self.logger.warn(
(name, vasp_metainfo_type, metainfo_type)) "Data type mismatch: %s. Vasp_type: %s, metainfo_type: %s " % (
name, vasp_metainfo_type, metainfo_type))
try: try:
shape = meta.get("shape", None) shape = meta.get("shape")
converter = metaTypeTransformers.get(metainfo_type) converter = meta_type_transformers.get(metainfo_type)
if not converter: if not converter:
backend.pwarn( self.logger.warn(
"could not find converter for dtypeStr %s when handling meta info %s" % "could not find converter for %s when handling meta info %s" %
(metainfo_type, meta )) (metainfo_type, meta))
elif shape: elif shape:
vals = re.split("\s+", el.text.strip()) vals = re.split(r"\s+", el.text.strip())
backend.addValue( setattr(root_section.section_method[-1], meta["name"], [converter(x) for x in vals])
meta["name"], [converter(x) for x in vals])
else: else:
# If-block to handle incars without value # If-block to handle incars without value
if el.text == None: if not el.text:
el.text = '' el.text = ''
backend.addValue(meta["name"], converter(el.text)) setattr(root_section.section_method[-1], meta["name"], converter(el.text))
except: except Exception:
backend.pwarn("Exception trying to handle incarOut %s: %s" % ( self.logger.warn("Exception trying to handle incarOut %s: %s" % (
name, traceback.format_exc())) name, traceback.format_exc()))
if name == 'ENMAX' or name == 'PREC': if name == 'ENMAX' or name == 'PREC':
...@@ -765,7 +749,7 @@ class VasprunContext(object): ...@@ -765,7 +749,7 @@ class VasprunContext(object):
else: else:
self.prec = 1.0 self.prec = 1.0
if name == 'GGA': if name == 'GGA':
fMap = { f_map = {
'91': ['GGA_X_PW91', 'GGA_C_PW91'], '91': ['GGA_X_PW91', 'GGA_C_PW91'],
'PE': ['GGA_X_PBE', 'GGA_C_PBE'], 'PE': ['GGA_X_PBE', 'GGA_C_PBE'],
'RP': ['GGA_X_RPBE', 'GGA_C_PBE'], 'RP': ['GGA_X_RPBE', 'GGA_C_PBE'],
...@@ -773,80 +757,63 @@ class VasprunContext(object): ...@@ -773,80 +757,63 @@ class VasprunContext(object):
'MK': ['GGA_X_OPTB86_VDW'], 'MK': ['GGA_X_OPTB86_VDW'],
'--': ['GGA_X_PBE', 'GGA_C_PBE'] # should check potcar '--': ['GGA_X_PBE', 'GGA_C_PBE'] # should check potcar
} }
functs = fMap.get(el.text.strip(), None) functs = f_map.get(el.text.strip(), None)
if not functs: if not functs:
backend.pwarn("Unknown XC functional %s" % self.logger.warn("Unknown XC functional %s" % el.text.strip())
el.text.strip())
else: else:
for f in functs: for f in functs:
backend.openNonOverlappingSection( section_XC_functionals = root_section.section_method[-1].m_create(msection_XC_functionals)
"section_XC_functionals") section_XC_functionals.XC_functional_name = f
backend.addValue("XC_functional_name", f)
backend.closeNonOverlappingSection(
"section_XC_functionals")
elif name == "ISPIN": elif name == "ISPIN":
self.ispin = int(el.text.strip()) self.ispin = int(el.text.strip())
def _separator_scan(self, element, depth=0):
def separatorScan(self, element, backend, depth=0):
for separators in element: for separators in element:
if separators.tag == "separator": if separators.tag == "separator":
separatorName = separators.attrib.get("name")
for el in separators: for el in separators:
if el.tag == "i": if el.tag == "i":
self.incarOutTag(el) self._incar_out_tag(el)
elif el.tag == "separator": elif el.tag == "separator":
self.separatorScan(el, backend, depth + 1) self._separator_scan(el, depth + 1)
else: else:
# backend.pwarn("unexpected tag %s %s in parameters separator %s at depth %d" % (
# el.tag, el.attrib, separatorName, depth))
pass pass
elif separators.tag == "i": elif separators.tag == "i":
self.incarOutTag(separators) self._incar_out_tag(separators)
else: else:
# backend.pwarn("unexpected tag %s %s in parameters at depth %d" % (
# separators.tag, separators.attrib, depth))
pass pass
def onEnd_parameters(self, parser, event, element, pathStr): def on_end_parameters(self, element, path_str):
self.separatorScan(element, parser.backend) self._separator_scan(element)
backend = parser.backend root_section = self.parser.root_section
try: try:
self.prec self.prec
try: try:
self.enmax self.enmax
self.waveCut = backend.openNonOverlappingSection( self.waveCut = root_section.m_create(msection_basis_set_cell_dependent)
"section_basis_set_cell_dependent") self.waveCut.basis_set_planewave_cutoff = eV2J(self.enmax * self.prec)
backend.addValue("basis_set_planewave_cutoff",
eV2J(self.enmax*self.prec)) section_method_basis_set = root_section.section_method[-1].m_create(msection_method_basis_set)
backend.closeNonOverlappingSection( section_method_basis_set.mapping_section_method_basis_set_cell_associated = self.waveCut
"section_basis_set_cell_dependent")
backend.openNonOverlappingSection("section_method_basis_set")
backend.addValue(
"mapping_section_method_basis_set_cell_associated", self.waveCut)
backend.closeNonOverlappingSection("section_method_basis_set")
except AttributeError: except AttributeError:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
backend.pwarn( self.logger.warn(
"Missing ENMAX for calculating plane wave basis cut off ") "Missing ENMAX for calculating plane wave basis cut off ")
except AttributeError: except AttributeError:
backend.pwarn( self.logger.pwarn(
"Missing PREC for calculating plane wave basis cut off ") "Missing PREC for calculating plane wave basis cut off ")
def onEnd_dos(self, parser, event, element, pathStr): def on_end_dos(self, element, path_str):
"density of states" "density of states"
backend = parser.backend root_section = self.parser.root_section
backend.openNonOverlappingSection("section_dos") section_dos = root_section.section_single_configuration_calculation[-1].m_create(msection_dos)
for el in element: for el in element:
if el.tag == "i": if el.tag == "i":
if el.attrib.get("name") == "efermi": if el.attrib.get("name") == "efermi":
self.eFermi = eV2J(float(el.text.strip())) self.e_fermi = eV2J(float(el.text.strip()))
backend.addArrayValues( section_dos.energy_reference_fermi = np.array([self.e_fermi] * self.ispin)
"energy_reference_fermi", np.array([self.eFermi] * self.ispin))
else: else:
backend.pwarn("unexpected tag %s %s in dos" % self.logger.warn("unexpected tag %s %s in dos" % (el.tag, el.attrib))
(el.tag, el.attrib))
elif el.tag == "total": elif el.tag == "total":
for el1 in el: for el1 in el:
if el1.tag == "array": if el1.tag == "array":
...@@ -855,20 +822,20 @@ class VasprunContext(object): ...@@ -855,20 +822,20 @@ class VasprunContext(object):
pass pass
elif el2.tag == "set": elif el2.tag == "set":
dosL = [] dosL = []
for spinComponent in el2: for spin_component in el2:
if spinComponent.tag == "set": if spin_component.tag == "set":
dosL.append( dosL.append(
getVector(spinComponent, field="r")) get_vector(spin_component, field="r"))
else: else:
backend.pwarn("unexpected tag %s %s in dos total array set" % ( self.logger.warn("unexpected tag %s %s in dos total array set" % (
spinComponent.tag, spinComponent.attrib)) spin_component.tag, spin_component.attrib))
dosA = np.asarray(dosL) dos_a = np.asarray(dosL)
if len(dosA.shape) != 3: if len(dos_a.shape) != 3:
raise Exception("unexpected shape %s (%s) for total dos (ragged arrays?)" % ( raise Exception("unexpected shape %s (%s) for total dos (ragged arrays?)" % (
dosA.shape), dosA.dtype) dos_a.shape), dos_a.dtype)
dosE = eV2JV(dosA[0, :, 0]) dos_e = eV2JV(dos_a[0, :, 0])
dosI = dosA[:, :, 2] dos_i = dos_a[:, :, 2]
dosV = dosA[:, :, 1] dos_v = dos_a[:, :, 1]
# Convert the DOS values to SI. VASP uses the # Convert the DOS values to SI. VASP uses the
# following units in the output: # following units in the output:
...@@ -878,18 +845,17 @@ class VasprunContext(object): ...@@ -878,18 +845,17 @@ class VasprunContext(object):
# the integrated dos value is the number of electrons until that energy level # the integrated dos value is the number of electrons until that energy level
# and thus not directly energy dependent anymore # and thus not directly energy dependent anymore
joule_in_ev = convert_unit(1, "eV", "J") joule_in_ev = convert_unit(1, "eV", "J")
dosV = dosV / joule_in_ev dos_v = dos_v / joule_in_ev
backend.addArrayValues("dos_energies", dosE) section_dos.dos_energies = dos_e
cell_volume = np.abs(np.linalg.det(self.cell)) cell_volume = np.abs(np.linalg.det(self.cell))
backend.addArrayValues("dos_values", dosV * cell_volume) section_dos.dos_values = dos_v * cell_volume
backend.addArrayValues( section_dos.dos_integrated_values = dos_i
"dos_integrated_values", dosI)
else: else:
backend.pwarn("unexpected tag %s %s in dos total array" % ( self.logger.warn("unexpected tag %s %s in dos total array" % (
el2.tag, el2.attrib)) el2.tag, el2.attrib))
else: else:
backend.pwarn("unexpected tag %s %s in dos total" % ( self.logger.warn("unexpected tag %s %s in dos total" % (
el2.tag, el2.attrib)) el2.tag, el2.attrib))
elif el.tag == "partial": elif el.tag == "partial":
for el1 in el: for el1 in el:
...@@ -924,42 +890,38 @@ class VasprunContext(object): ...@@ -924,42 +890,38 @@ class VasprunContext(object):
if atom.tag == "set": if atom.tag == "set":
atomL = [] atomL = []
dosL.append(atomL) dosL.append(atomL)