Package: aiida-pyscf
aiida-pyscfAnAiiDAplugin for thePython-based Simulations of Chemistry Framework (PySCF).InstallationRequirementsSetupExamplesMean-field calculationCustomizing the structureOptimizing geometryWriting Hamiltonian to FCIDUMP filesWriting orbitals to CUBE filesRestarting unconverged calculationsAutomatic error recoveryPickled modelInstallationThe recommended method of installation is throughpip:pip install aiida-pyscfRequirementsTo useaiida-pyscfa configured AiiDA profile is required. Please refer to thedocumentation ofaiida-corefor
detailed instructions.SetupTo run a PySCF calculation through AiiDA using theaiida-pyscfplugin, the computer needs to be configured where PySCF
should be run. Please refer to thedocumentation ofaiida-corefor detailed instructions.Then the PySCF code needs to be configured. The following YAML configuration file can be taken as a starting point:label:pyscfdescription:PySCFcomputer:localhostfilepath_executable:pythondefault_calc_job_plugin:pyscf.baseuse_double_quotes:falsewith_mpi:falseprepend_text:''append_text:''Write the contents to a file namedpyscf.yml, making sure to update the value ofcomputerto the label of the
computer configured in the previous step. To configure the code, execute:verdicodecreatecore.code.installed--configpyscf.yml-nThis should now have created the code with the labelpyscfthat will be used in the following examples.ExamplesMean-field calculationThe default calculation is to perform a mean-field calculation. At a very minimum, the structure and the mean-field
method should be defined:fromase.buildimportmoleculefromaiida.engineimportrunfromaiida.ormimportDict,StructureData,load_codebuilder=load_code('pyscf').get_builder()builder.structure=StructureData(ase=molecule('H2O'))builder.parameters=Dict({'mean_field':{'method':'RHF'}})results,node=run.get_node(builder)This runs a Hartree-Fock calculation on the geometry of a water molecule.The main results are stored in theparametersoutput, which by default contain the computedtotal_energyandforces, details on the molecular orbitals, as well as some timing information:print(results['parameters'].get_dict()){'mean_field':{'forces':[[-6.4898366104394e-16,3.0329042995656e-15,2.2269765466236],[1.122487932593e-14,0.64803103141326,-1.1134882733107],[-1.0575895664886e-14,-0.64803103141331,-1.1134882733108]],'forces_units':'eV/Å','molecular_orbitals':{'labels':['0 O 1s','0 O 2s','0 O 2px','0 O 2py','0 O 2pz','1 H 1s','2 H 1s'],'energies':[-550.86280025028,-34.375426862456,-16.629598134599,-12.323304634736,-10.637428057751,16.200273277782,19.796075801491],'occupations':[2.0,2.0,2.0,2.0,2.0,0.0,0.0]},'total_energy':-2039.8853743664,'total_energy_units':'eV',},'timings':{'total':1.3238215579768,'mean_field':0.47364449803717},}Customizing the structureThe geometry of the structure is fully defined through thestructureinput, which is provided by aStructureDatanode. Any other properties, e.g., the charge and what basis set to use, can be specified through thestructuredictionary in theparametersinput:fromase.buildimportmoleculefromaiida.engineimportrunfromaiida.ormimportDict,StructureData,load_codebuilder=load_code('pyscf').get_builder()builder.structure=StructureData(ase=molecule('H2O'))builder.parameters=Dict({'mean_field':{'method':'RHF'},'structure':{'basis ':'sto-3g','charge':0,}})results,node=run.get_node(builder)Any attribute of thepyscf.gto.Moleclasswhich is used to define the structure can
be set through thestructuredictionary, with the exception of theatomandunitattributes, which are set
automatically by the plugin based on theStructureDatainput.Optimizing geometryThe geometry can be optimized by specifying theoptimizerdictionary in the inputparameters. Thesolverhas to be
specified, and currently the solversgeometricandbernyare supported. Theconvergence_parametersaccepts the
parameters for the selected solver (seePySCF documentationfor details):fromase.buildimportmoleculefromaiida.engineimportrunfromaiida.ormimportDict,StructureData,load_codebuilder=load_code('pyscf').get_builder()builder.structure=StructureData(ase=molecule('H2O'))builder.parameters=Dict({'mean_field':{'method':'RHF'},'optimizer':{'solver':'geometric','convergence_parameters':{'convergence_energy':1e-6,# Eh'convergence_grms':3e-4,# Eh/Bohr'convergence_gmax':4.5e-4,# Eh/Bohr'convergence_drms':1.2e-3,# Angstrom'convergence_dmax':1.8e-3,# Angstrom}}})results,node=run.get_node(builder)The optimized structure is returned in the form of aStructureDataunder thestructureoutput label. The structure
and energy of each frame in the geometry optimization trajectory, are stored in the form of aTrajectoryDataunder thetrajectoryoutput label. The total energies can be retrieved as follows:results['trajectory'].get_array('energies')Localizing orbitalsTo compute localized orbitals, specify the desired method in theparameters.localize_orbitals.methodinput:fromase.buildimportmoleculefromaiida.engineimportrunfromaiida.ormimportDict,StructureData,load_codebuilder=load_code('pyscf').get_builder()builder.structure=StructureData(ase=molecule('H2O'))builder.parameters=Dict({'mean_field':{'method':'RHF'},'localize_orbitals':{'method':'ibo'}})results,node=run.get_node(builder)The following methods are supported:boys,cholesky,edmiston,iao,ibo,lowdin,nao,orth,pipek,vvo. For more information, please refer to thePySCF documentation.Computing the HessianIn order to compute the Hessian, specify an empty dictionary for thehessiankey in theparametersinput:fromase.buildimportmoleculefromaiida.engineimportrunfromaiida.ormimportDict,StructureData,load_codebuilder=load_code('pyscf').get_builder()builder.structure=StructureData(ase=molecule('H2O'))builder.parameters=Dict({'mean_field':{'method':'RHF'},'hessian':{}})results,node=run.get_node(builder)The computed Hessian will be attached as anArrayDatanode with the link labelhessian. Usenode.outputs.hessian.get_array('hessian')to retrieve the computed Hessian as a numpy array for further processing.Writing Hamiltonian to FCIDUMP filesTo instruct the calculation to dump a representation of the Hamiltonian to FCIDUMP files, add thefcidumpdictionary
to theparametersinput:fromase.buildimportmoleculefromaiida.engineimportrunfromaiida.ormimportDict,StructureData,load_codebuilder=load_code('pyscf').get_builder()builder.structure=StructureData(ase=molecule('N2'))builder.parameters=Dict({'mean_field':{'method':'RHF'},'fcidump':{'active_spaces':[[5,6,8,9]],'occupations':[[1,1,1,1]]}})results,node=run.get_node(builder)Theactive_spacesandoccupationskeys are requires and each take a list of list of integers. For each element in
the list, a FCIDUMP file is generated for the corresponding active spaces and the occupations of the orbitals. The shape
of theactive_spacesandoccupationsarray has to be identical.The generated FCIDUMP files are attached asSinglefileDataoutput nodes in thefcidumpnamespace, where the label is
determined by the index of the corresponding active space in the list:print(results['fcidump']['active_space_0'].get_content())&FCINORB=4,NELEC=4,MS2=0,ORBSYM=1,1,1,1,ISYM=1,&END0.583212712168299811110.53596425004980741122-2.942091015256668e-1511320.53812901859059141133-3.782672959584676e-151141...Generating CUBE filesThepyscf.tools.cubegenmodule provides functions to compute various properties of the system and write them as CUBE
files. ThePyscfCalculationplugin currently supports computing the following:molecular orbitalscharge densitymolecular electrostatic potentialTo instruct the calculation to dump a representation of any of these quantities to CUBE files, add thecubegendictionary to theparametersinput:fromase.buildimportmoleculefromaiida.engineimportrunfromaiida.ormimportDict,StructureData,load_codebuilder=load_code('pyscf').get_builder()builder.structure=StructureData(ase=molecule('N2'))builder.parameters=Dict({'mean_field':{'method':'RHF'},'cubegen':{'orbitals: {'indices':[5,6],'parameters':{'nx':40,'ny':40,'nz':40,}},'density':{'parameters':{'resolution':300,}},'mep':{'parameters':{'resolution':300,}}}})results,node=run.get_node(builder)Theindiceskey has to be specified for theorbitalssubdictionary and takes a list of integers, indicating the
indices of the molecular orbitals that should be written to file. Additional parameters can be provided in theparameterssubdictionary (see thePySCF documentationfor details). Theparameterssubdictionaries for thedensityandmepdictionaries are optional. To compute the
charge density and molecular electrostatic potential, the and empty dictionary for thedensityandmepkeys,
respectively, is sufficient.The generated CUBE files are attached asSinglefileDataoutput nodes in thecubegennamespace, with theorbitals,densityandmepsubnamespaces. For theorbitalssubnamespace, the label is determined by the corresponding
molecular orbital index:print(results['cubegen']['orbitals']['mo_5'].get_content())Orbitalvalueinrealspace(1/Bohr^3)PySCFVersion:2.1.1Date:SunApr215:59:1920232-3.000000-3.000000-4.067676400.1538460.0000000.000000400.0000000.1538460.000000400.0000000.0000000.20859970.0000000.0000000.0000001.06767670.0000000.0000000.000000-1.067676-1.10860E-04-1.56874E-04-2.16660E-04-2.92099E-04-3.84499E-04-4.94299E-04-6.20809E-04-7.62048E-04-9.14724E-04-1.07439E-03-1.23579E-03-1.39331E-03...WarningPySCF is known to fail when computing the MEP with DHF, DKS, GHF and GKS references.Restarting unconverged calculationsThe plugin will automatically instruct PySCF to write a checkpoint file. If the calculation did not converge, it will
finish with exit status410and the checkpoint file is attached as aSinglefileDataas thecheckpointoutput node.
This node can then be passed as input to a new calculation to restart from the checkpoint:failed_calculation=load_node(IDENTIFIER)builder=failed_calculation.get_builder_restart()builder.checkpoint=failed_calculation.outputs.checkpointsubmit(builder)The plugin will write the checkpoint file of the failed calculation to the working directory such that PySCF can start
of from there.Post-processingThePyscfCalculationplugin does not support all PySCF functionality; it aims to support most functionality that is
computationally intensive, as in this case it is important to be able to offload these calculations as a calcjob on a
remote compute resource. Most post-processing utilities are computationally inexpensive, and since the API is in Python,
they can be called directly in AiiDA workflows ascalcfunctions. Many PySCF utilities require themodelof the
system as an argument, where model is the main object used in PySCF, i.e. the object assigned to themean_fieldvariable in the following:frompyscfimportscfmean_field=scf.RHF(..)mean_field.kernel()Thekernelmethod is often computationally expensive, but its results (stored on the model object) are lost when thePyscfCalculationfinishes as the Python interpreter of the calcjob shuts down and so themean_fieldobject no longer
exists. This would force post-processing code to reconstruct the model from scratch and rerun the expensive kernel.
Therefore, thePyscfCalculationserializes the PySCF model that was computed and stores it as aPickledDataoutput
node with the link labelmodelin the provenance graph. This allows recreating the model in another Python interpreter
and have it ready to be used for post-processing:frompyscf.hessianimportthermonode=load_node()# Load the completed `PyscfCalculation`mean_field=node.outputs.model.load()# Reconstruct the model by calling the `load()` methodhessian=mean_field.Hessian().kernel()freq_info=thermo.harmonic_analysis(mean_field.mol,hessian)Automatic error recoveryThere are a variety of reasons why a PySCF calculation may not finish with the intended result. Examples are the
self-consistent field cycle not converging or the job getting killed by the scheduler because it ran out of the
requested walltime. ThePyscfBaseWorkChainis designed to try and automatically recover from these kinds of errors
whenever it can potentially be handled. It is a simple wrapper around thePyscfCalculationplugin that automatically
restarts a newPyscfCalculationif the previous iterations failed. Launching aPyscfBaseWorkChainis almost
identical to launching aPyscfCalculationdirectly; the inputs just have to be "nested" inside thepyscfnamespace:fromaiida.engineimportrunfromaiida.ormimportDict,StructureData,load_code,load_nodefromaiida_pyscf.workflows.baseimportPyscfBaseWorkChainfromase.buildimportmoleculebuilder=PyscfBaseWorkChain.get_builder()builder.pyscf.code=load_code('pyscf')builder.pyscf.structure=StructureData(ase=molecule('H2O'))builder.pyscf.parameters=Dict({'mean_field':{'method':'RHF','max_cycle':3,}})results,node=run.get_node(builder)In this example, we purposefully set the maximum number of iterations in the self-consistent field cycle to 3
('mean_field.max_cycle' = 3), which will cause the first iteration to fail to reach convergence. ThePyscfBaseWorkChaindetects the error, indicated by exit status410on thePyscfCalculation, and automatically
restarts the calculation from the saved checkpoint. After three iterations, the calculation converges:$verdiprocessstatusIDENTIFIERPyscfBaseWorkChain<30126> Finished [0] [2:results]├── PyscfCalculation<30127> Finished [410]├── PyscfCalculation<30132> Finished [410]└── PyscfCalculation<30137> Finished [0]The following error modes are currently handled by thePyscfBaseWorkChain:120: Out of walltime: The calculation will be restarted from the last checkpoint if available, otherwise the work
chain is aborted140: Node failure: The calculation will be restarted from the last checkpoint410: Electronic convergence not achieved: The calculation will be restarted from the last checkpoint500: Ionic convergence not achieved: The geometry optmizization did not converge, calculation will be restarted from
the last checkpoint and structurePickled modelThe main objective of aPyscfCalculationis to solve the mean-field problem for a given structure. The results of
this, often computationally expensive, step are stored in themean_field_runvariable in the main script:mean_field=scf.RHF(structure)density_matrix=mean_field.from_chk('restart.chk')mean_field_run=mean_field.run(density_matrix)Themean_field_runobject can be used for a number of further post-processing operations implemented in PySCF. To keep
thePyscfCalculationinterface simple, not all of this functionality is supported. However, as soon as the calculation
job finishes, themean_field_runvariable is lost and can no longer be accessed to be used for further processing.As a workaround, thePyscfCalculationwill"pickle"themean_field_runobject and attach it as themodeloutput to the calculation. Themodeloutput node can be
"unpickled" to restore the originalmean_field_runobject such that it can be used for further processing:fromaiida.engineimportruninputs={}results,node=run.get_node(PyscfCalculation,**inputs)mean_field=node.outputs.model.load()print(mean_field.e_tot)WarningFor certain cases, the calculation may fail to pickle the model and will except. In this case, one can set
thepickle_modelinput to thePyscfCalculationtoFalse.ContributingThis project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License
Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For
details, visithttps://cla.opensource.microsoft.com.When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate
the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only
need to do this once across all repos using our CLA.This project has adopted theMicrosoft Open Source Code of Conduct.
For more information see theCode of Conduct FAQor contactopencode@microsoft.comwith any additional questions or comments.TrademarksThis project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks
or logos is subject to and must followMicrosoft's Trademark & Brand Guidelines.
Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft
sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies.