autocell.f90 Source File

Files Dependent On This One

sourcefile~~autocell.f90~~AfferentGraph sourcefile~autocell.f90 autocell.f90 sourcefile~main.f90~8 main.f90 sourcefile~autocell.f90->sourcefile~main.f90~8
Help

Source Code


Source Code

#include "precompilerdefinitions"
module autocell
    use konstanter, only: flyt,lo_tol,lo_pi
    use helpers, only: lo_determ
    use geometryfunctions, only: lo_inscribed_sphere_in_box
    use type_crystalstructure, only: lo_crystalstructure
    
    implicit none
    private
    public :: return_supercellmatrix

contains

!> return a good supercell matrix
subroutine return_supercellmatrix(p,na,supercellmatrix)
    !> unitcell
    type(lo_crystalstructure), intent(in) :: p
    !> desired number of atoms
    integer, intent(in) :: na
    !> fashionable supercell matrix
    integer, dimension(3,3), intent(out) :: supercellmatrix

    real(flyt), dimension(3,3) :: m0,m1,m2,basis,guessm
    real(flyt) :: det,f0,fillratio,r0,volumetolerance
    real(flyt) :: perfect_fill,sphvolf,volfactor
    integer, dimension(3,3) :: guessmatrix
    integer :: i1,i2,i3,i4,i5,i6,i7,i8,i9,nrep
    logical :: foundsomething

    ! Some parameters. First the ideal fill-ratio of a unit sphere in a unit cube.
    ! if I achieve this, I can cancel the loop or something
    basis=p%latticevectors
    volfactor=(na*1.0_flyt)/p%na
    perfect_fill=0.523598775598299_flyt
    sphvolf=4.0_flyt*lo_pi/3.0_flyt
    
    ! Start by getting a decent guess on how to build a cubic matrix, without regard
    ! to how many atoms there are and so on.
    fillratio=0.0_flyt ! reset the fillratio
    guessm=0.0_flyt    ! reset the guess matrix
    ! this is probably really dangerous, but whatever
    reploop: do nrep=1,4
    do i1=nrep,-nrep,-1
    do i2=nrep,-nrep,-1 
    do i3=nrep,-nrep,-1 
    do i4=nrep,-nrep,-1 
    do i5=nrep,-nrep,-1 
    do i6=nrep,-nrep,-1 
    do i7=nrep,-nrep,-1 
    do i8=nrep,-nrep,-1 
    do i9=nrep,-nrep,-1
        m0(:,1)=[i1,i2,i3]
        m0(:,2)=[i4,i5,i6]
        m0(:,3)=[i7,i8,i9]
        det=lo_determ(m0)
        if ( det .lt. lo_tol ) cycle
        m1=matmul(basis,m0)               ! apply the supercell matrix
        det=abs(lo_determ(m1))            ! get the volume
        r0=lo_inscribed_sphere_in_box(m1) ! radius of inscribed sphere  
        f0=sphvolf*r0**3/det              ! filling ratio
        if ( f0-fillratio .gt. lo_tol ) then
            fillratio=f0
            guessm=m0
            if ( fillratio/perfect_fill .gt. 0.96_flyt ) exit reploop
        endif 
    enddo
    enddo
    enddo
    enddo
    enddo
    enddo
    enddo
    enddo
    enddo
    enddo reploop

    ! Now I have a decent guess. Adjust this matrix so that it has exactly
    ! the correct determinant
    det=lo_determ(guessm)
    m2=guessm/( det**(1.0_flyt/3.0_flyt) )
    m2=m2*( volfactor**(1.0_flyt/3.0_flyt) )
    ! for the guess, I will round this.
    guessmatrix=int(anint(m2))

    ! Now that I have an approximate supercell matrix, search a bit 
    ! around the guess to find a really good one
    nrep=2                              ! probably an ok guess
    fillratio=0.0_flyt                  ! reset the fillratio
    m2=0.0_flyt                         ! reset the guess matrix
    volumetolerance=volfactor*0.2_flyt  ! initial tolerance for number of atoms
    foundsomething=.false.
    do i1=nrep,-nrep,-1
    do i2=nrep,-nrep,-1 
    do i3=nrep,-nrep,-1 
    do i4=nrep,-nrep,-1 
    do i5=nrep,-nrep,-1 
    do i6=nrep,-nrep,-1 
    do i7=nrep,-nrep,-1 
    do i8=nrep,-nrep,-1 
    do i9=nrep,-nrep,-1
        m0(:,1)=[i1,i2,i3]
        m0(:,2)=[i4,i5,i6]
        m0(:,3)=[i7,i8,i9]
        m0=m0+guessmatrix
        det=lo_determ(m0)
        if ( det .lt. volfactor-lo_tol ) cycle
        if ( abs(det-volfactor) .gt. volumetolerance ) cycle
        m1=matmul(basis,m0)               ! apply the supercell matrix
        det=abs(lo_determ(m1))            ! get the volume
        r0=lo_inscribed_sphere_in_box(m1) ! radius of inscribed sphere  
        f0=sphvolf*r0**3/det              ! filling ratio
        if ( f0-fillratio .gt. lo_tol ) then
            fillratio=f0
            m2=m0
            foundsomething=.true.
        endif 
    enddo
    enddo
    enddo
    enddo
    enddo
    enddo
    enddo
    enddo
    enddo
    ! Return the results, perhaps?
    if ( foundsomething ) then
        supercellmatrix=int(anint(m2))
    else
        write(*,*) 'Could not find any supercell. This is easily fixable:'
        write(*,*) 'try with a different number of desired atoms, per default only'
        write(*,*) 'supercells within 20% of this number of atoms are accepted.'
        stop
    endif
   
end subroutine

end module