Geometry optimization is however a surprising hard problem to do, and writing algorithms from scratch might result in poorly behaved optimizations.
So instead let us an open-source library.
One of the freely available libraries for doing geometry optimization is geomeTRIC.
Luckily, geomeTRIC has an example of how to use it using a custom-made energy and gradient function.
Let us now modify this one to work with the Hellmann-Feynman forces from PySCF.
The first step is define the custom model:
The model for this case takes the input of the coordinates and the atom symbols, such that PySCF can construct the it’s molecule object.
The energy and the forces are then calculated (forces are calculated as describe previously.
In the end the function only returns the total energy and the total forces on each nuclei.
From geomeTRIC it is expected that model() function will only take the coordinates as input, this will be fixed later in the script using functools.partial.
Next the CustomEngine() class is constructed:
This one is identical to the one in the geomeTRIC example, execpt that the __init__ now takes in the variable model_.
At last the driver call is defined:
What should be noted here is that ‘model’ is defined as ‘partial(model_expanded_input, atom_symbols=molecule.elem)’, and then passed to CustomEngine().
This way model() only takes in the coordinates as argument because the atom_symbols have now been fixed as a constant.
Running this will give a total energy of -1.1515 Hartree, and an interatomic distance of 1.4408 bohr.
This is the same as was found using gradient descent (within convergence thresholds), -1.1515 Hartree and 1.4417 bohr.
If you enjoyed this post you can donate a coffee , if you like :)