9
1
mirror of https://github.com/QuantumPackage/qp2.git synced 2024-10-08 08:57:19 +02:00

Merge branch 'dev-stable' of github.com:QuantumPackage/qp2 into dev-stable

This commit is contained in:
Anthony Scemama 2023-05-10 10:12:18 +02:00
commit 0272c6489a
104 changed files with 25262 additions and 412 deletions

View File

@ -46,7 +46,7 @@ def main(arguments):
append_bats(dirname, filenames)
else:
for (dirname, _, filenames) in os.walk(os.getcwd(), followlinks=False):
if "IRPF90_temp" not in dirname:
if "IRPF90_temp" not in dirname and "external" not in dirname:
append_bats(dirname, filenames)
l_bats = [y for _, y in sorted(l_bats)]
@ -67,6 +67,7 @@ def main(arguments):
os.system(test+" python3 bats_to_sh.py "+bats_file+
"| bash")
else:
# print(" ".join(["bats", "--verbose-run", "--trace", bats_file]))
subprocess.check_call(["bats", "--verbose-run", "--trace", bats_file], env=os.environ)

View File

@ -110,6 +110,11 @@ function qp()
unset COMMAND
;;
"test")
shift
qp_test $@
;;
*)
which "qp_$1" &> /dev/null
if [[ $? -eq 0 ]] ; then
@ -183,7 +188,7 @@ _qp_Complete()
;;
esac;;
set_file)
COMPREPLY=( $(compgen -W "$(for i in * ; do [[ -f ${i}/ezfio/.version ]] && echo $i ; done)" -- ${cur} ) )
COMPREPLY=( $(compgen -W "$(for i in $(find . -name ezfio | sed 's/ezfio$/.version/') ; do [[ -f $i ]] && echo ${i%/.version} ; done)" -- ${cur} ) )
return 0
;;
plugins)
@ -215,10 +220,15 @@ _qp_Complete()
return 0
;;
esac;;
test)
COMPREPLY=( $(compgen -W "-v -a " -- $cur ) )
return 0
;;
*)
COMPREPLY=( $(compgen -W 'plugins set_file \
unset_file man \
create_ezfio \
test \
convert_output_to_ezfio \
-h update' -- $cur ) )

View File

@ -0,0 +1,97 @@
#!/usr/bin/env bats
source $QP_ROOT/tests/bats/common.bats.sh
source $QP_ROOT/quantum_package.rc
zero () {
if [ -z "$1" ]; then echo 0.0; else echo $1; fi
}
function run() {
thresh1=1e-10
thresh2=1e-12
thresh3=1e-4
test_exe scf || skip
qp set_file $1
qp edit --check
qp reset -d
qp set_frozen_core
qp set localization localization_method boys
file="$(echo $1 | sed 's/.ezfio//g')"
energy="$(cat $1/hartree_fock/energy)"
fb_err1="$(qp run debug_gradient_loc | grep 'Max error' | tail -n 1 | awk '{print $3}')"
fb_err2="$(qp run debug_hessian_loc | grep 'Max error' | tail -n 1 | awk '{print $3}')"
qp run localization > $file.loc.out
fb_energy="$(qp run print_energy | grep -A 1 'Nuclear repulsion energy' | tail -n 1 )"
fb_c="$(cat $file.loc.out | grep 'Criterion:Core' | tail -n 1 | awk '{print $3}')i"
fb_i="$(cat $file.loc.out | grep 'Criterion:Inactive' | tail -n 1 | awk '{print $3}')"
fb_a="$(cat $file.loc.out | grep 'Criterion:Active' | tail -n 1 | awk '{print $3}')"
fb_v="$(cat $file.loc.out | grep 'Criterion:Virtual' | tail -n 1 | awk '{print $3}')"
qp reset -a
qp run scf
qp set_frozen_core
qp set localization localization_method pipek
pm_err1="$(qp run debug_gradient_loc | grep 'Max error' | tail -n 1 | awk '{print $3}')"
pm_err2="$(qp run debug_hessian_loc | grep 'Max error' | tail -n 1 | awk '{print $3}')"
qp run localization > $file.loc.out
pm_c="$(cat $file.loc.out | grep 'Criterion:Core' | tail -n 1 | awk '{print $3}')i"
pm_i="$(cat $file.loc.out | grep 'Criterion:Inactive' | tail -n 1 | awk '{print $3}')"
pm_a="$(cat $file.loc.out | grep 'Criterion:Active' | tail -n 1 | awk '{print $3}')"
pm_v="$(cat $file.loc.out | grep 'Criterion:Virtual' | tail -n 1 | awk '{print $3}')"
pm_energy="$(qp run print_energy | grep -A 1 'Nuclear repulsion energy' | tail -n 1 )"
qp set localization localization_method boys
qp reset -a
qp run scf
qp set_frozen_core
eq $energy $fb_energy $thresh1
eq $fb_err1 0.0 $thresh2
eq $fb_err2 0.0 $thresh2
eq $energy $pm_energy $thresh1
eq $pm_err1 0.0 $thresh2
eq $pm_err2 0.0 $thresh2
fb_c=$(zero $fb_c)
fb_i=$(zero $fb_i)
fb_a=$(zero $fb_a)
fb_v=$(zero $fb_v)
pm_c=$(zero $pm_c)
pm_i=$(zero $pm_i)
pm_a=$(zero $pm_a)
pm_v=$(zero $pm_v)
eq $fb_c $2 $thresh3
eq $fb_i $3 $thresh3
eq $fb_a $4 $thresh3
eq $fb_v $5 $thresh3
eq $pm_c $6 $thresh3
eq $pm_i $7 $thresh3
eq $pm_a $8 $thresh3
eq $pm_v $9 $thresh3
}
@test "b2_stretched" {
run b2_stretched.ezfio -32.1357551678876 -47.0041982094667 0.0 -223.470015856259 -1.99990778964451 -2.51376723927071 0.0 -12.8490602539275
}
@test "clo" {
run clo.ezfio -44.1624001765291 -32.4386660941387 0.0 -103.666309287187 -5.99985418946811 -5.46871580225222 0.0 -20.2480064922275
}
@test "clf" {
run clf.ezfio -47.5143398826967 -35.7206886315104 0.0 -107.043029033468 -5.99994222062230 -6.63916513458470 0.0 -19.7035159913484
}
@test "h2o2" {
run h2o2.ezfio -7.76848143170524 -30.9694344369829 0.0 -175.898343829453 -1.99990497554575 -5.62980322957485 0.0 -33.5699813186666
}
@test "h2o" {
run h2o.ezfio 0.0 -2.52317434969591 0.0 -45.3136377925359 0.0 -3.01248365356981 0.0 -22.4470831240924
}
@test "h3coh" {
run h3coh.ezfio -3.66763692804590 -24.0463089480870 0.0 -111.485948435075 -1.99714061342078 -4.89242181322988 0.0 -23.6405412057679
}
@test "n2h4" {
run n2h4.ezfio -7.46608163002070 -35.7632174051822 0.0 -305.913449004632 -1.99989326143356 -4.62496615892268 0.0 -51.5171904685553
}

View File

@ -0,0 +1,54 @@
[localization_method]
type: character*(32)
doc: Method for the orbital localization. boys: Foster-Boys, pipek: Pipek-Mezey.
interface: ezfio,provider,ocaml
default: boys
[localization_max_nb_iter]
type: integer
doc: Maximal number of iterations for the orbital localization.
interface: ezfio,provider,ocaml
default: 1000
[localization_use_hessian]
type: logical
doc: If true, it uses the trust region algorithm with the gradient and the diagonal of the hessian. Else it computes the rotation between each pair of MOs that should be applied to maximize/minimize the localization criterion. The last option is not easy to converge.
interface: ezfio,provider,ocaml
default: true
[auto_mo_class]
type: logical
doc: If true, set automatically the classes.
interface: ezfio,provider,ocaml
default: true
[thresh_loc_max_elem_grad]
type: double precision
doc: Threshold for the convergence, the localization exits when the largest element in the gradient is smaller than thresh_localization_max_elem_grad.
interface: ezfio,provider,ocaml
default: 1.e-6
[kick_in_mos]
type: logical
doc: If True, it applies a rotation of an angle angle_pre_rot between the MOs of a same mo_class before the localization.
interface: ezfio,provider,ocaml
default: true
[angle_pre_rot]
type: double precision
doc: To define the angle for the rotation of the MOs before the localization (in rad).
interface: ezfio,provider,ocaml
default: 0.1
[sort_mos_by_e]
type: logical
doc: If True, the MOs are sorted using the diagonal elements of the Fock matrix.
interface: ezfio,provider,ocaml
default: false
[debug_hf]
type: logical
doc: If True, prints the HF energy before/after the different steps of the localization. Only for debugging.
interface: ezfio,provider,ocaml
default: false

3
src/mo_localization/NEED Normal file
View File

@ -0,0 +1,3 @@
hartree_fock
utils_trust_region
determinants

View File

@ -0,0 +1,113 @@
# Orbital localisation
To localize the MOs:
```
qp run localization
```
By default, the different otbital classes are automatically set by splitting
the orbitales in the following classes:
- Core -> Core
- Active, doubly occupied -> Inactive
- Active, singly occupied -> Active
- Active, empty -> Virtual
- Deleted -> Deleted
The orbitals will be localized among each class, excpect the deleted ones.
If you want to choose another splitting, you can set
```
qp set mo_localization auto_mo_class false
```
and define the classes with
```
qp set_mo_class -c [] -a [] -v [] -i [] -d []
```
for more information
```
qp set_mo_class -q
```
We don't care about the name of the
mo classes. The algorithm just localizes all the MOs of
a given class between them, for all the classes, except the deleted MOs.
If you are using the last option don't forget to reset the initial mo classes
after the localization.
Before the localization, a kick is done for each mo class
(except the deleted ones) to break the MOs. This is done by
doing a given rotation between the MOs.
This feature can be removed by setting:
```
qp set localization kick_in_mos false
```
and the default angle for the rotation can be changed with:
```
qp set localization angle_pre_rot 1e-3 # or something else
```
After the localization, the MOs of each class (except the deleted ones)
can be sorted between them using the diagonal elements of
the fock matrix with:
```
qp set localization sort_mos_by_e true
```
You can check the Hartree-Fock energy before/during/after the localization
by putting (only for debugging):
```
qp set localization debug_hf true
```
## Foster-Boys & Pipek-Mezey
Foster-Boys:
```
qp set localization localization_method boys
```
Pipek-Mezey:
```
qp set localization localization_method pipek
```
# Break the spatial symmetry of the MOs
This program work exactly as the localization.
To break the spatial symmetry of the MOs:
```
qp run break_spatial_sym
```
The default angle for the rotations is too big for this kind of
application, a value between 1e-3 and 1e-6 should break the spatial
symmetry with just a small change in the energy:
```
qp set localization angle_pre_rot 1e-3
```
# With or without hessian + trust region
With hessian + trust region
```
qp set localization localisation_use_hessian true
```
It uses the trust region algorithm with the diagonal of the hessian of the
localization criterion with respect to the MO rotations.
Without the hessian and the trust region
```
qp set localization localisation_use_hessian false
```
By doing so it does not require to store the hessian but the
convergence is not easy, in particular for virtual MOs.
It seems that it not possible to converge with Pipek-Mezey
localization with this approach.
# Parameters
Some other parameters are available for the localization (qp edit for more details).
# Tests
```
qp test
```
# Org files
The org files are stored in the directory org in order to avoid overwriting on user changes.
The org files can be modified, to export the change to the source code, run
```
./TANGLE_org_mode.sh
mv *.irp.f ../.
```

View File

@ -0,0 +1,27 @@
! ! A small program to break the spatial symmetry of the MOs.
! ! You have to defined your MO classes or set security_mo_class to false
! ! with:
! ! qp set orbital_optimization security_mo_class false
! ! The default angle for the rotations is too big for this kind of
! ! application, a value between 1e-3 and 1e-6 should break the spatial
! ! symmetry with just a small change in the energy.
program break_spatial_sym
!BEGIN_DOC
! Break the symmetry of the MOs with a rotation
!END_DOC
implicit none
kick_in_mos = .True.
TOUCH kick_in_mos
call set_classes_loc
call apply_pre_rotation
call unset_classes_loc
end

View File

@ -0,0 +1,65 @@
program debug_gradient_loc
!BEGIN_DOC
! Check if the gradient is correct
!END_DOC
implicit none
integer :: list_size, n
integer, allocatable :: list(:)
double precision, allocatable :: v_grad(:), v_grad2(:)
double precision :: norm, max_elem, threshold, max_error
integer :: i, nb_error
threshold = 1d-12
list_size = dim_list_act_orb
allocate(list(list_size))
list = list_act
n = list_size*(list_size-1)/2
allocate(v_grad(n),v_grad2(n))
if (localization_method == 'boys') then
print*,'Foster-Boys'
call gradient_FB(n,list_size,list,v_grad,max_elem,norm)
call gradient_FB_omp(n,list_size,list,v_grad2,max_elem,norm)
elseif (localization_method == 'pipek') then
print*,'Pipek-Mezey'
call gradient_PM(n,list_size,list,v_grad,max_elem,norm)
call gradient_PM(n,list_size,list,v_grad2,max_elem,norm)
else
print*,'Unknown localization_method, please select boys or pipek'
call abort
endif
do i = 1, n
print*,i,v_grad(i)
enddo
v_grad = v_grad - v_grad2
nb_error = 0
max_elem = 0d0
do i = 1, n
if (dabs(v_grad(i)) > threshold) then
print*,v_grad(i)
nb_error = nb_error + 1
if (dabs(v_grad(i)) > max_elem) then
max_elem = v_grad(i)
endif
endif
enddo
print*,'Threshold error', threshold
print*, 'Nb error', nb_error
print*,'Max error', max_elem
deallocate(v_grad,v_grad2)
end

View File

@ -0,0 +1,65 @@
program debug_hessian_loc
!BEGIN_DOC
! Check if the hessian is correct
!END_DOC
implicit none
integer :: list_size, n
integer, allocatable :: list(:)
double precision, allocatable :: H(:), H2(:)
double precision :: threshold, max_error, max_elem
integer :: i, nb_error
threshold = 1d-12
list_size = dim_list_act_orb
allocate(list(list_size))
list = list_act
n = list_size*(list_size-1)/2
allocate(H(n),H2(n))
if (localization_method == 'boys') then
print*,'Foster-Boys'
call hessian_FB(n,list_size,list,H)
call hessian_FB_omp(n,list_size,list,H2)
elseif(localization_method == 'pipek') then
print*,'Pipek-Mezey'
call hessian_PM(n,list_size,list,H)
call hessian_PM(n,list_size,list,H2)
else
print*,'Unknown localization_method, please select boys or pipek'
call abort
endif
do i = 1, n
print*,i,H(i)
enddo
H = H - H2
nb_error = 0
max_elem = 0d0
do i = 1, n
if (dabs(H(i)) > threshold) then
print*,H(i)
nb_error = nb_error + 1
if (dabs(H(i)) > max_elem) then
max_elem = H(i)
endif
endif
enddo
print*,'Threshold error', threshold
print*, 'Nb error', nb_error
print*,'Max error', max_elem
deallocate(H,H2)
end

View File

@ -0,0 +1,16 @@
program kick_the_mos
!BEGIN_DOC
! To do a small rotation of the MOs
!END_DOC
implicit none
kick_in_mos = .True.
TOUCH kick_in_mos
call set_classes_loc
call apply_pre_rotation
call unset_classes_loc
end

View File

@ -0,0 +1,520 @@
program localization
implicit none
call set_classes_loc
call run_localization
call unset_classes_loc
end
! Variables:
! | pre_rot(mo_num, mo_num) | double precision | Matrix for the pre rotation |
! | R(mo_num,mo_num) | double precision | Rotation matrix |
! | tmp_R(:,:) | double precision | Rottation matrix in a subsapce |
! | prev_mos(ao_num, mo_num) | double precision | Previous mo_coef |
! | spatial_extent(mo_num) | double precision | Spatial extent of the orbitals |
! | criterion | double precision | Localization criterion |
! | prev_criterion | double precision | Previous criterion |
! | criterion_model | double precision | Estimated next criterion |
! | rho | double precision | Ratio to measure the agreement between the model |
! | | | and the reality |
! | delta | double precision | Radisu of the trust region |
! | norm_grad | double precision | Norm of the gradient |
! | info | integer | for dsyev from Lapack |
! | max_elem | double precision | maximal element in the gradient |
! | v_grad(:) | double precision | Gradient |
! | H(:,:) | double precision | Hessian (diagonal) |
! | e_val(:) | double precision | Eigenvalues of the hessian |
! | W(:,:) | double precision | Eigenvectors of the hessian |
! | tmp_x(:) | double precision | Step in 1D (in a subaspace) |
! | tmp_m_x(:,:) | double precision | Step in 2D (in a subaspace) |
! | tmp_list(:) | double precision | List of MOs in a mo_class |
! | i,j,k | integer | Indexes in the full MO space |
! | tmp_i, tmp_j, tmp_k | integer | Indexes in a subspace |
! | l | integer | Index for the mo_class |
! | key(:) | integer | Key to sort the eigenvalues of the hessian |
! | nb_iter | integer | Number of iterations |
! | must_exit | logical | To exit the trust region loop |
! | cancel_step | logical | To cancel a step |
! | not_*converged | logical | To localize the different mo classes |
! | t* | double precision | To measure the time |
! | n | integer | mo_num*(mo_num-1)/2, number of orbital parameters |
! | tmp_n | integer | dim_subspace*(dim_subspace-1)/2 |
! | | | Number of dimension in the subspace |
! Variables in qp_edit for the localization:
! | localization_method |
! | localization_max_nb_iter |
! | default_mo_class |
! | thresh_loc_max_elem_grad |
! | kick_in_mos |
! | angle_pre_rot |
! + all the variables for the trust region
! Cf. qp_edit orbital optimization
subroutine run_localization
include 'pi.h'
BEGIN_DOC
! Orbital localization
END_DOC
implicit none
! Variables
double precision, allocatable :: pre_rot(:,:), R(:,:)
double precision, allocatable :: prev_mos(:,:), spatial_extent(:), tmp_R(:,:)
double precision :: criterion, norm_grad
integer :: i,j,k,l,p, tmp_i, tmp_j, tmp_k
integer :: info
integer :: n, tmp_n, tmp_list_size
double precision, allocatable :: v_grad(:), H(:), tmp_m_x(:,:), tmp_x(:),W(:),e_val(:)
double precision :: max_elem, t1, t2, t3, t4, t5, t6
integer, allocatable :: tmp_list(:), key(:)
double precision :: prev_criterion, rho, delta, criterion_model
integer :: nb_iter, nb_sub_iter
logical :: not_converged, not_core_converged
logical :: not_act_converged, not_inact_converged, not_virt_converged
logical :: use_trust_region, must_exit, cancel_step,enforce_step_cancellation
n = mo_num*(mo_num-1)/2
! Allocation
allocate(spatial_extent(mo_num))
allocate(pre_rot(mo_num, mo_num), R(mo_num, mo_num))
allocate(prev_mos(ao_num, mo_num))
! Locality before the localization
call compute_spatial_extent(spatial_extent)
! Choice of the method
print*,''
print*,'Localization method:',localization_method
if (localization_method == 'boys') then
print*,'Foster-Boys localization'
elseif (localization_method == 'pipek') then
print*,'Pipek-Mezey localization'
else
print*,'Unknown localization_method, please select boys or pipek'
call abort
endif
print*,''
! Localization criterion (FB, PM, ...) for each mo_class
print*,'### Before the pre rotation'
! Debug
if (debug_hf) then
print*,'HF energy:', HF_energy
endif
do l = 1, 4
if (l==1) then ! core
tmp_list_size = dim_list_core_orb
elseif (l==2) then ! act
tmp_list_size = dim_list_act_orb
elseif (l==3) then ! inact
tmp_list_size = dim_list_inact_orb
else ! virt
tmp_list_size = dim_list_virt_orb
endif
! Allocation tmp array
allocate(tmp_list(tmp_list_size))
! To give the list of MOs in a mo_class
if (l==1) then ! core
tmp_list = list_core
elseif (l==2) then
tmp_list = list_act
elseif (l==3) then
tmp_list = list_inact
else
tmp_list = list_virt
endif
if (tmp_list_size >= 2) then
call criterion_localization(tmp_list_size, tmp_list,criterion)
print*,'Criterion:', criterion, mo_class(tmp_list(1))
endif
deallocate(tmp_list)
enddo
! Debug
!print*,'HF', HF_energy
! Loc
! Pre rotation, to give a little kick in the MOs
call apply_pre_rotation()
! Criterion after the pre rotation
! Localization criterion (FB, PM, ...) for each mo_class
print*,'### After the pre rotation'
! Debug
if (debug_hf) then
touch mo_coef
print*,'HF energy:', HF_energy
endif
do l = 1, 4
if (l==1) then ! core
tmp_list_size = dim_list_core_orb
elseif (l==2) then ! act
tmp_list_size = dim_list_act_orb
elseif (l==3) then ! inact
tmp_list_size = dim_list_inact_orb
else ! virt
tmp_list_size = dim_list_virt_orb
endif
if (tmp_list_size >= 2) then
! Allocation tmp array
allocate(tmp_list(tmp_list_size))
! To give the list of MOs in a mo_class
if (l==1) then ! core
tmp_list = list_core
elseif (l==2) then
tmp_list = list_act
elseif (l==3) then
tmp_list = list_inact
else
tmp_list = list_virt
endif
call criterion_localization(tmp_list_size, tmp_list,criterion)
print*,'Criterion:', criterion, trim(mo_class(tmp_list(1)))
deallocate(tmp_list)
endif
enddo
! Debug
!print*,'HF', HF_energy
print*,''
print*,'========================'
print*,' Orbital localization'
print*,'========================'
print*,''
!Initialization
not_converged = .TRUE.
! To do the localization only if there is at least 2 MOs
if (dim_list_core_orb >= 2) then
not_core_converged = .TRUE.
else
not_core_converged = .FALSE.
endif
if (dim_list_act_orb >= 2) then
not_act_converged = .TRUE.
else
not_act_converged = .FALSE.
endif
if (dim_list_inact_orb >= 2) then
not_inact_converged = .TRUE.
else
not_inact_converged = .FALSE.
endif
if (dim_list_virt_orb >= 2) then
not_virt_converged = .TRUE.
else
not_virt_converged = .FALSE.
endif
! Loop over the mo_classes
do l = 1, 4
if (l==1) then ! core
not_converged = not_core_converged
tmp_list_size = dim_list_core_orb
elseif (l==2) then ! act
not_converged = not_act_converged
tmp_list_size = dim_list_act_orb
elseif (l==3) then ! inact
not_converged = not_inact_converged
tmp_list_size = dim_list_inact_orb
else ! virt
not_converged = not_virt_converged
tmp_list_size = dim_list_virt_orb
endif
! Next iteration if converged = true
if (.not. not_converged) then
cycle
endif
! Allocation tmp array
allocate(tmp_list(tmp_list_size))
! To give the list of MOs in a mo_class
if (l==1) then ! core
tmp_list = list_core
elseif (l==2) then
tmp_list = list_act
elseif (l==3) then
tmp_list = list_inact
else
tmp_list = list_virt
endif
! Display
if (not_converged) then
print*,''
print*,'###', trim(mo_class(tmp_list(1))), 'MOs ###'
print*,''
endif
! Size for the 2D -> 1D transformation
tmp_n = tmp_list_size * (tmp_list_size - 1)/2
! Without hessian + trust region
if (.not. localization_use_hessian) then
! Allocation of temporary arrays
allocate(v_grad(tmp_n), tmp_m_x(tmp_list_size, tmp_list_size))
allocate(tmp_R(tmp_list_size, tmp_list_size), tmp_x(tmp_n))
! Criterion
call criterion_localization(tmp_list_size, tmp_list, prev_criterion)
! Init
nb_iter = 0
delta = 1d0
!Loop
do while (not_converged)
print*,''
print*,'***********************'
print*,'Iteration', nb_iter
print*,'***********************'
print*,''
! Angles of rotation
call theta_localization(tmp_list, tmp_list_size, tmp_m_x, max_elem)
tmp_m_x = - tmp_m_x * delta
! Rotation submatrix
call rotation_matrix(tmp_m_x, tmp_list_size, tmp_R, tmp_list_size, tmp_list_size, &
info, enforce_step_cancellation)
! To ensure that the rotation matrix is unitary
if (enforce_step_cancellation) then
print*, 'Step cancellation, too large error in the rotation matrix'
delta = delta * 0.5d0
cycle
else
delta = min(delta * 2d0, 1d0)
endif
! Full rotation matrix and application of the rotation
call sub_to_full_rotation_matrix(tmp_list_size, tmp_list, tmp_R, R)
call apply_mo_rotation(R, prev_mos)
! Update the needed data
call update_data_localization()
! New criterion
call criterion_localization(tmp_list_size, tmp_list, criterion)
print*,'Criterion:', trim(mo_class(tmp_list(1))), nb_iter, criterion
print*,'Max elem :', max_elem
print*,'Delta :', delta
nb_iter = nb_iter + 1
! Exit
if (nb_iter >= localization_max_nb_iter .or. dabs(max_elem) < thresh_loc_max_elem_grad) then
not_converged = .False.
endif
enddo
! Save the changes
call update_data_localization()
call save_mos()
TOUCH mo_coef
! Deallocate
deallocate(v_grad, tmp_m_x, tmp_list)
deallocate(tmp_R, tmp_x)
! Trust region
else
! Allocation of temporary arrays
allocate(v_grad(tmp_n), H(tmp_n), tmp_m_x(tmp_list_size, tmp_list_size))
allocate(tmp_R(tmp_list_size, tmp_list_size))
allocate(tmp_x(tmp_n), W(tmp_n), e_val(tmp_n), key(tmp_n))
! ### Initialization ###
delta = 0d0 ! can be deleted (normally)
nb_iter = 0 ! Must start at 0 !!!
rho = 0.5d0 ! Must be 0.5
! Compute the criterion before the loop
call criterion_localization(tmp_list_size, tmp_list, prev_criterion)
! Loop until the convergence
do while (not_converged)
print*,''
print*,'***********************'
print*,'Iteration', nb_iter
print*,'***********************'
print*,''
! Gradient
call gradient_localization(tmp_n, tmp_list_size, tmp_list, v_grad, max_elem, norm_grad)
! Diagonal hessian
call hessian_localization(tmp_n, tmp_list_size, tmp_list, H)
! Diagonalization of the diagonal hessian by hands
!call diagonalization_hessian(tmp_n,H,e_val,w)
do i = 1, tmp_n
e_val(i) = H(i)
enddo
! Key list for dsort
do i = 1, tmp_n
key(i) = i
enddo
! Sort of the eigenvalues
call dsort(e_val, key, tmp_n)
! Eigenvectors
W = 0d0
do i = 1, tmp_n
W(i) = dble(key(i))
enddo
! To enter in the loop just after
cancel_step = .True.
nb_sub_iter = 0
! Loop to reduce the trust radius until the criterion decreases and rho >= thresh_rho
do while (cancel_step)
print*,'-----------------------------'
print*, mo_class(tmp_list(1))
print*,'Iteration:', nb_iter
print*,'Sub iteration:', nb_sub_iter
print*,'Max elem grad:', max_elem
print*,'-----------------------------'
! Hessian,gradient,Criterion -> x
call trust_region_step_w_expected_e(tmp_n,1, H, W, e_val, v_grad, prev_criterion, &
rho, nb_iter, delta, criterion_model, tmp_x, must_exit)
! Internal loop exit condition
if (must_exit) then
print*,'trust_region_step_w_expected_e sent: Exit'
exit
endif
! 1D tmp -> 2D tmp
call vec_to_mat_v2(tmp_n, tmp_list_size, tmp_x, tmp_m_x)
! Rotation submatrix (square matrix tmp_list_size by tmp_list_size)
call rotation_matrix(tmp_m_x, tmp_list_size, tmp_R, tmp_list_size, tmp_list_size, &
info, enforce_step_cancellation)
if (enforce_step_cancellation) then
print*, 'Step cancellation, too large error in the rotation matrix'
rho = 0d0
cycle
endif
! tmp_R to R, subspace to full space
call sub_to_full_rotation_matrix(tmp_list_size, tmp_list, tmp_R, R)
! Rotation of the MOs
call apply_mo_rotation(R, prev_mos)
! Update the things related to mo_coef
call update_data_localization()
! Update the criterion
call criterion_localization(tmp_list_size, tmp_list, criterion)
print*,'Criterion:', trim(mo_class(tmp_list(1))), nb_iter, criterion
! Criterion -> step accepted or rejected
call trust_region_is_step_cancelled(nb_iter, prev_criterion, criterion, &
criterion_model, rho, cancel_step)
! Cancellation of the step, previous MOs
if (cancel_step) then
mo_coef = prev_mos
endif
nb_sub_iter = nb_sub_iter + 1
enddo
!call save_mos() !### depend of the time for 1 iteration
! To exit the external loop if must_exti = .True.
if (must_exit) then
exit
endif
! Step accepted, nb iteration + 1
nb_iter = nb_iter + 1
! External loop exit conditions
if (DABS(max_elem) < thresh_loc_max_elem_grad) then
not_converged = .False.
endif
if (nb_iter > localization_max_nb_iter) then
not_converged = .False.
endif
enddo
! Deallocation of temporary arrays
deallocate(v_grad, H, tmp_m_x, tmp_R, tmp_list, tmp_x, W, e_val, key)
! Save the MOs
call save_mos()
TOUCH mo_coef
! Debug
if (debug_hf) then
touch mo_coef
print*,'HF energy:', HF_energy
endif
endif
enddo
! Seems unecessary
TOUCH mo_coef
! To sort the MOs using the diagonal elements of the Fock matrix
if (sort_mos_by_e) then
call run_sort_by_fock_energies()
endif
! Debug
if (debug_hf) then
touch mo_coef
print*,'HF energy:', HF_energy
endif
! Locality after the localization
call compute_spatial_extent(spatial_extent)
end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
#!/bin/sh
list='ls *.org'
for element in $list
do
emacs --batch $element -f org-babel-tangle
done

View File

@ -0,0 +1,28 @@
! A small program to break the spatial symmetry of the MOs.
! You have to defined your MO classes or set security_mo_class to false
! with:
! qp set orbital_optimization security_mo_class false
! The default angle for the rotations is too big for this kind of
! application, a value between 1e-3 and 1e-6 should break the spatial
! symmetry with just a small change in the energy.
#+BEGIN_SRC f90 :comments org :tangle break_spatial_sym.irp.f
program break_spatial_sym
!BEGIN_DOC
! Break the symmetry of the MOs with a rotation
!END_DOC
implicit none
kick_in_mos = .True.
TOUCH kick_in_mos
call set_classes_loc
call apply_pre_rotation
call unset_classes_loc
end
#+END_SRC

View File

@ -0,0 +1,67 @@
#+BEGIN_SRC f90 :comments org :tangle debug_gradient_loc.irp.f
program debug_gradient_loc
!BEGIN_DOC
! Check if the gradient is correct
!END_DOC
implicit none
integer :: list_size, n
integer, allocatable :: list(:)
double precision, allocatable :: v_grad(:), v_grad2(:)
double precision :: norm, max_elem, threshold, max_error
integer :: i, nb_error
threshold = 1d-12
list_size = dim_list_act_orb
allocate(list(list_size))
list = list_act
n = list_size*(list_size-1)/2
allocate(v_grad(n),v_grad2(n))
if (localization_method == 'boys') then
print*,'Foster-Boys'
call gradient_FB(n,list_size,list,v_grad,max_elem,norm)
call gradient_FB_omp(n,list_size,list,v_grad2,max_elem,norm)
elseif (localization_method == 'pipek') then
print*,'Pipek-Mezey'
call gradient_PM(n,list_size,list,v_grad,max_elem,norm)
call gradient_PM(n,list_size,list,v_grad2,max_elem,norm)
else
print*,'Unknown localization_method, please select boys or pipek'
call abort
endif
do i = 1, n
print*,i,v_grad(i)
enddo
v_grad = v_grad - v_grad2
nb_error = 0
max_elem = 0d0
do i = 1, n
if (dabs(v_grad(i)) > threshold) then
print*,v_grad(i)
nb_error = nb_error + 1
if (dabs(v_grad(i)) > max_elem) then
max_elem = v_grad(i)
endif
endif
enddo
print*,'Threshold error', threshold
print*, 'Nb error', nb_error
print*,'Max error', max_elem
deallocate(v_grad,v_grad2)
end
#+END_SRC

View File

@ -0,0 +1,67 @@
#+BEGIN_SRC f90 :comments org :tangle debug_hessian_loc.irp.f
program debug_hessian_loc
!BEGIN_DOC
! Check if the hessian is correct
!END_DOC
implicit none
integer :: list_size, n
integer, allocatable :: list(:)
double precision, allocatable :: H(:), H2(:)
double precision :: threshold, max_error, max_elem
integer :: i, nb_error
threshold = 1d-12
list_size = dim_list_act_orb
allocate(list(list_size))
list = list_act
n = list_size*(list_size-1)/2
allocate(H(n),H2(n))
if (localization_method == 'boys') then
print*,'Foster-Boys'
call hessian_FB(n,list_size,list,H)
call hessian_FB_omp(n,list_size,list,H2)
elseif(localization_method == 'pipek') then
print*,'Pipek-Mezey'
call hessian_PM(n,list_size,list,H)
call hessian_PM(n,list_size,list,H2)
else
print*,'Unknown localization_method, please select boys or pipek'
call abort
endif
do i = 1, n
print*,i,H(i)
enddo
H = H - H2
nb_error = 0
max_elem = 0d0
do i = 1, n
if (dabs(H(i)) > threshold) then
print*,H(i)
nb_error = nb_error + 1
if (dabs(H(i)) > max_elem) then
max_elem = H(i)
endif
endif
enddo
print*,'Threshold error', threshold
print*, 'Nb error', nb_error
print*,'Max error', max_elem
deallocate(H,H2)
end
#+END_SRC

View File

@ -0,0 +1,18 @@
#+BEGIN_SRC f90 :comments org :tangle kick_the_mos.irp.f
program kick_the_mos
!BEGIN_DOC
! To do a small rotation of the MOs
!END_DOC
implicit none
kick_in_mos = .True.
TOUCH kick_in_mos
call set_classes_loc
call apply_pre_rotation
call unset_classes_loc
end
#+END_SRC

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,62 @@
#!/usr/bin/env bats
source $QP_ROOT/tests/bats/common.bats.sh
source $QP_ROOT/quantum_package.rc
function run() {
thresh=2e-3
test_exe scf || skip
qp set_file $1
qp edit --check
qp reset -a
qp run scf
qp set_frozen_core
qp set determinants n_states 2
qp set determinants read_wf true
qp set mo_two_e_ints io_mo_two_e_integrals None
file="$(echo $1 | sed 's/.ezfio//g')"
qp run cis
qp run debug_gradient_list_opt > $file.debug_g.out
err3="$(grep 'Max error:' $file.debug_g.out | awk '{print $3}')"
qp run debug_hessian_list_opt > $file.debug_h1.out
err1="$(grep 'Max error:' $file.debug_h1.out | awk '{print $3}')"
qp run orb_opt > $file.opt1.out
energy1="$(grep 'State average energy:' $file.opt1.out | tail -n 1 | awk '{print $4}')"
qp set orbital_optimization optimization_method diag
qp reset -d
qp run scf
qp run cis
qp run debug_hessian_list_opt > $file.debug_h2.out
err2="$(grep 'Max error_H:' $file.debug_h2.out | awk '{print $3}')"
qp run orb_opt > $file.opt2.out
energy2="$(grep 'State average energy:' $file.opt2.out | tail -n 1 | awk '{print $4}')"
qp set orbital_optimization optimization_method full
qp reset -d
qp run scf
eq $energy1 $2 $thresh
eq $energy2 $3 $thresh
eq $err1 0.0 1e-12
eq $err2 0.0 1e-12
eq $err3 0.0 1e-12
}
@test "b2_stretched" {
run b2_stretched.ezfio -48.9852901484277 -48.9852937541510
}
@test "h2o" {
run h2o.ezfio -75.9025622449206 -75.8691844585879
}
@test "h2s" {
run h2s.ezfio -398.576255809878 -398.574145943928
}
@test "hbo" {
run hbo.ezfio -99.9234823022109 -99.9234763597840
}
@test "hco" {
run hco.ezfio -113.204915552241 -113.204905207050
}

View File

@ -0,0 +1,23 @@
[optimization_method]
type: character*(32)
doc: Define the kind of hessian for the orbital optimization full : full hessian, diag : diagonal hessian, none : no hessian
interface: ezfio,provider,ocaml
default: full
[n_det_max_opt]
type: integer
doc: Maximal number of the determinants in the wf for the orbital optimization (to stop the optimization if n_det > n_det_max_opt)
interface: ezfio,provider,ocaml
default: 200000
[optimization_max_nb_iter]
type: integer
doc: Maximal number of iterations for the orbital optimization
interface: ezfio,provider,ocaml
default: 20
[thresh_opt_max_elem_grad]
type: double precision
doc: Threshold for the convergence, the optimization exits when the biggest element in the gradient is smaller than thresh_optimization_max_elem_grad
interface: ezfio,provider,ocaml
default: 1.e-5

7
src/mo_optimization/NEED Normal file
View File

@ -0,0 +1,7 @@
two_body_rdm
hartree_fock
cipsi
davidson_undressed
selectors_full
generators_full
utils_trust_region

View File

@ -0,0 +1,74 @@
# Orbital optimization
## Methods
Different methods are available:
- full hessian
```
qp set orbital_optimization optimization_method full
```
- diagonal hessian
```
qp set orbital_optimization optimization_method diag
```
- identity matrix
```
qp set orbital_optimization optimization_method none
```
After the optimization the ezfio contains the optimized orbitals
## For a fixed number of determinants
To optimize the MOs for the actual determinants:
```
qp run orb_opt
```
## For a complete optimization, i.e, with a larger and larger wave function
To optimize the MOs with a larger and larger wave function:
```
qp run optimization
```
The results are stored in the EZFIO in "mo_optimization/result_opt",
with the following format:
(1) (2) (3) (4)
1: Number of determinants in the wf,
2: Cispi energy before the optimization,
3: Cipsi energy after the optimization,
4: Energy difference between (2) and (3).
The optimization process if the following:
- we do a first cipsi step to obtain a small number of determinants in the wf
- we run an orbital optimization for this wf
- we do a new cipsi step to double the number of determinants in the wf
- we run an orbital optimization for this wf
- ...
- we do that until the energy difference between (2) and (3) is
smaller than the targeted accuracy for the cispi (targeted_accuracy_cipsi in qp edit)
or the wf is larger than a given size (n_det_max_opt in qp_edit)
- after that you can reset your determinants (qp reset -d) and run a clean Cispi calculation
### End of the optimization
You can choos the number of determinants after what the
optimization will stop:
```
qp set orbital_optimization n_det_max_opt 1e5 # or any number
```
## Weight of the states
You can change the weights of the differents states directly in qp edit.
It will affect ths weights used in the orbital optimization.
# Tests
To run the tests:
```
qp test
```
# Org files
The org files are stored in the directory org in order to avoid overwriting on user changes.
The org files can be modified, to export the change to the source code, run
```
./TANGLE_org_mode.sh
mv *.irp.f ../.
```

View File

@ -0,0 +1,12 @@
BEGIN_PROVIDER [ logical, do_only_1h1p ]
&BEGIN_PROVIDER [ logical, do_only_cas ]
&BEGIN_PROVIDER [ logical, do_ddci ]
implicit none
BEGIN_DOC
! In the FCI case, all those are always false
END_DOC
do_only_1h1p = .False.
do_only_cas = .False.
do_ddci = .False.
END_PROVIDER

View File

@ -0,0 +1 @@
logical, parameter :: debug=.False.

View File

@ -0,0 +1,78 @@
! Debug the gradient
! *Program to check the gradient*
! The program compares the result of the first and last code for the
! gradient.
! Provided:
! | mo_num | integer | number of MOs |
! Internal:
! | n | integer | number of orbitals pairs (p,q) p<q |
! | v_grad(n) | double precision | Original gradient |
! | v_grad2(n) | double precision | Gradient |
! | i | integer | index |
! | threshold | double precision | threshold for the errors |
! | max_error | double precision | maximal error in the gradient |
! | nb_error | integer | number of error in the gradient |
program debug_gradient_list
implicit none
! Variables
double precision, allocatable :: v_grad(:), v_grad2(:)
integer :: n,m
integer :: i
double precision :: threshold
double precision :: max_error, max_elem, norm
integer :: nb_error
m = dim_list_act_orb
! Definition of n
n = m*(m-1)/2
PROVIDE mo_two_e_integrals_in_map ! Vérifier pour suppression
! Allocation
allocate(v_grad(n), v_grad2(n))