LCOV - code coverage report
Current view: top level - force - relaxation.F90 (source / functions) Hit Total Coverage
Test: FLEUR test coverage Lines: 70 127 55.1 %
Date: 2024-04-24 04:44:14 Functions: 2 4 50.0 %

          Line data    Source code
       1             : !--------------------------------------------------------------------------------
       2             : ! Copyright (c) 2016 Peter Grünberg Institut, Forschungszentrum Jülich, Germany
       3             : ! This file is part of FLEUR and available as free software under the conditions
       4             : ! of the MIT license as expressed in the LICENSE file in more detail.
       5             : !--------------------------------------------------------------------------------
       6             : 
       7             : MODULE m_relaxation
       8             :    USE m_judft
       9             : 
      10             : #ifdef CPP_MPI
      11             :    USE mpi
      12             : #endif
      13             : 
      14             :    IMPLICIT NONE
      15             : 
      16             :    PRIVATE
      17             :    PUBLIC relaxation !This is the interface. Below there are internal subroutines for bfgs, simple mixing, CG ...
      18             : 
      19             : CONTAINS
      20           4 :    SUBROUTINE relaxation(fmpi,input,atoms,cell,sym ,vacuum,force_new,energies_new)
      21             :       ! This routine uses the current force,energies and atomic positions to
      22             :       ! generate a displacement in a relaxation step.
      23             :       ! The history is taken into account by read_relax from m_relaxio
      24             :       ! After generating new positions the code stops
      25             : 
      26             :       USE m_types
      27             :       USE m_constants
      28             :       USE m_relaxio
      29             :       USE m_mixing_history
      30             :       USE m_chkmt
      31             :       USE m_types_xml
      32             :       USE m_xsf_io
      33             : 
      34             :       TYPE(t_mpi),    INTENT(IN) :: fmpi
      35             :       TYPE(t_input),  INTENT(IN) :: input
      36             :       TYPE(t_atoms),  INTENT(IN) :: atoms
      37             :       TYPE(t_sym),    INTENT(IN) :: sym
      38             : 
      39             :       TYPE(t_vacuum), INTENT(IN) :: vacuum
      40             :       TYPE(t_cell),   INTENT(IN) :: cell
      41             :       REAL,           INTENT(IN) :: force_new(:,:), energies_new !data for this iteration
      42             : 
      43           4 :       REAL, ALLOCATABLE :: pos(:,:,:), force(:,:,:), energies(:)
      44           4 :       REAL, ALLOCATABLE :: displace(:,:), old_displace(:,:), tempDisplace(:,:)
      45           4 :       REAL, ALLOCATABLE :: totalDisplace(:,:)
      46           4 :       REAL              :: dispAll(3,atoms%nat), overlap(0:atoms%ntype,atoms%ntype)
      47             :       REAL              :: dispLength, maxDisp, limitDisp
      48             :       INTEGER           :: iType, ierr, numDispReduce
      49             :       LOGICAL           :: l_conv
      50             : 
      51             :       CHARACTER(len=100):: filename_add
      52             : 
      53             :       ! To calculate the current displacement
      54             :       TYPE(t_xml)   :: xml
      55           4 :       TYPE(t_atoms) :: atoms_non_displaced
      56           4 :       TYPE(t_atoms) :: tempAtoms
      57             : 
      58           4 :       IF (fmpi%irank==0) THEN
      59           2 :          filename_add = ""
      60           2 :          IF (judft_was_argument("-add_name")) filename_add = TRIM(judft_string_for_argument("-add_name"))//"_"
      61           2 :          CALL xml%init(filename_add)
      62           6 :          ALLOCATE(pos(3,atoms%ntype,1));
      63             : 
      64           6 :          DO iType = 1, atoms%ntype
      65          18 :             pos(:,iType,1)=atoms%pos(:,atoms%firstAtom(iType))
      66             :          END DO
      67             : 
      68          20 :          ALLOCATE(force(3,atoms%ntype,1)); force(:,:,1)=force_new
      69           2 :          ALLOCATE(energies(1));energies(1)=energies_new
      70           6 :          ALLOCATE(displace(3,atoms%ntype),old_displace(3,atoms%ntype))
      71           6 :          ALLOCATE(tempDisplace(3,atoms%ntype),totalDisplace(3,atoms%ntype))
      72          18 :          totalDisplace=0.0
      73             :          ! Remove force components that are not selected for relaxation
      74           6 :          DO iType = 1, atoms%ntype
      75           6 :             IF (atoms%l_geo(iType)) THEN
      76          16 :                force(:,iType,1)=force(:,iType,1)*REAL(atoms%relax(:,iType))
      77             :             ELSE
      78           0 :                force(:,iType,1)=0.0
      79             :             END IF
      80             :          END DO
      81             : 
      82             :          ! Add history
      83           2 :          CALL read_relax(pos,force,energies)
      84             : 
      85             :          ! Determine new positions
      86           2 :          IF (SIZE(energies)==1.OR.input%forcemix==0) THEN
      87             :             ! No history present simple step
      88             :             ! choose a reasonable first guess for scaling
      89             :             ! this choice is based on a Debye temperature of 330K;
      90             :             ! modify as needed
      91             :             !alpha = (250.0/(MAXVAL(atoms%zatom)*input%xa))*((330./input%thetad)**2)
      92           2 :             CALL simple_step(input%forcealpha,0.25,force,displace)
      93           0 :          ELSE IF (input%forcemix==1) THEN
      94           0 :             CALL simple_cg(pos,force,displace)
      95           0 :          ELSE IF (input%forcemix==2) THEN
      96           0 :             CALL simple_bfgs(pos,force,displace)
      97             :          ELSE
      98           0 :             CALL juDFT_error('Unknown mixing scheme for forces', calledby='relaxation')
      99             :          END IF
     100             : 
     101             :          ! Check for convergence of forces/displacements
     102           2 :          maxDisp = 0.0
     103           2 :          l_conv = .TRUE.
     104           6 :          DO iType = 1, atoms%ntype
     105          16 :             IF (DOT_PRODUCT(force(:,iType,SIZE(force,3)),force(:,iType,SIZE(force,3)))>input%epsforce**2) l_conv=.FALSE.
     106          16 :             dispLength = SQRT(DOT_PRODUCT(displace(:,iType),displace(:,iType)))
     107           4 :             maxDisp = MAX(maxDisp,dispLength)
     108           6 :             IF (dispLength>input%epsdisp) l_conv=.FALSE.
     109             :          END DO
     110             : 
     111             :          ! Limit the maximal displacement in a single force relaxation step to limitDisp = 0.2 a_0.
     112           2 :          limitDisp = 0.2
     113           2 :          IF(maxDisp.GT.limitDisp) THEN
     114           0 :             displace(:,:) = limitDisp*displace(:,:) / maxDisp
     115             :          END IF
     116             : 
     117             :          ! New displacements relative to positions in inp.xml
     118             :          !CALL read_displacements(atoms,old_displace)
     119           2 :          CALL atoms_non_displaced%read_xml(xml)
     120           2 :          CALL xml%freeResources()
     121           2 :          CALL atoms_non_displaced%init(cell)
     122             : 
     123           6 :          DO iType = 1, atoms%ntype
     124             :             old_displace(:,iType) = atoms%pos(:,atoms%firstAtom(iType)) - &
     125          18 :                                     atoms_non_displaced%pos(:,atoms%firstAtom(iType))
     126             :          END DO
     127             : 
     128           6 :          tempAtoms = atoms_non_displaced
     129          86 :          tempDisplace = MATMUL(cell%bmat,totalDisplace)/tpi_const
     130             : 
     131           2 :          CALL rotate_to_all_sites(tempDisplace,atoms_non_displaced,cell,sym,dispAll)
     132          22 :          tempAtoms%taual(:,:)=atoms_non_displaced%taual(:,:)+dispAll(:,:)
     133         222 :          tempAtoms%pos=MATMUL(cell%amat,tempAtoms%taual)
     134             : 
     135           6 :          numDispReduce = 0
     136          18 :          overlap=1.0
     137          22 :          DO WHILE(ANY(overlap.GT.0.0))
     138          18 :             overlap = 0.0
     139          20 :             totalDisplace=displace+old_displace
     140             : 
     141          10 :             tempAtoms = atoms_non_displaced
     142         122 :             tempDisplace = MATMUL(cell%bmat,totalDisplace)/tpi_const
     143             : 
     144           2 :             CALL rotate_to_all_sites(tempDisplace,atoms_non_displaced,cell,sym,dispAll)
     145          22 :             tempAtoms%taual(:,:)=atoms_non_displaced%taual(:,:)+dispAll(:,:)
     146         222 :             tempAtoms%pos=MATMUL(cell%amat,tempAtoms%taual)
     147           2 :             CALL chkmt(tempAtoms,input,vacuum,cell ,.TRUE.,overlap=overlap)
     148             : 
     149          20 :             IF (ANY(overlap.GT.0.0)) THEN
     150           0 :                numDispReduce = numDispReduce + 1
     151           0 :                IF (numDispReduce.GE.3) THEN
     152           0 :                   CALL juDFT_warn("Strong MT spheres crash in structural relaxation")
     153             :                END IF
     154           0 :                displace(:,:) = 0.5 * displace(:,:)
     155           0 :                WRITE(oUnit,*) 'Automatically reducing atom displacements because MT spheres crash into each other!'
     156           0 :                WRITE(*,*) 'Automatically reducing atom displacements because MT spheres crash into each other!'
     157             :                ! TODO: Why two calls?
     158             :             END IF
     159             :          END DO
     160             : 
     161             :          ! Write relax file
     162           2 :          CALL write_relax(pos,force,energies,totalDisplace)
     163             : 
     164             :          ! Structure in xsf-format
     165           2 :          OPEN (55,file="struct-relax.xsf",status='replace')
     166           2 :          CALL xsf_WRITE_atoms(55,tempAtoms,input%film,cell%amat)
     167           2 :          CLOSE (55)
     168             :       END IF
     169             : 
     170             : #ifdef CPP_MPI
     171           4 :       CALL MPI_BCAST(l_conv,1,MPI_LOGICAL,0,fmpi%mpi_comm,ierr)
     172             : #endif
     173             : 
     174           4 :       IF (l_conv) THEN
     175           0 :          CALL judft_end("Structural relaxation: Done",fmpi%irank)
     176             :       ELSE
     177           4 :          CALL mixing_history_reset(fmpi)
     178           4 :          CALL judft_end("Structural relaxation: new displacements generated",fmpi%irank)
     179             :       END IF
     180             : 
     181           4 :    END SUBROUTINE relaxation
     182             : 
     183           2 :    SUBROUTINE simple_step(alpha,maxdisp,force,displace)
     184             : 
     185             :       IMPLICIT NONE
     186             : 
     187             :       REAL, INTENT(IN)  :: alpha,maxdisp
     188             :       REAL, INTENT(IN)  :: force(:,:,:)
     189             :       REAL, INTENT(OUT) :: displace(:,:)
     190             : 
     191             :       REAL :: corr
     192             : 
     193          18 :       displace = alpha*force(:,:,SIZE(force,3))
     194          18 :       corr=maxdisp/maxval(abs(displace))
     195           2 :       IF (corr<1.0) displace = corr*alpha*force(:,:,size(force,3))
     196             : 
     197           2 :    END SUBROUTINE simple_step
     198             : 
     199           0 :    SUBROUTINE simple_bfgs(pos,force,shift)
     200             :       !--------------------------------------------------------------------------
     201             :       !  Simple BFGS method to calculate shift out of old positions and forces
     202             :       !--------------------------------------------------------------------------
     203             :       USE m_constants
     204             : 
     205             :       REAL,INTENT(IN)  :: pos(:,:,:),force(:,:,:)
     206             :       REAL,INTENT(OUT) :: shift(:,:)
     207             : 
     208             :       INTEGER           :: n, i, j, hist_length, n_force
     209             :       REAL, ALLOCATABLE :: h(:,:)
     210           0 :       REAL, ALLOCATABLE :: p(:), y(:), v(:)
     211             :       REAL              :: py, yy, gamma
     212             : 
     213           0 :       n_force=3*SIZE(pos,2)
     214           0 :       ALLOCATE(h(n_force,n_force))
     215           0 :       ALLOCATE(p(n_force),y(n_force),v(n_force))
     216             : 
     217             :       ! Calculate approx. Hessian
     218             : 
     219             :       ! Initialize H
     220           0 :       h = 0.0
     221             : 
     222           0 :       DO n = 1,n_force
     223           0 :          h(n,n) = 1.0
     224             :       END DO
     225             : 
     226             :       ! Loop over all iterations (including current)
     227           0 :       hist_length=SIZE(pos,3)
     228             : 
     229           0 :       DO n = 2,hist_length
     230             :          ! Differences
     231           0 :          p(:) = RESHAPE(pos(:,:,n)-pos(:,:,n-1),(/SIZE(p)/))
     232           0 :          y(:) = RESHAPE(force(:,:,n-1)-force(:,:,n),(/SIZE(p)/))
     233             : 
     234             :          ! Get necessary inner products and H|y>
     235           0 :          py = DOT_PRODUCT(p,y)
     236           0 :          v = MATMUL(y,h)
     237           0 :          yy = DOT_PRODUCT(y,v)
     238             : 
     239             :          ! Check that update will leave h positive definite:
     240           0 :          IF (py <= 0.0) THEN
     241           0 :             WRITE (oUnit,*) '  bfgs: <p|y> < 0'
     242           0 :             WRITE (oUnit,*) '  check convergence of forces'
     243             :             ! Starting over with initial hessian
     244           0 :             h = 0.0
     245           0 :             DO j = 1,n_force
     246           0 :                h(j,j) = 1.0
     247             :             END   DO
     248             :             CYCLE
     249             :          ELSE
     250             :             ! Update h
     251           0 :             IF (n == 2) THEN
     252           0 :                gamma = py/yy
     253             :             ELSE
     254             :                gamma = 1.0
     255             :             END IF
     256             : 
     257           0 :             DO j = 1,n_force
     258           0 :                DO i = 1,n_force
     259           0 :                   h(i,j) = (h(i,j) - (v(i)*p(j)+p(i)*v(j))/py)*gamma + (1.+gamma*yy/py)*p(i)*p(j)/py
     260             :                END DO
     261             :             END DO
     262             :          END IF
     263             :       END DO
     264             : 
     265           0 :       y(:) = RESHAPE(force(:,:,hist_length),(/SIZE(p)/))
     266           0 :       shift = RESHAPE(MATMUL(y,h),SHAPE(shift))
     267           0 :    END SUBROUTINE simple_bfgs
     268             : 
     269           0 :    SUBROUTINE simple_cg(pos,force,shift)
     270             : 
     271             :       REAL, INTENT(IN)  :: pos(:,:,:),force(:,:,:)
     272             :       REAL, INTENT(OUT) :: shift(:,:)
     273             : 
     274           0 :       REAL               :: f1(3,SIZE(pos,2)),f2(3,SIZE(pos,2))
     275           0 :       REAL               :: dist(3,SIZE(pos,2))
     276             :       REAL               :: eps
     277             :       INTEGER            :: n_old, i, j
     278             : 
     279           0 :       eps = 1.0e-9
     280             : 
     281           0 :       n_old = SIZE(pos,3)-1
     282             : 
     283           0 :       dist(:,:) = pos(:,:,n_old+1)-pos(:,:,n_old)
     284             : 
     285           0 :       DO i = 1, SIZE(pos,2)
     286           0 :          DO j = 1, 3
     287           0 :             IF(ABS(dist(j,i)).LT.eps) dist(j,i) = eps ! To avoid calculation of 0.0/0.0 below.
     288             :          END DO
     289             :       END DO
     290             : 
     291           0 :       f1 = (force(:,:,n_old+1)-force(:,:,n_old))/dist
     292           0 :       f2 = force(:,:,n_old+1)-f1*pos(:,:,n_old+1)
     293           0 :       shift = -1.*f2/f1-force(:,:,n_old+1)
     294           0 :    END SUBROUTINE simple_cg
     295             : 
     296           0 : END MODULE m_relaxation

Generated by: LCOV version 1.14