def _generate_NEBinputdata(self, neb_parameters, settings_dict): """ This methods generate the input data for the NEB part of the calculation """ # I put the first-level keys as uppercase (i.e., namelist and card names) # and the second-level keys as lowercase # (deeper levels are unchanged) input_params = _uppercase_dict(neb_parameters.get_dict(), dict_name='parameters') input_params = { k: _lowercase_dict(v, dict_name=k) for k, v in input_params.iteritems() } # For the neb input there is no blocked keyword # Create an empty dictionary for the compulsory namelist 'PATH' # if not present if 'PATH' not in input_params: input_params['PATH'] = {} # In case of climbing image, we need the corresponding card climbing_image = False if input_params['PATH'].get('ci_scheme', 'no-ci').lower() in ['manual']: climbing_image = True try: climbing_image_list = settings_dict.pop("CLIMBING_IMAGES") except KeyError: raise InputValidationError( "No climbing image specified for this calculation") if not isinstance(climbing_image_list, list): raise InputValidationError( "Climbing images should be provided as a list") if [ i for i in climbing_image_list if i < 2 or i >= input_params['PATH'].get('num_of_images', 2) ]: raise InputValidationError( "The climbing images should be in the range between the first " "and the last image") climbing_image_card = "CLIMBING_IMAGES\n" climbing_image_card += ", ".join( [str(_) for _ in climbing_image_list]) + "\n" inputfile = "" inputfile += "&PATH\n" # namelist content; set to {} if not present, so that we leave an # empty namelist namelist = input_params.pop('PATH', {}) for k, v in sorted(namelist.iteritems()): inputfile += get_input_data_text(k, v) inputfile += "/\n" # Write cards now if climbing_image: inputfile += climbing_image_card if input_params: raise InputValidationError( "The following namelists are specified in input_params, but are " "not valid namelists for the current type of calculation: " "{}".format(",".join(input_params.keys()))) return inputfile
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!) """ try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError("No code specified for this calculation") 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: qpoints = inputdict.pop(self.get_linkname('qpoints')) except KeyError: raise InputValidationError("No qpoints specified for this calculation") if not isinstance(qpoints, KpointsData): raise InputValidationError("qpoints is not of type KpointsData") # Settings can be undefined, and defaults to an empty dictionary. # They will be used for any input that doen't fit elsewhere. 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') parent_calc_folder = inputdict.pop(self.get_linkname('parent_folder'),None) if parent_calc_folder is None: raise InputValidationError("No parent calculation found, needed to " "compute phonons") # TODO: to be a PwCalculation is not sufficient: it could also be a nscf # calculation that is invalid for phonons if not isinstance(parent_calc_folder, RemoteData): raise InputValidationError("parent_calc_folder, if specified," "must be of type RemoteData") restart_flag = False # extract parent calculation parent_calcs = parent_calc_folder.get_inputs(node_type=JobCalculation) n_parents = len(parent_calcs) if n_parents != 1: raise UniquenessError("Input RemoteData is child of {} " "calculation{}, while it should have " "a single parent".format(n_parents, "" if n_parents==0 else "s")) parent_calc = parent_calcs[0] # check that it is a valid parent self._check_valid_parent(parent_calc) if not isinstance(parent_calc, PwCalculation): restart_flag = True # Also, the parent calculation must be on the same computer new_comp = self.get_computer() old_comp = parent_calc.get_computer() if ( not new_comp.uuid == old_comp.uuid ): raise InputValidationError("PhCalculation must be launched on the same computer" " of the parent: {}".format(old_comp.get_name())) # put by default, default_parent_output_folder = ./out try: default_parent_output_folder = parent_calc._OUTPUT_SUBFOLDER except AttributeError: try: default_parent_output_folder = parent_calc._get_output_folder() except AttributeError: raise InputValidationError("Parent of PhCalculation does not " "have a default output subfolder") #os.path.join( # parent_calc.OUTPUT_SUBFOLDER, # '{}.save'.format(parent_calc.PREFIX)) parent_calc_out_subfolder = settings_dict.pop('PARENT_CALC_OUT_SUBFOLDER', default_parent_output_folder) # Here, there should be no other inputs if inputdict: raise InputValidationError("The following input data nodes are " "unrecognized: {}".format(inputdict.keys())) ############################## # END OF INITIAL INPUT CHECK # ############################## # I put the first-level keys as uppercase (i.e., namelist and card names) # and the second-level keys as lowercase # (deeper levels are unchanged) input_params = _uppercase_dict(parameters.get_dict(), dict_name='parameters') input_params = {k: _lowercase_dict(v, dict_name=k) for k, v in input_params.iteritems()} prepare_for_d3 = settings_dict.pop('PREPARE_FOR_D3',False) if prepare_for_d3: self._blocked_keywords += [('INPUTPH', 'fildrho'), ('INPUTPH', 'drho_star%open'), ('INPUTPH', 'drho_star%ext'), ('INPUTPH', 'drho_star%dir')] # I remove unwanted elements (for the moment, instead, I stop; to change when # we setup a reasonable logging) for nl, flag in self._blocked_keywords: if nl in input_params: if flag in input_params[nl]: raise InputValidationError( "You cannot specify explicitly the '{}' flag in the '{}' " "namelist or card.".format(flag, nl)) # Set some variables (look out at the case! NAMELISTS should be uppercase, # internal flag names must be lowercase) if 'INPUTPH' not in input_params: raise InputValidationError("No namelist INPUTPH found in input") # I cannot decide what to do in the calculation input_params['INPUTPH']['outdir'] = self._OUTPUT_SUBFOLDER input_params['INPUTPH']['iverbosity'] = 1 # in human language 1=high input_params['INPUTPH']['prefix'] = self._PREFIX input_params['INPUTPH']['fildyn'] = self._OUTPUT_DYNAMICAL_MATRIX_PREFIX if prepare_for_d3: input_params['INPUTPH']['fildrho'] = self._DRHO_PREFIX input_params['INPUTPH']['drho_star%open'] = True input_params['INPUTPH']['drho_star%ext'] = self._DRHO_STAR_EXT input_params['INPUTPH']['drho_star%dir'] = self._FOLDER_DRHO # qpoints part try: mesh,offset = qpoints.get_kpoints_mesh() if any([i!=0. for i in offset]): raise NotImplementedError("Computation of phonons on a mesh with" " non zero offset is not implemented, at the level of ph.x") input_params["INPUTPH"]["ldisp"] = True input_params["INPUTPH"]["nq1"] = mesh[0] input_params["INPUTPH"]["nq2"] = mesh[1] input_params["INPUTPH"]["nq3"] = mesh[2] postpend_text = None except AttributeError: # this is the case where no mesh was set. Maybe it's a list try: list_of_points = qpoints.get_kpoints(cartesian=True) except AttributeError as e: # In this case, there are no info on the qpoints at all raise InputValidationError("Neither a qpoints mesh or a valid " "list of qpoints was found in input", e.message) # change to 2pi/a coordinates lattice_parameter = numpy.linalg.norm(qpoints.cell[0]) list_of_points *= lattice_parameter / (2.*numpy.pi) # add here the list of point coordinates if len(list_of_points)>1: input_params["INPUTPH"]["qplot"] = True input_params["INPUTPH"]["ldisp"] = True postpend_text = "{}\n".format(len(list_of_points)) for points in list_of_points: postpend_text += "{} {} {} 1\n".format(*points) # Note: the weight is fixed to 1, because ph.x calls these # things weights but they are not such. If they are going to # exist with the meaning of weights, they will be supported else: input_params["INPUTPH"]["ldisp"] = False postpend_text = "" for points in list_of_points: postpend_text += "{} {} {}\n".format(*points) # =================== NAMELISTS ======================== # customized namelists, otherwise not present in the distributed ph code try: namelists_toprint = settings_dict.pop('NAMELISTS') if not isinstance(namelists_toprint, list): raise InputValidationError( "The 'NAMELISTS' value, if specified in the settings input " "node, must be a list of strings") except KeyError: # list of namelists not specified in the settings; do automatic detection namelists_toprint = self._compulsory_namelists input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) # create a folder for the dynamical matrices if not restart_flag: # if it is a restart, it will be copied over tempfolder.get_subfolder(self._FOLDER_DYNAMICAL_MATRIX, create=True) with open(input_filename,'w') as infile: infile.write('AiiDA calculation\n') for namelist_name in namelists_toprint: infile.write("&{0}\n".format(namelist_name)) # namelist content; set to {} if not present, so that we leave an # empty namelist namelist = input_params.pop(namelist_name,{}) for k, v in sorted(namelist.iteritems()): infile.write(get_input_data_text(k,v)) infile.write("/\n") # add list of qpoints if required if postpend_text is not None: infile.write(postpend_text) #TODO: write nat_todo if input_params: raise InputValidationError( "The following namelists are specified in input_params, but are " "not valid namelists for the current type of calculation: " "{}".format(",".join(input_params.keys()))) # copy the parent scratch symlink = settings_dict.pop('PARENT_FOLDER_SYMLINK', _default_symlink_usage) # a boolean if symlink: # I create a symlink to each file/folder in the parent ./out tempfolder.get_subfolder(self._OUTPUT_SUBFOLDER, create=True) remote_symlink_list.append( (parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), parent_calc_out_subfolder, "*"), self._OUTPUT_SUBFOLDER ) ) # I also create a symlink for the ./pseudo folder # TODO: suppress this when the recover option of QE will be fixed # (bug when trying to find pseudo file) remote_symlink_list.append((parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), self._get_pseudo_folder()), self._get_pseudo_folder() )) #pass else: # here I copy the whole folder ./out remote_copy_list.append( (parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), parent_calc_out_subfolder), self._OUTPUT_SUBFOLDER)) # I also copy the ./pseudo folder # TODO: suppress this when the recover option of QE will be fixed # (bug when trying to find pseudo file) remote_copy_list.append( (parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), self._get_pseudo_folder()), self._get_pseudo_folder())) if restart_flag: # in this case, copy in addition also the dynamical matrices if symlink: remote_symlink_list.append( (parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), self._FOLDER_DYNAMICAL_MATRIX), self._FOLDER_DYNAMICAL_MATRIX)) else: # copy the dynamical matrices remote_copy_list.append( (parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), self._FOLDER_DYNAMICAL_MATRIX), '.')) # no need to copy the _ph0, since I copied already the whole ./out folder # 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') calcinfo = CalcInfo() calcinfo.uuid = self.uuid # Empty command line by default 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 codeinfo = CodeInfo() codeinfo.cmdline_params = (list(cmdline_params) + ["-in", 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 xml file calcinfo.retrieve_list = [] calcinfo.retrieve_list.append(self._OUTPUT_FILE_NAME) calcinfo.retrieve_list.append(self._FOLDER_DYNAMICAL_MATRIX) calcinfo.retrieve_list.append( os.path.join(self._OUTPUT_SUBFOLDER, '_ph0', '{}.phsave'.format(self._PREFIX), self._OUTPUT_XML_TENSOR_FILE_NAME)) extra_retrieved = settings_dict.pop('ADDITIONAL_RETRIEVE_LIST', []) for extra in extra_retrieved: calcinfo.retrieve_list.append( extra ) 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 = [] 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") # 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') parent_calc_folder = inputdict.pop(self.get_linkname('parent_folder'), None) if parent_calc_folder is not None: if not isinstance(parent_calc_folder, self._parent_folder_type): if not isinstance(self._parent_folder_type, tuple): possible_types = [self._parent_folder_type.__name__] else: possible_types = [ t.__name__ for t in self._parent_folder_type ] raise InputValidationError("parent_calc_folder, if specified," "must be of type {}".format( " or ".join(possible_types))) following_text = self._get_following_text(inputdict, settings) # 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 # ############################## # I put the first-level keys as uppercase (i.e., namelist and card names) # and the second-level keys as lowercase # (deeper levels are unchanged) input_params = _uppercase_dict(parameters.get_dict(), dict_name='parameters') input_params = { k: _lowercase_dict(v, dict_name=k) for k, v in input_params.iteritems() } # set default values. NOTE: this is different from PW/CP for blocked in self._blocked_keywords: namelist = blocked[0].upper() key = blocked[1].lower() value = blocked[2] if namelist in input_params: if key in input_params[namelist]: raise InputValidationError( "You cannot specify explicitly the '{}' key in the '{}' " "namelist.".format(key, namelist)) # set to a default if not input_params[namelist]: input_params[namelist] = {} input_params[namelist][key] = value # =================== NAMELISTS AND CARDS ======================== try: namelists_toprint = settings_dict.pop('NAMELISTS') if not isinstance(namelists_toprint, list): raise InputValidationError( "The 'NAMELISTS' value, if specified in the settings input " "node, must be a list of strings") except KeyError: # list of namelists not specified; do automatic detection namelists_toprint = self._default_namelists input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) with open(input_filename, 'w') as infile: for namelist_name in namelists_toprint: infile.write("&{0}\n".format(namelist_name)) # namelist content; set to {} if not present, so that we leave an # empty namelist namelist = input_params.pop(namelist_name, {}) for k, v in sorted(namelist.iteritems()): infile.write(get_input_data_text(k, v)) infile.write("/\n") # Write remaning text now, if any infile.write(following_text) # Check for specified namelists that are not expected if input_params: raise InputValidationError( "The following namelists are specified in input_params, but are " "not valid namelists for the current type of calculation: " "{}".format(",".join(input_params.keys()))) # copy remote output dir, if specified if parent_calc_folder is not None: if isinstance(parent_calc_folder, RemoteData): parent_calc_out_subfolder = settings_dict.pop( 'PARENT_CALC_OUT_SUBFOLDER', self._INPUT_SUBFOLDER) remote_copy_list.append( (parent_calc_folder.get_computer().uuid, os.path.join(parent_calc_folder.get_remote_path(), parent_calc_out_subfolder), self._OUTPUT_SUBFOLDER)) elif isinstance(parent_calc_folder, FolderData): local_copy_list.append( (parent_calc_folder.get_abs_path(self._INPUT_SUBFOLDER), self._OUTPUT_SUBFOLDER)) elif isinstance(parent_calc_folder, SinglefileData): filename = parent_calc_folder.get_file_abs_path() local_copy_list.append((filename, os.path.basename(filename))) calcinfo = CalcInfo() calcinfo.uuid = self.uuid # Empty command line by default calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = remote_copy_list codeinfo = CodeInfo() codeinfo.cmdline_params = settings_dict.pop('CMDLINE', []) 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 xml file calcinfo.retrieve_list = [] calcinfo.retrieve_list.append(self._OUTPUT_FILE_NAME) settings_retrieve_list = settings_dict.pop('ADDITIONAL_RETRIEVE_LIST', []) calcinfo.retrieve_list += settings_retrieve_list calcinfo.retrieve_list += self._internal_retrieve_list calcinfo.retrieve_singlefile_list = self._retrieve_singlefile_list if settings_dict: 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, or it is set to None raise InputValidationError( "The following keys have been found in " "the settings input node, but were not understood: {}". format(",".join(settings_dict.keys()))) return calcinfo