Source code for aim2dat.aiida_workflows.critic2.calcjobs

"""
Calcjobs for the critic2 software package.
"""

# Third party library imports
from aiida.common import CalcInfo, CodeInfo, InputValidationError
from aiida.engine import CalcJob
import aiida.orm as aiida_orm


[docs]class Critic2Calculation(CalcJob): """ Calcjob for the critic2 software package. """ @classmethod def define(cls, spec): """Define input/output and outline.""" super().define(spec) spec.input( "parameters", valid_type=aiida_orm.List, help="List of input parameters (each item is parsed as a line in the input file).", ) spec.input( "charge_density_folder", valid_type=aiida_orm.RemoteData, help="Folder containing the carge-density cube files", ) spec.input( "kind_info", valid_type=aiida_orm.List, help="List containing the number of valence and core electrons for each element.", required=False, ) spec.inputs["metadata"]["options"]["input_filename"].default = "aiida.in" spec.inputs["metadata"]["options"]["output_filename"].default = "aiida.out" spec.inputs["metadata"]["options"]["resources"].default = { "num_machines": 1, "num_mpiprocs_per_machine": 1, } spec.inputs["metadata"]["options"]["withmpi"].default = False spec.inputs["metadata"]["options"]["parser_name"].default = "aim2dat.critic2" spec.output( "output_parameters", valid_type=aiida_orm.Dict, required=True, help="The output dictionary containing results of the calculation.", ) spec.output( "output_bader_populations", valid_type=aiida_orm.List, required=False, help="Calculated Bader populations.", ) spec.output_namespace( "output_planes", dynamic=True, required=False, help="Calculated planes.", ) spec.default_output_node = "output_parameters" spec.exit_code( 310, "ERROR_READING_OUTPUT_FILE", message="The output file could not be read." ) spec.exit_code( 320, "ERROR_INVALID_OUTPUT", message="The output file contains invalid output." ) spec.exit_code( 402, "ERROR_ABORT", message="Calculation was not successful.", ) def prepare_for_submission(self, folder): """Prepare for submission.""" cube_files = [] retrieve_list = [self.options.output_filename] with folder.open(self.options.input_filename, "w", encoding="utf8") as handle: for input_item in self.inputs.parameters.get_list(): cube_files += [arg for arg in input_item.split() if "cube" in arg] if input_item.split()[-1] == "zpsp" and "kind_info" in self.inputs: input_item += self._add_zpsp_section() if input_item.split()[0] == "plane": retrieve_list += self._get_plane_file_name(input_item) handle.write(input_item + "\n") cube_files = list(set(cube_files)) cd_folder = self.inputs.charge_density_folder remote_path = self.inputs.charge_density_folder.get_remote_path() comp_uuid = self.inputs.charge_density_folder.computer.uuid copy_links = [] for cube_f in cube_files: if cube_f in cd_folder.listdir(): copy_links.append((comp_uuid, remote_path + "/" + cube_f, cube_f)) else: raise InputValidationError(f"{cube_f} not found in `charge_density_folder`.") codeinfo = CodeInfo() codeinfo.code_uuid = self.inputs.code.uuid codeinfo.stdin_name = self.options.input_filename codeinfo.stdout_name = self.options.output_filename codeinfo.cmdline_params = [self.options.input_filename] calcinfo = CalcInfo() calcinfo.codes_info = [codeinfo] calcinfo.local_copy_list = [] if self.inputs.code.computer.uuid == cd_folder.computer.uuid: calcinfo.remote_symlink_list = copy_links else: self.report( f"Transfering files from {cd_folder.computer.label} to " f"{self.inputs.code.computer.label}." ) calcinfo.remote_copy_list = copy_links calcinfo.retrieve_list = retrieve_list return calcinfo def _add_zpsp_section(self): element_dict = {} for kind_info in self.inputs.kind_info.get_list(): element_dict[kind_info["element"]] = kind_info["valence_electrons"] return "".join([f" {el} {val_e}" for el, val_e in element_dict.items()]) @staticmethod def _get_plane_file_name(input_item): line_splitted = input_item.split() if "file" in line_splitted: return [line_splitted[line_splitted.index("file") + 1]] else: return ["stdin_plane.dat"]