diff --git a/aiida_fleur/cmdline/launch/launch.py b/aiida_fleur/cmdline/launch/launch.py index 8a578c5d..a16f6e95 100755 --- a/aiida_fleur/cmdline/launch/launch.py +++ b/aiida_fleur/cmdline/launch/launch.py @@ -155,7 +155,7 @@ def launch_fleur(fleurinp, fleur, parent_folder, settings, daemon, max_num_machi @click.command('scf') -@options.STRUCTURE_OR_FILE(default="inp.xml", show_default=True) +@options.STRUCTURE_OR_FILE(default='inp.xml', show_default=True) @options.INPGEN() @options.CALC_PARAMETERS() @options.SETTINGS() @@ -171,13 +171,13 @@ def launch_scf(structure, inpgen, calc_parameters, fleurinp, fleur, wf_parameter """ Launch a scf workchain """ - fleurinp=None - + fleurinp = None + if isinstance(structure, FleurinpData): - fleurinp=structure - structure=None - inpgen=None - + fleurinp = structure + structure = None + inpgen = None + workchain_class = WorkflowFactory('fleur.scf') inputs = { 'inpgen': inpgen, @@ -194,31 +194,32 @@ def launch_scf(structure, inpgen, calc_parameters, fleurinp, fleur, wf_parameter inputs = clean_nones(inputs) builder = workchain_class.get_builder() builder.update(inputs) - pk=utils.launch_process(builder, daemon) + pk = utils.launch_process(builder, daemon) #Now create output files if fleurinp and not daemon: from aiida.orm import load_node - wf=load_node(pk) - scf_output=wf.outputs.output_scf_wc_para.get_dict() - scf_output["SCF-uuid"]=wf.uuid - + wf = load_node(pk) + scf_output = wf.outputs.output_scf_wc_para.get_dict() + scf_output['SCF-uuid'] = wf.uuid + #json with dict import json - with open("scf.json","w") as file: - json.dump(scf_output,file,indent=2) + with open('scf.json', 'w') as file: + json.dump(scf_output, file, indent=2) #plot from aiida_fleur.tools.plot.fleur import plot_fleur - plot_fleur(wf,save=True,show=False) + plot_fleur(wf, save=True, show=False) #store files - for file in ["out.xml","cdn1","cdn_last.hdf"]: + for file in ['out.xml', 'cdn1', 'cdn_last.hdf']: if file in wf.outputs.last_calc.retrieved.list_object_names(): - with open(file,"wb") as f: - f.write(wf.outputs.last_calc.retrieved.get_object_content(file,"rb")) + with open(file, 'wb') as f: + f.write(wf.outputs.last_calc.retrieved.get_object_content(file, 'rb')) + @click.command('relax') -@options.STRUCTURE_OR_FILE(default="inp.xml", show_default=True) +@options.STRUCTURE_OR_FILE(default='inp.xml', show_default=True) @options.INPGEN() @options.CALC_PARAMETERS() @options.FLEUR() @@ -235,19 +236,16 @@ def launch_relax(structure, inpgen, calc_parameters, fleur, wf_parameters, scf_p # TODO final scf input """ from aiida_fleur.workflows.relax import FleurRelaxWorkChain - + if isinstance(structure, FleurinpData): - fleurinp=structure - structure=None - inpgen=None + fleurinp = structure + structure = None + inpgen = None # we need a scf_paramters dict to change the forcemix if required later - if scf_parameters==None: - scf_parameters=Dict(dict= { - 'force_dict': {'forcemix': 'BFGS'}, - 'inpxml_changes': [] - }) - + if scf_parameters == None: + scf_parameters = Dict(dict={'force_dict': {'forcemix': 'BFGS'}, 'inpxml_changes': []}) + #workchain_class = WorkflowFactory('fleur.base_relax') inputs = { 'scf': { @@ -262,37 +260,36 @@ def launch_relax(structure, inpgen, calc_parameters, fleur, wf_parameters, scf_p 'wf_parameters': wf_parameters } - inputs = clean_nones(inputs) builder = FleurRelaxWorkChain.get_builder() builder.update(inputs) - pk=utils.launch_process(builder, daemon) + pk = utils.launch_process(builder, daemon) #Now create output files if fleurinp and not daemon: from aiida.orm import load_node - wf=load_node(pk) - relax_output=wf.outputs.output_relax_wc_para.get_dict() - relax_output["Relax-uuid"]=wf.uuid - relax_output["retrieved-uuid"]=wf.outputs.last_scf.last_calc.retrieved.uuid - - + wf = load_node(pk) + relax_output = wf.outputs.output_relax_wc_para.get_dict() + relax_output['Relax-uuid'] = wf.uuid + relax_output['retrieved-uuid'] = wf.outputs.last_scf.last_calc.retrieved.uuid + #json with dict import json - with open("relax.json","w") as file: - json.dump(relax_output,file,indent=2) + with open('relax.json', 'w') as file: + json.dump(relax_output, file, indent=2) #plot from aiida_fleur.tools.plot.fleur import plot_fleur - plot_fleur([wf],save=True,show=False) + plot_fleur([wf], save=True, show=False) #store files - for file in ["relax.xml","out.xml","cdn1","cdn_last.hdf"]: + for file in ['relax.xml', 'out.xml', 'cdn1', 'cdn_last.hdf']: if file in wf.outputs.last_scf.last_calc.retrieved.list_object_names(): - with open(file,"wb") as f: - f.write(wf.outputs.last_scf.last_calc.retrieved.get_object_content(file,"rb")) + with open(file, 'wb') as f: + f.write(wf.outputs.last_scf.last_calc.retrieved.get_object_content(file, 'rb')) + @click.command('eos') -@options.STRUCTURE_OR_FILE(default="inp.xml", show_default=True) +@options.STRUCTURE_OR_FILE(default='inp.xml', show_default=True) @options.INPGEN() @options.CALC_PARAMETERS() @options.FLEUR() @@ -307,13 +304,13 @@ def launch_eos(structure, inpgen, calc_parameters, fleur, wf_parameters, scf_par """ workchain_class = WorkflowFactory('fleur.eos') - - fleurinp=None - + + fleurinp = None + if isinstance(structure, FleurinpData): - fleurinp=structure - structure=None - + fleurinp = structure + structure = None + inputs = { 'scf': { 'wf_parameters': scf_parameters, @@ -329,34 +326,34 @@ def launch_eos(structure, inpgen, calc_parameters, fleur, wf_parameters, scf_par inputs = clean_nones(inputs) builder = workchain_class.get_builder() builder.update(inputs) - pk=utils.launch_process(builder, daemon) + pk = utils.launch_process(builder, daemon) #Now create output files if fleurinp and not daemon: from aiida.orm import load_node - wf=load_node(pk) - eos_output=wf.outputs.output_eos_wc_para.get_dict() + wf = load_node(pk) + eos_output = wf.outputs.output_eos_wc_para.get_dict() #json with dict import json - with open("eos.json","w") as file: - json.dump(eos_output,file,indent=2) + with open('eos.json', 'w') as file: + json.dump(eos_output, file, indent=2) #cif file - if "output_eos_wc_structure" in wf.outputs: + if 'output_eos_wc_structure' in wf.outputs: import os.path - if os.path.isfile("opt_struct.cif"): os.remove("opt_struct.cif") - cif_struct=wf.outputs.output_eos_wc_structure.get_cif() - cif_struct.export("opt_struct.cif") + if os.path.isfile('opt_struct.cif'): + os.remove('opt_struct.cif') + cif_struct = wf.outputs.output_eos_wc_structure.get_cif() + cif_struct.export('opt_struct.cif') #plot - if eos_output["volume_gs"] >0 : + if eos_output['volume_gs'] > 0: from aiida_fleur.tools.plot.fleur import plot_fleur - plot_fleur(wf,save=True,show=False) - - for i,uuid in enumerate(eos_output["calculations"]): - scf=load_node(uuid) - scale=eos_output["scaling"][i] - with open(f"out_{scale}.xml","w") as f: - f.write(scf.outputs.last_calc.retrieved.get_object_content("out.xml")) + plot_fleur(wf, save=True, show=False) + for i, uuid in enumerate(eos_output['calculations']): + scf = load_node(uuid) + scale = eos_output['scaling'][i] + with open(f"out_{scale}.xml", 'w') as f: + f.write(scf.outputs.last_calc.retrieved.get_object_content('out.xml')) @click.command('dos') @@ -371,15 +368,15 @@ def launch_dos(fleurinp, fleur, wf_parameters, parent_folder, daemon, settings, """ Launch a banddos workchain (special command to set the dos as a default mode) """ - if wf_parameters==None: - wf_parameters=Dict({"mode":"dos"}) + if wf_parameters == None: + wf_parameters = Dict({'mode': 'dos'}) else: - wf_dict=wf_parameters.get_dict() - wf_dict["mode"]="dos" - wf_parameters=Dict(wf_dict) + wf_dict = wf_parameters.get_dict() + wf_dict['mode'] = 'dos' + wf_parameters = Dict(wf_dict) launch_banddos(fleurinp, fleur, wf_parameters, parent_folder, daemon, settings, option_node) - + @click.command('band') @options.FLEURINP(default='inp.xml') @@ -395,11 +392,12 @@ def launch_band(fleurinp, fleur, wf_parameters, parent_folder, daemon, settings, """ #Band is default launch_banddos(fleurinp, fleur, wf_parameters, parent_folder, daemon, settings, option_node) - + + def launch_banddos(fleurinp, fleur, wf_parameters, parent_folder, daemon, settings, option_node): """ Launch a banddos workchain - """ + """ workchain_class = WorkflowFactory('fleur.banddos') inputs = { 'wf_parameters': wf_parameters, @@ -411,23 +409,23 @@ def launch_banddos(fleurinp, fleur, wf_parameters, parent_folder, daemon, settin inputs = clean_nones(inputs) builder = workchain_class.get_builder() builder.update(inputs) - pk=utils.launch_process(builder, daemon) + pk = utils.launch_process(builder, daemon) #Now create output files from aiida.orm import load_node - wf=load_node(pk) - banddos_output=wf.outputs.output_banddos_wc_para.get_dict() + wf = load_node(pk) + banddos_output = wf.outputs.output_banddos_wc_para.get_dict() #json with dict import json - with open("banddos.json","w") as file: - json.dump(banddos_output,file,indent=2) - #the banddos.hdf file - with open(f"banddos.hdf","wb") as f: - f.write(wf.outputs.banddos_calc.retrieved.get_object_content("banddos.hdf",'rb')) + with open('banddos.json', 'w') as file: + json.dump(banddos_output, file, indent=2) + #the banddos.hdf file + with open(f"banddos.hdf", 'wb') as f: + f.write(wf.outputs.banddos_calc.retrieved.get_object_content('banddos.hdf', 'rb')) #plot from aiida_fleur.tools.plot.fleur import plot_fleur - plot_fleur(wf,save=True,show=False) + plot_fleur(wf, save=True, show=False) @click.command('init_cls') @@ -607,8 +605,9 @@ def launch_ssdisp(structure, inpgen, calc_parameters, fleur, wf_parameters, scf_ builder.update(inputs) utils.launch_process(builder, daemon) + @click.command('ssdisp_conv') -@options.STRUCTURE_OR_FILE(default="inp.xml", show_default=True) +@options.STRUCTURE_OR_FILE(default='inp.xml', show_default=True) @options.INPGEN() @options.CALC_PARAMETERS() @options.FLEUR() @@ -622,12 +621,12 @@ def launch_ssdisp(structure, inpgen, calc_parameters, fleur, wf_parameters, scf_ """ workchain_class = WorkflowFactory('fleur.ssdisp_conv') - fleurinp=None - if (isinstance(structure,FleurinpData)): - fleurinp=structure - structure=None - inpgen=None - calc_parameters=None + fleurinp = None + if (isinstance(structure, FleurinpData)): + fleurinp = structure + structure = None + inpgen = None + calc_parameters = None inputs = { 'scf': { @@ -644,17 +643,18 @@ def launch_ssdisp(structure, inpgen, calc_parameters, fleur, wf_parameters, scf_ inputs = clean_nones(inputs) builder = workchain_class.get_builder() builder.update(inputs) - pk=utils.launch_process(builder, daemon) + pk = utils.launch_process(builder, daemon) if not daemon: from aiida.orm import load_node - wf=load_node(pk) - ssdisp_output=wf.outputs.output_ssdisp_conv_wc_para.get_dict() + wf = load_node(pk) + ssdisp_output = wf.outputs.output_ssdisp_conv_wc_para.get_dict() #json with dict import json - with open("ssdisp_conv.json","w") as file: - json.dump(ssdisp_output,file,indent=2) - #TODO plotting would be nice here + with open('ssdisp_conv.json', 'w') as file: + json.dump(ssdisp_output, file, indent=2) + #TODO plotting would be nice here + @click.command('dmi') @options.STRUCTURE_OR_FILE(default=defaults.get_fept_film_structure, show_default=True) diff --git a/aiida_fleur/cmdline/util/__init__.py b/aiida_fleur/cmdline/util/__init__.py index 75623123..552370b1 100755 --- a/aiida_fleur/cmdline/util/__init__.py +++ b/aiida_fleur/cmdline/util/__init__.py @@ -13,8 +13,8 @@ ''' import click import json - -from .defaults import get_code_interactive,get_default_dict + +from .defaults import get_code_interactive, get_default_dict from aiida.cmdline.utils import decorators @@ -24,20 +24,17 @@ def cmd_defaults(): """Interactively create/modify the default settings for aiida-fleur CLI.""" - dict=get_default_dict() + dict = get_default_dict() #default codes - dict["fleur"]=get_code_interactive("fleur.fleur",dict["fleur"]) - dict["inpgen"]=get_code_interactive("fleur.inpgen",dict["inpgen"]) - + dict['fleur'] = get_code_interactive('fleur.fleur', dict['fleur']) + dict['inpgen'] = get_code_interactive('fleur.inpgen', dict['inpgen']) + import os - HOME=os.getenv("HOME") + HOME = os.getenv('HOME') try: os.mkdir(f"{HOME}/.aiida-fleur") except: - pass #dir might exist already - with open(f"{HOME}/.aiida-fleur/cli.json","w") as f: - json.dump(dict,f) - - - + pass #dir might exist already + with open(f"{HOME}/.aiida-fleur/cli.json", 'w') as f: + json.dump(dict, f) diff --git a/aiida_fleur/cmdline/util/defaults.py b/aiida_fleur/cmdline/util/defaults.py index 6cf7e195..bb20d7a5 100644 --- a/aiida_fleur/cmdline/util/defaults.py +++ b/aiida_fleur/cmdline/util/defaults.py @@ -2,21 +2,17 @@ Here we specify some defaults for cli commands """ + def get_default_dict(): import os - HOME=os.getenv("HOME") + HOME = os.getenv('HOME') #first see if we have already a setting file try: - with open(f"{HOME}/.aiida-fleur/cli.json","r") as f: - dict=json.load(f) + with open(f"{HOME}/.aiida-fleur/cli.json") as f: + dict = json.load(f) except: - dict={"fleur":None, - "inpgen":None, - "copyback":False, - "resources":None - } - return dict - + dict = {'fleur': None, 'inpgen': None, 'copyback': False, 'resources': None} + return dict # Structures @@ -99,19 +95,19 @@ def get_fept_film_structure(): # Codes def get_inpgen(): """Return a `Code` node of the latest added inpgen executable in the database.""" - inpgen=get_default_dict()["inpgen"] - if inpgen==None: - inpgen=get_last_code("fleur.inpgen") - return inpgen + inpgen = get_default_dict()['inpgen'] + if inpgen == None: + inpgen = get_last_code('fleur.inpgen') + return inpgen + def get_fleur(): """Return a `Code` node of the latest added inpgen executable in the database.""" - fleur=fleur=get_default_dict()["fleur"] - if fleur==None: - fleur=get_last_code('fleur.fleur') - return fleur + fleur = fleur = get_default_dict()['fleur'] + if fleur == None: + fleur = get_last_code('fleur.fleur') + return fleur - def get_last_code(entry_point_name): """Return a `Code` node of the latest code executable of the given entry_point_name in the database. @@ -138,7 +134,7 @@ def get_last_code(entry_point_name): return results[0].uuid -def get_code_interactive(entry_point_name,default_uuid=None): +def get_code_interactive(entry_point_name, default_uuid=None): """Return a `Code` node of the given entry_point_name in the database. The database will be queried for the existence the possible codes, they will be listed and @@ -160,20 +156,19 @@ def get_code_interactive(entry_point_name,default_uuid=None): if not builder.all(): raise NotExistent(f'ERROR: Could not find any Code in the database with entry point: {entry_point_name}!') - - print(f"Selection for {entry_point_name}:") - i=0 - default_i=0 + + print(f"Selection for {entry_point_name}:") + i = 0 + default_i = 0 for code in builder.all(): - if code[0].uuid==default_uuid: - default_i=i + if code[0].uuid == default_uuid: + default_i = i print(f"{i}:{code[0].full_label}") - i=i+1 - i=click.prompt("Please enter your choice",type=int,default=default_i) + i = i + 1 + i = click.prompt('Please enter your choice', type=int, default=default_i) try: - result=builder.all()[i] + result = builder.all()[i] except: return default_uuid - - return result[0].uuid \ No newline at end of file + return result[0].uuid diff --git a/aiida_fleur/cmdline/util/options.py b/aiida_fleur/cmdline/util/options.py index 2b1d9d43..52dfa530 100755 --- a/aiida_fleur/cmdline/util/options.py +++ b/aiida_fleur/cmdline/util/options.py @@ -17,7 +17,7 @@ from aiida.cmdline.params import types from aiida.cmdline.params.options import OverridableOption from .defaults import get_inpgen, get_fleur, get_si_bulk_structure -from .types import StructureNodeOrFileParamType,WFParameterType,RemoteType,FleurinpType,OptionsType +from .types import StructureNodeOrFileParamType, WFParameterType, RemoteType, FleurinpType, OptionsType STRUCTURE_OR_FILE = OverridableOption( '-s', diff --git a/aiida_fleur/cmdline/util/types.py b/aiida_fleur/cmdline/util/types.py index bf21d281..81a733df 100644 --- a/aiida_fleur/cmdline/util/types.py +++ b/aiida_fleur/cmdline/util/types.py @@ -18,53 +18,61 @@ from aiida.plugins import DataFactory from aiida.cmdline.utils.decorators import with_dbenv -wf_template_files={"eos":'{"points": 9,\n' - '"step": 0.002,\n' - '"guess": 1.00}', - "scf":'{"fleur_runmax": 4,\n' - '"density_converged": 0.00002,\n' - '"energy_converged": 0.002,\n' - '"mode": "density",\n' - '"itmax_per_run": 30}', - "band":'{\n' - '// Select your k-points\n' - '"kpath": "auto"// This can be "auto" (meaning you try to pick a good choice automatically from inp.xml) or "seek" to use seek-k-path\n' - '//"klistname": "path-3",//You can specify directly a list in the inp.xml/kpts.xml\n' - '//"kpoints_number": 200,\n' - '//"kpoints_distance": 0.1,\n' - '//"kpoints_explicit": None\n}', - "dos":'{\n' - '// Select your k-points\n' - '//"klistname": "path-3",//You can specify directly a list in the inp.xml/kpts.xml\n' - '//"kpoints_number": 200,\n' - '//"kpoints_distance": 0.1,\n' - '// These parameters are relevant for the DOS mode\n' - '"sigma": 0.005,\n' - '"emin": -0.50,\n' - '"emax": 0.90\n}', - "relax":'{\n' - '"film_distance_relaxation": "False", // if True, sets relaxXYZ="FFT" for all atoms\n' - '"force_criterion": 0.049, // Sets the threshold of the largest force\n' - '"relax_iter": 5 // Maximum number of optimization iterations\n' - '}', - "ssdisp_conv":'{\n' - '"beta": {"all": 1.57079}, // set the angle of some or all atoms\n' - '"q_vectors": {"label1": [0.0,0.0,0.0], //set the q-vectors. Each has a label attached\n' - ' "label2": [0.1,0.0,0.0]\n' - ' }\n' - '//"suppress_symmetries": False // Only if you start from a structure: do not use symmetries\n' - '}' - - } +wf_template_files = { + 'eos': + '{"points": 9,\n' + '"step": 0.002,\n' + '"guess": 1.00}', + 'scf': + '{"fleur_runmax": 4,\n' + '"density_converged": 0.00002,\n' + '"energy_converged": 0.002,\n' + '"mode": "density",\n' + '"itmax_per_run": 30}', + 'band': + '{\n' + '// Select your k-points\n' + '"kpath": "auto"// This can be "auto" (meaning you try to pick a good choice automatically from inp.xml) or "seek" to use seek-k-path\n' + '//"klistname": "path-3",//You can specify directly a list in the inp.xml/kpts.xml\n' + '//"kpoints_number": 200,\n' + '//"kpoints_distance": 0.1,\n' + '//"kpoints_explicit": None\n}', + 'dos': + '{\n' + '// Select your k-points\n' + '//"klistname": "path-3",//You can specify directly a list in the inp.xml/kpts.xml\n' + '//"kpoints_number": 200,\n' + '//"kpoints_distance": 0.1,\n' + '// These parameters are relevant for the DOS mode\n' + '"sigma": 0.005,\n' + '"emin": -0.50,\n' + '"emax": 0.90\n}', + 'relax': + '{\n' + '"film_distance_relaxation": "False", // if True, sets relaxXYZ="FFT" for all atoms\n' + '"force_criterion": 0.049, // Sets the threshold of the largest force\n' + '"relax_iter": 5 // Maximum number of optimization iterations\n' + '}', + 'ssdisp_conv': + '{\n' + '"beta": {"all": 1.57079}, // set the angle of some or all atoms\n' + '"q_vectors": {"label1": [0.0,0.0,0.0], //set the q-vectors. Each has a label attached\n' + ' "label2": [0.1,0.0,0.0]\n' + ' }\n' + '//"suppress_symmetries": False // Only if you start from a structure: do not use symmetries\n' + '}' +} + class OptionsType(click.ParamType): """ Type to construct options for the computational resources to use """ - name= "options for Computational resources" - def convert(self,value,param,ctx): - - wf_options_template='''{ + name = 'options for Computational resources' + + def convert(self, value, param, ctx): + + wf_options_template = '''{ "resources": { "num_machines": 1, //Number of computing nodes "num_mpiprocs_per_machine": 1, //Number of MPI processes per node @@ -74,55 +82,56 @@ def convert(self,value,param,ctx): "max_wallclock_seconds": 3600 //Maximum wallclock time in seconds }''' - try: #Perhaps a pk or uuid was given? return types.DataParamType(sub_classes=('aiida.data:core.dict',)).convert(value, param, ctx) except: - pass #Ok this failed, then we examine the argument as a filename + pass #Ok this failed, then we examine the argument as a filename - if value=="template.json": - print("Writing template to wf_options.json") - with open(f"wf_options.json","w") as f: - f.write(wf_options_template) + if value == 'template.json': + print('Writing template to wf_options.json') + with open(f"wf_options.json", 'w') as f: + f.write(wf_options_template) quit() import os if (os.path.isfile(value)): # a file was given. Create a dict from the file and use it try: - with open(value,"r") as f: + with open(value) as f: import json from json_minify import json_minify - wf_options=json.loads(json_minify(f.read())) + wf_options = json.loads(json_minify(f.read())) except RuntimeError as error: print(error) print(f"{value} could not be converted into a dict") os.abort() - aiida_dict=DataFactory("dict") - wf_dict=aiida_dict(wf_options) - - return wf_dict - - return None + aiida_dict = DataFactory('dict') + wf_dict = aiida_dict(wf_options) + + return wf_dict + + return None + class FleurinpType(click.ParamType): """ Type to either load a fleurinp node or read an inp.xml file """ - name = "FleurInp data/inp.xml file" - def convert(self,value,param,ctx): + name = 'FleurInp data/inp.xml file' + + def convert(self, value, param, ctx): try: return types.DataParamType(sub_classes=('aiida.data:fleur.fleurinp',)).convert(value, param, ctx) except: - pass #Ok this failed, so we try to read the file + pass #Ok this failed, so we try to read the file - if value in ["inp.xml",".",'./']: + if value in ['inp.xml', '.', './']: from aiida_fleur.data.fleurinp import FleurinpData - inp_files=["inp.xml"] + inp_files = ['inp.xml'] #check if there are included files in this dir - for file in ["kpts.xml","sym.xml","relax.xml"]: + for file in ['kpts.xml', 'sym.xml', 'relax.xml']: import os.path if os.path.isfile(file): inp_files.append(file) @@ -130,67 +139,72 @@ def convert(self,value,param,ctx): return finp.store() return None + class RemoteType(click.ParamType): """ Type for remote data. Might be specified by a uuid or a file in which this uuid is found """ - name = "Remote folder" - def convert(self,value,param,ctx): + name = 'Remote folder' + + def convert(self, value, param, ctx): #Try to interpret value as uuid try: return types.DataParamType(sub_classes=('aiida.data:core.remote',)).convert(value, param, ctx) except: - pass #Ok this failed, so we try to read the file - + pass #Ok this failed, so we try to read the file + try: from aiida.orm import load_node - with open(value,"r") as f: + with open(value) as f: import json - dict_from_file=json.load(f) + dict_from_file = json.load(f) if 'SCF-uuid' in dict_from_file: - scf_wf=load_node(dict_from_file["SCF-uuid"]) + scf_wf = load_node(dict_from_file['SCF-uuid']) return scf_wf.outputs.last_calc.remote_folder if 'retrieved-uuid' in dict_from_file: - return dict_from_file["retrieved-uuid"] + return dict_from_file['retrieved-uuid'] except: return None + class WFParameterType(click.ParamType): """ ParamType for giving workflow parameters """ - name = "Workflow parameters" - def convert(self,value,param,ctx): + name = 'Workflow parameters' + + def convert(self, value, param, ctx): import os - if value=="template.json": + if value == 'template.json': if ctx.command.name in wf_template_files: - with open(f"wf_{ctx.command.name}.json","w") as f: - f.write(wf_template_files[ctx.command.name]) + with open(f"wf_{ctx.command.name}.json", 'w') as f: + f.write(wf_template_files[ctx.command.name]) quit() if (os.path.isfile(value)): # a file was given. Create a dict from the file and use it try: - with open(value,"r") as f: + with open(value) as f: import json from json_minify import json_minify - wf_param=json.loads(json_minify(f.read())) + wf_param = json.loads(json_minify(f.read())) except RuntimeError as error: print(error) print(f"{value} could not be converted into a dict") os.abort() - aiida_dict=DataFactory("dict") - wf_dict=aiida_dict(wf_param) - + aiida_dict = DataFactory('dict') + wf_dict = aiida_dict(wf_param) + return wf_dict - + #Now load from aiida wf_dict = types.DataParamType(sub_classes=('aiida.data:core.dict',)).convert(value, param, ctx) - + return wf_dict - + + class StructureNodeOrFileParamType(click.ParamType): """ The ParamType for identifying a structure by node or to extract it from a given file @@ -209,11 +223,11 @@ def convert(self, value, param, ctx): # aiida allows also for shorten uuids from aiida.orm import StructureData, QueryBuilder - if value in ["inp.xml",".",'./']: + if value in ['inp.xml', '.', './']: from aiida_fleur.data.fleurinp import FleurinpData - inp_files=["inp.xml"] + inp_files = ['inp.xml'] #check if there are included files in this dir - for file in ["kpts.xml","sym.xml","relax.xml"]: + for file in ['kpts.xml', 'sym.xml', 'relax.xml']: import os.path if os.path.isfile(file): inp_files.append(file) diff --git a/aiida_fleur/cmdline/util/utils.py b/aiida_fleur/cmdline/util/utils.py index e898bf4b..cf4faa61 100644 --- a/aiida_fleur/cmdline/util/utils.py +++ b/aiida_fleur/cmdline/util/utils.py @@ -63,4 +63,4 @@ def launch_process(process, daemon, **inputs): _, node = launch.run_get_node(process, **inputs) echo_process_results(node) - return node.pk + return node.pk diff --git a/aiida_fleur/cmdline/workflows/__init__.py b/aiida_fleur/cmdline/workflows/__init__.py index b5358847..34c8cee2 100755 --- a/aiida_fleur/cmdline/workflows/__init__.py +++ b/aiida_fleur/cmdline/workflows/__init__.py @@ -28,8 +28,9 @@ def cmd_workflow(): @cmd_workflow.command('res') -@arguments.PROCESS('process', type=ProcessParamType() - ) #, type=WorkflowParamType(sub_classes=('aiida.node:process.workflow.workchain',))) +@arguments.PROCESS( + 'process', + type=ProcessParamType()) #, type=WorkflowParamType(sub_classes=('aiida.node:process.workflow.workchain',))) @click.option('--info/--no-info', default=False, help='Print an info header above each node.') @click.option('-l', '--label', 'label', type=str, help='Print only output dicts with a certain link_label.') @options_fl.SHOW() @@ -69,8 +70,9 @@ def workchain_res(process, info, label, show, keys, fmt): @cmd_workflow.command('inputdict') -@arguments.PROCESS('process', type=ProcessParamType() - ) #, type=WorkflowParamType(sub_classes=('aiida.node:process.workflow.workchain',))) +@arguments.PROCESS( + 'process', + type=ProcessParamType()) #, type=WorkflowParamType(sub_classes=('aiida.node:process.workflow.workchain',))) @click.option('--info/--no-info', default=False, help='Print an info header above each node.') @click.option('-l', '--label', 'label', type=str, help='Print only output dicts with a certain link_label.') @options_fl.SHOW() diff --git a/aiida_fleur/data/fleurinp.py b/aiida_fleur/data/fleurinp.py index 7f8cc04c..0ff2d51d 100644 --- a/aiida_fleur/data/fleurinp.py +++ b/aiida_fleur/data/fleurinp.py @@ -39,8 +39,6 @@ 'get_fleurinp_from_remote_data_cf') - - class FleurinpData(orm.Data): """ AiiDA data object representing everything a FLEUR calculation needs. @@ -695,6 +693,7 @@ def convert_inpxml(fleurinp: FleurinpData, to_version: orm.Str) -> FleurinpData: """ return fleurinp.convert_inpxml_ncf(to_version.value) + @cf def get_fleurinp_from_folder_data_cf(folder_node: orm.FolderData, additional_files: orm.List | None = None) -> FleurinpData: diff --git a/aiida_fleur/data/fleurinpmodifier.py b/aiida_fleur/data/fleurinpmodifier.py index a6c1b98a..feaf557b 100644 --- a/aiida_fleur/data/fleurinpmodifier.py +++ b/aiida_fleur/data/fleurinpmodifier.py @@ -39,7 +39,7 @@ def inpxml_changes(wf_parameters: dict | orm.Dict | ProcessBuilderNamespace, append: bool = True, builder_entry: str = 'wf_parameters', - builder_replace_stored: bool = True) -> Generator[FleurinpModifier, None, None]: + builder_replace_stored: bool = True) -> Generator[FleurinpModifier]: """ Contextmanager to construct an `inpxml_changes` entry in the given dictionary diff --git a/aiida_fleur/parsers/fleur.py b/aiida_fleur/parsers/fleur.py index cb7b6082..3765df35 100644 --- a/aiida_fleur/parsers/fleur.py +++ b/aiida_fleur/parsers/fleur.py @@ -131,9 +131,9 @@ def parse(self, **kwargs): # Open log-file as well try: - run_was_successful="finished successfully" in error_file_lines + run_was_successful = 'finished successfully' in error_file_lines except: - run_was_successful=False + run_was_successful = False if FleurCalculation._LOG_FILE_NAME in list_of_files: logfile = FleurCalculation._LOG_FILE_NAME # read @@ -141,13 +141,13 @@ def parse(self, **kwargs): try: with output_folder.open(logfile, 'r') as efile: log_file_entries = json.load(efile) - run_was_successful="Success" in log_file_entries[-1] + run_was_successful = 'Success' in log_file_entries[-1] except OSError: self.logger.error(f'Failed to open log file: {logfile}.') return self.exit_codes.ERROR_OPENING_OUTPUTS except json.JSONDecodeError: - self.logger.error("logfile not correctly formatted") - + self.logger.error('logfile not correctly formatted') + #Now check for different kind of errors if not run_was_successful: self.logger.warning('The following was written into std error and piped to {}' @@ -159,8 +159,7 @@ def parse(self, **kwargs): kb_used = 0.0 if has_xml_outfile: - with output_folder.open(FleurCalculation._OUTXML_FILE_NAME, - 'r') as out_file: # lazy out.xml parsing + with output_folder.open(FleurCalculation._OUTXML_FILE_NAME, 'r') as out_file: # lazy out.xml parsing outlines = out_file.read() try: line_avail = re.findall(r'