aiida_vasp.data.potcar#

Representation of the POTCAR files.

Attempt to create a convenient but license-respecting storage system that also guarantees provenance.

Consists of two classes, PotcarData and PotcarFileData. Between the two data node classes exists a one to one mapping but never a DbLink of any kind. The mapping must be defined in terms of a POTCAR file hash sum.

Reasons for not using a file system based solution in general:

  • simplicity -> no necessity to define an fs based storage / retrieval schema

  • storage schema can be updated without manual user interaction

  • with fs based it is possible to lose enhanced provenance locally by deleting a file

  • This is easier to share between machines for same user / group members

Reasons for not using fs paths:

  • migrating to a new machine involves reinstating file hierarchy, might be non-trivial

  • corner cases with links, recursion etc

Reasons for not using pymatgen system:

  • changing an environment variable would invalidate provenance / disable reusing potentials

  • would block upgrading to newer pymatgen versions if they decide to change

Note:

An fs based solution can be advantageous but should be 'expert mode' and not
default solution due to provenance tradeoffs.

The following requirements have to be met:

  • The file hash attribute of PotcarFileData is unique in the Db

  • The file hash attribute of PotcarData is unique in the Db

  • Both classes can easily and quickly be found via the hash attribute

  • A PotcarData node can be exported without exporting the PotcarFileData node

  • The corresponding PotcarData node can be created at any time from the PotcarFileData node

  • PotcarFileData nodes are expected to be grouped in DbGroups called ‘families’

  • The PotcarFileData nodes can be found according to their ‘functional type’ (pymatgen term)

The following would be nice to also allow optionally:

  • To pre-upload the files to a remote computer from a db and concat them right on there (to save traffic)

  • To use files directly on the remote computer (disclaimer: will never be as secure / tested)

  • To use existing pymatgen-style potentials library (disclaimer: support might break)

It is not to be expected for hundreds of distinct Potcar families to be present in the same database.

The mechanism for reading a POTCAR file into the Db:

+-----------------------+
[ parsing a POTCAR file ]
+-----------------------+
        |
        v
        pmg_potcar = PotcarData.get_or_create_from_file()
        |
        v
 _----------------------------------------------_
( exists for PotcarFileData with pmg_potcar.sha512? )-----> no
 ^----------------------------------------------^         |
        |                                                 v
        v                                                 create
        yes                                               |
        |                                                 |
        v                                                 v
 _-------------------------_                             _-------------------------_
( Family given to parse to? ) -------------> no -+      ( Family given to parse to? )
 ^-------------------------^                     |       ^-------------------------^
        |                                        |        |         |
        v                                        |        |         no
        yes<------------------------------------]|[-------+         |
        |                                        |                  choose family according to functional type
        |                                        |                  |  (with fallback?)
        v                                        |                  |
        add existing PotcarFileData to family<--]|[-----------------+
        |                                        |
        |                     +------------------+
        v                     v
 _--------------------------------_
( exists corresponding PotcarData? )-----> no -----> create
 ^--------------------------------^ <------------------+
        |
        v
        return corresponding PotcarData

The mechanism for writing one or more PotcarData to file (from a calculation):

+-----------------------+
[ Writing a POTCAR file ]
+-----------------------+
        |
        v
        for each PotcarData node:
            get corresponding PotcarFileData <-> query for same symbol, family, hash, do not use links
        |
        v
        write_file using the write() of MultiPotcarIo

Module Contents#

Classes#

PotcarGroup

A group for holding PotcarData objects that maps to various collections of POTCARs.

PotcarWalker

Walk the file system and find POTCAR files under a given directory.

PotcarMetadataMixin

Provide common Potcar metadata access and querying functionality.

VersioningMixin

Minimalistic Node versioning.

PotcarFileData

Store a POTCAR file in the db, never use as input to a calculation or workchain.

PotcarData

Store enough metadata about a POTCAR file to identify and find it.

Functions#

migrate_potcar_group

Migrate existing potcar family groups to new specification. This creates copies of the old potcar family groups using the new PotcarGroup class.

normalize_potcar_contents

Normalize whitespace in a POTCAR given as a string.

sha512_potcar

Hash the contents of a POTCAR file (given as str).

temp_dir

Temporary directory context manager that deletes the tempdir after use.

temp_potcar

Temporary POTCAR file from contents.

extract_tarfile

Extract a .tar archive into an appropriately named folder, return the path of the folder, avoid extracting if folder exists.

by_older

by_user

Data#

API#

aiida_vasp.data.potcar.POTCAR_FAMILY_TYPE = 'vasp.potcar'#
aiida_vasp.data.potcar.OLD_POTCAR_FAMILY_TYPE = 'data.vasp.potcar.family'#
class aiida_vasp.data.potcar.PotcarGroup(label: Optional[str] = None, user: Optional[aiida.orm.User] = None, description: str = '', type_string: Optional[str] = None, time: Optional[datetime.datetime] = None, extras: Optional[Dict[str, Any]] = None, backend: Optional[aiida.orm.implementation.StorageBackend] = None)[source]#

Bases: aiida.orm.Group

A group for holding PotcarData objects that maps to various collections of POTCARs.

Initialization

Create a new group. Either pass a dbgroup parameter, to reload a group from the DB (and then, no further parameters are allowed), or pass the parameters for the Group creation.

Parameters:
  • label – The group label, required on creation

  • description – The group description (by default, an empty string)

  • user – The owner of the group (by default, the automatic user)

  • type_string – a string identifying the type of group (by default, an empty string, indicating an user-defined group.

get_matched_set()[source]#

Verify the group against known sets

verify()[source]#

Verify the current data set against known sets

get_potcar_identity()[source]#

Return which potpaw dataset the POTCARs in the group are from

get_duplicated_symbols()[source]#

Get duplicated symbols

This may happen when using original PBE.54 and PBE.52 datasets released where several GW POTCARs are wrongly labeled. For example, B_GW is labeled as B

aiida_vasp.data.potcar.migrate_potcar_group() None[source]#

Migrate existing potcar family groups to new specification. This creates copies of the old potcar family groups using the new PotcarGroup class.

Despite the name ‘migrate’, the potcar family group created are in fact left as they are.

aiida_vasp.data.potcar.normalize_potcar_contents(potcar_contents: str | bytes) str[source]#

Normalize whitespace in a POTCAR given as a string.

aiida_vasp.data.potcar.sha512_potcar(potcar_contents: str) str[source]#

Hash the contents of a POTCAR file (given as str).

aiida_vasp.data.potcar.temp_dir() Any[source]#

Temporary directory context manager that deletes the tempdir after use.

aiida_vasp.data.potcar.temp_potcar(contents: bytes) Any[source]#

Temporary POTCAR file from contents.

aiida_vasp.data.potcar.extract_tarfile(file_path: pathlib.Path) pathlib.Path[source]#

Extract a .tar archive into an appropriately named folder, return the path of the folder, avoid extracting if folder exists.

aiida_vasp.data.potcar.by_older(left: Any, right: Any) int[source]#
aiida_vasp.data.potcar.by_user(left: Any, right: Any) int[source]#
class aiida_vasp.data.potcar.PotcarWalker(path: pathlib.Path | str)[source]#

Walk the file system and find POTCAR files under a given directory.

Build a list of POTCARs including their full path and whether they are archived inside a tar archive.

Initialization

walk() None[source]#

Walk the folder tree to find POTCAR, extracting any tar archives along the way.

file_dispatch(root: str, dirs: list[str], file_name: str) pathlib.Path | None[source]#

Add POTCAR files to the list and dispatch handling of different kinds of files to other methods.

classmethod handle_tarfile(dirs: list[str], file_path: pathlib.Path) pathlib.Path[source]#

Handle .tar archives: extract and add the extracted folder to be searched.

class aiida_vasp.data.potcar.PotcarMetadataMixin[source]#

Provide common Potcar metadata access and querying functionality.

_query_label = 'label'#
classmethod query_by_attrs(query: Any = None, **kwargs: Any) aiida.orm.QueryBuilder[source]#

Find a Data node by attributes.

classmethod find(**kwargs: Any) list[Any][source]#

Find nodes by POTCAR metadata attributes given in kwargs.

classmethod find_one(**kwargs: Any) Any[source]#

Find one single node.

Raise an exception if there are multiple.

classmethod exists(**kwargs: Any) bool[source]#

Answers the question wether a node with attributes given in kwargs exists.

property sha512: str#

Sha512 hash of the POTCAR file (readonly).

property title: str#

Title of the POTCAR file (readonly).

property functional: str#

Functional class of the POTCAR potential (readonly).

property element: str#

Chemical element described by the POTCAR (readonly).

property symbol: str#

Element symbol property (VASP term) of the POTCAR potential (readonly).

property original_file_name: str#

The name of the original file uploaded into AiiDA.

property full_name: str#

The name of the original file uploaded into AiiDA.

property potential_set: str#

The name of the original file uploaded into AiiDA.

verify_unique() None[source]#

Raise a UniquenessError if an equivalent node exists.

class aiida_vasp.data.potcar.VersioningMixin[source]#

Minimalistic Node versioning.

_HAS_MODEL_VERSIONING = True#
_VERSION = None#
set_version() None[source]#
property model_version: Any#
classmethod old_versions_in_db() bool[source]#

Determine whether there are Nodes created with an older version of the model.

class aiida_vasp.data.potcar.PotcarFileData(*args: Any, **kwargs: Any)[source]#

Bases: aiida_vasp.data.archive.ArchiveData, aiida_vasp.data.potcar.PotcarMetadataMixin, aiida_vasp.data.potcar.VersioningMixin

Store a POTCAR file in the db, never use as input to a calculation or workchain.

Warning

Warning! Sharing nodes of this type may be illegal!

In general POTCAR files may lay under license agreements, such as the ones distributed by the VASP group to VASP license holders. Take care to not share such licensed data with non-license holders.

When writing a calculation plugin or workchain, do not use this as an input type, use aiida_vasp.data.potcar.PotcarData instead!

Initialization

Construct a new instance, setting the source attribute if provided as a keyword argument.

_query_label = 'potcar_file'#
_query_type_string = 'data.vasp.potcar_file.'#
_plugin_type_string = 'data.vasp.potcar_file.PotcarFileData.'#
_VERSION = 1#
init_with_kwargs(**kwargs: Any) None[source]#

Delegate initialization to _init_with - methods.

_init_with_file(filepath: pathlib.Path) None[source]#

Initialized from a file path.

add_file(src_abs: pathlib.Path, dst_filename: Any = None) None[source]#

Add the POTCAR file to the archive and set attributes.

classmethod get_file_sha512(path: pathlib.Path | str) str[source]#

Get the sha512 sum for a POTCAR file (after whitespace normalization).

classmethod get_contents_sha512(contents: str) str[source]#

Get the sha512 sum for the contents of a POTCAR file (after normalization).

store(*args: Any, create_data_node=True, verify=True, **kwargs: Any) Any[source]#

Ensure uniqueness and existence of a matching PotcarData node before storing.

get_file_obj() Any[source]#

Open a readonly file object to read the stored POTCAR file.

get_file_obj_and_tar_obj() Any[source]#

Return both decompressed file object and the archive object

export_archive(archive: Any, dry_run: bool = False) str[source]#

Add the stored POTCAR file to an archive for export.

export_file(path: pathlib.Path, dry_run: bool = False) pathlib.Path[source]#

Write the contents of the stored POTCAR file to a destination on the local file system.

Parameters:

path – path to the destination file or folder as a Path or string object

When given a folder, the destination file will be created in a subdirectory with the name of the symbol. This is for conveniently exporting multiple files into the same folder structure as the POTCARs are distributed in.

Examples:

potcar_file = PotcarFileData.get_or_create(<file>)
assert potcar_file.symbol == 'Si_d'

potcar_file.export('./POTCAR.Si')
## writes to ./POTCAR.Si

potcar_file.export('./potcars/')
## writes to
## ./
##  |-potcars/
##           |-Si_d/
##                 |-POTCAR
get_content() bytes[source]#
classmethod get_or_create(filepath: pathlib.Path) tuple[Any, bool][source]#

Get or create (store) a PotcarFileData node.

classmethod get_or_create_from_contents(contents: str) tuple[Any, bool][source]#

Get or create (store) a PotcarFileData node from a string containing the POTCAR contents.

class aiida_vasp.data.potcar.PotcarData(**kwargs: Any)[source]#

Bases: aiida.orm.Data, aiida_vasp.data.potcar.PotcarMetadataMixin, aiida_vasp.data.potcar.VersioningMixin

Store enough metadata about a POTCAR file to identify and find it.

Meant to be used as an input to calculations. This node type holds no licenced data and can be freely shared without legal repercussions.

Initialization

Construct a new instance, setting the source attribute if provided as a keyword argument.

_query_label = 'potcar'#
_query_type_string = 'data.vasp.potcar.'#
_plugin_type_string = 'data.vasp.potcar.PotcarData.'#
_VERSION = 1#
set_potcar_file_node(potcar_file_node: Any) None[source]#

Initialize from a PotcarFileData node.

find_file_node() Any[source]#

Find and return the matching PotcarFileData node.

store(*args: Any, verify=True, **kwargs: Any) Any[source]#

Ensure uniqueness before storing.

classmethod get_or_create(file_node: Any) tuple[Any, bool][source]#

Get or create (store) a PotcarData node.

classmethod get_or_create_from_file(file_path: str | pathlib.Path) tuple[aiida.orm.Data, bool][source]#

Get or create (store) a PotcarData node from a POTCAR file.

classmethod get_or_create_from_file_many(file_paths: list[str | pathlib.Path]) list[tuple[aiida.orm.Data, bool]][source]#

Get or create (store) many PotcarData node from a POTCAR file.

Parameters:

file_paths – A list of file paths to POTCAR files.

Returns:

A list of tuples (PotcarData node, created flag) for each file.

classmethod get_or_create_from_contents(contents: str) tuple[aiida.orm.Data, bool][source]#

Get or create (store) a PotcarData node from a string containing the POTCAR contents.

classmethod file_not_uploaded(file_path: str | pathlib.Path) aiida_vasp.data.potcar.PotcarFileData | tuple[source]#
get_family_names() list[str][source]#

List potcar families to which this instance belongs.

classmethod get_potcar_group(group_name: str) aiida_vasp.data.potcar.PotcarGroup | None[source]#

Return the PotcarFamily group with the given name.

classmethod get_potcar_groups(filter_elements: list[str] | str | None = None, filter_symbols: list[str] | None = None) list[aiida_vasp.data.potcar.PotcarGroup][source]#

List all names of groups of type PotcarFamily, possibly with some filters.

Parameters:
  • filter_elements – list of strings. If present, returns only the groups that contains one POTCAR for every element present in the list. Default=None, meaning that all families are returned. A single element can be passed as a string.

  • filter_symbols – list of strings with symbols to filter for.

classmethod get_potcars_dict(elements: list[str], family_name: str, mapping: dict[str, str] | None = None, auto_migrate: bool = True) dict[str, Any][source]#

Get a dictionary {element: PotcarData.full_name} for all given symbols.

Parameters:
  • elements – The list of symbols to find POTCARs for

  • family_name – The POTCAR family to be used

  • mapping – A mapping[element] -> full_name, for example: mapping={‘In’: ‘In’, ‘As’: ‘As_d’}

  • auto_migrate – A flag of whether to perform the migration automatically when migration is found to be needed.

Exceptions:

*If the mapping does not contain an item for a given element name, raise a ValueError. *If no POTCAR is found for a given element, a NotExistent error is raised.

If there are multiple POTCAR with the same full_name, the first one returned by PotcarData.find() will be used.

classmethod query_by_attrs(query: Any = None, **kwargs: Any) Any[source]#
classmethod get_full_names(family_name: str | None = None, element: str | None = None) list[str][source]#

Gives a set of symbols provided by this family.

Not every symbol may be supported for every element.

classmethod get_potcars_from_structure(structure: aiida.orm.StructureData, family_name: str, mapping: dict[str, str] | None = None) dict[str, aiida_vasp.data.potcar.PotcarData][source]#

Given a POTCAR family name and a AiiDA structure, return a dictionary associating each kind name with its PotcarData object.

Parameters:
  • structure – An AiiDA structure

  • family_name – The POTCAR family to be used

  • mapping – A mapping[kind name] -> full_name, for example: mapping={‘In1’: ‘In’, ‘In2’: ‘In_d’}

The Dictionary looks as follows:

{
    kind1.name: PotcarData_for_kind1,
    kind2.name: ...
}

This is to make the output of this function suitable for giving directly as input to VaspCalculation.process() instances.

Raises:
  • MultipleObjectsError – if more than one UPF for the same element is found in the group.

  • NotExistent – if no UPF for an element in the group is found in the group.

Example:

## using VASP recommended POTCARs
from aiida_vasp.utils.default_paws import DEFAULT_LDA, DEFAULT_GW
vasp_process = CalculationFactory('vasp.vasp').process()
inputs = vasp_process.get_inputs_template()
inputs.structure = load_node(123)
inputs.potential = PotcarData.get_potcars_from_structure(
    structure=inputs.structure,
    family_name='PBE',
    mapping=DEFAULT_GW
)

## using custom POTCAR map
custom_mapping = {
    'In1': 'In',
    'In2': 'In_d',
    'As': 'As_d'
}
inputs.potential = PotcarData.get_potcars_from_structure(
    structure=inputs.structure,
    family_name='PBE',
    mapping=custom_mapping
)
classmethod _prepare_group_for_upload(group_name: str, group_description: str | None = None, dry_run: bool = False) aiida_vasp.data.potcar.PotcarGroup[source]#

Prepare a (possibly new) group to upload a POTCAR family to.

classmethod upload_potcar_family(source: str | pathlib.Path, group_name: str, group_description: str | None = None, stop_if_existing: bool = True, dry_run: bool = False) tuple[int, int, int][source]#

Upload a set of POTCAR potentials as a family.

Parameters:
  • source – a path containing all POTCAR files to be added.

  • group_name – the name of the group to create. If it exists and is non-empty, a UniquenessError is raised.

  • group_description – a string to be set as the group description. Overwrites previous descriptions, if the group was existing.

  • stop_if_existing – if True, check for the sha512 of the files and, if the file already exists in the DB, raises a MultipleObjectsError. If False, simply adds the existing PotcarData node to the group.

  • dry_run – If True, do not change the database.

classmethod _try_upload_potcars(file_paths: list[pathlib.Path], stop_if_existing: bool = True, dry_run: bool = False) list[tuple[Any, bool, str]][source]#

Given a list of absolute paths to potcar files, try to upload them (or pretend to if dry_run=True).

classmethod export_family_folder(family_name: str, path: str | pathlib.Path | None = None, dry_run: bool = False) list[pathlib.Path][source]#

Export a family of POTCAR nodes into a file hierarchy similar to the one POTCARs are distributed in.

Parameters:
  • family_name – name of the POTCAR family

  • path – path to a local directory, either a string or Path object, default to current directory

  • dry_run – bool, if True, only collect the names of files that would otherwise be written.

If path already exists, everything will be written into a subdirectory with the name of the family.

classmethod export_family_archive(family_name: str, path: str | pathlib.Path | None = None, dry_run: bool = False) tuple[pathlib.Path, list[str]][source]#

Export a family of POTCAR nodes into a compressed archive.

get_content() bytes[source]#
classmethod find(**kwargs: Any) list[Any][source]#

Extend PotcarMetadataMixin.find() with filtering by POTCAR family.

If no POTCAR is found, raise a NotExistent exception.

If multiple POTCAR are found, sort them by:

  • POTCARS belonging to the active user first

  • oldest first

verify_unique() None[source]#

Raise a UniquenessError if an equivalent node exists.

check_and_fix_inconsistent_potcar_symbol(fix=False)[source]#

Check inconsistence in the POTCAR symbols parsed compared with the apparent folder name.

Parameters:

fix – Create a new PotcarData node with the corrected symbol name.