Skip to content

Commit

Permalink
Merge pull request #38 from alchem0x2A/master
Browse files Browse the repository at this point in the history
Allow choosing API versions in SparcBundle and SPARC calculator
  • Loading branch information
alchem0x2A authored Jan 16, 2024
2 parents 9c7cdda + b129798 commit a18575f
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 2,085 deletions.
1 change: 1 addition & 0 deletions .github/workflows/installation_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ jobs:
# python -m pytest -svv tests/ --cov=sparc --cov-report=json --cov-report=html
export SPARC_TESTS_DIR="./SPARC-master/tests"
export ASE_SPARC_COMMAND="mpirun -n 1 sparc"
export SPARC_DOC_PATH="./SPARC-master/doc"
coverage run -a -m pytest -svv tests/
coverage json --omit="tests/*.py"
coverage html --omit="tests/*.py"
Expand Down
1 change: 1 addition & 0 deletions sparc/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
class SparcAPI:
def __init__(self, json_api=None):
"""Initialize the API from a json file"""
# TODO: like ase io, adapt to both file and fio
if json_api is None:
json_api = Path(default_json_api)
else:
Expand Down
14 changes: 9 additions & 5 deletions sparc/calculator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from .api import SparcAPI
from .io import SparcBundle
from .utils import _find_default_sparc, deprecated, h2gpts
from .utils import _find_default_sparc, deprecated, h2gpts, locate_api

# Below are a list of ASE-compatible calculator input parameters that are
# in Angstrom/eV units
Expand All @@ -24,7 +24,6 @@
"nbands",
]


defaultAPI = SparcAPI()


Expand Down Expand Up @@ -54,6 +53,8 @@ def __init__(
command=None,
psp_dir=None,
log="sparc.log",
sparc_json_file=None,
sparc_doc_path=None,
**kwargs,
):
# Initialize the calculator but without restart.
Expand All @@ -73,12 +74,14 @@ def __init__(
if label is None:
label = "SPARC" if restart is None else None

self.validator = locate_api(json_file=sparc_json_file, doc_path=sparc_doc_path)
self.sparc_bundle = SparcBundle(
directory=Path(self.directory),
mode="w",
atoms=self.atoms,
label=label,
psp_dir=psp_dir,
validator=self.validator,
)

# Try restarting from an old calculation and set results
Expand Down Expand Up @@ -432,14 +435,15 @@ def get_fermi_level(self):

def _detect_sparc_version(self):
"""Run a short sparc test to determine which sparc is used"""
# TODO: complete the implementation
command = self._make_command()

return None

def _sanitize_kwargs(self, kwargs):
"""Convert known parameters from"""
# print(kwargs)
# TODO: versioned validator
validator = defaultAPI
validator = self.validator
valid_params = {}
special_params = self.default_params.copy()
# TODO: how about overwriting the default parameters?
Expand Down Expand Up @@ -469,7 +473,7 @@ def _convert_special_params(self, atoms=None):
h <--> gpts <--> FD_GRID, only when None of FD_GRID / ECUT or MESH_SPACING is provided
"""
converted_sparc_params = {}
validator = defaultAPI
validator = self.validator
params = self.special_params.copy()

# xc --> EXCHANGE_CORRELATION
Expand Down
1 change: 1 addition & 0 deletions sparc/docparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ def to_dict(self):
@classmethod
def json_from_directory(cls, directory=".", include_subdirs=True, **kwargs):
"""Recursively add parameters from all Manual files"""
directory = Path(directory)
root_dict = cls(directory=directory, **kwargs).to_dict()
if include_subdirs:
for sub_manual_tex in directory.glob("*/Manual*.tex"):
Expand Down
39 changes: 25 additions & 14 deletions sparc/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,22 @@
from ase.calculators.singlepoint import SinglePointDFTCalculator
from ase.units import GPa, Hartree

# various io formatters
from .api import SparcAPI
from .common import psp_dir as default_psp_dir
from .download_data import is_psp_download_complete
from .sparc_parsers.aimd import _read_aimd
from .sparc_parsers.atoms import atoms_to_dict, dict_to_atoms
from .sparc_parsers.geopt import _read_geopt
from .sparc_parsers.inpt import _read_inpt, _write_inpt

# various io formatters
from .sparc_parsers.ion import _read_ion, _write_ion
from .sparc_parsers.out import _read_out
from .sparc_parsers.pseudopotential import copy_psp_file, parse_psp8_header
from .sparc_parsers.static import _read_static
from .utils import deprecated, string2index
from .utils import deprecated, string2index, locate_api

# from .sparc_parsers.ion import read_ion, write_ion
defaultAPI = SparcAPI()


class SparcBundle:
Expand Down Expand Up @@ -67,6 +68,7 @@ def __init__(
atoms=None,
label=None,
psp_dir=None,
validator=defaultAPI,
):
self.directory = Path(directory)
self.mode = mode.lower()
Expand All @@ -85,6 +87,7 @@ def __init__(
# Sorting should be consistent across the whole bundle!
self.sorting = None
self.last_image = -1
self.validator = validator

def _find_files(self):
"""Find all files matching '{label}.*'"""
Expand Down Expand Up @@ -187,8 +190,8 @@ def _read_ion_and_inpt(self):
This method should be rarely used
"""
f_ion, f_inpt = self._indir(".ion"), self._indir(".inpt")
ion_data = _read_ion(f_ion)
inpt_data = _read_inpt(f_inpt)
ion_data = _read_ion(f_ion, validator=self.validator)
inpt_data = _read_inpt(f_inpt, validator=self.validator)
merged_data = {**ion_data, **inpt_data}
return dict_to_atoms(merged_data)

Expand Down Expand Up @@ -254,8 +257,8 @@ def _write_ion_and_inpt(
target_fname = copy_psp_file(origin_psp, target_dir)
block["PSEUDO_POT"] = target_fname

_write_ion(self._indir(".ion"), data_dict)
_write_inpt(self._indir(".inpt"), data_dict)
_write_ion(self._indir(".ion"), data_dict, validator=self.validator)
_write_inpt(self._indir(".inpt"), data_dict, validator=self.validator)
return

def read_raw_results(self, include_all_files=False):
Expand Down Expand Up @@ -673,7 +676,9 @@ def read_sparc(filename, index=-1, include_all_files=False, **kwargs):
with embedded calculator result.
"""
sb = SparcBundle(directory=filename)
# We rely on minimal api version choose, i.e. default or set from env
api = locate_api()
sb = SparcBundle(directory=filename, validator=api)
atoms_or_images = sb.convert_to_ase(
index=index, include_all_files=include_all_files, **kwargs
)
Expand All @@ -690,7 +695,8 @@ def write_sparc(filename, images, **kwargs):
if len(images) > 1:
raise ValueError("SPARC format only supports writing one atoms object!")
atoms = images[0]
sb = SparcBundle(directory=filename, mode="w")
api = locate_api()
sb = SparcBundle(directory=filename, mode="w", validator=api)
sb._write_ion_and_inpt(atoms, **kwargs)
return

Expand All @@ -704,8 +710,9 @@ def read_ion(filename, **kwargs):
The returned Atoms object of read_ion method only contains the initial positions
"""
api = locate_api()
parent_dir = Path(filename).parent
sb = SparcBundle(directory=parent_dir)
sb = SparcBundle(directory=parent_dir, validator=api)
atoms = sb._read_ion_and_inpt()
return atoms

Expand All @@ -720,7 +727,8 @@ def write_ion(filename, atoms, **kwargs):
"""
label = Path(filename).with_suffix("").name
parent_dir = Path(filename).parent
sb = SparcBundle(directory=parent_dir, label=label, mode="w")
api = locate_api()
sb = SparcBundle(directory=parent_dir, label=label, mode="w", validator=api)
sb._write_ion_and_inpt(atoms, **kwargs)
return atoms

Expand All @@ -730,7 +738,8 @@ def read_static(filename, index=-1, **kwargs):
The reader works only when other files (.ion, .inpt) exist.
"""
parent_dir = Path(filename).parent
sb = SparcBundle(directory=parent_dir)
api = locate_api()
sb = SparcBundle(directory=parent_dir, validator=api)
atoms_or_images = sb.convert_to_ase(index=index, **kwargs)
return atoms_or_images

Expand All @@ -740,7 +749,8 @@ def read_geopt(filename, index=-1, **kwargs):
The reader works only when other files (.ion, .inpt) exist.
"""
parent_dir = Path(filename).parent
sb = SparcBundle(directory=parent_dir)
api = locate_api()
sb = SparcBundle(directory=parent_dir, validator=api)
atoms_or_images = sb.convert_to_ase(index=index, **kwargs)
return atoms_or_images

Expand All @@ -750,7 +760,8 @@ def read_aimd(filename, index=-1, **kwargs):
The reader works only when other files (.ion, .inpt) exist.
"""
parent_dir = Path(filename).parent
sb = SparcBundle(directory=parent_dir)
api = locate_api()
sb = SparcBundle(directory=parent_dir, validator=api)
atoms_or_images = sb.convert_to_ase(index=index, **kwargs)
return atoms_or_images

Expand Down
Loading

0 comments on commit a18575f

Please sign in to comment.