55#include "../base/base_uses.f90"
59 CHARACTER(len=*),
PARAMETER,
PRIVATE :: moduleN =
'ps_implicit_methods'
67 INTERFACE ps_implicit_compute_ehartree
68 MODULE PROCEDURE compute_ehartree_periodic_bc, &
69 compute_ehartree_mixed_bc
70 END INTERFACE ps_implicit_compute_ehartree
72 REAL(dp),
PRIVATE,
PARAMETER :: large_error = 1.0e4_dp
95 CHARACTER(LEN=*),
PARAMETER :: routinen =
'ps_implicit_create'
97 INTEGER :: boundary_condition, handle, j, &
98 n_contacts, neumann_directions
101 CALL timeset(routinen, handle)
105 IF (.NOT.
ASSOCIATED(ps_implicit_env))
THEN
106 ALLOCATE (ps_implicit_env)
108 ps_implicit_env%do_dbc_cube = poisson_params%dbc_params%do_dbc_cube
109 boundary_condition = poisson_params%ps_implicit_params%boundary_condition
110 neumann_directions = poisson_params%ps_implicit_params%neumann_directions
113 NULLIFY (ps_implicit_env%dielectric)
114 SELECT CASE (boundary_condition)
116 CALL dielectric_create(ps_implicit_env%dielectric, pw_pool, poisson_params%dielectric_params)
119 CALL dielectric_create(ps_implicit_env%dielectric, pw_pool_xpndd, poisson_params%dielectric_params)
124 NULLIFY (ps_implicit_env%initial_guess)
127 NULLIFY (ps_implicit_env%v_eps)
128 ALLOCATE (ps_implicit_env%v_eps)
129 CALL pw_pool%create_pw(ps_implicit_env%v_eps)
130 CALL pw_zero(ps_implicit_env%v_eps)
133 NULLIFY (ps_implicit_env%cstr_charge)
134 SELECT CASE (boundary_condition)
136 ALLOCATE (ps_implicit_env%cstr_charge)
137 CALL pw_pool%create_pw(ps_implicit_env%cstr_charge)
138 CALL pw_zero(ps_implicit_env%cstr_charge)
141 ALLOCATE (ps_implicit_env%cstr_charge)
142 CALL pw_pool_xpndd%create_pw(ps_implicit_env%cstr_charge)
143 CALL pw_zero(ps_implicit_env%cstr_charge)
148 ps_implicit_env%ehartree = 0.0_dp
149 ps_implicit_env%electric_enthalpy = 0.0_dp
151 ps_implicit_env%times_called = 0
155 CALL dct_type_init(pw_pool%pw_grid, neumann_directions, ps_implicit_env%dct_env)
160 CALL ps_implicit_prepare_blocks(pw_pool, dct_pw_grid, green, poisson_params, ps_implicit_env)
163 (.NOT. poisson_params%dbc_params%do_dbc_cube))
THEN
164 n_contacts =
SIZE(ps_implicit_env%contacts)
172 CALL timestop(handle)
191 REAL(dp),
INTENT(OUT),
OPTIONAL :: ehartree
193 CHARACTER(LEN=*),
PARAMETER :: routinen =
'implicit_poisson_solver_periodic'
195 INTEGER :: handle, iter, max_iter, outp_unit, &
197 LOGICAL :: reached_max_iter, reached_tol, &
198 use_zero_initial_guess
199 REAL(dp) :: nabs_error, omega, pres_error, tol
207 CALL timeset(routinen, handle)
209 pw_pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
210 dielectric => poisson_env%implicit_env%dielectric
211 green => poisson_env%green_fft
212 ps_implicit_env => poisson_env%implicit_env
214 tol = poisson_env%parameters%ps_implicit_params%tol
215 omega = poisson_env%parameters%ps_implicit_params%omega
216 max_iter = poisson_env%parameters%ps_implicit_params%max_iter
217 use_zero_initial_guess = poisson_env%parameters%ps_implicit_params%zero_initial_guess
218 times_called = ps_implicit_env%times_called
221 IF (times_called == 0)
CALL ps_implicit_initial_guess_create(ps_implicit_env, pw_pool)
223 CALL pw_pool%create_pw(g)
224 CALL pw_pool%create_pw(v_old)
225 CALL pw_pool%create_pw(res_old)
226 CALL pw_pool%create_pw(res_new)
227 CALL pw_pool%create_pw(qainvxres)
228 CALL pw_pool%create_pw(pxqainvxres)
230 IF (use_zero_initial_guess)
THEN
233 CALL pw_copy(ps_implicit_env%initial_guess, v_old)
236 g%array =
fourpi*density%array/dielectric%eps%array
239 CALL apply_poisson_operator_fft(pw_pool, green, dielectric, v_old, res_old)
244 CALL apply_inv_laplace_operator_fft(pw_pool, green, res_old, qainvxres)
256 CALL apply_p_operator(pw_pool, dielectric, qainvxres, pxqainvxres)
257 CALL pw_copy(pxqainvxres, res_new)
259 CALL pw_axpy(res_old, res_new, 1.0_dp - omega)
262 CALL ps_implicit_compute_error_fft(pw_pool, green, res_new, v_old, v_new, qainvxres, &
263 pres_error, nabs_error)
265 CALL ps_implicit_output(iter, pres_error, nabs_error, outp_unit)
266 IF (
PRESENT(ehartree))
THEN
267 CALL ps_implicit_compute_ehartree(density, v_new, ehartree)
268 CALL ps_implicit_report_ehartree(ps_implicit_env, outp_unit, ehartree)
269 ps_implicit_env%ehartree = ehartree
271 IF (outp_unit > 0)
WRITE (outp_unit,
'(A1,/)')
275 reached_max_iter = iter > max_iter
276 reached_tol = pres_error <= tol
277 IF (pres_error > large_error)
THEN
278 cpabort(
"Poisson solver did not converge.")
280 ps_implicit_env%times_called = ps_implicit_env%times_called + 1
281 IF (reached_max_iter .OR. reached_tol)
EXIT
288 CALL ps_implicit_print_convergence_msg(iter, max_iter, outp_unit)
290 IF ((times_called /= 0) .AND. (.NOT. use_zero_initial_guess))
THEN
291 CALL pw_copy(v_new, ps_implicit_env%initial_guess)
294 IF (
PRESENT(ehartree)) ehartree = ps_implicit_env%ehartree
298 v_eps%pw_grid => ps_implicit_env%v_eps%pw_grid
299 v_eps%array => ps_implicit_env%v_eps%array
300 CALL ps_implicit_compute_veps(pw_pool, dielectric, v_new, v_eps)
303 CALL pw_pool%give_back_pw(g)
304 CALL pw_pool%give_back_pw(v_old)
305 CALL pw_pool%give_back_pw(res_old)
306 CALL pw_pool%give_back_pw(res_new)
307 CALL pw_pool%give_back_pw(qainvxres)
308 CALL pw_pool%give_back_pw(pxqainvxres)
310 CALL timestop(handle)
328 TYPE(pw_poisson_type),
INTENT(IN) :: poisson_env
329 TYPE(pw_r3d_rs_type),
INTENT(IN) :: density
330 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: v_new
331 REAL(dp),
INTENT(OUT),
OPTIONAL :: ehartree
333 CHARACTER(LEN=*),
PARAMETER :: routinen =
'implicit_poisson_solver_neumann'
335 INTEGER :: handle, iter, max_iter, &
336 neumann_directions, outp_unit, &
338 LOGICAL :: reached_max_iter, reached_tol, &
339 use_zero_initial_guess
340 REAL(dp) :: nabs_error, omega, pres_error, tol, &
342 TYPE(dct_type),
POINTER :: dct_env
343 TYPE(dielectric_type),
POINTER :: dielectric
344 TYPE(greens_fn_type),
POINTER :: green
345 TYPE(ps_implicit_type),
POINTER :: ps_implicit_env
346 TYPE(pw_pool_type),
POINTER :: pw_pool, pw_pool_xpndd
347 TYPE(pw_r3d_rs_type) :: density_xpndd, g, pxqainvxres, &
348 qainvxres, res_new, res_old, &
349 v_eps_xpndd, v_new_xpndd, v_old
351 CALL timeset(routinen, handle)
353 pw_pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
354 dielectric => poisson_env%implicit_env%dielectric
355 green => poisson_env%green_fft
356 ps_implicit_env => poisson_env%implicit_env
357 dct_env => ps_implicit_env%dct_env
359 tol = poisson_env%parameters%ps_implicit_params%tol
360 omega = poisson_env%parameters%ps_implicit_params%omega
361 max_iter = poisson_env%parameters%ps_implicit_params%max_iter
362 use_zero_initial_guess = poisson_env%parameters%ps_implicit_params%zero_initial_guess
363 neumann_directions = poisson_env%parameters%ps_implicit_params%neumann_directions
364 times_called = ps_implicit_env%times_called
366 SELECT CASE (neumann_directions)
369 CASE (neumannxy, neumannxz, neumannyz)
371 CASE (neumannx, neumanny, neumannz)
375 CALL pw_pool_create(pw_pool_xpndd, pw_grid=poisson_env%dct_pw_grid)
378 IF (times_called == 0)
CALL ps_implicit_initial_guess_create(ps_implicit_env, pw_pool_xpndd)
380 CALL pw_pool_xpndd%create_pw(g)
381 CALL pw_pool_xpndd%create_pw(v_old)
382 CALL pw_pool_xpndd%create_pw(res_old)
383 CALL pw_pool_xpndd%create_pw(res_new)
384 CALL pw_pool_xpndd%create_pw(qainvxres)
385 CALL pw_pool_xpndd%create_pw(pxqainvxres)
386 CALL pw_pool_xpndd%create_pw(density_xpndd)
387 CALL pw_pool_xpndd%create_pw(v_new_xpndd)
388 CALL pw_pool_xpndd%create_pw(v_eps_xpndd)
390 IF (use_zero_initial_guess)
THEN
393 CALL pw_copy(ps_implicit_env%initial_guess, v_old)
396 CALL pw_expand(neumann_directions, &
397 dct_env%recv_msgs_bnds, dct_env%dests_expand, dct_env%srcs_expand, &
398 dct_env%flipg_stat, dct_env%bounds_shftd, density, density_xpndd)
399 CALL pw_expand(neumann_directions, &
400 dct_env%recv_msgs_bnds, dct_env%dests_expand, dct_env%srcs_expand, &
401 dct_env%flipg_stat, dct_env%bounds_shftd, v_new, v_new_xpndd)
403 g%array = fourpi*density_xpndd%array/dielectric%eps%array
406 CALL apply_poisson_operator_dct(pw_pool_xpndd, green, dielectric, v_old, res_old)
407 CALL pw_scale(res_old, -1.0_dp)
408 CALL pw_axpy(g, res_old)
411 CALL apply_inv_laplace_operator_dct(pw_pool_xpndd, green, res_old, qainvxres)
417 CALL pw_scale(qainvxres, omega)
418 CALL pw_copy(qainvxres, v_new_xpndd)
419 CALL pw_axpy(v_old, v_new_xpndd)
423 CALL apply_p_operator(pw_pool_xpndd, dielectric, qainvxres, pxqainvxres)
424 CALL pw_copy(pxqainvxres, res_new)
425 CALL pw_scale(res_new, -1.0_dp)
426 CALL pw_axpy(res_old, res_new, 1.0_dp - omega)
429 CALL ps_implicit_compute_error_dct(pw_pool_xpndd, green, res_new, v_old, v_new_xpndd, qainvxres, &
430 pres_error, nabs_error)
432 CALL ps_implicit_output(iter, pres_error, nabs_error, outp_unit)
433 IF (
PRESENT(ehartree))
THEN
434 CALL ps_implicit_compute_ehartree(density_xpndd, v_new_xpndd, ehartree)
435 CALL ps_implicit_report_ehartree(ps_implicit_env, outp_unit, ehartree/vol_scfac)
436 ps_implicit_env%ehartree = ehartree/vol_scfac
438 IF (outp_unit > 0)
WRITE (outp_unit,
'(A1,/)')
442 reached_max_iter = iter > max_iter
443 reached_tol = pres_error <= tol
444 IF (pres_error > large_error)
THEN
445 cpabort(
"Poisson solver did not converge.")
447 ps_implicit_env%times_called = ps_implicit_env%times_called + 1
448 IF (reached_max_iter .OR. reached_tol)
EXIT
451 CALL pw_copy(v_new_xpndd, v_old)
452 CALL pw_copy(res_new, res_old)
455 CALL ps_implicit_print_convergence_msg(iter, max_iter, outp_unit)
457 CALL pw_shrink(neumann_directions, dct_env%dests_shrink, dct_env%srcs_shrink, &
458 dct_env%bounds_local_shftd, v_new_xpndd, v_new)
460 IF ((times_called /= 0) .AND. (.NOT. use_zero_initial_guess))
THEN
461 CALL pw_copy(v_new_xpndd, ps_implicit_env%initial_guess)
464 IF (
PRESENT(ehartree)) ehartree = ps_implicit_env%ehartree
467 CALL ps_implicit_compute_veps(pw_pool_xpndd, dielectric, v_new_xpndd, v_eps_xpndd)
469 TYPE(pw_r3d_rs_type) :: v_eps
470 v_eps%pw_grid => ps_implicit_env%v_eps%pw_grid
471 v_eps%array => ps_implicit_env%v_eps%array
472 CALL pw_shrink(neumann_directions, dct_env%dests_shrink, dct_env%srcs_shrink, &
473 dct_env%bounds_local_shftd, v_eps_xpndd, v_eps)
476 CALL pw_pool_xpndd%give_back_pw(g)
477 CALL pw_pool_xpndd%give_back_pw(v_old)
478 CALL pw_pool_xpndd%give_back_pw(res_old)
479 CALL pw_pool_xpndd%give_back_pw(res_new)
480 CALL pw_pool_xpndd%give_back_pw(qainvxres)
481 CALL pw_pool_xpndd%give_back_pw(pxqainvxres)
482 CALL pw_pool_xpndd%give_back_pw(density_xpndd)
483 CALL pw_pool_xpndd%give_back_pw(v_new_xpndd)
484 CALL pw_pool_xpndd%give_back_pw(v_eps_xpndd)
485 CALL pw_pool_release(pw_pool_xpndd)
487 CALL timestop(handle)
503 TYPE(pw_poisson_type),
INTENT(IN) :: poisson_env
504 TYPE(pw_r3d_rs_type),
INTENT(IN) :: density
505 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: v_new
506 REAL(dp),
INTENT(OUT),
OPTIONAL :: electric_enthalpy
508 CHARACTER(LEN=*),
PARAMETER :: routinen =
'implicit_poisson_solver_mixed_periodic'
510 INTEGER :: data_size, handle, iter, j, lb1, lb2, lb3, max_iter, n_contacts, n_tiles_tot, ng, &
511 ngpts_local, nt, nt_tot, outp_unit, times_called, ub1, ub2, ub3
512 INTEGER(KIND=int_8) :: ngpts
513 INTEGER,
DIMENSION(2, 3) :: bounds_local
514 INTEGER,
DIMENSION(3) :: npts_local
515 LOGICAL :: reached_max_iter, reached_tol, &
516 use_zero_initial_guess
517 REAL(dp) :: axvbar_avg, ehartree, eta, g_avg, &
518 gminusaxvbar_avg, nabs_error, omega, &
520 REAL(dp),
ALLOCATABLE,
DIMENSION(:) :: btxlambda_new, btxlambda_old, bxv_bar, bxv_new, &
521 lambda0, lambda_new, lambda_newneta, lambda_old, qsxlambda, v_bar1d, v_d, v_new1d, w
522 REAL(dp),
ALLOCATABLE,
DIMENSION(:, :) :: b, bt, qs, rinv
523 REAL(dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: btxlambda_new3d, btxlambda_old3d
524 TYPE(dielectric_type),
POINTER :: dielectric
525 TYPE(greens_fn_type),
POINTER :: green
526 TYPE(ps_implicit_type),
POINTER :: ps_implicit_env
527 TYPE(pw_grid_type),
POINTER :: pw_grid
528 TYPE(pw_pool_type),
POINTER :: pw_pool
529 TYPE(pw_r3d_rs_type) :: axvbar, g, pxqainvxres, qainvxres, &
530 res_new, res_old, v_old
532 CALL timeset(routinen, handle)
534 pw_pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
535 pw_grid => pw_pool%pw_grid
536 dielectric => poisson_env%implicit_env%dielectric
537 green => poisson_env%green_fft
538 ps_implicit_env => poisson_env%implicit_env
540 ngpts_local = pw_grid%ngpts_local
541 ngpts = pw_grid%ngpts
542 npts_local = pw_grid%npts_local
543 bounds_local = pw_grid%bounds_local
544 tol = poisson_env%parameters%ps_implicit_params%tol
545 omega = poisson_env%parameters%ps_implicit_params%omega
546 max_iter = poisson_env%parameters%ps_implicit_params%max_iter
547 use_zero_initial_guess = poisson_env%parameters%ps_implicit_params%zero_initial_guess
548 times_called = ps_implicit_env%times_called
550 n_contacts =
SIZE(ps_implicit_env%contacts)
553 n_tiles_tot = n_tiles_tot + ps_implicit_env%contacts(j)%dirichlet_bc%n_tiles
556 IF (pw_grid%para%blocked)
THEN
557 data_size = product(npts_local)
558 ELSE IF (pw_grid%para%ray_distribution)
THEN
559 data_size = ngpts_local
561 data_size = product(npts_local)
565 IF (times_called == 0)
CALL ps_implicit_initial_guess_create(ps_implicit_env, pw_pool)
567 ALLOCATE (b(n_tiles_tot, data_size))
568 ALLOCATE (bt(data_size, n_tiles_tot))
569 ALLOCATE (qs(n_tiles_tot, n_tiles_tot))
570 ALLOCATE (rinv(n_tiles_tot + 1, n_tiles_tot + 1))
572 b(:, :) = ps_implicit_env%B
573 bt(:, :) = ps_implicit_env%Bt
574 qs(:, :) = ps_implicit_env%QS
575 rinv(:, :) = ps_implicit_env%Rinv
576 CALL get_voltage(poisson_env%parameters%dbc_params%time, ps_implicit_env%v_D, ps_implicit_env%osc_frac, &
577 ps_implicit_env%frequency, ps_implicit_env%phase, v_d)
579 lb1 = bounds_local(1, 1); ub1 = bounds_local(2, 1)
580 lb2 = bounds_local(1, 2); ub2 = bounds_local(2, 2)
581 lb3 = bounds_local(1, 3); ub3 = bounds_local(2, 3)
583 ALLOCATE (lambda0(n_tiles_tot), lambda_old(n_tiles_tot), lambda_new(n_tiles_tot))
584 ALLOCATE (btxlambda_old(data_size), btxlambda_new(data_size))
585 ALLOCATE (btxlambda_old3d(lb1:ub1, lb2:ub2, lb3:ub3), btxlambda_new3d(lb1:ub1, lb2:ub2, lb3:ub3))
586 ALLOCATE (qsxlambda(n_tiles_tot))
587 ALLOCATE (w(n_tiles_tot + 1))
588 ALLOCATE (lambda_newneta(n_tiles_tot + 1))
589 ALLOCATE (v_bar1d(data_size))
590 ALLOCATE (bxv_bar(n_tiles_tot))
592 ALLOCATE (v_new1d(data_size))
593 ALLOCATE (bxv_new(n_tiles_tot))
595 CALL pw_pool%create_pw(g)
596 CALL pw_pool%create_pw(v_old)
597 CALL pw_pool%create_pw(res_old)
598 CALL pw_pool%create_pw(res_new)
599 CALL pw_pool%create_pw(qainvxres)
600 CALL pw_pool%create_pw(pxqainvxres)
601 CALL pw_pool%create_pw(axvbar)
603 IF (use_zero_initial_guess)
THEN
607 CALL pw_copy(ps_implicit_env%initial_guess, v_old)
608 lambda0(:) = ps_implicit_env%initial_lambda
611 g%array = fourpi*density%array/dielectric%eps%array
612 g_avg = accurate_sum(g%array)/ngpts
614 lambda_old(:) = lambda0
617 CALL apply_poisson_operator_fft(pw_pool, green, dielectric, v_old, res_old)
618 CALL pw_scale(res_old, -1.0_dp)
619 CALL pw_axpy(g, res_old)
620 IF (data_size /= 0)
THEN
621 CALL dgemv(
'N', data_size, n_tiles_tot, 1.0_dp, bt, data_size, lambda_old, 1, 0.0_dp, btxlambda_old, 1)
623 CALL convert_1dto3d(ps_implicit_env%idx_1dto3d, btxlambda_old, btxlambda_old3d)
624 res_old%array = res_old%array - btxlambda_old3d
627 CALL apply_inv_laplace_operator_fft(pw_pool, green, res_old, qainvxres)
633 CALL pw_scale(qainvxres, omega)
634 CALL pw_copy(qainvxres, v_new)
635 CALL pw_axpy(v_old, v_new)
639 CALL apply_p_operator(pw_pool, dielectric, v_new, axvbar)
640 axvbar_avg = accurate_sum(axvbar%array)/ngpts
641 gminusaxvbar_avg = g_avg - axvbar_avg
642 CALL pw_grid%para%group%sum(gminusaxvbar_avg)
645 CALL dgemv(
'N', n_tiles_tot, n_tiles_tot, 1.0_dp, qs, n_tiles_tot, lambda_old, 1, 0.0_dp, qsxlambda, 1)
646 v_bar1d(ps_implicit_env%idx_1dto3d) = reshape(v_new%array, [data_size])
647 CALL dgemv(
'N', n_tiles_tot, data_size, 1.0_dp, b, n_tiles_tot, v_bar1d, 1, 0.0_dp, bxv_bar, 1)
648 CALL pw_grid%para%group%sum(bxv_bar)
651 w(:) = [qsxlambda + v_d - bxv_bar, gminusaxvbar_avg]
652 CALL dgemv(
'N', n_tiles_tot + 1, n_tiles_tot + 1, 1.0_dp, rinv, n_tiles_tot + 1, w, 1, 0.0_dp, lambda_newneta, 1)
653 lambda_new(:) = lambda_newneta(1:n_tiles_tot)
654 eta = lambda_newneta(n_tiles_tot + 1)
657 v_new%array = v_new%array + eta/ngpts
660 IF (data_size /= 0)
THEN
661 CALL dgemv(
'N', data_size, n_tiles_tot, 1.0_dp, bt, data_size, lambda_new, 1, 0.0_dp, btxlambda_new, 1)
663 CALL convert_1dto3d(ps_implicit_env%idx_1dto3d, btxlambda_new, btxlambda_new3d)
667 CALL pw_zero(res_new)
668 CALL apply_p_operator(pw_pool, dielectric, qainvxres, pxqainvxres)
669 CALL pw_axpy(pxqainvxres, res_new, -1.0_dp)
670 CALL pw_axpy(res_old, res_new, 1.0_dp - omega)
671 res_new%array = res_new%array + btxlambda_old3d - btxlambda_new3d
674 CALL ps_implicit_compute_error_fft(pw_pool, green, res_new, v_old, v_new, qainvxres, &
675 pres_error, nabs_error)
677 CALL ps_implicit_output(iter, pres_error, nabs_error, outp_unit)
678 IF (
PRESENT(electric_enthalpy))
THEN
679 CALL ps_implicit_compute_ehartree(dielectric, density, btxlambda_new3d, v_new, ehartree, electric_enthalpy)
680 CALL ps_implicit_report_ehartree(ps_implicit_env, outp_unit, ehartree)
681 ps_implicit_env%ehartree = ehartree
682 ps_implicit_env%electric_enthalpy = electric_enthalpy
684 IF (outp_unit > 0)
WRITE (outp_unit,
'(A1,/)')
688 IF (poisson_env%parameters%dbc_params%verbose_output)
THEN
689 v_new1d(ps_implicit_env%idx_1dto3d) = reshape(v_new%array, [data_size])
690 CALL dgemv(
'N', n_tiles_tot, data_size, 1.0_dp, b, n_tiles_tot, v_new1d, 1, 0.0_dp, bxv_new, 1)
691 CALL pw_grid%para%group%sum(bxv_new)
692 IF (outp_unit > 0)
THEN
693 WRITE (outp_unit,
'(T3,A,A)')
"======== verbose ", repeat(
'=', 61)
694 WRITE (outp_unit,
'(T20,A)')
"Drgn tile vhartree lambda "
695 WRITE (outp_unit,
'(T19,A)') repeat(
'-', 46)
697 DO ng = 1, n_contacts
698 DO nt = 1, ps_implicit_env%contacts(ng)%dirichlet_bc%n_tiles
699 WRITE (outp_unit,
'(T17,I6,5X,I6,3X,E13.4,E13.4)') ng, nt, bxv_new(nt_tot), lambda_new(nt_tot)
703 WRITE (outp_unit,
'(T3,A)') repeat(
'=', 78)
709 reached_max_iter = iter > max_iter
710 reached_tol = pres_error <= tol
711 ps_implicit_env%times_called = ps_implicit_env%times_called + 1
712 IF (pres_error > large_error)
THEN
713 cpabort(
"Poisson solver did not converge.")
715 IF (reached_max_iter .OR. reached_tol)
EXIT
718 CALL pw_copy(v_new, v_old)
719 lambda_old(:) = lambda_new
720 CALL pw_copy(res_new, res_old)
721 btxlambda_old3d(:, :, :) = btxlambda_new3d
724 CALL ps_implicit_print_convergence_msg(iter, max_iter, outp_unit)
726 IF ((times_called /= 0) .AND. (.NOT. use_zero_initial_guess))
THEN
727 CALL pw_copy(v_new, ps_implicit_env%initial_guess)
728 ps_implicit_env%initial_lambda(:) = lambda_new
731 ps_implicit_env%cstr_charge%array = btxlambda_new3d
732 IF (
PRESENT(electric_enthalpy)) electric_enthalpy = ps_implicit_env%electric_enthalpy
735 TYPE(pw_r3d_rs_type) :: tmp
736 tmp%pw_grid => ps_implicit_env%v_eps%pw_grid
737 tmp%array => ps_implicit_env%v_eps%array
738 CALL ps_implicit_compute_veps(pw_pool, dielectric, v_new, tmp)
741 CALL pw_pool%give_back_pw(g)
742 CALL pw_pool%give_back_pw(v_old)
743 CALL pw_pool%give_back_pw(res_old)
744 CALL pw_pool%give_back_pw(res_new)
745 CALL pw_pool%give_back_pw(qainvxres)
746 CALL pw_pool%give_back_pw(pxqainvxres)
747 CALL pw_pool%give_back_pw(axvbar)
749 CALL timestop(handle)
766 TYPE(pw_poisson_type),
INTENT(IN) :: poisson_env
767 TYPE(pw_r3d_rs_type),
INTENT(IN) :: density
768 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: v_new
769 REAL(dp),
INTENT(OUT),
OPTIONAL :: electric_enthalpy
771 CHARACTER(LEN=*),
PARAMETER :: routinen =
'implicit_poisson_solver_mixed'
773 INTEGER :: data_size, handle, iter, j, lb1, lb2, lb3, max_iter, n_contacts, n_tiles_tot, &
774 neumann_directions, ng, ngpts_local, nt, nt_tot, outp_unit, times_called, ub1, ub2, ub3
775 INTEGER(KIND=int_8) :: ngpts
776 INTEGER,
DIMENSION(2, 3) :: bounds_local
777 INTEGER,
DIMENSION(3) :: npts_local
778 LOGICAL :: reached_max_iter, reached_tol, &
779 use_zero_initial_guess
780 REAL(dp) :: axvbar_avg, ehartree, eta, g_avg, &
781 gminusaxvbar_avg, nabs_error, omega, &
782 pres_error, tol, vol_scfac
783 REAL(dp),
ALLOCATABLE,
DIMENSION(:) :: btxlambda_new, btxlambda_old, bxv_bar, bxv_new, &
784 lambda0, lambda_new, lambda_newneta, lambda_old, qsxlambda, v_bar1d, v_d, v_new1d, w
785 REAL(dp),
ALLOCATABLE,
DIMENSION(:, :) :: b, bt, qs, rinv
786 REAL(dp),
ALLOCATABLE,
DIMENSION(:, :, :) :: btxlambda_new3d, btxlambda_old3d
787 TYPE(dct_type),
POINTER :: dct_env
788 TYPE(dielectric_type),
POINTER :: dielectric
789 TYPE(greens_fn_type),
POINTER :: green
790 TYPE(ps_implicit_type),
POINTER :: ps_implicit_env
791 TYPE(pw_grid_type),
POINTER :: dct_pw_grid, pw_grid
792 TYPE(pw_pool_type),
POINTER :: pw_pool, pw_pool_xpndd
793 TYPE(pw_r3d_rs_type) :: axvbar, density_xpndd, g, pxqainvxres, &
794 qainvxres, res_new, res_old, &
795 v_eps_xpndd, v_new_xpndd, v_old
797 CALL timeset(routinen, handle)
799 pw_pool => poisson_env%pw_pools(poisson_env%pw_level)%pool
800 pw_grid => pw_pool%pw_grid
801 dielectric => poisson_env%implicit_env%dielectric
802 green => poisson_env%green_fft
803 ps_implicit_env => poisson_env%implicit_env
804 dct_env => ps_implicit_env%dct_env
806 dct_pw_grid => poisson_env%dct_pw_grid
807 ngpts_local = dct_pw_grid%ngpts_local
808 ngpts = dct_pw_grid%ngpts
809 npts_local = dct_pw_grid%npts_local
810 bounds_local = dct_pw_grid%bounds_local
811 tol = poisson_env%parameters%ps_implicit_params%tol
812 omega = poisson_env%parameters%ps_implicit_params%omega
813 max_iter = poisson_env%parameters%ps_implicit_params%max_iter
814 use_zero_initial_guess = poisson_env%parameters%ps_implicit_params%zero_initial_guess
815 neumann_directions = poisson_env%parameters%ps_implicit_params%neumann_directions
816 times_called = ps_implicit_env%times_called
818 SELECT CASE (neumann_directions)
821 CASE (neumannxy, neumannxz, neumannyz)
823 CASE (neumannx, neumanny, neumannz)
827 n_contacts =
SIZE(ps_implicit_env%contacts)
830 n_tiles_tot = n_tiles_tot + ps_implicit_env%contacts(j)%dirichlet_bc%n_tiles
833 IF (dct_pw_grid%para%blocked)
THEN
834 data_size = product(npts_local)
835 ELSE IF (dct_pw_grid%para%ray_distribution)
THEN
836 data_size = ngpts_local
838 data_size = product(npts_local)
841 CALL pw_pool_create(pw_pool_xpndd, pw_grid=dct_pw_grid)
844 IF (times_called == 0)
CALL ps_implicit_initial_guess_create(ps_implicit_env, pw_pool_xpndd)
846 ALLOCATE (b(n_tiles_tot, data_size))
847 ALLOCATE (bt(data_size, n_tiles_tot))
848 ALLOCATE (qs(n_tiles_tot, n_tiles_tot))
849 ALLOCATE (rinv(n_tiles_tot + 1, n_tiles_tot + 1))
851 b(:, :) = ps_implicit_env%B
852 bt(:, :) = ps_implicit_env%Bt
853 qs(:, :) = ps_implicit_env%QS
854 rinv(:, :) = ps_implicit_env%Rinv
855 CALL get_voltage(poisson_env%parameters%dbc_params%time, ps_implicit_env%v_D, ps_implicit_env%osc_frac, &
856 ps_implicit_env%frequency, ps_implicit_env%phase, v_d)
858 lb1 = bounds_local(1, 1); ub1 = bounds_local(2, 1)
859 lb2 = bounds_local(1, 2); ub2 = bounds_local(2, 2)
860 lb3 = bounds_local(1, 3); ub3 = bounds_local(2, 3)
862 ALLOCATE (lambda0(n_tiles_tot), lambda_old(n_tiles_tot), lambda_new(n_tiles_tot))
863 ALLOCATE (btxlambda_old(data_size), btxlambda_new(data_size))
864 ALLOCATE (btxlambda_old3d(lb1:ub1, lb2:ub2, lb3:ub3), btxlambda_new3d(lb1:ub1, lb2:ub2, lb3:ub3))
865 ALLOCATE (qsxlambda(n_tiles_tot))
866 ALLOCATE (w(n_tiles_tot + 1))
867 ALLOCATE (lambda_newneta(n_tiles_tot + 1))
868 ALLOCATE (v_bar1d(data_size))
869 ALLOCATE (bxv_bar(n_tiles_tot))
871 ALLOCATE (v_new1d(data_size))
872 ALLOCATE (bxv_new(n_tiles_tot))
874 CALL pw_pool_xpndd%create_pw(g)
875 CALL pw_pool_xpndd%create_pw(v_old)
876 CALL pw_pool_xpndd%create_pw(res_old)
877 CALL pw_pool_xpndd%create_pw(res_new)
878 CALL pw_pool_xpndd%create_pw(qainvxres)
879 CALL pw_pool_xpndd%create_pw(pxqainvxres)
880 CALL pw_pool_xpndd%create_pw(axvbar)
881 CALL pw_pool_xpndd%create_pw(density_xpndd)
882 CALL pw_pool_xpndd%create_pw(v_new_xpndd)
883 CALL pw_pool_xpndd%create_pw(v_eps_xpndd)
885 IF (use_zero_initial_guess)
THEN
889 CALL pw_copy(ps_implicit_env%initial_guess, v_old)
890 lambda0(:) = ps_implicit_env%initial_lambda
893 CALL pw_expand(neumann_directions, &
894 dct_env%recv_msgs_bnds, dct_env%dests_expand, dct_env%srcs_expand, &
895 dct_env%flipg_stat, dct_env%bounds_shftd, density, density_xpndd)
896 CALL pw_expand(neumann_directions, &
897 dct_env%recv_msgs_bnds, dct_env%dests_expand, dct_env%srcs_expand, &
898 dct_env%flipg_stat, dct_env%bounds_shftd, v_new, v_new_xpndd)
900 g%array = fourpi*density_xpndd%array/dielectric%eps%array
901 g_avg = accurate_sum(g%array)/ngpts
903 lambda_old(:) = lambda0
906 CALL apply_poisson_operator_dct(pw_pool_xpndd, green, dielectric, v_old, res_old)
907 CALL pw_scale(res_old, -1.0_dp)
908 CALL pw_axpy(g, res_old)
909 IF (data_size /= 0)
THEN
910 CALL dgemv(
'N', data_size, n_tiles_tot, 1.0_dp, bt, data_size, lambda_old, 1, 0.0_dp, btxlambda_old, 1)
912 CALL convert_1dto3d(ps_implicit_env%idx_1dto3d, btxlambda_old, btxlambda_old3d)
913 res_old%array = res_old%array - btxlambda_old3d
916 CALL apply_inv_laplace_operator_dct(pw_pool_xpndd, green, res_old, qainvxres)
922 CALL pw_scale(qainvxres, omega)
923 CALL pw_copy(qainvxres, v_new_xpndd)
924 CALL pw_axpy(v_old, v_new_xpndd)
928 CALL apply_p_operator(pw_pool_xpndd, dielectric, v_new_xpndd, axvbar)
929 axvbar_avg = accurate_sum(axvbar%array)/ngpts
930 gminusaxvbar_avg = g_avg - axvbar_avg
931 CALL dct_pw_grid%para%group%sum(gminusaxvbar_avg)
934 CALL dgemv(
'N', n_tiles_tot, n_tiles_tot, 1.0_dp, qs, n_tiles_tot, lambda_old, 1, 0.0_dp, qsxlambda, 1)
935 v_bar1d(ps_implicit_env%idx_1dto3d) = reshape(v_new_xpndd%array, [data_size])
936 CALL dgemv(
'N', n_tiles_tot, data_size, 1.0_dp, b, n_tiles_tot, v_bar1d, 1, 0.0_dp, bxv_bar, 1)
937 CALL dct_pw_grid%para%group%sum(bxv_bar)
940 w(:) = [qsxlambda + v_d - bxv_bar, gminusaxvbar_avg]
941 CALL dgemv(
'N', n_tiles_tot + 1, n_tiles_tot + 1, 1.0_dp, rinv, n_tiles_tot + 1, w, 1, 0.0_dp, lambda_newneta, 1)
942 lambda_new(:) = lambda_newneta(1:n_tiles_tot)
943 eta = lambda_newneta(n_tiles_tot + 1)
946 v_new_xpndd%array = v_new_xpndd%array + eta/ngpts
949 IF (data_size /= 0)
THEN
950 CALL dgemv(
'N', data_size, n_tiles_tot, 1.0_dp, bt, data_size, lambda_new, 1, 0.0_dp, btxlambda_new, 1)
952 CALL convert_1dto3d(ps_implicit_env%idx_1dto3d, btxlambda_new, btxlambda_new3d)
956 CALL pw_zero(res_new)
957 CALL apply_p_operator(pw_pool_xpndd, dielectric, qainvxres, pxqainvxres)
958 CALL pw_axpy(pxqainvxres, res_new, -1.0_dp)
959 CALL pw_axpy(res_old, res_new, 1.0_dp - omega)
960 res_new%array = res_new%array - btxlambda_new3d + btxlambda_old3d
963 CALL ps_implicit_compute_error_dct(pw_pool_xpndd, green, res_new, v_old, v_new_xpndd, qainvxres, &
964 pres_error, nabs_error)
966 CALL ps_implicit_output(iter, pres_error, nabs_error, outp_unit)
967 IF (
PRESENT(electric_enthalpy))
THEN
968 CALL ps_implicit_compute_ehartree(dielectric, density_xpndd, btxlambda_new3d, v_new_xpndd, &
969 ehartree, electric_enthalpy)
970 CALL ps_implicit_report_ehartree(ps_implicit_env, outp_unit, ehartree/vol_scfac)
971 ps_implicit_env%ehartree = ehartree/vol_scfac
972 ps_implicit_env%electric_enthalpy = electric_enthalpy/vol_scfac
974 IF (outp_unit > 0)
WRITE (outp_unit,
'(A1,/)')
978 IF (poisson_env%parameters%dbc_params%verbose_output)
THEN
979 v_new1d(ps_implicit_env%idx_1dto3d) = reshape(v_new_xpndd%array, [data_size])
980 CALL dgemv(
'N', n_tiles_tot, data_size, 1.0_dp, b, n_tiles_tot, v_new1d, 1, 0.0_dp, bxv_new, 1)
981 CALL pw_grid%para%group%sum(bxv_new)
982 IF (outp_unit > 0)
THEN
983 WRITE (outp_unit,
'(T3,A)')
"======== verbose "//repeat(
'=', 61)
984 WRITE (outp_unit,
'(T20,A)')
"Drgn tile vhartree lambda "
985 WRITE (outp_unit,
'(T19,A)') repeat(
'-', 46)
987 DO ng = 1, n_contacts
988 DO nt = 1, ps_implicit_env%contacts(ng)%dirichlet_bc%n_tiles
989 WRITE (outp_unit,
'(T17,I6,5X,I6,3X,E13.4,E13.4)') ng, nt, bxv_new(nt_tot), lambda_new(nt_tot)
993 WRITE (outp_unit,
'(T3,A)') repeat(
'=', 78)
999 reached_max_iter = iter > max_iter
1000 reached_tol = pres_error <= tol
1001 ps_implicit_env%times_called = ps_implicit_env%times_called + 1
1002 IF (pres_error > large_error)
THEN
1003 cpabort(
"Poisson solver did not converge.")
1005 IF (reached_max_iter .OR. reached_tol)
EXIT
1008 CALL pw_copy(v_new_xpndd, v_old)
1009 lambda_old(:) = lambda_new
1010 CALL pw_copy(res_new, res_old)
1011 btxlambda_old3d(:, :, :) = btxlambda_new3d
1014 CALL ps_implicit_print_convergence_msg(iter, max_iter, outp_unit)
1016 CALL pw_shrink(neumann_directions, dct_env%dests_shrink, dct_env%srcs_shrink, &
1017 dct_env%bounds_local_shftd, v_new_xpndd, v_new)
1019 IF ((times_called /= 0) .AND. (.NOT. use_zero_initial_guess))
THEN
1020 CALL pw_copy(v_new_xpndd, ps_implicit_env%initial_guess)
1021 ps_implicit_env%initial_lambda(:) = lambda_new
1024 ps_implicit_env%cstr_charge%array = btxlambda_new3d
1025 IF (
PRESENT(electric_enthalpy)) electric_enthalpy = ps_implicit_env%electric_enthalpy
1027 CALL ps_implicit_compute_veps(pw_pool_xpndd, dielectric, v_new_xpndd, v_eps_xpndd)
1028 CALL pw_shrink(neumann_directions, dct_env%dests_shrink, dct_env%srcs_shrink, &
1029 dct_env%bounds_local_shftd, v_eps_xpndd, ps_implicit_env%v_eps)
1031 CALL pw_pool_xpndd%give_back_pw(g)
1032 CALL pw_pool_xpndd%give_back_pw(v_old)
1033 CALL pw_pool_xpndd%give_back_pw(res_old)
1034 CALL pw_pool_xpndd%give_back_pw(res_new)
1035 CALL pw_pool_xpndd%give_back_pw(qainvxres)
1036 CALL pw_pool_xpndd%give_back_pw(pxqainvxres)
1037 CALL pw_pool_xpndd%give_back_pw(axvbar)
1038 CALL pw_pool_xpndd%give_back_pw(density_xpndd)
1039 CALL pw_pool_xpndd%give_back_pw(v_new_xpndd)
1040 CALL pw_pool_xpndd%give_back_pw(v_eps_xpndd)
1041 CALL pw_pool_release(pw_pool_xpndd)
1043 CALL timestop(handle)
1055 SUBROUTINE ps_implicit_initial_guess_create(ps_implicit_env, pw_pool)
1057 TYPE(ps_implicit_type),
INTENT(INOUT),
POINTER :: ps_implicit_env
1058 TYPE(pw_pool_type),
INTENT(IN),
POINTER :: pw_pool
1060 CHARACTER(LEN=*),
PARAMETER :: routinen =
'ps_implicit_initial_guess_create'
1062 INTEGER :: handle, n_tiles_tot
1064 CALL timeset(routinen, handle)
1066 n_tiles_tot =
SIZE(ps_implicit_env%v_D)
1067 NULLIFY (ps_implicit_env%initial_guess)
1068 ALLOCATE (ps_implicit_env%initial_guess)
1069 CALL pw_pool%create_pw(ps_implicit_env%initial_guess)
1070 CALL pw_zero(ps_implicit_env%initial_guess)
1071 ALLOCATE (ps_implicit_env%initial_lambda(n_tiles_tot))
1072 ps_implicit_env%initial_lambda = 0.0_dp
1074 CALL timestop(handle)
1076 END SUBROUTINE ps_implicit_initial_guess_create
1089 SUBROUTINE ps_implicit_prepare_blocks(pw_pool_orig, dct_pw_grid, green, &
1090 poisson_params, ps_implicit_env)
1092 TYPE(pw_pool_type),
INTENT(IN),
POINTER :: pw_pool_orig
1093 TYPE(pw_grid_type),
INTENT(IN),
POINTER :: dct_pw_grid
1094 TYPE(greens_fn_type),
INTENT(IN) :: green
1095 TYPE(pw_poisson_parameter_type),
INTENT(IN) :: poisson_params
1096 TYPE(ps_implicit_type),
INTENT(INOUT),
POINTER :: ps_implicit_env
1098 CHARACTER(LEN=*),
PARAMETER :: routinen =
'ps_implicit_prepare_blocks'
1100 INTEGER :: data_size, handle, i, indx1, indx2, info, j, k, l, lb1, lb2, lb3, n_contacts, &
1101 n_tiles, n_tiles_tot, neumann_directions, ngpts_local, ub1, ub2, ub3, unit_nr
1102 INTEGER(KIND=int_8) :: ngpts
1103 INTEGER,
ALLOCATABLE,
DIMENSION(:) :: ipiv
1104 INTEGER,
DIMENSION(2, 3) :: bounds, bounds_local
1105 INTEGER,
DIMENSION(3) :: npts, npts_local
1106 LOGICAL :: done_preparing
1107 REAL(dp) :: tile_volume, vol_scfac
1108 REAL(dp),
ALLOCATABLE,
DIMENSION(:) :: bxunit_vec, test_vec, work_arr
1109 REAL(dp),
ALLOCATABLE,
DIMENSION(:, :) :: qainvxbt, r
1110 TYPE(cp_logger_type),
POINTER :: logger
1111 TYPE(dct_type),
POINTER :: dct_env
1112 TYPE(pw_grid_type),
POINTER :: pw_grid_orig
1113 TYPE(pw_pool_type),
POINTER :: pw_pool_xpndd
1114 TYPE(pw_r3d_rs_type) :: pw_in, pw_out
1116 CALL timeset(routinen, handle)
1118 pw_grid_orig => pw_pool_orig%pw_grid
1120 logger => cp_get_default_logger()
1121 IF (logger%para_env%is_source())
THEN
1122 unit_nr = cp_logger_get_default_unit_nr(logger, local=.true.)
1127 SELECT CASE (poisson_params%ps_implicit_params%boundary_condition)
1130 ngpts_local = dct_pw_grid%ngpts_local
1131 ngpts = dct_pw_grid%ngpts
1132 npts_local = dct_pw_grid%npts_local
1133 npts = dct_pw_grid%npts
1134 bounds_local = dct_pw_grid%bounds_local
1135 bounds = dct_pw_grid%bounds
1136 dct_env => ps_implicit_env%dct_env
1138 neumann_directions = poisson_params%ps_implicit_params%neumann_directions
1140 SELECT CASE (neumann_directions)
1143 CASE (neumannxy, neumannxz, neumannyz)
1145 CASE (neumannx, neumanny, neumannz)
1150 lb1 = bounds_local(1, 1); ub1 = bounds_local(2, 1)
1151 lb2 = bounds_local(1, 2); ub2 = bounds_local(2, 2)
1152 lb3 = bounds_local(1, 3); ub3 = bounds_local(2, 3)
1154 IF (dct_pw_grid%para%blocked)
THEN
1155 data_size = product(npts_local)
1156 ELSE IF (dct_pw_grid%para%ray_distribution)
THEN
1157 data_size = ngpts_local
1159 data_size = product(npts_local)
1162 ALLOCATE (ps_implicit_env%idx_1dto3d(data_size))
1172 ps_implicit_env%idx_1dto3d(l) = (i - lb1 + 1) + &
1173 (j - lb2)*npts_local(1) + &
1174 (k - lb3)*npts_local(1)*npts_local(2)
1182 n_contacts =
SIZE(ps_implicit_env%contacts)
1184 DO j = 1, n_contacts
1185 n_tiles_tot = n_tiles_tot + ps_implicit_env%contacts(j)%dirichlet_bc%n_tiles
1188 ALLOCATE (ps_implicit_env%B(n_tiles_tot, data_size))
1189 ALLOCATE (ps_implicit_env%Bt(data_size, n_tiles_tot))
1190 ALLOCATE (ps_implicit_env%QS(n_tiles_tot, n_tiles_tot))
1191 ALLOCATE (ps_implicit_env%Rinv(n_tiles_tot + 1, n_tiles_tot + 1))
1192 ALLOCATE (ps_implicit_env%v_D(n_tiles_tot))
1193 ALLOCATE (ps_implicit_env%osc_frac(n_tiles_tot))
1194 ALLOCATE (ps_implicit_env%frequency(n_tiles_tot))
1195 ALLOCATE (ps_implicit_env%phase(n_tiles_tot))
1197 ALLOCATE (qainvxbt(data_size, n_tiles_tot))
1198 ALLOCATE (bxunit_vec(n_tiles_tot))
1199 ALLOCATE (test_vec(n_tiles_tot))
1200 ALLOCATE (r(n_tiles_tot + 1, n_tiles_tot + 1))
1201 ALLOCATE (work_arr(n_tiles_tot + 1), ipiv(n_tiles_tot + 1))
1204 CALL pw_pool_create(pw_pool_xpndd, pw_grid=dct_pw_grid)
1208 DO j = 1, n_contacts
1209 n_tiles = ps_implicit_env%contacts(j)%dirichlet_bc%n_tiles
1210 indx2 = indx1 + n_tiles - 1
1213 CALL pw_pool_xpndd%create_pw(pw_in)
1214 CALL pw_expand(neumann_directions, &
1215 dct_env%recv_msgs_bnds, dct_env%dests_expand, dct_env%srcs_expand, &
1216 dct_env%flipg_stat, dct_env%bounds_shftd, &
1217 ps_implicit_env%contacts(j)%dirichlet_bc%tiles(i)%tile%tile_pw, pw_in)
1219 tile_volume = ps_implicit_env%contacts(j)%dirichlet_bc%tiles(i)%tile%volume
1220 CALL pw_scale(pw_in, 1.0_dp/(vol_scfac*tile_volume))
1221 ps_implicit_env%Bt(ps_implicit_env%idx_1dto3d, indx1 + i - 1) = reshape(pw_in%array, [data_size])
1223 CALL pw_pool_xpndd%create_pw(pw_out)
1224 CALL apply_inv_laplace_operator_dct(pw_pool_xpndd, green, pw_in, pw_out)
1225 qainvxbt(ps_implicit_env%idx_1dto3d, indx1 + i - 1) = reshape(pw_out%array, [data_size])
1227 ps_implicit_env%v_D(indx1 + i - 1) = -1.0_dp*ps_implicit_env%contacts(j)%dirichlet_bc%v_D
1228 ps_implicit_env%osc_frac(indx1 + i - 1) = ps_implicit_env%contacts(j)%dirichlet_bc%osc_frac
1229 ps_implicit_env%frequency(indx1 + i - 1) = ps_implicit_env%contacts(j)%dirichlet_bc%frequency
1230 ps_implicit_env%phase(indx1 + i - 1) = ps_implicit_env%contacts(j)%dirichlet_bc%phase
1232 CALL pw_pool_xpndd%give_back_pw(pw_in)
1233 CALL pw_pool_xpndd%give_back_pw(pw_out)
1237 ps_implicit_env%B(:, :) = transpose(ps_implicit_env%Bt)
1240 IF (data_size /= 0)
THEN
1241 CALL dgemm(
'N',
'N', n_tiles_tot, n_tiles_tot, data_size, &
1242 -1.0_dp, ps_implicit_env%B, n_tiles_tot, qainvxbt, &
1243 data_size, 0.0_dp, ps_implicit_env%QS, n_tiles_tot)
1245 CALL pw_grid_orig%para%group%sum(ps_implicit_env%QS)
1248 bxunit_vec(:) = sum(ps_implicit_env%B, 2)/ngpts
1249 CALL pw_grid_orig%para%group%sum(bxunit_vec)
1252 r(1:n_tiles_tot, 1:n_tiles_tot) = ps_implicit_env%QS
1253 r(1:n_tiles_tot, n_tiles_tot + 1) = bxunit_vec
1254 r(n_tiles_tot + 1, 1:n_tiles_tot) = bxunit_vec
1256 ps_implicit_env%Rinv(:, :) = r
1257 CALL dgetrf(n_tiles_tot + 1, n_tiles_tot + 1, ps_implicit_env%Rinv, n_tiles_tot + 1, ipiv, info)
1259 CALL cp_abort(__location__, &
1260 "R is (nearly) singular! Either two Dirichlet constraints are identical or "// &
1261 "you need to reduce the number of tiles.")
1263 CALL dgetri(n_tiles_tot + 1, ps_implicit_env%Rinv, n_tiles_tot + 1, ipiv, work_arr, n_tiles_tot + 1, info)
1265 cpabort(
"Inversion of R failed!")
1268 DEALLOCATE (qainvxbt, bxunit_vec, r, work_arr, ipiv)
1269 CALL pw_pool_release(pw_pool_xpndd)
1271 done_preparing = .true.
1272 CALL pw_grid_orig%para%group%sum(done_preparing)
1273 IF ((unit_nr > 0) .AND. done_preparing)
THEN
1274 WRITE (unit_nr,
"(T3,A,/,T3,A,/,A)")
"POISSON| ... Done. ", repeat(
'-', 78)
1277 CASE (mixed_periodic_bc)
1279 ngpts_local = pw_grid_orig%ngpts_local
1280 ngpts = pw_grid_orig%ngpts
1281 npts_local = pw_grid_orig%npts_local
1282 npts = pw_grid_orig%npts
1283 bounds_local = pw_grid_orig%bounds_local
1284 bounds = pw_grid_orig%bounds
1285 dct_env => ps_implicit_env%dct_env
1288 lb1 = bounds_local(1, 1); ub1 = bounds_local(2, 1)
1289 lb2 = bounds_local(1, 2); ub2 = bounds_local(2, 2)
1290 lb3 = bounds_local(1, 3); ub3 = bounds_local(2, 3)
1292 IF (pw_grid_orig%para%blocked)
THEN
1293 data_size = product(npts_local)
1294 ELSE IF (pw_grid_orig%para%ray_distribution)
THEN
1295 data_size = ngpts_local
1297 data_size = product(npts_local)
1300 ALLOCATE (ps_implicit_env%idx_1dto3d(data_size))
1310 ps_implicit_env%idx_1dto3d(l) = (i - lb1 + 1) + &
1311 (j - lb2)*npts_local(1) + &
1312 (k - lb3)*npts_local(1)*npts_local(2)
1320 n_contacts =
SIZE(ps_implicit_env%contacts)
1322 DO j = 1, n_contacts
1323 n_tiles_tot = n_tiles_tot + ps_implicit_env%contacts(j)%dirichlet_bc%n_tiles
1326 ALLOCATE (ps_implicit_env%B(n_tiles_tot, data_size))
1327 ALLOCATE (ps_implicit_env%Bt(data_size, n_tiles_tot))
1328 ALLOCATE (ps_implicit_env%QS(n_tiles_tot, n_tiles_tot))
1329 ALLOCATE (ps_implicit_env%Rinv(n_tiles_tot + 1, n_tiles_tot + 1))
1330 ALLOCATE (ps_implicit_env%v_D(n_tiles_tot))
1331 ALLOCATE (ps_implicit_env%osc_frac(n_tiles_tot))
1332 ALLOCATE (ps_implicit_env%frequency(n_tiles_tot))
1333 ALLOCATE (ps_implicit_env%phase(n_tiles_tot))
1335 ALLOCATE (qainvxbt(data_size, n_tiles_tot))
1336 ALLOCATE (bxunit_vec(n_tiles_tot))
1337 ALLOCATE (test_vec(n_tiles_tot))
1338 ALLOCATE (r(n_tiles_tot + 1, n_tiles_tot + 1))
1339 ALLOCATE (work_arr(n_tiles_tot + 1), ipiv(n_tiles_tot + 1))
1343 DO j = 1, n_contacts
1344 n_tiles = ps_implicit_env%contacts(j)%dirichlet_bc%n_tiles
1345 indx2 = indx1 + n_tiles - 1
1347 CALL pw_pool_orig%create_pw(pw_in)
1348 CALL pw_copy(ps_implicit_env%contacts(j)%dirichlet_bc%tiles(i)%tile%tile_pw, pw_in)
1350 tile_volume = ps_implicit_env%contacts(j)%dirichlet_bc%tiles(i)%tile%volume
1351 CALL pw_scale(pw_in, 1.0_dp/tile_volume)
1352 ps_implicit_env%Bt(ps_implicit_env%idx_1dto3d, indx1 + i - 1) = reshape(pw_in%array, [data_size])
1354 CALL pw_pool_orig%create_pw(pw_out)
1355 CALL apply_inv_laplace_operator_fft(pw_pool_orig, green, pw_in, pw_out)
1356 qainvxbt(ps_implicit_env%idx_1dto3d, indx1 + i - 1) = reshape(pw_out%array, [data_size])
1358 ps_implicit_env%v_D(indx1 + i - 1) = -1.0_dp*ps_implicit_env%contacts(j)%dirichlet_bc%v_D
1359 ps_implicit_env%osc_frac(indx1 + i - 1) = ps_implicit_env%contacts(j)%dirichlet_bc%osc_frac
1360 ps_implicit_env%frequency(indx1 + i - 1) = ps_implicit_env%contacts(j)%dirichlet_bc%frequency
1361 ps_implicit_env%phase(indx1 + i - 1) = ps_implicit_env%contacts(j)%dirichlet_bc%phase
1363 CALL pw_pool_orig%give_back_pw(pw_in)
1364 CALL pw_pool_orig%give_back_pw(pw_out)
1368 ps_implicit_env%B(:, :) = transpose(ps_implicit_env%Bt)
1371 IF (data_size /= 0)
THEN
1372 CALL dgemm(
'N',
'N', n_tiles_tot, n_tiles_tot, data_size, &
1373 -1.0_dp, ps_implicit_env%B, n_tiles_tot, qainvxbt, &
1374 data_size, 0.0_dp, ps_implicit_env%QS, n_tiles_tot)
1376 CALL pw_grid_orig%para%group%sum(ps_implicit_env%QS)
1379 bxunit_vec(:) = sum(ps_implicit_env%B, 2)/ngpts
1380 CALL pw_grid_orig%para%group%sum(bxunit_vec)
1383 r(1:n_tiles_tot, 1:n_tiles_tot) = ps_implicit_env%QS
1384 r(1:n_tiles_tot, n_tiles_tot + 1) = bxunit_vec
1385 r(n_tiles_tot + 1, 1:n_tiles_tot) = bxunit_vec
1387 ps_implicit_env%Rinv(:, :) = r
1388 CALL dgetrf(n_tiles_tot + 1, n_tiles_tot + 1, ps_implicit_env%Rinv, n_tiles_tot + 1, ipiv, info)
1390 CALL cp_abort(__location__, &
1391 "R is (nearly) singular! Either two Dirichlet constraints are identical or "// &
1392 "you need to reduce the number of tiles.")
1394 CALL dgetri(n_tiles_tot + 1, ps_implicit_env%Rinv, n_tiles_tot + 1, ipiv, work_arr, n_tiles_tot + 1, info)
1396 cpabort(
"Inversion of R failed!")
1399 DEALLOCATE (qainvxbt, bxunit_vec, r, work_arr, ipiv)
1401 done_preparing = .true.
1402 CALL pw_grid_orig%para%group%sum(done_preparing)
1403 IF ((unit_nr > 0) .AND. done_preparing)
THEN
1404 WRITE (unit_nr,
"(T3,A,/,T3,A,/,A)")
"POISSON| ... Done. ", repeat(
'-', 78)
1407 CASE (periodic_bc, neumann_bc)
1409 ALLOCATE (ps_implicit_env%idx_1dto3d(1))
1410 ALLOCATE (ps_implicit_env%B(1, 1))
1411 ALLOCATE (ps_implicit_env%Bt(1, 1))
1412 ALLOCATE (ps_implicit_env%QS(1, 1))
1413 ALLOCATE (ps_implicit_env%Rinv(1, 1))
1414 ALLOCATE (ps_implicit_env%v_D(1))
1415 ALLOCATE (ps_implicit_env%osc_frac(1))
1416 ALLOCATE (ps_implicit_env%frequency(1))
1417 ALLOCATE (ps_implicit_env%phase(1))
1419 ps_implicit_env%idx_1dto3d = 1
1420 ps_implicit_env%B = 0.0_dp
1421 ps_implicit_env%Bt = 0.0_dp
1422 ps_implicit_env%QS = 0.0_dp
1423 ps_implicit_env%Rinv = 0.0_dp
1424 ps_implicit_env%v_D = 0.0_dp
1427 CALL cp_abort(__location__, &
1428 "Please specify the type of boundary conditions using the "// &
1429 "input file keyword BOUNDARY_CONDITIONS.")
1432 CALL timestop(handle)
1434 END SUBROUTINE ps_implicit_prepare_blocks
1447 SUBROUTINE apply_p_operator(pw_pool, dielectric, v, Pxv)
1449 TYPE(pw_pool_type),
POINTER :: pw_pool
1450 TYPE(dielectric_type),
INTENT(IN),
POINTER :: dielectric
1451 TYPE(pw_r3d_rs_type),
INTENT(IN) :: v
1452 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: pxv
1454 CHARACTER(LEN=*),
PARAMETER :: routinen =
'apply_P_operator'
1456 INTEGER :: handle, i
1457 TYPE(pw_r3d_rs_type),
DIMENSION(3) :: dv
1459 CALL timeset(routinen, handle)
1462 CALL pw_pool%create_pw(dv(i))
1465 CALL derive_fft(v, dv, pw_pool)
1466 associate(dln_eps => dielectric%dln_eps)
1467 pxv%array = -(dv(1)%array*dln_eps(1)%array + &
1468 dv(2)%array*dln_eps(2)%array + &
1469 dv(3)%array*dln_eps(3)%array)
1473 CALL pw_pool%give_back_pw(dv(i))
1476 CALL timestop(handle)
1478 END SUBROUTINE apply_p_operator
1490 SUBROUTINE apply_inv_laplace_operator_fft(pw_pool, green, pw_in, pw_out)
1492 TYPE(pw_pool_type),
INTENT(IN),
POINTER :: pw_pool
1493 TYPE(greens_fn_type),
INTENT(IN) :: green
1494 TYPE(pw_r3d_rs_type),
INTENT(IN) :: pw_in
1495 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: pw_out
1497 CHARACTER(LEN=*),
PARAMETER :: routinen =
'apply_inv_laplace_operator_fft'
1499 INTEGER :: handle, ig, ng
1500 REAL(dp) :: prefactor
1501 TYPE(pw_c1d_gs_type) :: pw_in_gs
1502 TYPE(pw_grid_type),
POINTER :: pw_grid
1504 CALL timeset(routinen, handle)
1507 prefactor = 1.0_dp/fourpi
1509 pw_grid => pw_pool%pw_grid
1510 ng =
SIZE(pw_grid%gsq)
1512 CALL pw_pool%create_pw(pw_in_gs)
1514 CALL pw_transfer(pw_in, pw_in_gs)
1516 pw_in_gs%array(ig) = prefactor*pw_in_gs%array(ig)*green%influence_fn%array(ig)
1518 CALL pw_transfer(pw_in_gs, pw_out)
1520 CALL pw_pool%give_back_pw(pw_in_gs)
1522 CALL timestop(handle)
1524 END SUBROUTINE apply_inv_laplace_operator_fft
1538 SUBROUTINE apply_inv_laplace_operator_dct(pw_pool, green, pw_in, pw_out)
1540 TYPE(pw_pool_type),
INTENT(IN),
POINTER :: pw_pool
1541 TYPE(greens_fn_type),
INTENT(IN) :: green
1542 TYPE(pw_r3d_rs_type),
INTENT(IN) :: pw_in
1543 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: pw_out
1545 CHARACTER(LEN=*),
PARAMETER :: routinen =
'apply_inv_laplace_operator_dct'
1547 INTEGER :: handle, ig, ng
1548 REAL(dp) :: prefactor
1549 TYPE(pw_c1d_gs_type) :: pw_in_gs
1550 TYPE(pw_grid_type),
POINTER :: pw_grid
1552 CALL timeset(routinen, handle)
1555 prefactor = 1.0_dp/fourpi
1557 pw_grid => pw_pool%pw_grid
1558 ng =
SIZE(pw_grid%gsq)
1560 CALL pw_pool%create_pw(pw_in_gs)
1562 CALL pw_transfer(pw_in, pw_in_gs)
1564 pw_in_gs%array(ig) = prefactor*pw_in_gs%array(ig)*green%dct_influence_fn%array(ig)
1566 CALL pw_transfer(pw_in_gs, pw_out)
1568 CALL pw_pool%give_back_pw(pw_in_gs)
1570 CALL timestop(handle)
1572 END SUBROUTINE apply_inv_laplace_operator_dct
1584 SUBROUTINE apply_laplace_operator_fft(pw_pool, green, pw_in, pw_out)
1586 TYPE(pw_pool_type),
INTENT(IN),
POINTER :: pw_pool
1587 TYPE(greens_fn_type),
INTENT(IN) :: green
1588 TYPE(pw_r3d_rs_type),
INTENT(IN) :: pw_in
1589 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: pw_out
1591 CHARACTER(LEN=*),
PARAMETER :: routinen =
'apply_laplace_operator_fft'
1593 INTEGER :: g0_index, handle, ig, ng
1595 REAL(dp) :: prefactor
1596 TYPE(pw_c1d_gs_type) :: pw_in_gs
1597 TYPE(pw_grid_type),
POINTER :: pw_grid
1599 CALL timeset(routinen, handle)
1604 pw_grid => pw_pool%pw_grid
1605 ng =
SIZE(pw_in%pw_grid%gsq)
1606 have_g0 = green%influence_fn%pw_grid%have_g0
1608 CALL pw_pool%create_pw(pw_in_gs)
1610 CALL pw_transfer(pw_in, pw_in_gs)
1613 g0_index = green%influence_fn%pw_grid%first_gne0 - 1
1614 pw_in_gs%array(g0_index) = 0.0_dp
1616 DO ig = green%influence_fn%pw_grid%first_gne0, ng
1617 pw_in_gs%array(ig) = prefactor*(pw_in_gs%array(ig)/green%influence_fn%array(ig))
1620 CALL pw_transfer(pw_in_gs, pw_out)
1622 CALL pw_pool%give_back_pw(pw_in_gs)
1624 CALL timestop(handle)
1626 END SUBROUTINE apply_laplace_operator_fft
1639 SUBROUTINE apply_laplace_operator_dct(pw_pool, green, pw_in, pw_out)
1641 TYPE(pw_pool_type),
INTENT(IN),
POINTER :: pw_pool
1642 TYPE(greens_fn_type),
INTENT(IN) :: green
1643 TYPE(pw_r3d_rs_type),
INTENT(IN) :: pw_in
1644 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: pw_out
1646 CHARACTER(LEN=*),
PARAMETER :: routinen =
'apply_laplace_operator_dct'
1648 INTEGER :: g0_index, handle, ig, ng
1650 REAL(dp) :: prefactor
1651 TYPE(pw_c1d_gs_type) :: pw_in_gs
1652 TYPE(pw_grid_type),
POINTER :: pw_grid
1654 CALL timeset(routinen, handle)
1659 pw_grid => pw_pool%pw_grid
1660 ng =
SIZE(pw_in%pw_grid%gsq)
1661 have_g0 = green%dct_influence_fn%pw_grid%have_g0
1663 CALL pw_pool%create_pw(pw_in_gs)
1665 CALL pw_transfer(pw_in, pw_in_gs)
1668 g0_index = green%dct_influence_fn%pw_grid%first_gne0 - 1
1669 pw_in_gs%array(g0_index) = 0.0_dp
1671 DO ig = green%dct_influence_fn%pw_grid%first_gne0, ng
1672 pw_in_gs%array(ig) = prefactor*(pw_in_gs%array(ig)/green%dct_influence_fn%array(ig))
1675 CALL pw_transfer(pw_in_gs, pw_out)
1677 CALL pw_pool%give_back_pw(pw_in_gs)
1679 CALL timestop(handle)
1681 END SUBROUTINE apply_laplace_operator_dct
1694 SUBROUTINE apply_poisson_operator_fft(pw_pool, green, dielectric, v, density)
1696 TYPE(pw_pool_type),
INTENT(IN),
POINTER :: pw_pool
1697 TYPE(greens_fn_type),
INTENT(IN) :: green
1698 TYPE(dielectric_type),
INTENT(IN),
POINTER :: dielectric
1699 TYPE(pw_r3d_rs_type),
INTENT(IN) :: v
1700 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: density
1702 CHARACTER(LEN=*),
PARAMETER :: routinen =
'apply_poisson_operator_fft'
1705 TYPE(pw_r3d_rs_type) :: pxv
1707 CALL timeset(routinen, handle)
1709 CALL pw_pool%create_pw(pxv)
1711 CALL apply_p_operator(pw_pool, dielectric, v, pxv)
1712 CALL apply_laplace_operator_fft(pw_pool, green, v, density)
1713 CALL pw_axpy(pxv, density)
1715 CALL pw_pool%give_back_pw(pxv)
1717 CALL timestop(handle)
1719 END SUBROUTINE apply_poisson_operator_fft
1734 SUBROUTINE apply_poisson_operator_dct(pw_pool, green, dielectric, v, density)
1736 TYPE(pw_pool_type),
INTENT(IN),
POINTER :: pw_pool
1737 TYPE(greens_fn_type),
INTENT(IN) :: green
1738 TYPE(dielectric_type),
INTENT(IN),
POINTER :: dielectric
1739 TYPE(pw_r3d_rs_type),
INTENT(IN) :: v
1740 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: density
1742 CHARACTER(LEN=*),
PARAMETER :: routinen =
'apply_poisson_operator_dct'
1745 TYPE(pw_r3d_rs_type) :: pxv
1747 CALL timeset(routinen, handle)
1749 CALL pw_pool%create_pw(pxv)
1751 CALL apply_p_operator(pw_pool, dielectric, v, pxv)
1752 CALL apply_laplace_operator_dct(pw_pool, green, v, density)
1753 CALL pw_axpy(pxv, density)
1755 CALL pw_pool%give_back_pw(pxv)
1757 CALL timestop(handle)
1759 END SUBROUTINE apply_poisson_operator_dct
1775 SUBROUTINE ps_implicit_compute_veps(pw_pool, dielectric, v, v_eps)
1777 TYPE(pw_pool_type),
INTENT(IN),
POINTER :: pw_pool
1778 TYPE(dielectric_type),
INTENT(IN),
POINTER :: dielectric
1779 TYPE(pw_r3d_rs_type),
INTENT(IN) :: v
1780 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: v_eps
1782 CHARACTER(LEN=*),
PARAMETER :: routinen =
'ps_implicit_compute_veps'
1784 INTEGER :: handle, i
1786 TYPE(pw_r3d_rs_type) :: dv2
1787 TYPE(pw_r3d_rs_type),
DIMENSION(3) :: dv
1789 CALL timeset(routinen, handle)
1793 CALL pw_pool%create_pw(dv2)
1795 CALL pw_pool%create_pw(dv(i))
1798 CALL derive_fft(v, dv, pw_pool)
1801 dv2%array = dv(1)%array**2 + dv(2)%array**2 + dv(3)%array**2
1803 v_eps%array = -(1.0_dp/eightpi)*(dv2%array*dielectric%deps_drho%array)
1805 CALL pw_pool%give_back_pw(dv2)
1807 CALL pw_pool%give_back_pw(dv(i))
1810 CALL timestop(handle)
1812 END SUBROUTINE ps_implicit_compute_veps
1823 SUBROUTINE compute_ehartree_periodic_bc(density, v, ehartree)
1825 TYPE(pw_r3d_rs_type),
INTENT(IN) :: density, v
1826 REAL(dp),
INTENT(OUT) :: ehartree
1828 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_ehartree_periodic_bc'
1832 CALL timeset(routinen, handle)
1835 ehartree = 0.5_dp*pw_integral_ab(density, v)
1837 CALL timestop(handle)
1839 END SUBROUTINE compute_ehartree_periodic_bc
1854 SUBROUTINE compute_ehartree_mixed_bc(dielectric, density, Btxlambda, v, ehartree, electric_enthalpy)
1856 TYPE(dielectric_type),
INTENT(IN),
POINTER :: dielectric
1857 TYPE(pw_r3d_rs_type),
INTENT(IN) :: density
1858 REAL(dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
1859 INTENT(IN) :: btxlambda
1860 TYPE(pw_r3d_rs_type),
INTENT(IN) :: v
1861 REAL(dp),
INTENT(OUT) :: ehartree, electric_enthalpy
1863 CHARACTER(LEN=*),
PARAMETER :: routinen =
'compute_ehartree_mixed_bc'
1866 REAL(dp) :: dvol, ehartree_rho, ehartree_rho_cstr
1867 TYPE(pw_grid_type),
POINTER :: pw_grid
1869 CALL timeset(routinen, handle)
1871 pw_grid => v%pw_grid
1878 ehartree_rho = accurate_sum(density%array*v%array)
1879 ehartree_rho_cstr = accurate_sum(dielectric%eps%array*btxlambda*v%array/fourpi)
1880 ehartree_rho = 0.5_dp*ehartree_rho*dvol
1881 ehartree_rho_cstr = 0.5_dp*ehartree_rho_cstr*dvol
1882 CALL pw_grid%para%group%sum(ehartree_rho)
1883 CALL pw_grid%para%group%sum(ehartree_rho_cstr)
1884 electric_enthalpy = ehartree_rho + ehartree_rho_cstr
1885 ehartree = ehartree_rho - ehartree_rho_cstr
1887 CALL timestop(handle)
1889 END SUBROUTINE compute_ehartree_mixed_bc
1906 SUBROUTINE ps_implicit_compute_error_fft(pw_pool, green, res_new, v_old, v_new, &
1907 QAinvxres_new, pres_error, nabs_error)
1909 TYPE(pw_pool_type),
INTENT(IN),
POINTER :: pw_pool
1910 TYPE(greens_fn_type),
INTENT(IN) :: green
1911 TYPE(pw_r3d_rs_type),
INTENT(IN) :: res_new, v_old, v_new
1912 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: qainvxres_new
1913 REAL(dp),
INTENT(OUT) :: pres_error, nabs_error
1915 CHARACTER(LEN=*),
PARAMETER :: routinen =
'ps_implicit_compute_error_fft'
1920 CALL timeset(routinen, handle)
1922 vol = pw_pool%pw_grid%vol
1925 CALL apply_inv_laplace_operator_fft(pw_pool, green, res_new, qainvxres_new)
1927 pres_error = accurate_sum(qainvxres_new%array(:, :, :)**2)
1928 CALL pw_pool%pw_grid%para%group%sum(pres_error)
1929 pres_error = sqrt(pres_error)/vol
1933 nabs_error = accurate_sum(abs(v_old%array - v_new%array)**2)
1934 CALL pw_pool%pw_grid%para%group%sum(nabs_error)
1935 nabs_error = sqrt(nabs_error)/vol
1937 CALL timestop(handle)
1939 END SUBROUTINE ps_implicit_compute_error_fft
1957 SUBROUTINE ps_implicit_compute_error_dct(pw_pool, green, res_new, v_old, v_new, &
1958 QAinvxres_new, pres_error, nabs_error)
1960 TYPE(pw_pool_type),
INTENT(IN),
POINTER :: pw_pool
1961 TYPE(greens_fn_type),
INTENT(IN) :: green
1962 TYPE(pw_r3d_rs_type),
INTENT(IN) :: res_new, v_old, v_new
1963 TYPE(pw_r3d_rs_type),
INTENT(INOUT) :: qainvxres_new
1964 REAL(dp),
INTENT(OUT) :: pres_error, nabs_error
1966 CHARACTER(LEN=*),
PARAMETER :: routinen =
'ps_implicit_compute_error_dct'
1971 CALL timeset(routinen, handle)
1973 vol = pw_pool%pw_grid%vol
1976 CALL apply_inv_laplace_operator_dct(pw_pool, green, res_new, qainvxres_new)
1978 pres_error = accurate_sum(qainvxres_new%array(:, :, :)**2)
1979 CALL pw_pool%pw_grid%para%group%sum(pres_error)
1980 pres_error = sqrt(pres_error)/vol
1984 nabs_error = accurate_sum(abs(v_old%array - v_new%array)**2)
1985 CALL pw_pool%pw_grid%para%group%sum(nabs_error)
1986 nabs_error = sqrt(nabs_error)/vol
1988 CALL timestop(handle)
1990 END SUBROUTINE ps_implicit_compute_error_dct
2002 SUBROUTINE ps_implicit_output(iter, pres_error, nabs_error, outp_unit)
2004 INTEGER,
INTENT(IN) :: iter
2005 REAL(dp),
INTENT(IN) :: pres_error, nabs_error
2006 INTEGER,
INTENT(OUT) :: outp_unit
2008 CHARACTER(LEN=*),
PARAMETER :: routinen =
'ps_implicit_output'
2009 INTEGER,
PARAMETER :: low_print_level = 1
2012 TYPE(cp_logger_type),
POINTER :: logger
2014 CALL timeset(routinen, handle)
2016 logger => cp_get_default_logger()
2017 IF (logger%para_env%is_source())
THEN
2018 outp_unit = cp_logger_get_default_unit_nr(logger, local=.true.)
2023 IF (logger%iter_info%print_level > low_print_level)
THEN
2024 IF ((outp_unit > 0) .AND. (iter == 1))
THEN
2025 WRITE (outp_unit,
'(T3,A)') &
2026 "POISSON| iter pres error nabs error E_hartree delta E"
2029 IF (outp_unit > 0)
THEN
2030 WRITE (outp_unit,
'(T3,A,I6,5X,E13.4,3X,E13.4)', advance=
'NO') &
2031 "POISSON| ", iter, pres_error, nabs_error
2035 CALL timestop(handle)
2037 END SUBROUTINE ps_implicit_output
2048 SUBROUTINE ps_implicit_report_ehartree(ps_implicit_env, outp_unit, ehartree)
2050 TYPE(ps_implicit_type) :: ps_implicit_env
2051 INTEGER,
INTENT(IN) :: outp_unit
2052 REAL(dp),
INTENT(IN) :: ehartree
2054 CHARACTER(LEN=*),
PARAMETER :: routinen =
'ps_implicit_report_ehartree'
2055 INTEGER,
PARAMETER :: low_print_level = 1
2058 TYPE(cp_logger_type),
POINTER :: logger
2060 logger => cp_get_default_logger()
2061 CALL timeset(routinen, handle)
2062 IF (logger%iter_info%print_level > low_print_level)
THEN
2063 IF (outp_unit > 0)
WRITE (outp_unit,
'(F19.10,E10.2)') &
2064 ehartree, ehartree - ps_implicit_env%ehartree
2066 CALL timestop(handle)
2068 END SUBROUTINE ps_implicit_report_ehartree
2079 SUBROUTINE ps_implicit_print_convergence_msg(iter, max_iter, outp_unit)
2081 INTEGER,
INTENT(IN) :: iter, max_iter, outp_unit
2083 CHARACTER(LEN=*),
PARAMETER :: routinen =
'ps_implicit_print_convergence_msg'
2085 CHARACTER(LEN=12) :: msg
2086 INTEGER :: handle, last_iter
2088 CALL timeset(routinen, handle)
2090 last_iter = iter - 1
2092 IF (outp_unit > 0)
THEN
2093 IF (last_iter == max_iter)
THEN
2094 WRITE (outp_unit,
'(T3,A)') &
2095 "POISSON| No convergence achieved within the maximum number of iterations."
2097 IF (last_iter < max_iter)
THEN
2098 IF (last_iter == 1)
THEN
2101 msg =
" iterations."
2103 WRITE (outp_unit,
'(T3,A,I0,A)') &
2104 "POISSON| Poisson solver converged in ", last_iter, msg
2107 CALL timestop(handle)
2109 END SUBROUTINE ps_implicit_print_convergence_msg
2117 SUBROUTINE convert_1dto3d(idx_1dto3d, arr1d, arr3d)
2119 INTEGER,
DIMENSION(:),
INTENT(IN) :: idx_1dto3d
2120 REAL(dp),
DIMENSION(:),
INTENT(IN) :: arr1d
2121 REAL(dp),
ALLOCATABLE,
DIMENSION(:, :, :), &
2122 INTENT(INOUT) :: arr3d
2124 CHARACTER(LEN=*),
PARAMETER :: routinen =
'convert_1dto3d'
2126 INTEGER :: handle, i, j, k, l, lb1, lb2, lb3, &
2127 npts1, npts2, npts3, ub1, ub2, ub3
2129 CALL timeset(routinen, handle)
2131 lb1 = lbound(arr3d, 1); ub1 = ubound(arr3d, 1)
2132 lb2 = lbound(arr3d, 2); ub2 = ubound(arr3d, 2)
2133 lb3 = lbound(arr3d, 3); ub3 = ubound(arr3d, 3)
2135 npts1 = ub1 - lb1 + 1
2136 npts2 = ub2 - lb2 + 1
2137 npts3 = ub3 - lb3 + 1
2139 DO l = 1,
SIZE(idx_1dto3d)
2140 k = ((idx_1dto3d(l) - 1)/(npts1*npts2)) + lb3
2141 j = ((idx_1dto3d(l) - 1) - (k - lb3)*npts1*npts2)/npts1 + lb2
2142 i = idx_1dto3d(l) - ((j - lb2)*npts1 + (k - lb3)*npts1*npts2) + lb1 - 1
2143 arr3d(i, j, k) = arr1d(l)
2146 CALL timestop(handle)
2148 END SUBROUTINE convert_1dto3d
2159 SUBROUTINE get_voltage(time, v_D, osc_frac, frequency, phase, v_D_new)
2161 REAL(dp),
INTENT(IN) :: time
2162 REAL(dp),
DIMENSION(:),
INTENT(IN) :: v_d, osc_frac, frequency, phase
2163 REAL(dp),
ALLOCATABLE,
DIMENSION(:),
INTENT(OUT) :: v_d_new
2165 CHARACTER(LEN=*),
PARAMETER :: routinen =
'get_voltage'
2167 INTEGER :: handle, i
2169 CALL timeset(routinen, handle)
2171 ALLOCATE (v_d_new(
SIZE(v_d)))
2174 v_d_new(i) = v_d(i)*(1 - osc_frac(i)) + &
2175 v_d(i)*osc_frac(i)*cos(2*pi*time*frequency(i) + phase(i))
2178 CALL timestop(handle)
2180 END SUBROUTINE get_voltage
static void dgemm(const char transa, const char transb, const int m, const int n, const int k, const double alpha, const double *a, const int lda, const double *b, const int ldb, const double beta, double *c, const int ldc)
Convenient wrapper to hide Fortran nature of dgemm_, swapping a and b.
collects all references to literature in CP2K as new algorithms / method are included from literature...
integer, save, public banihashemian2016
various routines to log and control the output. The idea is that decisions about where to log should ...
recursive integer function, public cp_logger_get_default_unit_nr(logger, local, skip_not_ionode)
asks the default unit number of the given logger. try to use cp_logger_get_unit_nr
type(cp_logger_type) function, pointer, public cp_get_default_logger()
returns the default logger
the type I Discrete Cosine Transform (DCT-I)
integer, parameter, public neumannx
integer, parameter, public neumannxy
subroutine, public dct_type_init(pw_grid, neumann_directions, dct_env)
Initializes a dct_type.
integer, parameter, public neumannxz
subroutine, public pw_shrink(neumann_directions, dests_shrink, srcs_shrink, bounds_local_shftd, pw_in, pw_shrinked)
shrinks an evenly symmetric pw_r3d_rs_type data to a pw_r3d_rs_type data that is 8 times smaller (the...
integer, parameter, public neumannxyz
integer, parameter, public neumannz
integer, parameter, public neumannyz
integer, parameter, public neumanny
subroutine, public pw_expand(neumann_directions, recv_msgs_bnds, dests_expand, srcs_expand, flipg_stat, bounds_shftd, pw_in, pw_expanded)
expands a pw_r3d_rs_type data to an evenly symmetric pw_r3d_rs_type data that is 8 times larger than ...
methods for evaluating the dielectric constant
subroutine, public dielectric_create(dielectric, pw_pool, dielectric_params)
allocates memory for a dielectric data type
subroutine, public derive_fft(f, df, pw_pool)
computes the derivative of a function using FFT
dielectric constant data type
subroutines for defining and creating Dirichlet type subdomains
subroutine, public dirichlet_boundary_region_setup(pw_pool, poisson_params, dbcs)
Sets up the Dirichlet boundary condition.
Dirichlet boundary condition data types.
subroutine, public dbc_tile_release(dbc, pw_pool)
releases tiles
sums arrays of real/complex numbers with much reduced round-off as compared to a naive implementation...
Defines the basic variable types.
integer, parameter, public int_8
integer, parameter, public dp
Definition of mathematical constants and functions.
real(kind=dp), parameter, public pi
real(kind=dp), parameter, public fourpi
The implicit (generalized) Poisson solver.
subroutine, public implicit_poisson_solver_periodic(poisson_env, density, v_new, ehartree)
implicit Poisson solver for periodic boundary conditions
subroutine, public implicit_poisson_solver_mixed(poisson_env, density, v_new, electric_enthalpy)
implicit Poisson solver for mixed boundary conditions (Neumann + Dirichlet)
subroutine, public implicit_poisson_solver_neumann(poisson_env, density, v_new, ehartree)
implicit Poisson solver: zero-average solution of the Poisson equation subject to homogeneous Neumann...
subroutine, public implicit_poisson_solver_mixed_periodic(poisson_env, density, v_new, electric_enthalpy)
implicit Poisson solver for mixed-periodic boundary conditions (periodic + Dirichlet)
subroutine, public ps_implicit_create(pw_pool, poisson_params, dct_pw_grid, green, ps_implicit_env)
Creates implicit Poisson solver environment.
Types containing essential information for running implicit (iterative) Poisson solver.
integer, parameter, public neumann_bc
integer, parameter, public mixed_bc
integer, parameter, public mixed_periodic_bc
integer, parameter, public periodic_bc
functions related to the poisson solver on regular grids
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...
subroutine, public pw_pool_release(pool)
releases the given pool (see cp2k/doc/ReferenceCounting.html)
subroutine, public pw_pool_create(pool, pw_grid, max_cache)
creates a pool for pw
type of a logger, at the moment it contains just a print level starting at which level it should be l...
contains all the informations needed by the fft based poisson solvers
parameters for the poisson solver independet of input_section
environment for the poisson solver
Manages a pool of grids (to be used for example as tmp objects), but can also be used to instantiate ...