added properly the first tuto!
continuous-integration/drone/push Build is failing Details

This commit is contained in:
eginer 2024-03-22 17:29:32 +01:00
parent dd2f0a2c07
commit e0af6d8425
3 changed files with 175 additions and 81 deletions

View File

@ -40,6 +40,7 @@
programmers_guide/ezfio programmers_guide/ezfio
programmers_guide/plugins programmers_guide/plugins
programmers_guide/plugins_tuto_intro programmers_guide/plugins_tuto_intro
programmers_guide/plugins_tuto_I
programmers_guide/new_ks programmers_guide/new_ks
programmers_guide/index programmers_guide/index

View File

@ -2,12 +2,12 @@
Tutorial for creating a plugin Tutorial for creating a plugin
============================== ==============================
Introduction: what is a plugin, and what this tuto will be about ? Introduction: what is a plugin, and what tutorial will be about ?
================================================================== =================================================================
The |QP| is split into two kinds of routines/global variables (i.e. *providers*): The |QP| is split into two kinds of routines/global variables (i.e. *providers*):
i) the **core modules** locatedin qp2/src/, which contains all the bulk of a quantum chemistry software (integrals, matrix elements between Slater determinants, linear algebra routines, DFT stuffs etc..) 1) the **core modules** locatedin qp2/src/, which contains all the bulk of a quantum chemistry software (integrals, matrix elements between Slater determinants, linear algebra routines, DFT stuffs etc..)
ii) the **plugins** which are external routines/*providers* connected to the qp2/src/ routines/*providers*. 2) the **plugins** which are external routines/*providers* connected to the qp2/src/ routines/*providers*.
More precisely, a **plugin** of the |QP| is a directory where you can create routines, More precisely, a **plugin** of the |QP| is a directory where you can create routines,
providers and executables that use all the global variables/functions/routines already created providers and executables that use all the global variables/functions/routines already created
@ -16,24 +16,24 @@ in the modules of qp2/src or in other plugins.
Instead of giving a theoretical lecture on what is a plugin, Instead of giving a theoretical lecture on what is a plugin,
we will go through a series of examples that allow you to do the following thing: we will go through a series of examples that allow you to do the following thing:
i) print out **one- and two-electron integrals** on the AO/MO basis, creates two providers which manipulate these objects, print out these providers, 1) print out **one- and two-electron integrals** on the AO/MO basis, creates two providers which manipulate these objects, print out these providers,
ii) browse the **Slater determinants stored** in the |EZFIO| wave function and compute their matrix elements, 2) browse the **Slater determinants stored** in the |EZFIO| wave function and compute their matrix elements,
iii) build the **Hamiltonian matrix** and **diagonalize** it either with **Lapack or Davidson**, 3) build the **Hamiltonian matrix** and **diagonalize** it either with **Lapack or Davidson**,
iv) print out the **one- and two-electron rdms**, 4) print out the **one- and two-electron rdms**,
v) obtain the **AOs** and **MOs** on the **DFT grid**, together with the **density**, 5) obtain the **AOs** and **MOs** on the **DFT grid**, together with the **density**,
How the tutorial will be done How the tutorial will be done
----------------------------- -----------------------------
This tuto is as follows: This tuto is as follows:
i) you **READ THIS FILE UNTIL THE END** in order to get the big picture and vocabulary, 1) you **READ THIS FILE UNTIL THE END** in order to get the big picture and vocabulary,
ii) you go to the directory :file:`qp2/plugins/tuto_plugins/` and you will find detailed tutorials for each of the 5 examples. 2) you go to the directory :file:`qp2/plugins/tuto_plugins/` and you will find detailed tutorials for each of the 5 examples.
Creating a plugin: the basic Creating a plugin: the basic
---------------------------- ----------------------------
@ -77,23 +77,23 @@ Then, to create the plugin of your dreams, the two questions you need to answer
The routine :c:func:`lapack_diagd` (which diagonalises a real hermitian matrix) is located in the file The routine :c:func:`lapack_diagd` (which diagonalises a real hermitian matrix) is located in the file
:file:`qp2/src/utils/linear_algebra.irp.f` :file:`qp2/src/utils/linear_algebra.irp.f`
therefore it "belongs" to the module "utils" therefore it "belongs" to the module :ref:`module_utils`
The routine :c:func:`ao_to_mo` (which converts a given matrix A from the AO basis to the MO basis) is located in the file The routine :c:func:`ao_to_mo` (which converts a given matrix A from the AO basis to the MO basis) is located in the file
:file:`qp2/src/mo_one_e_ints/ao_to_mo.irp.f` :file:`qp2/src/mo_one_e_ints/ao_to_mo.irp.f`
therefore it "belongs" to the module "mo_one_e_ints" therefore it "belongs" to the module :ref:`module_mo_one_e_ints`
The provider :c:data:`ao_one_e_integrals` (which is the integrals of one-body part of H on the AO basis) is located in the file The provider :c:data:`ao_one_e_integrals` (which is the integrals of one-body part of H on the AO basis) is located in the file
:file:`qp2/src/mo_one_e_ints/ao_to_mo.irp.f` :file:`qp2/src/ao_one_e_ints/ao_one_e_ints.irp.f`
therefore it belongs to the module "mo_one_e_ints" therefore it belongs to the module :ref:`module_ao_one_e_ints`
The provider :c:data:`one_e_dm_mo_beta_average` (which is the state average beta density matrix on the MO basis) is located in the file The provider :c:data:`one_e_dm_mo_beta_average` (which is the state average beta density matrix on the MO basis) is located in the file
:file:`qp2/src/determinants/density_matrix.irp.f` :file:`qp2/src/determinants/density_matrix.irp.f`
therefore it belongs to the module "determinants" therefore it belongs to the module :ref:`module_determinants`
To import all the variables that you need, you just need to write the name of the plugins in the :file:`NEED` file . To import all the variables that you need, you just need to write the name of the plugins in the :file:`NEED` file .
To import all the variables/routines of the module "utils", "determinants" and "mo_one_e_ints", the :file:`NEED` file you will need is simply the following: To import all the variables/routines of the module :ref:`module_utils`, :ref:`module_determinants` and :ref:`module_mo_one_e_ints`, the :file:`NEED` file you will need is simply the following:
.. code:: bash .. code:: bash
@ -121,6 +121,7 @@ Example: execute the following command line :
Then all the information you need on :c:data:`ao_one_e_integrals` will appear on the screen. Then all the information you need on :c:data:`ao_one_e_integrals` will appear on the screen.
This includes This includes
- **where** the provider is created, (*i.e.* the actual file where the provider is designed) - **where** the provider is created, (*i.e.* the actual file where the provider is designed)
- the **type** of the provider (*i.e.* a logical, integer etc ...) - the **type** of the provider (*i.e.* a logical, integer etc ...)
- the **dimension** if it is an array, - the **dimension** if it is an array,

View File

@ -1,126 +1,218 @@
===================================================================== =============================================
Tutorial for plugin I: One-e integrals (duration: 20 minutes at most) Tuto I: One- and two-e integrals (20 minutes)
===================================================================== =============================================
Requirements Requirements
------------ ------------
a) You know how to create an EZFIO file and run calculations with QP 1) You know how to create an |EZFIO| file and run calculations with |QP| (check the tuto: `<https://quantumpackage.github.io/qp2/post/hartree-fock/>`_),
(check the tuto: `<https://quantumpackage.github.io/qp2/post/hartree-fock/>`),
b) You have an EZFIO file with MOs created (with the 'scf' executable for instance). 2) You have an |EZFIO| file with MOs created (with the :ref:`scf` executable for instance). As we are going to print out some integrals, don't take a too large system/basis (Ex: H2, cc-pVDZ is ok :)
As we are going to print out some integrals, don't take a too large system/basis (Ex: H2, cc-pVDZ is ok :)
c) You made an qp set_file YOUR_EZFIO_FILE_FOR_H2 in order to work on that ezfio folder, 3) You made an qp set_file YOUR_EZFIO_FILE_FOR_H2 in order to work on that ezfio folder.
d) You have READ the ../README.rst file to HAVE THE VOCABULARY.
4) You have READ the :file:`qp2/plugins/README.rst` file to HAVE THE **VOCABULARY**.
Our goals: Our goals:
---------- ----------
We want to create a plugin to do the following things: We want to create a plugin to do the following things:
a) print out one- and two-electron integrals on the AO/MO basis, 1) print out one- and two-electron integrals on the AO/MO basis,
b) creates two providers which manipulate these objects,
c) print out these providers,
I) Starting: creating the plugin 2) creates two providers which manipulate these objects,
--------------------------------
3) print out these providers.
I) Getting started: creating the plugin
---------------------------------------
We will go step-by-step through these plugins. We will go step-by-step through these plugins.
The name of the plugin will be "plugin_I", and its location is in "tuto_plugins". We will create a plugin named "plugin_I", and its location will be in "tuto_plugins".
Therefore to create the plugin, we do: Therefore to create the plugin, we do:
qp plugins create -n plugin_I -r tuto_plugins .. code:: bash
qp plugins create -n plugin_I -r tuto_plugins
Then do an "ls" in qp2/plugins/tuto_plugins/ and you will find a directory called "plugin_I". Then do an "ls" in qp2/plugins/tuto_plugins/ and you will find a directory called "plugin_I".
In that directory you will find: In that directory you will find:
i) a "NEED" file that will eventually contain all the other modules/plugins needed by our "plugin_I"
ii) a "README.rst" file that you can AND SHOULD modify in order to document what is doing the plugin. 1) a :file:`NEED` file that will eventually contain all the other modules/plugins needed by our "plugin_I",
iii) a "plugin_I.irp.f" file that is a program to be compiled and just printing "Hello world"
2) a :file:`README.rst` file that you can and **SHOULD** modify in order to **DOCUMENT** what is doing the plugin,
3) a :file:`plugin_I.irp.f` file that is a program to be compiled and just printing "Hello world"
II) Specifying the dependencies II) Specifying the dependencies
------------------------------- -------------------------------
The next step is to know what are the other modules/plugins that we need to do what we want. The next step is to know what are the other modules/plugins that we need to do what we want.
We need here We need here
a) the one-electron integrals on the AO basis, which are computed in qp2/src/ao_one_e_ints/
b) the one-electron integrals on the MO basis, which are computed in qp2/src/mo_one_e_ints/ a) the one-electron integrals on the AO basis, which are computed in :file:`qp2/src/ao_one_e_ints/`
c) the two-electron integrals on the AO basis, which are computed in qp2/src/ao_two_e_ints/
d) the two-electron integrals on the MO basis, which are computed in qp2/src/mo_two_e_ints/ b) the one-electron integrals on the MO basis, which are computed in :file:`qp2/src/mo_one_e_ints/`
c) the two-electron integrals on the AO basis, which are computed in :file:`qp2/src/ao_two_e_ints/`
d) the two-electron integrals on the MO basis, which are computed in :file:`qp2/src/mo_two_e_ints/`
Therefore, we will need the following four modules: Therefore, we will need the following four modules:
a) ao_one_e_ints
b) mo_one_e_ints a) ao_one_e_ints
c) ao_two_e_ints b) mo_one_e_ints
d) mo_two_e_ints c) ao_two_e_ints
d) mo_two_e_ints
You can then create the following "NEED" file by executing the following command You can then create the following "NEED" file by executing the following command
$ cat <<EOF > NEED
ao_one_e_ints .. code:: bash
mo_one_e_ints
ao_two_e_ints cat <<EOF > NEED
mo_two_e_ints ao_one_e_ints
EOF mo_one_e_ints
ao_two_e_ints
mo_two_e_ints
EOF
II) Installing the plugin II) Installing the plugin
------------------------- -------------------------
Now that we have specified the various depenencies we need now to INSTALL the plugin, which means to create the equivalent of a Makefile for the compilation. Now that we have specified the various depenencies we need now to INSTALL the plugin, which means to create the equivalent of a Makefile for the compilation.
To do it we simply do To do it we simply do
$ qp plugins install plugin_I
.. code:: bash
qp plugins install plugin_I
III) Compiling the void plugin III) Compiling the void plugin
------------------------------ ------------------------------
It is customary to compile first your "void" plugin, void in the sense that it does not contain anything else than the program printing "Hello world". It is customary to compile first your "void" plugin, void in the sense that it does not contain anything else than the program printing "Hello world".
To do so, just go in the plugin and execute the following command To do so, just go in the plugin and execute the following command
$ ninja
.. code:: bash
ninja
It does a lot of stuffs, but it must conclude with something like It does a lot of stuffs, but it must conclude with something like
"
make: Leaving directory 'SOME_PATH_TOWARD_YOUR_QP2_DIRECTORY/qp2/ocaml' .. code:: bash
"
make: Leaving directory 'SOME_PATH_TOWARD_YOUR_QP2_DIRECTORY/qp2/ocaml'
Since that it has compiled, an executable "plugin_I" has been created. Since that it has compiled, an executable "plugin_I" has been created.
Also, if you make "ls" in the "plugin_I" you will notice that many symbolink links have been created, and among which the four modules that you included in the NEED file. Also, if you make "ls" in the "plugin_I" you will notice that many symbolink links have been created, and among which the four modules that you included in the NEED file.
All the other modules (Ex:"ao_basis", "utils") are here because they are need by some of the four modules that you need.
All the other modules (Ex::ref:`module_ao_basis`, :ref:`module_utils`) are here because they are need by some of the four modules that you need.
The variables that we need are The variables that we need are
ao_one_e_integrals
mo_one_e_integrals :data:`ao_one_e_integrals`
:data:`mo_one_e_integrals`
You can check them with You can check them with
irpman ao_one_e_integrals
irpman mo_one_e_integrals .. code:: bash
irpman ao_one_e_integrals
.. code:: bash
irpman mo_one_e_integrals
in order to get some information on where they are created, and many more information. in order to get some information on where they are created, and many more information.
We will modify the executable such that it prints out the integrals. We will now create an executable such that it prints out the integrals.
IV) Printing out the one-electron integrals IV) Printing out the one-electron integrals
-------------------------------------------- --------------------------------------------
We will create a program that will print out the one-electron integrals on the AO and MO basis. We will now create a program that will print out the one-electron integrals on the AO and MO basis.
You can then copy the file "print_one_e_h.irp.f" located in "plugins/tuto_plugins/tuto_I" in your plugin.
In the file you will see that we simply browse the two arrays "ao_one_e_integrals" and "mo_one_e_integrals", which are global variables (providers) and we browse them until either "ao_num" or "mo_num" which are also providers representing the number of AOs or MOs. You can then copy the file :file:`qp2/plugins/tuto_plugins/tuto_I/print_one_e_h.irp.f` in your plugin.
You can check these variables with irpman !
If you recompile using "ninja" as before, and another executable has been created "print_one_e_h". In this file you will see that we simply browse the two arrays :data:`ao_one_e_integrals` and :data:`mo_one_e_integrals`, which are the providers and we browse them until either :data:`ao_num` or :data:`mo_num` which are also providers representing the number of AOs or MOs.
.. seealso::
You can check these variables with :command:`irpman` !
If you recompile using |ninja| as before, and another executable has been created "print_one_e_h".
Then, you can run the program on the ezfio file by doing Then, you can run the program on the ezfio file by doing
qp run print_one_e_h
.. code:: bash
qp run print_one_e_h
and will print out the data you need :) and will print out the data you need :)
By the way, as the file "plugin_I.irp.f" contains nothing but a "Hello world" print, you can simply remove it if you want. By the way, as the file :file:`plugin_I.irp.f` contains nothing but a "Hello world" print, you can simply remove it if you want.
V) Printing out the two-electron integrals V) Printing out the two-electron integrals
------------------------------------------ ------------------------------------------
We will now create a file that prints out the two-electron integrals in the AO and MO basis. We will now create a file that prints out the two-electron integrals in the AO and MO basis.
These can be accessed with the following subroutines : These can be accessed with the following subroutines :
+) get_ao_two_e_integral for the AO basis
+) get_two_e_integral for the MO basis 1- :c:func:`get_ao_two_e_integral` for the AO basis
check them with irpman !
To print the two-electron integrals, you can copy the file "print_two_e_h.irp.f" in your plugin and recompile. 2- :c:func:`get_two_e_integral` for the MO basis
.. seealso::
check them with irpman !
To print the two-electron integrals, you can copy the file :file:`qp2/plugins/tuto_plugins/tuto_I/print_two_e_h.irp.f` in your plugin and recompile with |ninja|.
Then just run the program Then just run the program
qp run print_two_e_h
.. code:: bash
qp run print_two_e_h
and it will print all the things you want :) and it will print all the things you want :)
VI) Creating new providers and a program to print them VI) Creating new providers and a program to print them
------------------------------------------------------ ------------------------------------------------------
We will now create new providers that manipulates the objects that we just printed. We will now create new providers that manipulates the objects that we just printed.
As an example, we will compute the trace of the one electron integrals in the AO and MO basis. As an example, we will compute the trace of the one electron integrals in the AO and MO basis.
In the file "traces_one_e.irp.f" you will find the several new providers among which In the file :file:`qp2/plugins/tuto_plugins/tuto_I/traces_one_e.irp.f` you will find the several new providers among which
a) trace_mo_one_e_ints : simply the sum of the diagonal matrix element of the one-electron integrals
b) trace_ao_one_e_ints : the corresponding trace on the AO basis : Sum(m,n) S^{-1}_{mn} h_{mn}
c) trace_ao_one_e_ints_from_mo : the trace on the AO basis with the integrals obtained first from the MO basis
As explained in these files, "trace_mo_one_e_ints" is equal to "trace_ao_one_e_ints" only if the number of AO basis functions is equal to the number of MO basis functions, which means if you work with cartesian functions.
(You can check with "qp create_ezfio -h" for the option to create an EZFIO with cartesian basis functions)
In the file "print_traces_on_e.irp.f" you will find an example of executable that prints out the various providers. 1- :c:data:`trace_mo_one_e_ints` : simply the sum of the diagonal matrix element of the one-electron integrals
2- :c:data:`trace_ao_one_e_ints` : the corresponding trace on the AO basis
.. math::
\text{Tr}({\bf h}{\bf S}^{-1}) = \sum_{m,n} S^{-1}_{mn} h_{mn}
3- :c:data:`trace_ao_one_e_ints_from_mo` : the trace on the AO basis with the integrals obtained first from the MO basis
.. math::
\text{Tr}({\bf \tilde{h}}{\bf S}^{-1}) = \text{Tr}\big({\bf SC h}({\bf SC }^T){\bf S}^{-1}\big)
Just copy the :file:`qp2/plugins/tuto_plugins/tuto_I/traces_one_e.irp.f` in your plugin and recompile.
.. seealso::
Once it has compiled, check your new providers with :command:`irpman` !
As explained in the files :file:`qp2/plugins/tuto_plugins/tuto_I/traces_one_e.irp.f` and :file:`qp2/plugins/tuto_plugins/tuto_I/print_traces_on_e.irp.f`, :c:data:`trace_mo_one_e_ints` is equal to :c:data:`trace_ao_one_e_ints` only if the number of AO basis functions is equal to the number of MO basis functions, which means if you work with cartesian functions.
.. seealso::
You can check with :command:`qp create_ezfio -h` for the option to create an |EZFIO| with cartesian basis functions
In the file :file:`qp2/plugins/tuto_plugins/tuto_I/print_traces_on_e.irp.f` you will find an example of executable that prints out the various providers.
Copy these two files in your plugin and recompile to execute it. Copy these two files in your plugin and recompile to execute it.
Execute the program print_traces_on_e and check for the results ! Execute the program print_traces_on_e and check for the results with
.. code:: bash
qp run print_traces_on_e
The code in :file:`qp2/plugins/tuto_plugins/tuto_I/print_traces_on_e.irp.f` should be easy to read, I let the reader interpret it.