LCOV - code coverage report
Current view: top level - src/45_geomoptim - m_pred_simple.F90 (source / functions) Coverage Total Hit
Test: coverage.info Lines: 90.4 % 157 142
Test Date: 2026-09-21 22:40:37 Functions: 100.0 % 2 2

            Line data    Source code
       1              : !!****m* ABINIT/m_pred_simple
       2              : !! NAME
       3              : !!  m_pred_simple
       4              : !!
       5              : !! FUNCTION
       6              : !!
       7              : !!
       8              : !! COPYRIGHT
       9              : !!  Copyright (C) 1998-2026 ABINIT group (DCA, XG, GMR, JCC, SE)
      10              : !!  This file is distributed under the terms of the
      11              : !!  GNU General Public License, see ~abinit/COPYING
      12              : !!  or http://www.gnu.org/copyleft/gpl.txt .
      13              : !!
      14              : !! SOURCE
      15              : 
      16              : #if defined HAVE_CONFIG_H
      17              : #include "config.h"
      18              : #endif
      19              : 
      20              : #include "abi_common.h"
      21              : 
      22              : module m_pred_simple
      23              : 
      24              :  use defs_basis
      25              :  use m_abicore
      26              :  use m_abimover
      27              :  use m_abihist
      28              : 
      29              :  use m_geometry,  only : fcart2gred, xred2xcart
      30              : 
      31              :  implicit none
      32              : 
      33              :  private
      34              : !!***
      35              : 
      36              :  public :: pred_simple
      37              :  public :: prec_simple
      38              : !!***
      39              : 
      40              : contains
      41              : !!***
      42              : 
      43              : !!****f* ABINIT/pred_simple
      44              : !! NAME
      45              : !! pred_simple
      46              : !!
      47              : !! FUNCTION
      48              : !! Ionmov predictors (4 & 5) Internal to scfcv.
      49              : !! Actually, this routine does nothing (only copy) as all operations are internal to scfcv ...
      50              : !!
      51              : !! IONMOV 4:
      52              : !! Conjugate gradient algorithm for simultaneous optimization
      53              : !! of potential and ionic degrees of freedom. It can be used with
      54              : !! iscf=2 and iscf=5 or 6
      55              : !!
      56              : !! IONMOV 5:
      57              : !! Simple relaxation of ionic positions according to (converged)
      58              : !! forces. Equivalent to ionmov=1 with zero masses, albeit the
      59              : !! relaxation coefficient is not vis, but iprcfc.
      60              : !!
      61              : !! INPUTS
      62              : !! ab_mover <type(abimover)> : Datatype with all the information needed by the preditor
      63              : !! zDEBUG : if true print some debugging information
      64              : !!
      65              : !! OUTPUT
      66              : !!
      67              : !! SIDE EFFECTS
      68              : !! hist <type(abihist)> : History of positions,forces acell, rprimd, stresses
      69              : !!
      70              : !! SOURCE
      71              : 
      72           35 : subroutine pred_simple(ab_mover,hist,iexit)
      73              : 
      74              : !Arguments ------------------------------------
      75              : !scalars
      76              :  type(abimover),intent(in) :: ab_mover
      77              :  type(abihist),intent(inout) :: hist
      78              :  integer,intent(in) :: iexit
      79              : 
      80              : !Local variables-------------------------------
      81              : !scalars
      82              :  integer  :: ihist_next,kk
      83              : 
      84              : !***************************************************************************
      85              : !Beginning of executable session
      86              : !***************************************************************************
      87              : 
      88           35 :  if(iexit/=0)then
      89              :    return
      90              :  end if
      91              : 
      92              : !All the operations are internal to scfcv.F90
      93              : 
      94              : !XRED, FCART and VEL
      95           28 :  ihist_next = abihist_findIndex(hist,+1)
      96           96 :  do kk = 1, ab_mover%natom
      97          272 :   hist%xred(:, kk, ihist_next) = hist%xred(:, kk, hist%ihist)
      98          272 :   hist%fcart(:, kk, ihist_next) = hist%fcart(:, kk, hist%ihist)
      99          300 :   hist%vel(:, kk, ihist_next) = hist%vel(:, kk, hist%ihist)
     100              :  end do
     101              : 
     102              : !ACELL
     103          112 :    hist%acell(1:3,ihist_next)=hist%acell(1:3,hist%ihist)
     104              : 
     105              : !RPRIMD
     106          112 :  do kk=1,3
     107          364 :      hist%rprimd(1:3,kk,ihist_next)=hist%rprimd(1:3,kk,hist%ihist)
     108              :  end do
     109              : 
     110           28 :  hist%ihist=ihist_next
     111              : 
     112              : end subroutine pred_simple
     113              : !!***
     114              : 
     115              : !!****f* ABINIT/prec_simple
     116              : !! NAME
     117              : !! prec_simple
     118              : !!
     119              : !! FUNCTION
     120              : !! Simple preconditioner, compute the force constant matrix
     121              : !! using the Badger's rule:
     122              : !!
     123              : !!                F=A/(r-B)^3
     124              : !!
     125              : !! INPUTS
     126              : !! ab_mover <type(abimover)> : Datatype with all the information needed by the preconditioner
     127              : !! zDEBUG : if true print some debugging information
     128              : !!
     129              : !! OUTPUT
     130              : !!
     131              : !! SIDE EFFECTS
     132              : !! hist <type(abihist)> : History of positions,forces acell, rprimd, stresses
     133              : !!
     134              : !! SOURCE
     135              : 
     136          440 : subroutine prec_simple(ab_mover,forstr,hist,icycle,itime,iexit)
     137              : 
     138              :  use m_linalg_interfaces
     139              : 
     140              : !Arguments ------------------------------------
     141              : !scalars
     142              :  integer,intent(in) :: iexit,itime,icycle
     143              :  type(abimover),intent(in) :: ab_mover
     144              :  type(abihist),intent(in) :: hist
     145              :  type(abiforstr),intent(inout) :: forstr
     146              : 
     147              : !Local variables-------------------------------
     148              : !scalars
     149              :  integer :: period,ii,jj,index,kk,ksub,jsub
     150              :  integer :: info,lwork,new_order_forces
     151              :  real(dp) :: Z,badgerfactor,lambda,sigma,val_rms
     152              :  integer,save :: order_forces
     153              :  logical :: Compute_Matrix
     154              : !arrays
     155          440 :  type(go_bonds) :: bonds
     156          440 :  integer,allocatable :: periods(:,:)
     157          440 :  integer,allocatable :: iatoms(:,:)
     158          880 :  integer  :: ipiv(3*ab_mover%natom)
     159          880 :  real(dp) :: xcart(3,ab_mover%natom)
     160          880 :  real(dp) :: fcart(3,ab_mover%natom)
     161          440 :  real(dp) :: B(3*ab_mover%natom)
     162              :  real(dp) :: rprimd(3,3)
     163          880 :  real(dp) :: w(3*ab_mover%natom)
     164          440 :  real(dp),allocatable :: matrix_tmp(:,:)
     165          440 :  real(dp),allocatable :: work(:)
     166              :  real(dp) :: badger(6,6)
     167              :  real(dp),allocatable,save :: matrix(:,:)
     168              :  character(len=18)   :: fmt
     169              : 
     170              : !***************************************************************************
     171              : !Beginning of executable session
     172              : !***************************************************************************
     173              : 
     174          440 :  if (iexit/=0)then
     175          405 :    if(allocated(matrix))then
     176            6 :      ABI_FREE(matrix)
     177              :    endif
     178          405 :    return
     179              :  end if
     180              : 
     181              : !##########################################################
     182              : !### 01. Show the Precondition parameters, set the badger
     183              : !###     matrix.
     184              : 
     185           35 :  write(std_out,*) 'Precondition option',ab_mover%goprecon
     186          140 :  write(std_out,*) 'Precondition parameters',ab_mover%goprecprm
     187           35 :  lambda=ab_mover%goprecprm(1)
     188              : 
     189              :  badger(:,:)=reshape( (/ -0.2573, 0.3401, 0.6937, 0.7126, 0.8335, 0.9491,&
     190              : & 0.3401, 0.9652, 1.2843, 1.4725, 1.6549, 1.7190,&
     191              : & 0.6937, 1.2843, 1.6925, 1.8238, 2.1164, 2.3185,&
     192              : & 0.7126, 1.4725, 1.8238, 2.0203, 2.2137, 2.5206,&
     193              : & 0.8335, 1.6549, 2.1164, 2.2137, 2.3718, 2.5110,&
     194           35 : & 0.9491, 1.7190, 2.3185, 2.5206, 2.5110, 0.0000 /), (/ 6, 6/) )
     195              : 
     196           35 :  write(fmt,'(a1,i4,a5)') '(',3*ab_mover%natom,'f8.3)'
     197              : 
     198              : !##########################################################
     199              : !### 02. Take the coordinates and cell parameters from HIST
     200              : 
     201          455 :  rprimd(:,:)=hist%rprimd(:,:,hist%ihist)
     202          315 :  fcart(:,:)=hist%fcart(:,:,hist%ihist)
     203           35 :  call xred2xcart(ab_mover%natom,rprimd,xcart,hist%xred(:,:,hist%ihist))
     204              : 
     205              : !##########################################################
     206              : !### 03. Decide based on kind of preconditioner if
     207              : !###     a new matrix should be computed
     208              : 
     209           35 :  new_order_forces = one  ! This to avoid using unitialized variables.
     210              : 
     211           35 :  if (ab_mover%goprecon==2)then
     212              : 
     213            0 :    val_rms=0.0
     214            0 :    do kk=1,ab_mover%natom
     215            0 :      do jj=1,3
     216            0 :        val_rms=val_rms+fcart(jj,kk)**2
     217              :      end do
     218              :    end do
     219            0 :    val_rms=sqrt(val_rms/dble(ab_mover%natom))
     220            0 :    new_order_forces=int(log(val_rms)/log(10.0))
     221              :  end if
     222              : 
     223           35 :  if (itime==1.and.icycle==1)then
     224            6 :    Compute_Matrix=.TRUE.
     225            6 :    order_forces=new_order_forces
     226            6 :    if (allocated(matrix))  then
     227            0 :      ABI_FREE(matrix)
     228              :    end if
     229              : 
     230           24 :    ABI_MALLOC(matrix,(3*ab_mover%natom,3*ab_mover%natom))
     231              :  else
     232           29 :    Compute_Matrix=.FALSE.
     233           29 :    if ((ab_mover%goprecon==2).and.(order_forces.gt.new_order_forces)) then
     234            0 :      Compute_Matrix=.TRUE.
     235            0 :      order_forces=new_order_forces
     236              :    end if
     237           29 :    if (ab_mover%goprecon==3) Compute_Matrix=.TRUE.
     238              :  end if
     239              : 
     240              : !##########################################################
     241              : !### 04. Compute a new precondition matrix if required
     242              : 
     243           29 :  if (Compute_Matrix)then
     244              : 
     245              : !  Fix the tolerance for create a bond
     246            6 :    bonds%tolerance=1.35
     247            6 :    bonds%nbonds=1
     248              : 
     249              : !  Allocate the arrays with exactly the rigth nbonds
     250            6 :    ABI_MALLOC(bonds%bond_vect,(3,bonds%nbonds))
     251            6 :    ABI_MALLOC(bonds%bond_length,(bonds%nbonds))
     252           18 :    ABI_MALLOC(bonds%indexi,(ab_mover%natom,bonds%nbonds))
     253           18 :    ABI_MALLOC(bonds%nbondi,(ab_mover%natom))
     254              : 
     255              : !  Compute the bonds
     256              :    call make_bonds_new(bonds,ab_mover%natom,ab_mover%ntypat,rprimd,&
     257            6 : &   ab_mover%typat,xcart,ab_mover%znucl)
     258              : 
     259          384 :    write(std_out,'(a,a,63a,a)') ch10,'---PRECONDITIONER',('-',kk=1,63),ch10
     260              : 
     261              : !  For all bonds detect wich atoms are involved
     262              : !  and wich period they coprrespond in the periodic table
     263            6 :    if (bonds%nbonds>0)then
     264              : 
     265           18 :      ABI_MALLOC(periods,(2,bonds%nbonds))
     266           12 :      ABI_MALLOC(iatoms,(2,bonds%nbonds))
     267           24 :      periods(:,:)=0
     268           24 :      iatoms(:,:)=0
     269              : 
     270            6 :      write(std_out,'(a)') 'Bond of Atom | Bond Number | Index'
     271              : 
     272           18 :      do ii=1,ab_mover%natom
     273           12 :        Z=ab_mover%znucl(ab_mover%typat(ii))
     274           12 :        if (Z==1)then
     275              :          period=1
     276            0 :        elseif ((Z>1).and.(Z<10))then
     277              :          period=2
     278            0 :        elseif ((Z>10).and.(Z<18))then
     279              :          period=3
     280            0 :        elseif ((Z>18).and.(Z<36))then
     281              :          period=4
     282            0 :        elseif ((Z>36).and.(Z<54))then
     283              :          period=5
     284            0 :        elseif ((Z>55).and.(Z<86))then
     285              :          period=6
     286              :        else
     287              : !        Here are the cases for atoms larger than Fr(87) and
     288              : !        All the noble gases He-Rn
     289            0 :          period=-1
     290              :        end if
     291              : 
     292           30 :        do jj=1,bonds%nbondi(ii)
     293           12 :          index=bonds%indexi(ii,jj)
     294              : 
     295           12 :          write(std_out,'(i6,a,i6,a,i4)') ii,'       |',jj,'       |',index
     296              : 
     297              : !        The first atom should have index=0
     298              : !        To make easy fill the matrix using its
     299              : !        index
     300              : 
     301           24 :          if (index>0)then
     302            6 :            periods(1,index)=period
     303            6 :            iatoms(1,index)=ii
     304            6 :          elseif (index<0) then
     305            6 :            periods(2,-index)=period
     306            6 :            iatoms(2,-index)=ii
     307              :          end if
     308              :        end do
     309              :      end do
     310              : 
     311            6 :      write(std_out,'(a)') ch10
     312              : 
     313              :    end if
     314              : 
     315              : !  For all bonds compute the 3x3 matrix and fill also the big matrix
     316              : 
     317          258 :    matrix(:,:)=0.0_dp
     318           12 :    do ii=1,bonds%nbonds
     319              : 
     320            6 :      write(std_out,*) 'Bond number:',ii
     321           12 :      if (iatoms(1,ii)>0 .and. iatoms(2,ii)>0) then
     322            6 :        write(std_out,*) 'Between atoms:',iatoms(1,ii),' and ',iatoms(2,ii)
     323            6 :        badgerfactor=badger(periods(1,ii),periods(2,ii))
     324            6 :        write(std_out,*) 'Periods of atoms:',periods(1,ii),' and ',periods(2,ii)
     325            6 :        write(std_out,*) 'Badger factor:',badgerfactor
     326              : 
     327              : !      Compute the diadic product and
     328              : !      Insert the matrix into the big one
     329           24 :        do jj=1,3
     330           78 :          do kk=1,3
     331              : !          The non diagonal elements
     332           54 :            jsub=3*(iatoms(1,ii)-1)+jj
     333           54 :            ksub=3*(iatoms(2,ii)-1)+kk
     334              :            matrix(jsub,ksub)=matrix(jsub,ksub)-&
     335           54 : &           badgerfactor*bonds%bond_vect(jj,ii)*bonds%bond_vect(kk,ii)
     336              : 
     337           54 :            jsub=3*(iatoms(2,ii)-1)+jj
     338           54 :            ksub=3*(iatoms(1,ii)-1)+kk
     339              :            matrix(jsub,ksub)=matrix(jsub,ksub)-&
     340           54 : &           badgerfactor*bonds%bond_vect(jj,ii)*bonds%bond_vect(kk,ii)
     341              : 
     342              : !          The diagonal blocks
     343           54 :            jsub=3*(iatoms(1,ii)-1)+jj
     344           54 :            ksub=3*(iatoms(1,ii)-1)+kk
     345              :            matrix(jsub,ksub)=matrix(jsub,ksub)+&
     346           54 : &           badgerfactor*bonds%bond_vect(jj,ii)*bonds%bond_vect(kk,ii)
     347              : 
     348           54 :            jsub=3*(iatoms(2,ii)-1)+jj
     349           54 :            ksub=3*(iatoms(2,ii)-1)+kk
     350              :            matrix(jsub,ksub)=matrix(jsub,ksub)+&
     351           72 : &           badgerfactor*bonds%bond_vect(jj,ii)*bonds%bond_vect(kk,ii)
     352              : 
     353              :          end do !do kk=1,3
     354              :        end do !do jj=1,3
     355              : 
     356              :      end if
     357              : 
     358              :    end do
     359              : 
     360            6 :    if (bonds%nbonds>0)then
     361            6 :      ABI_FREE(periods)
     362            6 :      ABI_FREE(iatoms)
     363              :    end if
     364              : 
     365            6 :    call bonds_free(bonds)
     366              : 
     367            6 :    if (3*ab_mover%natom<100)then
     368              : !    Visualize the matrix
     369           42 :      do jj=1,3*ab_mover%natom
     370           42 :        write (std_out,fmt) matrix(jj,:)
     371              :      end do
     372              :    end if
     373              : 
     374           24 :    ABI_MALLOC(matrix_tmp,(3*ab_mover%natom,3*ab_mover%natom))
     375              : 
     376          258 :    matrix_tmp(:,:)=matrix(:,:)
     377              :    !write(*,*)"matrix_tmp",matrix_tmp
     378              : 
     379            6 :    ABI_MALLOC(work,(1))
     380            6 :    lwork=-1
     381            6 :    call DSYEV('V', 'U', 3*ab_mover%natom, matrix_tmp, 3*ab_mover%natom, w , work, lwork, info )
     382            6 :    lwork=work(1)
     383            6 :    write(std_out,*) '[DSYEV] Recommended lwork=',lwork
     384            6 :    ABI_FREE(work)
     385           18 :    ABI_MALLOC(work,(lwork))
     386            6 :    call DSYEV('V', 'U', 3*ab_mover%natom, matrix_tmp, 3*ab_mover%natom, w , work, lwork, info )
     387            6 :    ABI_FREE(work)
     388            6 :    ABI_FREE(matrix_tmp)
     389              : 
     390            6 :    write(std_out,*) 'DSYEV info=',info
     391            6 :    write(std_out,*) 'Eigenvalues:'
     392            6 :    write(std_out,fmt) w(:)
     393              : 
     394            6 :    sigma=0
     395           42 :    do jj=1,3*ab_mover%natom
     396           42 :      sigma=max(w(jj),sigma)
     397              :    end do
     398              : 
     399          258 :    matrix=lambda*matrix
     400              : 
     401            6 :    write(std_out,*) ch10
     402           42 :    do ii=1,3*ab_mover%natom
     403           42 :      matrix(ii,ii)=matrix(ii,ii)+(1-lambda)*sigma
     404              :    end do
     405              : 
     406              :  end if ! if (Compute_Matrix)
     407              : 
     408              : !##########################################################
     409              : !### 05. Use the precondition matrix to compute new residuals
     410              : 
     411           70 :  B=reshape(fcart,(/ 3*ab_mover%natom /))
     412              : 
     413           35 :  if (3*ab_mover%natom<100)then
     414              : !  Visualize the matrix
     415          245 :    do jj=1,3*ab_mover%natom
     416          245 :      write (std_out,fmt) matrix(jj,:)
     417              :    end do
     418              :  end if
     419              : 
     420              : !call dsysv( uplo, n, nrhs, a, lda, ipiv, b, ldb, work, lwork, info )
     421              : !MGNAG FIXME: This call causes a floating point exception if NAG+MKL
     422           35 :  ABI_MALLOC(work,(1))
     423           35 :  lwork=-1
     424              :  call DSYSV( 'U', 3*ab_mover%natom, 1, matrix,&
     425           35 : & 3*ab_mover%natom, ipiv, B, 3*ab_mover%natom, work, lwork, info )
     426              : 
     427           35 :  lwork=work(1)
     428           35 :  write(std_out,*) '[DSYSV] Recomended lwork=',lwork
     429           35 :  ABI_FREE(work)
     430          105 :  ABI_MALLOC(work,(lwork))
     431              :  call DSYSV( 'U', 3*ab_mover%natom, 1, matrix,&
     432           35 : & 3*ab_mover%natom, ipiv, B, 3*ab_mover%natom, work, lwork, info )
     433           35 :  ABI_FREE(work)
     434              : 
     435           35 :  write(std_out,*) 'DSYSV info=',info
     436           35 :  write(std_out,*) 'Solution:'
     437           35 :  write(std_out,fmt) B(:)
     438              : 
     439          420 :  forstr%fcart=reshape(B,(/ 3, ab_mover%natom /) )
     440           35 :  call fcart2gred(forstr%fcart,forstr%gred,rprimd,ab_mover%natom)
     441              : 
     442          440 : end subroutine prec_simple
     443              : !!***
     444              : 
     445              : end module m_pred_simple
     446              : !!***
        

Generated by: LCOV version 2.3-1