1! 2! Copyright (C) 1996-2016 The SIESTA group 3! This file is distributed under the terms of the 4! GNU General Public License: see COPYING in the top directory 5! or http://www.gnu.org/copyleft/gpl.txt. 6! See Docs/Contributors.txt for a list of contributors. 7! 8! This code segment has been fully created by: 9! Nick Papior Andersen, 2013, nickpapior@gmail.com 10! Please conctact the author, prior to re-using this code. 11! 12 13! This module contains the geometrical object: 14! PLANE 15 16module m_geom_plane 17 18 use m_geom_aux 19 20 implicit none 21 22 private 23 24 ! Types 25 public :: geo_plane_delta 26 public :: geo_plane_gauss 27 public :: geo_plane_exp 28 ! Interfaces 29 public :: fgeo_read_plane 30 public :: correct_plane 31 public :: voxel_in_plane 32 public :: voxel_val_plane 33 34 ! Explicit routines 35 public :: fgeo_read_plane_delta 36 public :: fgeo_read_plane_gauss 37 public :: fgeo_read_plane_exp 38 public :: correct_plane_delta 39 public :: correct_plane_gauss 40 public :: correct_plane_exp 41 public :: voxel_in_plane_delta 42 public :: voxel_in_plane_gauss 43 public :: voxel_in_plane_exp 44 public :: voxel_val_plane_delta 45 public :: voxel_val_plane_gauss 46 public :: voxel_val_plane_exp 47 48 type geo_plane_delta 49 ! Describing an infinite plane which will satisfy the following: 50 ! n \dot ( x1 - c ) = 0 51 ! where x1 is any coordinate (x,y,z) 52 sequence 53 ! The coordinate from which the normal vector 54 ! is draw... 55 real(dp) :: c(3) 56 ! The NORMALIZED normal vector to the plane in point 'c'. 57 real(dp) :: n(3) 58 ! Auxillary distance length which is merely '- n dot c' 59 ! This will ease the computations as it is used extensively 60 real(dp) :: d = 0._dp 61 end type geo_plane_delta 62 63 type geo_plane_gauss 64 sequence 65 ! The gauss tail of the plane 66 ! This is: 1/(2*\sigma^2) 67 real(dp) :: inv_2var 68 ! The cutoff-radii of the Gaussian function 69 real(dp) :: cut_off 70 71 real(dp) :: c(3) 72 real(dp) :: n(3) 73 real(dp) :: d_A = 0._dp ! d_Above 74 real(dp) :: d_B = 0._dp ! d_Below 75 end type geo_plane_gauss 76 77 type geo_plane_exp 78 sequence 79 ! The gauss tail of the plane 80 ! This is: h^{-1} = + r_{1/2} / log(2.) 81 real(dp) :: h 82 ! The cutoff-radii of the exponential function 83 real(dp) :: cut_off 84 85 real(dp) :: c(3) 86 real(dp) :: n(3) 87 real(dp) :: d_A = 0._dp ! d_Above 88 real(dp) :: d_B = 0._dp ! d_Below 89 end type geo_plane_exp 90 91 interface fgeo_read_plane 92 module procedure fgeo_read_plane_delta 93 module procedure fgeo_read_plane_gauss 94 module procedure fgeo_read_plane_exp 95 end interface 96 97 interface correct_plane 98 module procedure correct_plane_delta 99 module procedure correct_plane_gauss 100 module procedure correct_plane_exp 101 end interface 102 103 interface voxel_in_plane 104 module procedure voxel_in_plane_delta 105 module procedure voxel_in_plane_gauss 106 module procedure voxel_in_plane_exp 107 end interface 108 109 interface voxel_val_plane 110 module procedure voxel_val_plane_delta 111 module procedure voxel_val_plane_gauss 112 module procedure voxel_val_plane_exp 113 end interface 114 115contains 116 117 ! This subroutine returns .true. in has if the box spanned in 118 ! lr,lr+dx,lr+dx+dy,..., has any points inside the plane. 119 ! - lr is the "lower-left" of the box. 120 ! - d is the extension of the box 121 122 ! TODO, for now this can only handle Cartesian boxes, it should be 123 ! extended to be used in skewed axes.... 124 ! TODO this should be easy if we project the normal vector into 125 ! the cell coordinates (i.e. do nb = (n dot bx, n dot by, n dot bz) 126 127 128 function voxel_in_plane_delta(plane,ll,d) result(has) 129 type(geo_plane_delta), intent(in) :: plane 130 real(dp), intent(in) :: ll(3), d(3) 131 logical :: has 132 ! The positive and negative vertices 133 real(dp) :: p(3), n(3) 134 135 ! We will use the (n,p)-vertex check 136 ! We select 2 vertices which are those farthest (n=negative) 137 ! and furthest (p=positiv) in the direction of the normal 138 ! vector describing the plane. 139 140 call voxel_pos_neg(ll,d,plane%n,p,n) 141 142 has = .false. 143 ! We can then consider whether the vertices lie both outside 144 ! if not, we have an intersection. 145 146 ! The positive vertex lies on the left side of the plane, 147 ! hence we know that it will not be crossing the plane 148 if ( plane%n(1)*p(1)+plane%n(2)*p(2)+plane%n(3)*p(3) < plane%d ) return 149 150 if ( plane%n(1)*n(1)+plane%n(2)*n(2)+plane%n(3)*n(3) <= plane%d ) then 151 ! The positive vertex lies on the right side of the plane, 152 ! This check ensures that the negative vertex lies on the left side 153 ! of the plane. Hence we have an intersection. 154 has = .true. 155 end if 156 157 end function voxel_in_plane_delta 158 159 function voxel_in_plane_gauss(plane,ll,d) result(has) 160 type(geo_plane_gauss), intent(in) :: plane 161 real(dp), intent(in) :: ll(3), d(3) 162 logical :: has 163 real(dp) :: p(3), n(3) 164 165 call voxel_pos_neg(ll,d,plane%n,p,n) 166 167 has = .false. 168 if ( plane%n(1)*p(1)+plane%n(2)*p(2)+plane%n(3)*p(3) < plane%d_B ) return 169 if ( plane%n(1)*n(1)+plane%n(2)*n(2)+plane%n(3)*n(3) <= plane%d_A ) then 170 has = .true. 171 end if 172 173 end function voxel_in_plane_gauss 174 175 function voxel_in_plane_exp(plane,ll,d) result(has) 176 type(geo_plane_exp), intent(in) :: plane 177 real(dp), intent(in) :: ll(3), d(3) 178 logical :: has 179 real(dp) :: p(3), n(3) 180 181 call voxel_pos_neg(ll,d,plane%n,p,n) 182 183 has = .false. 184 if ( plane%n(1)*p(1)+plane%n(2)*p(2)+plane%n(3)*p(3) < plane%d_B ) return 185 if ( plane%n(1)*n(1)+plane%n(2)*n(2)+plane%n(3)*n(3) <= plane%d_A ) then 186 has = .true. 187 end if 188 189 end function voxel_in_plane_exp 190 191 192 ! This subroutine returns the value of the charge 193 ! that is attributed from the exponential function 194 ! - ll is the "lower-left" of the box. 195 ! - d is the extension of the box 196 function voxel_val_plane_gauss(plane,ll,d) result(vol) 197 type(geo_plane_gauss), intent(in) :: plane 198 real(dp), intent(in) :: ll(3), d(3) 199 real(dp) :: c(3) 200 real(dp) :: vol 201 real(dp) :: radii 202 203 ! find the center of box 204 c = ll + d * 0.5_dp 205 206 radii = plane%n(1)*c(1)+plane%n(2)*c(2)+plane%n(3)*c(3) - & 207 (plane%d_B + plane%cut_off) 208 if ( abs(radii) <= plane%cut_off ) then 209 vol = dexp(-radii**2*plane%inv_2var) 210 else 211 vol = 0._dp 212 end if 213 214 end function voxel_val_plane_gauss 215 216 function voxel_val_plane_exp(plane,ll,d) result(vol) 217 type(geo_plane_exp), intent(in) :: plane 218 real(dp), intent(in) :: ll(3), d(3) 219 real(dp) :: c(3) 220 real(dp) :: vol 221 real(dp) :: radii 222 223 ! find the center of box 224 c = ll + d * 0.5_dp 225 226 radii = abs(plane%n(1)*c(1)+plane%n(2)*c(2)+plane%n(3)*c(3) - & 227 (plane%d_B + plane%cut_off)) 228 if ( radii <= plane%cut_off ) then 229 vol = dexp(-radii*plane%h) 230 else 231 vol = 0._dp 232 end if 233 234 end function voxel_val_plane_exp 235 236 function voxel_val_plane_delta(plane,ll,d) result(vol) 237 type(geo_plane_delta), intent(in) :: plane 238 real(dp), intent(in) :: ll(3), d(3) 239 real(dp) :: vol 240 vol = 1._dp 241 end function voxel_val_plane_delta 242 243 ! Returns the positive and negative corner of the voxel 244 pure subroutine voxel_pos_neg(ll,d,e,p,n) 245 real(dp), intent(in) :: ll(3), d(3), e(3) 246 real(dp), intent(out) :: p(3), n(3) 247 integer :: i 248 249 do i = 1 , 3 250 if ( e(i) >= 0._dp ) then 251 ! The normal-vector points in the i'th-direction 252 p(i) = ll(i) + d(i) 253 254 ! hence the negative vertex is the minimum coordinate 255 n(i) = ll(i) 256 else 257 ! The normal-vector points in the negative i'th-direction 258 p(i) = ll(i) 259 260 ! hence the negative index lies in the positive i'th-direction 261 n(i) = ll(i) + d(i) 262 end if 263 end do 264 265 end subroutine voxel_pos_neg 266 267 ! Subroutine for initializing the planes by transforming them 268 ! to the corresponding cell 269 subroutine correct_plane_delta(cell,plane) 270 use intrinsic_missing, only : VNORM 271 real(dp), intent(in) :: cell(3,3) 272 type(geo_plane_delta), intent(inout) :: plane 273 real(dp) :: tmp(3) 274 real(dp) :: ncell(3) 275 integer :: i 276 277 ! Normalize the vector 278 plane%n = plane%n / VNORM(plane%n) 279 280 ! Correct the direction of the normal-vector to 281 ! be that of the cell-direction 282 do i = 1 , 3 283 ncell = cell(:,i) / VNORM(cell(:,i)) 284 tmp(i) = & 285 plane%n(1)*ncell(1) + & 286 plane%n(2)*ncell(2) + & 287 plane%n(3)*ncell(3) 288 end do 289 ! Copy the new normal vector in units of the cell-direction 290 plane%n = tmp / VNORM(tmp) 291 292 ! Calculate the auxillary distance 293 plane%d = plane%n(1)*plane%c(1) & 294 + plane%n(2)*plane%c(2) & 295 + plane%n(3)*plane%c(3) 296 297 end subroutine correct_plane_delta 298 299 subroutine correct_plane_gauss(cell,plane) 300 real(dp), intent(in) :: cell(3,3) 301 type(geo_plane_gauss), intent(inout) :: plane 302 type(geo_plane_delta) :: t_plane 303 304 t_plane%n = plane%n 305 t_plane%c = plane%c 306 call correct_plane_delta(cell,t_plane) 307 plane%n = t_plane%n 308 plane%d_A = t_plane%d + plane%cut_off 309 plane%d_B = t_plane%d - plane%cut_off 310 311 end subroutine correct_plane_gauss 312 313 subroutine correct_plane_exp(cell,plane) 314 real(dp), intent(in) :: cell(3,3) 315 type(geo_plane_exp), intent(inout) :: plane 316 type(geo_plane_delta) :: t_plane 317 318 t_plane%n = plane%n 319 t_plane%c = plane%c 320 call correct_plane_delta(cell,t_plane) 321 plane%n = t_plane%n 322 plane%d_A = t_plane%d + plane%cut_off 323 plane%d_B = t_plane%d - plane%cut_off 324 325 end subroutine correct_plane_exp 326 327 328 subroutine fgeo_read_plane_delta(bName, ngeom,geom,params,par_unit) 329 330 use intrinsic_missing, only : VNORM 331 use fdf 332 333! ******************** 334! * INPUT variables * 335! ******************** 336 character(len=*), intent(in) :: bName 337 integer, intent(in) :: ngeom 338 character(len=*), intent(in), optional :: par_unit 339 340! ******************** 341! * OUTPUT variables * 342! ******************** 343 type(geo_plane_delta), intent(out) :: geom(ngeom) 344 real(dp), intent(out) :: params(ngeom) 345 346! ******************** 347! * LOCAL variables * 348! ******************** 349 type(block_fdf) :: bfdf 350 type(parsed_line), pointer :: pline 351 integer :: t, ip 352 real(dp) :: v 353 354 ! if none found, simply return 355 if ( ngeom <= 0 ) return 356 357 ! Count the number of planes 358 call fgeo_count(bName,GEOM_PLANE_DELTA,t) 359 360 if ( t /= ngeom ) & 361 call die('Could not find any delta planes') 362 363 ! Do the processing 364 if ( .not. fdf_block(bName,bfdf) ) & 365 call die('Could not find the block again...?') 366 367 ip = 0 368 count_geom: do while ( ip < ngeom ) 369 370 ! First loop until we have the geometry 371 call fgeo_next(bfdf,t,v,unit=par_unit) 372 373 ! If it is not the correct geometry, cycle... 374 if ( t /= GEOM_PLANE_DELTA ) cycle 375 376 ! Counter for geometry 377 ip = ip + 1 378 379 ! The parameter for the geometry 380 params(ip) = v 381 382 ! Step delta 383 if ( .not. fdf_bline(bfdf,pline) ) & 384 call die('Could not step the delta mark') 385 386 ! An infinite plane is defined by any point in the plane 387 if ( .not. fdf_bline(bfdf,pline) ) & 388 call die('Could not read the point for the & 389 &infinite plane of a plane geometry object') 390 call fgeo_read_vals(pline,geom(ip)%c,units=.true.) 391 392 ! A plane is defined by the normal vector 393 if ( .not. fdf_bline(bfdf,pline) ) & 394 call die('Could not read the first vector & 395 &of a plane geometry object') 396 call fgeo_read_vals(pline,geom(ip)%n,units=.false.) 397 398 end do count_geom 399 400 end subroutine fgeo_read_plane_delta 401 402 403 subroutine fgeo_read_plane_gauss(bName, ngeom,geom,params,par_unit) 404 405 use intrinsic_missing, only : VNORM 406 use fdf 407 408! ******************** 409! * INPUT variables * 410! ******************** 411 character(len=*), intent(in) :: bName 412 character(len=*), intent(in), optional :: par_unit 413 414! ******************** 415! * OUTPUT variables * 416! ******************** 417 integer, intent(in) :: ngeom 418 type(geo_plane_gauss), intent(out) :: geom(ngeom) 419 real(dp), intent(out) :: params(ngeom) 420 421! ******************** 422! * LOCAL variables * 423! ******************** 424 type(block_fdf) :: bfdf 425 type(parsed_line), pointer :: pline 426 integer :: t, ip 427 real(dp) :: v 428 429 ! if none found, simply return 430 if ( ngeom <= 0 ) return 431 432 ! Count the number of planes 433 call fgeo_count(bName,GEOM_PLANE_GAUSS,t) 434 435 if ( t /= ngeom ) & 436 call die('Could not find any Gaussian planes') 437 438 ! Do the processing 439 if ( .not. fdf_block(bName,bfdf) ) & 440 call die('Could not find the block again...?') 441 442 ip = 0 443 count_geom: do while ( ip < ngeom ) 444 445 ! First loop until we have the geometry 446 call fgeo_next(bfdf,t,v,unit=par_unit) 447 448 ! If it is not the correct geometry, cycle... 449 if ( t /= GEOM_PLANE_GAUSS ) cycle 450 451 ! Counter for geometry 452 ip = ip + 1 453 454 ! The parameter for the geometry 455 params(ip) = v 456 457 ! Step to gauss 458 if ( .not. fdf_bline(bfdf,pline) ) & 459 call die('Could not step the gauss mark') 460 461 ! We need to read in the \sigma and cut_off 462 call fgeo_read_vals(pline,geom(ip)%c(1:2),units=.true.,unit_offset=1) 463 v = geom(ip)%c(1) 464 geom(ip)%inv_2var = 1._dp/(2._dp*v**2) 465 geom(ip)%cut_off = geom(ip)%c(2) 466 467 ! An infinite plane is defined by any point in the plane 468 if ( .not. fdf_bline(bfdf,pline) ) & 469 call die('Could not read the point for the & 470 &infinite plane of a plane geometry object') 471 call fgeo_read_vals(pline,geom(ip)%c,units=.true.) 472 473 ! A plane is defined by the normal vector 474 if ( .not. fdf_bline(bfdf,pline) ) & 475 call die('Could not read the first vector & 476 &of a plane geometry object') 477 call fgeo_read_vals(pline,geom(ip)%n,units=.false.) 478 479 end do count_geom 480 481 end subroutine fgeo_read_plane_gauss 482 483 subroutine fgeo_read_plane_exp(bName, ngeom,geom,params,par_unit) 484 485 use intrinsic_missing, only : VNORM 486 use fdf 487 488! ******************** 489! * INPUT variables * 490! ******************** 491 character(len=*), intent(in) :: bName 492 character(len=*), intent(in), optional :: par_unit 493 494! ******************** 495! * OUTPUT variables * 496! ******************** 497 integer, intent(in) :: ngeom 498 type(geo_plane_exp), intent(out) :: geom(ngeom) 499 real(dp), intent(out) :: params(ngeom) 500 501! ******************** 502! * LOCAL variables * 503! ******************** 504 type(block_fdf) :: bfdf 505 type(parsed_line), pointer :: pline 506 integer :: t, ip 507 real(dp) :: v 508 509 ! if none found, simply return 510 if ( ngeom <= 0 ) return 511 512 ! Count the number of planes 513 call fgeo_count(bName,GEOM_PLANE_EXP,t) 514 515 if ( t /= ngeom ) & 516 call die('Could not find any Exponential planes') 517 518 ! Do the processing 519 if ( .not. fdf_block(bName,bfdf) ) & 520 call die('Could not find the block again...?') 521 522 ip = 0 523 count_geom: do while ( ip < ngeom ) 524 525 ! First loop until we have the geometry 526 call fgeo_next(bfdf,t,v,unit=par_unit) 527 528 ! If it is not the correct geometry, cycle... 529 if ( t /= GEOM_PLANE_EXP ) cycle 530 531 ! Counter for geometry 532 ip = ip + 1 533 534 ! The parameter for the geometry 535 params(ip) = v 536 537 ! Step to gauss 538 if ( .not. fdf_bline(bfdf,pline) ) & 539 call die('Could not step the gauss mark') 540 541 ! Calculate the exponential decay length 542 ! this ensures that exp(-r/h) == .5 for r == half-length 543 ! Note, we save the inverse as that is faster for computation 544 call fgeo_read_vals(pline,geom(ip)%c(1:2),units=.true.,unit_offset=1) 545 v = geom(ip)%c(1) 546 geom(ip)%h = log(2._dp) / v 547 v = geom(ip)%c(2) 548 geom(ip)%cut_off = v 549 550 ! An infinite plane is defined by any point in the plane 551 if ( .not. fdf_bline(bfdf,pline) ) & 552 call die('Could not read the point for the & 553 &infinite plane of a plane geometry object') 554 call fgeo_read_vals(pline,geom(ip)%c,units=.true.) 555 556 ! A plane is defined by the normal vector 557 if ( .not. fdf_bline(bfdf,pline) ) & 558 call die('Could not read the first vector & 559 &of a plane geometry object') 560 call fgeo_read_vals(pline,geom(ip)%n,units=.false.) 561 562 end do count_geom 563 564 end subroutine fgeo_read_plane_exp 565 566end module m_geom_plane 567