def _prepare_for_submission(self, tempfolder, inputdict): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param tempfolder: 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_inputdata_dict (without the Code!) """ in_nodes = self._verify_inlinks(inputdict) params, structure, code, settings, local_copy_list = in_nodes # write cp2k input file inp = RaspaInput(params) inp_fn = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(inp_fn, "w") as f: f.write(inp.render()) # create code info codeinfo = CodeInfo() cmdline = settings.pop('cmdline', []) cmdline += [self._INPUT_FILE_NAME] codeinfo.cmdline_params = cmdline codeinfo.code_uuid = code.uuid # create calc info calcinfo = CalcInfo() calcinfo.stdin_name = self._INPUT_FILE_NAME calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self._INPUT_FILE_NAME # calcinfo.stdout_name = self._OUTPUT_FILE_NAME calcinfo.codes_info = [codeinfo] # file lists calcinfo.remote_symlink_list = [] calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = [] calcinfo.retrieve_list = [[self._OUTPUT_FILE_NAME,'.',0]] calcinfo.retrieve_list += settings.pop('additional_retrieve_list', []) # check for left over settings if settings: msg = "The following keys have been found " msg += "in the settings input node {}, ".format(self.pk) msg += "but were not understood: " + ",".join(settings.keys()) raise InputValidationError(msg) return calcinfo
def _prepare_for_submission(self, tempfolder, inputdict): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param tempfolder: 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_inputdata_dict (without the Code!) """ local_copy_list = [] remote_copy_list = [] # Process the settings dictionary first # Settings can be undefined, and defaults to an empty dictionary settings = inputdict.pop(self.get_linkname('settings'), None) if settings is None: settings_dict = {} else: if not isinstance(settings, ParameterData): raise InputValidationError( "settings, if specified, must be of " "type ParameterData") # Settings converted to UPPERCASE # Presumably to standardize the usage and avoid # ambiguities settings_dict = _uppercase_dict(settings.get_dict(), dict_name='settings') try: parameters = inputdict.pop(self.get_linkname('parameters')) except KeyError: raise InputValidationError("No parameters specified for this " "calculation") if not isinstance(parameters, ParameterData): raise InputValidationError("parameters is not of type " "ParameterData") try: parent_calc_folder = inputdict.pop( self.get_linkname('parent_folder')) except KeyError: raise InputValidationError( "No parent_calc_folder specified for this " "calculation") if not isinstance(parent_calc_folder, RemoteData): raise InputValidationError("parent_calc_folder, if specified," "must be of type RemoteData") # # Important note: This program should NOT be run with MPI. # Scripts using this plugin should use: # # calc.set_withmpi(False) # # We do it right here, and hope that it will not be overriden # # self.set_withmpi(False) # try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError( "No code specified for this calculation") # Here, there should be no more parameters... if inputdict: raise InputValidationError("The following input data nodes are " "unrecognized: {}".format( inputdict.keys())) # END OF INITIAL INPUT CHECK # # # There should be a warning for duplicated (canonicalized) keys # in the original dictionary in the script input_params = FDFDict(parameters.get_dict()) # Look for blocked keywords and # add the proper values to the dictionary for blocked_key in self._aiida_blocked_keywords: canonical_blocked = FDFDict.translate_key(blocked_key) for key in input_params: if key == canonical_blocked: raise InputValidationError( "You cannot specify explicitly the '{}' flag in the " "input parameters".format( input_params.get_last_key(key))) input_params.update({'system-label': self._PREFIX}) input_params.update({'mode': 'constant-height'}) input_params.update({'extension': 'ldos'}) # Maybe check that the 'z' coordinate makes sense... input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(input_filename, 'w') as infile: infile.write("aiida\n") infile.write("ldos\n") infile.write("constant-height\n") # Convert height to bohr... infile.write("{}\n".format(input_params['z'] / 0.529177)) infile.write("unformatted\n") # ------------------------------------- END of input file creation # The presence of a 'parent_calc_folder' is mandatory, to get the LDOS file # as indicated in the self._restart_copy_from attribute. # (this is not technically a restart, though) # It will be copied to the current calculation's working folder. if parent_calc_folder is not None: remote_copy_list.append( (parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), self._restart_copy_from), self._restart_copy_to)) calcinfo = CalcInfo() calcinfo.uuid = self.uuid # # Empty command line by default # Why use 'pop' ? cmdline_params = settings_dict.pop('CMDLINE', []) if cmdline_params: calcinfo.cmdline_params = list(cmdline_params) calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = remote_copy_list calcinfo.stdin_name = self._INPUT_FILE_NAME calcinfo.stdout_name = self._OUTPUT_FILE_NAME # # Code information object # codeinfo = CodeInfo() codeinfo.cmdline_params = list(cmdline_params) codeinfo.stdin_name = self._INPUT_FILE_NAME codeinfo.stdout_name = self._OUTPUT_FILE_NAME codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] # Retrieve by default: the output file and the plot file calcinfo.retrieve_list = [] calcinfo.retrieve_list.append(self._OUTPUT_FILE_NAME) calcinfo.retrieve_list.append(self._PLOT_FILE_NAME) # Any other files specified in the settings dictionary settings_retrieve_list = settings_dict.pop('ADDITIONAL_RETRIEVE_LIST', []) calcinfo.retrieve_list += settings_retrieve_list return calcinfo
def _prepare_for_submission(self, tempfolder, inputdict): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param tempfolder: 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_inputdata_dict (without the Code!) """ in_nodes = self._verify_inlinks(inputdict) params, structure, code, settings, local_copy_list, \ parent_calc_folder = in_nodes # write cp2k input file inp = Cp2kInput(params) inp.add_keyword("GLOBAL/PROJECT", self._PROJECT_NAME) if structure is not None: struct_fn = tempfolder.get_abs_path(self._COORDS_FILE_NAME) structure.export(struct_fn, fileformat="xyz") for i, a in enumerate('ABC'): val = '{:<15} {:<15} {:<15}'.format(*structure.cell[i]) inp.add_keyword('FORCE_EVAL/SUBSYS/CELL/' + a, val) topo = "FORCE_EVAL/SUBSYS/TOPOLOGY" inp.add_keyword(topo + "/COORD_FILE_NAME", self._COORDS_FILE_NAME) inp.add_keyword(topo + "/COORD_FILE_FORMAT", "XYZ") inp_fn = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(inp_fn, "w") as f: f.write(inp.render()) # create code info codeinfo = CodeInfo() cmdline = settings.pop('cmdline', []) cmdline += ["-i", self._INPUT_FILE_NAME] codeinfo.cmdline_params = cmdline codeinfo.stdout_name = self._OUTPUT_FILE_NAME codeinfo.join_files = True codeinfo.code_uuid = code.uuid # create calc info calcinfo = CalcInfo() calcinfo.stdin_name = self._INPUT_FILE_NAME calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self._INPUT_FILE_NAME calcinfo.stdout_name = self._OUTPUT_FILE_NAME calcinfo.codes_info = [codeinfo] # file lists calcinfo.remote_symlink_list = [] calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = [] calcinfo.retrieve_list = [ self._OUTPUT_FILE_NAME, self._RESTART_FILE_NAME, ['*dcd', '.', 0] ] calcinfo.retrieve_list += settings.pop('additional_retrieve_list', []) # symlinks if parent_calc_folder is not None: comp_uuid = parent_calc_folder.get_computer().uuid remote_path = parent_calc_folder.get_remote_path() symlink = (comp_uuid, remote_path, self._PARENT_CALC_FOLDER_NAME) calcinfo.remote_symlink_list.append(symlink) # check for left over settings if settings: msg = "The following keys have been found " msg += "in the settings input node {}, ".format(self.pk) msg += "but were not understood: " + ",".join(settings.keys()) raise InputValidationError(msg) return calcinfo
def _prepare_for_submission(self, tempfolder, inputdict): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param tempfolder: 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!) """ local_copy_list = [] remote_copy_list = [] remote_symlink_list = [] try: parameters = inputdict.pop(self.get_linkname('parameters')) except KeyError: raise InputValidationError( "No parameters specified for this calculation") if not isinstance(parameters, ParameterData): raise InputValidationError( "parameters is not of type ParameterData") try: structure = inputdict.pop(self.get_linkname('structure')) except KeyError: raise InputValidationError( "No structure specified for this calculation") if not isinstance(structure, StructureData): raise InputValidationError( "structure is not of type StructureData") if self._use_kpoints: try: kpoints = inputdict.pop(self.get_linkname('kpoints')) except KeyError: raise InputValidationError( "No kpoints specified for this calculation") if not isinstance(kpoints, KpointsData): raise InputValidationError( "kpoints is not of type KpointsData") else: kpoints = None # Settings can be undefined, and defaults to an empty dictionary settings = inputdict.pop(self.get_linkname('settings'), None) if settings is None: settings_dict = {} else: if not isinstance(settings, ParameterData): raise InputValidationError( "settings, if specified, must be of " "type ParameterData") # Settings converted to uppercase settings_dict = _uppercase_dict(settings.get_dict(), dict_name='settings') pseudos = {} # I create here a dictionary that associates each kind name to a pseudo for link in inputdict.keys(): if link.startswith(self._get_linkname_pseudo_prefix()): kindstring = link[len(self._get_linkname_pseudo_prefix()):] kinds = kindstring.split('_') the_pseudo = inputdict.pop(link) if not isinstance(the_pseudo, UpfData): raise InputValidationError( "Pseudo for kind(s) {} is not of " "type UpfData".format(",".join(kinds))) for kind in kinds: if kind in pseudos: raise InputValidationError( "Pseudo for kind {} passed " "more than one time".format(kind)) pseudos[kind] = the_pseudo parent_calc_folder = inputdict.pop(self.get_linkname('parent_folder'), None) if parent_calc_folder is not None: if not isinstance(parent_calc_folder, RemoteData): raise InputValidationError("parent_calc_folder, if specified, " "must be of type RemoteData") vdw_table = inputdict.pop(self.get_linkname('vdw_table'), None) if vdw_table is not None: if not isinstance(vdw_table, SinglefileData): raise InputValidationError("vdw_table, if specified, " "must be of type SinglefileData") try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError( "No code specified for this calculation") # Here, there should be no more parameters... if inputdict: raise InputValidationError("The following input data nodes are " "unrecognized: {}".format( inputdict.keys())) # Check structure, get species, check peudos kindnames = [k.name for k in structure.kinds] if set(kindnames) != set(pseudos.keys()): err_msg = ("Mismatch between the defined pseudos and the list of " "kinds of the structure. Pseudos: {}; kinds: {}".format( ",".join(pseudos.keys()), ",".join(list(kindnames)))) raise InputValidationError(err_msg) ############################## # END OF INITIAL INPUT CHECK # ############################## # I create the subfolder that will contain the pseudopotentials tempfolder.get_subfolder(self._PSEUDO_SUBFOLDER, create=True) # I create the subfolder with the output data (sometimes Quantum # Espresso codes crash if an empty folder is not already there tempfolder.get_subfolder(self._OUTPUT_SUBFOLDER, create=True) # 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 QE. if vdw_table: local_copy_list.append( (vdw_table.get_file_abs_path(), os.path.join(self._PSEUDO_SUBFOLDER, os.path.split( vdw_table.get_file_abs_path())[1]))) input_filecontent, local_copy_pseudo_list = self._generate_PWCPinputdata( parameters, settings_dict, pseudos, structure, kpoints) local_copy_list += local_copy_pseudo_list input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(input_filename, 'w') as infile: infile.write(input_filecontent) # operations for restart 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.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), self._restart_copy_from), self._restart_copy_to)) else: # copy remote output dir, if specified if parent_calc_folder is not None: remote_copy_list.append( (parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), self._restart_copy_from), self._restart_copy_to)) # here we may create an aiida.EXIT file create_exit_file = settings_dict.pop('ONLY_INITIALIZATION', False) if create_exit_file: exit_filename = tempfolder.get_abs_path('{}.EXIT'.format( self._PREFIX)) with open(exit_filename, 'w') as f: f.write('\n') # Check if specific inputs for the ENVIRON module where specified environ_namelist = settings_dict.pop('ENVIRON', None) if environ_namelist is not None: if not isinstance(environ_namelist, dict): raise InputValidationError( "ENVIRON namelist should be specified as a dictionary") # We first add the environ flag to the command-line options (if not already present) try: if '-environ' not in settings_dict['CMDLINE']: settings_dict['CMDLINE'].append('-environ') except KeyError: settings_dict['CMDLINE'] = ['-environ'] # To create a mapping from the species to an incremental fortran 1-based index # we use the alphabetical order as in the inputdata generation mapping_species = { sp_name: (idx + 1) for idx, sp_name in enumerate( sorted([kind.name for kind in structure.kinds])) } environ_input_filename = tempfolder.get_abs_path( self._ENVIRON_INPUT_FILE_NAME) with open(environ_input_filename, 'w') as environ_infile: environ_infile.write("&ENVIRON\n") for k, v in sorted(environ_namelist.iteritems()): environ_infile.write( get_input_data_text(k, v, mapping=mapping_species)) environ_infile.write("/\n") calcinfo = CalcInfo() calcinfo.uuid = self.uuid # Empty command line by default cmdline_params = settings_dict.pop('CMDLINE', []) # we commented calcinfo.stin_name and added it here in cmdline_params # in this way the mpirun ... pw.x ... < aiida.in # is replaced by mpirun ... pw.x ... -in aiida.in # in the scheduler, _get_run_line, if cmdline_params is empty, it # simply uses < calcinfo.stin_name calcinfo.cmdline_params = (list(cmdline_params) + ["-in", self._INPUT_FILE_NAME]) # calcinfo.stdin_name = self._INPUT_FILE_NAME # calcinfo.stdout_name = self._OUTPUT_FILE_NAME codeinfo = CodeInfo() codeinfo.cmdline_params = (list(cmdline_params) + ["-in", self._INPUT_FILE_NAME]) # calcinfo.stdin_name = self._INPUT_FILE_NAME codeinfo.stdout_name = self._OUTPUT_FILE_NAME codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = remote_copy_list calcinfo.remote_symlink_list = remote_symlink_list # Retrieve by default the output file and the xml file calcinfo.retrieve_list = [] calcinfo.retrieve_list.append(self._OUTPUT_FILE_NAME) calcinfo.retrieve_list.append(self._DATAFILE_XML) settings_retrieve_list = settings_dict.pop('ADDITIONAL_RETRIEVE_LIST', []) if settings_dict.pop('ALSO_BANDS', False): # To retrieve also the bands data settings_retrieve_list.append([ os.path.join(self._OUTPUT_SUBFOLDER, self._PREFIX + '.save', 'K*[0-9]', 'eigenval*.xml'), '.', 2 ]) calcinfo.retrieve_list += settings_retrieve_list calcinfo.retrieve_list += self._internal_retrieve_list try: Parserclass = self.get_parserclass() parser = Parserclass(self) parser_opts = parser.get_parser_settings_key() settings_dict.pop(parser_opts) except (KeyError, AttributeError): # the key parser_opts isn't inside the dictionary pass if settings_dict: raise InputValidationError( "The following keys have been found in " "the settings input node, but were not understood: {}".format( ",".join(settings_dict.keys()))) return calcinfo
def _prepare_for_submission(self, tempfolder, inputdict): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param tempfolder: 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_inputdata_dict (without the Code!) """ local_copy_list = [] remote_copy_list = [] # Process the settings dictionary first # Settings can be undefined, and defaults to an empty dictionary settings = inputdict.pop(self.get_linkname('settings'), None) if settings is None: settings_dict = {} else: if not isinstance(settings, ParameterData): raise InputValidationError( "settings, if specified, must be of " "type ParameterData") # Settings converted to UPPERCASE # Presumably to standardize the usage and avoid # ambiguities settings_dict = _uppercase_dict(settings.get_dict(), dict_name='settings') try: parameters = inputdict.pop(self.get_linkname('parameters')) except KeyError: raise InputValidationError("No parameters specified for this " "calculation") if not isinstance(parameters, ParameterData): raise InputValidationError("parameters is not of type " "ParameterData") try: structure = inputdict.pop(self.get_linkname('structure')) except KeyError: raise InputValidationError("No structure specified for this " "calculation") if not isinstance(structure, StructureData): raise InputValidationError( "structure is not of type StructureData") bandskpoints = inputdict.pop(self.get_linkname('bandskpoints'), None) if bandskpoints is None: flagbands = False else: flagbands = True if not isinstance(bandskpoints, KpointsData): raise InputValidationError( "kpoints for bands is not of type KpointsData") singlefile = inputdict.pop(self.get_linkname('singlefile'), None) if singlefile is not None: if not isinstance(singlefile, SinglefileData): raise InputValidationError("singlefile, if specified," "must be of type SinglefileData") parent_calc_folder = inputdict.pop(self.get_linkname('parent_folder'), None) if parent_calc_folder is not None: if not isinstance(parent_calc_folder, RemoteData): raise InputValidationError("parent_calc_folder, if specified," "must be of type RemoteData") try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError( "No code specified for this calculation") # Here, there should be no more parameters... if inputdict: raise InputValidationError("The following input data nodes are " "unrecognized: {}".format( inputdict.keys())) ############################## # END OF INITIAL INPUT CHECK # ############################## # # There should be a warning for duplicated (canonicalized) keys # in the original dictionary in the script input_params = FDFDict(parameters.get_dict()) # Look for blocked keywords and # add the proper values to the dictionary for blocked_key in self._aiida_blocked_keywords: canonical_blocked = FDFDict.translate_key(blocked_key) for key in input_params: if key == canonical_blocked: raise InputValidationError( "You cannot specify explicitly the '{}' flag in the " "input parameters".format( input_params.get_last_key(key))) input_params.update({'system-name': self._PREFIX}) input_params.update({'system-label': self._PREFIX}) input_params.update({'number-of-species': len(structure.kinds)}) input_params.update({'number-of-atoms': len(structure.sites)}) # # Regarding the lattice-constant parameter: # -- The variable "alat" is not typically kept anywhere, and # has already been used to define the vectors. # We need to specify that the units of these vectors are Ang... input_params.update({'lattice-constant': '1.0 Ang'}) # Note that this will break havoc with the band-k-points "pi/a" # option. The use of this option should be banned. # Note that the implicit coordinate convention of the Structure # class corresponds to the "Ang" convention in Siesta. # The "atomic-coordinates-format" keyword is blocked to ScaledCartesian, # which is given in terms of the lattice constant (1.0 Ang). input_params.update({'atomic-coordinates-format': 'ScaledCartesian'}) # ============== Preparation of input data =============== # # ------------ CELL_PARAMETERS ----------- cell_parameters_card = "%block lattice-vectors\n" for vector in structure.cell: cell_parameters_card += ("{0:18.10f} {1:18.10f} {2:18.10f}" "\n".format(*vector)) cell_parameters_card += "%endblock lattice-vectors\n" # ------------- ATOMIC_SPECIES ------------ # Only the species index and the mass are necessary # Dictionary to get the mass of a given element datmn = dict([(v['symbol'], v['mass']) for k, v in elements.iteritems()]) spind = {} spcount = 0 for kind in structure.kinds: spcount += 1 spind[kind.name] = spcount # ------------ ATOMIC_POSITIONS ----------- atomic_positions_card_list = [ "%block atomiccoordinatesandatomicspecies\n" ] countatm = 0 for site in structure.sites: countatm += 1 atomic_positions_card_list.append( "{0:18.10f} {1:18.10f} {2:18.10f} {3:4} {4:10} \n".format( site.position[0], site.position[1], site.position[2], spind[site.kind_name], datmn[kind.symbol])) atomic_positions_card = "".join(atomic_positions_card_list) del atomic_positions_card_list # Free memory atomic_positions_card += "%endblock atomiccoordinatesandatomicspecies\n" # --------------- K-POINTS-FOR-BANDS ----------------! #This part is computed only if flagbands=True #Two possibility are supported in Siesta: BandLines ad BandPoints #At the moment the user can't choose directly one of the two options #BandsLine is set automatically if bandskpoints has labels, #BandsPoints if bandskpoints has no labels #BandLinesScale =pi/a is not supported at the moment because currently #a=1 always. BandLinesScale ReciprocalLatticeVectors is always set if flagbands: bandskpoints_card_list = [ "BandLinesScale ReciprocalLatticeVectors\n" ] if bandskpoints.labels == None: bandskpoints_card_list.append("%block BandPoints\n") for s in bandskpoints.get_kpoints(): bandskpoints_card_list.append( "{0:8.3f} {1:8.3f} {2:8.3f} \n".format( s[0], s[1], s[2])) fbkpoints_card = "".join(bandskpoints_card_list) fbkpoints_card += "%endblock BandPoints\n" else: bandskpoints_card_list.append("%block BandLines\n") savs = [] listforbands = bandskpoints.get_kpoints() for s, m in bandskpoints.labels: savs.append(s) rawindex = 0 for s, m in bandskpoints.labels: rawindex = rawindex + 1 nkpnt, x, y, z, = listforbands[s] if rawindex == 1: bandskpoints_card_list.append( "{0:2} {1:8.3f} {2:8.3f} {3:8.3f} {4:1}\n".format( 1, x, y, z, m)) else: bandskpoints_card_list.append( "{0:.0f} {1:8.3f} {2:8.3f} {3:8.3f} {4:1}\n". format(nkpnt, x, y, z, m)) fbkpoints_card = "".join(bandskpoints_card_list) fbkpoints_card += "%endblock BandLines\n" del bandskpoints_card_list # -------------ADDITIONAL FILES ----------- # I create the subfolder that will contain additional Siesta files tempfolder.get_subfolder(self._SFILES_SUBFOLDER, create=True) # I create the subfolder with the output data tempfolder.get_subfolder(self._OUTPUT_SUBFOLDER, create=True) if singlefile is not None: lfile = singlefile.get_file_abs_path().split("path/", 1)[1] local_copy_list.append((singlefile.get_file_abs_path(), os.path.join(self._SFILES_SUBFOLDER, lfile))) # ================ Namelists and cards =================== input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(input_filename, 'w') as infile: # here print keys and values tp file for k, v in sorted(input_params.iteritems()): infile.write(get_input_data_text(k, v)) # ,mapping=mapping_species)) # Write previously generated cards now infile.write("#\n# -- Structural Info follows\n#\n") infile.write(cell_parameters_card) infile.write(atomic_positions_card) if flagbands: infile.write("#\n# -- Bandlines/Bandpoints Info follows\n#\n") infile.write(fbkpoints_card) # ------------------------------------- END of fdf file creation # The presence of a 'parent_calc_folder' input node signals # that we want to get something from there, as indicated in the # self._restart_copy_from attribute. # In Siesta's case, for now, it is just the density-matrix file # # It will be copied to the current calculation's working folder. if parent_calc_folder is not None: remote_copy_list.append( (parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), self._restart_copy_from), self._restart_copy_to)) calcinfo = CalcInfo() calcinfo.uuid = self.uuid # # Empty command line by default # Why use 'pop' ? cmdline_params = settings_dict.pop('CMDLINE', []) # Comment this paragraph better, if applicable to Siesta # #we commented calcinfo.stin_name and added it here in cmdline_params #in this way the mpirun ... pw.x ... < aiida.in #is replaced by mpirun ... pw.x ... -in aiida.in # in the scheduler, _get_run_line, if cmdline_params is empty, it # simply uses < calcinfo.stin_name if cmdline_params: calcinfo.cmdline_params = list(cmdline_params) calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = remote_copy_list calcinfo.stdin_name = self._INPUT_FILE_NAME calcinfo.stdout_name = self._OUTPUT_FILE_NAME calcinfo.fc_name = self._FC_FILE_NAME # # Code information object # codeinfo = CodeInfo() codeinfo.cmdline_params = list(cmdline_params) codeinfo.stdin_name = self._INPUT_FILE_NAME codeinfo.stdout_name = self._OUTPUT_FILE_NAME codeinfo.fc_name = self._FC_FILE_NAME codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] # Retrieve by default: the output file, the xml file, and the # messages file. # If flagbands=True we also add the bands file to the retrieve list! # This is extremely important because the parser parses the bands # only if aiida.bands is in the retrieve list!! calcinfo.retrieve_list = [] calcinfo.retrieve_list.append(self._OUTPUT_FILE_NAME) if flagbands: calcinfo.retrieve_list.append(self._BANDS_FILE_NAME) # Any other files specified in the settings dictionary settings_retrieve_list = settings_dict.pop('ADDITIONAL_RETRIEVE_LIST', []) calcinfo.retrieve_list += settings_retrieve_list return calcinfo
def _prepare_for_submission(self, tempfolder, inputdict): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param tempfolder: 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_inputdata_dict (without the Code!) """ in_nodes = self._verify_inlinks(inputdict) params, structure, code, settings, restart_folder, local_copy_list = in_nodes # handle restart if restart_folder is not None: self._create_restart(restart_folder, params, tempfolder) for i, component in enumerate(params['Component']): if 'BlockPockets' in component: if component['BlockPockets'] is True: if 'BlockPocketsPk' in component: self._create_block(params, tempfolder, i) else: raise InputValidationError( "You did not specify" " the parent pk number for block calculation." " Please define BlockPocketsPk in the input" " Component {} section".format(i)) # write raspa input file if 'FrameworkName' in params['GeneralSettings']: raise InputValidationError( 'You should not provide "FrameworkName"' ' as an input parameter. It will be generated automatically' ' by AiiDA') else: params['GeneralSettings']['FrameworkName'] = 'framework' inp = RaspaInput(params) inp_fn = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(inp_fn, "w") as f: f.write(inp.render()) # create structure file if structure is not None: dest = tempfolder.get_abs_path(structure.filename) copyfile(structure.get_file_abs_path(), tempfolder.get_abs_path(self._COORDS_FILE_NAME)) # create code info codeinfo = CodeInfo() cmdline = settings.pop('cmdline', []) cmdline += [self._INPUT_FILE_NAME] codeinfo.cmdline_params = cmdline codeinfo.code_uuid = code.uuid # create calc info calcinfo = CalcInfo() calcinfo.stdin_name = self._INPUT_FILE_NAME calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self._INPUT_FILE_NAME # calcinfo.stdout_name = self._OUTPUT_FILE_NAME calcinfo.codes_info = [codeinfo] # file lists calcinfo.remote_symlink_list = [] calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = [] calcinfo.retrieve_list = [[self._OUTPUT_FILE_NAME, '.', 0], [self._RESTART_FILE_NAME, '.', 0]] calcinfo.retrieve_list += settings.pop('additional_retrieve_list', []) # check for left over settings if settings: msg = "The following keys have been found " msg += "in the settings input node {}, ".format(self.pk) msg += "but were not understood: " + ",".join(settings.keys()) raise InputValidationError(msg) return calcinfo
def _prepare_for_submission(self, tempfolder, inputdict): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param tempfolder: 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_inputdata_dict (without the Code!) """ ### ------------------------------------------------------ ### Input check try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError("No code specified for this calculation") try: parameters = inputdict.pop(self.get_linkname('parameters')) except KeyError: raise InputValidationError("No parameters specified for this calculation") if not isinstance(parameters, ParameterData): raise InputValidationError("parameters is not of type ParameterData") try: parent_calc_folder = inputdict.pop(self.get_linkname('parent_calc_folder')) except KeyError: raise InputValidationError("No parent_calc_folder specified for this calculation") if not isinstance(parent_calc_folder, RemoteData): raise InputValidationError("parent_calc_folder is not of type RemoteData") try: settings = inputdict.pop(self.get_linkname('settings')) except KeyError: raise InputValidationError("No settings specified for this calculation") if not isinstance(settings, ParameterData): raise InputValidationError("settings is not of type ParameterData") settings_dict = settings.get_dict() # Here, there should be no more parameters... if inputdict: raise InputValidationError("The following input data nodes are " "unrecognized: {}".format(inputdict.keys())) ### End of input check ### ------------------------------------------------------ # create code info codeinfo = CodeInfo() codeinfo.code_uuid = code.uuid cmdline = [] for key in parameters.dict: cmdline += [key] if parameters.dict[key] != '': if isinstance(parameters.dict[key], list): cmdline += parameters.dict[key] else: cmdline += [parameters.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_dict.pop('additional_retrieve_list', []) # symlinks if parent_calc_folder is not None: comp_uuid = parent_calc_folder.get_computer().uuid remote_path = parent_calc_folder.get_remote_path() symlink = (comp_uuid, remote_path, self._PARENT_CALC_FOLDER_NAME) calcinfo.remote_symlink_list.append(symlink) return calcinfo # EOF
def _prepare_for_submission(self, tempfolder, inputdict): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param tempfolder: 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_inputdata_dict (without the Code!) """ local_copy_list = [] remote_copy_list = [] # Process the settings dictionary first # Settings can be undefined, and defaults to an empty dictionary settings = inputdict.pop(self.get_linkname('settings'), None) if settings is None: settings_dict = {} else: if not isinstance(settings, ParameterData): raise InputValidationError( "settings, if specified, must be of " "type ParameterData") # Settings converted to UPPERCASE # Presumably to standardize the usage and avoid # ambiguities settings_dict = _uppercase_dict(settings.get_dict(), dict_name='settings') try: parameters = inputdict.pop(self.get_linkname('parameters')) except KeyError: raise InputValidationError("No parameters specified for this " "calculation") if not isinstance(parameters, ParameterData): raise InputValidationError("parameters is not of type " "ParameterData") # Basis can be undefined, and defaults to an empty dictionary, # Siesta will use default parameters basis = inputdict.pop(self.get_linkname('basis'), None) if basis is None: input_basis = {} else: if not isinstance(basis, ParameterData): raise InputValidationError("basis not of type ParameterData") # input_basis=FDFDict(basis.get_dict()) input_basis = basis.get_dict() try: structure = inputdict.pop(self.get_linkname('structure')) except KeyError: raise InputValidationError("No structure specified for this " "calculation") if not isinstance(structure, StructureData): raise InputValidationError( "structure is not of type StructureData") # k-points # It is now possible to elide the kpoints node. # # Note also that a *different* set of k-points is needed if a band # calculation is carried out. This should be specified somehow in # the 'settings' dictionary (see QE example...) kpoints = inputdict.pop(self.get_linkname('kpoints'), None) if kpoints is None: # Do nothing. Assume it is a gamma-point calculation pass else: if not isinstance(kpoints, KpointsData): raise InputValidationError("kpoints, if specified, must be of " "type KpointsData") bandskpoints = inputdict.pop(self.get_linkname('bandskpoints'), None) if bandskpoints is None: flagbands = False else: flagbands = True if not isinstance(bandskpoints, KpointsData): raise InputValidationError( "kpoints for bands is not of type KpointsData") pseudos = {} # I create here a dictionary that associates each kind name to a pseudo for link in inputdict.keys(): if link.startswith(self._get_linkname_pseudo_prefix()): kindstring = link[len(self._get_linkname_pseudo_prefix()):] kinds = kindstring.split('_') the_pseudo = inputdict.pop(link) if not isinstance(the_pseudo, PsfData): raise InputValidationError("Pseudo for kind(s) {} is not " " of type PsfData".format( ",".join(kinds))) # # Note that we can associate the same pseudo object to different # atom kinds # for kind in kinds: pseudos[kind] = the_pseudo parent_calc_folder = inputdict.pop(self.get_linkname('parent_folder'), None) if parent_calc_folder is not None: if not isinstance(parent_calc_folder, RemoteData): raise InputValidationError("parent_calc_folder, if specified," "must be of type RemoteData") try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError( "No code specified for this calculation") # Here, there should be no more parameters... if inputdict: raise InputValidationError("The following input data nodes are " "unrecognized: {}".format( inputdict.keys())) # Check structure, get species, check peudos kindnames = [k.name for k in structure.kinds] if set(kindnames) != set(pseudos.keys()): err_msg = ("Mismatch between the defined pseudos and the list of " "kinds of the structure. Pseudos: {}; kinds: {}".format( ",".join(pseudos.keys()), ",".join(list(kindnames)))) raise InputValidationError(err_msg) ############################## # END OF INITIAL INPUT CHECK # ############################## # # There should be a warning for duplicated (canonicalized) keys # in the original dictionary in the script input_params = FDFDict(parameters.get_dict()) # Look for blocked keywords and # add the proper values to the dictionary for blocked_key in self._aiida_blocked_keywords: canonical_blocked = FDFDict.translate_key(blocked_key) for key in input_params: if key == canonical_blocked: raise InputValidationError( "You cannot specify explicitly the '{}' flag in the " "input parameters".format( input_params.get_last_key(key))) input_params.update({'system-name': self._PREFIX}) input_params.update({'system-label': self._PREFIX}) input_params.update({'use-tree-timer': 'T'}) input_params.update({'xml-write': 'T'}) input_params.update({'number-of-species': len(structure.kinds)}) input_params.update({'number-of-atoms': len(structure.sites)}) # # Regarding the lattice-constant parameter: # -- The variable "alat" is not typically kept anywhere, and # has already been used to define the vectors. # We need to specify that the units of these vectors are Ang... input_params.update({'lattice-constant': '1.0 Ang'}) # Note that this will break havoc with the band-k-points "pi/a" # option. The use of this option should be banned. # Note that the implicit coordinate convention of the Structure # class corresponds to the "Ang" convention in Siesta. # That is why the "atomic-coordinates-format" keyword is blocked # and reset. input_params.update({'atomic-coordinates-format': 'Ang'}) # ============== Preparation of input data =============== # # ------------ CELL_PARAMETERS ----------- cell_parameters_card = "%block lattice-vectors\n" for vector in structure.cell: cell_parameters_card += ("{0:18.10f} {1:18.10f} {2:18.10f}" "\n".format(*vector)) cell_parameters_card += "%endblock lattice-vectors\n" # ------------- ATOMIC_SPECIES ------------ # I create the subfolder that will contain the pseudopotentials tempfolder.get_subfolder(self._PSEUDO_SUBFOLDER, create=True) # I create the subfolder with the output data tempfolder.get_subfolder(self._OUTPUT_SUBFOLDER, create=True) atomic_species_card_list = [] # Dictionary to get the atomic number of a given element datmn = dict([(v['symbol'], k) for k, v in elements.iteritems()]) spind = {} spcount = 0 for kind in structure.kinds: ps = pseudos[kind.name] # I add this pseudo file to the list of files to copy, # with the appropiate name local_copy_list.append((ps.get_file_abs_path(), os.path.join(self._PSEUDO_SUBFOLDER, kind.name + ".psf"))) spcount += 1 spind[kind.name] = spcount atomic_species_card_list.append("{0:5} {1:5} {2:5}\n".format( spind[kind.name], datmn[kind.symbol], kind.name.rjust(6))) atomic_species_card_list = (["%block chemicalspecieslabel\n"] + list(atomic_species_card_list)) atomic_species_card = "".join(atomic_species_card_list) atomic_species_card += "%endblock chemicalspecieslabel\n" # Free memory del atomic_species_card_list # ------------ ATOMIC_POSITIONS ----------- atomic_positions_card_list = [ "%block atomiccoordinatesandatomicspecies\n" ] countatm = 0 for site in structure.sites: countatm += 1 atomic_positions_card_list.append( "{0:18.10f} {1:18.10f} {2:18.10f} {3:4} {4:6} {5:6}\n".format( site.position[0], site.position[1], site.position[2], spind[site.kind_name], site.kind_name.rjust(6), countatm)) atomic_positions_card = "".join(atomic_positions_card_list) del atomic_positions_card_list # Free memory atomic_positions_card += "%endblock atomiccoordinatesandatomicspecies\n" # --------------- K-POINTS ---------------- if kpoints is not None: # # Get a mesh for sampling # NOTE that there is not yet support for the 'kgrid-cutoff' # option in Siesta. # try: mesh, offset = kpoints.get_kpoints_mesh() has_mesh = True except AttributeError: raise InputValidationError("K-point sampling for scf " "must be given in mesh form") kpoints_card_list = ["%block kgrid_monkhorst_pack\n"] # # This will fail if has_mesh is False (for the case of a list), # since in that case 'offset' is undefined. # kpoints_card_list.append("{0:6} {1:6} {2:6} {3:18.10f}\n".format( mesh[0], 0, 0, offset[0])) kpoints_card_list.append("{0:6} {1:6} {2:6} {3:18.10f}\n".format( 0, mesh[1], 0, offset[1])) kpoints_card_list.append("{0:6} {1:6} {2:6} {3:18.10f}\n".format( 0, 0, mesh[2], offset[2])) kpoints_card = "".join(kpoints_card_list) kpoints_card += "%endblock kgrid_monkhorst_pack\n" del kpoints_card_list # --------------- K-POINTS-FOR-BANDS ----------------! #This part is computed only if flagbands=True #Two possibility are supported in Siesta: BandLines ad BandPoints #At the moment the user can't choose directly one of the two options #BandsLine is set automatically if bandskpoints has labels, #BandsPoints if bandskpoints has no labels #BandLinesScale =pi/a is not supported at the moment because currently #a=1 always. BandLinesScale ReciprocalLatticeVectors is always set if flagbands: bandskpoints_card_list = [ "BandLinesScale ReciprocalLatticeVectors\n" ] if bandskpoints.labels == None: bandskpoints_card_list.append("%block BandPoints\n") for s in bandskpoints.get_kpoints(): bandskpoints_card_list.append( "{0:8.3f} {1:8.3f} {2:8.3f} \n".format( s[0], s[1], s[2])) fbkpoints_card = "".join(bandskpoints_card_list) fbkpoints_card += "%endblock BandPoints\n" else: bandskpoints_card_list.append("%block BandLines\n") savs = [] listforbands = bandskpoints.get_kpoints() for s, m in bandskpoints.labels: savs.append(s) rawindex = 0 for s, m in bandskpoints.labels: rawindex = rawindex + 1 x, y, z = listforbands[s] if rawindex == 1: bandskpoints_card_list.append( "{0:3} {1:8.3f} {2:8.3f} {3:8.3f} {4:1} \n".format( 1, x, y, z, m)) else: bandskpoints_card_list.append( "{0:3} {1:8.3f} {2:8.3f} {3:8.3f} {4:1} \n".format( s - savs[rawindex - 2], x, y, z, m)) fbkpoints_card = "".join(bandskpoints_card_list) fbkpoints_card += "%endblock BandLines\n" del bandskpoints_card_list # ================ Namelists and cards =================== input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(input_filename, 'w') as infile: # here print keys and values tp file for k, v in sorted(input_params.iteritems()): infile.write(get_input_data_text(k, v)) # ,mapping=mapping_species)) # Basis set info is processed just like the general # parameters section. Some discipline is needed to # put any basis-related parameters (including blocks) # in the basis dictionary in the input script. # if basis is not None: infile.write("#\n# -- Basis Set Info follows\n#\n") for k, v in input_basis.iteritems(): infile.write(get_input_data_text(k, v)) # Write previously generated cards now infile.write("#\n# -- Structural Info follows\n#\n") infile.write(atomic_species_card) infile.write(cell_parameters_card) infile.write(atomic_positions_card) if kpoints is not None: infile.write("#\n# -- K-points Info follows\n#\n") infile.write(kpoints_card) if flagbands: infile.write("#\n# -- Bandlines/Bandpoints Info follows\n#\n") infile.write(fbkpoints_card) # Write max wall-clock time infile.write("#\n# -- Max wall-clock time block\n#\n") infile.write("max.walltime {}".format( self.get_max_wallclock_seconds())) # ------------------------------------- END of fdf file creation # operations for restart # The presence of a 'parent_calc_folder' input node signals # that we want to get something from there, as indicated in the # self._restart_copy_from attribute. # In Siesta's case, for now, it is just the density-matrix file # # It will be copied to the current calculation's working folder. if parent_calc_folder is not None: remote_copy_list.append( (parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), self._restart_copy_from), self._restart_copy_to)) calcinfo = CalcInfo() calcinfo.uuid = self.uuid # # Empty command line by default # Why use 'pop' ? cmdline_params = settings_dict.pop('CMDLINE', []) # Comment this paragraph better, if applicable to Siesta # #we commented calcinfo.stin_name and added it here in cmdline_params #in this way the mpirun ... pw.x ... < aiida.in #is replaced by mpirun ... pw.x ... -in aiida.in # in the scheduler, _get_run_line, if cmdline_params is empty, it # simply uses < calcinfo.stin_name if cmdline_params: calcinfo.cmdline_params = list(cmdline_params) calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = remote_copy_list calcinfo.stdin_name = self._INPUT_FILE_NAME calcinfo.stdout_name = self._OUTPUT_FILE_NAME calcinfo.xml_name = self._XML_FILE_NAME calcinfo.json_name = self._JSON_FILE_NAME calcinfo.messages_name = self._MESSAGES_FILE_NAME # # Code information object # codeinfo = CodeInfo() codeinfo.cmdline_params = list(cmdline_params) codeinfo.stdin_name = self._INPUT_FILE_NAME codeinfo.stdout_name = self._OUTPUT_FILE_NAME codeinfo.xml_name = self._XML_FILE_NAME codeinfo.json_name = self._JSON_FILE_NAME codeinfo.messages_name = self._MESSAGES_FILE_NAME codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] # Retrieve by default: the output file, the xml file, and the # messages file. # If flagbands=True we also add the bands file to the retrieve list! # This is extremely important because the parser parses the bands # only if aiida.bands is in the retrieve list!! calcinfo.retrieve_list = [] calcinfo.retrieve_list.append(self._OUTPUT_FILE_NAME) calcinfo.retrieve_list.append(self._XML_FILE_NAME) calcinfo.retrieve_list.append(self._JSON_FILE_NAME) calcinfo.retrieve_list.append(self._MESSAGES_FILE_NAME) if flagbands: calcinfo.retrieve_list.append(self._BANDS_FILE_NAME) # Any other files specified in the settings dictionary settings_retrieve_list = settings_dict.pop('ADDITIONAL_RETRIEVE_LIST', []) calcinfo.retrieve_list += settings_retrieve_list return calcinfo
def _prepare_for_submission(self, tempfolder, inputdict): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param tempfolder: 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_inputdata_dict (without the Code!) """ in_nodes = self._verify_inlinks(inputdict) params, structure, code, settings, block_pockets, restart_folder, local_copy_list = in_nodes # handle restart if restart_folder is not None: self._create_restart(restart_folder, params, tempfolder) # handle block pockets for i, block_pocket in enumerate(block_pockets): if block_pocket: params['Component'][i][ 'BlockPocketsFileName'] = 'component_{}'.format(i) params['Component'][i]['BlockPockets'] = 'yes' copyfile( block_pocket.get_file_abs_path(), tempfolder.get_subfolder(".").get_abs_path( 'component_{}.block'.format(i))) # write raspa input file if 'FrameworkName' in params['GeneralSettings']: raise InputValidationError( 'You should not provide "FrameworkName"' ' as an input parameter. It will be generated automatically' ' by AiiDA') elif structure is not None: params['GeneralSettings']['Framework'] = '0' params['GeneralSettings']['FrameworkName'] = 'framework' inp = RaspaInput(params) inp_fn = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(inp_fn, "w") as f: f.write(inp.render()) # create structure file if structure is not None: # rewrite cif file using ase to get correct labels column in format e.g. O1 O2 ... # otherwise RASPA parses cif file often incorrectly # atoms = structure.get_ase() # write(tempfolder.get_abs_path(self._COORDS_FILE_NAME), atoms) copyfile(structure.get_file_abs_path(), tempfolder.get_abs_path(self._COORDS_FILE_NAME)) # create code info codeinfo = CodeInfo() cmdline = settings.pop('cmdline', []) cmdline += [self._INPUT_FILE_NAME] codeinfo.cmdline_params = cmdline codeinfo.code_uuid = code.uuid # create calc info calcinfo = CalcInfo() calcinfo.stdin_name = self._INPUT_FILE_NAME calcinfo.uuid = self.uuid calcinfo.cmdline_params = codeinfo.cmdline_params calcinfo.stdin_name = self._INPUT_FILE_NAME # calcinfo.stdout_name = self._OUTPUT_FILE_NAME calcinfo.codes_info = [codeinfo] # file lists calcinfo.remote_symlink_list = [] calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = [] calcinfo.retrieve_list = [[self._OUTPUT_FILE_NAME, '.', 0], [self._RESTART_FILE_NAME, '.', 0]] calcinfo.retrieve_list += settings.pop('additional_retrieve_list', []) # check for left over settings if settings: msg = "The following keys have been found " msg += "in the settings input node {}, ".format(self.pk) msg += "but were not understood: " + ",".join(list( settings.keys())) raise InputValidationError(msg) return calcinfo
def _prepare_for_submission(self, tempfolder, inputdict): """ This is the routine to be called when you want to create the input files and related stuff with a plugin. :param tempfolder: 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_inputdata_dict (without the Code!) """ local_copy_list = [] remote_copy_list = [] # Process the settings dictionary first # Settings can be undefined, and defaults to an empty dictionary settings = inputdict.pop(self.get_linkname('settings'), None) if settings is None: settings_dict = {} else: if not isinstance(settings, ParameterData): raise InputValidationError( "settings, if specified, must be of " "type ParameterData") # Settings converted to UPPERCASE to standardize the usage and # avoid ambiguities settings_dict = _uppercase_dict(settings.get_dict(), dict_name='settings') # Parameters try: parameters = inputdict.pop(self.get_linkname('parameters')) except KeyError: raise InputValidationError("No parameters specified for this " "calculation") if not isinstance(parameters, ParameterData): raise InputValidationError("parameters is not of type " "ParameterData") # Singlefile singlefile = inputdict.pop(self.get_linkname('singlefile'), None) if singlefile is not None: if not isinstance(singlefile, SinglefileData): raise InputValidationError("singlefile, if specified," "must be of type SinglefileData") # Parent calculation folder parent_calc_folder = inputdict.pop(self.get_linkname('parent_folder'), None) if parent_calc_folder is not None: if not isinstance(parent_calc_folder, RemoteData): raise InputValidationError("parent_calc_folder, if specified," "must be of type RemoteData") # Code try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError( "No code specified for this calculation") # Here, there should be no more input data if inputdict: raise InputValidationError("The following input data nodes are " "unrecognized: {}".format( inputdict.keys())) ############################## # END OF INITIAL INPUT CHECK # ############################## input_params = parameters.get_dict() # = Preparation of input data ============================ input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(input_filename, 'w') as infile: # Here print keys and values to file for k, v in sorted(input_params.iteritems()): infile.write(get_input_data_text(k, v)) # = Additional files ===================================== # Create the subfolder that will contain Gollum files tempfolder.get_subfolder(self._GFILES_SUBFOLDER, create=True) # Create the subfolder with the output data tempfolder.get_subfolder(self._OUTPUT_SUBFOLDER, create=True) if singlefile is not None: lfile = singlefile.get_file_abs_path().split("path/", 1)[1] local_copy_list.append((singlefile.get_file_abs_path(), os.path.join(self._GFILES_SUBFOLDER, lfile))) settings_local_copy_list = settings_dict.pop( 'ADDITIONAL_LOCAL_COPY_LIST', []) if settings_local_copy_list is not None: for k in settings_local_copy_list: lfile = k.split("/") lf = './' + lfile[len(lfile) - 1] local_copy_list.append((unicode(k), unicode(lf))) # = Parent calculation folder ============================ # The presence of a 'parent_calc_folder' input node signals # that we want to get something from there, as indicated in the # self._restart_copy_from attribute. In Gollum, partial.mat # # It will be copied to the current calculation's working folder if parent_calc_folder is not None: remote_copy_list.append( (parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), self._restart_copy_from), self._restart_copy_to)) # = Calculation information and parameters =============== calcinfo = CalcInfo() calcinfo.uuid = self.uuid cmdline_params = settings_dict.pop('CMDLINE', []) if cmdline_params: calcinfo.cmdline_params = list(cmdline_params) calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = remote_copy_list calcinfo.stdin_name = self._INPUT_FILE_NAME calcinfo.stdout_name = self._OUTPUT_FILE_NAME calcinfo.messages_name = self._MESSAGES_FILE_NAME calcinfo.oc_name = self._OC_FILE_NAME calcinfo.ou_name = self._OU_FILE_NAME calcinfo.od_name = self._OD_FILE_NAME calcinfo.tt_name = self._TT_FILE_NAME calcinfo.tu_name = self._TU_FILE_NAME calcinfo.td_name = self._TD_FILE_NAME # = Code information object ============================== codeinfo = CodeInfo() #codeinfo.cmdline_params = list(cmdline_params) codeinfo.cmdline_params = [cmdline_params] #codeinfo.stdin_name = self._INPUT_FILE_NAME codeinfo.stdout_name = self._OUTPUT_FILE_NAME codeinfo.messages_name = self._MESSAGES_FILE_NAME codeinfo.oc_name = self._OC_FILE_NAME codeinfo.ou_name = self._OU_FILE_NAME codeinfo.od_name = self._OD_FILE_NAME codeinfo.tt_name = self._TT_FILE_NAME codeinfo.tu_name = self._TU_FILE_NAME codeinfo.td_name = self._TD_FILE_NAME codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] # = Retrieve files ======================================= # Retrieve by default: the output file calcinfo.retrieve_list = [] calcinfo.retrieve_list.append(self._OUTPUT_FILE_NAME) calcinfo.retrieve_list.append(self._MESSAGES_FILE_NAME) calcinfo.retrieve_list.append(self._OC_FILE_NAME) calcinfo.retrieve_list.append(self._OU_FILE_NAME) calcinfo.retrieve_list.append(self._OD_FILE_NAME) calcinfo.retrieve_list.append(self._TT_FILE_NAME) calcinfo.retrieve_list.append(self._TU_FILE_NAME) calcinfo.retrieve_list.append(self._TD_FILE_NAME) # Any other files specified in the settings dictionary settings_retrieve_list = settings_dict.pop('ADDITIONAL_RETRIEVE_LIST', []) calcinfo.retrieve_list += settings_retrieve_list # = Copy additional remote files ========================= # Additional remote copy list for files like the EM or leads settings_remote_copy_list = settings_dict.pop( 'ADDITIONAL_REMOTE_COPY_LIST', []) calcinfo.remote_copy_list += settings_remote_copy_list if settings_remote_copy_list and parent_calc_folder is None: raise ValueError("The definition of a parent calculation folder " "is also needed when there is a remote copy list") for src_relative, dest_relative in settings_remote_copy_list: calcinfo.remote_copy_list.append([ parent_calc_folder.get_computer().uuid, src_relative, dest_relative ]) return calcinfo