From f4ceb52f53c713b2b317994f70066e8c5783bfd6 Mon Sep 17 00:00:00 2001 From: Han Lin Mai Date: Tue, 26 Dec 2023 19:47:29 +0100 Subject: [PATCH 1/5] Fix non parsing of INCAR/generator block --- pyiron_atomistics/vasp/vasprun.py | 98 +++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 6 deletions(-) diff --git a/pyiron_atomistics/vasp/vasprun.py b/pyiron_atomistics/vasp/vasprun.py index a42d8483b..6c5f0cc57 100644 --- a/pyiron_atomistics/vasp/vasprun.py +++ b/pyiron_atomistics/vasp/vasprun.py @@ -84,8 +84,7 @@ def parse_root_to_dict(self, filename): for _, leaf in ETree.iterparse(filename): if leaf.tag in ["generator", "incar"]: d[leaf.tag] = dict() - for items in leaf: - d[leaf.tag] = self.parse_item_to_dict(items, d[leaf.tag]) + d[leaf.tag] = self.parse_container_element(leaf, d[leaf.tag]) if leaf.tag in ["kpoints"]: d[leaf.tag] = dict() self.parse_kpoints_to_dict(leaf, d[leaf.tag]) @@ -538,18 +537,41 @@ def parse_structure_to_dict(self, node, d): if leaf.tag == "varray" and leaf.attrib["name"] == "selective": d["selective_dynamics"] = self._parse_2d_matrix(leaf, vec_type=bool) + + def parse_container_element(self, container, d): + """ + Parses XML container elements into a dictionary. This method is specifically + designed to handle elements within 'generator' and 'incar' tags of a VASP XML file. + It processes elements with 'i' and 'v' tags, using different parsing methods for each. + + Args: + container (xml.etree.Element): An XML element that contains child elements to be parsed. + Typically, this would be a 'generator' or 'incar' element. + Returns: + dict: A dictionary containing parsed data from the XML container. Keys are the names + of the elements, and values are the parsed data, which could be a simple value + or a list, depending on the element type. + """ + for item in container: + if item.tag == 'i': + d.update(self.parse_item_to_dict(item, d)) + elif item.tag == 'v': + d[item.attrib["name"]] = self.parse_INCAR_vector_to_list(item) + return d + @staticmethod def parse_item_to_dict(node, d): """ - Parses values from an item to a dictionary + Parses an XML element with the tag 'i' into a dictionary. The method handles different + data types specified in the 'type' attribute of the element (e.g., string, float, int, logical). Args: - node (etree.Element instance): Node to be parsed - d (dict): The dictionary to which data is to be parsed + node (xml.etree.Element): An XML element with the tag 'i', containing data to be parsed. Returns: - d (dictionary) + dict: A dictionary with a single key-value pair. The key is the 'name' attribute of the element, + and the value is the parsed data, converted to the appropriate Python data type. """ type_dict = {"string": str, "float": float, "int": int, "logical": bool} logical_dict = {"T": True, "F": False} @@ -562,6 +584,70 @@ def parse_item_to_dict(node, d): d[node.attrib["name"]] = node.text return d + @staticmethod + def parse_INCAR_vector_to_list(node, filename=None): + """ + Parses an XML element with the tag 'v' into a list. This method is robust to conversion errors and + is specifically tailored for parsing vector data from the INCAR section of a VASP XML file. In case of + conversion errors, it can optionally read correct values from an INCAR file. + + Args: + node (xml.etree.Element): An XML element with the tag 'v', containing vector data to be parsed. + filename (str, optional): The path to an INCAR file used for error handling. If provided, + the method will attempt to read correct values from this file in case + of conversion errors. Defaults to None. + + Returns: + list: A list of parsed values. Each value is converted to the appropriate Python data type + based on the 'type' attribute of the element. + """ + val_type = node.attrib.get("type", "string") + values = node.text.strip().split() if node.text else [] + parsed_values = [] + for val in values: + try: + if val_type == "logical": + parsed_values.append(val == "T") + elif val_type == "int": + parsed_values.append(int(val)) + elif val_type == "float": + parsed_values.append(float(val)) + else: # Default case for string type + parsed_values.append(val) + except ValueError: + # Handle conversion error - placeholder for special handling + # For example, read from an INCAR file or set to a default value + # This part needs to be adapted based on your specific requirements + parsed_value = Vasprun.read_from_incar(filename, node.attrib["name"], val_type, val) + if parsed_value is not None: + parsed_values.append(parsed_value) + else: + raise ValueError(f"Error parsing value '{val}' in {node.attrib['name']}") + + return parsed_values + + @staticmethod + def read_from_incar(filename, param_name, val_type, val): + """ + Placeholder method for reading and parsing parameter values from an INCAR file. This method is intended + to be used for handling special cases where values in the VASP XML file are not correctly formatted. + + Args: + filename (str): The path to the INCAR file. + param_name (str): The name of the parameter to be read. + val_type (str): The expected data type of the parameter ('string', 'float', 'int', 'logical'). + val (str): The original value from the XML file that needs special handling. + + Returns: + The correct value read from the INCAR file, or None if the value cannot be determined. The return + type should match the expected `val_type`. + """ + pass + # Placeholder for special handling logic + # Adapt this method based on specific handling logic for irregular values + # For example, read from an INCAR file or set to a default value + return None + def parse_parameters(self, node, d): """ Parses parameter data from a node to a dictionary From 7f7035be666ad2432067667b406e2fb42aae8f43 Mon Sep 17 00:00:00 2001 From: Han Lin Mai Date: Tue, 26 Dec 2023 20:11:40 +0100 Subject: [PATCH 2/5] just borrow pymatgen implementation --- pyiron_atomistics/vasp/vasprun.py | 150 +++++++++++++++++------------- 1 file changed, 87 insertions(+), 63 deletions(-) diff --git a/pyiron_atomistics/vasp/vasprun.py b/pyiron_atomistics/vasp/vasprun.py index 6c5f0cc57..a486d4b54 100644 --- a/pyiron_atomistics/vasp/vasprun.py +++ b/pyiron_atomistics/vasp/vasprun.py @@ -57,6 +57,7 @@ def from_file(self, filename="vasprun.xml"): """ if not (os.path.isfile(filename)): raise AssertionError() + self.filename=filename try: self.parse_root_to_dict(filename) except ParseError: @@ -83,8 +84,7 @@ def parse_root_to_dict(self, filename): d["stress_tensors"] = list() for _, leaf in ETree.iterparse(filename): if leaf.tag in ["generator", "incar"]: - d[leaf.tag] = dict() - d[leaf.tag] = self.parse_container_element(leaf, d[leaf.tag]) + d[leaf.tag] = self._parse_INCAR_and_generator(leaf) if leaf.tag in ["kpoints"]: d[leaf.tag] = dict() self.parse_kpoints_to_dict(leaf, d[leaf.tag]) @@ -537,28 +537,95 @@ def parse_structure_to_dict(self, node, d): if leaf.tag == "varray" and leaf.attrib["name"] == "selective": d["selective_dynamics"] = self._parse_2d_matrix(leaf, vec_type=bool) - - def parse_container_element(self, container, d): + + def _parse_INCAR_generator_parameters(self, val_type, val): + """ + Helper function to convert a Vasprun parameter into the proper type. + Boolean, int and float types are converted. + + Args: + val_type: Value type parsed from vasprun.xml. + val: Actual string value parsed for vasprun.xml. + """ + if val_type == "logical": + return val == "T" + if val_type == "int": + return int(val) + if val_type == "string": + return val.strip() + return float(val) + + + def _parse_INCAR_generator_vector_parameters(self, val_type, val, filename, param_name): """ - Parses XML container elements into a dictionary. This method is specifically - designed to handle elements within 'generator' and 'incar' tags of a VASP XML file. - It processes elements with 'i' and 'v' tags, using different parsing methods for each. + Helper function to convert a Vasprun array-type parameter into the proper + type. Boolean, int and float types are converted. Args: - container (xml.etree.Element): An XML element that contains child elements to be parsed. - Typically, this would be a 'generator' or 'incar' element. + val_type: Value type parsed from vasprun.xml. + val: Actual string value parsed for vasprun.xml. + filename: Fullpath of vasprun.xml. Used for robust error handling. + E.g., if vasprun.xml contains *** for some Incar parameters, + the code will try to read from an INCAR file present in the same + directory. + param_name: Name of parameter. Returns: - dict: A dictionary containing parsed data from the XML container. Keys are the names - of the elements, and values are the parsed data, which could be a simple value - or a list, depending on the element type. - """ - for item in container: - if item.tag == 'i': - d.update(self.parse_item_to_dict(item, d)) - elif item.tag == 'v': - d[item.attrib["name"]] = self.parse_INCAR_vector_to_list(item) - return d + Parsed value. + """ + err = ValueError("Error in parsing vasprun.xml") + if val_type == "logical": + val = [i == "T" for i in val.split()] + elif val_type == "int": + try: + val = [int(i) for i in val.split()] + except ValueError: + # Fix for stupid error in vasprun sometimes which displays + # LDAUL/J as 2**** + val = self._parse_from_incar(filename, param_name) + if val is None: + raise err + elif val_type == "string": + val = val.split() + else: + try: + val = [float(i) for i in val.split()] + except ValueError: + # Fix for stupid error in vasprun sometimes which displays + # MAGMOM as 2**** + # val = self._parse_from_incar(filename, param_name) + va + if val is None: + raise err + return val + + def _parse_INCAR_and_generator(self, elem): + params = {} + for c in elem: + name = c.attrib.get("name") + if c.tag not in ("i", "v"): + p = self._parse_INCAR_and_generator(c) + if name == "response functions": + # Delete duplicate fields from "response functions", + # which overrides the values in the root params. + p = {k: v for k, v in p.items() if k not in params} + params.update(p) + else: + ptype = c.attrib.get("type") + val = c.text.strip() if c.text else "" + try: + if c.tag == "i": + params[name] = self._parse_INCAR_generator_parameters(ptype, val) + else: + params[name] = self._parse_INCAR_generator_vector_parameters(ptype, val, self.filename, name) + except Exception as exc: + if name == "RANDOM_SEED": + # Handles the case where RANDOM SEED > 99999, which results in ***** + params[name] = None + else: + raise exc + elem.clear() + return params @staticmethod def parse_item_to_dict(node, d): @@ -584,50 +651,7 @@ def parse_item_to_dict(node, d): d[node.attrib["name"]] = node.text return d - @staticmethod - def parse_INCAR_vector_to_list(node, filename=None): - """ - Parses an XML element with the tag 'v' into a list. This method is robust to conversion errors and - is specifically tailored for parsing vector data from the INCAR section of a VASP XML file. In case of - conversion errors, it can optionally read correct values from an INCAR file. - - Args: - node (xml.etree.Element): An XML element with the tag 'v', containing vector data to be parsed. - filename (str, optional): The path to an INCAR file used for error handling. If provided, - the method will attempt to read correct values from this file in case - of conversion errors. Defaults to None. - - Returns: - list: A list of parsed values. Each value is converted to the appropriate Python data type - based on the 'type' attribute of the element. - """ - val_type = node.attrib.get("type", "string") - values = node.text.strip().split() if node.text else [] - parsed_values = [] - for val in values: - try: - if val_type == "logical": - parsed_values.append(val == "T") - elif val_type == "int": - parsed_values.append(int(val)) - elif val_type == "float": - parsed_values.append(float(val)) - else: # Default case for string type - parsed_values.append(val) - except ValueError: - # Handle conversion error - placeholder for special handling - # For example, read from an INCAR file or set to a default value - # This part needs to be adapted based on your specific requirements - parsed_value = Vasprun.read_from_incar(filename, node.attrib["name"], val_type, val) - if parsed_value is not None: - parsed_values.append(parsed_value) - else: - raise ValueError(f"Error parsing value '{val}' in {node.attrib['name']}") - - return parsed_values - - @staticmethod - def read_from_incar(filename, param_name, val_type, val): + def _parse_from_incar(self, param_name, val_type, val): """ Placeholder method for reading and parsing parameter values from an INCAR file. This method is intended to be used for handling special cases where values in the VASP XML file are not correctly formatted. From d40487efdf789231a18547e2d8b3c0f6ceabc262 Mon Sep 17 00:00:00 2001 From: pyiron-runner Date: Tue, 26 Dec 2023 19:18:37 +0000 Subject: [PATCH 3/5] Format black --- pyiron_atomistics/vasp/vasprun.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/pyiron_atomistics/vasp/vasprun.py b/pyiron_atomistics/vasp/vasprun.py index a486d4b54..a73529b39 100644 --- a/pyiron_atomistics/vasp/vasprun.py +++ b/pyiron_atomistics/vasp/vasprun.py @@ -57,7 +57,7 @@ def from_file(self, filename="vasprun.xml"): """ if not (os.path.isfile(filename)): raise AssertionError() - self.filename=filename + self.filename = filename try: self.parse_root_to_dict(filename) except ParseError: @@ -537,7 +537,7 @@ def parse_structure_to_dict(self, node, d): if leaf.tag == "varray" and leaf.attrib["name"] == "selective": d["selective_dynamics"] = self._parse_2d_matrix(leaf, vec_type=bool) - + def _parse_INCAR_generator_parameters(self, val_type, val): """ Helper function to convert a Vasprun parameter into the proper type. @@ -555,8 +555,9 @@ def _parse_INCAR_generator_parameters(self, val_type, val): return val.strip() return float(val) - - def _parse_INCAR_generator_vector_parameters(self, val_type, val, filename, param_name): + def _parse_INCAR_generator_vector_parameters( + self, val_type, val, filename, param_name + ): """ Helper function to convert a Vasprun array-type parameter into the proper type. Boolean, int and float types are converted. @@ -615,9 +616,13 @@ def _parse_INCAR_and_generator(self, elem): val = c.text.strip() if c.text else "" try: if c.tag == "i": - params[name] = self._parse_INCAR_generator_parameters(ptype, val) + params[name] = self._parse_INCAR_generator_parameters( + ptype, val + ) else: - params[name] = self._parse_INCAR_generator_vector_parameters(ptype, val, self.filename, name) + params[name] = self._parse_INCAR_generator_vector_parameters( + ptype, val, self.filename, name + ) except Exception as exc: if name == "RANDOM_SEED": # Handles the case where RANDOM SEED > 99999, which results in ***** @@ -626,11 +631,11 @@ def _parse_INCAR_and_generator(self, elem): raise exc elem.clear() return params - + @staticmethod def parse_item_to_dict(node, d): """ - Parses an XML element with the tag 'i' into a dictionary. The method handles different + Parses an XML element with the tag 'i' into a dictionary. The method handles different data types specified in the 'type' attribute of the element (e.g., string, float, int, logical). Args: @@ -653,7 +658,7 @@ def parse_item_to_dict(node, d): def _parse_from_incar(self, param_name, val_type, val): """ - Placeholder method for reading and parsing parameter values from an INCAR file. This method is intended + Placeholder method for reading and parsing parameter values from an INCAR file. This method is intended to be used for handling special cases where values in the VASP XML file are not correctly formatted. Args: @@ -671,7 +676,7 @@ def _parse_from_incar(self, param_name, val_type, val): # Adapt this method based on specific handling logic for irregular values # For example, read from an INCAR file or set to a default value return None - + def parse_parameters(self, node, d): """ Parses parameter data from a node to a dictionary From 226f5e409e6a1de9bb683c829a6f7ebe9dec559d Mon Sep 17 00:00:00 2001 From: Han Lin Mai Date: Tue, 26 Dec 2023 22:36:09 +0100 Subject: [PATCH 4/5] improve previously useless tests --- tests/vasp/test_vasprun.py | 106 ++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 2 deletions(-) diff --git a/tests/vasp/test_vasprun.py b/tests/vasp/test_vasprun.py index 24612b8ef..5fde8de8f 100644 --- a/tests/vasp/test_vasprun.py +++ b/tests/vasp/test_vasprun.py @@ -48,6 +48,89 @@ def test_get_potentiostat_output(self): self.assertIsNone(vp.get_potentiostat_output()) def test_parse_generator(self): + vasprun_data = { + 'vasprun_1.xml': { + 'program': 'vasp', + 'version': '4.6.28', + 'subversion': '25Jul05 complex parallel', + 'platform': 'LinuxIFC', + 'date': '2016 04 10', + 'time': '17:29:20' + }, + 'vasprun_2.xml': { + 'program': 'vasp', + 'version': '5.3.5', + 'subversion': '31Mar14 (build Apr 17 2014 15:55:21) complex parallel', + 'platform': 'LinuxIFC', + 'date': '2016 06 22', + 'time': '20:08:33' + }, + 'vasprun_3.xml': { + 'program': 'vasp', + 'version': '5.3.5', + 'subversion': '31Mar14 (build Dec 16 2016 13:46:59) complex parallel', + 'platform': 'LinuxIFC', + 'date': '2017 04 25', + 'time': '19:09:22' + }, + 'vasprun_4.xml': { + 'program': 'vasp', + 'version': '5.3.5', + 'subversion': '31Mar14 (build Dec 16 2016 13:46:59) complex parallel', + 'platform': 'LinuxIFC', + 'date': '2017 04 25', + 'time': '19:47:01' + }, + 'vasprun_5.xml': { + 'program': 'vasp', + 'version': '5.3.5', + 'subversion': '31Mar14 (build Dec 16 2016 13:46:59) complex parallel', + 'platform': 'LinuxIFC', + 'date': '2017 04 26', + 'time': '12:55:54' + }, + 'vasprun_6.xml': { + 'program': 'vasp', + 'version': '5.4.1', + 'subversion': '24Jun15 (build Dec 18 2016 09:48:16) gamma-only parallel', + 'platform': 'IFC91_ompi', + 'date': '2017 11 21', + 'time': '15:01:21' + }, + 'vasprun_7.xml': { + 'program': 'vasp', + 'version': '5.4.4.18Apr17-6-g9f103f2a35', + 'subversion': '(build Oct 10 2019 11:41:53) complex parallel', + 'platform': 'LinuxIFC', + 'date': '2019 12 02', + 'time': '06:30:52' + }, + 'vasprun_8.xml': { + 'program': 'vasp', + 'version': '5.4.4.18Apr17-6-g9f103f2a35', + 'subversion': '(build Oct 10 2019 11:41:53) complex parallel', + 'platform': 'LinuxIFC', + 'date': '2019 12 02', + 'time': '06:30:52' + }, + 'vasprun_9.xml': { + 'program': 'vasp', + 'version': '5.4.4.18Apr17-6-g9f103f2a35', + 'subversion': '(build Mar 04 2021 11:38:41) gamma-only parallel', + 'platform': 'LinuxIFC', + 'date': '2021 03 04', + 'time': '11:39:31' + }, + 'vasprun_line.xml': { + 'program': 'vasp', + 'version': '5.4.1', + 'subversion': '24Jun15 (build Dec 18 2016 09:36:42) complex parallel', + 'platform': 'IFC91_ompi', + 'date': '2019 03 19', + 'time': '16:54:22' + } + } + for vp in self.vp_list: self.assertIsInstance(vp.vasprun_dict["generator"], dict) self.assertTrue("program" in vp.vasprun_dict["generator"].keys()) @@ -56,10 +139,29 @@ def test_parse_generator(self): self.assertTrue("subversion" in vp.vasprun_dict["generator"].keys()) self.assertTrue("platform" in vp.vasprun_dict["generator"].keys()) self.assertTrue("date" in vp.vasprun_dict["generator"].keys()) + self.assertEqual(vp.vasprun_dict["generator"], vasprun_data[os.path.basename(vp.filename)]) + def test_parse_incar(self): - for vp in self.vp_list: - self.assertIsInstance(vp.vasprun_dict["incar"], dict) + expected_incar_outputs = { + 'vasprun_1.xml': {'SYSTEM': 'passivated_AlN_vacuum_118.0', 'ISTART': 0, 'PREC': 'accurate', 'ALGO': 'Fast', 'ICHARG': 2, 'NELM': 40, 'NELMDL': -5, 'NELMIN': 8, 'EDIFF': 1e-05, 'EDIFFG': 0.001, 'IBRION': 1, 'NSW': 10, 'ISIF': 2, 'ENCUT': 500.0, 'LREAL': False, 'ISMEAR': 2, 'SIGMA': 0.1, 'LWAVE': False, 'LCHARG': False, 'LVTOT': False, 'REF_TYPE': 'none'}, + 'vasprun_2.xml': {'SYSTEM': 'ToDo', 'ISTART': 0, 'PREC': 'accurate', 'ALGO': 'Fast', 'NELM': 300, 'IBRION': -1, 'ENCUT': 400.0, 'LREAL': False, 'SIGMA': 0.1, 'LCHARG': True, 'LVTOT': True, 'LORBIT': False, 'LDIPOL': True, 'IDIPOL': 3, 'DIP%EFIELD': -0.01}, + 'vasprun_3.xml': {'SYSTEM': 'ToDo', 'PREC': 'accurate', 'ALGO': 'Fast', 'NELM': 60, 'IBRION': -1, 'ENCUT': 250.0, 'LREAL': False, 'LWAVE': False, 'LORBIT': False}, + 'vasprun_4.xml': {'SYSTEM': 'ToDo', 'PREC': 'accurate', 'ALGO': 'Fast', 'NELM': 60, 'IBRION': -1, 'ENCUT': 250.0, 'LREAL': False, 'LWAVE': False, 'LORBIT': False}, + 'vasprun_5.xml': {'SYSTEM': 'ToDo', 'PREC': 'accurate', 'ALGO': 'Fast', 'NELM': 60, 'IBRION': -1, 'ENCUT': 250.0, 'LREAL': False, 'LWAVE': False, 'LORBIT': False}, + 'vasprun_6.xml': {'SYSTEM': 'ToDo', 'ISTART': 1, 'PREC': 'accurate', 'ALGO': 'Fast', 'NELM': 200, 'IBRION': -1, 'EDIFF': 1e-06, 'ISYM': 0, 'ENCUT': 500.0, 'LREAL': 'Auto', 'ISMEAR': -1, 'SIGMA': 0.1, 'LWAVE': True, 'LCHARG': True, 'LVTOT': True, 'LVHAR': True, 'LORBIT': False, 'KPOINT_BSE': [-1, 0, 0, 0], 'LDIPOL': True, 'IDIPOL': 3, 'DIPOL': [0.0, 0.0, 0.31870518]}, + 'vasprun_7.xml': {'SYSTEM': 'pseudo_H', 'PREC': 'accurate', 'ALGO': 'Fast', 'NELM': 400, 'IBRION': -1, 'LREAL': False, 'LWAVE': False, 'LORBIT': 0, 'KPOINT_BSE': [-1, 0, 0, 0]}, + 'vasprun_8.xml': {'SYSTEM': 'pseudo_H', 'PREC': 'accurate', 'ALGO': 'Fast', 'NELM': 400, 'IBRION': -1, 'LREAL': False, 'LWAVE': False, 'LORBIT': 0, 'KPOINT_BSE': [-1, 0, 0, 0]}, + 'vasprun_9.xml': {'SYSTEM': 'Ge.water', 'PREC': 'normal', 'ALGO': 'FAST', 'NELM': 100, 'IBRION': 0, 'EDIFF': 1e-05, 'EDIFFG': -0.01, 'NSW': 2, 'IWAVPR': 10, 'ISYM': 0, 'ENCUT': 400.0, 'POTIM': 0.5, 'TEBEG': 400.0, 'SMASS': -3.0, 'LREAL': 'A', 'ISMEAR': 0, 'SIGMA': 0.05, 'LWAVE': False, 'LCHARG': False, 'LVTOT': True, 'LVHAR': True, 'MDALGO': 5, 'CSVRTAU': 400.0, 'ICCE': 4, 'CCETYP': 3, 'POTTAU': 100.0, 'UBEG': 0.0, 'POTCAP': 0.03339719, 'ILOC': 3, 'KPOINT_BSE': [-1, 0, 0, 0], 'LDIPOL': True, 'IDIPOL': 3, 'DIPOL': [0.0, 0.0, 0.337978]}, + 'vasprun_line.xml': {'SYSTEM': 'Test2', 'ISTART': 0, 'PREC': 'high', 'ALGO': 'FAST', 'ICHARG': 11, 'NELM': 400, 'EDIFF': 1e-07, 'ENCUT': 450.0, 'LREAL': False, 'ISMEAR': 1, 'SIGMA': 0.1, 'LWAVE': False, 'LCHARG': True, 'LORBIT': False, 'KPOINT_BSE': [-1, 0, 0, 0]} + } + + for _, vp in enumerate(self.vp_list): + filename = os.path.basename(vp.filename) # Extract filename + self.assertIn(filename, expected_incar_outputs) # Ensure expected output is defined for this file + expected_incar = expected_incar_outputs[filename] + actual_incar = vp.vasprun_dict["incar"] + self.assertEqual(actual_incar, expected_incar) def test_parse_kpoints(self): for vp in self.vp_list: From 237d795c65e1a415ad520b9ae17a6129d4a26dd9 Mon Sep 17 00:00:00 2001 From: pyiron-runner Date: Sat, 27 Jan 2024 11:52:35 +0000 Subject: [PATCH 5/5] Format black --- pyiron_atomistics/atomistics/job/atomistic.py | 12 +-- .../atomistics/master/phonopy.py | 6 +- .../atomistics/structure/atoms.py | 27 +++--- pyiron_atomistics/dft/bader.py | 1 - pyiron_atomistics/dft/waves/dos.py | 1 - pyiron_atomistics/dft/waves/electronic.py | 13 ++- pyiron_atomistics/interactive/quasi_newton.py | 7 +- pyiron_atomistics/lammps/base.py | 90 +++++++++--------- pyiron_atomistics/lammps/control.py | 6 +- pyiron_atomistics/lammps/interactive.py | 6 +- pyiron_atomistics/lammps/potential.py | 1 - pyiron_atomistics/sphinx/base.py | 8 +- pyiron_atomistics/testing/randomatomistic.py | 16 +--- pyiron_atomistics/vasp/base.py | 92 ++++++++++--------- pyiron_atomistics/vasp/parser/outcar.py | 22 +++-- pyiron_atomistics/vasp/vasprun.py | 7 +- 16 files changed, 153 insertions(+), 162 deletions(-) diff --git a/pyiron_atomistics/atomistics/job/atomistic.py b/pyiron_atomistics/atomistics/job/atomistic.py index e1d80e085..0eb2e799a 100644 --- a/pyiron_atomistics/atomistics/job/atomistic.py +++ b/pyiron_atomistics/atomistics/job/atomistic.py @@ -259,15 +259,15 @@ def calc_md( self._generic_input["temperature"] = temperature self._generic_input["n_ionic_steps"] = n_ionic_steps self._generic_input["n_print"] = n_print - self._generic_input[ - "temperature_damping_timescale" - ] = temperature_damping_timescale + self._generic_input["temperature_damping_timescale"] = ( + temperature_damping_timescale + ) if pressure is not None: self._generic_input["pressure"] = pressure if pressure_damping_timescale is not None: - self._generic_input[ - "pressure_damping_timescale" - ] = pressure_damping_timescale + self._generic_input["pressure_damping_timescale"] = ( + pressure_damping_timescale + ) if time_step is not None: self._generic_input["time_step"] = time_step self._generic_input.remove_keys(["max_iter"]) diff --git a/pyiron_atomistics/atomistics/master/phonopy.py b/pyiron_atomistics/atomistics/master/phonopy.py index 3724dc50d..e164f076a 100644 --- a/pyiron_atomistics/atomistics/master/phonopy.py +++ b/pyiron_atomistics/atomistics/master/phonopy.py @@ -277,9 +277,9 @@ def collect_output(self): hdf5_out["qpoints"] = mesh_dict["qpoints"] hdf5_out["supercell_matrix"] = self._phonopy_supercell_matrix() hdf5_out["displacement_dataset"] = self.phonopy.get_displacement_dataset() - hdf5_out[ - "dynamical_matrix" - ] = self.phonopy.dynamical_matrix.get_dynamical_matrix() + hdf5_out["dynamical_matrix"] = ( + self.phonopy.dynamical_matrix.get_dynamical_matrix() + ) hdf5_out["force_constants"] = self.phonopy.force_constants def write_phonopy_force_constants(self, file_name="FORCE_CONSTANTS", cwd=None): diff --git a/pyiron_atomistics/atomistics/structure/atoms.py b/pyiron_atomistics/atomistics/structure/atoms.py index 9b24b481a..8e46a93b1 100644 --- a/pyiron_atomistics/atomistics/structure/atoms.py +++ b/pyiron_atomistics/atomistics/structure/atoms.py @@ -2446,15 +2446,17 @@ def get_initial_magnetic_moments(self): ): return np.array( [ - [ - float(spin_dir) - for spin_dir in spin.replace("[", "") - .replace("]", "") - .replace(",", "") - .split() - ] - if spin - else [0.0, 0.0, 0.0] + ( + [ + float(spin_dir) + for spin_dir in spin.replace("[", "") + .replace("]", "") + .replace(",", "") + .split() + ] + if spin + else [0.0, 0.0, 0.0] + ) for spin in spin_lst ] ) @@ -3133,9 +3135,9 @@ def ase_to_pyiron(ase_obj): elif constraint_dict["name"] == "FixScaled": if "selective_dynamics" not in pyiron_atoms.arrays.keys(): pyiron_atoms.add_tag(selective_dynamics=[True, True, True]) - pyiron_atoms.selective_dynamics[ - constraint_dict["kwargs"]["a"] - ] = constraint_dict["kwargs"]["mask"] + pyiron_atoms.selective_dynamics[constraint_dict["kwargs"]["a"]] = ( + constraint_dict["kwargs"]["mask"] + ) else: warnings.warn("Unsupported ASE constraint: " + constraint_dict["name"]) return pyiron_atoms @@ -3404,7 +3406,6 @@ def default(data, dflt): class Symbols(ASESymbols): - """ Derived from the ase symbols class which has the following docs: diff --git a/pyiron_atomistics/dft/bader.py b/pyiron_atomistics/dft/bader.py index 0b125648c..c7260f8fd 100644 --- a/pyiron_atomistics/dft/bader.py +++ b/pyiron_atomistics/dft/bader.py @@ -19,7 +19,6 @@ class Bader: - """ Module to apply the Bader charge partitioning scheme to finished DFT jobs. This module is interfaced with the `Bader code`_ from the Greame Henkelmann group. diff --git a/pyiron_atomistics/dft/waves/dos.py b/pyiron_atomistics/dft/waves/dos.py index f4022991f..69adb87c2 100644 --- a/pyiron_atomistics/dft/waves/dos.py +++ b/pyiron_atomistics/dft/waves/dos.py @@ -18,7 +18,6 @@ class Dos(object): - """ The DOS class stores all information to store and retrieve the total and resolved density of states from an electronic structure calculation. diff --git a/pyiron_atomistics/dft/waves/electronic.py b/pyiron_atomistics/dft/waves/electronic.py index 2f9ac59ba..fb3e94af3 100644 --- a/pyiron_atomistics/dft/waves/electronic.py +++ b/pyiron_atomistics/dft/waves/electronic.py @@ -462,9 +462,9 @@ def grand_dos_matrix(self): for spin in range(self.n_spins): for i, kpt in enumerate(self.kpoints): for j, band in enumerate(kpt.bands): - self._grand_dos_matrix[ - spin, i, j, :, : - ] = band.resolved_dos_matrix + self._grand_dos_matrix[spin, i, j, :, :] = ( + band.resolved_dos_matrix + ) return self._grand_dos_matrix @grand_dos_matrix.setter @@ -624,9 +624,9 @@ def generate_from_matrices(self): occ = self.occupancy_matrix[spin][i][j] self.kpoints[-1].add_band(eigenvalue=val, occupancy=occ, spin=spin) if self._grand_dos_matrix is not None: - self.kpoints[-1].bands[spin][ - -1 - ].resolved_dos_matrix = self.grand_dos_matrix[spin, i, j, :, :] + self.kpoints[-1].bands[spin][-1].resolved_dos_matrix = ( + self.grand_dos_matrix[spin, i, j, :, :] + ) def get_spin_resolved_dos(self, spin_indices=0): """ @@ -751,7 +751,6 @@ def __repr__(self): class Kpoint(object): - """ All data related to a single k-point is stored in this module diff --git a/pyiron_atomistics/interactive/quasi_newton.py b/pyiron_atomistics/interactive/quasi_newton.py index 1d456ffb5..b07392dab 100644 --- a/pyiron_atomistics/interactive/quasi_newton.py +++ b/pyiron_atomistics/interactive/quasi_newton.py @@ -91,8 +91,7 @@ def inv_hessian(self): return np.einsum( "ik,k,jk->ij", self.eigenvectors, - self.eigenvalues - / (self.eigenvalues**2 + np.exp(self.regularization)), + self.eigenvalues / (self.eigenvalues**2 + np.exp(self.regularization)), self.eigenvectors, ) else: @@ -158,8 +157,7 @@ def _get_PSB(dx, dg, H_tmp): dH = (dH + dH.T) / dxdx return ( dH - - np.einsum("i,i,j,k->jk", dx, H_tmp, dx, dx, optimize="optimal") - / dxdx**2 + - np.einsum("i,i,j,k->jk", dx, H_tmp, dx, dx, optimize="optimal") / dxdx**2 ) @staticmethod @@ -255,7 +253,6 @@ def run_qn( class QuasiNewton(InteractiveWrapper): - """ Structure optimization scheme via Quasi-Newton algorithm. diff --git a/pyiron_atomistics/lammps/base.py b/pyiron_atomistics/lammps/base.py index 9b3738eaa..982f2ad1b 100644 --- a/pyiron_atomistics/lammps/base.py +++ b/pyiron_atomistics/lammps/base.py @@ -366,9 +366,9 @@ def enable_h5md(self): """ del self.input.control["dump_modify___1"] del self.input.control["dump___1"] - self.input.control[ - "dump___1" - ] = "all h5md ${dumptime} dump.h5 position force create_group yes" + self.input.control["dump___1"] = ( + "all h5md ${dumptime} dump.h5 position force create_group yes" + ) def write_input(self): """ @@ -902,79 +902,79 @@ def _set_selective_dynamics(self): self.input.control["group___constraintxyz"] = "id " + " ".join( [str(ind) for ind in constraint_xyz] ) - self.input.control[ - "fix___constraintxyz" - ] = "constraintxyz setforce 0.0 0.0 0.0" + self.input.control["fix___constraintxyz"] = ( + "constraintxyz setforce 0.0 0.0 0.0" + ) if self._generic_input["calc_mode"] == "md": - self.input.control[ - "velocity___constraintxyz" - ] = "set 0.0 0.0 0.0" + self.input.control["velocity___constraintxyz"] = ( + "set 0.0 0.0 0.0" + ) if len(constraint_xy) > 0: self.input.control["group___constraintxy"] = "id " + " ".join( [str(ind) for ind in constraint_xy] ) - self.input.control[ - "fix___constraintxy" - ] = "constraintxy setforce 0.0 0.0 NULL" + self.input.control["fix___constraintxy"] = ( + "constraintxy setforce 0.0 0.0 NULL" + ) if self._generic_input["calc_mode"] == "md": - self.input.control[ - "velocity___constraintxy" - ] = "set 0.0 0.0 NULL" + self.input.control["velocity___constraintxy"] = ( + "set 0.0 0.0 NULL" + ) if len(constraint_yz) > 0: self.input.control["group___constraintyz"] = "id " + " ".join( [str(ind) for ind in constraint_yz] ) - self.input.control[ - "fix___constraintyz" - ] = "constraintyz setforce NULL 0.0 0.0" + self.input.control["fix___constraintyz"] = ( + "constraintyz setforce NULL 0.0 0.0" + ) if self._generic_input["calc_mode"] == "md": - self.input.control[ - "velocity___constraintyz" - ] = "set NULL 0.0 0.0" + self.input.control["velocity___constraintyz"] = ( + "set NULL 0.0 0.0" + ) if len(constraint_zx) > 0: self.input.control["group___constraintxz"] = "id " + " ".join( [str(ind) for ind in constraint_zx] ) - self.input.control[ - "fix___constraintxz" - ] = "constraintxz setforce 0.0 NULL 0.0" + self.input.control["fix___constraintxz"] = ( + "constraintxz setforce 0.0 NULL 0.0" + ) if self._generic_input["calc_mode"] == "md": - self.input.control[ - "velocity___constraintxz" - ] = "set 0.0 NULL 0.0" + self.input.control["velocity___constraintxz"] = ( + "set 0.0 NULL 0.0" + ) if len(constraint_x) > 0: self.input.control["group___constraintx"] = "id " + " ".join( [str(ind) for ind in constraint_x] ) - self.input.control[ - "fix___constraintx" - ] = "constraintx setforce 0.0 NULL NULL" + self.input.control["fix___constraintx"] = ( + "constraintx setforce 0.0 NULL NULL" + ) if self._generic_input["calc_mode"] == "md": - self.input.control[ - "velocity___constraintx" - ] = "set 0.0 NULL NULL" + self.input.control["velocity___constraintx"] = ( + "set 0.0 NULL NULL" + ) if len(constraint_y) > 0: self.input.control["group___constrainty"] = "id " + " ".join( [str(ind) for ind in constraint_y] ) - self.input.control[ - "fix___constrainty" - ] = "constrainty setforce NULL 0.0 NULL" + self.input.control["fix___constrainty"] = ( + "constrainty setforce NULL 0.0 NULL" + ) if self._generic_input["calc_mode"] == "md": - self.input.control[ - "velocity___constrainty" - ] = "set NULL 0.0 NULL" + self.input.control["velocity___constrainty"] = ( + "set NULL 0.0 NULL" + ) if len(constraint_z) > 0: self.input.control["group___constraintz"] = "id " + " ".join( [str(ind) for ind in constraint_z] ) - self.input.control[ - "fix___constraintz" - ] = "constraintz setforce NULL NULL 0.0" + self.input.control["fix___constraintz"] = ( + "constraintz setforce NULL NULL 0.0" + ) if self._generic_input["calc_mode"] == "md": - self.input.control[ - "velocity___constraintz" - ] = "set NULL NULL 0.0" + self.input.control["velocity___constraintz"] = ( + "set NULL NULL 0.0" + ) @staticmethod def _modify_structure_to_allow_requested_deformation( diff --git a/pyiron_atomistics/lammps/control.py b/pyiron_atomistics/lammps/control.py index b6f750a0e..5462ac53a 100644 --- a/pyiron_atomistics/lammps/control.py +++ b/pyiron_atomistics/lammps/control.py @@ -816,9 +816,9 @@ def _fix_with_three_vector(self, ids, vector, fix_string, conversion): vector[i] = str(v * conversion) name = str(hash(tuple(ids))).replace("-", "m") # A unique name for the group self._set_group_by_id(name, ids) - self[ - "fix___{}_{}".format(fix_string.replace(" ", "_"), name) - ] = "{} {} {}".format(name, fix_string, " ".join(vector)) + self["fix___{}_{}".format(fix_string.replace(" ", "_"), name)] = ( + "{} {} {}".format(name, fix_string, " ".join(vector)) + ) def fix_move_linear_by_id(self, ids, velocity): """ diff --git a/pyiron_atomistics/lammps/interactive.py b/pyiron_atomistics/lammps/interactive.py index abeffc7b8..99dde397a 100644 --- a/pyiron_atomistics/lammps/interactive.py +++ b/pyiron_atomistics/lammps/interactive.py @@ -274,9 +274,9 @@ def function(ptr, timestep, nlocal, ids, x, fexternal): if not self.server.run_mode.interactive: raise AssertionError("Callback works only in interactive mode") self._user_fix_external = _FixExternal(function) - self.input.control[ - "fix___fix_external" - ] = "all external pf/callback {} {}".format(n_call, n_apply) + self.input.control["fix___fix_external"] = ( + "all external pf/callback {} {}".format(n_call, n_apply) + ) if overload_internal_fix_external: self._user_fix_external.fix_external = function diff --git a/pyiron_atomistics/lammps/potential.py b/pyiron_atomistics/lammps/potential.py index 01b55856b..b33beb04e 100644 --- a/pyiron_atomistics/lammps/potential.py +++ b/pyiron_atomistics/lammps/potential.py @@ -26,7 +26,6 @@ class LammpsPotential(GenericParameters): - """ This module helps write commands which help in the control of parameters related to the potential used in LAMMPS simulations diff --git a/pyiron_atomistics/sphinx/base.py b/pyiron_atomistics/sphinx/base.py index 28a9c55aa..af3b50776 100644 --- a/pyiron_atomistics/sphinx/base.py +++ b/pyiron_atomistics/sphinx/base.py @@ -2017,9 +2017,11 @@ def write_spin_constraints(self, file_name="spins.in", cwd=None, spins_list=None if self.structure.has("initial_magmoms"): if any( [ - True - if isinstance(spin, list) or isinstance(spin, np.ndarray) - else False + ( + True + if isinstance(spin, list) or isinstance(spin, np.ndarray) + else False + ) for spin in self.structure.get_initial_magnetic_moments() ] ): diff --git a/pyiron_atomistics/testing/randomatomistic.py b/pyiron_atomistics/testing/randomatomistic.py index fead998b1..fd213bc7a 100644 --- a/pyiron_atomistics/testing/randomatomistic.py +++ b/pyiron_atomistics/testing/randomatomistic.py @@ -467,9 +467,7 @@ def _s_r(self): return self.input["sigma"] / self.neigh.flattened.distances def interactive_energy_pot_getter(self): - return self.input["epsilon"] * ( - np.sum(self._s_r**12) - np.sum(self._s_r**6) - ) + return self.input["epsilon"] * (np.sum(self._s_r**12) - np.sum(self._s_r**6)) def interactive_energy_tot_getter(self): return ( @@ -479,13 +477,7 @@ def interactive_energy_tot_getter(self): def interadtive_energy_kin_getter(self): v = np.einsum("ni,n->", self._velocity**2, self.structure.get_masses()) / 2 return ( - ( - v - * self._unit.angstrom**2 - / self._unit.second**2 - / 1e-30 - * self._unit.amu - ) + (v * self._unit.angstrom**2 / self._unit.second**2 / 1e-30 * self._unit.amu) .to("eV") .magnitude ) @@ -529,9 +521,7 @@ def interactive_pressures_getter(self): * self._unit.amu ) return ( - (pot_part + kin_part) - / self.structure.get_volume() - / self._unit.angstrom**3 + (pot_part + kin_part) / self.structure.get_volume() / self._unit.angstrom**3 ).to(self._unit.pascal).magnitude / 1e9 def interactive_stress_getter(self): diff --git a/pyiron_atomistics/vasp/base.py b/pyiron_atomistics/vasp/base.py index f4fb61e27..f7494d5ea 100644 --- a/pyiron_atomistics/vasp/base.py +++ b/pyiron_atomistics/vasp/base.py @@ -458,9 +458,9 @@ def collect_output_parser(self, cwd): self._output_parser.generic_output.dft_log_dict["bader_charges"] = ( valence_charges - charges ) - self._output_parser.generic_output.dft_log_dict[ - "bader_volumes" - ] = volumes + self._output_parser.generic_output.dft_log_dict["bader_volumes"] = ( + volumes + ) return self._output_parser.to_dict() # define routines that collect all output files @@ -839,9 +839,9 @@ def get_final_structure_from_file(self, cwd, filename="CONTCAR"): species_list=input_structure.get_parent_symbols(), ) input_structure.cell = output_structure.cell.copy() - input_structure.positions[ - self.sorted_indices - ] = output_structure.positions + input_structure.positions[self.sorted_indices] = ( + output_structure.positions + ) except (IndexError, ValueError, IOError): raise IOError("Unable to read output structure") return input_structure @@ -856,9 +856,11 @@ def write_magmoms(self): if self.input.incar["ISPIN"] != 1: final_cmd = " ".join( [ - " ".join([str(spinmom) for spinmom in spin]) - if isinstance(spin, (list, np.ndarray)) - else str(spin) + ( + " ".join([str(spinmom) for spinmom in spin]) + if isinstance(spin, (list, np.ndarray)) + else str(spin) + ) for spin in self.structure.get_initial_magnetic_moments()[ self.sorted_indices ] @@ -2053,12 +2055,12 @@ def collect(self, directory=os.getcwd(), sorted_indices=None): final_magmoms[:, sorted_indices, :] = final_magmoms.copy() else: final_magmoms[:, sorted_indices] = final_magmoms.copy() - self.generic_output.dft_log_dict[ - "magnetization" - ] = magnetization.tolist() - self.generic_output.dft_log_dict[ - "final_magmoms" - ] = final_magmoms.tolist() + self.generic_output.dft_log_dict["magnetization"] = ( + magnetization.tolist() + ) + self.generic_output.dft_log_dict["final_magmoms"] = ( + final_magmoms.tolist() + ) self.generic_output.dft_log_dict["e_fermi_list"] = self.outcar.parse_dict[ "e_fermi_list" ] @@ -2120,9 +2122,9 @@ def collect(self, directory=os.getcwd(), sorted_indices=None): ] = self.electronic_structure.resolved_densities[:, :, :, :].copy() self.structure.positions = log_dict["positions"][-1] self.structure.set_cell(log_dict["cells"][-1]) - self.generic_output.dft_log_dict[ - "potentiostat_output" - ] = self.vp_new.get_potentiostat_output() + self.generic_output.dft_log_dict["potentiostat_output"] = ( + self.vp_new.get_potentiostat_output() + ) valence_charges_orig = self.vp_new.get_valence_electrons_per_atom() valence_charges = valence_charges_orig.copy() valence_charges[sorted_indices] = valence_charges_orig @@ -2154,9 +2156,9 @@ def collect(self, directory=os.getcwd(), sorted_indices=None): log_dict["volume"] = np.array( [np.linalg.det(cell) for cell in self.outcar.parse_dict["cells"]] ) - self.generic_output.dft_log_dict[ - "scf_energy_free" - ] = self.outcar.parse_dict["scf_energies"] + self.generic_output.dft_log_dict["scf_energy_free"] = ( + self.outcar.parse_dict["scf_energies"] + ) self.generic_output.dft_log_dict["scf_dipole_mom"] = self.outcar.parse_dict[ "scf_dipole_moments" ] @@ -2198,9 +2200,9 @@ def collect(self, directory=os.getcwd(), sorted_indices=None): self.generic_output.log_dict = log_dict if vasprun_working: # self.dft_output.log_dict["parameters"] = self.vp_new.vasprun_dict["parameters"] - self.generic_output.dft_log_dict[ - "scf_dipole_mom" - ] = self.vp_new.vasprun_dict["scf_dipole_moments"] + self.generic_output.dft_log_dict["scf_dipole_mom"] = ( + self.vp_new.vasprun_dict["scf_dipole_moments"] + ) if len(self.generic_output.dft_log_dict["scf_dipole_mom"][0]) > 0: total_dipole_moments = np.array( [ @@ -2209,15 +2211,15 @@ def collect(self, directory=os.getcwd(), sorted_indices=None): ] ) self.generic_output.dft_log_dict["dipole_mom"] = total_dipole_moments - self.generic_output.dft_log_dict[ - "scf_energy_int" - ] = self.vp_new.vasprun_dict["scf_energies"] - self.generic_output.dft_log_dict[ - "scf_energy_free" - ] = self.vp_new.vasprun_dict["scf_fr_energies"] - self.generic_output.dft_log_dict[ - "scf_energy_zero" - ] = self.vp_new.vasprun_dict["scf_0_energies"] + self.generic_output.dft_log_dict["scf_energy_int"] = ( + self.vp_new.vasprun_dict["scf_energies"] + ) + self.generic_output.dft_log_dict["scf_energy_free"] = ( + self.vp_new.vasprun_dict["scf_fr_energies"] + ) + self.generic_output.dft_log_dict["scf_energy_zero"] = ( + self.vp_new.vasprun_dict["scf_0_energies"] + ) self.generic_output.dft_log_dict["energy_int"] = np.array( [ e_int[-1] @@ -2236,9 +2238,9 @@ def collect(self, directory=os.getcwd(), sorted_indices=None): self.generic_output.dft_log_dict["energy_free"], np.round(self.oszicar.parse_dict["energy_pot"], 8), ): - self.generic_output.dft_log_dict[ - "energy_free" - ] = self.oszicar.parse_dict["energy_pot"] + self.generic_output.dft_log_dict["energy_free"] = ( + self.oszicar.parse_dict["energy_pot"] + ) self.generic_output.dft_log_dict["energy_zero"] = np.array( [ e_zero[-1] @@ -2250,12 +2252,12 @@ def collect(self, directory=os.getcwd(), sorted_indices=None): ) if "kinetic_energies" in self.vp_new.vasprun_dict.keys(): # scf_energy_kin is for backwards compatibility - self.generic_output.dft_log_dict[ - "scf_energy_kin" - ] = self.vp_new.vasprun_dict["kinetic_energies"] - self.generic_output.dft_log_dict[ - "energy_kin" - ] = self.vp_new.vasprun_dict["kinetic_energies"] + self.generic_output.dft_log_dict["scf_energy_kin"] = ( + self.vp_new.vasprun_dict["kinetic_energies"] + ) + self.generic_output.dft_log_dict["energy_kin"] = ( + self.vp_new.vasprun_dict["kinetic_energies"] + ) if ( "LOCPOT" in files_present @@ -2283,9 +2285,9 @@ def to_dict(self): hdf5_output["structure"] = self.structure.to_dict() if self.electrostatic_potential.total_data is not None: - hdf5_output[ - "electrostatic_potential" - ] = self.electrostatic_potential.to_dict() + hdf5_output["electrostatic_potential"] = ( + self.electrostatic_potential.to_dict() + ) if self.charge_density.total_data is not None: hdf5_output["charge_density"] = self.charge_density.to_dict() diff --git a/pyiron_atomistics/vasp/parser/outcar.py b/pyiron_atomistics/vasp/parser/outcar.py index cd4619428..ee3760c7c 100644 --- a/pyiron_atomistics/vasp/parser/outcar.py +++ b/pyiron_atomistics/vasp/parser/outcar.py @@ -1150,12 +1150,14 @@ def get_energy_components(filename="OUTCAR", lines=None): [ np.hstack( [ - float(lines[ind + i].split()[-1]) - if i != 7 - else [ - float(lines[ind_lst[-1] + 7].split()[-2]), - float(lines[ind_lst[-1] + 7].split()[-1]), - ] + ( + float(lines[ind + i].split()[-1]) + if i != 7 + else [ + float(lines[ind_lst[-1] + 7].split()[-2]), + float(lines[ind_lst[-1] + 7].split()[-1]), + ] + ) for i in range(2, 12) ] ) @@ -1205,9 +1207,11 @@ def _split_indices(ind_ionic_lst, ind_elec_lst): """ ind_elec_array = np.array(ind_elec_lst) return [ - ind_elec_array[(ind_elec_array < j2) & (j1 < ind_elec_array)] - if j1 < j2 - else ind_elec_array[(ind_elec_array < j2)] + ( + ind_elec_array[(ind_elec_array < j2) & (j1 < ind_elec_array)] + if j1 < j2 + else ind_elec_array[(ind_elec_array < j2)] + ) for j1, j2 in zip(np.roll(ind_ionic_lst, 1), ind_ionic_lst) ] diff --git a/pyiron_atomistics/vasp/vasprun.py b/pyiron_atomistics/vasp/vasprun.py index a73529b39..8c03e8d73 100644 --- a/pyiron_atomistics/vasp/vasprun.py +++ b/pyiron_atomistics/vasp/vasprun.py @@ -29,7 +29,6 @@ class Vasprun(object): - """ This module is used to parse vasprun.xml files and store the data consistent with the pyiron input/output storage formats. @@ -228,9 +227,9 @@ def parse_atom_information_to_dict(self, node, d): species_dict[special_element]["n_atoms"] = int( elements[0].text ) - species_dict[special_element][ - "valence" - ] = float(elements[3].text) + species_dict[special_element]["valence"] = ( + float(elements[3].text) + ) else: species_key = elements[1].text species_dict[species_key] = dict()