Source code for aiida_raspa.utils.base_input_generator

# -*- coding: utf-8 -*-
"""Basic raspa input generator."""
from copy import deepcopy

ORDERED_ITEMS_COMPONENT_SECTION = [
    "NumberOfIdentityChanges",
    "IdentityChangesList",
]


[docs]class RaspaInput: # pylint: disable=too-few-public-methods """Convert input dictionary into input file"""
[docs] def __init__(self, params): self.params = deepcopy(params) # make sure the original object is not modified try: self.system_order = sorted(params["System"].keys()) # we sort the keys to keep the order in the input except KeyError: raise KeyError("The input dictionary should contain the System subdictionary.") except AttributeError: raise AttributeError("The System subdictionary should be of type dict.") # file persistent this is essential for the restarts. if not self.system_order: raise ValueError("The System subdictionary should not be empty.")
# --------------------------------------------------------------------------
[docs] def render(self): """Perform conversion""" output = ["!!! Generated by AiiDA !!!"] params = deepcopy(self.params) # make sure it is idempotent # General settings can be be rendered without any problems section = params.pop("GeneralSettings") self._render_section(output, section) # System section has to make sure to keep the order persistent, this is why we use # self.system_order to iterate through section = params.pop("System") for my_id, name in enumerate(self.system_order): system = section[name] s_type = system.pop("type") output.append("{} {}".format(s_type, my_id)) if s_type == "Framework": output.append("{}FrameworkName {}".format(' ' * 3, name)) self._render_section(output, system, indent=3) # Section Component may contain parameters thar are for several systems # like: # CreateNumberOfMolecules n1, n2 <--- n1 is for system 0, n2 is for system 1 section = params.pop("Component") for my_id, (name, molecule) in enumerate(section.items()): output.append('Component {} MoleculeName {}'.format(my_id, name)) if "BlockPocketsFileName" in molecule: if isinstance(molecule["BlockPocketsFileName"], dict): try: bps = self._dict_to_ordered_list(molecule["BlockPocketsFileName"]) except KeyError as err: raise KeyError("You did not provide BlockPocketsFileName parameter for the system '{}'".format( str(err))) molecule["BlockPocketsFileName"] = bps molecule["BlockPockets"] = ["yes" if bp else "no" for bp in bps] elif isinstance(molecule["BlockPocketsFileName"], str): molecule["BlockPockets"] = "yes" if "CreateNumberOfMolecules" in molecule: if isinstance(molecule["CreateNumberOfMolecules"], dict): try: molecule["CreateNumberOfMolecules"] = self._dict_to_ordered_list( molecule["CreateNumberOfMolecules"]) except KeyError as err: raise KeyError("You did not provide CreateNumberOfMolecules parameter for the system {}".format( str(err))) for item in ORDERED_ITEMS_COMPONENT_SECTION: if item in molecule: self._render_item(output, item, molecule.pop(item), indent=3) self._render_section(output, molecule, indent=3) return "\n".join(output) + "\n"
[docs] def _dict_to_ordered_list(self, input_dict): """Convert dict to ordered list. Convert dictionary {"framework_name1": something1, "framework_name2": something2} to [something2, something1], where the order is defined by self.system_order list :param input_dict: dictionary that looks as folows {"framework_name1": something1, "framework_name2": something2} :type input_dict: dict :returns: a list of items ordered according to the order of frameworks in the input file :rtype: list """ ordered_list = [None] * len(self.system_order) for i, name in enumerate(self.system_order): ordered_list[i] = input_dict[name] return ordered_list
# --------------------------------------------------------------------------
[docs] @staticmethod def _render_section(output, params, indent=0): """ It takes a dictionary and recurses through. For key-value pair it checks whether the value is a dictionary and prepends the key with & It passes the valued to the same function, increasing the indentation If the value is a list, I assume that this is something the user wants to store repetitively """ # output.append("enter") # output.append("This what comes:" + str(params)) for key, val in sorted(params.items()): RaspaInput._render_item(output, key, val, indent=indent)
[docs] @staticmethod def _render_item(output, key, val, indent=0): """ It takes one key-value item and adds to the output file """ if isinstance(val, list): output.append('{}{} {}'.format(' ' * indent, key, ' '.join(str(p) for p in val))) elif isinstance(val, bool): val_str = 'yes' if val else 'no' output.append('{}{} {}'.format(' ' * indent, key, val_str)) else: output.append('{}{} {}'.format(' ' * indent, key, val))