def prepare_for_submission(self, folder): # create code info codeinfo = CodeInfo() codeinfo.code_uuid = self.inputs.code.uuid codeinfo.cmdline_params = [ self.PARENT_FOLDER_NAME + "/" + self.inputs.chk_name.value, self.DEFAULT_OUTPUT_FILE ] codeinfo.withmpi = self.inputs.metadata.options.withmpi # create calculation info calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.codes_info = [codeinfo] calcinfo.retrieve_list = [] if self.inputs.retrieve_fchk: calcinfo.retrieve_list.append(self.DEFAULT_OUTPUT_FILE) # symlink or copy to parent calculation calcinfo.remote_symlink_list = [] calcinfo.remote_copy_list = [] comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, self.PARENT_FOLDER_NAME) if self.inputs.code.computer.uuid == comp_uuid: # if running on the same computer - make a symlink # if not - copy the folder calcinfo.remote_symlink_list.append(copy_info) else: calcinfo.remote_copy_list.append(copy_info) return calcinfo
def prepare_for_submission(self, folder): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param folder: a aiida.common.folders.Folder subclass where the plugin should put all its files. """ if 'structure' in self.inputs: pmg_structure = self.inputs.structure.get_pymatgen_molecule() else: # If structure is not specified, it is read from the chk file pmg_structure = None # Generate the input file input_string = GaussianCalculation._render_input_string_from_params( self.inputs.parameters.get_dict(), pmg_structure) with open(folder.get_abs_path(self.INPUT_FILE), "w") as out_file: out_file.write(input_string) settings = self.inputs.settings.get_dict( ) if "settings" in self.inputs else {} # create code info codeinfo = CodeInfo() codeinfo.cmdline_params = settings.pop("cmdline", []) codeinfo.code_uuid = self.inputs.code.uuid codeinfo.stdin_name = self.INPUT_FILE codeinfo.stdout_name = self.OUTPUT_FILE codeinfo.withmpi = self.inputs.metadata.options.withmpi # create calculation info calcinfo = CalcInfo() calcinfo.remote_copy_list = [] calcinfo.local_copy_list = [] calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self.INPUT_FILE calcinfo.stdout_name = self.OUTPUT_FILE calcinfo.codes_info = [codeinfo] calcinfo.retrieve_list = [self.OUTPUT_FILE] # symlink or copy to parent calculation calcinfo.remote_symlink_list = [] calcinfo.remote_copy_list = [] if "parent_calc_folder" in self.inputs: comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, self.PARENT_FOLDER_NAME) if (self.inputs.code.computer.uuid == comp_uuid): # if running on the same computer - make a symlink # if not - copy the folder calcinfo.remote_symlink_list.append(copy_info) else: calcinfo.remote_copy_list.append(copy_info) return calcinfo
def prepare_for_submission(self, folder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param folder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.datastructures.CalcInfo` instance """ settings = self.inputs.settings.get_dict( ) if 'settings' in self.inputs else {} param_dict = self.inputs.parameters.get_dict() # --------------------------------------------------- # Write params.ini file params_fn = folder.get_abs_path("params.ini") with open(params_fn, 'w') as f: for key, val in param_dict.items(): line = str(key) + " " if isinstance(val, list): line += " ".join(str(v) for v in val) else: line += str(val) f.write(line + '\n') # --------------------------------------------------- # create code info codeinfo = CodeInfo() codeinfo.code_uuid = self.inputs.code.uuid codeinfo.withmpi = False # create calc info calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.codes_info = [codeinfo] # file lists calcinfo.remote_symlink_list = [] calcinfo.local_copy_list = [ (self.inputs.atomtypes.uuid, self.inputs.atomtypes.filename, 'atomtypes.ini') ] calcinfo.remote_copy_list = [] calcinfo.retrieve_list = ["*/*/*.npy"] # symlinks if 'parent_calc_folder' in self.inputs: comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, 'parent_calc_folder/') if self.inputs.code.computer.uuid == comp_uuid: # if running on the same computer - make a symlink # if not - copy the folder calcinfo.remote_symlink_list.append(copy_info) else: calcinfo.remote_copy_list.append(copy_info) return calcinfo # EOF
def prepare_for_submission(self, folder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param folder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.datastructures.CalcInfo` instance """ # create code info codeinfo = CodeInfo() codeinfo.code_uuid = self.inputs.code.uuid param_dict = self.inputs.parameters.get_dict() cmdline = [] for key in param_dict: cmdline += [key] if param_dict[key] != '': if isinstance(param_dict[key], list): cmdline += param_dict[key] else: cmdline += [param_dict[key]] codeinfo.cmdline_params = cmdline # create calc info calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.codes_info = [codeinfo] # file lists calcinfo.remote_symlink_list = [] calcinfo.local_copy_list = [] calcinfo.remote_copy_list = [] calcinfo.retrieve_list = ["*.npy", "*.npz"] # symlinks if 'parent_calc_folder' in self.inputs: comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, 'parent_calc_folder/') if self.inputs.code.computer.uuid == comp_uuid: # if running on the same computer - make a symlink # if not - copy the folder calcinfo.remote_symlink_list.append(copy_info) else: calcinfo.remote_copy_list.append(copy_info) if 'ppm_calc_folder' in self.inputs: comp_uuid = self.inputs.ppm_calc_folder.computer.uuid remote_path = self.inputs.ppm_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, 'ppm_calc_folder/') if self.inputs.code.computer.uuid == comp_uuid: # if running on the same computer - make a symlink # if not - copy the folder calcinfo.remote_symlink_list.append(copy_info) else: calcinfo.remote_copy_list.append(copy_info) return calcinfo
def prepare_for_submission(self, folder): # create calculation info calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.codes_info = [] calcinfo.retrieve_list = [] for key, params in self.inputs.parameters.get_dict().items(): cube_name = key+".cube" kind_str = params["kind"] npts = params["npts"] # create code info codeinfo = CodeInfo() codeinfo.cmdline_params = [] codeinfo.cmdline_params.append(str(self.inputs.metadata.options.resources['tot_num_mpiprocs'])) codeinfo.cmdline_params.append(kind_str) codeinfo.cmdline_params.append(self._PARENT_FOLDER_NAME + "/" + self._DEFAULT_INPUT_FILE) codeinfo.cmdline_params.append(cube_name) codeinfo.cmdline_params.append(str(npts)) codeinfo.code_uuid = self.inputs.code.uuid codeinfo.withmpi = self.inputs.metadata.options.withmpi calcinfo.codes_info.append(codeinfo) if self.inputs.retrieve_cubes.value: calcinfo.retrieve_list.append(cube_name) extra_prepend = "\nexport GAUSS_MEMDEF=%dMB\n" % self.inputs.gauss_memdef if not hasattr(calcinfo, 'prepend_text') or not calcinfo.prepend_text: calcinfo.prepend_text = extra_prepend else: calcinfo.prepend_text += extra_prepend # symlink or copy to parent calculation calcinfo.remote_symlink_list = [] calcinfo.remote_copy_list = [] comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, self._PARENT_FOLDER_NAME) if self.inputs.code.computer.uuid == comp_uuid: # if running on the same computer - make a symlink # if not - copy the folder calcinfo.remote_symlink_list.append(copy_info) else: calcinfo.remote_copy_list.append(copy_info) return calcinfo
def prepare_for_submission(self, folder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param folder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.datastructures.CalcInfo` instance """ # Write input to file input_filename = folder.get_abs_path(self._DEFAULT_INPUT_FILE) with open(input_filename, 'w') as infile: infile.write(input_render(self.inputs.parameters.get_dict())) # Prepare CalcInfo to be returned to aiida calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.local_copy_list = [] calcinfo.remote_copy_list = [] calcinfo.remote_symlink_list = [] calcinfo.retrieve_list = [ self._DEFAULT_OUTPUT_FILE, [self._DEFAULT_ADDITIONAL_RETRIEVE_LIST, '.', 0], ] # Charge-density remotefolder (now working only for CP2K) if 'charge_density_folder' in self.inputs: charge_density_folder = self.inputs.charge_density_folder comp_uuid = charge_density_folder.computer.uuid remote_path = os.path.join( charge_density_folder.get_remote_path(), 'aiida-ELECTRON_DENSITY-1_0.cube', ) symlink = (comp_uuid, remote_path, 'valence_density.cube') calcinfo.remote_symlink_list.append(symlink) codeinfo = CodeInfo() codeinfo.cmdline_params = [] codeinfo.code_uuid = self.inputs.code.uuid calcinfo.codes_info = [codeinfo] return calcinfo
def prepare_for_submission(self, folder): """ The baseclass will only setup the basic calcinfo arguments but will not write **any** files which has to be implemented in the subclassed prepare_for_submission() method """ # if no custodian code is defined directly run the VASP calculation, # i.e. initialize the CodeInfo for the passed VASP code if not self.inputs.custodian.get('code', False): codeinfo = CodeInfo() codeinfo.code_uuid = self.inputs.code.uuid codeinfo.stdout_name = self._default_output_file codeinfo.stderr_name = self._default_error_file # otherwise wrap in Custodian calculation and initialize CodeInfo for # the passed Custodian code (This is sufficient as AiiDA will scan all # Code-inputs to generate the required prepend / append lines) else: codeinfo = CodeInfo() codeinfo.code_uuid = self.inputs.custodian.code.uuid # define custodian-exe command line arguments codeinfo.cmdline_params = ['run', PluginDefaults.CSTDN_SPEC_FNAME] # never add the MPI command to custodian since it will call # VASP using MPI itself codeinfo.withmpi = False calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.codes_info = [codeinfo] # those list are set defined in the inherited classes calcinfo.local_copy_list = [] calcinfo.remote_copy_list = [] calcinfo.remote_symlink_list = [] # retrieve lists are defined on the base class calcinfo.retrieve_temporary_list = self.retrieve_temporary_list() calcinfo.retrieve_list = self.retrieve_permanent_list() # need to set run mode since presubmit() takes all code inputs into # account and would complain if both vasp and custodian codes are set calcinfo.codes_run_mode = CodeRunMode.SERIAL # finally write the neccessary calculation inputs to the calculation's # input folder calcinfo = self.create_calculation_inputs(folder, calcinfo) return calcinfo
def prepare_for_submission(self, folder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param folder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.datastructures.CalcInfo` instance """ from .utils import Cp2kInput # create input structure if "structure" in self.inputs: self.inputs.structure.export(folder.get_abs_path( self._DEFAULT_COORDS_FILE_NAME), fileformat="xyz") # create cp2k input file inp = Cp2kInput(self.inputs.parameters.get_dict()) inp.add_keyword("GLOBAL/PROJECT", self._DEFAULT_PROJECT_NAME) if "structure" in self.inputs: for i, letter in enumerate("ABC"): inp.add_keyword( "FORCE_EVAL/SUBSYS/CELL/" + letter, "{:<15} {:<15} {:<15}".format( *self.inputs.structure.cell[i]), ) topo = "FORCE_EVAL/SUBSYS/TOPOLOGY" inp.add_keyword(topo + "/COORD_FILE_NAME", self._DEFAULT_COORDS_FILE_NAME) inp.add_keyword(topo + "/COORD_FILE_FORMAT", "XYZ") with io.open(folder.get_abs_path(self._DEFAULT_INPUT_FILE), mode="w", encoding="utf-8") as fobj: try: inp.to_file(fobj) except ValueError as exc: six.raise_from( InputValidationError( "invalid keys or values in input parameters found"), exc, ) if "settings" in self.inputs: settings = self.inputs.settings.get_dict() else: settings = {} # create code info codeinfo = CodeInfo() codeinfo.cmdline_params = settings.pop("cmdline", []) + [ "-i", self._DEFAULT_INPUT_FILE, ] codeinfo.stdout_name = self._DEFAULT_OUTPUT_FILE codeinfo.join_files = True codeinfo.code_uuid = self.inputs.code.uuid # create calc info calcinfo = CalcInfo() calcinfo.stdin_name = self._DEFAULT_INPUT_FILE calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self._DEFAULT_INPUT_FILE calcinfo.stdout_name = self._DEFAULT_OUTPUT_FILE calcinfo.codes_info = [codeinfo] # file lists calcinfo.remote_symlink_list = [] if "file" in self.inputs: calcinfo.local_copy_list = [] for fobj in self.inputs.file.values(): calcinfo.local_copy_list.append( (fobj.uuid, fobj.filename, fobj.filename)) calcinfo.remote_copy_list = [] calcinfo.retrieve_list = [ self._DEFAULT_OUTPUT_FILE, self._DEFAULT_RESTART_FILE_NAME, ] calcinfo.retrieve_list += settings.pop("additional_retrieve_list", []) # symlinks if "parent_calc_folder" in self.inputs: comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() symlink = (comp_uuid, remote_path, self._DEFAULT_PARENT_CALC_FLDR_NAME) calcinfo.remote_symlink_list.append(symlink) # check for left over settings if settings: raise InputValidationError( "The following keys have been found " + "in the settings input node {}, ".format(self.pk) + "but were not understood: " + ",".join(settings.keys())) return calcinfo
def prepare_for_submission(self, folder): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param folder: a aiida.common.folders.Folder subclass where the plugin should put all its files. """ # create calc info calcinfo = CalcInfo() calcinfo.remote_copy_list = [] calcinfo.local_copy_list = [] # The main input try: input_string = GaussianCalculation._render_input_string_from_params( self.inputs.parameters.get_dict(), self.inputs.structure ) # If structure is not specified the user might want to restart from a chk except AttributeError: input_string = GaussianCalculation._render_input_string_from_params( self.inputs.parameters.get_dict(), None ) # Parse additional link1 sections if "extra_link1_sections" in self.inputs: for l1_name, l1_params in self.inputs.extra_link1_sections.items(): input_string += "--Link1--\n" # The link1 secions don't support their own geometries. input_string += GaussianCalculation._render_input_string_from_params( l1_params.get_dict(), None ) with open(folder.get_abs_path(self.INPUT_FILE), "w") as out_file: out_file.write(input_string) settings = self.inputs.settings.get_dict() if "settings" in self.inputs else {} # create code info codeinfo = CodeInfo() codeinfo.cmdline_params = settings.pop("cmdline", []) codeinfo.code_uuid = self.inputs.code.uuid codeinfo.stdin_name = self.INPUT_FILE codeinfo.stdout_name = self.OUTPUT_FILE codeinfo.withmpi = self.inputs.metadata.options.withmpi # create calculation info calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self.INPUT_FILE calcinfo.stdout_name = self.OUTPUT_FILE calcinfo.codes_info = [codeinfo] calcinfo.retrieve_list = [self.OUTPUT_FILE] # symlink or copy to parent calculation calcinfo.remote_symlink_list = [] calcinfo.remote_copy_list = [] if "parent_calc_folder" in self.inputs: comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, "parent_calc") if ( self.inputs.code.computer.uuid == comp_uuid ): # if running on the same computer - make a symlink # if not - copy the folder calcinfo.remote_symlink_list.append(copy_info) else: calcinfo.remote_copy_list.append(copy_info) return calcinfo
def prepare_for_submission(self, folder): """Prepare the calculation job for submission by transforming input nodes into input files. In addition to the input files being written to the sandbox folder, a `CalcInfo` instance will be returned that contains lists of files that need to be copied to the remote machine before job submission, as well as file lists that are to be retrieved after job completion. :param folder: a sandbox folder to temporarily write files on disk. :return: :py:`~aiida.common.datastructures.CalcInfo` instance. """ # pylint: disable=too-many-branches,too-many-statements import numpy as np local_copy_list = [] remote_copy_list = [] remote_symlink_list = [] # Convert settings dictionary to have uppercase keys, or create an empty one if none was given. if 'settings' in self.inputs: settings_dict = _uppercase_dict(self.inputs.settings.get_dict(), dict_name='settings') else: settings_dict = {} first_structure = self.inputs.first_structure last_structure = self.inputs.last_structure # Check that the first and last image have the same cell if abs(np.array(first_structure.cell) - np.array(last_structure.cell)).max() > 1.e-4: raise InputValidationError('Different cell in the fist and last image') # Check that the first and last image have the same number of sites if len(first_structure.sites) != len(last_structure.sites): raise InputValidationError('Different number of sites in the fist and last image') # Check that sites in the initial and final structure have the same kinds if first_structure.get_site_kindnames() != last_structure.get_site_kindnames(): raise InputValidationError( 'Mismatch between the kind names and/or order between ' 'the first and final image' ) # Check that a pseudo potential was specified for each kind present in the `StructureData` # self.inputs.pw.pseudos is a plumpy.utils.AttributesFrozendict kindnames = [kind.name for kind in first_structure.kinds] if set(kindnames) != set(self.inputs.pw.pseudos.keys()): raise InputValidationError( 'Mismatch between the defined pseudos and the list of kinds of the structure.\nPseudos: {};\n' 'Kinds: {}'.format(', '.join(list(self.inputs.pw.pseudos.keys())), ', '.join(list(kindnames))) ) ############################## # END OF INITIAL INPUT CHECK # ############################## # Create the subfolder that will contain the pseudopotentials folder.get_subfolder(self._PSEUDO_SUBFOLDER, create=True) # Create the subfolder for the output data (sometimes Quantum ESPRESSO codes crash if the folder does not exist) folder.get_subfolder(self._OUTPUT_SUBFOLDER, create=True) # We first prepare the NEB-specific input file. neb_input_filecontent = self._generate_input_files(self.inputs.parameters, settings_dict) with folder.open(self.inputs.metadata.options.input_filename, 'w') as handle: handle.write(neb_input_filecontent) # We now generate the PW input files for each input structure local_copy_pseudo_list = [] for i, structure in enumerate([first_structure, last_structure]): # We need to a pass a copy of the settings_dict for each structure this_settings_dict = copy.deepcopy(settings_dict) pw_input_filecontent, this_local_copy_pseudo_list = PwCalculation._generate_PWCPinputdata( # pylint: disable=protected-access self.inputs.pw.parameters, this_settings_dict, self.inputs.pw.pseudos, structure, self.inputs.pw.kpoints ) local_copy_pseudo_list += this_local_copy_pseudo_list with folder.open(f'pw_{i + 1}.in', 'w') as handle: handle.write(pw_input_filecontent) # We need to pop the settings that were used in the PW calculations for key in list(settings_dict.keys()): if key not in list(this_settings_dict.keys()): settings_dict.pop(key) # We avoid to copy twice the same pseudopotential to the same filename local_copy_pseudo_list = set(local_copy_pseudo_list) # We check that two different pseudopotentials are not copied # with the same name (otherwise the first is overwritten) if len({filename for (uuid, filename, local_path) in local_copy_pseudo_list}) < len(local_copy_pseudo_list): raise InputValidationError('Same filename for two different pseudopotentials') local_copy_list += local_copy_pseudo_list # If present, add also the Van der Waals table to the pseudo dir. Note that the name of the table is not checked # but should be the one expected by Quantum ESPRESSO. vdw_table = self.inputs.get('pw.vdw_table', None) if vdw_table: local_copy_list.append( (vdw_table.uuid, vdw_table.filename, os.path.join(self._PSEUDO_SUBFOLDER, vdw_table.filename)) ) # operations for restart parent_calc_folder = self.inputs.get('parent_folder', None) symlink = settings_dict.pop('PARENT_FOLDER_SYMLINK', self._default_symlink_usage) # a boolean if symlink: if parent_calc_folder is not None: # I put the symlink to the old parent ./out folder remote_symlink_list.append(( parent_calc_folder.computer.uuid, os.path.join(parent_calc_folder.get_remote_path(), self._OUTPUT_SUBFOLDER, '*'), # asterisk: make individual symlinks for each file self._OUTPUT_SUBFOLDER )) # and to the old parent prefix.path remote_symlink_list.append(( parent_calc_folder.computer.uuid, os.path.join(parent_calc_folder.get_remote_path(), f'{self._PREFIX}.path'), f'{self._PREFIX}.path' )) else: # copy remote output dir and .path file, if specified if parent_calc_folder is not None: remote_copy_list.append(( parent_calc_folder.computer.uuid, os.path.join(parent_calc_folder.get_remote_path(), self._OUTPUT_SUBFOLDER, '*'), self._OUTPUT_SUBFOLDER )) # and copy the old parent prefix.path remote_copy_list.append(( parent_calc_folder.computer.uuid, os.path.join(parent_calc_folder.get_remote_path(), f'{self._PREFIX}.path'), f'{self._PREFIX}.path' )) # here we may create an aiida.EXIT file create_exit_file = settings_dict.pop('ONLY_INITIALIZATION', False) if create_exit_file: exit_filename = f'{self._PREFIX}.EXIT' with folder.open(exit_filename, 'w') as handle: handle.write('\n') calcinfo = CalcInfo() codeinfo = CodeInfo() calcinfo.uuid = self.uuid cmdline_params = settings_dict.pop('CMDLINE', []) calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = remote_copy_list calcinfo.remote_symlink_list = remote_symlink_list # In neb calculations there is no input read from standard input!! codeinfo.cmdline_params = (['-input_images', '2'] + list(cmdline_params)) codeinfo.stdout_name = self.inputs.metadata.options.output_filename codeinfo.code_uuid = self.inputs.code.uuid calcinfo.codes_info = [codeinfo] # Retrieve the output files and the xml files calcinfo.retrieve_list = [] calcinfo.retrieve_list.append(self.inputs.metadata.options.output_filename) calcinfo.retrieve_list.append(( os.path.join(self._OUTPUT_SUBFOLDER, self._PREFIX + '_*[0-9]', 'PW.out'), # source relative path (globbing) '.', # destination relative path 2 # depth to preserve )) for xml_filepath in self.xml_filepaths: # pylint: disable=not-an-iterable calcinfo.retrieve_list.append([xml_filepath, '.', 3]) calcinfo.retrieve_list += settings_dict.pop('ADDITIONAL_RETRIEVE_LIST', []) calcinfo.retrieve_list += self._internal_retrieve_list # We might still have parser options in the settings dictionary: pop them. _pop_parser_options(self, settings_dict) if settings_dict: unknown_keys = ', '.join(list(settings_dict.keys())) raise InputValidationError(f'`settings` contained unexpected keys: {unknown_keys}') return calcinfo
def prepare_for_submission(self, folder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param folder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.datastructures.CalcInfo` instance """ settings = self.inputs.settings.get_dict( ) if 'settings' in self.inputs else {} # create code info codeinfo = CodeInfo() codeinfo.code_uuid = self.inputs.code.uuid param_dict = self.inputs.parameters.get_dict() cmdline = [] for key in param_dict: cmdline += [key] if param_dict[key] != '': if isinstance(param_dict[key], list): cmdline += param_dict[key] else: cmdline += [param_dict[key]] codeinfo.cmdline_params = cmdline # create calc info calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.codes_info = [codeinfo] # file lists calcinfo.remote_symlink_list = [] calcinfo.local_copy_list = [] calcinfo.remote_copy_list = [] calcinfo.retrieve_list = settings.pop('additional_retrieve_list', []) # symlinks if 'parent_calc_folder' in self.inputs: comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, 'parent_calc_folder/') if self.inputs.code.computer.uuid == comp_uuid: # if running on the same computer - make a symlink # if not - copy the folder calcinfo.remote_symlink_list.append(copy_info) else: calcinfo.remote_copy_list.append(copy_info) # check for left over settings if settings: raise InputValidationError( "The following keys have been found " + "in the settings input node {}, ".format(self.pk) + "but were not understood: " + ",".join(settings.keys())) return calcinfo # EOF
def prepare_for_submission(self, folder): # create calculation info calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.codes_info = [] calcinfo.retrieve_list = [] calcinfo.retrieve_temporary_list = [] calcinfo.prepend_text = "export GAUSS_MEMDEF=%dMB\n" % self.inputs.gauss_memdef calcinfo.local_copy_list = [] if "stencil" in self.inputs: calcinfo.local_copy_list.append( (self.inputs.stencil.uuid, self.inputs.stencil.filename, 'stencil.txt')) for key, params in self.inputs.parameters.get_dict().items(): cube_name = key + ".cube" kind_str = params["kind"] npts = params["npts"] # create code info codeinfo = CodeInfo() codeinfo.cmdline_params = [] codeinfo.cmdline_params.append( str(self.inputs.metadata.options.resources['tot_num_mpiprocs']) ) codeinfo.cmdline_params.append(kind_str) codeinfo.cmdline_params.append(self.PARENT_FOLDER_NAME + "/" + self.DEFAULT_INPUT_FILE) codeinfo.cmdline_params.append(cube_name) if npts == -1: if 'stencil' not in self.inputs: self.report( "Warning: npts: -1 set but no stencil provided, using -2" ) codeinfo.cmdline_params.append("-2") else: codeinfo.cmdline_params.append(str(npts)) codeinfo.stdin_name = "stencil.txt" else: codeinfo.cmdline_params.append(str(npts)) codeinfo.code_uuid = self.inputs.code.uuid codeinfo.withmpi = self.inputs.metadata.options.withmpi calcinfo.codes_info.append(codeinfo) if self.inputs.retrieve_cubes.value: calcinfo.retrieve_list.append(cube_name) else: calcinfo.retrieve_temporary_list.append(cube_name) # symlink or copy to parent calculation calcinfo.remote_symlink_list = [] calcinfo.remote_copy_list = [] comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, self.PARENT_FOLDER_NAME) if self.inputs.code.computer.uuid == comp_uuid: # if running on the same computer - make a symlink # if not - copy the folder calcinfo.remote_symlink_list.append(copy_info) else: calcinfo.remote_copy_list.append(copy_info) return calcinfo
def prepare_for_submission(self, folder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param folder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.datastructures.CalcInfo` instance """ from aiida_cp2k.utils import Cp2kInput # create cp2k input file inp = Cp2kInput(self.inputs.parameters.get_dict()) inp.add_keyword("GLOBAL/PROJECT", self._DEFAULT_PROJECT_NAME) # create input structure(s) if 'structure' in self.inputs: # As far as I understand self.inputs.structure can't deal with tags # self.inputs.structure.export(folder.get_abs_path(self._DEFAULT_COORDS_FILE_NAME), fileformat="xyz") self._write_structure(self.inputs.structure, folder, self._DEFAULT_COORDS_FILE_NAME) # modify the input dictionary accordingly for i, letter in enumerate('ABC'): inp.add_keyword('FORCE_EVAL/SUBSYS/CELL/' + letter, '{:<15} {:<15} {:<15}'.format( *self.inputs.structure.cell[i]), override=False, conflicting_keys=[ 'ABC', 'ALPHA_BETA_GAMMA', 'CELL_FILE_NAME' ]) topo = "FORCE_EVAL/SUBSYS/TOPOLOGY" inp.add_keyword(topo + "/COORD_FILE_NAME", self._DEFAULT_COORDS_FILE_NAME, override=False) inp.add_keyword(topo + "/COORD_FILE_FORMAT", "XYZ", override=False, conflicting_keys=['COORDINATE']) with io.open(folder.get_abs_path(self._DEFAULT_INPUT_FILE), mode="w", encoding="utf-8") as fobj: try: fobj.write(inp.render()) except ValueError as exc: six.raise_from( InputValidationError( "invalid keys or values in input parameters found"), exc) settings = self.inputs.settings.get_dict( ) if 'settings' in self.inputs else {} # create code info codeinfo = CodeInfo() codeinfo.cmdline_params = settings.pop( 'cmdline', []) + ["-i", self._DEFAULT_INPUT_FILE] codeinfo.stdout_name = self._DEFAULT_OUTPUT_FILE codeinfo.join_files = True codeinfo.code_uuid = self.inputs.code.uuid # create calc info calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self._DEFAULT_INPUT_FILE calcinfo.stdout_name = self._DEFAULT_OUTPUT_FILE calcinfo.codes_info = [codeinfo] # files or additional structures if 'file' in self.inputs: calcinfo.local_copy_list = [] for name, obj in self.inputs.file.items(): if isinstance(obj, SinglefileData): calcinfo.local_copy_list.append( (obj.uuid, obj.filename, obj.filename)) elif isinstance(obj, StructureData): self._write_structure(obj, folder, name + '.xyz') calcinfo.retrieve_list = [ self._DEFAULT_OUTPUT_FILE, self._DEFAULT_RESTART_FILE_NAME, self._DEFAULT_TRAJECT_FILE_NAME ] calcinfo.retrieve_list += settings.pop('additional_retrieve_list', []) # symlinks calcinfo.remote_symlink_list = [] calcinfo.remote_copy_list = [] if 'parent_calc_folder' in self.inputs: comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, self._DEFAULT_PARENT_CALC_FLDR_NAME) if self.inputs.code.computer.uuid == comp_uuid: # if running on the same computer - make a symlink # if not - copy the folder calcinfo.remote_symlink_list.append(copy_info) else: calcinfo.remote_copy_list.append(copy_info) # check for left over settings if settings: raise InputValidationError( "The following keys have been found " + "in the settings input node {}, ".format(self.pk) + "but were not understood: " + ",".join(settings.keys())) return calcinfo
def prepare_for_submission(self, folder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param folder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.datastructures.CalcInfo` instance """ # Determine atomic densities directory pm_dict = self.inputs.parameters.get_dict() if DENSITY_DIR_KEY not in pm_dict: pm_dict[DENSITY_DIR_KEY] = self.inputs.code.extras.get( DENSITY_DIR_EXTRA) if not pm_dict[DENSITY_DIR_KEY]: raise ValueError( f"Please provide '{DENSITY_DIR_KEY}' in the input parameters or set the " f"{DENSITY_DIR_EXTRA} extra on the ddec code.") # The directory must end with a slash or chargemol crashes if not pm_dict[DENSITY_DIR_KEY].endswith('/'): pm_dict[DENSITY_DIR_KEY] += '/' if not os.path.isabs(pm_dict[DENSITY_DIR_KEY]): raise ValueError( f"Path to atomic densities directory '{pm_dict[DENSITY_DIR_KEY]}' is not absolute." ) # Create symlink to atomic densities directory density_dir_symlink = (self.inputs.code.computer.uuid, pm_dict[DENSITY_DIR_KEY], DENSITY_DIR_SYMLINK) pm_dict[DENSITY_DIR_KEY] = DENSITY_DIR_SYMLINK # Write input to file input_filename = folder.get_abs_path(self._DEFAULT_INPUT_FILE) with open(input_filename, 'w') as infile: infile.write(input_render(pm_dict)) # Prepare CalcInfo to be returned to aiida calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.local_copy_list = [] calcinfo.remote_copy_list = [] calcinfo.remote_symlink_list = [density_dir_symlink] calcinfo.retrieve_list = [ self._DEFAULT_OUTPUT_FILE, [self._DEFAULT_ADDITIONAL_RETRIEVE_LIST, '.', 0], ] # Charge-density remote folder (now working only for CP2K) if 'charge_density_folder' in self.inputs: charge_density_folder = self.inputs.charge_density_folder comp_uuid = charge_density_folder.computer.uuid remote_path = os.path.join( charge_density_folder.get_remote_path(), 'aiida-ELECTRON_DENSITY-1_0.cube', ) copy_info = (comp_uuid, remote_path, 'valence_density.cube') if self.inputs.code.computer.uuid == comp_uuid: # if running on the same computer - make a symlink calcinfo.remote_symlink_list.append(copy_info) else: # if not - copy the folder self.report( f"Warning: Transferring cube file {charge_density_folder.get_remote_path()} from " + f"computer {charge_density_folder.computer.label} to computer {self.inputs.code.computer.label}. " + "This may put strain on your network.") calcinfo.remote_copy_list.append(copy_info) codeinfo = CodeInfo() codeinfo.cmdline_params = [] codeinfo.code_uuid = self.inputs.code.uuid calcinfo.codes_info = [codeinfo] return calcinfo
def prepare_for_submission(self, folder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param folder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.datastructures.CalcInfo` instance """ # pylint: disable=too-many-statements,too-many-branches # Create cp2k input file. inp = Cp2kInput(self.inputs.parameters.get_dict()) inp.add_keyword("GLOBAL/PROJECT", self._DEFAULT_PROJECT_NAME) # Create input structure(s). if 'structure' in self.inputs: # As far as I understand self.inputs.structure can't deal with tags # self.inputs.structure.export(folder.get_abs_path(self._DEFAULT_COORDS_FILE_NAME), fileformat="xyz") self._write_structure(self.inputs.structure, folder, self._DEFAULT_COORDS_FILE_NAME) # modify the input dictionary accordingly for i, letter in enumerate('ABC'): inp.add_keyword('FORCE_EVAL/SUBSYS/CELL/' + letter, '{:<15} {:<15} {:<15}'.format(*self.inputs.structure.cell[i]), override=False, conflicting_keys=['ABC', 'ALPHA_BETA_GAMMA', 'CELL_FILE_NAME']) topo = "FORCE_EVAL/SUBSYS/TOPOLOGY" inp.add_keyword(topo + "/COORD_FILE_NAME", self._DEFAULT_COORDS_FILE_NAME, override=False) inp.add_keyword(topo + "/COORD_FILE_FORMAT", "XYZ", override=False, conflicting_keys=['COORDINATE']) if 'basissets' in self.inputs: validate_basissets(inp, self.inputs.basissets, self.inputs.structure if 'structure' in self.inputs else None) write_basissets(inp, self.inputs.basissets, folder) if 'pseudos' in self.inputs: validate_pseudos(inp, self.inputs.pseudos, self.inputs.structure if 'structure' in self.inputs else None) write_pseudos(inp, self.inputs.pseudos, folder) # Kpoints. if 'kpoints' in self.inputs: try: mesh, _ = self.inputs.kpoints.get_kpoints_mesh() except AttributeError: raise InputValidationError("K-point sampling for SCF must be given in mesh form.") inp.add_keyword('FORCE_EVAL/DFT/KPOINTS', {'WAVEFUNCTIONS': ' COMPLEX', 'FULL_GRID': '.TRUE.'}) inp.add_keyword('FORCE_EVAL/DFT/KPOINTS/SCHEME MONKHORST-PACK', f'{mesh[0]} {mesh[1]} {mesh[2]}') with io.open(folder.get_abs_path(self._DEFAULT_INPUT_FILE), mode="w", encoding="utf-8") as fobj: try: fobj.write(inp.render()) except ValueError as exc: raise InputValidationError("Invalid keys or values in input parameters found") from exc settings = self.inputs.settings.get_dict() if 'settings' in self.inputs else {} # Create code info. codeinfo = CodeInfo() codeinfo.cmdline_params = settings.pop('cmdline', []) + ["-i", self._DEFAULT_INPUT_FILE] codeinfo.stdout_name = self._DEFAULT_OUTPUT_FILE codeinfo.join_files = True codeinfo.code_uuid = self.inputs.code.uuid # Create calc info. calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self._DEFAULT_INPUT_FILE calcinfo.stdout_name = self._DEFAULT_OUTPUT_FILE calcinfo.codes_info = [codeinfo] # Files or additional structures. if 'file' in self.inputs: calcinfo.local_copy_list = [] for name, obj in self.inputs.file.items(): if isinstance(obj, SinglefileData): calcinfo.local_copy_list.append((obj.uuid, obj.filename, obj.filename)) elif isinstance(obj, StructureData): self._write_structure(obj, folder, name + '.xyz') calcinfo.retrieve_list = [ self._DEFAULT_OUTPUT_FILE, self._DEFAULT_RESTART_FILE_NAME, self._DEFAULT_TRAJECT_FILE_NAME ] calcinfo.retrieve_list += settings.pop('additional_retrieve_list', []) # Symlinks. calcinfo.remote_symlink_list = [] calcinfo.remote_copy_list = [] if 'parent_calc_folder' in self.inputs: comp_uuid = self.inputs.parent_calc_folder.computer.uuid remote_path = self.inputs.parent_calc_folder.get_remote_path() copy_info = (comp_uuid, remote_path, self._DEFAULT_PARENT_CALC_FLDR_NAME) # If running on the same computer - make a symlink. if self.inputs.code.computer.uuid == comp_uuid: calcinfo.remote_symlink_list.append(copy_info) # If not - copy the folder. else: calcinfo.remote_copy_list.append(copy_info) # Check for left over settings. if settings: raise InputValidationError( f"The following keys have been found in the settings input node {self.pk}, but were not understood: " + ",".join(settings.keys())) return calcinfo
def prepare_for_submission(self, folder): """ Routine to be called when create the input files and other stuff :param folder: a aiida.common.folders.Folder subclass where the plugin should put all its files. :param inputdict: a dictionary with the input nodes, as they would be returned by get_inputs_dict (without the Code!) """ self.prepare_inputs() local_copy_list = [] remote_copy_list = [] remote_symlink_list = [] require_parent = False for k in self.param_dict: if str(k).lower() in ["reuse", "continuation"]: require_parent = True break parent_calc_folder = self.inputs.get('parent_calc_folder') if parent_calc_folder is None and require_parent: raise InputValidationError( "No parent calculation folder passed" " for restart calculation using reuse/continuation") ############################## # END OF INITIAL INPUT CHECK # ############################## # Generate input file self.prepare_inputs(reset=True) if self._write_headers is True: cell_nodes = [] for name, inp in self.inputs.items(): if name in self._cell_links and inp: cell_nodes.append([name, inp]) # process pseudos for name, pseudo in self.inputs.pseudos.items(): cell_nodes.append(['pseudo__{}'.format(name), pseudo]) self.cell_file.header = self._generate_header_lines(cell_nodes) param_nodes = [] for name, inp in self.inputs.items(): if name in self._param_links and inp: param_nodes.append([name, inp]) self.param_file.header = self._generate_header_lines(param_nodes) local_copy_list.extend(self.local_copy_list_to_append) seedname = self.inputs.metadata.options.seedname cell_fn = seedname + ".cell" param_fn = seedname + ".param" with folder.open(cell_fn, mode='w') as incell: incell.write(self.cell_file.get_string()) with folder.open(param_fn, mode="w") as inparam: inparam.write(self.param_file.get_string()) # IMPLEMENT OPERATIONS FOR RESTART symlink = self.inputs.metadata.options.symlink_usage parent_calc_folder = self.inputs.get('parent_calc_folder', None) if parent_calc_folder: comp_uuid = parent_calc_folder.computer.uuid remote_path = parent_calc_folder.get_remote_path() if symlink: remote_list = remote_symlink_list else: remote_list = remote_copy_list remote_list.append( (comp_uuid, remote_path, self.inputs.metadata.options.parent_folder_name)) calcinfo = CalcInfo() calcinfo.uuid = self.uuid # COPY/SYMLINK LISTS calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = remote_copy_list calcinfo.remote_symlink_list = remote_symlink_list # SET UP extra CMDLINE arguments cmdline_params = self.settings_dict.pop("CMDLINE", []) # Extra parameters are added after the seed for CASTEP calcinfo.cmdline_params = [seedname] + list(cmdline_params) # CASTEP don't have any STDOUT etc when running calculations # Error is shown in the *.err file # Construct codeinfo instance codeinfo = CodeInfo() codeinfo.cmdline_params = [seedname] + list(cmdline_params) codeinfo.code_uuid = self.inputs.code.uuid calcinfo.codes_info = [codeinfo] # Retrieve by default the .castep file and the bands file calcinfo.retrieve_list = [] calcinfo.retrieve_list.append(seedname + ".castep") calcinfo.retrieve_list.append(seedname + ".bands") settings_retrieve_list = self.settings_dict.pop( "ADDITIONAL_RETRIEVE_LIST", []) calcinfo.retrieve_list.extend(settings_retrieve_list) calcinfo.retrieve_temporary_list = [] calcinfo.retrieve_temporary_list.extend( self.settings_dict.pop("ADDITIONAL_RETRIEVE_TEMPORARY_LIST", [])) calculation_mode = self.param_file.get("task", "singlepoint") # If we are doing geometryoptimisation retrieved the geom file and -out.cell file # dictionary for task specific file retrieve task_extra = self.retrieve_dict.get(calculation_mode.lower(), []) for suffix in task_extra: settings_retrieve_list.append(seedname + suffix) # Retrieve output cell file if requested if self.param_file.get("write_cell_structure"): settings_retrieve_list.append(seedname + "-out.cell") calcinfo.retrieve_list += settings_retrieve_list calcinfo.retrieve_list += self._default_retrieve_list # Remove parser options in the setting dictionary # At the moment parser options are not used here if self.settings_dict: raise InputValidationError( "The following keys have been found in " "the settings input node, but were not understood: {}".format( ",".join(list(self.settings_dict.keys())))) return calcinfo
def prepare_for_submission(self, folder): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param folder: a aiida.common.folders.Folder subclass where the plugin should put all its files. """ # initialize input parameters inp = RaspaInput(self.inputs.parameters.get_dict()) # keep order of systems in the extras self.node.set_extra('system_order', inp.system_order) # handle framework(s) and/or box(es) if "System" in inp.params: self._handle_system_section(inp.params["System"], folder) # handle restart if 'retrieved_parent_folder' in self.inputs: self._handle_retrieved_parent_folder(inp, folder) inp.params['GeneralSettings']['RestartFile'] = True # handle binary restart remote_copy_list = [] if 'parent_folder' in self.inputs: self._handle_parent_folder(remote_copy_list) inp.params['GeneralSettings']['ContinueAfterCrash'] = True # get settings if 'settings' in self.inputs: settings = self.inputs.settings.get_dict() else: settings = {} # write raspa input file with open(folder.get_abs_path(self.INPUT_FILE), "w") as fobj: fobj.write(inp.render()) # create code info codeinfo = CodeInfo() codeinfo.cmdline_params = settings.pop('cmdline', []) + [self.INPUT_FILE] codeinfo.code_uuid = self.inputs.code.uuid # create calc info calcinfo = CalcInfo() calcinfo.stdin_name = self.INPUT_FILE calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self.INPUT_FILE #calcinfo.stdout_name = self.OUTPUT_FILE calcinfo.codes_info = [codeinfo] # file lists calcinfo.remote_symlink_list = [] calcinfo.local_copy_list = [] if 'file' in self.inputs: for fobj in self.inputs.file.values(): calcinfo.local_copy_list.append( (fobj.uuid, fobj.filename, fobj.filename)) # block pockets if 'block_pocket' in self.inputs: for name, fobj in self.inputs.block_pocket.items(): calcinfo.local_copy_list.append( (fobj.uuid, fobj.filename, name + '.block')) # continue the previous calculation starting from the binary restart calcinfo.remote_copy_list = remote_copy_list calcinfo.retrieve_list = [self.OUTPUT_FOLDER, self.RESTART_FOLDER] calcinfo.retrieve_list += settings.pop('additional_retrieve_list', []) # check for left over settings if settings: raise InputValidationError( "The following keys have been found " + "in the settings input node {}, ".format(self.pk) + "but were not understood: " + ",".join(list(settings.keys()))) return calcinfo