1!--------------------------------------------------------------------------------------------------! 2! CP2K: A general program to perform molecular dynamics simulations ! 3! Copyright (C) 2000 - 2020 CP2K developers group ! 4!--------------------------------------------------------------------------------------------------! 5 6! ************************************************************************************************** 7!> \brief Routines to deal with vectors in 3-D real space. 8! ************************************************************************************************** 9 10MODULE negf_vectors 11 USE kinds, ONLY: dp 12 USE particle_types, ONLY: particle_type 13 USE qs_subsys_types, ONLY: qs_subsys_get,& 14 qs_subsys_type 15#include "./base/base_uses.f90" 16 17 IMPLICIT NONE 18 PRIVATE 19 20 CHARACTER(len=*), PARAMETER, PRIVATE :: moduleN = 'negf_vectors' 21 22 PUBLIC :: contact_direction_vector, projection_on_direction_vector 23 24CONTAINS 25 26! ************************************************************************************************** 27!> \brief compute direction vector of the given contact 28!> \param origin origin 29!> \param direction_vector direction vector 30!> \param origin_bias origin which will be used to apply the external bias 31!> (in contrast with 'origin' it does not include screening region) 32!> \param direction_vector_bias direction vector which will be used to apply the external bias 33!> (together with 'origin_bias' it defines a contact region where 34!> the external potential is kept constant) 35!> \param atomlist_screening atoms belonging to the contact's screening region 36!> \param atomlist_bulk atoms belonging to the contact's bulk region 37!> \param subsys QuickStep subsystem 38!> \author Sergey Chulkov 39! ************************************************************************************************** 40 SUBROUTINE contact_direction_vector(origin, direction_vector, origin_bias, direction_vector_bias, & 41 atomlist_screening, atomlist_bulk, subsys) 42 REAL(kind=dp), DIMENSION(3), INTENT(out) :: origin, direction_vector, origin_bias, & 43 direction_vector_bias 44 INTEGER, DIMENSION(:), INTENT(in) :: atomlist_screening, atomlist_bulk 45 TYPE(qs_subsys_type), POINTER :: subsys 46 47 CHARACTER(LEN=*), PARAMETER :: routineN = 'contact_direction_vector', & 48 routineP = moduleN//':'//routineN 49 50 INTEGER :: handle, iatom, natoms_bulk, & 51 natoms_screening, nparticles 52 REAL(kind=dp) :: proj, proj_max, proj_min, proj_min_bias 53 REAL(kind=dp), DIMENSION(3) :: vector 54 TYPE(particle_type), DIMENSION(:), POINTER :: particle_set 55 56 CALL timeset(routineN, handle) 57 CALL qs_subsys_get(subsys, particle_set=particle_set) 58 59 natoms_screening = SIZE(atomlist_screening) 60 natoms_bulk = SIZE(atomlist_bulk) 61 nparticles = SIZE(particle_set) 62 63 CPASSERT(natoms_screening > 0) 64 CPASSERT(natoms_bulk > 0) 65 CPASSERT(nparticles > 0) 66 67 ! geometrical centre of the first contact unit cell 68 origin = particle_set(atomlist_screening(1))%r 69 DO iatom = 2, natoms_screening 70 origin = origin + particle_set(atomlist_screening(iatom))%r 71 END DO 72 origin = origin/REAL(natoms_screening, kind=dp) 73 74 ! geometrical centre of the second contact unit cell 75 direction_vector = particle_set(atomlist_bulk(1))%r 76 DO iatom = 2, natoms_bulk 77 direction_vector = direction_vector + particle_set(atomlist_bulk(iatom))%r 78 END DO 79 direction_vector = direction_vector/REAL(natoms_bulk, kind=dp) 80 81 ! vector between the geometrical centers of the first and the second contact unit cells 82 direction_vector = direction_vector - origin 83 84 ! the point 'center_of_coords0' belongs to the first unit cell, so the lowest projection of any point 85 ! from the first unit cell on the direction vector 'center_of_coords1 - center_of_coords0' should be <= 0 86 proj_min = 0.0_dp 87 proj_min_bias = 0.0_dp 88 DO iatom = 1, natoms_screening 89 vector = particle_set(atomlist_screening(iatom))%r - origin 90 proj = projection_on_direction_vector(vector, direction_vector) 91 92 IF (proj < proj_min) proj_min = proj 93 IF (proj > proj_min_bias) proj_min_bias = proj 94 END DO 95 96 ! the point 'center_of_coords1' belongs to the given contact, so the highest projection should be >= 1 97 proj_max = 1.0_dp 98 DO iatom = 1, nparticles 99 vector = particle_set(iatom)%r - origin 100 proj = projection_on_direction_vector(vector, direction_vector) 101 102 IF (proj > proj_max) proj_max = proj 103 END DO 104 105 ! adjust the origin, so it lies on a plane between the given contact and the scattering region 106 origin_bias = origin + proj_min_bias*direction_vector 107 origin = origin + proj_min*direction_vector 108 109 ! rescale the vector, so the last atom of the given contact and the point 'origin + direction_vector' lie on 110 ! the same plane parallel to the 'origin' plane -- which separates the contact from the scattering region. 111 direction_vector_bias = (proj_max - proj_min_bias)*direction_vector 112 direction_vector = (proj_max - proj_min)*direction_vector 113 114 CALL timestop(handle) 115 END SUBROUTINE contact_direction_vector 116 117! ************************************************************************************************** 118!> \brief project the 'vector' onto the direction 'vector0'. Both vectors should have the same origin. 119!> \param vector vector to project 120!> \param vector0 direction vector 121!> \return projection (in terms of the direction vector's length) 122!> \author Sergey Chulkov 123!> \note \parblock 124!> & vector 125!> / 126!> / 127!> / 128!> *---|------> vector0 129!> l = proj * | vector0 | 130!>\endparblock 131! ************************************************************************************************** 132 PURE FUNCTION projection_on_direction_vector(vector, vector0) RESULT(proj) 133 REAL(kind=dp), DIMENSION(3), INTENT(in) :: vector, vector0 134 REAL(kind=dp) :: proj 135 136 REAL(kind=dp) :: len2, len2_v0, len2_v1 137 REAL(kind=dp), DIMENSION(3) :: vector1 138 139 vector1 = vector - vector0 140 len2 = DOT_PRODUCT(vector, vector) 141 len2_v0 = DOT_PRODUCT(vector0, vector0) 142 len2_v1 = DOT_PRODUCT(vector1, vector1) 143 144 proj = 0.5_dp*((len2 - len2_v1)/len2_v0 + 1.0_dp) 145 END FUNCTION projection_on_direction_vector 146END MODULE negf_vectors 147