diff --git a/dpdata/gaussian/gjf.py b/dpdata/gaussian/gjf.py index c2051761c..21300a60b 100644 --- a/dpdata/gaussian/gjf.py +++ b/dpdata/gaussian/gjf.py @@ -4,6 +4,7 @@ """Generate Gaussian input file.""" import itertools +import re import uuid import warnings from typing import List, Optional, Tuple, Union @@ -272,3 +273,68 @@ def make_gaussian_input( ) buff.append("\n") return "\n".join(buff) + + +def read_gaussian_input(inp: str): + """Read Gaussian input. + + Parameters + ---------- + inp : str + Gaussian input str + + Returns + ------- + dict + system data + """ + flag = 0 + coords = [] + elements = [] + cells = [] + for line in inp.split("\n"): + if not line.strip(): + # empty line + flag += 1 + elif flag == 0: + # keywords + if line.startswith("#"): + # setting + keywords = line.split() + elif line.startswith("%"): + pass + elif flag == 1: + # title + pass + elif flag == 2: + # multi and coords + s = line.split() + if len(s) == 2: + pass + elif len(s) == 4: + if s[0] == "TV": + cells.append(list(map(float, s[1:4]))) + else: + # element + elements.append(re.sub("\\(.*?\\)|\\{.*?}|\\[.*?]", "", s[0])) + coords.append(list(map(float, s[1:4]))) + elif flag == 3: + # end + break + atom_names, atom_types, atom_numbs = np.unique( + elements, return_inverse=True, return_counts=True + ) + if len(cells): + nopbc = False + else: + nopbc = True + cells = np.array([np.eye(3)]) * 100 + return { + "atom_names": list(atom_names), + "atom_numbs": list(atom_numbs), + "atom_types": atom_types, + "cells": np.array(cells).reshape(1, 3, 3), + "nopbc": nopbc, + "coords": np.array(coords).reshape(1, -1, 3), + "orig": np.zeros(3), + } diff --git a/dpdata/plugins/gaussian.py b/dpdata/plugins/gaussian.py index 1ea097cc0..a22ce8630 100644 --- a/dpdata/plugins/gaussian.py +++ b/dpdata/plugins/gaussian.py @@ -27,6 +27,20 @@ def from_labeled_system(self, file_name, **kwargs): class GaussiaGJFFormat(Format): """Gaussian input file.""" + def from_system(self, file_name: str, **kwargs): + """Read Gaussian input file. + + Parameters + ---------- + file_name : str + file name + **kwargs : dict + keyword arguments + """ + with open(file_name) as fp: + text = fp.read() + return dpdata.gaussian.gjf.read_gaussian_input(text) + def to_system(self, data: dict, file_name: str, **kwargs): """Generate Gaussian input file. diff --git a/tests/test_gaussian_gjf.py b/tests/test_gaussian_gjf.py index 861eae287..2e5f4ea8f 100644 --- a/tests/test_gaussian_gjf.py +++ b/tests/test_gaussian_gjf.py @@ -1,6 +1,7 @@ import os import unittest +from comp_sys import CompSys from context import dpdata @@ -11,3 +12,16 @@ def setUp(self): def test_dump_gaussian_gjf(self): self.system.to_gaussian_gjf("tmp.gjf", keywords="force b3lyp/6-31g*") os.remove("tmp.gjf") + + +class TestGaussianGJFComp(unittest.TestCase, CompSys): + def setUp(self): + self.system_1 = dpdata.LabeledSystem( + "poscars/OUTCAR.h2o.md", fmt="vasp/outcar" + )[0] + self.system_1.to_gaussian_gjf("tmp.gjf", keywords="force b3lyp/6-31g*") + self.system_2 = dpdata.System( + "tmp.gjf", fmt="gaussian/gjf", type_map=self.system_1.get_atom_names() + ) + os.remove("tmp.gjf") + self.places = 6