import glob
import json
import os
from abc import ABC, abstractmethod
from monty.serialization import dumpfn
from dpgen.auto_test.calculator import make_calculator
[docs]
class Property(ABC):
@abstractmethod
def __init__(self, parameter):
"""Constructor.
Parameters
----------
parameter : dict
A dict that defines the property.
"""
pass
[docs]
@abstractmethod
def make_confs(self, path_to_work, path_to_equi, refine=False):
"""Make configurations needed to compute the property.
The tasks directory will be named as path_to_work/task.xxxxxx
IMPORTANT: handel the case when the directory exists.
Parameters
----------
path_to_work : str
The path where the tasks for the property are located
path_to_equi : str
-refine == False: The path to the directory that equilibrated the configuration.
-refine == True: The path to the directory that has property confs.
refine : str
To refine existing property confs or generate property confs from a equilibrated conf
Returns
-------
task_list: list of str
The list of task directories.
"""
pass
[docs]
@abstractmethod
def post_process(self, task_list):
"""post_process the KPOINTS file in elastic."""
pass
@property
@abstractmethod
def task_type(self):
"""Return the type of each computational task, for example, 'relaxation', 'static'...."""
pass
@property
@abstractmethod
def task_param(self):
"""Return the parameter of each computational task, for example, {'ediffg': 1e-4}."""
pass
[docs]
def compute(self, output_file, print_file, path_to_work):
"""Postprocess the finished tasks to compute the property.
Output the result to a json database.
Parameters
----------
output_file:
The file to output the property in json format
print_file:
The file to output the property in txt format
path_to_work:
The working directory where the computational tasks locate.
"""
path_to_work = os.path.abspath(path_to_work)
task_dirs = glob.glob(os.path.join(path_to_work, "task.[0-9]*[0-9]"))
task_dirs.sort()
all_res = []
for ii in task_dirs:
with open(os.path.join(ii, "inter.json")) as fp:
idata = json.load(fp)
poscar = os.path.join(ii, "POSCAR")
task = make_calculator(idata, poscar)
res = task.compute(ii)
dumpfn(res, os.path.join(ii, "result_task.json"), indent=4)
# all_res.append(res)
all_res.append(os.path.join(ii, "result_task.json"))
# cwd = os.getcwd()
# os.chdir(path_to_work)
res, ptr = self._compute_lower(output_file, task_dirs, all_res)
# with open(output_file, 'w') as fp:
# json.dump(fp, res, indent=4)
with open(print_file, "w") as fp:
fp.write(ptr)
# os.chdir(cwd)
@abstractmethod
def _compute_lower(self, output_file, all_tasks, all_res):
"""Compute the property.
Parameters
----------
output_file
The file to output the property
all_tasks : list of str
The list of directories to the tasks
all_res : list of str
The list of results
Returns
-------
res_data : dist
The dict storing the result of the property
ptr_data : str
The result printed in string format
"""
pass