Source code for aim2dat.aiida_workflows.chargemol.calcjobs

"""
Calcjobs for the chargemol software package.
"""

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


[docs]class ChargemolCalculation(CalcJob): """ Calcjob for the chargemol software package. """ @classmethod def define(cls, spec): """Define input/output and outline.""" super().define(spec) spec.input( "parameters", valid_type=aiida_orm.Dict, help="Dictionary containing the input parameters.", ) spec.input( "charge_density_folder", valid_type=aiida_orm.RemoteData, help="Folder containing the carge-density cube files", ) spec.input( "charge_density_filename", valid_type=aiida_orm.Str, required=False, help="Name of the cube-file containing the valence density of the system.", ) spec.input( "spin_density_filename", valid_type=aiida_orm.Str, required=False, help="Name of the cube-file containing the spin density of the system.", ) spec.input( "kind_info", valid_type=aiida_orm.List, required=False, help="List containing the atomic number and number of core electrons.", ) spec.input( "path_atomic_densities", valid_type=aiida_orm.Str, required=False, help="Absolte path to the atomic densities needed for the chargemol calculation.", ) spec.inputs["metadata"]["options"]["input_filename"].default = "job_control.txt" spec.inputs["metadata"]["options"][ "output_filename" ].default = "valence_cube_DDEC_analysis.output" 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.chargemol" spec.output( "output_parameters", valid_type=aiida_orm.Dict, required=True, help="The output dictionary containing results of the calculation.", ) spec.output( "output_ddec3_populations", valid_type=aiida_orm.List, required=False, help="Calculated DDEC3 populations.", ) spec.output( "output_ddec6_populations", valid_type=aiida_orm.List, required=False, help="Calculated DDEC6 populations.", ) 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( 401, "ERROR_CHARGE_DENSITY_FILES", message="Charge density files not found in remote folder.", ) spec.exit_code( 402, "ERROR_ABORT", message="Calculation was not successful.", ) spec.exit_code( 403, "ERROR_INSUFFICIENT_ACCURACY", message="Integration volumes are not sufficiently accurate.", ) def prepare_for_submission(self, folder): """Prepare for submission.""" 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 = [] if "charge_density_filename" in self.inputs: cube_f = self.inputs.charge_density_filename.value if cube_f not in cd_folder.listdir(): return self.exit_codes.ERROR_CHARGE_DENSITY_FILES copy_links.append((comp_uuid, remote_path + "/" + cube_f, "valence_density.cube")) if "spin_density_filename" in self.inputs: cube_f = self.inputs.spin_density_filename.value if cube_f not in cd_folder.listdir(): return self.exit_codes.ERROR_SPIN_DENSITY_FILES copy_links.append((comp_uuid, remote_path + "/" + cube_f, "spin_density.cube")) with folder.open(self.options.input_filename, "w", encoding="utf8") as handle: parameters = self.inputs.parameters.get_dict() for key, item in parameters.items(): handle.write(f"<{key}>\n") if isinstance(item, (list, tuple)): for list_item in item: handle.write(f"{list_item}\n") else: handle.write(f"{item}\n") handle.write(f"</{key}>\n\n") if ( "path_atomic_densities" in self.inputs and "atomic densities directory complete path" not in parameters ): handle.write("<atomic densities directory complete path>\n") handle.write(f"{self.inputs.path_atomic_densities.value}\n") handle.write("</atomic densities directory complete path>\n\n") if "kind_info" in self.inputs and "number of core electrons" not in parameters: handle.write("<number of core electrons>\n") element_list = [] for kind_info in self.inputs.kind_info.get_list(): if kind_info["element"] not in element_list: element_list.append(kind_info["element"]) handle.write(f"{kind_info['atomic_nr']} {kind_info['core_electrons']}\n") handle.write("</number of core electrons>\n") 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 = [self.options.output_filename, ("*.xyz", ".", 0)] return calcinfo