ddx 0.6.0
Libary for domain-decomposition methods for polarizable continuum models
ddx_legacy.f90
1
4use ddx
5implicit none
6
7contains
8
25subroutine mkrhs(params, constants, workspace, phi_flag, phi_cav, grad_flag, &
26 & gradphi_cav, hessian_flag, hessianphi_cav, psi, charges)
27 use ddx_core
28 implicit none
29 type(ddx_params_type), intent(in) :: params
30 type(ddx_workspace_type), intent(inout) :: workspace
31 type(ddx_constants_type), intent(in) :: constants
32 integer, intent(in) :: phi_flag, grad_flag, hessian_flag
33 real(dp), intent(out) :: phi_cav(constants % ncav)
34 real(dp), intent(out) :: gradphi_cav(3, constants % ncav)
35 real(dp), intent(out) :: hessianphi_cav(3, 3, constants % ncav)
36 real(dp), intent(out) :: psi(constants % nbasis, &
37 & params % nsph)
38 real(dp), intent(in) :: charges(params % nsph)
39 ! Local variables
40 integer :: isph, igrid, icav, inode, jnear, jnode, jsph, i
41 real(dp) :: d(3), v, tmpv, r, gradv(3), hessianv(3, 3), tmpd(3)
42 real(dp), allocatable :: grid_grad(:,:,:), grid_hessian(:,:,:,:), &
43 & grid_hessian2(:,:,:)
44 real(dp), external :: dnrm2
45
46 write(6, *) "Warning: subroutine mkrhs is deprecated"
47
48 if (grad_flag .eq. 1) allocate(grid_grad(params % ngrid, 3, &
49 & params % nsph))
50 if (hessian_flag .eq. 1) allocate(grid_hessian(params % ngrid, &
51 & 3, 3, params % nsph), grid_hessian2(params % ngrid, &
52 & 3, params % nsph))
53
54 ! In case FMM is disabled compute phi and gradphi at cavity points by a
55 ! naive double loop of a quadratic complexity
56 if (params % fmm .eq. 0) then
57 do icav = 1, constants % ncav
58 v = zero
59 gradv = zero
60 hessianv = zero
61 do isph = 1, params % nsph
62 d = constants % ccav(:, icav) - &
63 & params % csph(:, isph)
64 r = dnrm2(3, d, 1)
65 d = d / r
66 tmpv = charges(isph) / r
67 v = v + tmpv
68 tmpv = tmpv / r
69 tmpd = tmpv * d
70 tmpv = tmpv / r
71 gradv = gradv - tmpd
72 tmpd = three / r * tmpd
73 hessianv(:, 1) = hessianv(:, 1) + tmpd*d(1)
74 hessianv(:, 2) = hessianv(:, 2) + tmpd*d(2)
75 hessianv(:, 3) = hessianv(:, 3) + tmpd*d(3)
76 hessianv(1, 1) = hessianv(1, 1) - tmpv
77 hessianv(2, 2) = hessianv(2, 2) - tmpv
78 hessianv(3, 3) = hessianv(3, 3) - tmpv
79 end do
80 if (phi_flag .eq. 1) then
81 phi_cav(icav) = v
82 end if
83 if (grad_flag .eq. 1) then
84 gradphi_cav(:, icav) = gradv
85 end if
86 if (hessian_flag .eq. 1) then
87 hessianphi_cav(:, :, icav) = hessianv
88 end if
89 end do
90 ! Use the FMM otherwise
91 else
92 ! P2M step from centers of harmonics
93 do isph = 1, params % nsph
94 inode = constants % snode(isph)
95 workspace % tmp_sph(1, isph) = &
96 & charges(isph) &
97 & / params % rsph(isph) / sqrt4pi
98 workspace % tmp_sph(2:, isph) = zero
99 workspace % tmp_node_m(1, inode) = &
100 & workspace % tmp_sph(1, isph)
101 workspace % tmp_node_m(2:, inode) = zero
102 end do
103 ! M2M, M2L and L2L translations
104
105 call tree_m2m_rotation(params, constants, &
106 & workspace % tmp_node_m)
107
108 call tree_m2l_rotation(params, constants, &
109 & workspace % tmp_node_m, workspace % tmp_node_l)
110
111 call tree_l2l_rotation(params, constants, &
112 & workspace % tmp_node_l)
113
114 call tree_l2p(params, constants, one, &
115 & workspace % tmp_node_l, zero, &
116 & workspace % tmp_grid, workspace % tmp_sph_l)
117
118 call tree_m2p(params, constants, &
119 & params % lmax, one, workspace % tmp_sph, &
120 & one, workspace % tmp_grid)
121
122 ! Potential from each sphere to its own grid points
123 call dgemm('T', 'N', params % ngrid, params % nsph, &
124 & constants % nbasis, one, constants % vgrid2, &
125 & constants % vgrid_nbasis, workspace % tmp_sph, &
126 & constants % nbasis, one, workspace % tmp_grid, &
127 & params % ngrid)
128
129 ! Rearrange potential from all grid points to external only
130 if (phi_flag.eq.1) then
131 icav = 0
132 do isph = 1, params % nsph
133 do igrid = 1, params % ngrid
134 ! Do not count internal grid points
135 if(constants % ui(igrid, isph) .eq. zero) cycle
136 icav = icav + 1
137 phi_cav(icav) = workspace % tmp_grid(igrid, isph)
138 end do
139 end do
140 end if
141
142 ! Now compute near-field FMM gradients and hessians
143 ! Cycle over all spheres
144 if (grad_flag.eq.1 .or. hessian_flag.eq.1) then
145 if (grad_flag.eq.1) grid_grad(:, :, :) = zero
146 if (hessian_flag.eq.1) grid_hessian(:, :, :, :) = zero
147 !$omp parallel do default(none) shared(params,constants,workspace, &
148 !$omp grid_grad,grid_hessian,grad_flag,hessian_flag,charges) &
149 !$omp private(isph,igrid,inode,jnear,jnode,jsph,d,r,tmpd,tmpv) &
150 !$omp schedule(dynamic)
151 do isph = 1, params % nsph
152 ! Cycle over all external grid points
153 do igrid = 1, params % ngrid
154 if(constants % ui(igrid, isph) .eq. zero) cycle
155 ! Cycle over all near-field admissible pairs of spheres,
156 ! including pair (isph, isph) which is a self-interaction
157 inode = constants % snode(isph)
158 do jnear = constants % snear(inode), &
159 & constants % snear(inode+1) - 1
160 ! Near-field interactions are possible only between leaf
161 ! nodes, which must contain only a single input sphere
162 jnode = constants % near(jnear)
163 jsph = constants % order( &
164 & constants % cluster(1, jnode))
165 d = params % csph(:, isph) + &
166 & constants % cgrid(:, igrid) &
167 & *params % rsph(isph) &
168 & - params % csph(:, jsph)
169! r = dnrm2(3, d, 1)
170 r = sqrt(d(1)*d(1) + d(2)*d(2) + d(3)*d(3))
171 d = d / r / r
172 tmpv = charges(jsph) / r
173 if (grad_flag.eq.1) grid_grad(igrid, :, isph) = &
174 & grid_grad(igrid, :, isph) - tmpv * d
175 tmpd = three * tmpv * d
176 tmpv = tmpv / r / r
177 if (hessian_flag.eq.1) then
178 grid_hessian(igrid, 1, :, isph) = &
179 & grid_hessian(igrid, 1, :, isph) + d(1)*tmpd
180 grid_hessian(igrid, 2, :, isph) = &
181 & grid_hessian(igrid, 2, :, isph) + d(2)*tmpd
182 grid_hessian(igrid, 3, :, isph) = &
183 & grid_hessian(igrid, 3, :, isph) + d(3)*tmpd
184 grid_hessian(igrid, 1, 1, isph) = &
185 & grid_hessian(igrid, 1, 1, isph) - tmpv
186 grid_hessian(igrid, 2, 2, isph) = &
187 & grid_hessian(igrid, 2, 2, isph) - tmpv
188 grid_hessian(igrid, 3, 3, isph) = &
189 & grid_hessian(igrid, 3, 3, isph) - tmpv
190 end if
191 end do
192 end do
193 end do
194 end if
195
196 ! Take into account far-field FMM gradients only if pl > 0
197 if ((params % pl .gt. 0) .and. (grad_flag.eq.1)) then
198 ! Get gradient of L2L
199 call tree_grad_l2l(params, constants, &
200 & workspace % tmp_node_l, &
201 & workspace % tmp_sph_l_grad, &
202 & workspace % tmp_sph_l)
203 ! Apply L2P for every axis with -1 multiplier since grad over
204 ! target point is equal to grad over source point
205 call dgemm('T', 'N', params % ngrid, &
206 & 3*params % nsph, (params % pl)**2, &
207 & -one, constants % vgrid2, &
208 & constants % vgrid_nbasis, &
209 & workspace % tmp_sph_l_grad, &
210 & (params % pl+1)**2, one, grid_grad, &
211 & params % ngrid)
212 end if
213 ! Take into account far-field FMM hessians only if pl > 1
214 if ((params % pl .gt. 1) .and. (hessian_flag.eq.1)) then
215 do i = 1, 3
216 ! Load previously computed gradient into leaves, since
217 ! tree_grad_l2l currently takes local expansions of entire
218 ! tree. In future it might be changed.
219 do isph = 1, params % nsph
220 inode = constants % snode(isph)
221 workspace % tmp_node_l(:, inode) = &
222 & workspace % tmp_sph_l_grad(:, i, isph)
223 end do
224 ! Get gradient of a gradient of L2L. Currently this uses input
225 ! pl maximal degree of local harmonics but in reality we need
226 ! only pl-1 maximal degree since coefficients of harmonics of a
227 ! degree pl are zeros.
228 call tree_grad_l2l(params, constants, &
229 & workspace % tmp_node_l, &
230 & workspace % tmp_sph_l_grad2, &
231 & workspace % tmp_sph_l)
232 ! Apply L2P for every axis
233 call dgemm('T', 'N', params % ngrid, &
234 & 3*params % nsph, (params % pl-1)**2, &
235 & one, constants % vgrid2, &
236 & constants % vgrid_nbasis, &
237 & workspace % tmp_sph_l_grad2, &
238 & (params % pl+1)**2, zero, grid_hessian2, &
239 & params % ngrid)
240 ! Properly copy hessian
241 grid_hessian(:, i, :, :) = grid_hessian(:, i, :, :) + grid_hessian2
242 end do
243 end if
244
245 ! Copy output for external grid points only
246 icav = 0
247 do isph = 1, params % nsph
248 do igrid = 1, params % ngrid
249 if(constants % ui(igrid, isph) .eq. zero) cycle
250 icav = icav + 1
251 if (grad_flag .eq. 1) gradphi_cav(:, icav) = &
252 & grid_grad(igrid, :, isph)
253 if (hessian_flag .eq. 1) hessianphi_cav(:, :, icav) = &
254 & grid_hessian(igrid, :, :, isph)
255 end do
256 end do
257 end if
258
259 ! Vector psi
260 psi(2:, :) = zero
261 do isph = 1, params % nsph
262 psi(1, isph) = sqrt4pi * charges(isph)
263 end do
264
265 ! deallocate temporary
266 if (grad_flag .eq. 1) deallocate(grid_grad)
267 if (hessian_flag .eq. 1) deallocate(grid_hessian, grid_hessian2)
268end subroutine mkrhs
269
285subroutine ddsolve_legacy(ddx_data, state, phi_cav, e_cav, hessianphi_cav, &
286 & psi, tol, esolv, force, ddx_error)
287 ! Inputs
288 type(ddx_type), intent(inout) :: ddx_data
289 type(ddx_state_type), intent(inout) :: state
290 real(dp), intent(in) :: phi_cav(ddx_data % constants % ncav), &
291 & e_cav(3, ddx_data % constants % ncav), &
292 & hessianphi_cav(3, ddx_data % constants % ncav), &
293 & psi(ddx_data % constants % nbasis, ddx_data % params % nsph), tol
294 ! Outputs
295 real(dp), intent(out) :: esolv, force(3, ddx_data % params % nsph)
296 type(ddx_error_type), intent(inout) :: ddx_error
297
298 write(6, *) "Warning: subroutine ddsolve_legacy is deprecated"
299
300 ! Find proper model
301 select case(ddx_data % params % model)
302 ! COSMO model
303 case (1)
304 call ddcosmo(ddx_data % params, ddx_data % constants, &
305 & ddx_data % workspace, state, phi_cav, psi, e_cav, &
306 & tol, esolv, force, ddx_error)
307 ! PCM model
308 case (2)
309 call ddpcm(ddx_data % params, ddx_data % constants, &
310 & ddx_data % workspace, state, phi_cav, psi, e_cav, &
311 & tol, esolv, force, ddx_error)
312 ! LPB model
313 case (3)
314 call ddlpb(ddx_data % params, ddx_data % constants, &
315 & ddx_data % workspace, state, phi_cav, e_cav, &
316 & psi, tol, esolv, hessianphi_cav, force, ddx_error)
317 ! Error case
318 case default
319 call update_error(ddx_error, "unsupported solvation " // &
320 & " model in the dd solver.")
321 return
322 end select
323end subroutine ddsolve_legacy
324
342subroutine ddcosmo(params, constants, workspace, state, phi_cav, &
343 & psi, e_cav, tol, esolv, force, ddx_error)
344 implicit none
345 type(ddx_params_type), intent(in) :: params
346 type(ddx_constants_type), intent(in) :: constants
347 type(ddx_workspace_type), intent(inout) :: workspace
348 type(ddx_state_type), intent(inout) :: state
349 real(dp), intent(in) :: phi_cav(constants % ncav), &
350 & psi(constants % nbasis, params % nsph), tol
351 real(dp), intent(out) :: esolv
352 real(dp), intent(in) :: e_cav(3, constants % ncav)
353 real(dp), intent(out), optional :: force(3, params % nsph)
354 type(ddx_error_type), intent(inout) :: ddx_error
355
356 write(6, *) "Warning: subroutine ddcosmo is deprecated"
357
358 call cosmo_setup(params, constants, workspace, state, phi_cav, psi, ddx_error)
359 if (ddx_error % flag .ne. 0) then
360 call update_error(ddx_error, &
361 & "ddlpb: ddcosmo_setup returned an error, exiting")
362 return
363 end if
364 call cosmo_guess(params, constants, workspace, state, ddx_error)
365 if (ddx_error % flag .ne. 0) then
366 call update_error(ddx_error, &
367 & "ddlpb: ddcosmo_guess returned an error, exiting")
368 return
369 end if
370 call cosmo_solve(params, constants, workspace, state, tol, ddx_error)
371 if (ddx_error % flag .ne. 0) then
372 call update_error(ddx_error, &
373 & "ddlpb: ddcosmo_solve returned an error, exiting")
374 return
375 end if
376
377 call cosmo_energy(constants, state, esolv, ddx_error)
378
379 ! Get forces if needed
380 if (params % force .eq. 1) then
381 ! solve the adjoint
382 call cosmo_guess_adjoint(params, constants, workspace, state, ddx_error)
383 if (ddx_error % flag .ne. 0) then
384 call update_error(ddx_error, &
385 & "ddlpb: ddcosmo_guess_adjoint returned an error, exiting")
386 return
387 end if
388 call cosmo_solve_adjoint(params, constants, workspace, state, tol, &
389 & ddx_error)
390 if (ddx_error % flag .ne. 0) then
391 call update_error(ddx_error, &
392 & "ddlpb: ddcosmo_guess_adjoint returned an error, exiting")
393 return
394 end if
395
396 ! evaluate the solvent unspecific contribution analytical derivatives
397 force = zero
398 call cosmo_solvation_force_terms(params, constants, workspace, &
399 & state, e_cav, force, ddx_error)
400 end if
401end subroutine ddcosmo
402
420subroutine ddpcm(params, constants, workspace, state, phi_cav, &
421 & psi, e_cav, tol, esolv, force, ddx_error)
422 implicit none
423 type(ddx_params_type), intent(in) :: params
424 type(ddx_constants_type), intent(in) :: constants
425 type(ddx_workspace_type), intent(inout) :: workspace
426 type(ddx_state_type), intent(inout) :: state
427 type(ddx_error_type), intent(inout) :: ddx_error
428 real(dp), intent(in) :: phi_cav(constants % ncav), &
429 & psi(constants % nbasis, params % nsph), tol
430 real(dp), intent(out) :: esolv
431 real(dp), intent(in) :: e_cav(3, constants % ncav)
432 real(dp), intent(out), optional :: force(3, params % nsph)
433
434 write(6, *) "Warning: subroutine ddpcm is deprecated"
435
436 call pcm_setup(params, constants, workspace, state, phi_cav, psi, ddx_error)
437 if (ddx_error % flag .ne. 0) then
438 call update_error(ddx_error, &
439 & "ddlpb: ddpcm_setup returned an error, exiting")
440 return
441 end if
442 call pcm_guess(params, constants, workspace, state, ddx_error)
443 if (ddx_error % flag .ne. 0) then
444 call update_error(ddx_error, &
445 & "ddlpb: ddpcm_guess returned an error, exiting")
446 return
447 end if
448 call pcm_solve(params, constants, workspace, state, tol, ddx_error)
449 if (ddx_error % flag .ne. 0) then
450 call update_error(ddx_error, &
451 & "ddlpb: ddpcm_solve returned an error, exiting")
452 return
453 end if
454
455 call pcm_energy(constants, state, esolv, ddx_error)
456
457 ! Get forces if needed
458 if (params % force .eq. 1) then
459 ! solve the adjoint
460 call pcm_guess_adjoint(params, constants, workspace, state, ddx_error)
461 if (ddx_error % flag .ne. 0) then
462 call update_error(ddx_error, &
463 & "ddlpb: ddpcm_guess_adjoint returned an error, exiting")
464 return
465 end if
466 call pcm_solve_adjoint(params, constants, workspace, state, &
467 & tol, ddx_error)
468 if (ddx_error % flag .ne. 0) then
469 call update_error(ddx_error, &
470 & "ddlpb: ddpcm_guess_adjoint returned an error, exiting")
471 return
472 end if
473
474 ! evaluate the solvent unspecific contribution analytical derivatives
475 force = zero
476 call pcm_solvation_force_terms(params, constants, workspace, &
477 & state, e_cav, force, ddx_error)
478 end if
479
480end subroutine ddpcm
481
499subroutine ddlpb(params, constants, workspace, state, phi_cav, e_cav, &
500 & psi, tol, esolv, hessianphi_cav, force, ddx_error)
501 implicit none
502 type(ddx_params_type), intent(in) :: params
503 type(ddx_constants_type), intent(inout) :: constants
504 type(ddx_workspace_type), intent(inout) :: workspace
505 type(ddx_state_type), intent(inout) :: state
506 real(dp), intent(in) :: phi_cav(constants % ncav), &
507 & e_cav(3, constants % ncav), &
508 & psi( constants % nbasis, params % nsph), tol
509 real(dp), intent(out) :: esolv
510 real(dp), intent(out), optional :: force(3, params % nsph)
511 real(dp), intent(in), optional :: hessianphi_cav(3, 3, constants % ncav)
512 type(ddx_error_type), intent(inout) :: ddx_error
513
514 write(6, *) "Warning: subroutine ddlpb is deprecated"
515
516 call lpb_setup(params, constants, workspace, state, phi_cav, &
517 & e_cav, psi, ddx_error)
518 if (ddx_error % flag .ne. 0) then
519 call update_error(ddx_error, &
520 & "ddlpb: ddlpb_setup returned an error, exiting")
521 return
522 end if
523 call lpb_guess(params, constants, workspace, state, tol, ddx_error)
524 if (ddx_error % flag .ne. 0) then
525 call update_error(ddx_error, &
526 & "ddlpb: ddlpb_guess returned an error, exiting")
527 return
528 end if
529 call lpb_solve(params, constants, workspace, state, tol, ddx_error)
530 if (ddx_error % flag .ne. 0) then
531 call update_error(ddx_error, &
532 & "ddlpb: ddlpb_solve returned an error, exiting")
533 return
534 end if
535
536 ! Compute the solvation energy
537 call lpb_energy(constants, state, esolv, ddx_error)
538
539 ! Get forces if needed
540 if(params % force .eq. 1) then
541 call lpb_guess_adjoint(params, constants, workspace, state, tol, ddx_error)
542 if (ddx_error % flag .ne. 0) then
543 call update_error(ddx_error, &
544 & "ddlpb: ddlpb_guess_adjoint returned an error, exiting")
545 return
546 end if
547 call lpb_solve_adjoint(params, constants, workspace, state, tol, ddx_error)
548 if (ddx_error % flag .ne. 0) then
549 call update_error(ddx_error, &
550 & "ddlpb: ddlpb_solve_adjoint returned an error, exiting")
551 return
552 end if
553 call lpb_solvation_force_terms(params, constants, workspace, &
554 & state, hessianphi_cav, force, ddx_error)
555 endif
556
557end subroutine ddlpb
558
559
560end module ddx_legacy
subroutine ddcosmo(params, constants, workspace, state, phi_cav, psi, e_cav, tol, esolv, force, ddx_error)
ddCOSMO solver
Definition: ddx_legacy.f90:344
subroutine ddpcm(params, constants, workspace, state, phi_cav, psi, e_cav, tol, esolv, force, ddx_error)
ddPCM solver
Definition: ddx_legacy.f90:422
Core routines and parameters of the ddX software.
Definition: ddx_core.f90:13
subroutine tree_grad_l2l(params, constants, node_l, sph_l_grad, work)
TODO.
Definition: ddx_core.f90:2714
subroutine tree_l2l_rotation(params, constants, node_l)
Transfer local coefficients over a tree.
Definition: ddx_core.f90:1866
subroutine tree_m2m_rotation(params, constants, node_m)
Transfer multipole coefficients over a tree.
Definition: ddx_core.f90:1656
subroutine tree_l2p(params, constants, alpha, node_l, beta, grid_v, sph_l)
TODO.
Definition: ddx_core.f90:2252
subroutine tree_m2l_rotation(params, constants, node_m, node_l)
Transfer multipole local coefficients into local over a tree.
Definition: ddx_core.f90:2046
subroutine tree_m2p(params, constants, p, alpha, sph_m, beta, grid_v)
TODO.
Definition: ddx_core.f90:2401
Routines which are only used by the tests and should not be used by external software.
Definition: ddx_legacy.f90:3
High-level module of the ddX software.
Definition: ddx.f90:2