LCOV - code coverage report
Current view: top level - src/78_effpot - m_opt_effpot.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 81.5 % 771 628
Test Date: 2026-09-19 17:42:43 Functions: 100.0 % 13 13

            Line data    Source code
       1              : 
       2              : !!****m* ABINIT/m_opt_effpot
       3              : !!
       4              : !! NAME
       5              : !! m_opt_effpot
       6              : !!
       7              : !! FUNCTION
       8              : !!
       9              : !!
      10              : !!
      11              : !! COPYRIGHT
      12              : !! Copyright (C) 2010-2026 ABINIT group (AM)
      13              : !! This file is distributed under the terms of the
      14              : !! GNU General Public Licence, see ~abinit/COPYING
      15              : !! or http://www.gnu.org/copyleft/gpl.txt .
      16              : !! For the initials of contributors, see ~abinit/doc/developers/contributors.txt .
      17              : !!
      18              : !! SOURCE
      19              : 
      20              : 
      21              : 
      22              : #if defined HAVE_CONFIG_H
      23              : #include "config.h"
      24              : #endif
      25              : 
      26              : #include "abi_common.h"
      27              : !#include "trace.h"
      28              : 
      29              : 
      30              : module m_opt_effpot
      31              : 
      32              : use defs_basis
      33              : use defs_datatypes
      34              : use defs_abitypes
      35              : use m_errors
      36              : use m_abicore
      37              : use m_xmpi
      38              : use m_effective_potential
      39              : use m_effective_potential_file, only : effective_potential_file_mapHistToRef
      40              : use m_fit_data
      41              : use m_fit_polynomial_coeff
      42              : use m_polynomial_coeff
      43              : use m_polynomial_term
      44              : use m_crystal,only : symbols_crystal
      45              : 
      46              : implicit none
      47              : 
      48              : public :: opt_effpot
      49              : public :: opt_effpotbound
      50              : public :: opt_getHOforterm
      51              : public :: opt_getCombisforterm
      52              : public :: opt_getHoTerms
      53              : public :: opt_getHOstrain
      54              : public :: opt_getHOcrossdisp
      55              : public :: opt_filterdisp
      56              : public :: opt_getSingleDispTerms
      57              : public :: opt_getHOSingleDispTerms
      58              : private :: opt_boundcoeff
      59              : private :: check_to_skip
      60              : !!****
      61              : CONTAINS
      62              : 
      63              : !!****f* m_opt_effpot/opt_effpot
      64              : !!
      65              : !! NAME
      66              : !! opt_effpot
      67              : !!
      68              : !! FUNCTION
      69              : !! Optimize Effective Potential by fitting the value of certain
      70              : !! coefficients while keeping the values of the others
      71              : !!
      72              : !! INPUTS
      73              : !! eff_pot<type(effective_potential)> = effective potential
      74              : !!
      75              : !! opt_coeff(opt_ncoeff) = list of terms whose coefficients are to be
      76              : !! optimized
      77              : !!
      78              : !! hist<type(abihist)> = Training set Data(or snapshot of DFT)
      79              : !! comm = MPI communicator
      80              : !!
      81              : !! OUTPUT
      82              : !! eff_pot<type(effective_potential)> = effective potential datatype with new fitted coefficients
      83              : !!
      84              : !! SOURCE
      85              : 
      86            1 : subroutine opt_effpot(eff_pot,opt_ncoeff,opt_coeff,hist,opt_on,opt_factors,comm, fit_weight_T, print_anh)
      87              : 
      88              :   !Arguments ------------------------------------
      89              :   !scalars
      90              :   integer,intent(in) :: comm,opt_ncoeff
      91              :   type(effective_potential_type),intent(inout) :: eff_pot
      92              :   type(abihist),intent(inout) :: hist
      93              :   !arrays
      94              :   integer,intent(in) :: opt_coeff(opt_ncoeff)
      95              :   real(dp),intent(in) :: opt_factors(3)
      96              :   real(dp), intent(in):: fit_weight_T
      97              :   !Logicals
      98              :   logical,intent(in) :: opt_on(3)
      99              :   logical,optional,intent(in) :: print_anh
     100              :   !Strings
     101              :   !Local variables ------------------------------
     102              :   !scalars
     103              :   integer :: ii, info,natom_sc,ntime,unit_anh1,unit_anh2
     104              :   integer :: master,nproc,my_rank
     105              :   real(dp) :: factor,mse,msef,mses
     106              :   real(dp),parameter :: HaBohr_eVAng = Ha_eV /Bohr_Ang
     107              :   !arrays
     108              :   integer :: sc_size(3)
     109            2 :   integer :: coeff_inds(opt_ncoeff)
     110            1 :   type(fit_data_type) :: fit_data
     111           11 :   type(polynomial_coeff_type) :: my_coeffs(opt_ncoeff)
     112            2 :   real(dp) :: coeff_values(opt_ncoeff), coeff_init_values(opt_ncoeff)
     113            1 :   real(dp), allocatable :: energy_coeffs(:,:),fcart_coeffs(:,:,:,:)
     114            1 :   real(dp), allocatable :: strten_coeffs(:,:,:)
     115            1 :   real(dp), allocatable :: my_weights(:)
     116              :   !Logicals
     117              :   logical :: need_print_anh,file_opened,iam_master
     118              :   !Strings
     119              :   character(len=1000) :: message
     120              :   character(len=1000) :: frmt
     121              :   character(len=fnlen) :: fn_bf='before_opt_diff', fn_af='after_opt_diff'
     122              :   ! *************************************************************************
     123              :   !MPI
     124            1 :   master = 0
     125            1 :   nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     126              :   iam_master = (my_rank == master)
     127              : 
     128              :   !Setting/Initializing Variables
     129            1 :   ntime = hist%mxhist
     130            1 :   natom_sc = size(hist%xred,2)
     131            1 :   factor   = 1._dp/natom_sc
     132            1 :   need_print_anh =.False.
     133              : 
     134            1 :   call get_weight_from_hist(hist, fit_weight_T, ntime, natom_sc, my_weights, comm)
     135              : 
     136              : 
     137            1 :   if(present(print_anh)) then
     138            1 :     if(print_anh) need_print_anh=.True.
     139              :   end if
     140              :   !if the number of atoms in reference supercell into effpot is not correct,
     141              :   !wrt to the number of atom in the hist, we set map the hist and set the good supercell
     142            1 :   if (natom_sc /= eff_pot%supercell%natom) then
     143            0 :     call effective_potential_file_mapHistToRef(eff_pot,hist,comm,verbose=.TRUE.)
     144              :   end if
     145              : 
     146              :   !we get the size of the supercell in the hist file
     147              :   ! This is only valid for diagonal sc_size.
     148              :   ! F08: sc_size(:) = int(anint( norm2(eff_pot%supercell%rprimd, dim=2) / &
     149              :   !   & norm2(eff_pot%crystal%rprimd, dim=2) ))
     150            4 :   do ii=1,3
     151              :     sc_size(ii) = int(anint(sqrt(eff_pot%supercell%rprimd(ii,1)**2+&
     152              :       &                               eff_pot%supercell%rprimd(ii,2)**2+&
     153              :       &                               eff_pot%supercell%rprimd(ii,3)**2) / &
     154              :       &                          sqrt(eff_pot%crystal%rprimd(ii,1)**2+&
     155              :       &                               eff_pot%crystal%rprimd(ii,2)**2+&
     156            4 :       &                               eff_pot%crystal%rprimd(ii,3)**2)))
     157              :   end do
     158              : 
     159              : 
     160              :   !Before the fit, compute constants with fit_data_compute.
     161              :   !Compute the strain of each configuration.
     162              :   !Compute the displacmeent of each configuration.
     163              :   !Compute the variation of the displacement due to strain of each configuration.
     164              :   !Compute fixed forces and stresse and get the standard deviation.
     165              :   !Compute Sheppard and al Factors  \Omega^{2} see J.Chem Phys 136, 074103 (2012) [[cite:Sheppard2012]].
     166            1 :   call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=.FALSE.)
     167              : 
     168              : 
     169            1 :   if(need_print_anh) call effective_potential_writeAnhHead(eff_pot%anharmonics_terms%ncoeff,&
     170            0 :     &                            fn_bf,eff_pot%anharmonics_terms)
     171              : 
     172              :   !Before deleting coefficients calculate MSD of initial model
     173              :   call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
     174              :     &                                     natom_sc,ntime,fit_data%training_set%sqomega,comm,&
     175            1 :     &                                     compute_anharmonic=.TRUE.,print_file=.TRUE.,filename=fn_bf)
     176              : 
     177              : 
     178              :   !  Print the standard devition of initial model
     179            1 :   write(message,'(6a,ES24.16,6a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
     180            1 :     &                    ' Mean Standard Deviation values of the effective-potential',ch10,&
     181            1 :     &                    ' with respect to the training-set before optimization (meV^2/atm):',&
     182            1 :     &               ch10,'   Energy          : ',&
     183            1 :     &               mse* (Ha_EV*1000)**2 *factor ,ch10,&
     184            1 :     &                    ' Goal function values of the effective.potential',ch10,&
     185            1 :     &                    ' with respect to the test-set (eV^2/A^2):',ch10,&
     186            1 :     &                    '   Forces+Stresses : ',&
     187            1 :     &               (msef+mses)*(HaBohr_eVAng)**2,ch10,&
     188            1 :     &                    '   Forces          : ',&
     189            1 :     &               msef*(HaBohr_eVAng)**2,ch10,&
     190            1 :     &                    '   Stresses        : ',&
     191            2 :     &               mses*(HaBohr_eVAng)**2,ch10
     192            1 :   call wrtout(ab_out,message,'COLL')
     193            1 :   call wrtout(std_out,message,'COLL')
     194              : 
     195              : 
     196              :   ! Write terms to my_coeffs(ii) and zero them in eff_pot
     197            3 :   do ii=1,opt_ncoeff
     198              :     !Store indices for later
     199            2 :     coeff_inds(ii) = ii
     200              :     !Initialize coefficients for optimizing
     201              :     call polynomial_coeff_init(coeff_values(ii),eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%nterm,&
     202              :       &                            my_coeffs(ii), eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%terms, &
     203            2 :       &                            check=.TRUE.)
     204              : 
     205              :       !DMSG(my_coeffs(ii)%debug_str)
     206              : 
     207              :     !Store initial values of coefficients
     208            2 :     coeff_init_values(ii) = eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%coefficient
     209              :     !Put them temporarely to zero
     210            3 :     eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%coefficient = zero
     211              :   end do
     212              : 
     213              :   !Before the fit, compute constants with fit_data_compute.
     214              :   !And coefficients to be optimized put to zero
     215              :   !Conpute the strain of each configuration.
     216              :   !Compute the displacmeent of each configuration.
     217              :   !Compute the variation of the displacement due to strain of each configuration.
     218              :   !Compute fixed forces and stresse and get the standard deviation.
     219              :   !Compute Sheppard and al Factors  \Omega^{2} see J.Chem Phys 136, 074103 (2012) [[cite:Sheppard2012]].
     220            1 :   call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=.TRUE.)
     221              : 
     222              :   !After deleting coefficients calculate MSD
     223              :   call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
     224              :     &                                     natom_sc,ntime,fit_data%training_set%sqomega,comm,&
     225            1 :     &                                      compute_anharmonic=.TRUE.)
     226              : 
     227              : 
     228              :   !  Print the standard deviation after deleting
     229            1 :   write(message,'(6a,ES24.16,6a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
     230            1 :     &                    ' Mean Standard Deviation values of the effective-potential',ch10,&
     231            1 :     &                    ' with respect to the training-set after deleting selected terms (meV^2/atm):',&
     232            1 :     &               ch10,'   Energy          : ',&
     233            1 :     &               mse* (Ha_EV*1000)**2 *factor ,ch10,&
     234            1 :     &                    ' Goal function values of the effective.potential',ch10,&
     235            1 :     &                    ' with respect to the test-set (eV^2/A^2):',ch10,&
     236            1 :     &                    '   Forces+Stresses : ',&
     237            1 :     &               (msef+mses)*(HaBohr_eVAng)**2,ch10,&
     238            1 :     &                    '   Forces          : ',&
     239            1 :     &               msef*(HaBohr_eVAng)**2,ch10,&
     240            1 :     &                    '   Stresses        : ',&
     241            2 :     &               mses*(HaBohr_eVAng)**2,ch10
     242            1 :   call wrtout(ab_out,message,'COLL')
     243            1 :   call wrtout(std_out,message,'COLL')
     244              : 
     245              : 
     246              : 
     247              :   ! Allocate necessary arrays for the fit-data
     248            4 :   ABI_MALLOC(energy_coeffs,(opt_ncoeff,ntime))
     249            5 :   ABI_MALLOC(fcart_coeffs,(3,natom_sc,opt_ncoeff,ntime))
     250            4 :   ABI_MALLOC(strten_coeffs,(6,ntime,opt_ncoeff))
     251              :   ! Calculate forces and stresses per coefficient, which are to be optimized
     252              :   call fit_polynomial_coeff_getFS(my_coeffs,fit_data%training_set%du_delta,&
     253              :     &                                 fit_data%training_set%displacement,&
     254              :     &                                 energy_coeffs,fcart_coeffs,natom_sc,eff_pot%crystal%natom,&
     255              :     &                                 opt_ncoeff,ntime,sc_size,fit_data%training_set%strain,&
     256            1 :     &                                 strten_coeffs,fit_data%training_set%ucvol,coeff_inds,opt_ncoeff)
     257              : 
     258              : 
     259              :   !  call the fit process routine
     260              :   !  This routine solves the linear system proposed
     261              :   !  by C.Escorihuela-Sayalero see PRB95,094115(2017) [[cite:Escorihuela-Sayalero2017]]
     262              :   call fit_polynomial_coeff_solve(coeff_values(1:opt_ncoeff),fcart_coeffs,fit_data%fcart_diff,&
     263              :     &                                  energy_coeffs,fit_data%energy_diff,info,&
     264              :     &                                  coeff_inds,natom_sc,opt_ncoeff,opt_ncoeff,ntime,&
     265              :     &                                  strten_coeffs,fit_data%strten_diff,&
     266              :     &                                  fit_data%training_set%sqomega,opt_on,opt_factors, &
     267            1 :     &                                  weights=my_weights)
     268            1 :   if (info /= 0 .and. all(coeff_values < tol16))then
     269            0 :     write(frmt,*) opt_ncoeff
     270            0 :     write(message, '(2a,'//ADJUSTR(frmt)//'I4,8a)' ) ch10,&
     271            0 :       &        '     The attempt to optimize the terms: ', opt_coeff ,ch10,&
     272            0 :       &        '     , returned a singular solution', ch10,&
     273            0 :       &        '     The terms could not be optimized ',ch10,&
     274            0 :       &        '     and the effective potential has not been altered.', ch10,&
     275            0 :       &        '     Action: Change training set or coefficients to be optimized.'
     276            0 :     ABI_WARNING(message)
     277            0 :     do ii=1,opt_ncoeff
     278            0 :       eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%coefficient = coeff_init_values(ii)
     279            0 :       call polynomial_coeff_free(my_coeffs(ii))
     280              :     end do
     281              :   else
     282              :     ! Transfer new fitted values to coefficients and write them into effective potential
     283              :     ! Deallcoate temporary coefficients my_coeffs
     284            3 :     do ii=1,opt_ncoeff
     285            2 :       eff_pot%anharmonics_terms%coefficients(opt_coeff(ii))%coefficient = coeff_values(ii)
     286            3 :       call polynomial_coeff_free(my_coeffs(ii))
     287              :     end do
     288              :     !Recalculate MSD of Final Model
     289              : 
     290              :     !Conpute the strain of each configuration.
     291              :     !Compute the displacmeent of each configuration.
     292              :     !Compute the variation of the displacement due to strain of each configuration.
     293              :     !Compute fixed forces and stresse and get the standard deviation.
     294              :     !Compute Sheppard and al Factors  \Omega^{2} see J.Chem Phys 136, 074103 (2012) [[cite:Sheppard2012]].
     295            1 :     call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=.TRUE.)
     296              : 
     297              : 
     298            1 :     if(need_print_anh) call effective_potential_writeAnhHead(eff_pot%anharmonics_terms%ncoeff,&
     299            0 :       &                            fn_af,eff_pot%anharmonics_terms)
     300              : 
     301              :     !After optimization of coefficients opt_coeff recalculate MSD
     302              :     call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
     303              :       &                                     natom_sc,ntime,fit_data%training_set%sqomega,comm,&
     304            1 :       &                                     compute_anharmonic=.TRUE.,print_file=.TRUE.,filename=fn_af)
     305              : 
     306              : 
     307              :     !  Print the standard deviation after optimization
     308            1 :     write(message,'(6a,ES24.16,6a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
     309            1 :       &                    ' Mean Standard Deviation values of the effective-potential',ch10,&
     310            1 :       &                    ' with respect to the training-set after optimizing selected terms (meV^2/atm):',&
     311            1 :       &               ch10,'   Energy          : ',&
     312            1 :       &               mse* (Ha_EV*1000)**2 *factor ,ch10,&
     313            1 :       &                    ' Goal function values of the effective.potential',ch10,&
     314            1 :       &                    ' with respect to the test-set (eV^2/A^2):',ch10,&
     315            1 :       &                    '   Forces+Stresses : ',&
     316            1 :       &               (msef+mses)*(HaBohr_eVAng)**2,ch10,&
     317            1 :       &                    '   Forces          : ',&
     318            1 :       &               msef*(HaBohr_eVAng)**2,ch10,&
     319            1 :       &                    '   Stresses        : ',&
     320            2 :       &               mses*(HaBohr_eVAng)**2,ch10
     321            1 :     call wrtout(ab_out,message,'COLL')
     322            1 :     call wrtout(std_out,message,'COLL')
     323              :   end if
     324              : 
     325              :   !Deallocation of fitting variables
     326            1 :   ABI_SFREE(energy_coeffs)
     327            1 :   ABI_SFREE(fcart_coeffs)
     328            1 :   ABI_SFREE(strten_coeffs)
     329            1 :   ABI_SFREE(my_weights)
     330              : 
     331            1 :   if(need_print_anh)then
     332            0 :     INQUIRE(FILE='before_opt_diff_anharmonic_terms_energy.dat',OPENED=file_opened,number=unit_anh1)
     333            0 :     if(file_opened) close(unit_anh1)
     334            0 :     INQUIRE(FILE='after_opt_diff_anharmonic_terms_energy.dat',OPENED=file_opened,number=unit_anh2)
     335            0 :     if(file_opened) close(unit_anh2)
     336              :   end if
     337              :   ! Deallocate and delete the fit-date
     338            1 :   call fit_data_free(fit_data)
     339            7 : end subroutine opt_effpot
     340              : !!***
     341              : 
     342              : !!****f* m_opt_effpot/opt_effpotbound
     343              : !!
     344              : !! NAME
     345              : !! opt_effpotbound
     346              : !!
     347              : !! FUNCTION
     348              : !! Compute and add high order terms to existing odd or negative even anharmonic terms
     349              : !! Fix the coefficient of the added new high order terms to a value such that it
     350              : !! doesn't influence the precision of the existing anharmonic potential with respect
     351              : !! to a relevent training set (ATTENTIION: A user must know what a relevant training set
     352              : !! is for the system he want's to study. Typically something oscillating around its ground-state.)
     353              : !! Finally optimize the coefficients of the orignal anharmonic terms under the presence of the
     354              : !! added high order terms.
     355              : !!
     356              : !! INPUTS
     357              : !! eff_pot: existing effective potential
     358              : !! order: order for which bounding terms are generated
     359              : !! order_ran: ?
     360              : !! bound_EFS:
     361              : !! bound_factors:
     362              : !! bound_penalty:
     363              : !! comm: MPI communicator
     364              : !! fit_weight_T: ?
     365              : !! print_anh: ?
     366              : !! bound_option: 1 or 2. Whether the bounding term should be the same nbody with the term to be bounded. 1. Yes (default), 2. No
     367              : !!
     368              : !!
     369              : !! OUTPUT
     370              : !! eff_pot new effective potential
     371              : !!
     372              : !!
     373              : !! SOURCE
     374              : 
     375            1 : subroutine opt_effpotbound(eff_pot,order_ran,hist,bound_EFS,bound_factors,bound_penalty,comm, fit_weight_T,bound_option, print_anh)
     376              : 
     377              :   !Arguments ------------------------------------
     378              :   !scalars
     379              :   integer,intent(in) :: comm
     380              :   type(effective_potential_type),target,intent(inout) :: eff_pot
     381              :   type(abihist),intent(inout) :: hist
     382              :   real(dp) :: bound_penalty
     383              :   !arrays
     384              :   integer,intent(in) :: order_ran(2),bound_EFS(3)
     385              :   integer, intent(in) :: bound_option
     386              :   real(dp),intent(in) :: bound_factors(3)
     387              :   real(dp), intent(in) :: fit_weight_T
     388              :   !Logicals
     389              :   logical,optional,intent(in) :: print_anh
     390              :   !Strings
     391              :   !Local variables ------------------------------
     392              :   !scalars
     393              :   integer :: i,ii,natom_sc,ntime,iterm,nterm, icombi3, nbody_term
     394              :   integer :: jterm, ncombi,ncombi1,ncombi2, ncombi1_real, ncombi2_real
     395              :   integer :: icombi
     396              :   integer :: nterm_start,nterm2
     397              :   integer :: nproc,my_rank,master
     398              :   !1406
     399              :   real(dp) :: factor,mse_ini,msef_ini,mses_ini,mse,msef,mses
     400              :   real(dp) :: coeff_tmp
     401              :   real(dp),parameter :: HaBohr_eVAng = Ha_eV /Bohr_Ang
     402              :   !arrays
     403              :   integer :: sc_size(3),temp_cntr
     404            1 :   integer,allocatable :: terms(:)
     405            1 :   logical,allocatable :: exists(:)
     406              :   logical :: any_exists
     407            1 :   type(fit_data_type) :: fit_data
     408              :   real(dp) :: GF_arr(2),coeff_opt(2)
     409            1 :   real(dp), allocatable :: my_weights(:)
     410              :   !real(dp), allocatable :: energy_coeffs(:,:),fcart_coeffs(:,:,:,:)
     411              :   !real(dp), allocatable :: strten_coeffs(:,:,:)
     412              :   !1406 strain_temrs_tmp
     413            1 :   type(polynomial_coeff_type),target,allocatable :: my_coeffs(:),my_coeffs_tmp(:)
     414            1 :   type(polynomial_coeff_type),allocatable :: singledisp_terms(:),HOsingledisp_terms(:)
     415            1 :   type(polynomial_coeff_type),allocatable :: HOcrossdisp_terms(:)
     416              :   !Logicals
     417              :   logical :: need_print_anh ! MARCUS FOR THE MOMENT PRINT NO FILES
     418              :   logical :: to_skip,iam_master
     419              :   !Strings
     420              :   character(len=5),allocatable :: symbols(:)
     421              :   character(len=200):: name
     422              :   character(len=1000) :: message
     423              :   character(len=fnlen) :: fn_bf='before_opt_diff'!, fn_af='after_opt_diff'
     424              :   ! types
     425            1 :   type(SymPairs_t) :: sympairs
     426              :   !*************************************************************************
     427              :   !MPI variables
     428            1 :   master = 0
     429            1 :   nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
     430              :   iam_master = (my_rank == master)
     431              : 
     432              :   ! Say hello to the world!
     433            1 :   write(message, '(3a)' )'-Start Bound optimization of Anharmonic Potential ',ch10
     434            1 :   call wrtout(ab_out,message,'COLL')
     435            1 :   call wrtout(std_out,message,'COLL')
     436              : 
     437              :   !Setting/Initializing Variables
     438            1 :   ntime = hist%mxhist
     439              : 
     440              : 
     441            1 :   natom_sc = size(hist%xred,2)
     442            1 :   factor   = 1._dp/natom_sc
     443            1 :   nterm =eff_pot%anharmonics_terms%ncoeff
     444            1 :   need_print_anh=.False.
     445            1 :   if(present(print_anh))then
     446            0 :     if(print_anh) need_print_anh = .True.
     447              :   endif
     448            1 :   call get_weight_from_hist(hist, fit_weight_T, ntime, natom_sc, my_weights, comm )
     449              : 
     450            3 :   ABI_MALLOC(symbols,(eff_pot%crystal%natom))
     451            3 :   ABI_MALLOC(terms,(nterm))
     452              :   call symbols_crystal(eff_pot%crystal%natom,eff_pot%crystal%ntypat,eff_pot%crystal%npsp,&
     453            1 :     &                     symbols,eff_pot%crystal%typat,eff_pot%crystal%znucl)
     454              : 
     455              : 
     456              :   !if the number of atoms in reference supercell into effpot is not correct,
     457              :   !wrt to the number of atom in the hist, we set map the hist and set the good supercell
     458            1 :   if (natom_sc /= eff_pot%supercell%natom) then
     459            0 :     call effective_potential_file_mapHistToRef(eff_pot,hist,comm,verbose=.TRUE.)
     460              :   end if
     461              : 
     462              :   !Check if input of order is correct
     463              :   ! TODO write error message here
     464            3 :   if (any(mod(order_ran,2) /= 0)) return
     465              : 
     466              :   !we get the size of the supercell in the hist file
     467            4 :   do ii=1,3
     468              :     sc_size(ii) = int(anint(sqrt(eff_pot%supercell%rprimd(ii,1)**2+&
     469              :       &                               eff_pot%supercell%rprimd(ii,2)**2+&
     470              :       &                               eff_pot%supercell%rprimd(ii,3)**2) / &
     471              :       &                          sqrt(eff_pot%crystal%rprimd(ii,1)**2+&
     472              :       &                               eff_pot%crystal%rprimd(ii,2)**2+&
     473            4 :       &                               eff_pot%crystal%rprimd(ii,3)**2)))
     474              :   end do
     475              : 
     476              : 
     477              :   !Before the fit, compute constants with fit_data_compute.
     478              :   !Conpute the strain of each configuration.
     479              :   !Compute the displacmeent of each configuration.
     480              :   !Compute the variation of the displacement due to strain of each configuration.
     481              :   !Compute fixed forces and stresse and get the standard deviation.
     482              :   !Compute Sheppard and al Factors  \Omega^{2} see J.Chem Phys 136, 074103 (2012) [[cite:Sheppard2012]].
     483              :   !call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=.FALSE.)
     484            1 :   call fit_data_compute(fit_data,eff_pot,hist,comm,verbose=.FALSE.)
     485              : 
     486            1 :   if(need_print_anh) call effective_potential_writeAnhHead(eff_pot%anharmonics_terms%ncoeff,&
     487            0 :     &                            fn_bf,eff_pot%anharmonics_terms)
     488              : 
     489              :   !Before adding bound coefficients calculate MSD of initial model
     490              :   !MS FOR THE MOMENT PRINT NO FILE
     491              :   call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse_ini,msef_ini,mses_ini,&
     492              :     &                                  natom_sc,ntime,fit_data%training_set%sqomega,comm,&
     493            1 :     &                                  compute_anharmonic=.TRUE.,print_file=.FALSE.)
     494              : 
     495              : 
     496              :   !  Print the standard devition of initial model
     497            1 :   write(message,'(6a,ES24.16,6a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
     498            1 :     &           ' Mean Standard Deviation values of the effective-potential',ch10,&
     499            1 :     &           ' with respect to the training-set before attempted bounding (meV^2/atm):',&
     500            1 :     &           ch10,'   Energy          : ',&
     501            1 :     &           mse_ini* (Ha_EV*1000)**2 *factor ,ch10,&
     502            1 :     &           ' Goal function values of the effective.potential',ch10,&
     503            1 :     &           ' with respect to the test-set (eV^2/A^2):',ch10,&
     504            1 :     &           '   Forces+Stresses : ',&
     505            1 :     &           (msef_ini+mses_ini)*(HaBohr_eVAng)**2,ch10,&
     506            1 :     &           '   Forces          : ',&
     507            1 :     &           msef_ini*(HaBohr_eVAng)**2,ch10,&
     508            1 :     &           '   Stresses        : ',&
     509            2 :     &           mses_ini*(HaBohr_eVAng)**2,ch10
     510            1 :   call wrtout(ab_out,message,'COLL')
     511            1 :   call wrtout(std_out,message,'COLL')
     512              : 
     513              :   !MS DEV
     514              :   ! single displacement terms with second order only.
     515            1 :   call opt_getSingleDispTerms(singledisp_terms,eff_pot%crystal, sc_size,comm)
     516              : 
     517              : 
     518              :   ! create pair list:
     519            1 :   call sympairs%init(eff_pot%crystal, sc_size)
     520              : 
     521              :   !For the moment order loop commented
     522              :   !do iorder=order(1),order(2),2, Order will be done per term
     523              :   !Loop over all original terms + 1
     524              :   ! + 1 to bound pure strain
     525            3 :   do iterm =1,nterm +1
     526            2 :     if(iterm <=nterm)then
     527            1 :       ncombi1=0
     528            1 :       ncombi2=0
     529            1 :       ncombi1_real=0
     530            1 :       ncombi2_real=0
     531              :       !Store for optimization
     532            1 :       terms(iterm) = iterm
     533              :       !Message: The world wants to know where we stand Batman
     534            1 :       write(message, '(a,(80a),a)' ) ch10,&
     535           81 :         &      ('_',ii=1,80),ch10
     536            1 :       call wrtout(ab_out,message,'COLL')
     537            1 :       call wrtout(std_out,message,'COLL')
     538            1 :       write(message,'(2a,I3,a,I3,3a)' )ch10,&
     539            2 :         &       ' Check term (',iterm,'/',nterm,'): ', trim(eff_pot%anharmonics_terms%coefficients(iterm)%name),ch10
     540            1 :       call wrtout(ab_out,message,'COLL')
     541            1 :       call wrtout(std_out,message,'COLL')
     542            1 :       to_skip = .FALSE.
     543            1 :       to_skip = check_to_skip(eff_pot%anharmonics_terms%coefficients(iterm))
     544              :       !Skip term if it doesn't need bounding
     545            1 :       if(.not. to_skip)then
     546              :         associate(term1=>eff_pot%anharmonics_terms%coefficients(iterm)%terms(1))
     547            1 :         nbody_term = term1%get_nbody()
     548              : 
     549              :         !Get List of high order single Terms for terms
     550              :         call opt_getHOSingleDispTerms(eff_pot%anharmonics_terms%coefficients(iterm),&
     551            1 :           &                                      HOsingledisp_terms,symbols,singledisp_terms,order_ran,ncombi1)
     552              : 
     553            4 :         ABI_MALLOC(my_coeffs,(size(eff_pot%anharmonics_terms%coefficients)))
     554            1 :         my_coeffs=eff_pot%anharmonics_terms%coefficients
     555            1 :           do icombi3=1, size(my_coeffs)
     556              :            !DMSG(my_coeffs(icombi3)%debug_str)
     557              :           end do
     558              : 
     559              :         ! then add the single disp terms.
     560            1 :         if (ncombi1>0) then
     561            3 :           do icombi3=1,ncombi1
     562            3 :             if (HOsingledisp_terms(icombi3)%terms(1)%get_nbody() == nbody_term .or. bound_option/=1) then
     563            0 :               call coeffs_list_append(my_coeffs,HOsingledisp_terms(icombi3), check=.TRUE.)
     564              :               !DMSG(my_coeffs(icombi3)%debug_str)
     565            0 :               ncombi1_real = ncombi1_real + 1
     566              :             endif
     567              :           end do
     568              :         endif
     569              : 
     570            1 :         if(allocated(HOsingledisp_terms)) call polynomial_coeff_list_free(HOsingledisp_terms)
     571              : 
     572              : 
     573              :         !Get List of high order cross Terms for term if ndisp > 1
     574            1 :         if(term1%ndisp>1 .or. &
     575              :             & term1%ndisp /= 0 .and. & ! why >1 or /=0?
     576              :             & term1%nstrain /= 0)then
     577              :             ! output HOcrossdisp_terms, ncombi2.
     578            1 :             call opt_getHOcrossdisp(HOcrossdisp_terms,ncombi2,eff_pot%anharmonics_terms%coefficients(iterm),order_ran)
     579              :         endif
     580              :         ! then add the crossdisp terms.
     581            1 :         if(ncombi2 > 0)then
     582            4 :           do icombi3=1,ncombi2
     583              :             !call coeffs_list_conc_onsite(my_coeffs, HOcrossdisp_terms(icombi3))
     584            4 :             if (HOcrossdisp_terms(icombi3)%terms(1)%get_nbody() == nbody_term .or. bound_option/=1) then
     585            1 :               call coeffs_list_append(my_coeffs,HOcrossdisp_terms(icombi3), check=.TRUE.)
     586            1 :               ncombi2_real = ncombi2_real + 1
     587              :               !DMSG(my_coeffs(ncombi2_real)%debug_str)
     588              :             endif
     589              :           end do
     590              :         endif
     591            2 :         if(allocated(HOcrossdisp_terms)) call polynomial_coeff_list_free(HOcrossdisp_terms)
     592              :        end associate
     593              :       else  ! to_skip
     594              :         ncombi2=0
     595              :         ncombi1=0
     596            0 :         ABI_MALLOC(my_coeffs,(size(eff_pot%anharmonics_terms%coefficients)))
     597            0 :         my_coeffs = eff_pot%anharmonics_terms%coefficients
     598              :       endif
     599            1 :       ncombi =  ncombi1_real + ncombi2_real
     600            1 :       nterm_start = eff_pot%anharmonics_terms%ncoeff
     601              :     else ! if iterm = nterm + 1 => Take care about strain
     602              :         block
     603            1 :         integer :: max_nbody_tmp(order_ran(2))
     604            1 :         if (bound_option==1) then
     605            7 :             max_nbody_tmp(:) = 1
     606              :         else
     607            0 :             max_nbody_tmp(:) = 888
     608              :         endif
     609            1 :          call opt_getHOstrain(my_coeffs,ncombi,nterm_start,eff_pot,order_ran,comm, max_nbody=max_nbody_tmp)
     610              :         end block
     611              :     endif !
     612              : 
     613              : 
     614              :     ! Modification of Alireza.
     615              :     !---------------------------------------------
     616              : !Here my_coeffs contains the previous coeff and the new bounding ones. wight is allways +1 so the power in SAT generation does not matter!!
     617              : 
     618              :     ! 1. We need to use generateTermsFromList module to create terms.
     619              :     ! 2. The  generateTermsFromList module accepts list combinations of terms: (\1,1,1,1,7,7\)
     620              :     ! 3. We need to convert the terms from bounding process to a list like (\1,1,1,1,7,7\)
     621              :     ! 4. use polynomial_coeff_getList to get pairs.
     622              :     ! 5. compare th list and the terms and find out what is the number of diplacement in list for a term.
     623              :     ! 6. convert term to list.
     624              :     ! 7. ask for the temrs from generateTermsFromList
     625              :     ! 8. check and see if the coeff is already considered or not. use coeffs_compare function
     626              :     !! strain the same thing should be done for the strain
     627              :     !! find the list of all the list_str,
     628              :     !! fond what is number of strain in the displacemt comapring it to
     629              :     !! the list_str and give this to
     630              :     !     get coeff from > generateTermsFromList(list_disp,****)
     631              :     !     setcoeff_to_tmp_coeffs
     632              :     ! generateTermsFromList(cell,index_coeff,list_coeff,list_str,ncoeff,ndisp_max,nrpt,nstr,nsym,nterm,terms)
     633              : 
     634              : ! call the new function to get the data required to call polynomial_coeff_getList
     635              : 
     636              : 
     637            2 :     call generate_bounding_term_and_add_to_list( sympairs, nterm_start, ncombi, my_coeffs, temp_cntr)
     638              : 
     639              : 
     640              : 
     641            2 :     if (temp_cntr>0) then
     642            5 :       do icombi=1,temp_cntr
     643              :         ! Copy all the terms in eff pot
     644              :         call polynomial_coeff_getName(name, &
     645            3 :           & my_coeffs(nterm_start+icombi),symbols,recompute=.TRUE.)
     646            3 :         call polynomial_coeff_SetName(name,my_coeffs(nterm_start+icombi))
     647              : 
     648              :         ! Set dimensions of temporary my_coeffs array
     649            3 :         nterm2 = eff_pot%anharmonics_terms%ncoeff + 1
     650           18 :         ABI_MALLOC(my_coeffs_tmp,(nterm2))
     651              :         ! Copy terms of previous cycle
     652            3 :         my_coeffs_tmp(1:nterm2-1) = eff_pot%anharmonics_terms%coefficients
     653              :         !Put new term to my_coeffs_tmp
     654           33 :         my_coeffs_tmp(nterm2) = my_coeffs(nterm_start+icombi)
     655              : 
     656              : 
     657              :         !call polynomial_coeff_init(my_coeffs(nterm_start+icombi)%coefficient, &
     658              :         !  & my_coeffs(nterm_start+icombi)%nterm, &
     659              :         !  & my_coeffs_tmp(nterm2),my_coeffs(nterm_start+icombi)%terms, &
     660              :         !  &my_coeffs(nterm_start+icombi)%name)
     661              : 
     662              :         !  DMSG(my_coeffs_tmp(nterm2)%debug_str)
     663              : 
     664              :         ! If order is greater than specified cycle
     665           14 :         if(sum(my_coeffs_tmp(nterm2)%terms(1)%power_disp) &
     666              :           &             +sum(my_coeffs_tmp(nterm2)%terms(1)%power_strain) > maxval(order_ran))then
     667            0 :           call polynomial_coeff_list_free(my_coeffs_tmp)
     668            0 :           cycle
     669              :         endif
     670              :         ! Message to Output
     671            3 :         write(message,'(5a)' )ch10,&
     672            6 :           &            ' ==> high order term: ', trim(my_coeffs_tmp(nterm2)%name),' created',ch10
     673            3 :         call wrtout(ab_out,message,'COLL')
     674            3 :         call wrtout(std_out,message,'COLL')
     675              :         ! Check if generated term is not already contained in effpot
     676              :         ! If yes cycle
     677            9 :         ABI_MALLOC(exists, (nterm2))
     678           12 :         exists=.FALSE.
     679            9 :         do jterm=1,nterm2-1
     680            9 :           exists(jterm) = coeffs_compare(my_coeffs_tmp(jterm),my_coeffs_tmp(nterm2))
     681              :         enddo !jterm
     682           12 :         any_exists=any(exists)
     683            3 :         ABI_SFREE(exists)
     684            3 :         if(any_exists)then
     685            0 :           write(message,'(3a)' )ch10,&
     686            0 :             &              '   ==> Term exists already. We cycle',ch10
     687            0 :           call wrtout(ab_out,message,'COLL')
     688            0 :           call wrtout(std_out,message,'COLL')
     689            0 :           call polynomial_coeff_list_free(my_coeffs_tmp)
     690            0 :           cycle
     691              :         endif
     692              : 
     693              : 
     694              :         ! Set new term into effective potential
     695            3 :         call effective_potential_setCoeffs(my_coeffs_tmp,eff_pot,nterm2)
     696              : 
     697              :         ! Tell the world what we do, They want to know.
     698            3 :         write(message,'(3a)' )ch10,&
     699            6 :           &           '   ==> Optimizing coefficient',ch10
     700            3 :         call wrtout(ab_out,message,'COLL')
     701            3 :         call wrtout(std_out,message,'COLL')
     702              : 
     703              :         ! Deallocation in loop
     704            3 :         call polynomial_coeff_list_free(my_coeffs_tmp)
     705              :         !Optimizing coefficient old style
     706              : 
     707            5 :         if(iterm>nterm)then
     708              :           ! MS 2006 Decomment for old style optimization
     709              :           call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
     710              :                     &   natom_sc,ntime,fit_data%training_set%sqomega,comm,&
     711            2 :                     &   compute_anharmonic=.TRUE.,print_file=.FALSE., weights=my_weights)
     712            2 :           i = 0
     713            2 :           write(message,'(a,I2,a,ES24.16)') "cycle ", i ," (msef+mses)/(msef_ini+mses_ini): ", (msef+mses)/(msef_ini+mses_ini)
     714            2 :           call wrtout(std_out,message,'COLL')
     715            2 :           write(message,'(a,I2,a,ES24.16)') "cycle ", i ," (msef+mses): ", (msef+mses)
     716            2 :           call wrtout(std_out,message,'COLL')
     717            2 :           do  while((msef+mses)/(msef_ini+mses_ini) >= 1.001)
     718            0 :             i = i + 1
     719              :             eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = &!coeff_ini / 2**i
     720            0 :               &                  eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient / 2**1
     721              :             call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
     722              :               &                                              natom_sc,ntime,fit_data%training_set%sqomega,comm,&
     723            0 :               &                                              compute_anharmonic=.TRUE.,print_file=.FALSE., weights=my_weights)
     724              : 
     725            0 :             write(message,'(a,I2,a,ES24.16)') "cycle ",i," (msef+mses)/(msef_ini+mses_ini): ",(msef+mses)/(msef_ini+mses_ini)
     726            0 :             call wrtout(std_out,message,'COLL')
     727            0 :             write(message,'(a,I2,a,ES24.16)') "cycle ", i ," (msef+mses): ", (msef+mses)
     728            0 :             call wrtout(std_out,message,'COLL')
     729              :           enddo ! while mse/mse_ini>1.0001
     730            2 :           write(message,'(a,ES24.16)') "coeff after opt:",   eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient
     731            2 :           call wrtout(std_out,message,'COLL')
     732            2 :           msef_ini = msef
     733            2 :           mses_ini = mses
     734              :           !           !Optimize coefficient with opt routine
     735              :           !           optterm(1)= nterm2
     736              :           !           nterm_opt = 1
     737              :           !           call opt_effpot(eff_pot,nterm_opt,optterm,hist,comm,print_anh=.FALSE.)
     738              :           !           write(*,*) "coeff after opt:",   eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient
     739              :           !            !Store new "inital precision for next coefficient
     740              :           !            msef_ini = msef
     741              :           !            mses_ini = mses
     742              : 
     743              :         else
     744              :           !Optimizing coefficient with GF criterion
     745            1 :           coeff_opt = 0
     746            1 :           GF_arr = 0
     747            1 :           i = 1
     748            3 :           do while(i<=2)
     749              :             eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = &
     750            2 :               &                eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient/ 2**(i-1)
     751              :             call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
     752              :               &                natom_sc,ntime,fit_data%training_set%sqomega,comm,&
     753            2 :               &                compute_anharmonic=.TRUE.,print_file=.FALSE.)
     754              :             GF_arr(i) =  (bound_factors(1)*bound_EFS(1)*mse+bound_factors(2)*bound_EFS(2)*msef&
     755              :               &                +bound_factors(3)*bound_EFS(3)*mses) / &
     756              :               &                (bound_factors(1)*bound_EFS(1)*mse_ini+bound_factors(2)*bound_EFS(2)*msef_ini&
     757            2 :               &                +bound_factors(3)*bound_EFS(3)*mses_ini)
     758            2 :             write(message,'(a,I2,a,ES24.16)') "cycle ",i," GF/GF_ini: ",GF_arr(i)
     759            2 :             call wrtout(std_out,message,'COLL')
     760            2 :             write(message,'(a,I2,a,ES24.16)') "cycle ", i ," GF: ",(bound_factors(1)*bound_EFS(1)*mse&
     761              :               &                                                                       +bound_factors(2)*bound_EFS(2)*msef&
     762            4 :               &                                                                       +bound_factors(3)*bound_EFS(3)*mses)
     763            2 :             call wrtout(std_out,message,'COLL')
     764            2 :             coeff_opt(i) =  eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient
     765            3 :             if(i==2 .and. abs(GF_arr(1)-GF_arr(2)) < tol8)then
     766              :               eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient =&
     767            0 :                 eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient*10d5
     768            0 :               write(message,'(5a)') ch10,"Differences between test-cycles to small increase",ch10, &
     769            0 :                 &                                          "test coefficient value by factor 1000",ch10
     770            0 :               call wrtout(std_out,message,'COLL')
     771            0 :               i = i+1
     772              :               ! This is weird, it keeps on increasing the coefficient by 1000, until a NaN is reached.
     773              :             else
     774            2 :               i=i+1
     775              :             end if
     776              :           enddo ! while mse/mse_ini>10
     777            1 :           if (eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient /= eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient) then
     778            0 :             eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = 0.0_dp
     779              :           end if
     780              : 
     781            1 :           eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = opt_boundcoeff(GF_arr,coeff_opt,bound_penalty)
     782            1 :           if (eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient /= eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient) then
     783            0 :             eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = 0.0_dp
     784              :           end if
     785              : 
     786            1 :           write(message,'(a,ES24.16)') "coeff after opt1:",   eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient
     787            1 :           call wrtout(std_out,message,'COLL')
     788            1 :           coeff_tmp = ANINT(eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient*10d10)
     789            1 :           eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient = coeff_tmp/10d10
     790            1 :           write(message,'(a,ES24.16)') "coeff after opt2:",   eff_pot%anharmonics_terms%coefficients(nterm2)%coefficient
     791            1 :           call wrtout(std_out,message,'COLL')
     792              :           call fit_polynomial_coeff_computeMSD(eff_pot,hist,mse,msef,mses,&
     793              :             &                                               natom_sc,ntime,fit_data%training_set%sqomega,comm,&
     794            1 :             &                                               compute_anharmonic=.TRUE.,print_file=.FALSE.)
     795            1 :           write(message,'(a,ES24.16)') "GF/GF_ini after_opt: ", (bound_factors(1)*bound_EFS(1)*mse&
     796              :             &                                                                     +bound_factors(2)*bound_EFS(2)*msef&
     797              :             &                                                                     +bound_factors(3)*bound_EFS(3)*mses) / &
     798              :             &                                                                     (bound_factors(1)*bound_EFS(1)*mse_ini&
     799              :             &                                                                     +bound_factors(2)*bound_EFS(2)*msef_ini&
     800            2 :             &                                                                     +bound_factors(3)*bound_EFS(3)*mses_ini)
     801            1 :           call wrtout(std_out,message,'COLL')
     802            1 :           mse_ini  = mse
     803            1 :           msef_ini = msef
     804            1 :           mses_ini = mses
     805              :         endif
     806              :         !DEALLOCATION
     807              :         !ABI_FREE(exists)
     808              :       enddo ! icombi
     809              :     end if
     810              : 
     811            5 :     call polynomial_coeff_list_free(my_coeffs)
     812              :   end do !iterm
     813              :   !enddo ! order
     814              : 
     815            1 :   if(allocated(singledisp_terms)) call polynomial_coeff_list_free(singledisp_terms)
     816              : 
     817            1 :   write(message, '(a,(80a),a)' ) ch10,&
     818           81 :     &('_',ii=1,80),ch10
     819            1 :   call wrtout(ab_out,message,'COLL')
     820            1 :   call wrtout(std_out,message,'COLL')
     821              : 
     822            1 :   write(message,'(3a)' )ch10,&
     823            2 :     &     ' Finished creating high-order terms',ch10  !,&
     824              :   !&     ' Optimize initial anharmonic terms !NOT IS COMMENTED NOW!',ch10
     825            1 :   call wrtout(ab_out,message,'COLL')
     826            1 :   call wrtout(std_out,message,'COLL')
     827              :   !  call opt_effpot(eff_pot,nterm,terms,hist,comm,print_anh=.FALSE.)
     828              : 
     829              :   !  Print the standard devition of final model
     830            1 :   write(message,'(6a,ES24.16,6a,ES24.16,2a,ES24.16,2a,ES24.16,a)' )ch10,&
     831            1 :     &                    ' Mean Standard Deviation values of the effective-potential',ch10,&
     832            1 :     &                    ' with respect to the training-set after attempted bounding (meV^2/atm):',&
     833            1 :     &               ch10,'   Energy          : ',&
     834            1 :     &               mse_ini* (Ha_EV*1000)**2 *factor ,ch10,&
     835            1 :     &                    ' Goal function values of the effective.potential',ch10,&
     836            1 :     &                    ' with respect to the test-set (eV^2/A^2):',ch10,&
     837            1 :     &                    '   Forces+Stresses : ',&
     838            1 :     &               (msef_ini+mses_ini)*(HaBohr_eVAng)**2,ch10,&
     839            1 :     &                    '   Forces          : ',&
     840            1 :     &               msef_ini*(HaBohr_eVAng)**2,ch10,&
     841            1 :     &                    '   Stresses        : ',&
     842            2 :     &               mses_ini*(HaBohr_eVAng)**2,ch10
     843            1 :   call wrtout(ab_out,message,'COLL')
     844            1 :   call wrtout(std_out,message,'COLL')
     845              : 
     846              : 
     847              :   !DEALLOCATION
     848            1 :   ABI_SFREE(symbols)
     849            1 :   ABI_SFREE(terms)
     850            1 :   ABI_SFREE(my_weights)
     851              : 
     852              :   !ABI_FREE(my_coeffs)
     853            1 :   call fit_data_free(fit_data)
     854            1 :   call sympairs%free()
     855              : 
     856              : 
     857            1 : end subroutine opt_effpotbound
     858              : !!***
     859              : 
     860              : 
     861              : !!****f* m_opt_effpot/opt_getHOforterm
     862              : !!
     863              : !! NAME
     864              : !! opt_effpotbound
     865              : !!
     866              : !! FUNCTION
     867              : !! Compute possible high orders for a given anharmonic term.
     868              : !! In the range of order_start,order_stop
     869              : !!
     870              : !!
     871              : !! INPUTS
     872              : !! term<polynomial_coeff_type>:anharmonic term
     873              : !! order_range(2):start and stop order desired by user
     874              : !!
     875              : !!
     876              : !! OUTPUT
     877              : !! order_start:possible start order
     878              : !! order_stop: possible stop order
     879              : !!
     880              : !! SOURCE
     881              : 
     882            2 : subroutine opt_getHOforterm(term,order_range,order_start,order_stop)
     883              : 
     884              :   !Arguments ------------------------------------
     885              :   !scalars
     886              :   type(polynomial_coeff_type),intent(in) :: term
     887              :   !arrays
     888              :   integer,intent(in) :: order_range(2)
     889              :   integer,intent(out) :: order_start, order_stop
     890              :   !Logicals
     891              :   !Strings
     892              :   !Local variables ------------------------------
     893              :   !scalars
     894              :   integer :: idisp,ndisp,nstrain,nterm_of_term,power_tot
     895              :   integer :: nbody_tot
     896              :   !arrays
     897            2 :   integer,allocatable :: powers(:)
     898              :   !Logicals
     899              :   !Strings
     900              :   !*************************************************************************
     901              : 
     902              :   !Get/Initialize variables
     903            2 :   ndisp = term%terms(1)%ndisp
     904            2 :   nstrain = term%terms(1)%nstrain
     905            2 :   nbody_tot = ndisp + nstrain
     906            2 :   nterm_of_term = term%nterm
     907              : 
     908            6 :   ABI_MALLOC(powers,(nbody_tot))
     909            6 :   powers(:ndisp) = term%terms(1)%power_disp
     910            3 :   powers(ndisp+1:) = term%terms(1)%power_strain
     911            7 :   power_tot = 0
     912              :   !write(std_out,*) "powers in getHOforterm", powers
     913              : 
     914              :   !Get rid off odd displacements
     915            7 :   do idisp=1,nbody_tot
     916            7 :     if(idisp <= ndisp .and. mod(powers(idisp),2) == 1)then
     917            2 :       powers(idisp) = powers(idisp) + 1
     918            3 :     else if(mod(powers(idisp),2) == 1)then
     919            1 :       powers(idisp) = powers(idisp) + 1
     920              :     endif
     921              :   enddo !idisp
     922              :   ! Count order
     923            7 :   do idisp=1,nbody_tot
     924            7 :     power_tot = power_tot + powers(idisp)
     925              :   enddo
     926              :   ! Get start and stop order for this term
     927              :   ! If term doesn't fit in order range give back order_start = order_stop = 0
     928            2 :   if(power_tot >= order_range(1) .and. power_tot <=order_range(2))then
     929            1 :     order_start = power_tot
     930            1 :     order_stop  = order_range(2)
     931            1 :   elseif(power_tot < order_range(1))then
     932            1 :     order_start = order_range(1)
     933            1 :     order_stop  = order_range(2)
     934            0 :   elseif(power_tot > order_range(2))then
     935            0 :     order_start = 0
     936            0 :     order_stop  = 0
     937              :   endif
     938              : 
     939            2 :   ABI_SFREE(powers)
     940              : 
     941            2 : end subroutine opt_getHOforterm
     942              : !!***
     943              : 
     944              : 
     945              : !!****f* m_opt_effpot/opt_getCombisforterm
     946              : !!
     947              : !! NAME
     948              : !! opt_getCombisforterm
     949              : !!
     950              : !! FUNCTION
     951              : !! For a given order range: order_start, order_stop
     952              : !! calculate number of total possible combinations ncombi
     953              : !! and calculat combinations per order ncombi_order(i)
     954              : !!
     955              : !!
     956              : !! INPUTS
     957              : !! order_start: start order for bounding terms
     958              : !! order_end: end order for bounding terms
     959              : !! ndisp: number of displacements a given term contains
     960              : !!
     961              : !!
     962              : !! OUTPUT
     963              : !! ncombi: total number of combinations
     964              : !! ncombi_order: array with number of combinations per order
     965              : !!
     966              : !!
     967              : !! SOURCE
     968              : 
     969            2 : subroutine opt_getCombisforterm(order_start,order_end,ndisp,ncombi,ncombi_order)
     970              : 
     971              :   !Arguments ------------------------------------
     972              :   !scalars
     973              :   integer,intent(in) :: ndisp
     974              :   integer,intent(in) :: order_start, order_end
     975              :   !arrays
     976              :   integer,intent(out) :: ncombi
     977              :   integer,intent(out) :: ncombi_order(:)
     978              :   !Logicals
     979              :   !Strings
     980              :   !Local variables ------------------------------
     981              :   !scalars
     982              :   integer :: i
     983              :   integer :: order,iorder1,iorder2
     984              :   !arrays
     985              :   !integer
     986              :   !Logicals
     987              :   !Strings
     988              :   character(len=1000) :: message
     989              :   !*************************************************************************
     990              : 
     991              :   !Test
     992            2 :   if(mod(order_start,2) /= 0 .or. mod(order_end,2) /= 0)then
     993              :     ! Message to Output
     994            0 :     write(message,'(4a)' )ch10,&
     995            0 :       &  'Either start or stop order are not even numbers',ch10,&
     996            0 :       &  'Action: change bound_range in input',ch10
     997            0 :     ABI_ERROR(message)
     998              :   endif
     999              : 
    1000              :   !Initialize Variables
    1001            2 :   i = 0
    1002            2 :   ncombi = 0
    1003            4 :   ncombi_order = 0
    1004              : 
    1005              :   !Calculate Combinations
    1006            4 :   do order=order_start,order_end,2
    1007            2 :     i = i+1
    1008            4 :     if(ndisp == 1)then
    1009            0 :       ncombi = ncombi + 1
    1010            0 :       ncombi_order(i) = 1
    1011              :     else
    1012            5 :       do iorder1 = 2,order-2*(ndisp-1),2
    1013            3 :         if(ndisp*iorder1 == order)then
    1014            1 :           ncombi = ncombi + 1
    1015            1 :           ncombi_order(i) = ncombi_order(i) + 1
    1016            1 :           cycle
    1017              :         endif
    1018            5 :         do iorder2=iorder1+2,order-2*(ndisp-1),2
    1019            3 :           if( iorder1 + (ndisp-1)*iorder2 == order)then
    1020            1 :             ncombi = ncombi + ndisp
    1021            1 :             ncombi_order(i) = ncombi_order(i) + ndisp
    1022            0 :           elseif(iorder1 * (ndisp-1) + iorder2 == order)then
    1023            0 :             ncombi = ncombi + ndisp
    1024            0 :             ncombi_order(i) = ncombi_order(i) + ndisp
    1025              :           endif
    1026              :         enddo !iorder2
    1027              :       enddo !iorder1 !
    1028              :     endif
    1029              :     !write(*,*) 'ncombi(',i,') for order',order,' is:', ncombi_order(i), 'are we happy?'
    1030              :   enddo !order
    1031              : 
    1032              :   !write(*,*) ncombi_order(:)
    1033              :   !write(*,*) 'ncombi for term is:', ncombi, 'are we happy?'
    1034              : 
    1035              : 
    1036            2 : end subroutine opt_getCombisforterm
    1037              : !!***
    1038              : 
    1039              : !!****f* m_opt_effpot/opt_getHoTerms
    1040              : !!
    1041              : !! NAME
    1042              : !! opt_geHoTerms
    1043              : !!
    1044              : !! FUNCTION
    1045              : !! For a term give all possible high order terms
    1046              : !! Attention order_start, order_stop, ncombi and
    1047              : !! ncombi_order have to be calculated before!
    1048              : !!
    1049              : !!
    1050              : !!
    1051              : !! INPUTS
    1052              : !! eff_pot: existing effective potential
    1053              : !! order: order for which bounding terms are generated
    1054              : !!
    1055              : !!
    1056              : !! OUTPUT
    1057              : !! eff_pot new effective potential
    1058              : !!
    1059              : !!
    1060              : !! SOURCE
    1061              : 
    1062            2 : subroutine opt_getHoTerms(terms,order_start,order_stop,ndisp,ncombi_order)
    1063              : 
    1064              :   !Arguments ------------------------------------
    1065              :   !scalars
    1066              :   integer,intent(in) :: ndisp
    1067              :   integer,intent(in) :: order_start, order_stop
    1068              :   !arrays
    1069              :   integer,intent(in) :: ncombi_order(:)
    1070              :   !Logicals
    1071              :   type(polynomial_coeff_type),intent(inout) :: terms(:)
    1072              :   !Strings
    1073              :   !Local variables ------------------------------
    1074              :   !scalars
    1075              :   integer :: i,icombi,icombi2,icombi_start,icombi_stop,idisp,nterm_of_term
    1076              :   integer :: order,iterm_of_term,jdisp,power_tot
    1077              :   integer :: jdisp1,jdisp2,sec,nstrain,nbody_tot
    1078              :   real(sp) :: to_divide,divider1,divider2,divided
    1079              :   !arrays
    1080              :   !integer
    1081              :   !Logicals
    1082              :   logical :: equal_term_done
    1083              :   !Strings
    1084              :   character(len=1000) :: message
    1085              :   !*************************************************************************
    1086              :   !Get Variables
    1087            2 :   nterm_of_term = terms(1)%nterm
    1088            2 :   nstrain = terms(1)%terms(1)%nstrain
    1089            2 :   nbody_tot = ndisp + nstrain
    1090              : 
    1091              :   ! Create all possible combinaions for the specified orders
    1092              :   ! If anybody has ever, ever to read and understand this I'm terribly sorry
    1093              :   ! ---this will be quite hell---
    1094            2 :   power_tot = 0
    1095            2 :   icombi_start = 1
    1096            2 :   i = 0
    1097              :   !write(*,*) "what is ncombi?", ncombi
    1098              :   !write(*,*) "what is ncmobi_order", ncombi_order
    1099              : 
    1100              :   !write(*,*) "order_start", order_start
    1101              :   !write(*,*) "order_stop", order_stop
    1102            2 :   order = order_start
    1103              :   ! TODO work here icombi start and order counting does not work yet.
    1104            4 :   do order=order_start,order_stop,2
    1105              :     !write(std_out,*) 'Was I now here?!(order-loop)'
    1106            2 :     i = i + 1
    1107            2 :     icombi_stop = icombi_start + ncombi_order(i) - 1
    1108            2 :     equal_term_done = .FALSE.
    1109              :     !write(std_out,*) 'order', order
    1110              :     !write(std_out,*) 'icombi_start', icombi_start
    1111              :     !write(std_out,*) 'icombi_stop', icombi_stop
    1112            2 :     icombi=icombi_start
    1113            6 :     do while (icombi<=icombi_stop)
    1114              :       power_tot = 0
    1115            7 :       do idisp=1,nbody_tot
    1116              :         !write(*,*) "what is icombi here?", icombi
    1117              :         !write(*,*) "what is icombi_stop here?", icombi_stop
    1118            7 :         if(idisp<=ndisp)then
    1119            4 :           power_tot = power_tot + terms(icombi)%terms(1)%power_disp(idisp)
    1120              :         else
    1121            1 :           power_tot = power_tot + terms(icombi)%terms(1)%power_strain(idisp-ndisp)
    1122              :         endif
    1123              :       enddo
    1124              :       ! Probably have to increase order at same time
    1125              :       ! If the term already has the right order we cycle
    1126              :       ! we increase icombi_start and icombi to go to the next term in the array
    1127            4 :       if(power_tot == order)then
    1128            1 :         icombi_start = icombi_start + 1
    1129            1 :         icombi = icombi + 1
    1130              :         !write(*,*) 'icombi-start in if', icombi_start
    1131            1 :         cycle
    1132              :         ! If the term is not already in the right order, we manipulate it until
    1133              :         ! it is
    1134              :       else
    1135              :         jdisp1 = 1
    1136            3 :         sec = 1
    1137              :         !write(*,*) 'what is ndisp actually', ndisp
    1138              :         ! Treat single permutations from the bottom of the order
    1139              :         ! so start from ^2^2^2 and get ^6^2^2,^2^6^2, and ^2^2^6 f.E.
    1140              :         ! do loop over displacements
    1141            3 :         do while(jdisp1<=nbody_tot .and. sec < 100)
    1142              :           !write(*,*) "what is jdisp1 here?", jdisp1
    1143              :           !write(*,*) "what is icombi here?", icombi
    1144              :           !write(*,*) "what is icombi_sotp?", icombi_stop
    1145              :           ! Increase the order of the displacements
    1146           50 :           do iterm_of_term=1,nterm_of_term
    1147           50 :             if(jdisp1 <= ndisp)then
    1148              :               terms(icombi)%terms(iterm_of_term)%power_disp(jdisp1) =&
    1149           48 :                 &                            terms(icombi)%terms(iterm_of_term)%power_disp(jdisp1) + 2
    1150              :             else
    1151              :               terms(icombi)%terms(iterm_of_term)%power_strain(jdisp1-ndisp) =&
    1152            0 :                 &                            terms(icombi)%terms(iterm_of_term)%power_strain(jdisp1-ndisp) + 2
    1153              : 
    1154              :             endif
    1155              :           enddo
    1156              :           ! Check total order of term after increase
    1157              :           power_tot=0
    1158            6 :           do jdisp2=1,nbody_tot
    1159            6 :             if(jdisp2 <= ndisp)then
    1160            4 :               power_tot = power_tot + terms(icombi)%terms(1)%power_disp(jdisp2)
    1161              :             else
    1162            0 :               power_tot = power_tot + terms(icombi)%terms(1)%power_strain(jdisp2-ndisp)
    1163              :             endif
    1164              :           enddo
    1165              :           ! If the term is at the right order do next displacement
    1166              :           ! increase icombi and icombi_start to go to next term in array
    1167            3 :           if(power_tot == order)then
    1168            2 :             icombi = icombi + 1
    1169            2 :             icombi_start = icombi_start +1
    1170              :             !write(*,*) 'what is icombi_start here', icombi_start
    1171            2 :             jdisp1 = jdisp1 + 1
    1172              :             !write(*,*) 'and what is jdisp1?', jdisp1
    1173              : 
    1174              :           endif
    1175              :         enddo!jdisp1
    1176              :         !Treat permutations in terms ndisp > 2 and order >= 10
    1177              :         !Start f.E. from ^4^4^4 and get ^4^2^4, ^2^4^4,^4^4^2
    1178            1 :         if(icombi_stop - icombi > 1 .and. nbody_tot >2 )then
    1179            0 :           do icombi2=icombi,icombi+nbody_tot-1
    1180            0 :             do jdisp=1,nbody_tot
    1181            0 :               do iterm_of_term=1,nterm_of_term
    1182            0 :                 if(jdisp <= ndisp)then
    1183              :                   terms(icombi2)%terms(iterm_of_term)%power_disp(jdisp) = &
    1184            0 :                     &                                    terms(icombi2)%terms(iterm_of_term)%power_disp(jdisp) +2
    1185              :                   !write(*,*) "What's the power now?", terms(icombi2)%terms(iterm_of_term)%power_disp(jdisp)
    1186              :                 else
    1187              :                   terms(icombi2)%terms(iterm_of_term)%power_strain(jdisp-ndisp) = &
    1188            0 :                     &                                    terms(icombi2)%terms(iterm_of_term)%power_strain(jdisp-ndisp) +2
    1189              :                 endif
    1190              :               enddo
    1191              :             enddo !jdisp
    1192              :           enddo
    1193              :           jdisp1 = 1
    1194            0 :           do while(jdisp1<=nbody_tot .and. sec < 100)
    1195            0 :             sec = sec + 1
    1196              :             !write(*,*) "how often did I go here, hu ?"
    1197              :             !write(*,*) "I did at least one displacement"
    1198            0 :             do iterm_of_term=1,nterm_of_term
    1199            0 :               if(jdisp1 <= ndisp)then
    1200              :                 terms(icombi)%terms(iterm_of_term)%power_disp(jdisp1) =&
    1201            0 :                   &                                terms(icombi)%terms(iterm_of_term)%power_disp(jdisp1) + 2
    1202              :               else
    1203              :                 terms(icombi)%terms(iterm_of_term)%power_strain(jdisp1-ndisp) =&
    1204            0 :                   &                                terms(icombi)%terms(iterm_of_term)%power_strain(jdisp1-ndisp) + 2
    1205              : 
    1206              :               endif
    1207              :             enddo
    1208              :             power_tot=0
    1209            0 :             do jdisp2=1,nbody_tot
    1210            0 :               if(jdisp2 <= ndisp)then
    1211            0 :                 power_tot = power_tot + terms(icombi)%terms(1)%power_disp(jdisp2)
    1212              :               else
    1213            0 :                 power_tot = power_tot + terms(icombi)%terms(1)%power_strain(jdisp2-ndisp)
    1214              :               endif
    1215              :             enddo
    1216            0 :             if(power_tot == order)then
    1217            0 :               icombi = icombi + 1
    1218            0 :               icombi_start = icombi_start +1
    1219              :               !write(*,*) 'what is icombi_start here', icombi_start
    1220            0 :               jdisp1 = jdisp1 + 1
    1221              :               !write(*,*) 'and what is jdisp1?', jdisp1
    1222              :             endif
    1223              :           enddo!jdisp1
    1224              :           ! Message to Output
    1225              :           if(sec>100)then
    1226              :             write(message,'(4a)' )ch10,&
    1227              :               &                     "You're stuck in a while loop.",ch10,&
    1228              :               &                     'Action: Contact Abinit Group',ch10
    1229              :             ABI_ERROR(message)
    1230              :           endif
    1231              :         endif! (icombi_stop - icombi)
    1232              :         !write(*,*) 'I was here!'
    1233            1 :         to_divide = real(order)
    1234            1 :         divider1 = real(nbody_tot)
    1235            1 :         divided = real(to_divide/divider1)
    1236            1 :         divider2 = real(2)
    1237              :         !write(*,*) 'divided', divided, 'divider2', divider2
    1238              :         !Treat terms with even power f.E. ^2^2^2^2, ^4^4 etc...
    1239            1 :         if(mod(divided,divider2) == 0 .and. .not. equal_term_done .and. nbody_tot > 1)then
    1240              :           !write(*,*) "Sometimes I should be here sometimes I shouldn't"
    1241            0 :           do jdisp=1,nbody_tot
    1242            0 :             do iterm_of_term=1,nterm_of_term
    1243            0 :               if(jdisp<=ndisp)then
    1244            0 :                 terms(icombi)%terms(iterm_of_term)%power_disp(jdisp) = order/ndisp
    1245              :               else
    1246            0 :                 terms(icombi)%terms(iterm_of_term)%power_strain(jdisp-ndisp) = order/ndisp
    1247              :               endif
    1248              :             enddo
    1249              :           enddo !jdisp
    1250            0 :           if(order < order_stop)then
    1251            0 :             do icombi2=icombi+1,icombi+nbody_tot
    1252            0 :               do jdisp=1,nbody_tot
    1253            0 :                 do iterm_of_term=1,nterm_of_term
    1254            0 :                   if(jdisp<=ndisp)then
    1255            0 :                     terms(icombi2)%terms(iterm_of_term)%power_disp(jdisp) = order/ndisp
    1256              :                   else
    1257            0 :                     terms(icombi2)%terms(iterm_of_term)%power_strain(jdisp-ndisp) = order/ndisp
    1258              :                   endif
    1259              :                 enddo
    1260              :               enddo !jdisp
    1261              :             enddo
    1262              :           endif
    1263            0 :           equal_term_done = .TRUE.
    1264            0 :           icombi = icombi + 1
    1265            0 :           icombi_start = icombi_start +1
    1266              :         endif ! equal term if
    1267              :       endif ! power_tot == order
    1268              :     enddo !icombination
    1269              :   enddo !order
    1270              : 
    1271            2 : end subroutine opt_getHoTerms
    1272              : !!***
    1273              : 
    1274              : !!****f* m_opt_effpot/opt_filterdisp
    1275              : !!
    1276              : !! NAME
    1277              : !! opt_opt_filterdisp
    1278              : !!
    1279              : !! FUNCTION
    1280              : !! If a anharmonic term represents a strain-phonon coupling
    1281              : !! delete the strain and only keep the displacement part.
    1282              : !!
    1283              : !!
    1284              : !! INPUTS
    1285              : !! term<polynomial_coeff_type>: anharmonic term to check
    1286              : !! nterm_of_term: number of symmetry equivalent terms for term
    1287              : !!
    1288              : !! OUTPUT
    1289              : !! term<polynomial_coeff_type>: only the displacement part of original term
    1290              : !!
    1291              : !! SOURCE
    1292              : 
    1293            1 : subroutine opt_filterdisp(term,nterm_of_term)
    1294              : 
    1295              :   !Arguments ------------------------------------
    1296              :   !scalars
    1297              :   type(polynomial_coeff_type),intent(inout) :: term
    1298              :   integer,intent(in) :: nterm_of_term
    1299              :   !arrays
    1300              :   !Logicals
    1301              :   !Strings
    1302              :   !Local variables ------------------------------
    1303              :   !scalars
    1304              :   integer :: iterm_of_term
    1305              :   !reals
    1306              :   real(dp) :: coeff
    1307              :   !arrays
    1308          242 :   type(polynomial_term_type) :: terms(nterm_of_term)
    1309              :   !Logicals
    1310              :   !Strings
    1311              :   !*************************************************************************
    1312              : 
    1313           25 :   do iterm_of_term=1,nterm_of_term
    1314              :     !terms(iterm_of_term) = term%terms(iterm_of_term)
    1315              : 
    1316              :     call polynomial_term_init(term%terms(iterm_of_term)%atindx, &
    1317              :       & term%terms(iterm_of_term)%cell,&
    1318              :       & term%terms(iterm_of_term)%direction,&
    1319              :       & term%terms(iterm_of_term)%ndisp, &
    1320              :       & term%terms(iterm_of_term)%nstrain, &
    1321              :       & terms(iterm_of_term),&
    1322              :       & term%terms(iterm_of_term)%power_disp, &
    1323              :       & term%terms(iterm_of_term)%power_strain,&
    1324              :       & term%terms(iterm_of_term)%strain, &
    1325              :       & term%terms(iterm_of_term)%weight, &
    1326           24 :       & check=.TRUE.)
    1327           24 :     terms(iterm_of_term)%nstrain = 0
    1328           48 :     terms(iterm_of_term)%power_strain = 0
    1329           49 :     terms(iterm_of_term)%strain = 0
    1330              :   !DMSG(terms(iterm_of_term)%debug_str)
    1331              :   enddo
    1332              : 
    1333            1 :   call polynomial_coeff_free(term)
    1334              :   !Reinitial term
    1335              :   !check=.TRUE. checks for duplicate terms
    1336            1 :   call polynomial_coeff_init(coeff,nterm_of_term,term,terms, check=.TRUE.)
    1337              :   !DMSG(term%debug_str)
    1338              : 
    1339              : 
    1340           25 :   do iterm_of_term=1,nterm_of_term
    1341           25 :     call polynomial_term_free(terms(iterm_of_term))
    1342              :   enddo
    1343              :   !if(nterm_of_term /= term%nterm)then
    1344              :   !  write(*,*) "nterm_of_term changed after deleting strain"
    1345              :   !endif
    1346              : 
    1347              : 
    1348          192 : end subroutine opt_filterdisp
    1349              : !!***
    1350              : 
    1351              : !!****f* m_opt_effpot/opt_getHOstrain
    1352              : !!
    1353              : !! NAME
    1354              : !! opt_getHOstrain
    1355              : !!
    1356              : !! FUNCTION
    1357              : !! Get HO anharmnonic strain terms for bounding and add them to list
    1358              : !! of existing terms in effective potential
    1359              : !!
    1360              : !! INPUTS
    1361              : !! eff_pot<effective_potential_type>: datatype with all the information
    1362              : !!                                    about the effective potential
    1363              : !! power_strain(2): start and stop order for strain terms
    1364              : !! comm: mpi communicator (at the moment only sequential tested)
    1365              : !!
    1366              : !! OUTPUT
    1367              : !! terms<polynomial_coeff_type>: list with original terms in effective
    1368              : !!                               potential + HO even strain terms
    1369              : !!
    1370              : !! SOURCE
    1371              : 
    1372            1 : subroutine opt_getHOstrain(terms,ncombi,nterm_start,eff_pot,power_strain,comm, max_nbody)
    1373              : 
    1374              :   !Arguments ------------------------------------
    1375              :   !scalars
    1376              :   integer,intent(in) :: comm
    1377              :   type(polynomial_coeff_type),allocatable,intent(inout) :: terms(:)
    1378              :   type(effective_potential_type), intent(in) :: eff_pot
    1379              :   integer,intent(in) :: power_strain(2), max_nbody(:)
    1380              :   integer,intent(out) :: ncombi,nterm_start
    1381              :   !arrays
    1382              :   !Logicals
    1383              :   !Strings
    1384              :   !Local variables ------------------------------
    1385              :   !scalars
    1386              :   integer ::  nterm_tot_tmp
    1387              :   integer :: i,ii
    1388              :   !integer :: nbody, ref_nbody
    1389              :   real(dp) :: coeff_ini
    1390              :   !reals
    1391           56 :   type(crystal_t) :: crystal
    1392              :   !arrays
    1393            1 :   type(polynomial_coeff_type),allocatable :: strain_terms_tmp(:)
    1394              :   !Logicals
    1395              :   !Strings
    1396              :   character(len=1000) :: message
    1397              :   !*************************************************************************
    1398              :   !Get variables
    1399            1 :   crystal = eff_pot%crystal
    1400            1 :   coeff_ini = 1000000
    1401              : 
    1402            1 :   write(message, '(a,(80a),a)' ) ch10,&
    1403           81 :     &   ('_',ii=1,80),ch10
    1404            1 :   call wrtout(ab_out,message,'COLL')
    1405            1 :   call wrtout(std_out,message,'COLL')
    1406            1 :   write(message,'(3a)' )ch10,&
    1407            2 :     &    ' Chreate high order strain terms ',ch10
    1408            1 :   call wrtout(ab_out,message,'COLL')
    1409            1 :   call wrtout(std_out,message,'COLL')
    1410              : 
    1411              : 
    1412              :   !1406 get count of high order even anharmonic strain terms and the strain terms itself
    1413            1 :   call polynomial_coeff_getEvenAnhaStrain(strain_terms_tmp,crystal,ncombi,power_strain,comm, max_nbody)
    1414              :   ! Allocate my_coeffs with ncombi free space to work with
    1415              : 
    1416              : 
    1417              : 
    1418            1 :   nterm_start = eff_pot%anharmonics_terms%ncoeff
    1419            1 :   nterm_tot_tmp = eff_pot%anharmonics_terms%ncoeff + ncombi
    1420            7 :   ABI_MALLOC(terms,(nterm_tot_tmp))
    1421            5 :   do i=1,nterm_tot_tmp
    1422            5 :     if(i<=nterm_start)then
    1423              :       call polynomial_coeff_init(coeff_ini,eff_pot%anharmonics_terms%coefficients(i)%nterm,terms(i),&
    1424              :         & eff_pot%anharmonics_terms%coefficients(i)%terms,eff_pot%anharmonics_terms%coefficients(i)%name,&
    1425            2 :         &  check=.TRUE.)
    1426              :         !DMSG(terms(i)%debug_str)
    1427              :     else
    1428            2 :       if (.not.allocated(strain_terms_tmp(i-nterm_start)%terms)) then
    1429            0 :         write(message,'(4a)' )ch10,&
    1430            0 :           &  'Error in opt_getHOstrain: strain_terms_tmp(i-nterm_start)%terms not allocated',ch10,&
    1431            0 :           &  'Action: Contact Abinit Group',ch10
    1432            0 :         ABI_ERROR(message)
    1433              :       endif
    1434              :       call polynomial_coeff_init(coeff_ini,strain_terms_tmp(i-nterm_start)%nterm,terms(i),&
    1435              :         &         strain_terms_tmp(i-nterm_start)%terms,strain_terms_tmp(i-nterm_start)%name,&
    1436            2 :         &         check=.TRUE.)
    1437              :         !DMSG(strain_terms_tmp(i-nterm_start)%debug_str)
    1438              : endif
    1439              :   enddo
    1440              : 
    1441            1 :   call polynomial_coeff_list_free(strain_terms_tmp)
    1442              : 
    1443            1 : end subroutine opt_getHOstrain
    1444              : !!***
    1445              : 
    1446              : !!****f* m_opt_effpot/opt_getHOcrossdisp
    1447              : !!
    1448              : !! NAME
    1449              : !! opt_getHOcrossdisp
    1450              : !!
    1451              : !! FUNCTION
    1452              : !! Get even high order displacement terms for a given input term and
    1453              : !! add them to an excisting list of terms. If the term is strain phonon type
    1454              : !! the strain part gets deleted and the high order terms for the displacement
    1455              : !! part are computed.
    1456              : !! Example: for a tree linear term with three displacements x*y*z the even high order
    1457              : !!          possibilites are computed and stored.
    1458              : !!          For range 6 to 8: x^2*y^2*z^2,x^4*y^2*z^2,x^2*y^4*z^2,x^2*y^2*z^4.
    1459              : !!
    1460              : !! INPUTS
    1461              : !! eff_pot<effective_potential_type>: datatype with all the information
    1462              : !!                                    about the effective potential
    1463              : !! power_disp(2): start and stop order for disp terms
    1464              : !! comm: mpi communicator (at the moment only sequential tested)
    1465              : !!
    1466              : !! OUTPUT
    1467              : !! terms<polynomial_coeff_type>: list with original terms in effective
    1468              : !!                               potential + HO even disp terms
    1469              : !!
    1470              : !! SOURCE
    1471              : 
    1472            1 : subroutine opt_getHOcrossdisp(terms_out,ncombi,term_in,power_disp)
    1473              : 
    1474              :   !Arguments ------------------------------------
    1475              :   !scalars
    1476              :   type(polynomial_coeff_type),allocatable,intent(inout) :: terms_out(:)
    1477              :   type(polynomial_coeff_type),intent(inout) :: term_in
    1478              :   integer,intent(in) :: power_disp(2)
    1479              :   integer,intent(out) :: ncombi
    1480              :   !arrays
    1481              :   !Logicals
    1482              :   !Strings
    1483              :   !Local variables ------------------------------
    1484              :   !scalars
    1485              :   integer ::  ndisp,nterm_of_term,nstrain,nbody_tot
    1486              :   integer ::  order_start,order_stop,norder
    1487              :   integer ::  order_start_str,order_stop_str
    1488              :   integer ::  icombi,idisp,iterm_of_term
    1489              :   integer ::  ncombi_tot,ncombi_str
    1490              :   !reals
    1491              :   real(dp) :: coeff_ini=1
    1492              :   !arrays
    1493            1 :   type(polynomial_coeff_type) :: term
    1494              :   integer,allocatable :: ncombi_order(:),ncombi_order_str(:)
    1495              :   !Logicals
    1496              :   logical :: had_strain
    1497              :   !Strings
    1498              :   character(len=1000) :: message
    1499              :   !*************************************************************************
    1500              :   !Get/Set Variables
    1501            1 :   norder = abs(((power_disp(2)-power_disp(1))/2)) + 1
    1502            3 :   ABI_MALLOC(ncombi_order,(norder))
    1503            2 :   ABI_MALLOC(ncombi_order_str,(norder))
    1504            2 :   ncombi_order = 0
    1505            2 :   ncombi_order_str = 0
    1506            1 :   order_start_str = 0
    1507            1 :   order_stop_str = 0
    1508              : 
    1509            1 :   ncombi = 0
    1510              :   !Get this term (iterm) and infromations about it
    1511              :   !Get number of displacements and equivalent terms for this term
    1512              :   !Chose term one to get ndisp. ndisp is equal for all terms of the term
    1513              :   !Get minimum oder for this term
    1514              :   !Get total number of terms in effpot for message
    1515            1 :   ndisp = term_in%terms(1)%ndisp
    1516            1 :   nstrain = term_in%terms(1)%nstrain
    1517            1 :   nbody_tot = ndisp + nstrain
    1518            1 :   nterm_of_term = term_in%nterm
    1519            1 :   call polynomial_coeff_init(coeff_ini,nterm_of_term,term,term_in%terms,term_in%name, check=.true.)
    1520              :   !DMSG(term%debug_str)
    1521              :   ! Check if term has strain component.
    1522              :   ! If yes filter strain and fit high order atomic displacement terms
    1523            1 :   had_strain = .FALSE.
    1524            1 :   if(term%terms(1)%nstrain /= 0)then
    1525              :     ! Message to Output
    1526            1 :     write(message,'(5a)' )ch10,&
    1527            1 :       &               '- Term has strain compenent',ch10,&
    1528            2 :       &               ' -> Filter Displacement',ch10
    1529            1 :     call wrtout(ab_out,message,'COLL')
    1530            1 :     call wrtout(std_out,message,'COLL')
    1531            1 :     call opt_filterdisp(term,nterm_of_term)
    1532              :     !Get new value of symmetry equivalent term nterm_of_term
    1533            1 :     nterm_of_term = term%nterm
    1534              :     !Remember if this term had strain
    1535            1 :     had_strain = .TRUE.
    1536              :     !cycle
    1537              :   endif
    1538              :   ! Ok we want it. Let's go.
    1539              : 
    1540              :   ! get start and stop order for this term
    1541            1 :   call opt_getHOforterm(term,power_disp,order_start,order_stop)
    1542            1 :   if(had_strain) call opt_getHOforterm(term_in,power_disp,order_start_str,order_stop_str)
    1543            1 :   if(order_start == 0)then
    1544              :     ! Message to Output
    1545            0 :     write(message,'(5a,I2,a,I2,3a)' )ch10,&
    1546            0 :       &               " ==> High order cross product terms for term ", trim(term%name),ch10,&
    1547            0 :       &               " ==> do not fit into specified order range from ", power_disp(1),' to ',power_disp(2),ch10,&
    1548            0 :       &               " ==> Can not construct high order cross product bounding term",ch10
    1549            0 :     call wrtout(ab_out,message,'COLL')
    1550            0 :     call wrtout(std_out,message,'COLL')
    1551            0 :     ABI_SFREE(ncombi_order)
    1552            0 :     ABI_SFREE(ncombi_order_str)
    1553            0 :     return
    1554              :   end if
    1555              : 
    1556            1 :   if(order_start_str == 0 .and. had_strain)then
    1557              :     ! Message to Output
    1558            0 :     write(message,'(5a,I2,a,I2,3a)' )ch10,&
    1559            0 :       &               " ==> High order cross product terms for term ", trim(term_in%name),ch10,&
    1560            0 :       &               " ==> do not fit into specified order range from ", power_disp(1),' to ',power_disp(2),ch10,&
    1561            0 :       &               " ==> Can not construct high order cross product bounding term",ch10
    1562            0 :     call wrtout(ab_out,message,'COLL')
    1563            0 :     call wrtout(std_out,message,'COLL')
    1564            0 :     had_strain = .FALSE.
    1565              :   end if
    1566              :   ! get total amount of combinations and combinations per order for the term
    1567            1 :   call opt_getCombisforterm(order_start,order_stop,ndisp,ncombi,ncombi_order)
    1568            1 :   if(had_strain)then
    1569            1 :     call opt_getCombisforterm(order_start_str,order_stop_str,nbody_tot,ncombi_str,ncombi_order_str)
    1570              :     !write(std_out,*) "I was here ncombi_str is: ", ncombi_str
    1571            6 :     ABI_MALLOC(terms_out,(ncombi+ncombi_str))
    1572            2 :     ncombi_tot = ncombi+ncombi_str
    1573              :   else
    1574            0 :     ABI_MALLOC(terms_out,(ncombi))
    1575            0 :     ncombi_tot = ncombi
    1576              :   endif
    1577              :   ! Copy current term to the ncombination elemenst a the end in array terms
    1578              :   ! change the value of their coefficient to a start value
    1579              :   ! The start is estimed to not be larger then half the initial term's value
    1580              :   ! This is because higher order terms should have smaller coefficients
    1581            4 :   do icombi=1,ncombi_tot
    1582            3 :     if(icombi <= ncombi)then
    1583            2 :       coeff_ini = 1 !abs(terms_out(icombi)%coefficient / 2)
    1584            2 :       nterm_of_term = term%nterm
    1585            2 :       call polynomial_coeff_init(coeff_ini,nterm_of_term,terms_out(icombi),term%terms, check=.true.)
    1586              :       !DMSG(terms_out(icombi)%debug_str)
    1587              :     else
    1588            1 :       coeff_ini = 10d3
    1589            1 :       nterm_of_term = term_in%nterm
    1590            1 :       call polynomial_coeff_init(coeff_ini,nterm_of_term,terms_out(icombi),term_in%terms, check=.true.)
    1591              :       !DMSG(terms_out(icombi)%debug_str)
    1592              :     endif
    1593              :     ! Set the power of all terms we want to add to two. We find the correct power later
    1594              :     ! Change the weight of the term to 1 (even terms have allways weight=1)
    1595           76 :     do iterm_of_term=1,nterm_of_term
    1596           72 :       terms_out(icombi)%terms(iterm_of_term)%weight = 1
    1597           72 :       if(icombi > ncombi)then
    1598           48 :         terms_out(icombi)%terms(iterm_of_term)%power_strain = 2
    1599           24 :         coeff_ini = 10d3 !abs(terms_out(icombi)%coefficient / 2)
    1600           24 :         terms_out(icombi)%coefficient = coeff_ini
    1601              :         !             elseif(icombi>2*ncombi)then
    1602              :         !                terms_out(icombi)%terms(iterm_of_term)%power_strain = 4
    1603              :         !                coeff_ini = 10d5 !abs(terms_out(icombi)%coefficient / 2)
    1604              :         !                terms_out(icombi)%coefficient = coeff_ini
    1605              :       endif
    1606          219 :       do idisp=1,ndisp
    1607          216 :         terms_out(icombi)%terms(iterm_of_term)%power_disp(idisp) = 2
    1608              :       enddo !idisp
    1609              :     enddo !iterm_of_term
    1610              :   enddo !icombi
    1611              : 
    1612              :   !If term had strain we had to reinitialize it in the process
    1613              :   !Refree memory
    1614              :   !if(had_strain)
    1615            1 :   call polynomial_coeff_free(term)
    1616              : 
    1617              :   ! Get high order combinations
    1618            1 :   if(had_strain)then
    1619            1 :     call opt_getHoTerms(terms_out(:ncombi),order_start,order_stop,ndisp,ncombi_order)
    1620            1 :     call opt_getHoTerms(terms_out(ncombi+1:),order_start_str,order_stop_str,ndisp,ncombi_order_str)
    1621            1 :     ncombi = ncombi_tot
    1622              :   else
    1623            0 :     call opt_getHoTerms(terms_out,order_start,order_stop,ndisp,ncombi_order)
    1624              :   endif
    1625              :   !DEALLOCATION
    1626            1 :   ABI_SFREE(ncombi_order)
    1627            1 :   ABI_SFREE(ncombi_order_str)
    1628              : 
    1629            3 : end subroutine opt_getHOcrossdisp
    1630              : !!***
    1631              : 
    1632              : !!****f* m_opt_effpot/opt_getSingleDispTerms
    1633              : !!
    1634              : !! NAME
    1635              : !! opt_getSingleDispTerms
    1636              : !!
    1637              : !! FUNCTION
    1638              : !! Get polynomial terms (<polynomial_coeff_type>) with single displacements
    1639              : !! at second order inside a given range defined by the supercell size
    1640              : !!
    1641              : !! INPUTS
    1642              : !! sc_size(3): supercell size
    1643              : !! crystal<type(crystal_t)>: all information about the crystal
    1644              : !! comm: mpi communicator (at the moment only sequential tested)
    1645              : !!
    1646              : !! OUTPUT
    1647              : !! terms<polynomial_coeff_type>: list single displacement polynomial_coeffs
    1648              : !!
    1649              : !! SOURCE
    1650              : 
    1651            1 : subroutine opt_getSingleDispTerms(terms,crystal, sc_size,comm)
    1652              : 
    1653              :   !Arguments ------------------------------------
    1654              :   !scalars
    1655              :   integer,intent(in) :: comm
    1656              :   type(polynomial_coeff_type),allocatable,intent(inout) :: terms(:)
    1657              :   type(crystal_t),intent(inout) :: crystal
    1658              :   real(dp) ::  cutoff
    1659              :   !arrays
    1660              :   integer :: sc_size(3)
    1661              : 
    1662              :   !Logicals
    1663              :   !Strings
    1664              :   !Local variables ------------------------------
    1665              :   !scalars
    1666              :   integer :: natom,nsym,nrpt,ncoeff_sym,nstr_sym
    1667              :   integer :: ncoeff,ncoeff_out,power_strph,option_GN,option
    1668              :   integer :: nterms_out,nterm1,iterm1,iterm2,ind,iatom,i
    1669              :   integer :: ncopy
    1670              :   integer :: ii !,ia,ib,r1,r2,r3
    1671              :   !integer :: irpt,irpt_ref
    1672              :   integer :: master,nproc,my_rank
    1673              :   !arrays
    1674              :   integer :: power_disp(2)
    1675            1 :   integer,allocatable :: cell(:,:)
    1676            1 :   integer,allocatable :: list_symcoeff(:,:,:),list_symstr(:,:,:)
    1677            1 :   logical,allocatable :: terms_to_copy(:)
    1678            1 :   type(polynomial_coeff_type),allocatable :: terms_tmp(:),terms_tmp2(:)
    1679              :   !type(polynomial_coeff_type),allocatable :: terms(:)
    1680              :   !real(dp),allocatable :: xcart(:,:),xred(:,:),rpt(:,:)
    1681              :   real(dp) :: rprimd(3,3),range_ifc(3)
    1682            1 :   real(dp),allocatable :: dist(:,:,:,:)
    1683            1 :   character(len=5),allocatable :: symbols(:)
    1684              :   !Logicals
    1685              :   logical :: iam_master,need_verbose
    1686              :   !Strings
    1687              :   character(len=1000) :: message
    1688              :   !*************************************************************************
    1689              : 
    1690            1 :   option = 2
    1691              : 
    1692              :   if(option == 1)then
    1693              :     !MPI variables
    1694              :     master = 0
    1695              :     nproc = xmpi_comm_size(comm); my_rank = xmpi_comm_rank(comm)
    1696              :     iam_master = (my_rank == master)
    1697              : 
    1698              :     !Set/Get other variables
    1699              :     !natom  = crystal%natom
    1700              :     !nsym   = crystal%nsym
    1701              :     rprimd = crystal%rprimd
    1702              :     need_verbose = .TRUE.
    1703              : 
    1704              : 
    1705              :     call prepare_for_getList(crystal,sc_size, dist, cell, natom, nsym, nrpt, range_ifc , symbols)
    1706              : 
    1707              :     ! FIXME: this is dangerous!
    1708              :     ! It assumes that the structure is cubic in a usual axis setting.
    1709              :     cutoff = rprimd(1,1)
    1710              : 
    1711              :     if(need_verbose)then
    1712              :       write(message,'(1a)')' Generation of the list of all the possible coefficients'
    1713              :       call wrtout(std_out,message,'COLL')
    1714              :     end if
    1715              :     call polynomial_coeff_getList(cell,crystal,dist,list_symcoeff,list_symstr,&
    1716              :       &                              natom,nstr_sym,ncoeff_sym,nrpt,range_ifc,cutoff,sc_size=sc_size)
    1717              : 
    1718              :     ABI_SFREE(dist)
    1719              :     !ABI_FREE(rpt)
    1720              : 
    1721              :     !write(*,*) "polynomial_getList worked"
    1722              : 
    1723              :     !Get Order1 term s
    1724              :     !Check difference between ncoeff_out, ncoeff
    1725              :     call polynomial_coeff_getOrder1(cell,terms,list_symcoeff,natom,nterms_out,ncoeff_sym,nrpt,nsym,symbols)
    1726              : 
    1727              :     !do ii=1,nterms_out
    1728              :     !   write(*,*) "Term(",ii,"/",nterms_out,"): ", terms(ii)%name
    1729              :     !enddo
    1730              : 
    1731              :   elseif(option == 2)then
    1732              :     !Get/set variables
    1733              :     ! FIXME: hexu: check these values of 2. Why are they are hard coded here.
    1734              :     ! Does this mean we only generate high-order terms in 2x2x2 cell?
    1735            1 :     power_disp = (/2,2/)
    1736            1 :     power_strph = zero
    1737            1 :     option_GN = 0
    1738            1 :     sc_size = (/2,2,2/)
    1739            1 :     cutoff = 0
    1740            1 :     natom  = crystal%natom
    1741              :     ! XXX: hexu: why cutoff = sum of axis lengths?
    1742            4 :     do ii=1,3
    1743              :       cutoff = cutoff + sqrt(crystal%rprimd(ii,1)**2 + &
    1744              :         &                            crystal%rprimd(ii,2)**2 + &
    1745            4 :         &                            crystal%rprimd(ii,3)**2)
    1746              :     enddo
    1747              : 
    1748              : 
    1749              :     !do iatom=1,3
    1750            6 :     do iatom=1,natom !Subhadeep
    1751              :     ! TODO: to be validated.
    1752              :     !do iatom=1,crystal%nirredat
    1753              :       call polynomial_coeff_getNorder(terms_tmp,crystal,cutoff,ncoeff,ncoeff_out,power_disp,&
    1754              :         &                               power_strph,option_GN,sc_size,comm,anharmstr=.false.,spcoupling=.false.,&
    1755              :         &                               only_odd_power=.false.,only_even_power=.true.,verbose=.false.,&
    1756              :         &                               compute_symmetric=.false.,fit_iatom=iatom,    &
    1757            5 :         &                            max_nbody=[999,999,999,999,999,999, 999,999,999,999])
    1758              :       !TEST MS
    1759              :       !  write(std_out,*) "behind call getNorder"
    1760              :       !  write(std_out,*) "ncoeff_out: ", ncoeff_out
    1761              :       !  do ii=1,ncoeff_out
    1762              :       !     write(*,*) "Term(",ii,"/",ncoeff_out,"): ", terms_tmp(ii)%name
    1763              :       !  enddo
    1764              :       !TEST MS
    1765            6 :       if(iatom == 1)then
    1766           13 :         ABI_MALLOC(terms,(size(terms_tmp)))
    1767            1 :         call coeffs_list_copy(terms,terms_tmp)
    1768              :       else
    1769           12 :         ABI_MALLOC(terms_to_copy,(size(terms_tmp)))
    1770              :         ! note: when iatom>1, terms is already initialized.
    1771            4 :         nterm1 = size(terms)
    1772          145 :         ABI_MALLOC(terms_tmp2,(nterm1))
    1773            4 :         terms_tmp2 = terms
    1774           44 :         terms_to_copy = .TRUE.
    1775           44 :         do iterm1=1,size(terms_tmp)
    1776          795 :           do iterm2=1,size(terms)
    1777          791 :             if(terms_tmp(iterm1) == terms(iterm2))then
    1778            0 :               terms_to_copy(iterm1) = .FALSE.
    1779            0 :               exit
    1780              :             endif
    1781              :           enddo!iterm1
    1782              :         enddo!iterm2
    1783           44 :         ncopy = count(terms_to_copy)
    1784            4 :         call polynomial_coeff_list_free(terms)
    1785          185 :         ABI_MALLOC(terms,(nterm1+ncopy))
    1786            4 :         call coeffs_list_copy(terms(:nterm1),terms_tmp2)
    1787            4 :         ind = 0
    1788           44 :         do i =1,size(terms_tmp)
    1789           44 :           if(terms_to_copy(i))then
    1790           40 :             ind=ind+1
    1791              :             call polynomial_coeff_init(terms_tmp(i)%coefficient,terms_tmp(i)%nterm,terms(nterm1+ind),terms_tmp(i)%terms,&
    1792           40 :               &                              terms_tmp(i)%name,check=.TRUE.)
    1793              :               !DMSG(terms(nterm1+ind)%debug_str)
    1794              :           endif
    1795              :         enddo!i=1,nterm1+ncopy
    1796            4 :         call polynomial_coeff_list_free(terms_tmp)
    1797            4 :         call polynomial_coeff_list_free(terms_tmp2)
    1798            4 :         ABI_SFREE(terms_to_copy)
    1799              :       endif!iatom==1
    1800              :     enddo !iatom=1,natom
    1801              :     !      call polynomial_coeff_getNorder(terms,crystal,cutoff,ncoeff,ncoeff_out,power_disp,&
    1802              :     !&                               power_strph,option_GN,sc_size,comm,anharmstr=.false.,spcoupling=.false.,&
    1803              :     !&                               only_odd_power=.false.,only_even_power=.true.,verbose=.false.,&
    1804              :     !&                               compute_symmetric=.false.)
    1805              : 
    1806              :   endif !option
    1807              :   !TEST MS
    1808              :   !  write(std_out,*) "behind call getNorder"
    1809              :   !  write(std_out,*) "ncoeff_out: ", size(terms)
    1810              :   !  do ii=1,size(terms)
    1811              :   !     write(*,*) "Term(",ii,"/",size(terms),"): ", terms(ii)%name
    1812              :   !  enddo
    1813              :   !TEST MS
    1814              : 
    1815            1 : end subroutine opt_getSingleDispTerms
    1816              : !!***
    1817              : 
    1818              : !!****f* m_opt_effpot/opt_getHOSingleDispTerms
    1819              : !!
    1820              : !! NAME
    1821              : !! opt_getHOSingleDispTerms
    1822              : !!
    1823              : !! FUNCTION
    1824              : !! For a given anharmonic term that might consits of product of
    1825              : !! terms find all even high order single displacement terms
    1826              : !! Example: Input term: x*y*z
    1827              : !!          Input HO-range: 6 8
    1828              : !!          Output terms: x^6,x^8,y^6,y^8,z^6,z^8
    1829              : !!          Caution only atomic displacements are taken into account
    1830              : !!
    1831              : !! INPUTS
    1832              : !! term_in<polynomial_coeff_type>: input anharmonic term
    1833              : !! crystal<type(crystal_t)>: all information about the crystal
    1834              : !! single_disp_terms<polynomial_coeff_out>: list of single disp terms at
    1835              : !!                                          second order to select terms from
    1836              : !! power_disp(2): Start and stop power for HO terms
    1837              : !! comm: mpi communicator (at the moment only sequential tested)
    1838              : !!
    1839              : !! OUTPUT
    1840              : !! terms_out<polynomial_coeff_out>: output high order even terms
    1841              : !! ncoeff: number of coefficients
    1842              : !!
    1843              : !! SOURCE
    1844              : 
    1845            1 : subroutine opt_getHOSingleDispTerms(term_in,terms_out,symbols,single_disp_terms,power_disp,ncoeff)
    1846              : 
    1847              :   !Arguments ------------------------------------
    1848              :   !scalars
    1849              :   integer,intent(out) :: ncoeff
    1850              :   type(polynomial_coeff_type),intent(in) :: term_in
    1851              :   type(polynomial_coeff_type),intent(in) :: single_disp_terms(:)
    1852              :   type(polynomial_coeff_type),allocatable,intent(out) :: terms_out(:)
    1853              :   !type(crystal_t),intent(inout) :: crystal
    1854              :   !arrays
    1855              :   integer, intent(in) :: power_disp(2)
    1856              :   character(len=5),intent(in) :: symbols(:)
    1857              :   !Logicals
    1858              :   !Strings
    1859              :   !Local variables ------------------------------
    1860              :   !scalars
    1861              :   integer :: ndisp,norder, nterm_of_term
    1862              :   integer :: icoeff,iorder,idisp, iterm1,iterm2,iterm3
    1863              :   real(dp) :: coeff_ini = 1
    1864              :   !Strings
    1865              :   character(len=200):: name
    1866              :   !arrays
    1867              :   type(polynomial_coeff_type),allocatable :: terms_out_tmp(:)
    1868              :   !Logicals
    1869            1 :   logical,allocatable :: found(:)
    1870              :   !*************************************************************************
    1871              :   !Get/Set Variables
    1872              :   !Number of output terms
    1873            1 :   ndisp = term_in%terms(1)%ndisp
    1874            1 :   norder = abs(power_disp(2)-power_disp(1))/2 + 1
    1875            1 :   ncoeff = norder * ndisp
    1876              :   !Allocate output terms
    1877            5 :   ABI_MALLOC(terms_out_tmp,(ncoeff))
    1878              :   !find equivalent second order terms in list of single disp terms
    1879              :   !for each displacement in input term
    1880              :   !Transfer to output term and increase order
    1881            1 :   icoeff = 0
    1882            3 :   do idisp=1,ndisp
    1883          103 :     do iterm1=1,size(single_disp_terms)
    1884         2346 :       do iterm2=1,single_disp_terms(iterm1)%nterm
    1885         2980 :         if(all(term_in%terms(1)%atindx(:,idisp) == single_disp_terms(iterm1)%terms(iterm2)%atindx(:,1)))then
    1886          606 :           if(all(term_in%terms(1)%cell(:,:,idisp) == single_disp_terms(iterm1)%terms(iterm2)%cell(:,:,1)))then
    1887            6 :             if(term_in%terms(1)%direction(idisp) == single_disp_terms(iterm1)%terms(iterm2)%direction(1))then
    1888            4 :               do iorder=1,norder
    1889            2 :                 icoeff = icoeff + 1
    1890           32 :                 terms_out_tmp(icoeff) = single_disp_terms(iterm1)
    1891            2 :                 nterm_of_term = single_disp_terms(iterm1)%nterm
    1892              :                 !Change order of term
    1893              :                 call polynomial_coeff_init(coeff_ini,nterm_of_term,terms_out_tmp(icoeff),&
    1894            2 :                   &                                               single_disp_terms(iterm1)%terms(:),  check=.true.)
    1895              :                 !DMSG(terms_out_tmp(icoeff)%debug_str)
    1896              : 
    1897           34 :                 do iterm3=1,nterm_of_term
    1898           62 :                   terms_out_tmp(icoeff)%terms(iterm3)%power_disp = power_disp(1) + (iorder-1)*2
    1899              :                 enddo !iterm3
    1900              :               enddo !iorder
    1901              :             endif
    1902              :           endif
    1903              :         endif
    1904              :       enddo !iterm2
    1905              :     enddo !iterm1
    1906              :   enddo!idisp
    1907              :   !Change Name
    1908            3 :   do icoeff=1,ncoeff
    1909            2 :     call polynomial_coeff_getName(name,terms_out_tmp(icoeff),symbols,recompute=.TRUE.)
    1910            3 :     call polynomial_coeff_SetName(name,terms_out_tmp(icoeff))
    1911              :   enddo
    1912              : 
    1913              :   !Check for doubles and delete them
    1914              :   !First count irreducible terms
    1915            3 :   ABI_MALLOC(found,(ncoeff))
    1916            3 :   found = .FALSE.
    1917              :   iterm3 = 0
    1918            3 :   do iterm1=1,ncoeff
    1919            4 :     do iterm2=iterm1+1,ncoeff
    1920            3 :       if(terms_out_tmp(iterm1) == terms_out_tmp(iterm2) .and. .not. found(iterm2))then
    1921            0 :         found(iterm2) = .TRUE.
    1922            0 :         iterm3 = iterm3 + 1
    1923              :       endif
    1924              :     enddo
    1925              :   enddo
    1926            1 :   iterm3 = ncoeff - iterm3
    1927            5 :   ABI_MALLOC(terms_out,(iterm3))
    1928            1 :   iterm3 = 0
    1929            3 :   do iterm1=1,ncoeff
    1930            3 :     if(.not. found(iterm1))then
    1931            2 :       iterm3 = iterm3 + 1
    1932              :       call polynomial_coeff_init(coeff_ini,terms_out_tmp(iterm1)%nterm,terms_out(iterm3),&
    1933            2 :         &                                terms_out_tmp(iterm1)%terms,terms_out_tmp(iterm1)%name, check=.TRUE.)
    1934              :         !DMSG(terms_out(iterm3)%debug_str)
    1935              :     endif
    1936              :   enddo
    1937            1 :   ABI_SFREE(found)
    1938            1 :   call polynomial_coeff_list_free(terms_out_tmp)
    1939            1 :   ncoeff = iterm3
    1940            1 : end subroutine opt_getHOSingleDispTerms
    1941              : !!***
    1942              : 
    1943              : 
    1944              : 
    1945              : !!****f* m_opt_effpot/opt_boundcoeff
    1946              : !! NAME
    1947              : !! opt_boundcoeff
    1948              : !!
    1949              : !! FUNCTION
    1950              : !!
    1951              : !! optimize a bound coefficient if optimized value is negative
    1952              : !! put an positive value that respects a precision penalty
    1953              : !!
    1954              : !! INPUTS
    1955              : !!
    1956              : !! OUTPUT
    1957              : !!
    1958              : !! SOURCE
    1959              : 
    1960            1 : function opt_boundcoeff(yvalues,cvalues,penalty_in) result (coeff)
    1961              :   !Arguments ------------------------------------
    1962              : 
    1963              :   !Arguments ------------------------------------
    1964              :   real(dp),intent(in) :: yvalues(2),cvalues(2),penalty_in
    1965              :   real(dp) :: coeff
    1966              :   !local
    1967              :   !variable
    1968              :   real(dp) :: a,b,coeff_tmp,x1,x2,penalty
    1969              :   !array
    1970              :   ! *************************************************************************
    1971              : 
    1972            1 :   a = ( (yvalues(1) - 1) - (yvalues(2)-1)*(cvalues(1)/cvalues(2))) / (cvalues(1)**2 - cvalues(1)*cvalues(2))
    1973              : 
    1974              :   b = ( (yvalues(2) - 1)/cvalues(2) ) - ( (yvalues(1) -1)*cvalues(2) - (yvalues(2) - 1)*cvalues(1) )&
    1975            1 :     &    / (cvalues(1)**2 - cvalues(1)*cvalues(2))
    1976              : 
    1977            1 :   penalty = penalty_in - 1
    1978            1 :   if (a/=a .or. b/=b .or. a==0) then
    1979            1 :     coeff = 0.0_dp
    1980              :     return
    1981              :   end if
    1982            1 :   coeff_tmp = -b/(2*a)
    1983              :   !write(*,*) "coeff_tmp", coeff_tmp
    1984            1 :   if(coeff_tmp > 0)then
    1985              :     coeff = coeff_tmp
    1986              :   else
    1987            1 :     x1 = (-b + sqrt(b**2 + 4*a*penalty)) / (2*a) ! 1.001 penalty value
    1988            1 :     x2 = (-b - sqrt(b**2 + 4*a*penalty)) / (2*a)
    1989            1 :     if(x1>0)then
    1990              :       coeff = x1
    1991              :     else
    1992            0 :       coeff = x2
    1993              :     endif
    1994              :   endif
    1995              : 
    1996              : end function opt_boundcoeff
    1997              : !!***
    1998              : 
    1999              : !!****f* m_opt_effpot/check_to_skip
    2000              : !! NAME
    2001              : !! check_to_skip
    2002              : !!
    2003              : !! FUNCTION
    2004              : !!
    2005              : !! Check if term contains only bodies with even power
    2006              : !! and has a positive coefficient. If yes term doesn't need
    2007              : !! a bounding high order equivalent and we can skip it.
    2008              : !! Function retursn logical to_skip.
    2009              : !!
    2010              : !! INPUTS
    2011              : !!
    2012              : !! term<polynomial_coeff_type>:anharmonic term
    2013              : !!
    2014              : !! OUTPUT
    2015              : !!
    2016              : !! logical: to_skip
    2017              : !!
    2018              : !! SOURCE
    2019              : 
    2020            1 : function check_to_skip(term) result (to_skip)
    2021              :   !Arguments ------------------------------------
    2022              :   type(polynomial_coeff_type),intent(in) :: term
    2023              :   logical :: to_skip
    2024              :   ! ------------------------------------
    2025              :   !local
    2026              :   !variable
    2027              :   character(len=1000) :: message
    2028              :   !array
    2029              :   ! *************************************************************************
    2030              : 
    2031            1 :   to_skip = .FALSE.
    2032              :   ! Let's check if we really want all this mess
    2033              :   ! If the term is even and its coefficient positive we skip it. Also here we take terms(1) as example for all equivalent terms of term
    2034            2 :   if(term%coefficient > 0 .and. .not. any(mod(term%terms(1)%power_disp(:),2) /= 0))then
    2035            0 :     if(.not. any(mod(term%terms(1)%power_strain(:),2) /= 0))then
    2036              :       ! Message to Output
    2037            0 :       write(message,'(3a)' )ch10,&
    2038            0 :         &         ' ==> No need for high order bounding term',ch10
    2039            0 :       call wrtout(ab_out,message,'COLL')
    2040            0 :       call wrtout(std_out,message,'COLL')
    2041            0 :       to_skip = .TRUE.
    2042            0 :       return
    2043              :     end if
    2044              :   end if
    2045              : 
    2046              : end function check_to_skip
    2047              : !!***
    2048              : 
    2049            2 : subroutine generate_bounding_term_and_add_to_list(sympairs, nterm_start, ncombi, my_coeffs, temp_cntr)
    2050              :   ! check if myterm
    2051              :   !type(polynomial_coeff_type),target, intent(in) :: terms(:)
    2052              : 
    2053              :   type(polynomial_coeff_type), allocatable, intent(inout) :: my_coeffs(:)
    2054              :   type(SymPairs_t), intent(inout) :: sympairs
    2055              :   integer, intent(in) :: nterm_start, ncombi
    2056              :   integer, intent(out) :: temp_cntr
    2057              : 
    2058            2 :   type(polynomial_term_type), allocatable :: terms2(:)
    2059              :   type(polynomial_term_type), pointer :: myterm=> null()
    2060              :   type(polynomial_coeff_type), target, allocatable :: my_coeffs_tmp(:)
    2061              :   integer :: idisp, my_nrpt, list_cntr, number_coeff, icombi
    2062              :   integer :: jterm
    2063              :   integer :: tmp_list(5), pwr
    2064              :   logical :: found
    2065              :   logical :: reverse_i, any_exists
    2066            2 :   logical, allocatable :: reverse(:), false_reverse(:), exists(:)
    2067              :   integer :: counter, nterm, tot_power
    2068            2 :   type(polynomial_coeff_type):: temp_coeff
    2069            2 :   integer, allocatable :: list_disp(:)
    2070              :   character(len=200):: name
    2071              :   integer :: ncoeff
    2072              : 
    2073              :   ! copy the coefficients to a temporary array my_coeffs_tmp
    2074            2 :   ncoeff=size(my_coeffs)
    2075              : 
    2076              : 
    2077           12 :   ABI_MALLOC(my_coeffs_tmp,(ncoeff))
    2078              : 
    2079              :   ! check if my_coeffs i allocated and has the right size
    2080            2 :   if(.not. allocated(my_coeffs)) then
    2081            0 :     ABI_BUG("my_coeffs is not allocated")
    2082              :   end if
    2083            2 :   if(size(my_coeffs) /= ncoeff) then
    2084            0 :     ABI_BUG("my_coeffs has the wrong size")
    2085              :   end if
    2086            2 :   if(size(my_coeffs_tmp) /= ncoeff) then
    2087            0 :     ABI_BUG("my_coeffs_tmp has the wrong size")
    2088              :   end if
    2089              : 
    2090            2 :   my_coeffs_tmp=my_coeffs
    2091              : 
    2092              :   !call coeffs_list_copy(my_coeffs_tmp, my_coeffs)
    2093              : 
    2094              :   ! free the original array and allocate a new one with the correct size
    2095            2 :   call polynomial_coeff_list_free(my_coeffs)
    2096           10 :   ABI_MALLOC(my_coeffs, (ncoeff))
    2097              :  !my_coeffs(1:nterm_start) = my_coeffs_tmp(1:nterm_start)
    2098            2 :   call coeffs_list_copy(my_coeffs(1:nterm_start), my_coeffs_tmp(1:nterm_start))
    2099              : 
    2100              : 
    2101              : 
    2102            2 :   temp_cntr =0
    2103            5 :   do icombi=1, ncombi
    2104            3 :     if(size( my_coeffs_tmp(nterm_start+icombi)%terms) == 0) cycle
    2105            3 :     myterm=> my_coeffs_tmp(nterm_start+icombi)%terms(1)
    2106            8 :     tot_power=sum(myterm%power_disp) + sum(myterm%power_strain)
    2107            9 :     ABI_MALLOC(list_disp, (tot_power))
    2108            6 :     ABI_MALLOC(reverse, (tot_power))
    2109            6 :     ABI_MALLOC(false_reverse, (tot_power))
    2110              : 
    2111           21 :     list_disp(:)=0
    2112           21 :     reverse(:)=.False.
    2113           21 :     false_reverse(:)=.False.
    2114            3 :     counter=0
    2115              :     ! put the indices of the disp terms into a list
    2116            5 :     do idisp=1,myterm%ndisp
    2117              :       ! for each disp, find its index in the pair list.
    2118            2 :       my_nrpt=find_irpt(cells=sympairs%cell, cell=myterm%cell(:, 2, idisp))
    2119              :       tmp_list(:) = (/myterm%direction(idisp),myterm%atindx(1,idisp), &
    2120           12 :         & myterm%atindx(2,idisp),my_nrpt,int(myterm%weight) /)
    2121            2 :       found=.False.  ! to find if the symmetry adapted term already exist.
    2122            2 :       reverse_i=.False.
    2123         1518 :       do list_cntr=1,size(sympairs%list_symcoeff, 2)
    2124              :         !do isym=1, sympairs%nsym
    2125         2220 :         if (all(tmp_list(:4)==sympairs%list_symcoeff(:4,list_cntr,1))) then
    2126            2 :           number_coeff = sympairs%list_symcoeff(6,list_cntr,1)
    2127            2 :           found = .True.
    2128              :           !if (found) exit
    2129              :         end if
    2130              :         !end do
    2131              :         !if(found) exit
    2132              :       end do
    2133            2 :       if(.not. found) then
    2134            0 :         reverse_i=.True.
    2135            0 :         my_nrpt=find_irpt(cells=sympairs%cell, cell=-myterm%cell(:, 2, idisp))
    2136              :         tmp_list(:) = (/myterm%direction(idisp),myterm%atindx(2,idisp), &
    2137            0 :           & myterm%atindx(1,idisp),my_nrpt,-int(myterm%weight) /)
    2138            0 :         do list_cntr=1,size(sympairs%list_symcoeff, 2)
    2139              :           !do isym=1, sympairs%nsym
    2140            0 :           if (all(tmp_list(:4)==sympairs%list_symcoeff(:4,list_cntr,1))) then
    2141            0 :             number_coeff = sympairs%list_symcoeff(6,list_cntr,1)
    2142            0 :             found = .True.
    2143              :             !if (found) exit
    2144              :           end if
    2145              :           !end do
    2146              :           !if(found) exit
    2147              :         end do
    2148              :       end if
    2149              : 
    2150            3 :       if (found )then
    2151            6 :         do pwr=1,myterm%power_disp(idisp)
    2152            4 :           counter=counter+1
    2153            4 :           list_disp(counter) = number_coeff
    2154            6 :           reverse(counter) = reverse_i
    2155              :         end do
    2156              :       else
    2157            0 :         ABI_BUG("The pair is not found in generated bounding terms.")
    2158              :       end if
    2159              :     end do
    2160              : 
    2161            6 :     do idisp=1,myterm%nstrain
    2162           20 :       do pwr=1,myterm%power_strain(idisp)
    2163           14 :         counter = counter+1
    2164           17 :         list_disp(counter) = myterm%strain(idisp)+size(sympairs%list_symcoeff,2)
    2165              :       end do
    2166              :     end do
    2167            3 :     nullify(myterm)
    2168              : 
    2169              :     ! generate the terms with false reverse, and save to the temp_coeff.
    2170            3 :     nterm=sympairs%nsym
    2171          153 :     ABI_MALLOC(terms2, (nterm))
    2172            3 :     call sympairs%generateTerms(list_disp,  tot_power, nterm, terms2, reverse=false_reverse)
    2173              :     call polynomial_coeff_init(one,nterm,temp_coeff, &
    2174            3 :       &terms2(1:nterm), check=.true.)
    2175            3 :     call polynomial_term_list_free(terms2)
    2176              :     !DMSG(temp_coeff%debug_str)
    2177              : 
    2178              :     call polynomial_coeff_getName(name, &
    2179            3 :       & temp_coeff,sympairs%symbols,recompute=.TRUE.)
    2180              : 
    2181              :     ! check if temp coeff already exists in the list of coeffs my_coeffs
    2182            9 :     ABI_MALLOC(exists, (nterm_start+icombi-1))
    2183            9 :     exists=.False.
    2184            9 :     do jterm=1,(nterm_start+icombi-1)
    2185            9 :       exists(jterm) = coeffs_compare(my_coeffs(jterm),temp_coeff)
    2186              :     enddo !jterm
    2187            3 :     call polynomial_coeff_free(temp_coeff)
    2188              : 
    2189            9 :     any_exists=any(exists)
    2190            3 :     ABI_FREE(exists)
    2191              : 
    2192              :     ! if the term already exists, we skip it. Otherwise we add also the reverse.
    2193            3 :     if (.not. any_exists) then
    2194            3 :       temp_cntr = temp_cntr+1
    2195          153 :       ABI_MALLOC(terms2, (nterm))
    2196            3 :       call sympairs%generateTerms(list_disp,  tot_power, nterm, terms2, reverse=reverse)
    2197              :       call polynomial_coeff_init(one,nterm, &
    2198            3 :         & my_coeffs(nterm_start+temp_cntr),terms2, check=.true.)
    2199              :       !DMSG(my_coeffs(nterm_start+temp_cntr)%debug_str)
    2200            3 :       call polynomial_term_list_free(terms2)
    2201              :     end if
    2202              : 
    2203            3 :     ABI_SFREE(list_disp)
    2204            3 :     ABI_SFREE(reverse)
    2205            5 :     ABI_SFREE(false_reverse)
    2206              :   end do
    2207              : 
    2208            2 :   call polynomial_coeff_list_free(my_coeffs_tmp)
    2209              : 
    2210              :   ! truncate my_coeffs.
    2211            2 :   call coeffs_list_truncate(my_coeffs, nterm_start+temp_cntr)
    2212            2 : end subroutine generate_bounding_term_and_add_to_list
    2213              : 
    2214              : 
    2215              : end module m_opt_effpot
    2216              : !!***
        

Generated by: LCOV version 2.3-1