LCOV - code coverage report
Current view: top level - io - relax_io.F90 (source / functions) Hit Total Coverage
Test: FLEUR test coverage Lines: 54 110 49.1 %
Date: 2024-04-19 04:21:58 Functions: 5 5 100.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_relaxio
       8             :   !This module handles IO to the relax.xml file
       9             :   !The writing is done directly to relax.xml
      10             :   !The reading uses the libxml interface to inp.xml. Hence the relax.xml has to be included here.
      11             :   USE m_judft
      12             :   USE m_constants
      13             :   IMPLICIT NONE
      14             :   PRIVATE
      15             :   PUBLIC :: read_relax,write_relax,apply_displacements,read_displacements,rotate_to_all_sites
      16             : CONTAINS
      17           2 :   SUBROUTINE write_relax(positions,forces,energies,displace)
      18             :     REAL,INTENT(in):: positions(:,:,:)
      19             :     REAL,INTENT(in):: forces(:,:,:)
      20             :     REAL,INTENT(in):: energies(:)
      21             :     REAL,INTENT(in):: displace(:,:)
      22             : 
      23             :     INTEGER :: no_steps,n,ntype,step
      24             : 
      25             :     CHARACTER(len=100):: path,p,str,filename_add
      26             : 
      27           2 :     filename_add = ""
      28           2 :     IF (judft_was_argument("-add_name")) filename_add = TRIM(judft_string_for_argument("-add_name"))//"_"
      29             :     
      30           2 :     No_steps=SIZE(positions,3)
      31           2 :     ntype=SIZE(positions,2)
      32             :     IF (ntype.NE.SIZE(forces,2).OR.ntype.NE.SIZE(displace,2).OR.&
      33           2 :          no_steps.NE.SIZE(forces,3).OR.no_steps.NE.SIZE(energies))THEN
      34           0 :        CALL judft_error("BUG in relax_io")
      35             :     ENDIF
      36           2 :     OPEN(765,file=TRIM(filename_add)//"relax.xml",status="replace")
      37           2 :     WRITE(765,*) "<!-- Attention, absolute coordinates used here -->"
      38           2 :     WRITE(765,*) "<relaxation>"
      39             :     !write current set of displacements
      40           2 :     WRITE(765,*) "  <displacements>"
      41           6 :     DO n=1,SIZE(displace,2)
      42             :        WRITE(765,"(a,3(f15.10,1x),a)") &
      43           6 :             '    <displace>',displace(:,n),'</displace>'
      44             :     END DO
      45           2 :     WRITE(765,"(a)") '  </displacements>'
      46             : 
      47             :     !Write all known old positions,forces and energies
      48           2 :     WRITE(765,*) "  <relaxation-history>"
      49           4 :     DO step=1,no_steps
      50           2 :        WRITE(765,"(a,f20.10,a)") '    <step energy="',energies(step),'">'
      51           6 :        DO n=1,ntype
      52             :           WRITE(765,"(a,6(f15.10,1x),a)") &
      53           6 :                '      <posforce>',positions(:,n,step),forces(:,n,step),'</posforce>'
      54             :        END DO
      55           4 :        WRITE(765,"(a)") '    </step>'
      56             :     ENDDO
      57           2 :     WRITE(765,*) "  </relaxation-history>"
      58           2 :     WRITE(765,*) "</relaxation>"
      59           2 :     CLOSE(765)
      60           2 :   END SUBROUTINE write_relax
      61             : 
      62           2 :   SUBROUTINE read_relax(positions,forces,energies)
      63             :     USE m_types_xml
      64             :     USE m_calculator
      65             :     REAL,INTENT(INOUT),ALLOCATABLE:: positions(:,:,:)
      66             :     REAL,INTENT(INOUT),ALLOCATABLE:: forces(:,:,:)
      67             :     REAL,INTENT(INOUT),ALLOCATABLE:: energies(:)
      68             : 
      69           2 :     REAL,ALLOCATABLE::rtmp(:,:,:)
      70             :     INTEGER:: no_steps
      71             :     INTEGER:: ntype,step,n
      72             :     CHARACTER(len=100):: path,p,str,filename_add
      73             : 
      74             :     TYPE(t_xml)::xml
      75           2 :     filename_add = ""
      76           2 :     IF (judft_was_argument("-add_name")) filename_add = TRIM(judft_string_for_argument("-add_name"))//"_"
      77           2 :     CALL xml%init(filename_add)
      78           2 :     no_steps=xml%GetNumberOfNodes('/fleurInput/relaxation/relaxation-history/step')
      79           2 :     ntype=SIZE(positions,2)
      80           2 :     IF (no_steps==0) THEN
      81           2 :        IF (.NOT.ALLOCATED(positions)) ALLOCATE(positions(0,0,0),forces(0,0,0),energies(0))
      82             :        RETURN
      83             :     END IF
      84           0 :     IF (ALLOCATED(positions)) THEN
      85             :        !Assume that we got already a set of positions, forces, energy and extend that list
      86           0 :        rtmp=positions
      87           0 :        DEALLOCATE(positions)
      88           0 :        ALLOCATE(positions(3,ntype,no_steps+SIZE(rtmp,3)))
      89           0 :        positions(:,:,no_steps+1:)=rtmp
      90           0 :        rtmp=forces
      91           0 :        DEALLOCATE(forces)
      92           0 :        ALLOCATE(forces(3,ntype,no_steps+SIZE(rtmp,3)))
      93           0 :        forces(:,:,no_steps+1:)=rtmp
      94           0 :        rtmp(1,1,:)=energies
      95           0 :        DEALLOCATE(energies)
      96           0 :        ALLOCATE(energies(no_steps+SIZE(rtmp,3)))
      97           0 :        energies(no_steps+1:)=rtmp(1,1,:)
      98             :     ELSE
      99           0 :        ALLOCATE(positions(3,ntype,no_steps))
     100           0 :        ALLOCATE(forces(3,ntype,no_steps))
     101           0 :        ALLOCATE(energies(no_steps))
     102             :     END IF
     103           0 :     DO step=1,no_steps
     104           0 :        WRITE(path,"(a,i0,a)") '/fleurInput/relaxation/relaxation-history/step[',step,']'
     105           0 :        energies(step)=evaluateFirstOnly(xml%GetAttributeValue(TRIM(path)//"/@energy"))
     106           0 :        DO n=1,ntype
     107           0 :           WRITE(p,"(a,a,i0,a)") TRIM(path),"/posforce[",n,"]"
     108           0 :           str=xml%GetAttributeValue(p)
     109           0 :           positions(:,n,step)=(/evaluateFirst(str),evaluateFirst(str),evaluateFirst(str)/)
     110           0 :           Forces(:,n,step)=(/evaluateFirst(str),evaluateFirst(str),evaluateFirst(str)/)
     111             :        ENDDO
     112             :     END DO
     113           0 :     call xml%FreeResources()
     114           2 :   END SUBROUTINE read_relax
     115             : 
     116             : 
     117          80 :   SUBROUTINE read_displacements(atoms,disp)
     118             :     USE m_types_xml
     119             :     USE m_calculator
     120             :     USE m_types
     121             :     TYPE(t_atoms),INTENT(in)::atoms
     122             :     REAL,INTENT(out)::disp(:,:)
     123             :     CHARACTER(len=50):: path,str
     124             :     INTEGER :: n
     125             : 
     126             :     TYPE(t_xml)::xml
     127             : 
     128         628 :     disp=0.0
     129          80 :     IF (xml%GetNumberOfNodes('/fleurInput/relaxation/displacements')==0) RETURN
     130             :     !read displacements and apply to positions
     131           0 :     IF (atoms%ntype.NE.xml%GetNumberOfNodes('/fleurInput/relaxation/displacements/displace')) CALL judft_error("Wrong number of displacements in relaxation")
     132           0 :     DO n=1,atoms%ntype
     133           0 :        WRITE(path,"(a,i0,a)") '/fleurInput/relaxation/displacements/displace[',n,']'
     134           0 :        str=xml%GetAttributeValue(path)
     135           0 :        disp(:,n)=(/evaluateFirst(str),evaluateFirst(str),evaluateFirst(str)/)
     136             :     END DO
     137          80 :   END SUBROUTINE read_displacements
     138             : 
     139          80 :   SUBROUTINE apply_displacements(cell,input,vacuum ,sym,noco,atoms,gfinp)
     140             :     USE m_types
     141             :     USE m_chkmt
     142             :     USE m_constants
     143             :     USE m_mapatom
     144             :     TYPE(t_input),INTENT(IN)   :: input
     145             :     TYPE(t_vacuum),INTENT(IN)  :: vacuum
     146             :     TYPE(t_cell),INTENT(IN)    :: cell
     147             : 
     148             :     TYPE(t_sym),INTENT(INOUT)  :: sym
     149             :     TYPE(t_noco),INTENT(IN)    :: noco
     150             :     type(t_gfinp), intent(in)  :: gfinp
     151          80 :     character(len=:), allocatable :: error_output
     152             : 
     153             :     TYPE(t_atoms),INTENT(INOUT):: atoms
     154             : 
     155             : 
     156             :     INTEGER:: n,indx(2)
     157          80 :     REAL   :: disp(3,atoms%ntype),disp_all(3,atoms%nat),taual0(3,atoms%nat),overlap(0:atoms%ntype,atoms%ntype)
     158             : 
     159          80 :     CALL read_displacements(atoms,disp)
     160             :     !change displacements to internal coordinates
     161        3197 :     disp=MATMUL(cell%bmat,disp)/tpi_const
     162         628 :     IF (ALL(ABS(disp)<1E-8)) RETURN
     163             :     !Fist make sure original MT spheres do not overlap
     164           0 :     CALL chkmt(atoms,input,vacuum,cell ,.TRUE.,overlap=overlap)
     165           0 :     IF(ANY(overlap>0.0)) CALL judft_error("Overlapping MT-spheres in relaxation before even applying any displacement",hint="You messed up your setup")
     166             : 
     167           0 :     taual0=atoms%taual !Store original positions
     168             : 
     169             :     !Now check for overlapping mt-spheres
     170           0 :     overlap=1.0
     171           0 :     DO WHILE(ANY(overlap>1E-10))
     172           0 :        atoms%taual=taual0
     173           0 :        CALL rotate_to_all_sites(disp,atoms,cell,sym,disp_all)
     174           0 :        atoms%taual=taual0+disp_all
     175           0 :        atoms%pos=MATMUL(cell%amat,atoms%taual)
     176           0 :        CALL chkmt(atoms,input,vacuum,cell ,.TRUE.,overlap=overlap)
     177           0 :        IF (ANY(overlap>0.0)) THEN
     178           0 :           IF (ANY(overlap(0,:)>1E-10)) CALL judft_error("Atom spills out into vacuum during relaxation")
     179           0 :           indx=MAXLOC(overlap(1:,:)) !the two indices with the most overlap
     180             :           !Try only 90% of displacement
     181           0 :           disp(:,indx(1))=disp(:,indx(1))*0.9
     182           0 :           disp(:,indx(2))=disp(:,indx(2))*0.9
     183           0 :           WRITE(*,*) "Attention: Overlapping MT-spheres. Reduced displacement by 10%"
     184           0 :           WRITE(*,*) indx,overlap(indx(1),indx(2))
     185           0 :           WRITE(oUnit,'(a,2(i0,1x),f12.8)') "Attention, overlapping MT-spheres: ",indx,overlap(indx(1),indx(2))
     186             :           ! WRITE(error_output, '(3a,f12.8,a)') "Overlapping MT-spheres during relaxation: ", atoms%label(atoms%firstAtom(indx(1))),&
     187             :           ! &atoms%label(atoms%firstAtom(indx(2))), overlap(indx(1),indx(2)),&
     188             :           ! &NEW_LINE('A')//"Treat as an error: writing rescaled displacements to relax.xml is not implemented"
     189             :           error_output = "Overlapping MT-spheres during relaxation: " // NEW_LINE('A') // &
     190             :                          strip(atoms%label(atoms%firstAtom(indx(1)))) // " " // &
     191             :                          strip(atoms%label(atoms%firstAtom(indx(2)))) // &
     192             :                          " olap: "//float2str(overlap(indx(1),indx(2)))//NEW_LINE('A')//&
     193           0 :                          "Treat as an error: writing rescaled displacements to relax.xml is not implemented"
     194           0 :           CALL judft_error(error_output)
     195             :        END IF
     196             :     END DO
     197             : 
     198           0 :     CALL mapatom(sym,atoms,cell,input,noco,gfinp)
     199             : 
     200           0 :     WRITE(oUnit,*) "Atomic positions including displacements:"
     201           0 :     DO n=1,atoms%nat
     202           0 :        WRITE(oUnit,"(i4,6(1x,f12.5))") n,atoms%taual(:,n),atoms%pos(:,n)
     203             :     ENDDO
     204             : 
     205           0 :   END SUBROUTINE apply_displacements
     206             : 
     207           4 :   SUBROUTINE rotate_to_all_sites(disp,atoms,cell,sym,disp_all)
     208             :     USE m_types
     209             :     REAL,INTENT(in)          :: disp(:,:)
     210             :     TYPE(t_atoms),INTENT(in) :: atoms
     211             :     TYPE(t_cell),INTENT(IN)  :: cell
     212             :     TYPE(t_sym),INTENT(IN)   :: sym
     213             :     REAL,INTENT(out)         :: disp_all(:,:)
     214             : 
     215             :     INTEGER:: iType,iAtom,jop, startAtom
     216             :     REAL   :: tau0(3),tau0_rot(3),tau_rot(3)
     217             : 
     218             : 
     219          12 :     DO iType = 1, atoms%ntype
     220           8 :        startAtom = atoms%firstAtom(iType)
     221          32 :        tau0=atoms%taual(:,startAtom)
     222          22 :        DO iAtom = startAtom, startAtom + atoms%neq(iType) - 1
     223          10 :           jop = sym%invtab(sym%ngopr(iAtom))
     224         280 :           tau0_rot=MATMUL(1.*sym%mrot(:,:,jop),tau0)+sym%tau(:,jop) !translation will cancel, included for clarity
     225         320 :           tau_rot=MATMUL(1.*sym%mrot(:,:,jop),tau0+disp(:,iType))+sym%tau(:,jop)
     226          48 :           disp_all(:,iAtom)=tau_rot-tau0_rot
     227             :        END DO
     228             :     END DO
     229           4 :   END SUBROUTINE rotate_to_all_sites
     230         100 : END MODULE m_relaxio

Generated by: LCOV version 1.14