mirror of
https://github.com/QuantumPackage/qp2.git
synced 2024-11-07 05:53:37 +01:00
added some providers and the first tutorial for plugins
This commit is contained in:
parent
7bc6b88854
commit
9d3743e530
@ -22,6 +22,8 @@ we will go through a series of examples that allow you to do the following thing
|
|||||||
IV) print out the one- and two-electron rdms,
|
IV) print out the one- and two-electron rdms,
|
||||||
V) obtain the AOs and MOs on the DFT grid, together with the density,
|
V) obtain the AOs and MOs on the DFT grid, together with the density,
|
||||||
|
|
||||||
|
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,
|
i) you READ THIS FILE UNTIL THE END in order to get the big picture and vocabulary,
|
||||||
ii) you go to the directory qp2/plugins/tuto_plugins/ and you will find detailed tuto there for each of the 5 examples.
|
ii) you go to the directory qp2/plugins/tuto_plugins/ and you will find detailed tuto there for each of the 5 examples.
|
||||||
@ -32,7 +34,7 @@ The first thing to do is to be in the QPSH mode: you execute the qp2/bin/qpsh sc
|
|||||||
the environement variables and allows for the completion of command lines in bash (that is an AMAZING feature :)
|
the environement variables and allows for the completion of command lines in bash (that is an AMAZING feature :)
|
||||||
|
|
||||||
Then, you need to known where you want to create your plugin, and what is the name of the plugin.
|
Then, you need to known where you want to create your plugin, and what is the name of the plugin.
|
||||||
!!!! WARINING: The plugins are NECESSARILY located in qp2/plugins/ !!!!
|
!!!! WARNING: The plugins are NECESSARILY located in qp2/plugins/ !!!!
|
||||||
Ex: If you want to create a plugin named "my_fancy_plugin" in the directory plugins/plugins_test/,
|
Ex: If you want to create a plugin named "my_fancy_plugin" in the directory plugins/plugins_test/,
|
||||||
this goes with the command
|
this goes with the command
|
||||||
qp plugins create -n my_fancy_plugin -r plugins_test/
|
qp plugins create -n my_fancy_plugin -r plugins_test/
|
||||||
|
24
plugins/tuto_plugins/tuto_I/print_traces_on_e.irp.f
Normal file
24
plugins/tuto_plugins/tuto_I/print_traces_on_e.irp.f
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
program my_program
|
||||||
|
implicit none
|
||||||
|
BEGIN_DOC
|
||||||
|
! This program is there essentially to show how one can use providers in programs
|
||||||
|
END_DOC
|
||||||
|
integer :: i,j
|
||||||
|
double precision :: accu
|
||||||
|
print*,'Trace on the AO basis '
|
||||||
|
print*,trace_ao_one_e_ints
|
||||||
|
print*,'Trace on the AO basis after projection on the MO basis'
|
||||||
|
print*,trace_ao_one_e_ints_from_mo
|
||||||
|
print*,'Trace of MO integrals '
|
||||||
|
print*,trace_mo_one_e_ints
|
||||||
|
print*,'ao_num = ',ao_num
|
||||||
|
print*,'mo_num = ',mo_num
|
||||||
|
if(ao_num .ne. mo_num)then
|
||||||
|
print*,'The AO basis and MO basis are different ...'
|
||||||
|
print*,'Trace on the AO basis should not be the same as Trace of MO integrals'
|
||||||
|
print*,'Only the second one must be equal to the trace on the MO integrals'
|
||||||
|
else
|
||||||
|
print*,'The AO basis and MO basis are the same !'
|
||||||
|
print*,'All traces should coincide '
|
||||||
|
endif
|
||||||
|
end
|
32
plugins/tuto_plugins/tuto_I/print_two_e_h.irp.f
Normal file
32
plugins/tuto_plugins/tuto_I/print_two_e_h.irp.f
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
program my_program_to_print_stuffs
|
||||||
|
implicit none
|
||||||
|
BEGIN_DOC
|
||||||
|
! TODO : Put the documentation of the program here
|
||||||
|
END_DOC
|
||||||
|
integer :: i,j,k,l
|
||||||
|
double precision :: integral
|
||||||
|
double precision :: get_ao_two_e_integral, get_two_e_integral ! declaration of the functions
|
||||||
|
print*,'AO integrals, physicist notations : <i j|k l>'
|
||||||
|
do i = 1, ao_num
|
||||||
|
do j = 1, ao_num
|
||||||
|
do k = 1, ao_num
|
||||||
|
do l = 1, ao_num
|
||||||
|
integral = get_ao_two_e_integral(i, j, k, l, ao_integrals_map)
|
||||||
|
print*,i,j,k,l,integral
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
|
||||||
|
print*,'MO integrals, physicist notations : <i j|k l>'
|
||||||
|
do i = 1, mo_num
|
||||||
|
do j = 1, mo_num
|
||||||
|
do k = 1, mo_num
|
||||||
|
do l = 1, mo_num
|
||||||
|
integral = get_two_e_integral(i, j, k, l, mo_integrals_map)
|
||||||
|
print*,i,j,k,l,integral
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
end
|
111
plugins/tuto_plugins/tuto_I/traces_one_e.irp.f
Normal file
111
plugins/tuto_plugins/tuto_I/traces_one_e.irp.f
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
! This file is an example of the kind of manipulations that you can do with providers
|
||||||
|
!
|
||||||
|
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!! Main providers useful for the program !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
|
||||||
|
!!! type name
|
||||||
|
BEGIN_PROVIDER [ double precision, trace_mo_one_e_ints]
|
||||||
|
implicit none
|
||||||
|
BEGIN_DOC
|
||||||
|
! trace_mo_one_e_ints = Trace of the one-electron integrals on the MO basis
|
||||||
|
!
|
||||||
|
! = sum_i mo_one_e_integrals(i,i)
|
||||||
|
END_DOC
|
||||||
|
integer :: i
|
||||||
|
trace_mo_one_e_ints = 0.d0
|
||||||
|
do i = 1, mo_num
|
||||||
|
trace_mo_one_e_ints += mo_one_e_integrals(i,i)
|
||||||
|
enddo
|
||||||
|
END_PROVIDER
|
||||||
|
|
||||||
|
BEGIN_PROVIDER [ double precision, trace_ao_one_e_ints]
|
||||||
|
implicit none
|
||||||
|
BEGIN_DOC
|
||||||
|
! trace_ao_one_e_ints = Trace of the one-electron integrals on the AO basis taking into account the non orthogonality
|
||||||
|
!
|
||||||
|
! Be aware that the trace of an operator in a non orthonormal basis is Tr(A S^{-1}) = \sum_{m,n}(A_mn S^{-1}_mn)
|
||||||
|
!
|
||||||
|
! WARNING: it is equal to the trace on the MO basis if and only if the AO basis and MO basis
|
||||||
|
! have the same number of functions
|
||||||
|
END_DOC
|
||||||
|
integer :: i,j
|
||||||
|
double precision, allocatable :: inv_overlap_times_integrals(:,:) ! = h S^{-1}
|
||||||
|
allocate(inv_overlap_times_integrals(ao_num,ao_num))
|
||||||
|
! routine that computes the product of two matrices, you can check it with
|
||||||
|
! irpman get_AB_prod
|
||||||
|
call get_AB_prod(ao_one_e_integrals,ao_num,ao_num,s_inv,ao_num,inv_overlap_times_integrals)
|
||||||
|
! Tr(inv_overlap_times_integrals) = Tr(h S^{-1})
|
||||||
|
trace_ao_one_e_ints = 0.d0
|
||||||
|
do i = 1, ao_num
|
||||||
|
trace_ao_one_e_ints += inv_overlap_times_integrals(i,i)
|
||||||
|
enddo
|
||||||
|
!
|
||||||
|
! testing the formula Tr(A S^{-1}) = \sum_{m,n}(A_mn S^{-1}_mn)
|
||||||
|
double precision :: test
|
||||||
|
test = 0.d0
|
||||||
|
do i = 1, ao_num
|
||||||
|
do j = 1, ao_num
|
||||||
|
test += ao_one_e_integrals(j,i) * s_inv(i,j)
|
||||||
|
enddo
|
||||||
|
enddo
|
||||||
|
if(dabs(accu - trace_ao_one_e_ints).gt.1.d-12)then
|
||||||
|
print*,'Warning ! '
|
||||||
|
print*,'Something is wrong because Tr(AB) \ne sum_{mn}A_mn B_nm'
|
||||||
|
endif
|
||||||
|
END_PROVIDER
|
||||||
|
|
||||||
|
BEGIN_PROVIDER [ double precision, trace_ao_one_e_ints_from_mo]
|
||||||
|
implicit none
|
||||||
|
BEGIN_DOC
|
||||||
|
! trace_ao_one_e_ints_from_mo = Trace of the one-electron integrals on the AO basis after projection on the MO basis
|
||||||
|
!
|
||||||
|
! = Tr([SC h {SC}^+] S^{-1})
|
||||||
|
!
|
||||||
|
! = Be aware that the trace of an operator in a non orthonormal basis is = Tr(A S^{-1}) where S is the metric
|
||||||
|
! Must be equal to the trace_mo_one_e_ints
|
||||||
|
END_DOC
|
||||||
|
integer :: i
|
||||||
|
double precision, allocatable :: inv_overlap_times_integrals(:,:)
|
||||||
|
allocate(inv_overlap_times_integrals(ao_num,ao_num))
|
||||||
|
! Using the provider ao_one_e_integrals_from_mo = [SC h {SC}^+]
|
||||||
|
call get_AB_prod(ao_one_e_integrals_from_mo,ao_num,ao_num,s_inv,ao_num,inv_overlap_times_integrals)
|
||||||
|
! inv_overlap_times_integrals = [SC h {SC}^+] S^{-1}
|
||||||
|
trace_ao_one_e_ints_from_mo = 0.d0
|
||||||
|
! Computing the trace
|
||||||
|
do i = 1, ao_num
|
||||||
|
trace_ao_one_e_ints_from_mo += inv_overlap_times_integrals(i,i)
|
||||||
|
enddo
|
||||||
|
END_PROVIDER
|
||||||
|
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!! Additional providers to check some stuffs !!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
|
||||||
|
BEGIN_PROVIDER [ double precision, ao_one_e_int_no_ov_from_mo, (ao_num, ao_num) ]
|
||||||
|
BEGIN_DOC
|
||||||
|
! ao_one_e_int_no_ov_from_mo = C mo_one_e_integrals C^T
|
||||||
|
!
|
||||||
|
! WARNING : NON EQUAL TO ao_one_e_integrals due to the non orthogonality
|
||||||
|
END_DOC
|
||||||
|
call mo_to_ao_no_overlap(mo_one_e_integrals,mo_num,ao_one_e_int_no_ov_from_mo,ao_num)
|
||||||
|
END_PROVIDER
|
||||||
|
|
||||||
|
BEGIN_PROVIDER [ double precision, ao_one_e_int_no_ov_from_mo_ov_ov, (ao_num, ao_num)]
|
||||||
|
BEGIN_DOC
|
||||||
|
! ao_one_e_int_no_ov_from_mo_ov_ov = S ao_one_e_int_no_ov_from_mo S = SC mo_one_e_integrals (SC)^T
|
||||||
|
!
|
||||||
|
! EQUAL TO ao_one_e_integrals ONLY IF ao_num = mo_num
|
||||||
|
END_DOC
|
||||||
|
double precision, allocatable :: tmp(:,:)
|
||||||
|
allocate(tmp(ao_num, ao_num))
|
||||||
|
call get_AB_prod(ao_overlap,ao_num,ao_num,ao_one_e_int_no_ov_from_mo,ao_num,tmp)
|
||||||
|
call get_AB_prod(tmp,ao_num,ao_num,ao_overlap,ao_num,ao_one_e_int_no_ov_from_mo_ov_ov)
|
||||||
|
END_PROVIDER
|
||||||
|
|
||||||
|
BEGIN_PROVIDER [ double precision, c_t_s_c, (mo_num, mo_num)]
|
||||||
|
implicit none
|
||||||
|
BEGIN_DOC
|
||||||
|
! C^T S C = should be the identity
|
||||||
|
END_DOC
|
||||||
|
call get_AB_prod(mo_coef_transp,mo_num,ao_num,S_mo_coef,mo_num,c_t_s_c)
|
||||||
|
END_PROVIDER
|
||||||
|
|
@ -1,14 +1,15 @@
|
|||||||
======================================
|
=====================================================================
|
||||||
Tutorial for plugin I: One-e integrals
|
Tutorial for plugin I: One-e integrals (duration: 20 minutes at most)
|
||||||
======================================
|
=====================================================================
|
||||||
|
|
||||||
!!! Requirements:
|
Requirements
|
||||||
a) you know how to create an EZFIO file and run calculations with QP
|
------------
|
||||||
|
a) 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 in the sto-3g from the file H2.xyz in plugins/tuto_plugins,
|
b) You have an EZFIO file with MOs created (with the 'scf' executable for instance).
|
||||||
and you have run an HF calculation giving an energy of -1.116759 a.u.,
|
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 be,
|
c) 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.
|
d) You have READ the ../README.rst file to HAVE THE VOCABULARY.
|
||||||
|
|
||||||
Our goals:
|
Our goals:
|
||||||
----------
|
----------
|
||||||
@ -22,11 +23,11 @@ I) Starting: 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".
|
The name of the plugin will be "plugin_I", and its location is 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
|
qp plugins create -n plugin_I -r tuto_plugins
|
||||||
Then to 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"
|
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.
|
ii) a "README.rst" file that you can AND SHOULD modify in order to document what is doing the plugin.
|
||||||
@ -78,8 +79,8 @@ The variables that we need are
|
|||||||
ao_one_e_integrals
|
ao_one_e_integrals
|
||||||
mo_one_e_integrals
|
mo_one_e_integrals
|
||||||
You can check them with
|
You can check them with
|
||||||
irpman ao_one_e_integral
|
irpman ao_one_e_integrals
|
||||||
irpman mo_one_e_integral
|
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 modify the executable such that it prints out the integrals.
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ We will modify the 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 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" in your plugin.
|
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.
|
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 check these variables with irpman !
|
You can check these variables with irpman !
|
||||||
If you recompile using "ninja" as before, and another executable has been created "print_one_e_h".
|
If you recompile using "ninja" as before, and another executable has been created "print_one_e_h".
|
||||||
@ -95,3 +96,31 @@ Then, you can run the program on the ezfio file by doing
|
|||||||
qp run print_one_e_h
|
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.
|
||||||
|
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.
|
||||||
|
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
|
||||||
|
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.
|
||||||
|
Then just run the program
|
||||||
|
qp run print_two_e_h
|
||||||
|
and it will print all the things you want :)
|
||||||
|
|
||||||
|
VI) Creating new providers and a program to print them
|
||||||
|
------------------------------------------------------
|
||||||
|
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.
|
||||||
|
In the file "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.
|
||||||
|
Copy these two files in your plugin and recompile to execute it.
|
||||||
|
|
||||||
|
Execute the program print_traces_on_e and check for the results !
|
||||||
|
@ -45,3 +45,13 @@ BEGIN_PROVIDER [ double precision, ao_one_e_integrals_imag,(ao_num,ao_num)]
|
|||||||
|
|
||||||
END_PROVIDER
|
END_PROVIDER
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN_PROVIDER [ double precision, ao_one_e_integrals_from_mo, (ao_num, ao_num)]
|
||||||
|
implicit none
|
||||||
|
BEGIN_DOC
|
||||||
|
! Integrals of the one e hamiltonian obtained from the integrals on the MO basis
|
||||||
|
!
|
||||||
|
! WARNING : this is equal to ao_one_e_integrals only if the AO and MO basis have the same number of functions
|
||||||
|
END_DOC
|
||||||
|
call mo_to_ao(mo_one_e_integrals,mo_num,ao_one_e_integrals_from_mo,ao_num)
|
||||||
|
END_PROVIDER
|
||||||
|
@ -166,6 +166,10 @@
|
|||||||
|
|
||||||
if(frozen_orb_scf)then
|
if(frozen_orb_scf)then
|
||||||
integer :: iorb,jorb
|
integer :: iorb,jorb
|
||||||
|
! active|core|active
|
||||||
|
!active | | 0 |
|
||||||
|
!core | 0 | | 0
|
||||||
|
!active | | 0 |
|
||||||
do i = 1, n_core_orb
|
do i = 1, n_core_orb
|
||||||
iorb = list_core(i)
|
iorb = list_core(i)
|
||||||
do j = 1, n_act_orb
|
do j = 1, n_act_orb
|
||||||
|
@ -2041,3 +2041,22 @@ subroutine get_A_squared(A,n,A2)
|
|||||||
double precision, intent(out):: A2(n,n)
|
double precision, intent(out):: A2(n,n)
|
||||||
call dgemm('N','N',n,n,n,1.d0,A,size(A,1),A,size(A,1),0.d0,A2,size(A2,1))
|
call dgemm('N','N',n,n,n,1.d0,A,size(A,1),A,size(A,1),0.d0,A2,size(A2,1))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
subroutine get_AB_prod(A,n,m,B,l,AB)
|
||||||
|
implicit none
|
||||||
|
BEGIN_DOC
|
||||||
|
! AB = A B where A is n x m, B is m x l. Use the dgemm routine
|
||||||
|
END_DOC
|
||||||
|
double precision, intent(in) :: A(n,m),B(m,l)
|
||||||
|
integer, intent(in) :: n,m,l
|
||||||
|
double precision, intent(out):: AB(n,l)
|
||||||
|
if(size(A,2).ne.m.or.size(B,1).ne.m)then
|
||||||
|
print*,'error in get_AB_prod ! '
|
||||||
|
print*,'matrices do not have the good dimension '
|
||||||
|
print*,'size(A,2) = ',size(A,2)
|
||||||
|
print*,'size(B,1) = ',size(B,1)
|
||||||
|
print*,'m = ',m
|
||||||
|
stop
|
||||||
|
endif
|
||||||
|
call dgemm('N','N',n,l,m,1.d0,A,size(A,1),B,size(B,1),0.d0,AB,size(AB,1))
|
||||||
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user