! ! Copyright (C) 2002-2005 Quantum ESPRESSO group ! This file is distributed under the terms of the ! GNU General Public License. See the file `License' ! in the root directory of the present distribution, ! or http://www.gnu.org/copyleft/gpl.txt . ! #define __REMOVE_CONSTRAINT_FORCE !#define __DEBUG_CONSTRAINTS #define __USE_PBC ! !---------------------------------------------------------------------------- MODULE constraints_module !---------------------------------------------------------------------------- ! ! ... variables and methods for constraint Molecular Dynamics and ! ... constrained ionic relaxations (the SHAKE algorithm based on ! ... lagrange multipliers) are defined here. ! ! ... most of these variables and methods are also used for meta-dynamics ! ... and free-energy smd : indeed the collective variables are implemented ! ... as constraints. ! ! ... written by Carlo Sbraccia ( 24/02/2004 ) ! ! ... references : ! ! ... 1) M. P. Allen and D. J. Tildesley, Computer Simulations of Liquids, ! ... Clarendon Press - Oxford (1986) ! USE kinds, ONLY : DP USE constants, ONLY : eps32, tpi, fpi USE io_global, ONLY : stdout ! USE basic_algebra_routines ! IMPLICIT NONE ! SAVE ! PRIVATE ! ! ... public methods ! PUBLIC :: init_constraint, & check_constraint, & remove_constr_force, & remove_constr_vec, & deallocate_constraint, & compute_dmax, & pbc, & constraint_grad ! ! ! ... public variables (assigned in the CONSTRAINTS input card) ! PUBLIC :: nconstr, & constr_tol, & constr_type, & constr, & lagrange, & constr_target, & dmax, & gp ! ! ... global variables ! INTEGER :: nconstr=0 REAL(DP) :: constr_tol INTEGER, ALLOCATABLE :: constr_type(:) REAL(DP), ALLOCATABLE :: constr(:,:) REAL(DP), ALLOCATABLE :: constr_target(:) REAL(DP), ALLOCATABLE :: lagrange(:) REAL(DP), ALLOCATABLE :: gp(:) REAL(DP) :: dmax ! CONTAINS ! ! ... public methods ! !----------------------------------------------------------------------- SUBROUTINE init_constraint( nat, tau, ityp, tau_units ) !----------------------------------------------------------------------- ! ! ... this routine is used to initialize constraints variables and ! ... collective variables (notice that collective variables are ! ... implemented as normal constraints but are read using specific ! ... input variables) ! USE input_parameters, ONLY : nconstr_inp, constr_tol_inp, & constr_type_inp, constr_inp, & constr_target_inp, & constr_target_set, nc_fields ! IMPLICIT NONE ! INTEGER, INTENT(in) :: nat REAL(DP), INTENT(in) :: tau(3,nat) INTEGER, INTENT(in) :: ityp(nat) REAL(DP), INTENT(in) :: tau_units ! INTEGER :: i, j INTEGER :: ia, ia0, ia1, ia2, ia3, n_type_coord1 REAL(DP) :: d0(3), d1(3), d2(3) REAL(DP) :: smoothing, r_c INTEGER :: type_coord1, type_coord2 REAL(DP) :: dtau(3), norm_dtau REAL(DP) :: k(3), phase, norm_k COMPLEX(DP) :: struc_fac CHARACTER(20),ALLOCATABLE :: tmp_type_inp(:) LOGICAL,ALLOCATABLE :: tmp_target_set(:) REAL(DP),ALLOCATABLE :: tmp_target_inp(:) ! CHARACTER(len=6), EXTERNAL :: int_to_char ! ! nconstr = nconstr_inp constr_tol = constr_tol_inp WRITE(stdout,'(5x,a,i4,a,f12.6)') & 'Setting up ',nconstr,' constraints; tolerance:', constr_tol ! ALLOCATE( lagrange( nconstr ) ) ALLOCATE( constr_target( nconstr ) ) ALLOCATE( constr_type( nconstr ) ) ! ALLOCATE( constr( nc_fields, nconstr ) ) ALLOCATE( gp( nconstr ) ) ALLOCATE( tmp_type_inp(nconstr),tmp_target_set(nconstr),tmp_target_inp(nconstr) ) ! ! ... setting constr to 0 to findout which elements have been ! ... set to an atomic index. This is required for CP. ! constr(:,:) = 0.0_DP ! constr(:,1:nconstr) = constr_inp(:,1:nconstr_inp) tmp_type_inp(1:nconstr) = constr_type_inp(1:nconstr_inp) tmp_target_set(1:nconstr) = constr_target_set(1:nconstr_inp) tmp_target_inp(1:nconstr) = constr_target_inp(1:nconstr_inp) ! ! ... set the largest possible distance among two atoms within ! ... the supercell ! IF ( any( tmp_type_inp(:) == 'distance' ) ) CALL compute_dmax() ! ! ... initializations of constr_target values for the constraints : ! DO ia = 1, nconstr ! SELECT CASE ( tmp_type_inp(ia) ) CASE( 'type_coord' ) ! ! ... constraint on global coordination-number, i.e. the average ! ... number of atoms of type B surrounding the atoms of type A ! constr_type(ia) = 1 IF ( tmp_target_set(ia) ) THEN constr_target(ia) = tmp_target_inp(ia) ELSE CALL set_type_coord( ia ) ENDIF ! WRITE(stdout,'(7x,i3,a,i3,a,i2,a,2f12.6,a,f12.6)') & ia,') type #',int(constr_inp(1,ia)) ,' coordination wrt type:', int(constr(2,ia)), & ' cutoff distance and smoothing:', constr(3:4,ia), & '; target:', constr_target(ia) ! CASE( 'atom_coord' ) ! ! ... constraint on local coordination-number, i.e. the average ! ... number of atoms of type A surrounding a specific atom ! constr_type(ia) = 2 IF ( tmp_target_set(ia) ) THEN constr_target(ia) = tmp_target_inp(ia) ELSE CALL set_atom_coord( ia ) ENDIF ! WRITE(stdout,'(7x,i3,a,i3,a,i2,a,2f12.6,a,f12.6)') & ia,') atom #',int(constr_inp(1,ia)) ,' coordination wrt type:', int(constr(2,ia)), & ' cutoff distance and smoothing:', constr(3:4,ia), & '; target:', constr_target(ia) ! CASE( 'distance' ) ! constr_type(ia) = 3 IF ( tmp_target_set(ia) ) THEN constr_target(ia) = tmp_target_inp(ia) ELSE CALL set_distance( ia ) ENDIF ! IF ( constr_target(ia) > dmax ) THEN ! WRITE( stdout, '(/,5X,"target = ",F12.8,/, & & 5X,"dmax = ",F12.8)' ) & constr_target(ia), dmax CALL errore( 'init_constraint', 'the target for constraint ' //& & trim( int_to_char( ia ) ) // ' is larger than ' //& & 'the largest possible value', 1 ) ! ENDIF ! WRITE(stdout,'(7x,i3,a,2i3,a,f12.6)') & ia,') distance between atoms: ', int(constr(1:2,ia)), '; target:', constr_target(ia) ! CASE( 'planar_angle' ) ! ! ... constraint on planar angle (for the notation used here see ! ... Appendix C of the Allen-Tildesley book) ! constr_type(ia) = 4 IF ( tmp_target_set(ia) ) THEN ! ! ... the input value of target for the torsional angle (given ! ... in degrees) is converted to the cosine of the angle ! constr_target(ia) = tmp_target_inp(ia) ELSE CALL set_planar_angle( ia ) ENDIF ! WRITE(stdout, '(7x,i3,a,3i3,a,f12.6)') & ia,') planar angle between atoms: ', int(constr(1:3,ia)), '; target:', constr_target(ia) ! CASE( 'torsional_angle' ) ! ! ... constraint on torsional angle (for the notation used here ! ... see Appendix C of the Allen-Tildesley book) ! constr_type(ia) = 5 IF ( tmp_target_set(ia) ) THEN ! ! ... the input value of target for the torsional angle (given ! ... in degrees) is converted to the cosine of the angle ! constr_target(ia) = tmp_target_inp(ia) ELSE CALL set_torsional_angle( ia ) ENDIF ! WRITE(stdout, '(7x,i3,a,4i3,a,f12.6)') & ia,') torsional angle between atoms: ', int(constr(1:4,ia)), '; target:', constr_target(ia) ! CASE( 'struct_fac' ) ! ! ... constraint on structure factor at a given k-vector ! constr_type(ia) = 6 IF ( tmp_target_set(ia) ) THEN constr_target(ia) = tmp_target_inp(ia) ELSE CALL set_structure_factor( ia ) ENDIF ! CASE( 'sph_struct_fac' ) ! ! ... constraint on spherical average of the structure factor for ! ... a given k-vector of norm k ! constr_type(ia) = 7 IF ( tmp_target_set(ia) ) THEN constr_target(ia) = tmp_target_inp(ia) ELSE CALL set_sph_structure_factor( ia ) ENDIF ! CASE( 'bennett_proj' ) ! ! ... constraint on the projection onto a given direction of the ! ... vector defined by the position of one atom minus the center ! ... of mass of the others ! ... ( Ch.H. Bennett in Diffusion in Solids, Recent Developments, ! ... Ed. by A.S. Nowick and J.J. Burton, New York 1975 ) ! constr_type(ia) = 8 IF ( tmp_target_set(ia) ) THEN constr_target(ia) = tmp_target_inp(ia) ELSE CALL set_bennett_proj( ia ) ENDIF ! CASE DEFAULT ! CALL errore( 'init_constraint', & 'collective-variable or constrait type not implemented', 1 ) ! END SELECT ! ENDDO ! DEALLOCATE( tmp_type_inp,tmp_target_set,tmp_target_inp ) ! RETURN ! CONTAINS ! !------------------------------------------------------------------- SUBROUTINE set_type_coord( ia ) !------------------------------------------------------------------- ! INTEGER, INTENT(in) :: ia ! type_coord1 = anint( constr(1,ia) ) type_coord2 = anint( constr(2,ia) ) ! r_c = constr(3,ia) ! smoothing = 1.0_DP / constr(4,ia) ! constr_target(ia) = 0.0_DP ! n_type_coord1 = 0 ! DO ia1 = 1, nat ! IF ( ityp(ia1) /= type_coord1 ) CYCLE ! DO ia2 = 1, nat ! IF ( ia2 == ia1 ) CYCLE ! IF ( ityp(ia2) /= type_coord2 ) CYCLE ! dtau(:) = pbc( ( tau(:,ia1) - tau(:,ia2) )*tau_units ) ! norm_dtau = norm( dtau(:) ) ! constr_target(ia) = constr_target(ia) + 1.0_DP / & ( exp( smoothing*( norm_dtau - r_c ) ) + 1.0_DP ) ! ENDDO ! n_type_coord1 = n_type_coord1 + 1 ! ENDDO ! constr_target(ia) = constr_target(ia) / dble( n_type_coord1 ) ! END SUBROUTINE set_type_coord ! !------------------------------------------------------------------- SUBROUTINE set_atom_coord( ia ) !------------------------------------------------------------------- ! INTEGER, INTENT(in) :: ia ! ia1 = anint( constr(1,ia) ) type_coord1 = anint( constr(2,ia) ) ! r_c = constr(3,ia) ! smoothing = 1.0_DP / constr(4,ia) ! constr_target(ia) = 0.0_DP ! DO ia2 = 1, nat ! IF ( ia2 == ia1 ) CYCLE ! IF ( ityp(ia2) /= type_coord1 ) CYCLE ! dtau(:) = pbc( ( tau(:,ia1) - tau(:,ia2) )*tau_units ) ! norm_dtau = norm( dtau(:) ) ! constr_target(ia) = constr_target(ia) + 1.0_DP / & ( exp( smoothing*( norm_dtau - r_c ) ) + 1.0_DP ) ! ENDDO ! END SUBROUTINE set_atom_coord ! !------------------------------------------------------------------- SUBROUTINE set_distance( ia ) !------------------------------------------------------------------- ! INTEGER, INTENT(in) :: ia ! ia1 = anint( constr(1,ia) ) ia2 = anint( constr(2,ia) ) ! dtau(:) = pbc( ( tau(:,ia1) - tau(:,ia2) )*tau_units ) ! constr_target(ia) = norm( dtau(:) ) ! END SUBROUTINE set_distance ! !------------------------------------------------------------------- SUBROUTINE set_planar_angle( ia ) !------------------------------------------------------------------- ! INTEGER, INTENT(in) :: ia ! ia0 = anint( constr(1,ia) ) ia1 = anint( constr(2,ia) ) ia2 = anint( constr(3,ia) ) ! d0(:) = pbc( ( tau(:,ia0) - tau(:,ia1) )*tau_units ) d1(:) = pbc( ( tau(:,ia1) - tau(:,ia2) )*tau_units ) ! d0(:) = d0(:) / norm( d0(:) ) d1(:) = d1(:) / norm( d1(:) ) ! constr_target(ia) = acos(- d0(:) .dot. d1(:))*360.0_DP/tpi ! END SUBROUTINE set_planar_angle ! !------------------------------------------------------------------- SUBROUTINE set_torsional_angle( ia ) !------------------------------------------------------------------- ! INTEGER, INTENT(in) :: ia REAL(DP) :: x01(3),x12(3),phi ! ia0 = anint( constr(1,ia) ) ia1 = anint( constr(2,ia) ) ia2 = anint( constr(3,ia) ) ia3 = anint( constr(4,ia) ) ! d0(:) = pbc( ( tau(:,ia0) - tau(:,ia1) )*tau_units ) d1(:) = pbc( ( tau(:,ia1) - tau(:,ia2) )*tau_units ) d2(:) = pbc( ( tau(:,ia2) - tau(:,ia3) )*tau_units ) ! x01(:) = cross(d0,d1) x12(:) = cross(d1,d2) ! IF((x01.dot.x01) ! ! ... in normal cases the constraint equation should be satisfied at ! ... the very first iteration. ! USE ions_base, ONLY : amass ! IMPLICIT NONE ! INTEGER, INTENT(in) :: nat REAL(DP), INTENT(inout) :: taup(3,nat) REAL(DP), INTENT(in) :: tau0(3,nat) INTEGER, INTENT(in) :: if_pos(3,nat) REAL(DP), INTENT(inout) :: force(3,nat) INTEGER, INTENT(in) :: ityp(nat) REAL(DP), INTENT(in) :: tau_units REAL(DP), INTENT(in) :: dt REAL(DP), INTENT(in) :: massconv ! INTEGER :: na, i, idx, dim REAL(DP), ALLOCATABLE :: dgp(:,:), dg0(:,:,:) REAL(DP) :: g0 REAL(DP) :: lambda, fac, invdtsq LOGICAL, ALLOCATABLE :: ltest(:) LOGICAL :: global_test INTEGER, PARAMETER :: maxiter = 100 ! REAL(DP), EXTERNAL :: ddot ! ! ALLOCATE( dgp( 3, nat ) ) ALLOCATE( dg0( 3, nat, nconstr ) ) ! ALLOCATE( ltest( nconstr ) ) ! invdtsq = 1.0_DP / dt**2 ! dim = 3*nat ! DO idx = 1, nconstr ! CALL constraint_grad( idx, nat, tau0, & if_pos, ityp, tau_units, g0, dg0(:,:,idx) ) ! ENDDO ! outer_loop: DO i = 1, maxiter ! inner_loop: DO idx = 1, nconstr ! ltest(idx) = .false. ! CALL constraint_grad( idx, nat, taup, & if_pos, ityp, tau_units, gp(idx), dgp ) ! ! ... check if gp = 0 ! #if defined (__DEBUG_CONSTRAINTS) WRITE( stdout, '(2(2X,I3),F12.8)' ) i, idx, abs( gp(idx) ) #endif ! IF ( abs( gp(idx) ) < constr_tol ) THEN ! ltest(idx) = .true. ! CYCLE inner_loop ! ENDIF ! ! ... if gp <> 0 find new taup and check again ! ... ( gp is in bohr and taup in tau_units ) ! DO na = 1, nat ! dgp(:,na) = dgp(:,na) / ( amass(ityp(na))*massconv ) ! ENDDO ! lambda = gp(idx) / ddot( dim, dgp, 1, dg0(:,:,idx), 1 ) ! DO na = 1, nat ! fac = amass(ityp(na))*massconv*tau_units ! taup(:,na) = taup(:,na) - lambda*dg0(:,na,idx)/fac ! ENDDO ! lagrange(idx) = lagrange(idx) + lambda*invdtsq ! force(:,:) = force(:,:) - lambda*dg0(:,:,idx)*invdtsq ! ENDDO inner_loop ! global_test = all( ltest(:) ) ! ! ... all constraints are satisfied ! IF ( global_test ) exit outer_loop ! ENDDO outer_loop ! IF ( .not. global_test ) THEN ! ! ... error messages ! WRITE( stdout, '(/,5X,"Number of step(s): ",I3)') min( i, maxiter ) WRITE( stdout, '(/,5X,"constr_target convergence: ")' ) ! DO i = 1, nconstr ! WRITE( stdout, '(5X,"constr # ",I3,2X,L1,3(2X,F16.10))' ) & i, ltest(i), abs( gp(i) ), constr_tol, constr_target(i) ! ENDDO ! CALL errore( 'check_constraint', & 'on some constraint g = 0 is not satisfied', 1 ) ! ENDIF ! DEALLOCATE( dgp ) DEALLOCATE( dg0 ) DEALLOCATE( ltest ) ! RETURN ! END SUBROUTINE check_constraint ! !----------------------------------------------------------------------- SUBROUTINE remove_constr_force( nat, tau, & if_pos, ityp, tau_units, force ) !----------------------------------------------------------------------- ! ! ... the component of the force that is orthogonal to the ! ... ipersurface defined by the constraint equations is removed ! ... and the corresponding value of the lagrange multiplier computed ! IMPLICIT NONE ! INTEGER, INTENT(in) :: nat REAL(DP), INTENT(in) :: tau(:,:) INTEGER, INTENT(in) :: if_pos(:,:) INTEGER, INTENT(in) :: ityp(:) REAL(DP), INTENT(in) :: tau_units REAL(DP), INTENT(inout) :: force(:,:) ! INTEGER :: i, j, dim REAL(DP) :: g, ndg, dgidgj REAL(DP) :: norm_before, norm_after REAL(DP), ALLOCATABLE :: dg(:,:,:) REAL(DP), ALLOCATABLE :: dg_matrix(:,:) INTEGER, ALLOCATABLE :: iwork(:) ! REAL(DP), EXTERNAL :: ddot, dnrm2 ! ! dim = 3*nat ! lagrange(:) = 0.0_DP ! #if defined (__REMOVE_CONSTRAINT_FORCE) ! norm_before = dnrm2( 3*nat, force, 1 ) ! ALLOCATE( dg( 3, nat, nconstr ) ) ! IF ( nconstr == 1 ) THEN ! CALL constraint_grad( 1, nat, tau, & if_pos, ityp, tau_units, g, dg(:,:,1) ) ! lagrange(1) = ddot( dim, force, 1, dg(:,:,1), 1 ) ! ndg = ddot( dim, dg(:,:,1), 1, dg(:,:,1), 1 ) ! force(:,:) = force(:,:) - lagrange(1)*dg(:,:,1)/ndg ! ELSE ! ALLOCATE( dg_matrix( nconstr, nconstr ) ) ALLOCATE( iwork( nconstr ) ) ! DO i = 1, nconstr ! CALL constraint_grad( i, nat, tau, & if_pos, ityp, tau_units, g, dg(:,:,i) ) ! ENDDO ! DO i = 1, nconstr ! dg_matrix(i,i) = ddot( dim, dg(:,:,i), 1, dg(:,:,i), 1 ) ! lagrange(i) = ddot( dim, force, 1, dg(:,:,i), 1 ) ! DO j = i + 1, nconstr ! dgidgj = ddot( dim, dg(:,:,i), 1, dg(:,:,j), 1 ) ! dg_matrix(i,j) = dgidgj dg_matrix(j,i) = dgidgj ! ENDDO ! ENDDO ! CALL DGESV( nconstr, 1, dg_matrix, & nconstr, iwork, lagrange, nconstr, i ) ! IF ( i /= 0 ) & CALL errore( 'remove_constr_force', & 'error in the solution of the linear system', i ) ! DO i = 1, nconstr ! force(:,:) = force(:,:) - lagrange(i)*dg(:,:,i) ! ENDDO ! DEALLOCATE( dg_matrix ) DEALLOCATE( iwork ) ! ENDIF ! #if defined (__DEBUG_CONSTRAINTS) ! WRITE( stdout, '(/,5X,"Intermediate forces (Ry/au):",/)') ! DO i = 1, nat ! WRITE( stdout, '(5X,"atom ",I3," type ",I2,3X,"force = ",3F14.8)' ) & i, ityp(i), force(:,i) ! ENDDO ! #endif ! norm_after = dnrm2( dim, force, 1 ) ! IF ( norm_before < norm_after ) THEN ! WRITE( stdout, '(/,5X,"norm before = ",F16.10)' ) norm_before WRITE( stdout, '( 5X,"norm after = ",F16.10)' ) norm_after ! CALL errore( 'remove_constr_force', & 'norm(F) before < norm(F) after', 1 ) ! ENDIF ! DEALLOCATE( dg ) ! #endif ! END SUBROUTINE remove_constr_force ! !----------------------------------------------------------------------- SUBROUTINE remove_constr_vec( nat, tau, & if_pos, ityp, tau_units, vec ) !----------------------------------------------------------------------- ! ! ... the component of a displacement vector that is orthogonal to the ! ... ipersurface defined by the constraint equations is removed ! ... and the corresponding value of the lagrange multiplier computed ! IMPLICIT NONE ! INTEGER, INTENT(in) :: nat REAL(DP), INTENT(in) :: tau(:,:) INTEGER, INTENT(in) :: if_pos(:,:) INTEGER, INTENT(in) :: ityp(:) REAL(DP), INTENT(in) :: tau_units REAL(DP), INTENT(inout) :: vec(:,:) ! INTEGER :: i, j, dim REAL(DP) :: g, ndg, dgidgj REAL(DP), ALLOCATABLE :: dg(:,:,:), dg_matrix(:,:), lambda(:) INTEGER, ALLOCATABLE :: iwork(:) ! REAL(DP), EXTERNAL :: ddot ! ! dim = 3*nat ! ALLOCATE( lambda( nconstr ) ) ALLOCATE( dg( 3, nat, nconstr ) ) ! IF ( nconstr == 1 ) THEN ! CALL constraint_grad( 1, nat, tau, & if_pos, ityp, tau_units, g, dg(:,:,1) ) ! lambda(1) = ddot( dim, vec, 1, dg(:,:,1), 1 ) ! ndg = ddot( dim, dg(:,:,1), 1, dg(:,:,1), 1 ) ! vec(:,:) = vec(:,:) - lambda(1)*dg(:,:,1)/ndg ! ELSE ! ALLOCATE( dg_matrix( nconstr, nconstr ) ) ALLOCATE( iwork( nconstr ) ) ! DO i = 1, nconstr ! CALL constraint_grad( i, nat, tau, & if_pos, ityp, tau_units, g, dg(:,:,i) ) ! ENDDO ! DO i = 1, nconstr ! dg_matrix(i,i) = ddot( dim, dg(:,:,i), 1, dg(:,:,i), 1 ) ! lambda(i) = ddot( dim, vec, 1, dg(:,:,i), 1 ) ! DO j = i + 1, nconstr ! dgidgj = ddot( dim, dg(:,:,i), 1, dg(:,:,j), 1 ) ! dg_matrix(i,j) = dgidgj dg_matrix(j,i) = dgidgj ! ENDDO ! ENDDO ! CALL DGESV( nconstr, 1, dg_matrix, & nconstr, iwork, lambda, nconstr, i ) ! IF ( i /= 0 ) & CALL errore( 'remove_constr_vec', & 'error in the solution of the linear system', i ) ! DO i = 1, nconstr ! vec(:,:) = vec(:,:) - lambda(i)*dg(:,:,i) ! ENDDO ! DEALLOCATE( dg_matrix ) DEALLOCATE( iwork ) ! ENDIF ! DEALLOCATE( lambda, dg ) ! END SUBROUTINE remove_constr_vec ! !----------------------------------------------------------------------- SUBROUTINE deallocate_constraint() !----------------------------------------------------------------------- ! IMPLICIT NONE ! ! IF ( allocated( lagrange ) ) DEALLOCATE( lagrange ) IF ( allocated( constr ) ) DEALLOCATE( constr ) IF ( allocated( constr_type ) ) DEALLOCATE( constr_type ) IF ( allocated( constr_target ) ) DEALLOCATE( constr_target ) IF ( allocated( gp ) ) DEALLOCATE( gp ) ! RETURN ! END SUBROUTINE deallocate_constraint ! !----------------------------------------------------------------------- FUNCTION cross(A,B) !----------------------------------------------------------------------- ! ! ... cross product ! IMPLICIT NONE ! REAL(DP),INTENT(in) :: A(3),B(3) REAL(DP) cross(3) ! cross(1) = A(2)*B(3)-A(3)*B(2) cross(2) = A(3)*B(1)-A(1)*B(3) cross(3) = A(1)*B(2)-A(2)*B(1) ! END FUNCTION ! !----------------------------------------------------------------------- FUNCTION pbc( vect ) !----------------------------------------------------------------------- ! ! ... periodic boundary conditions ( vect is assumed to be given ! ... in cartesian coordinates and in atomic units ) ! USE cell_base, ONLY : at, bg, alat ! IMPLICIT NONE ! REAL(DP), INTENT(in) :: vect(3) REAL(DP) :: pbc(3) ! ! #if defined (__USE_PBC) ! pbc(:) = matmul( vect(:), bg(:,:) )/alat ! pbc(:) = pbc(:) - anint( pbc(:) ) ! pbc(:) = matmul( at(:,:), pbc(:) )*alat ! #else ! pbc(:) = vect(:) ! #endif RETURN ! END FUNCTION pbc ! !----------------------------------------------------------------------- SUBROUTINE compute_dmax() !----------------------------------------------------------------------- ! ! ... dmax corresponds to one half the longest diagonal of the cell ! USE cell_base, ONLY : at, alat ! IMPLICIT NONE ! INTEGER :: x,y,z REAL(DP) :: diago(3) ! dmax = 0._dp !norm(at(:,1)+at(:,2)+at(:,3)) ! DO z = -1,1,2 DO y = -1,1,2 DO x = -1,1,2 diago = x*at(:,1) + y*at(:,2) + z*at(:,3) dmax = max(dmax, norm(diago)) ENDDO ENDDO ENDDO ! dmax= dmax*alat*.5_dp ! RETURN ! END SUBROUTINE compute_dmax ! END MODULE constraints_module