def test_check_2Dinput_consistency(self): from aiida_kkr.tools.common_workfunctions import check_2Dinput_consistency from aiida.orm import DataFactory StructureData = DataFactory('structure') ParameterData = DataFactory('parameter') s = StructureData(cell=[[0.5, 0.5, 0], [1, 0, 0], [0, 0, 1]]) s.append_atom(position=[0, 0, 0], symbols='Fe') p = ParameterData(dict={'INTERFACE': True}) input_check = check_2Dinput_consistency(s, p) assert input_check[0] assert input_check[1] == '2D consistency check complete'
def test_check_2Dinput_consistency_1(self): # case 1: 3D structure and no 2D params input from aiida_kkr.tools.common_workfunctions import check_2Dinput_consistency from aiida.plugins import DataFactory StructureData = DataFactory('structure') Dict = DataFactory('dict') s = StructureData(cell=[[0.5, 0.5, 0], [1,0,0], [0,0,1]]) s.append_atom(position=[0,0,0], symbols='Fe') p = Dict(dict={'INTERFACE':False}) input_check = check_2Dinput_consistency(s, p) assert input_check[0] assert input_check[1] == '2D consistency check complete'
def test_check_2Dinput_consistency_3(self): # case 3: 2D structure but incomplete 2D input parameters given from aiida_kkr.tools.common_workfunctions import check_2Dinput_consistency from aiida.plugins import DataFactory StructureData = DataFactory('structure') Dict = DataFactory('dict') s = StructureData(cell=[[0.5, 0.5, 0], [1,0,0], [0,0,1]]) s.append_atom(position=[0,0,0], symbols='Fe') s.set_pbc((True, True, False)) p = Dict(dict={'INTERFACE':True, '<NRBASIS>':1,}) input_check = check_2Dinput_consistency(s, p) assert not input_check[0] assert input_check[1] == "2D info given in parameters but structure is 3D\nstructure is 2D? {}\ninput has 2D info? {}\nset keys are: {}".format(True, False, ['INTERFACE', '<NRBASIS>'])
def test_check_2Dinput_consistency_2(self): # case 2: 2D structure and 2D params input from aiida_kkr.tools.common_workfunctions import check_2Dinput_consistency from aiida.plugins import DataFactory StructureData = DataFactory('structure') Dict = DataFactory('dict') s = StructureData(cell=[[0.5, 0.5, 0], [1,0,0], [0,0,1]]) s.append_atom(position=[0,0,0], symbols='Fe') s.set_pbc((True, True, False)) p = Dict(dict={'INTERFACE':True, '<NRBASIS>':1, '<RBLEFT>':[0,0,0], '<RBRIGHT>':[0,0,0], 'ZPERIODL':[0,0,0], 'ZPERIODR':[0,0,0], '<NLBASIS>':1}) input_check = check_2Dinput_consistency(s, p) assert input_check[0] assert input_check[1] == "2D consistency check complete"
def test_check_2Dinput_consistency_5(self): # case 5: 3D structure but 2D params given from aiida_kkr.tools.common_workfunctions import check_2Dinput_consistency from aiida.plugins import DataFactory StructureData = DataFactory('structure') Dict = DataFactory('dict') s = StructureData(cell=[[0.5, 0.5, 0], [1,0,0], [0,0,1]]) s.append_atom(position=[0,0,0], symbols='Fe') s.set_pbc((True, True, True)) p = Dict(dict={'INTERFACE':True, '<NRBASIS>':1, '<RBLEFT>':[0,0,0], '<RBRIGHT>':[0,0,0], 'ZPERIODL':[0,0,0], 'ZPERIODR':[0,0,0], '<NLBASIS>':1}) input_check = check_2Dinput_consistency(s, p) assert not input_check[0] assert list(input_check[1]).sort() == list("3D info given in parameters but structure is 2D\nstructure is 2D? {}\ninput has 2D info? {}\nset keys are: {}".format(False, True, ['ZPERIODL', '<NRBASIS>', '<RBLEFT>', 'INTERFACE', '<NLBASIS>', 'ZPERIODR', '<RBRIGHT>'])).sort()
def _prepare_for_submission(self, tempfolder, inputdict): """ Create input files. :param tempfolder: aiida.common.folders.Folder subclass where the plugin should put all its files. :param inputdict: dictionary of the input nodes as they would be returned by get_inputs_dict """ has_parent = False local_copy_list = [] # Check inputdict 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 not of type ParameterData") try: imp_info = inputdict.pop(self.get_linkname('impurity_info')) found_imp_info = True except KeyError: imp_info = None found_imp_info = False if found_imp_info and not isinstance(imp_info, ParameterData): raise InputValidationError( "impurity_info not of type ParameterData") try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError( "No code specified for this calculation") # get qdos inputs try: kpath = inputdict.pop(self.get_linkname('kpoints')) found_kpath = True except KeyError: found_kpath = False try: parent_calc_folder = inputdict.pop( self.get_linkname('parent_folder')) except KeyError: raise InputValidationError( "Voronoi or previous KKR files needed for KKR calculation, " "you need to provide a Parent Folder/RemoteData node.") #TODO deal with data from folder data if calculation is continued on a different machine if not isinstance(parent_calc_folder, RemoteData): raise InputValidationError( "parent_calc_folder must be of type RemoteData") # 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] has_parent = True if n_parents == 1: parent_calc = parent_calcs[0] has_parent = True # check if parent is either Voronoi or previous KKR calculation self._check_valid_parent(parent_calc) # extract parent input parameter dict for following check try: parent_inp_dict = parent_calc.inp.parameters.get_dict() except: self.logger.error( "Failed trying to find input parameter of parent {}".format( parent_calc)) raise InputValidationError( "No parameter node found of parent calculation.") # check if no keys are illegally overwritten (i.e. compare with keys in self._do_never_modify) for key in parameters.get_dict().keys(): value = parameters.get_dict()[key] #self.logger.info("Checking {} {}".format(key, value)) if not value is None: if key in self._do_never_modify: oldvalue = parent_inp_dict[key] if oldvalue is None and key in __kkr_default_params__: oldvalue = __kkr_default_params__.get(key) if value != oldvalue: self.logger.error( "You are trying to set keyword {} = {} but this is not allowed since the structure would be modified. Please use a suitable workfunction instead." .format(key, value)) raise InputValidationError( "You are trying to modify a keyword that is not allowed to be changed! (key={}, oldvalue={}, newvalue={})" .format(key, oldvalue, value)) #TODO check for remote folder (starting from folder data not implemented yet) # if voronoi calc check if folder from db given, or get folder from rep. # Parent calc does not has to be on the same computer. # so far we copy every thing from local computer ggf if kkr we want to copy remotely # get StructureData node from Parent if Voronoi structure = None self.logger.info( "KkrCalculation: Get structure node from voronoi parent") if isinstance(parent_calc, VoronoiCalculation): self.logger.info("KkrCalculation: Parent is Voronoi calculation") try: structure, voro_parent = VoronoiCalculation.find_parent_structure( parent_calc) except: self.logger.error( 'KkrCalculation: Could not get structure from Voronoi parent.' ) raise ValidationError("Cound not find structure node") elif isinstance(parent_calc, KkrCalculation): self.logger.info("KkrCalculation: Parent is KKR calculation") try: self.logger.info( 'KkrCalculation: extract structure from KKR parent') structure, voro_parent = VoronoiCalculation.find_parent_structure( parent_calc) except: self.logger.error('Could not get structure from parent.') raise ValidationError( 'Cound not find structure node starting from parent {}'. format(parent_calc)) else: self.logger.error( "KkrCalculation: Parent is neither Voronoi nor KKR calculation!" ) raise ValidationError('Cound not find structure node') if inputdict: self.logger.error( 'KkrCalculation: Unknown inputs for structure lookup') raise ValidationError("Unknown inputs") # for VCA: check if input structure and parameter node define VCA structure vca_structure = vca_check(structure, parameters) ################################### # prepare scoef file if impurity_info was given write_scoef = False runopt = parameters.get_dict().get('RUNOPT', None) kkrflex_opt = False if runopt is not None: if 'KKRFLEX' in runopt: kkrflex_opt = True if kkrflex_opt: write_scoef = True elif found_imp_info: self.logger.info( 'Found impurity_info in inputs of the calculation, automatically add runopt KKRFLEX' ) write_scoef = True runopt = parameters.get_dict().get('RUNOPT', []) runopt.append('KKRFLEX') parameters = update_params_wf( parameters, ParameterData( dict={ 'RUNOPT': runopt, 'nodename': 'update_KKRFLEX', 'nodedesc': 'Update Parameter node with KKRFLEX runopt' })) if found_imp_info and write_scoef: scoef_filename = os.path.join(tempfolder.get_abs_path(''), self._SCOEF) imp_info_dict = imp_info.get_dict() Rcut = imp_info_dict.get('Rcut', None) hcut = imp_info_dict.get('hcut', -1.) cylinder_orient = imp_info_dict.get('cylinder_orient', [0., 0., 1.]) ilayer_center = imp_info_dict.get('ilayer_center', 0) for i in range(len(cylinder_orient)): try: len(cylinder_orient[i]) vec_shape = False except TypeError: vec_shape = True if ilayer_center > len(structure.sites) - 1: raise IndexError( 'Index of the reference site is out of range! Possible values: 0 to {}.' .format(len(structure.sites) - 1)) elif Rcut < 0: raise ValueError('Cutoff radius has to be positive!') elif vec_shape == False or len(cylinder_orient) != 3: raise TypeError( 'Input orientation vector ({}) has the wrong shape! It needs to be a 3D-vector!' .format(cylinder_orient)) else: print('Input parameters for make_scoef read in correctly!') make_scoef(structure, Rcut, scoef_filename, hcut, cylinder_orient, ilayer_center) elif write_scoef: self.logger.info( 'Need to write scoef file but no impurity_info given!') raise ValidationError( 'Found RUNOPT KKRFLEX but no impurity_info in inputs') # Check for 2D case twoDimcheck, msg = check_2Dinput_consistency(structure, parameters) if not twoDimcheck: raise InputValidationError(msg) # set shapes array either from parent voronoi run or read from inputcard in kkrimporter calculation if parent_calc.get_parser_name() != 'kkr.kkrimporterparser': # get shapes array from voronoi parent shapes = voro_parent.res.shapes else: # extract shapes from input parameters node constructed by kkrimporter calculation shapes = voro_parent.inp.parameters.get_dict().get('<SHAPE>') # use_alat_input = parameters.get_dict().get('use_input_alat', False) # qdos option, ensure low T, E-contour, qdos run option and write qvec.dat file if found_kpath: # check qdos settings change_values = [] runopt = parameters.get_dict().get('RUNOPT') if runopt is None: runopt = [] runopt = [i.strip() for i in runopt] if 'qdos' not in runopt: runopt.append('qdos') change_values.append(['RUNOPT', runopt]) tempr = parameters.get_dict().get('TEMPR') if tempr is None or tempr > 100.: change_values.append(['TEMPR', 50.]) N1 = parameters.get_dict().get('TEMPR') if N1 is None or N1 > 0: change_values.append(['NPT1', 0]) N2 = parameters.get_dict().get('NPT2') if N2 is None: change_values.append(['NPT2', 100]) N3 = parameters.get_dict().get('NPT3') if N3 is None or N3 > 0.: change_values.append(['NPT3', 0]) NPOL = parameters.get_dict().get('NPOL') if NPOL is None or NPOL > 0.: change_values.append(['NPOL', 0]) if change_values != []: new_params = { 'nodename': 'changed_params_qdos', 'nodedesc': 'Changed parameters to mathc qdos mode. Changed values: {}' .format(change_values) } for key, val in change_values: new_params[key] = val new_params_node = ParameterData(dict=new_params) parameters = update_params_wf(parameters, new_params_node) # write qvec.dat file kpath_array = kpath.get_kpoints() # convert automatically to internal units if use_alat_input: alat = parameters.get_dict().get('ALATBASIS') else: alat = get_alat_from_bravais( array(structure.cell), is3D=structure.pbc[2]) * get_Ang2aBohr() kpath_array = kpath_array * (alat / 2. / pi) qvec = ['%i\n' % len(kpath_array)] qvec += [ '%e %e %e\n' % (kpt[0], kpt[1], kpt[2]) for kpt in kpath_array ] qvecpath = tempfolder.get_abs_path(self._QVEC) with open(qvecpath, 'w') as file: file.writelines(qvec) # Prepare inputcard from Structure and input parameter data input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) natom, nspin, newsosol = generate_inputcard_from_structure( parameters, structure, input_filename, parent_calc, shapes=shapes, vca_structure=vca_structure, use_input_alat=use_alat_input) ################# # Decide what files to copy based on settings to the code (e.g. KKRFLEX option needs scoef) if has_parent: # copy the right files #TODO check first if file, exists and throw # warning, now this will throw an error outfolderpath = parent_calc.out.retrieved.folder.abspath outfolderpath = os.path.join(outfolderpath, 'path') self.logger.info("out folder path {}".format(outfolderpath)) copylist = [] if isinstance(parent_calc, KkrCalculation): copylist = self._copy_filelist_kkr # TODO ggf copy remotely... if isinstance(parent_calc, VoronoiCalculation): copylist = [parent_calc._SHAPEFUN] # copy either overwrite potential or voronoi output potential # (voronoi caclualtion retreives only one of the two) if parent_calc._POTENTIAL_IN_OVERWRITE in os.listdir( outfolderpath): copylist.append(parent_calc._POTENTIAL_IN_OVERWRITE) else: copylist.append(parent_calc._OUT_POTENTIAL_voronoi) #change copylist in case the calculation starts from an imported calculation if parent_calc.get_parser_name() == 'kkr.kkrimporterparser': copylist = [] if not os.path.exists( os.path.join(outfolderpath, self._OUT_POTENTIAL)): copylist.append(self._POTENTIAL) else: copylist.append(self._OUT_POTENTIAL) if os.path.exists(os.path.join(outfolderpath, self._SHAPEFUN)): copylist.append(self._SHAPEFUN) # create local_copy_list from copylist and change some names automatically for file1 in copylist: filename = file1 if (file1 == 'output.pot' or file1 == self._OUT_POTENTIAL or (isinstance(parent_calc, VoronoiCalculation) and file1 == parent_calc._POTENTIAL_IN_OVERWRITE)): filename = self._POTENTIAL local_copy_list.append( (os.path.join(outfolderpath, file1), os.path.join(filename))) # for set-ef option: ef_set = parameters.get_dict().get('ef_set', None) if ef_set is not None: print('local copy list before change: {}'.format( local_copy_list)) print( "found 'ef_set' in parameters: change EF of potential to this value" ) potcopy_info = [ i for i in local_copy_list if i[1] == self._POTENTIAL ][0] with open(potcopy_info[0]) as file: # change potential and copy list local_copy_list.remove(potcopy_info) pot_new_name = tempfolder.get_abs_path(self._POTENTIAL + '_new_ef') local_copy_list.append((pot_new_name, self._POTENTIAL)) # change potential txt = file.readlines() potstart = [] for iline in range(len(txt)): line = txt[iline] if 'exc:' in line: potstart.append(iline) for ipotstart in potstart: tmpline = txt[ipotstart + 3] tmpline = tmpline.split() newline = '%10.5f%20.14f%20.14f\n' % (float( tmpline[0]), ef_set, float(tmpline[-1])) txt[ipotstart + 3] = newline # write new file pot_new_ef = open(pot_new_name, 'w') pot_new_ef.writelines(txt) pot_new_ef.close() # TODO different copy lists, depending on the keywors input print('local copy list: {}'.format(local_copy_list)) self.logger.info('local copy list: {}'.format(local_copy_list)) # Prepare CalcInfo to be returned to aiida calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = [] # TODO retrieve list needs some logic, retrieve certain files, # only if certain input keys are specified.... calcinfo.retrieve_list = [ self._DEFAULT_OUTPUT_FILE, self._INPUT_FILE_NAME, self._POTENTIAL, self._SHAPEFUN, self._SCOEF, self._NONCO_ANGLES_OUT, self._OUT_POTENTIAL, self._OUTPUT_0_INIT, self._OUTPUT_000, self._OUTPUT_2, self._OUT_TIMING_000 ] # for special cases add files to retireve list: # 1. dos calculation, add *dos* files if NPOL==0 retrieve_dos_files = False print('NPOL in parameter input:', parameters.get_dict()['NPOL']) if 'NPOL' in parameters.get_dict().keys(): if parameters.get_dict()['NPOL'] == 0: retrieve_dos_files = True if 'TESTOPT' in parameters.get_dict().keys(): testopts = parameters.get_dict()['TESTOPT'] if testopts is not None: stripped_test_opts = [i.strip() for i in testopts] if 'DOS' in stripped_test_opts: retrieve_dos_files = True if retrieve_dos_files: print('adding files for dos output', self._COMPLEXDOS, self._DOS_ATOM, self._LMDOS) add_files = [self._COMPLEXDOS] for iatom in range(natom): add_files.append(self._DOS_ATOM % (iatom + 1)) for ispin in range(nspin): add_files.append( (self._LMDOS % (iatom + 1, ispin + 1)).replace( ' ', '0')) calcinfo.retrieve_list += add_files # 2. KKRFLEX calculation retrieve_kkrflex_files = False if 'RUNOPT' in parameters.get_dict().keys(): runopts = parameters.get_dict()['RUNOPT'] if runopts is not None: stripped_run_opts = [i.strip() for i in runopts] if 'KKRFLEX' in stripped_run_opts: retrieve_kkrflex_files = True if retrieve_kkrflex_files: add_files = self._ALL_KKRFLEX_FILES print('adding files for KKRFLEX output', add_files) calcinfo.retrieve_list += add_files # 3. qdos claculation retrieve_qdos_files = False if 'RUNOPT' in parameters.get_dict().keys(): runopts = parameters.get_dict()['RUNOPT'] if runopts is not None: stripped_run_opts = [i.strip() for i in runopts] if 'qdos' in stripped_run_opts: retrieve_qdos_files = True if retrieve_qdos_files: print('adding files for qdos output', self._QDOS_ATOM, self._QVEC) add_files = [self._QVEC] for iatom in range(natom): for ispin in range(nspin): add_files.append( (self._QDOS_ATOM % (iatom + 1, ispin + 1)).replace( ' ', '0')) calcinfo.retrieve_list += add_files codeinfo = CodeInfo() codeinfo.cmdline_params = [] codeinfo.code_uuid = code.uuid codeinfo.stdout_name = self._DEFAULT_OUTPUT_FILE calcinfo.codes_info = [codeinfo] return calcinfo
def _prepare_for_submission(self, tempfolder, inputdict): """ Create input files. :param tempfolder: aiida.common.folders.Folder subclass where the plugin should put all its files. :param inputdict: dictionary of the input nodes as they would be returned by get_inputs_dict """ # Check inputdict 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 not of type " "ParameterData") try: structure = inputdict.pop(self.get_linkname('structure')) found_structure = True except KeyError: found_structure = False vca_structure = False if found_structure: if not isinstance(structure, StructureData): raise InputValidationError("structure not of type " "StructureData") # for VCA: check if input structure and parameter node define VCA structure vca_structure = vca_check(structure, parameters) try: code = inputdict.pop(self.get_linkname('code')) except KeyError: raise InputValidationError("No code specified for this " "calculation") # check if a parent folder containing a potential file (out_potential) is given try: parent_calc_folder = inputdict.pop(self.get_linkname('parent_KKR')) found_parent = True except KeyError: found_parent = False if found_parent: if not isinstance(parent_calc_folder, RemoteData): raise InputValidationError( "parent_KKR must be of type RemoteData") # check if parent is either Voronoi or previous KKR calculation overwrite_potential, parent_calc = self._check_valid_parent( parent_calc_folder) #cross check if no structure was given and extract structure from parent if found_structure and not vca_structure: raise InputValidationError( "parent_KKR and structure found in input. " "Can only use either parent_KKR or structure in input.") else: structure_remote_KKR, voro_parent = self.find_parent_structure( parent_calc) if not vca_structure: structure = structure_remote_KKR else: # check consistency of input vca structure and structure from remote KKR folder # TODO check consistency pass else: overwrite_potential = False if not found_structure: raise InputValidationError( "Neither structure nor parent_KKR specified for this " "calculation") # check if overwrite potential is given explicitly try: potfile_overwrite = inputdict.pop( self.get_linkname('potential_overwrite')) has_potfile_overwrite = True except KeyError: has_potfile_overwrite = False if has_potfile_overwrite: overwrite_potential = True if not isinstance(potfile_overwrite, SingleFileData): raise InputValidationError( "potfile_overwrite must be of type SingleFileData") if not found_structure: raise InputValidationError( "Input structure needed for this calculation " "(using 'potential_overwrite' input node)") # finally check if something else was given as input (should not be the case) if inputdict: raise ValidationError("Unknown inputs: {}".format(inputdict)) ################################### # Check for 2D case twoDimcheck, msg = check_2Dinput_consistency(structure, parameters) if not twoDimcheck: raise InputValidationError(msg) # Prepare inputcard from Structure and input parameter data input_filename = tempfolder.get_abs_path(self._INPUT_FILE_NAME) try: use_alat_input = parameters.get_dict().get('use_input_alat', False) natom, nspin, newsosol = generate_inputcard_from_structure( parameters, structure, input_filename, isvoronoi=True, vca_structure=vca_structure, use_input_alat=use_alat_input) except ValueError as e: raise InputValidationError( "Input ParameterData not consistent: {}".format(e)) # Decide what files to copy local_copy_list = [] if overwrite_potential: # copy the right files #TODO check first if file, exists and throw # warning, now this will throw an error if found_parent and self._is_KkrCalc(parent_calc): outfolderpath = parent_calc.out.retrieved.folder.abspath self.logger.info("out folder path {}".format(outfolderpath)) filename = os.path.join(outfolderpath, 'path', parent_calc._OUT_POTENTIAL) copylist = [filename] elif has_potfile_overwrite: copylist = [potfile_overwrite.get_file_abs_path()] else: copylist = [] for file1 in copylist: filename = file1 if (found_parent or has_potfile_overwrite) and file1 == copylist[0]: filename = self._POTENTIAL_IN_OVERWRITE local_copy_list.append((file1, filename)) # Prepare CalcInfo to be returned to aiida calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = [] calcinfo.retrieve_list = [ self._OUTPUT_FILE_NAME, self._ATOMINFO, self._RADII, self._SHAPEFUN, self._VERTICES, self._INPUT_FILE_NAME ] # pass on overwrite potential if this was given in input # (KkrCalculation checks if this file is there and takes this file instead of _OUT_POTENTIAL_voronoi # if given) if overwrite_potential: calcinfo.retrieve_list += [self._POTENTIAL_IN_OVERWRITE] else: calcinfo.retrieve_list += [self._OUT_POTENTIAL_voronoi] codeinfo = CodeInfo() codeinfo.cmdline_params = [] codeinfo.stdout_name = self._OUTPUT_FILE_NAME codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] return calcinfo
def prepare_for_submission(self, tempfolder): """ Create input files. :param tempfolder: aiida.common.folders.Folder subclass where the plugin should put all its files. :param inputdict: dictionary of the input nodes as they would be returned by get_inputs_dict """ has_parent = False local_copy_list = [] # get mandatory input nodes parameters = self.inputs.parameters code = self.inputs.code parent_calc_folder = self.inputs.parent_folder # now check for optional nodes # for GF writeout if 'impurity_info' in self.inputs: imp_info = self.inputs.impurity_info found_imp_info = True else: imp_info = None found_imp_info = False # for qdos funcitonality if 'kpoints' in self.inputs: kpath = self.inputs.kpoints found_kpath = True else: found_kpath = False # extract parent calculation parent_calcs = parent_calc_folder.get_incoming(node_class=CalcJobNode) n_parents = len(parent_calcs.all_link_labels()) 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")) # TODO change to exit code if n_parents == 1: parent_calc = parent_calcs.first().node has_parent = True # check if parent is either Voronoi or previous KKR calculation #self._check_valid_parent(parent_calc) # extract parent input parameter dict for following check try: parent_inp_dict = parent_calc.inputs.parameters.get_dict() except: self.logger.error( "Failed trying to find input parameter of parent {}".format( parent_calc)) raise InputValidationError( "No parameter node found of parent calculation.") # check if no keys are illegally overwritten (i.e. compare with keys in self._do_never_modify) for key in list(parameters.get_dict().keys()): value = parameters.get_dict()[key] #self.logger.info("Checking {} {}".format(key, value)) if not value is None: if key in self._do_never_modify: oldvalue = parent_inp_dict[key] if oldvalue is None and key in __kkr_default_params__: oldvalue = __kkr_default_params__.get(key) if value == oldvalue: values_eqivalent = True else: values_eqivalent = False # check if values match up to certain numerical accuracy if type(value) == float: if abs(value - oldvalue) < self._eps: values_eqivalent = True elif type(value) == list or type(value) == ndarray: tmp_value, tmp_oldvalue = array(value).reshape( -1), array(oldvalue).reshape(-1) values_eqivalent_tmp = [] for ival in range(len(tmp_value)): if abs(tmp_value[ival] - tmp_oldvalue[ival]) < self._eps: values_eqivalent_tmp.append(True) else: values_eqivalent_tmp.append(False) if all(values_eqivalent_tmp) and len(value) == len( oldvalue): values_eqivalent = True if not values_eqivalent: self.logger.error( "You are trying to set keyword {} = {} but this is not allowed since the structure would be modified. Please use a suitable workfunction instead." .format(key, value)) raise InputValidationError( "You are trying to modify a keyword that is not allowed to be changed! (key={}, oldvalue={}, newvalue={})" .format(key, oldvalue, value)) #TODO check for remote folder (starting from folder data not implemented yet) # if voronoi calc check if folder from db given, or get folder from rep. # Parent calc does not has to be on the same computer. # so far we copy every thing from local computer ggf if kkr we want to copy remotely # get StructureData node from Parent if Voronoi structure = None self.logger.info( "KkrCalculation: Get structure node from voronoi parent") try: structure, voro_parent = VoronoiCalculation.find_parent_structure( parent_calc) except: self.logger.error( 'KkrCalculation: Could not get structure from Voronoi parent ({}).' .format(parent_calc)) raise ValidationError( "Cound not find structure node from parent {}".format( parent_calc)) # for VCA: check if input structure and parameter node define VCA structure vca_structure = vca_check(structure, parameters) ################################### # check whether or not the alat from the input parameters are used (this enters as a scaling factor for some parameters) use_alat_input = parameters.get_dict().get('use_input_alat', False) # prepare scoef file if impurity_info was given write_scoef = False runopt = parameters.get_dict().get('RUNOPT', None) kkrflex_opt = False if runopt is not None: if 'KKRFLEX' in runopt: kkrflex_opt = True if kkrflex_opt: write_scoef = True elif found_imp_info: self.logger.info( 'Found impurity_info in inputs of the calculation, automatically add runopt KKRFLEX' ) write_scoef = True runopt = parameters.get_dict().get('RUNOPT', []) runopt.append('KKRFLEX') parameters = update_params_wf( parameters, Dict( dict={ 'RUNOPT': runopt, 'nodename': 'update_KKRFLEX', 'nodedesc': 'Update Parameter node with KKRFLEX runopt' })) if found_imp_info and write_scoef: imp_info_dict = imp_info.get_dict() Rcut = imp_info_dict.get('Rcut', None) hcut = imp_info_dict.get('hcut', -1.) cylinder_orient = imp_info_dict.get('cylinder_orient', [0., 0., 1.]) ilayer_center = imp_info_dict.get('ilayer_center', 0) for i in range(len(cylinder_orient)): try: len(cylinder_orient[i]) vec_shape = False except TypeError: vec_shape = True if ilayer_center > len(structure.sites) - 1: raise IndexError( 'Index of the reference site is out of range! Possible values: 0 to {}.' .format(len(structure.sites) - 1)) elif Rcut < 0: raise ValueError('Cutoff radius has to be positive!') elif vec_shape == False or len(cylinder_orient) != 3: raise TypeError( 'Input orientation vector ({}) has the wrong shape! It needs to be a 3D-vector!' .format(cylinder_orient)) else: print('Input parameters for make_scoef read in correctly!') with tempfolder.open(self._SCOEF, 'w') as scoef_file: if use_alat_input: alat_input = parameters.get_dict().get( 'ALATBASIS', None) / get_Ang2aBohr() self.logger.info('alat_input is ' + str(alat_input)) else: self.logger.info('alat_input is None') alat_input = None make_scoef(structure, Rcut, scoef_file, hcut, cylinder_orient, ilayer_center, alat_input) elif write_scoef: self.logger.info( 'Need to write scoef file but no impurity_info given!') raise ValidationError( 'Found RUNOPT KKRFLEX but no impurity_info in inputs') # Check for 2D case twoDimcheck, msg = check_2Dinput_consistency(structure, parameters) if not twoDimcheck: raise InputValidationError(msg) # set shapes array either from parent voronoi run or read from inputcard in kkrimporter calculation if parent_calc.process_label == 'VoronoiCalculation' or parent_calc.process_label == 'KkrCalculation': # get shapes array from voronoi parent shapes = voro_parent.outputs.output_parameters.get_dict().get( 'shapes') else: # extract shapes from input parameters node constructed by kkrimporter calculation shapes = voro_parent.inputs.parameters.get_dict().get('<SHAPE>') self.logger.info('Extracted shapes: {}'.format(shapes)) # qdos option, ensure low T, E-contour, qdos run option and write qvec.dat file if found_kpath: # check qdos settings change_values = [] runopt = parameters.get_dict().get('RUNOPT') if runopt is None: runopt = [] runopt = [i.strip() for i in runopt] if 'qdos' not in runopt: runopt.append('qdos') change_values.append(['RUNOPT', runopt]) tempr = parameters.get_dict().get('TEMPR') if tempr is None or tempr > 100.: change_values.append(['TEMPR', 50.]) N1 = parameters.get_dict().get('NPT1') if N1 is None or N1 > 0: change_values.append(['NPT1', 0]) N2 = parameters.get_dict().get('NPT2') if N2 is None: change_values.append(['NPT2', 100]) N3 = parameters.get_dict().get('NPT3') if N3 is None or N3 > 0.: change_values.append(['NPT3', 0]) NPOL = parameters.get_dict().get('NPOL') if NPOL is None or NPOL > 0.: change_values.append(['NPOL', 0]) if change_values != []: new_params = {} #{'nodename': 'changed_params_qdos', 'nodedesc': 'Changed parameters to mathc qdos mode. Changed values: {}'.format(change_values)} for key, val in parameters.get_dict().items(): new_params[key] = val for key, val in change_values: new_params[key] = val new_params_node = Dict(dict=new_params) #parameters = update_params_wf(parameters, new_params_node) parameters = new_params_node # write qvec.dat file kpath_array = kpath.get_kpoints(cartesian=True) # convert automatically to internal units alat = get_alat_from_bravais( array( structure.cell), is3D=structure.pbc[2]) * get_Ang2aBohr() if use_alat_input: alat_input = parameters.get_dict().get('ALATBASIS') else: alat_input = alat kpath_array = kpath_array * ( alat_input / alat) / get_Ang2aBohr() / (2 * pi / alat) # now write file qvec = ['%i\n' % len(kpath_array)] qvec += [ '%e %e %e\n' % (kpt[0], kpt[1], kpt[2]) for kpt in kpath_array ] with tempfolder.open(self._QVEC, 'w') as qvecfile: qvecfile.writelines(qvec) # Prepare inputcard from Structure and input parameter data with tempfolder.open(self._INPUT_FILE_NAME, u'w') as input_file: natom, nspin, newsosol, warnings_write_inputcard = generate_inputcard_from_structure( parameters, structure, input_file, parent_calc, shapes=shapes, vca_structure=vca_structure, use_input_alat=use_alat_input) ################# # Decide what files to copy based on settings to the code (e.g. KKRFLEX option needs scoef) if has_parent: # copy the right files #TODO check first if file, exists and throw # warning, now this will throw an error outfolder = parent_calc.outputs.retrieved copylist = [] if parent_calc.process_class == KkrCalculation: copylist = [self._OUT_POTENTIAL] # TODO ggf copy remotely from remote node if present ... elif parent_calc.process_class == VoronoiCalculation: copylist = [parent_calc.process_class._SHAPEFUN] # copy either overwrite potential or voronoi output potential # (voronoi caclualtion retreives only one of the two) if parent_calc.process_class._POTENTIAL_IN_OVERWRITE in outfolder.list_object_names( ): copylist.append( parent_calc.process_class._POTENTIAL_IN_OVERWRITE) else: copylist.append( parent_calc.process_class._OUT_POTENTIAL_voronoi) #change copylist in case the calculation starts from an imported calculation else: #if parent_calc.process_class == KkrImporterCalculation: if self._OUT_POTENTIAL in outfolder.list_object_names(): copylist.append(self._OUT_POTENTIAL) else: copylist.append(self._POTENTIAL) if self._SHAPEFUN in outfolder.list_object_names(): copylist.append(self._SHAPEFUN) # create local_copy_list from copylist and change some names automatically for file1 in copylist: # deal with special case that file is written to another name if (file1 == 'output.pot' or file1 == self._OUT_POTENTIAL or (parent_calc.process_class == VoronoiCalculation and file1 == parent_calc.process_class._POTENTIAL_IN_OVERWRITE)): filename = self._POTENTIAL else: filename = file1 # now add to copy list local_copy_list.append((outfolder.uuid, file1, filename)) # add shapefun file from voronoi parent if needed if self._SHAPEFUN not in copylist: try: struc, voro_parent = VoronoiCalculation.find_parent_structure( parent_calc) except ValueError: return self.exit_codes.ERROR_NO_SHAPEFUN_FOUND # copy shapefun from retrieved of voro calc voro_retrieved = voro_parent.outputs.retrieved local_copy_list.append( (voro_retrieved.uuid, VoronoiCalculation._SHAPEFUN, self._SHAPEFUN)) # for set-ef option: ef_set = parameters.get_dict().get('ef_set', None) if ef_set is not None: print('local copy list before change: {}'.format( local_copy_list)) print( "found 'ef_set' in parameters: change EF of potential to this value" ) potcopy_info = [ i for i in local_copy_list if i[2] == self._POTENTIAL ][0] with load_node(potcopy_info[0]).open( potcopy_info[1]) as potfile: # remove previous output potential from copy list local_copy_list.remove(potcopy_info) # create potential here by readin in old potential and overwriting with changed Fermi energy with tempfolder.open(self._POTENTIAL, 'w') as pot_new_ef: # change potential txt = potfile.readlines() potstart = [] for iline in range(len(txt)): line = txt[iline] if 'exc:' in line: potstart.append(iline) for ipotstart in potstart: tmpline = txt[ipotstart + 3] tmpline = tmpline.split() newline = '%10.5f%20.14f%20.14f\n' % (float( tmpline[0]), ef_set, float(tmpline[-1])) txt[ipotstart + 3] = newline # write new file pot_new_ef.writelines(txt) # now this directory contains the updated potential file, thus it is not needed to put it in the local copy list anymore # TODO different copy lists, depending on the keywors input print('local copy list: {}'.format(local_copy_list)) self.logger.info('local copy list: {}'.format(local_copy_list)) # Prepare CalcInfo to be returned to aiida calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = [] # TODO retrieve list needs some logic, retrieve certain files, # only if certain input keys are specified.... calcinfo.retrieve_list = [ self._DEFAULT_OUTPUT_FILE, self._INPUT_FILE_NAME, self._SCOEF, self._NONCO_ANGLES_OUT, self._OUT_POTENTIAL, self._OUTPUT_0_INIT, self._OUTPUT_000, self._OUTPUT_2, self._OUT_TIMING_000 ] # for special cases add files to retireve list: # 1. dos calculation, add *dos* files if NPOL==0 retrieve_dos_files = False print('NPOL in parameter input:', parameters.get_dict()['NPOL']) if 'NPOL' in list(parameters.get_dict().keys()): if parameters.get_dict()['NPOL'] == 0: retrieve_dos_files = True if 'TESTOPT' in list(parameters.get_dict().keys()): testopts = parameters.get_dict()['TESTOPT'] if testopts is not None: stripped_test_opts = [i.strip() for i in testopts] if 'DOS' in stripped_test_opts: retrieve_dos_files = True if retrieve_dos_files: print('adding files for dos output', self._COMPLEXDOS, self._DOS_ATOM, self._LMDOS) add_files = [self._COMPLEXDOS] for iatom in range(natom): add_files.append(self._DOS_ATOM % (iatom + 1)) for ispin in range(nspin): add_files.append( (self._LMDOS % (iatom + 1, ispin + 1)).replace( ' ', '0')) calcinfo.retrieve_list += add_files # 2. KKRFLEX calculation retrieve_kkrflex_files = False if 'RUNOPT' in list(parameters.get_dict().keys()): runopts = parameters.get_dict()['RUNOPT'] if runopts is not None: stripped_run_opts = [i.strip() for i in runopts] if 'KKRFLEX' in stripped_run_opts: retrieve_kkrflex_files = True if retrieve_kkrflex_files: add_files = self._ALL_KKRFLEX_FILES print('adding files for KKRFLEX output', add_files) calcinfo.retrieve_list += add_files # 3. qdos claculation retrieve_qdos_files = False if 'RUNOPT' in list(parameters.get_dict().keys()): runopts = parameters.get_dict()['RUNOPT'] if runopts is not None: stripped_run_opts = [i.strip() for i in runopts] if 'qdos' in stripped_run_opts: retrieve_qdos_files = True if retrieve_qdos_files: print('adding files for qdos output', self._QDOS_ATOM, self._QVEC) add_files = [self._QVEC] for iatom in range(natom): for ispin in range(nspin): add_files.append( (self._QDOS_ATOM % (iatom + 1, ispin + 1)).replace( ' ', '0')) # retrieve also qdos_sx,y,z files if written out add_files.append( (self._QDOS_SX % (iatom + 1)).replace(' ', '0')) add_files.append( (self._QDOS_SY % (iatom + 1)).replace(' ', '0')) add_files.append( (self._QDOS_SZ % (iatom + 1)).replace(' ', '0')) calcinfo.retrieve_list += add_files # 4. Jij calculation retrieve_Jij_files = False if 'RUNOPT' in list(parameters.get_dict().keys()): runopts = parameters.get_dict()['RUNOPT'] if runopts is not None: stripped_run_opts = [i.strip() for i in runopts] if 'XCPL' in stripped_run_opts: retrieve_Jij_files = True if retrieve_Jij_files: add_files = [self._SHELLS_DAT] + [ self._Jij_ATOM % iatom for iatom in range(1, natom + 1) ] print('adding files for Jij output', add_files) calcinfo.retrieve_list += add_files codeinfo = CodeInfo() codeinfo.cmdline_params = [] codeinfo.code_uuid = code.uuid codeinfo.stdout_name = self._DEFAULT_OUTPUT_FILE calcinfo.codes_info = [codeinfo] return calcinfo
def prepare_for_submission(self, tempfolder): """Create the input files from the input nodes passed to this instance of the `CalcJob`. :param tempfolder: an `aiida.common.folders.Folder` to temporarily write files on disk :return: `aiida.common.datastructures.CalcInfo` instance """ # Check inputdict parameters = self.inputs.parameters if 'structure' in self.inputs: structure = self.inputs.structure found_structure = True else: found_structure = False vca_structure = False if found_structure: # for VCA: check if input structure and parameter node define VCA structure vca_structure = vca_check(structure, parameters) code = self.inputs.code # check if a parent folder containing a potential file (out_potential) is given if 'parent_KKR' in self.inputs: parent_calc_folder = self.inputs.parent_KKR found_parent = True else: found_parent = False if found_parent: # check if parent is either Voronoi or previous KKR calculation overwrite_potential, parent_calc = self._check_valid_parent( parent_calc_folder) #cross check if no structure was given and extract structure from parent if found_structure and not vca_structure: raise InputValidationError( "parent_KKR and structure found in input. " "Can only use either parent_KKR or structure in input.") else: structure_remote_KKR, voro_parent = self.find_parent_structure( parent_calc) if not vca_structure: structure = structure_remote_KKR else: # check consistency of input vca structure and structure from remote KKR folder # TODO check consistency pass else: overwrite_potential = False if not found_structure: raise InputValidationError( "Neither structure nor parent_KKR specified for this " "calculation") # check if overwrite potential is given explicitly if 'potential_overwrite' in self.inputs: potfile_overwrite = self.inputs.potential_overwrite has_potfile_overwrite = True else: has_potfile_overwrite = False if has_potfile_overwrite: overwrite_potential = True if not found_structure: raise InputValidationError( "Input structure needed for this calculation " "(using 'potential_overwrite' input node)") ################################### # Check for 2D case twoDimcheck, msg = check_2Dinput_consistency(structure, parameters) if not twoDimcheck: raise InputValidationError(msg) # Prepare inputcard from Structure and input parameter data input_file = tempfolder.open(self._INPUT_FILE_NAME, u'w') try: use_alat_input = parameters.get_dict().get('use_input_alat', False) natom, nspin, newsosol, warnings_write_inputcard = generate_inputcard_from_structure( parameters, structure, input_file, isvoronoi=True, vca_structure=vca_structure, use_input_alat=use_alat_input) except ValueError as e: raise InputValidationError( "Input Dict not consistent: {}".format(e)) # Decide what files to copy local_copy_list = [] if overwrite_potential: # copy the right files #TODO check first if file, exists and throw # warning, now this will throw an error if found_parent and self._is_KkrCalc(parent_calc): outfolder = parent_calc.outputs.retrieved # copy from remote folder copylist = [parent_calc._OUT_POTENTIAL] elif has_potfile_overwrite: outfolder = potfile_overwrite # copy from potential sfd copylist = [potfile_overwrite.filename] else: copylist = [] for file1 in copylist: filename = file1 if (found_parent or has_potfile_overwrite) and file1 == copylist[0]: filename = self._POTENTIAL_IN_OVERWRITE local_copy_list.append((outfolder.uuid, file1, filename)) # Prepare CalcInfo to be returned to aiida calcinfo = CalcInfo() calcinfo.uuid = self.uuid calcinfo.local_copy_list = local_copy_list calcinfo.remote_copy_list = [] calcinfo.retrieve_list = [ self._OUTPUT_FILE_NAME, self._ATOMINFO, self._RADII, self._SHAPEFUN, self._VERTICES, self._INPUT_FILE_NAME ] # pass on overwrite potential if this was given in input # (KkrCalculation checks if this file is there and takes this file instead of _OUT_POTENTIAL_voronoi # if given) if overwrite_potential: calcinfo.retrieve_list += [self._POTENTIAL_IN_OVERWRITE] else: calcinfo.retrieve_list += [self._OUT_POTENTIAL_voronoi] codeinfo = CodeInfo() codeinfo.cmdline_params = [] codeinfo.stdout_name = self._OUTPUT_FILE_NAME codeinfo.code_uuid = code.uuid calcinfo.codes_info = [codeinfo] return calcinfo