26 use,
intrinsic :: iso_fortran_env
89 integer,
parameter :: PCM_DIM_SPACE = 3
93 logical,
public :: run_pcm
94 integer,
public :: tdlevel
96 integer,
public :: n_tesserae
97 type(pcm_sphere_t),
allocatable :: spheres(:)
98 type(pcm_tessera_t),
allocatable,
public :: tess(:)
99 real(real64) :: scale_r
100 real(real64),
allocatable :: matrix(:,:)
101 real(real64),
allocatable :: matrix_d(:,:)
102 real(real64),
allocatable :: matrix_lf(:,:)
103 real(real64),
allocatable :: matrix_lf_d(:,:)
104 real(real64),
allocatable,
public :: q_e(:)
105 real(real64),
allocatable :: q_n(:)
106 real(real64),
allocatable,
public :: q_e_in(:)
107 real(real64),
allocatable :: rho_e(:)
108 real(real64),
allocatable :: rho_n(:)
109 real(real64) :: qtot_e
110 real(real64) :: qtot_n
111 real(real64) :: qtot_e_in
112 real(real64) :: q_e_nominal
113 real(real64) :: q_n_nominal
114 logical :: renorm_charges
115 real(real64) :: q_tot_tol
116 real(real64) :: deltaQ_e
117 real(real64) :: deltaQ_n
118 real(real64),
allocatable :: v_e(:)
119 real(real64),
allocatable :: v_n(:)
120 real(real64),
allocatable,
public :: v_e_rs(:)
121 real(real64),
allocatable,
public :: v_n_rs(:)
122 real(real64),
allocatable :: q_ext(:)
123 real(real64),
allocatable :: q_ext_in(:)
124 real(real64),
allocatable :: rho_ext(:)
125 real(real64) :: qtot_ext
126 real(real64) :: qtot_ext_in
127 real(real64),
allocatable :: v_ext(:)
128 real(real64),
allocatable,
public :: v_ext_rs(:)
129 real(real64),
allocatable :: q_kick(:)
130 real(real64),
allocatable :: rho_kick(:)
131 real(real64) :: qtot_kick
132 real(real64),
allocatable :: v_kick(:)
133 real(real64),
allocatable,
public :: v_kick_rs(:)
134 real(real64),
public :: epsilon_0
135 real(real64),
public :: epsilon_infty
136 integer,
public :: which_eps
137 type(debye_param_t) :: deb
138 type(drude_param_t) :: drl
139 logical,
public :: localf
140 logical,
public :: solute
141 logical :: kick_is_present
143 logical,
public :: kick_like
144 integer :: initial_asc
145 real(real64) :: gaussian_width
147 integer,
public :: counter
148 character(len=80) :: input_cavity
149 integer :: update_iter
150 integer,
public :: iter
151 integer :: calc_method
153 real(real64),
public :: dt
157 type(namespace_t),
pointer :: namespace
158 type(space_t) :: space
167 type(debye_param_t) :: deb
168 type(drude_param_t) :: drl
171 real(real64),
allocatable :: s_mat_act(:,:)
172 real(real64),
allocatable :: d_mat_act(:,:)
173 real(real64),
allocatable :: Sigma(:,:)
174 real(real64),
allocatable :: Delta(:,:)
176 logical :: gamess_benchmark
179 integer,
parameter :: &
184 integer,
parameter,
public :: &
188 integer,
parameter :: &
199 subroutine pcm_init(pcm, namespace, space, ions, grid, qtot, val_charge, external_potentials_present, kick_present)
205 real(real64),
intent(in) :: qtot
206 real(real64),
intent(in) :: val_charge
207 logical,
intent(in) :: external_potentials_present
208 logical,
intent(in) :: kick_present
210 integer :: ia, ii, itess, jtess, pcm_vdw_type, subdivider
211 integer :: cav_unit_test, iunit, pcmmat_unit
212 integer :: pcmmat_gamess_unit, cav_gamess_unit
213 real(real64) :: min_distance
215 integer,
parameter :: mxts = 10000
217 real(real64) :: default_value
218 real(real64) :: vdw_radius
223 logical :: add_spheres_h
224 logical :: changed_default_nn
226 integer :: default_nn
227 real(real64) :: max_area
231 pcm%kick_is_present = kick_present
236 pcm%kick_like = .false.
238 pcm%namespace => namespace
254 if (pcm%run_pcm)
then
256 if (pcm%space%dim /= pcm_dim_space)
then
257 message(1) =
"PCM is only available for 3d calculations"
260 select type (box => grid%box)
263 message(1) =
"PCM is only available for BoxShape = minimum"
287 select case (pcm_vdw_type)
289 default_value = 1.2_real64
291 default_value =
m_one
302 call parse_variable(namespace,
'PCMRadiusScaling', default_value, pcm%scale_r)
326 if (pcm%tdlevel /=
pcm_td_eq .and. (.not. pcm%run_pcm))
then
327 call messages_write(
'Sorry, you have set PCMTDLevel /= eq, but PCMCalculation = no.')
329 call messages_write(
'To spare you some time, Octopus will proceed as if PCMCalculation = yes.')
351 call parse_variable(namespace,
'PCMDynamicEpsilon', pcm%epsilon_0, pcm%epsilon_infty)
374 call messages_write(
'Sorry, only Debye or Drude-Lorentz dielectric models are available.')
376 call messages_write(
'To spare you some time, Octopus will proceed with the default choice (Debye).')
378 call messages_write(
'You may change PCMEpsilonModel value for a Drude-Lorentz run.')
383 call messages_write(
'Sorry, inertial/dynamic polarization splitting scheme for TD-PCM')
386 call messages_write(
'require both static and dynamic dielectric constants,')
389 call messages_write(
'Octopus will run using TD-PCM version in equilibrium')
409 call parse_variable(namespace,
'PCMEoMInitialCharges', 0, pcm%initial_asc)
412 if (pcm%initial_asc /= 0)
then
416 call messages_write(
'Sorry, initial polarization charges can only be read')
420 call messages_write(
'Octopus will proceed as if PCMEoMInitialCharges = 0.')
427 pcm%deb%eps_0 = pcm%epsilon_0
428 pcm%deb%eps_d = pcm%epsilon_infty
445 (abs(pcm%deb%tau) <=
m_epsilon .or.
is_close(pcm%deb%eps_0, pcm%deb%eps_d)))
then
447 call messages_write(
'but you have not included all required Debye model parameters.')
449 call messages_write(
'You need PCMEpsilonStatic, PCMEpsilonDynamic')
450 call messages_write(
'and PCMDebyeRelaxTime for an EOM TD-PCM run.')
452 call messages_write(
'Octopus will run using TD-PCM version in equilibrium')
460 message(1) =
"PCMEpsilonStatic = 1 is incompatible with a Drude-Lorentz EOM-PCM run."
479 call messages_write(
'but this is incompatible with a Drude-Lorentz EOM-PCM run.')
482 call messages_write(
'Octopus will run using the default value of PCMDrudeLOmega.')
486 message(1) =
"PCMEpsilonStatic = 1 is incompatible with a Drude-Lorentz EOM-PCM run."
503 pcm%drl%aa = (pcm%epsilon_0 -
m_one)*pcm%drl%w0**2
515 call parse_variable(namespace,
'PCMLocalField', .false., pcm%localf)
518 if (pcm%localf .and. ((.not. external_potentials_present) .and. (.not. pcm%kick_is_present)))
then
519 message(1) =
"Sorry, you have set PCMLocalField = yes, but you have not included any external potentials."
535 if (pcm%run_pcm .and. (.not. pcm%solute))
then
536 call messages_write(
'N.B. This PCM run do not consider the polarization effects due to the solute.')
538 if (.not. pcm%localf)
then
539 message(1) =
"You have activated a PCM run without polarization effects. Octopus will halt."
558 if (pcm%kick_like .and. (.not. pcm%run_pcm))
then
559 message(1) =
"PCMKick option can only be activated when PCMCalculation = yes. Octopus will halt."
563 if (pcm%kick_like .and. (.not. pcm%localf))
then
564 message(1) =
"PCMKick option can only be activated when a PCMLocalField = yes. Octopus will halt."
568 if (pcm%kick_like .and. (.not. pcm%kick_is_present))
then
569 message(1) =
"Sorry, you have set PCMKick = yes, but you have not included any kick."
573 if (pcm%kick_is_present .and. pcm%run_pcm .and. (.not. pcm%localf))
then
574 message(1) =
"You have set up a PCM calculation with a kick without local field effects."
575 message(2) =
"Please, reconsider if you want the kick to be relevant for the PCM run."
586 call parse_variable(namespace,
'PCMUpdateIter', 1, pcm%update_iter)
597 call parse_variable(namespace,
'PCMGamessBenchmark', .false., gamess_benchmark)
610 call parse_variable(namespace,
'PCMRenormCharges', .false., pcm%renorm_charges)
626 if (pcm%renorm_charges)
then
627 message(1) =
"Info: Polarization charges will be renormalized"
628 message(2) =
" if |Q_tot_PCM - Q_M| > PCMQtotTol"
644 if (abs(pcm%gaussian_width) <=
m_epsilon)
then
645 message(1) =
"Info: PCM potential will be defined in terms of polarization point charges"
648 message(1) =
"Info: PCM potential is regularized to avoid Coulomb singularity"
670 if (pcm%input_cavity ==
'')
then
679 call parse_variable(namespace,
'PCMSpheresOnH', .false., add_spheres_h)
683 do ia = 1, ions%natoms
684 if ((.not. add_spheres_h) .and. ions%atom(ia)%label ==
'H') cycle
685 pcm%n_spheres = pcm%n_spheres + 1
688 safe_allocate(pcm%spheres(1:pcm%n_spheres))
695 do ia = 1, ions%natoms
696 if ((.not. add_spheres_h) .and. ions%atom(ia)%label ==
'H') cycle
697 pcm%n_spheres = pcm%n_spheres + 1
700 pcm%spheres(pcm%n_spheres)%x = ions%pos(1, ia)
701 pcm%spheres(pcm%n_spheres)%y = ions%pos(2, ia)
702 pcm%spheres(pcm%n_spheres)%z = ions%pos(3, ia)
705 pcm%spheres(pcm%n_spheres)%r = vdw_radius*pcm%scale_r
709 pcm%info_unit =
io_open(
pcm_dir//
'pcm_info.out', pcm%namespace, action=
'write')
711 write(pcm%info_unit,
'(A35)')
'# Configuration: Molecule + Solvent'
712 write(pcm%info_unit,
'(A35)')
'# ---------------------------------'
713 write(pcm%info_unit,
'(A21,F12.3)')
'# Epsilon(Solvent) = ', pcm%epsilon_0
714 write(pcm%info_unit,
'(A1)')
'#'
715 write(pcm%info_unit,
'(A35,I4)')
'# Number of interlocking spheres = ', pcm%n_spheres
716 write(pcm%info_unit,
'(A1)')
'#'
718 write(pcm%info_unit,
'(A8,3X,A7,8X,A26,20X,A10)')
'# SPHERE',
'ELEMENT',
'CENTER (X,Y,Z) (A)',
'RADIUS (A)'
719 write(pcm%info_unit,
'(A8,3X,A7,4X,A43,7X,A10)')
'# ------',
'-------', &
720 '-------------------------------------------',
'----------'
724 do ia = 1, ions%natoms
725 if ((.not. add_spheres_h) .and. ions%atom(ia)%label ==
'H') cycle
726 pcm%n_spheres = pcm%n_spheres + 1
728 write(pcm%info_unit,
'(A1,2X,I3,7X,A2,3X,F14.8,2X,F14.8,2X,F14.8,4X,F14.8)')
'#', pcm%n_spheres, &
729 ions%atom(ia)%label, &
730 ions%pos(1, ia)*
p_a_b, &
731 ions%pos(2, ia)*
p_a_b, &
732 ions%pos(3, ia)*
p_a_b, &
733 pcm%spheres(pcm%n_spheres)%r*
p_a_b
745 call parse_variable(namespace,
'PCMTessSubdivider', 1, subdivider)
747 safe_allocate(dum2(1:subdivider*
n_tess_sphere*pcm%n_spheres))
757 call parse_variable(namespace,
'PCMTessMinDistance', 0.1_real64, min_distance)
761 call cav_gen(subdivider, min_distance, pcm%n_spheres, pcm%spheres, pcm%n_tesserae, dum2, pcm%info_unit)
763 safe_allocate(pcm%tess(1:pcm%n_tesserae))
765 do ia=1, pcm%n_tesserae
766 pcm%tess(ia)%point =
m_zero
767 pcm%tess(ia)%area =
m_zero
768 pcm%tess(ia)%r_sphere =
m_zero
769 pcm%tess(ia)%normal =
m_zero
772 pcm%tess = dum2(1:pcm%n_tesserae)
774 safe_deallocate_a(dum2)
776 message(1) =
"Info: van der Waals surface has been calculated"
782 iunit =
io_open(trim(pcm%input_cavity), pcm%namespace, action=
'read', status=
'old')
783 read(iunit,*) pcm%n_tesserae
785 if (pcm%n_tesserae > mxts)
then
786 write(
message(1),
'(a,I5,a,I5)')
"total number of tesserae", pcm%n_tesserae,
">", mxts
790 safe_allocate(pcm%tess(1:pcm%n_tesserae))
792 do ia = 1, pcm%n_tesserae
793 pcm%tess(ia)%point =
m_zero
794 pcm%tess(ia)%area =
m_zero
795 pcm%tess(ia)%r_sphere =
m_zero
796 pcm%tess(ia)%normal =
m_zero
799 do ia = 1, pcm%n_tesserae
800 read(iunit,*) pcm%tess(ia)%point(1)
803 do ia = 1, pcm%n_tesserae
804 read(iunit,*) pcm%tess(ia)%point(2)
807 do ia = 1, pcm%n_tesserae
808 read(iunit,*) pcm%tess(ia)%point(3)
811 do ia = 1, pcm%n_tesserae
812 read(iunit,*) pcm%tess(ia)%area
815 do ia = 1, pcm%n_tesserae
816 read(iunit,*) pcm%tess(ia)%r_sphere
819 do ia = 1, pcm%n_tesserae
820 read(iunit,*) pcm%tess(ia)%normal
824 message(1) =
"Info: van der Waals surface has been read from " // trim(pcm%input_cavity)
829 cav_unit_test =
io_open(
pcm_dir//
'cavity_mol.xyz', pcm%namespace, action=
'write')
831 write (cav_unit_test,
'(2X,I4)') pcm%n_tesserae + ions%natoms
832 write (cav_unit_test,
'(2X)')
834 do ia = 1, pcm%n_tesserae
835 write(cav_unit_test,
'(2X,A2,3X,4f15.8,3X,4f15.8,3X,4f15.8)')
'H', pcm%tess(ia)%point*
p_a_b
838 do ia = 1, ions%natoms
839 write(cav_unit_test,
'(2X,A2,3X,4f15.8,3X,4f15.8,3X,4f15.8)') ions%atom(ia)%label, &
840 ions%pos(:, ia)*
p_a_b
845 write(pcm%info_unit,
'(A1)')
'#'
847 write(pcm%info_unit,
'(A1,4X,A4,14X,A4,21X,A4,21X,A4,21X,A4,21X,A7,18X,A7,18X,A8,17X,A5,20X,A8,17X,A5,20X,A8,17X,A5)') &
848 '#',
'iter',
'E_ee',
'E_en',
'E_nn',
'E_ne',
'E_e_ext',
'E_n_ext',
'E_M-solv', &
849 'Q_pol^e',
'deltaQ^e',
'Q_pol^n',
'deltaQ^n',
'Q_pol^ext'
851 write(pcm%info_unit,
'(A1,4X,A4,14X,A4,21X,A4,21X,A4,21X,A4,21X,A8,17X,A5,20X,A8,17X,A5,20X, A8)') &
852 '#',
'iter',
'E_ee',
'E_en',
'E_nn',
'E_ne',
'E_M-solv',
'Q_pol^e',
'deltaQ^e',
'Q_pol^n',
'deltaQ^n'
858 if (gamess_benchmark .and.
mpi_world%is_root())
then
859 cav_gamess_unit =
io_open(
pcm_dir//
'geom_cavity_gamess.out', pcm%namespace, action=
'write')
861 write(cav_gamess_unit,*) pcm%n_tesserae
863 do ia = 1, pcm%n_tesserae
864 write(cav_gamess_unit,*) pcm%tess(ia)%point(1)
867 do ia = 1, pcm%n_tesserae
868 write(cav_gamess_unit,*) pcm%tess(ia)%point(2)
871 do ia = 1, pcm%n_tesserae
872 write(cav_gamess_unit,*) pcm%tess(ia)%point(3)
875 do ia = 1, pcm%n_tesserae
876 write(cav_gamess_unit,*) pcm%tess(ia)%area
879 do ia = 1, pcm%n_tesserae
880 write(cav_gamess_unit,*) pcm%tess(ia)%r_sphere
883 do ia = 1, pcm%n_tesserae
884 write(cav_gamess_unit,*) pcm%tess(ia)%normal
891 if (gamess_benchmark)
then
892 safe_allocate(
mat_gamess(1:pcm%n_tesserae, 1:pcm%n_tesserae))
896 if (.not.
is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
898 safe_allocate(pcm%matrix_d(1:pcm%n_tesserae, 1:pcm%n_tesserae))
901 call pcm_matrix(pcm%epsilon_infty, pcm%tess, pcm%n_tesserae, pcm%matrix_d)
903 if (gamess_benchmark .and.
mpi_world%is_root())
then
904 pcmmat_gamess_unit =
io_open(
pcm_dir//
'pcm_matrix_gamess_dyn.out', pcm%namespace, action=
'write')
906 do jtess = 1, pcm%n_tesserae
907 do itess = 1, pcm%n_tesserae
908 write(pcmmat_gamess_unit,*)
mat_gamess(itess,jtess)
918 safe_allocate(pcm%matrix_lf_d(1:pcm%n_tesserae, 1:pcm%n_tesserae))
921 call pcm_matrix(pcm%epsilon_infty, pcm%tess, pcm%n_tesserae, pcm%matrix_lf_d, .
true.)
925 pcmmat_unit =
io_open(
pcm_dir//
'pcm_matrix_dynamic_lf.out', pcm%namespace, action=
'write')
926 do jtess = 1, pcm%n_tesserae
927 do itess = 1, pcm%n_tesserae
928 write(pcmmat_unit,*) pcm%matrix_lf_d(itess,jtess)
938 safe_allocate(pcm%matrix(1:pcm%n_tesserae, 1:pcm%n_tesserae))
941 call pcm_matrix(pcm%epsilon_0, pcm%tess, pcm%n_tesserae, pcm%matrix)
944 pcmmat_unit =
io_open(
pcm_dir//
'pcm_matrix.out', pcm%namespace, action=
'write')
945 if (gamess_benchmark) pcmmat_gamess_unit =
io_open(
pcm_dir//
'pcm_matrix_gamess.out', &
946 pcm%namespace, action=
'write')
948 do jtess = 1, pcm%n_tesserae
949 do itess = 1, pcm%n_tesserae
950 write(pcmmat_unit,*) pcm%matrix(itess,jtess)
951 if (gamess_benchmark)
write(pcmmat_gamess_unit,*)
mat_gamess(itess,jtess)
955 if (gamess_benchmark)
call io_close(pcmmat_gamess_unit)
959 if (gamess_benchmark)
then
965 safe_allocate(pcm%matrix_lf(1:pcm%n_tesserae, 1:pcm%n_tesserae))
968 call pcm_matrix(pcm%epsilon_0, pcm%tess, pcm%n_tesserae, pcm%matrix_lf, .
true.)
972 pcmmat_unit =
io_open(
pcm_dir//
'pcm_matrix_static_lf.out', pcm%namespace, action=
'write')
973 do jtess = 1, pcm%n_tesserae
974 do itess = 1, pcm%n_tesserae
975 write(pcmmat_unit,*) pcm%matrix_lf(itess,jtess)
983 message(1) =
"Info: PCM response matrices has been evaluated"
1005 do ia = 1, pcm%n_tesserae
1006 if (pcm%tess(ia)%area > max_area) max_area = pcm%tess(ia)%area
1010 default_nn = int(max_area*pcm%gaussian_width/minval(grid%spacing(1:pcm%space%dim)))
1012 changed_default_nn = .false.
1014 do ii = default_nn, 1, -1
1019 changed_default_nn = .
true.
1022 if (changed_default_nn)
then
1023 call messages_write(
'PCM nearest neighbors have been reduced from ')
1033 default_nn = pcm%tess_nn
1047 call parse_variable(namespace,
'PCMChargeSmearNN', default_nn, pcm%tess_nn)
1057 safe_allocate(pcm%rho_n(1:grid%np_part))
1058 safe_allocate(pcm%rho_e(1:grid%np_part))
1059 if (pcm%localf)
then
1060 safe_allocate(pcm%rho_ext(1:grid%np_part))
1061 if (pcm%kick_is_present)
then
1062 safe_allocate(pcm%rho_kick(1:grid%np_part))
1068 safe_allocate(pcm%v_n(1:pcm%n_tesserae))
1069 safe_allocate(pcm%q_n(1:pcm%n_tesserae))
1070 safe_allocate(pcm%v_n_rs(1:grid%np))
1075 safe_allocate(pcm%v_e(1:pcm%n_tesserae))
1076 safe_allocate(pcm%q_e(1:pcm%n_tesserae))
1077 safe_allocate(pcm%v_e_rs(1:grid%np))
1082 safe_allocate(pcm%q_e_in(1:pcm%n_tesserae))
1086 if (pcm%localf)
then
1087 safe_allocate(pcm%v_ext(1:pcm%n_tesserae))
1088 safe_allocate(pcm%q_ext(1:pcm%n_tesserae))
1089 safe_allocate(pcm%v_ext_rs(1:grid%np))
1094 safe_allocate(pcm%q_ext_in(1:pcm%n_tesserae))
1097 if (pcm%kick_is_present)
then
1098 safe_allocate(pcm%v_kick(1:pcm%n_tesserae))
1099 safe_allocate(pcm%q_kick(1:pcm%n_tesserae))
1100 safe_allocate(pcm%v_kick_rs(1:grid%np))
1108 pcm%q_e_nominal = qtot
1109 pcm%q_n_nominal = val_charge
1120 subroutine pcm_calc_pot_rs(pcm, mesh, psolver, ions, v_h, v_ext, kick, time_present, kick_time)
1121 type(
pcm_t),
intent(inout) :: pcm
1122 class(
mesh_t),
intent(in) :: mesh
1124 type(
ions_t),
optional,
intent(in) :: ions
1125 real(real64),
optional,
intent(in) :: v_h(:)
1126 real(real64),
optional,
intent(in) :: v_ext(:)
1127 real(real64),
optional,
intent(in) :: kick(:)
1128 logical,
optional,
intent(in) :: time_present
1129 logical,
optional,
intent(in) :: kick_time
1131 integer,
save :: calc
1133 logical,
save :: input_asc_e
1134 logical,
save :: input_asc_ext
1139 logical,
save :: not_yet_called = .false.
1140 logical,
save :: is_time_for_kick = .false.
1141 logical,
save :: after_kick = .false.
1143 logical,
save :: td_calc_mode = .false.
1145 integer,
save :: asc_vs_t_unit_e
1147 character(len=23),
save :: asc_vs_t_unit_format
1148 character(len=16),
save :: asc_vs_t_unit_format_tail
1154 assert(
present(v_h) .or.
present(ions) .or.
present(v_ext) .or.
present(kick))
1159 if ((.not.
present(v_ext)) .and.
present(kick)) calc =
pcm_kick
1162 if (
present(time_present))
then
1163 if (time_present) td_calc_mode = .
true.
1166 if (
present(kick_time))
then
1167 is_time_for_kick = kick_time
1168 if (kick_time) after_kick = .
true.
1171 select case (pcm%initial_asc)
1173 input_asc_e = .
true.
1174 input_asc_ext = .false.
1176 input_asc_e = .false.
1177 input_asc_ext = .
true.
1179 input_asc_e = .
true.
1180 input_asc_ext = .
true.
1182 input_asc_e = .false.
1183 input_asc_ext = .false.
1188 call pcm_charges(pcm%q_n, pcm%qtot_n, pcm%v_n, pcm%matrix, pcm%n_tesserae, &
1189 pcm%q_n_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_n)
1193 call pcm_pot_rs(pcm, pcm%v_n_rs, pcm%q_n, pcm%rho_n, mesh, psolver)
1198 if (td_calc_mode .and. .not.
is_close(pcm%epsilon_infty, pcm%epsilon_0) .and. pcm%tdlevel /=
pcm_td_eq)
then
1200 select case (pcm%tdlevel)
1202 select case (pcm%which_eps)
1212 pcm%qtot_e = sum(pcm%q_e)
1214 select case (pcm%iter)
1219 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix, pcm%n_tesserae, &
1220 pcm%q_e_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1223 call pcm_charges(pcm%q_e_in, pcm%qtot_e_in, pcm%v_e, pcm%matrix_d, pcm%n_tesserae, &
1224 pcm%q_e_nominal, pcm%epsilon_infty, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1226 pcm%q_e_in = pcm%q_e - pcm%q_e_in
1227 pcm%qtot_e_in = pcm%qtot_e - pcm%qtot_e_in
1230 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix_d, pcm%n_tesserae, &
1231 pcm%q_e_nominal, pcm%epsilon_infty, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1233 pcm%q_e = pcm%q_e + pcm%q_e_in
1234 pcm%qtot_e = pcm%qtot_e + pcm%qtot_e_in
1240 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix, pcm%n_tesserae, &
1241 pcm%q_e_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1247 call pcm_pot_rs(pcm, pcm%v_e_rs, pcm%q_e, pcm%rho_e, mesh, psolver)
1257 if (td_calc_mode .and. .not.
is_close(pcm%epsilon_infty, pcm%epsilon_0) .and. pcm%tdlevel /=
pcm_td_eq)
then
1259 select case (pcm%tdlevel)
1261 select case (pcm%which_eps)
1264 pcm%which_eps, pcm%namespace, this_drl=pcm%drl)
1267 pcm%which_eps, pcm%namespace, this_deb=pcm%deb)
1271 pcm%qtot_ext = sum(pcm%q_ext)
1274 pcm%q_ext = pcm%q_ext + pcm%q_ext_in
1275 pcm%qtot_ext = pcm%qtot_ext + pcm%qtot_ext_in
1278 call pcm_charges(pcm%q_ext, pcm%qtot_ext, pcm%v_ext, pcm%matrix_lf_d, pcm%n_tesserae)
1282 pcm%q_ext = pcm%q_ext + pcm%q_ext_in
1283 pcm%qtot_ext = pcm%qtot_ext + pcm%qtot_ext_in
1290 call pcm_charges(pcm%q_ext, pcm%qtot_ext, pcm%v_ext, pcm%matrix_lf, pcm%n_tesserae)
1293 pcm%q_ext_in = pcm%q_ext
1294 pcm%qtot_ext_in = pcm%qtot_ext
1299 call pcm_pot_rs(pcm, pcm%v_ext_rs, pcm%q_ext, pcm%rho_ext, mesh, psolver)
1306 if (is_time_for_kick)
then
1311 if (pcm%kick_like)
then
1312 if (is_time_for_kick)
then
1314 if (.not.
is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
1315 call pcm_charges(pcm%q_kick, pcm%qtot_kick, pcm%v_kick, pcm%matrix_lf_d, pcm%n_tesserae)
1317 call pcm_charges(pcm%q_kick, pcm%qtot_kick, pcm%v_kick, pcm%matrix_lf, pcm%n_tesserae)
1329 if (after_kick)
then
1331 select case (pcm%which_eps)
1334 pcm%which_eps, pcm%namespace, this_drl=pcm%drl)
1337 pcm%which_eps, pcm%namespace, this_deb=pcm%deb)
1340 pcm%qtot_kick = sum(pcm%q_kick)
1356 call pcm_pot_rs(pcm, pcm%v_kick_rs, pcm%q_kick, pcm%rho_kick, mesh, psolver)
1357 if (.not. pcm%kick_like)
then
1359 pcm%q_ext = pcm%q_ext + pcm%q_kick
1360 pcm%v_ext_rs = pcm%v_ext_rs + pcm%v_kick_rs
1362 pcm%q_ext = pcm%q_kick
1363 pcm%v_ext_rs = pcm%v_kick_rs
1371 write (asc_vs_t_unit_format_tail,
'(I5,A11)') pcm%n_tesserae,
'(1X,F14.8))'
1372 write (asc_vs_t_unit_format,
'(A)')
'(F14.8,'//trim(adjustl(asc_vs_t_unit_format_tail))
1374 if (pcm%solute .and. pcm%localf .and. td_calc_mode .and. calc ==
pcm_electrons)
then
1375 asc_vs_t_unit_e =
io_open(
pcm_dir//
'ASC_e_vs_t.dat', pcm%namespace, &
1376 action=
'write', position=
'append', form=
'formatted')
1377 write(asc_vs_t_unit_e,trim(adjustl(asc_vs_t_unit_format))) pcm%iter*pcm%dt, &
1378 (pcm%q_e(ia) , ia = 1,pcm%n_tesserae)
1390 type(
pcm_t),
intent(in) :: pcm
1391 type(
mesh_t),
intent(in) :: mesh
1392 real(real64),
intent(in) :: v_mesh(:)
1393 real(real64),
intent(out) :: v_cav(:)
1405 do ia = 1, pcm%n_tesserae
1419 real(real64),
intent(out) :: v_n_cav(:)
1420 type(
ions_t),
intent(in) :: ions
1422 integer,
intent(in) :: n_tess
1424 real(real64) :: dist
1432 do ia = 1, ions%natoms
1434 dist = norm2(ions%pos(1:pcm_dim_space, ia) - tess(ik)%point)
1436 v_n_cav(ik) = v_n_cav(ik) - ions%charge(ia)/dist
1448 subroutine pcm_elect_energy(ions, pcm, E_int_ee, E_int_en, E_int_ne, E_int_nn, E_int_e_ext, E_int_n_ext)
1449 type(
ions_t),
intent(in) :: ions
1450 type(
pcm_t),
intent(in) :: pcm
1451 real(real64),
intent(out) :: e_int_ee
1452 real(real64),
intent(out) :: e_int_en
1453 real(real64),
intent(out) :: e_int_ne
1454 real(real64),
intent(out) :: e_int_nn
1455 real(real64),
optional,
intent(out) :: e_int_e_ext
1456 real(real64),
optional,
intent(out) :: e_int_n_ext
1458 real(real64) :: dist, z_ia
1468 if (pcm%localf .and. ((.not.
present(e_int_e_ext)) .or. &
1469 (.not.
present(e_int_n_ext))))
then
1470 message(1) =
"pcm_elect_energy: There are lacking terms in subroutine call."
1472 else if (pcm%localf .and. (
present(e_int_e_ext) .and. &
1473 present(e_int_n_ext)))
then
1478 do ik = 1, pcm%n_tesserae
1480 e_int_ee = e_int_ee + pcm%v_e(ik)*pcm%q_e(ik)
1481 e_int_en = e_int_en + pcm%v_e(ik)*pcm%q_n(ik)
1482 if (pcm%localf)
then
1483 e_int_e_ext = e_int_e_ext + pcm%v_e(ik)*pcm%q_ext(ik)
1486 do ia = 1, ions%natoms
1488 dist = norm2(ions%pos(1:pcm_dim_space, ia) - pcm%tess(ik)%point)
1490 z_ia = -ions%charge(ia)
1492 e_int_ne = e_int_ne + z_ia*pcm%q_e(ik) / dist
1493 e_int_nn = e_int_nn + z_ia*pcm%q_n(ik) / dist
1494 if (pcm%localf) e_int_n_ext = e_int_n_ext + z_ia*pcm%q_ext(ik) / dist
1499 e_int_ee =
m_half*e_int_ee
1500 e_int_en =
m_half*e_int_en
1501 e_int_ne =
m_half*e_int_ne
1502 e_int_nn =
m_half*e_int_nn
1507 if (pcm%localf)
then
1508 write(pcm%info_unit, &
1509 '(3X,I5,5X,F20.8,5X,F20.8,5X,F20.8,5X,F20.8,5X,F20.8,5X,F20.8,5X,F20.8,5X,F20.8,F20.8,5X,F20.8,5X,F20.8,5X,F20.8,5X)') &
1524 write(pcm%info_unit, &
1525 '(3X,I5,5X,F20.8,5X,F20.8,5X,F20.8,5X,F20.8,5X,F20.8,5X,F20.8,5X,F20.8,5X,F20.8,5X,F20.8)') &
1547 subroutine pcm_charges(q_pcm, q_pcm_tot, v_cav, pcm_mat, n_tess, qtot_nominal, epsilon, renorm_charges, q_tot_tol, deltaQ)
1548 real(real64),
intent(out) :: q_pcm(:)
1549 real(real64),
intent(out) :: q_pcm_tot
1550 real(real64),
intent(in) :: v_cav(:)
1551 real(real64),
intent(in) :: pcm_mat(:,:)
1552 integer,
intent(in) :: n_tess
1553 real(real64),
optional,
intent(in) :: qtot_nominal
1554 real(real64),
optional,
intent(in) :: epsilon
1555 logical,
optional,
intent(in) :: renorm_charges
1556 real(real64),
optional,
intent(in) :: q_tot_tol
1557 real(real64),
optional,
intent(out) :: deltaq
1560 real(real64) :: q_pcm_tot_norm
1561 real(real64) :: coeff
1571 q_pcm(ia) = q_pcm(ia) + pcm_mat(ia,ib)*v_cav(ib)
1573 q_pcm_tot = q_pcm_tot + q_pcm(ia)
1576 if (
present(qtot_nominal) .and.
present(epsilon) .and. &
1577 present(renorm_charges) .and.
present(q_tot_tol) .and.
present(deltaq))
then
1579 deltaq = abs(q_pcm_tot) - ((epsilon -
m_one)/epsilon) * abs(qtot_nominal)
1580 if ((renorm_charges) .and. (abs(deltaq) > q_tot_tol))
then
1582 coeff = sign(
m_one, qtot_nominal)*sign(
m_one, deltaq)
1584 q_pcm(ia) = q_pcm(ia) + coeff*q_pcm(ia)/q_pcm_tot*abs(deltaq)
1585 q_pcm_tot_norm = q_pcm_tot_norm + q_pcm(ia)
1587 q_pcm_tot = q_pcm_tot_norm
1598 type(
pcm_t),
intent(in) :: pcm
1599 class(
mesh_t),
intent(in) :: mesh
1601 integer :: ia, nm(pcm%space%dim), ipt, i1, i2, i3
1602 real(real64) :: posrel(pcm%space%dim)
1603 integer(int64) :: pt
1608 do ia = 1, pcm%n_tesserae
1610 posrel(:) = pcm%tess(ia)%point(1:pcm%space%dim)/mesh%spacing(1:pcm%space%dim)
1612 nm(:) =
floor(posrel(:))
1616 do i1 = -pcm%tess_nn + 1 , pcm%tess_nn
1617 do i2 = -pcm%tess_nn + 1 , pcm%tess_nn
1618 do i3 = -pcm%tess_nn + 1 , pcm%tess_nn
1622 if (pt <= 0 .or. pt > mesh%np_part_global)
then
1639 type(
pcm_t),
intent(in) :: pcm
1640 class(
mesh_t),
intent(in) :: mesh
1645 message(1) =
'The simulation box is too small to contain all the requested'
1646 message(2) =
'nearest neighbors for each tessera.'
1647 message(3) =
'Consider using a larger box or reduce PCMChargeSmearNN.'
1658 type(
pcm_t),
intent(inout) :: pcm
1659 real(real64),
intent(in) :: q_pcm(:)
1660 real(real64),
intent(in) :: q_pcm_tot
1661 type(
mesh_t),
intent(in) :: mesh
1662 real(real64),
intent(out) :: rho(:)
1665 real(real64) :: norm, qtot, rr, xx(pcm%space%dim), pp(pcm%space%dim)
1668 integer :: nm(pcm%space%dim)
1669 real(real64) :: posrel(pcm%space%dim)
1671 integer :: i1, i2, i3
1672 integer,
allocatable :: pt(:)
1673 real(real64),
allocatable :: lrho(:)
1674 logical :: inner_point, boundary_point
1682 npt = (2*pcm%tess_nn)**pcm%space%dim
1683 safe_allocate(pt(1:npt))
1684 safe_allocate(lrho(1:npt))
1689 do ia = 1, pcm%n_tesserae
1691 pp(:) = pcm%tess(ia)%point(1:pcm%space%dim)
1692 posrel(:) = pp(:)/mesh%spacing(1:pcm%space%dim)
1694 nm(:) =
floor(posrel(:))
1698 do i1 = -pcm%tess_nn + 1 , pcm%tess_nn
1699 do i2 = -pcm%tess_nn + 1 , pcm%tess_nn
1700 do i3 = -pcm%tess_nn + 1 , pcm%tess_nn
1716 if (pt(ipt) > 0 .and. pt(ipt) <= mesh%np_part)
then
1718 if (mesh%parallel_in_domains)
then
1719 boundary_point = pt(ipt) > mesh%np + mesh%pv%np_ghost
1720 inner_point = pt(ipt) > 0 .and. pt(ipt) <= mesh%np
1722 if (boundary_point .or. inner_point)
then
1723 xx(:) = mesh%x(:, pt(ipt))
1729 xx(:) = mesh%x(:, pt(ipt))
1732 rr = sum((xx(1:pcm%space%dim) - pp(1:pcm%space%dim))**2)
1733 norm = norm +
exp(-rr/(pcm%tess(ia)%area*pcm%gaussian_width))
1734 lrho(ipt) = lrho(ipt) +
exp(-rr/(pcm%tess(ia)%area*pcm%gaussian_width))
1740 call mesh%allreduce(lrho, npt)
1743 norm = sum(lrho(1:npt)) * mesh%volume_element
1745 norm = q_pcm(ia)/norm
1749 lrho(:) = lrho(:) * norm
1754 if (pt(ipt) > 0 .and. pt(ipt) <= mesh%np_part_global)
then
1756 if (mesh%parallel_in_domains)
then
1757 boundary_point = pt(ipt) > mesh%np + mesh%pv%np_ghost
1758 inner_point = pt(ipt) > 0 .and. pt(ipt) <= mesh%np
1759 if (boundary_point .or. inner_point) rho(pt(ipt)) = rho(pt(ipt)) + lrho(ipt)
1761 rho(pt(ipt)) = rho(pt(ipt)) + lrho(ipt)
1769 if (
debug%info)
then
1783 safe_deallocate_a(pt)
1784 safe_deallocate_a(lrho)
1794 subroutine pcm_pot_rs(pcm, v_pcm, q_pcm, rho, mesh, psolver)
1795 type(
pcm_t),
intent(inout) :: pcm
1796 real(real64),
contiguous,
intent(inout) :: v_pcm(:)
1797 real(real64),
contiguous,
intent(in) :: q_pcm(:)
1798 real(real64),
contiguous,
intent(inout) :: rho(:)
1799 type(
mesh_t),
intent(in) :: mesh
1809 select case (pcm%calc_method)
1811 call pcm_pot_rs_direct(v_pcm, q_pcm, pcm%tess, pcm%n_tesserae, mesh, pcm%gaussian_width)
1822 if (
debug%info)
then
1837 real(real64),
contiguous,
intent(inout) :: v_pcm(:)
1839 real(real64),
contiguous,
intent(inout) :: rho(:)
1852 real(real64),
intent(out) :: v_pcm(:)
1853 real(real64),
intent(in) :: q_pcm(:)
1854 real(real64),
intent(in) :: width_factor
1855 integer,
intent(in) :: n_tess
1856 type(
mesh_t),
intent(in) :: mesh
1859 real(real64),
parameter :: p_1 = 0.119763_real64
1860 real(real64),
parameter :: p_2 = 0.205117_real64
1861 real(real64),
parameter :: q_1 = 0.137546_real64
1862 real(real64),
parameter :: q_2 = 0.434344_real64
1864 real(real64) :: term
1877 call mesh_r(mesh, ip, term, origin=tess(ia)%point)
1878 arg = term/
sqrt(tess(ia)%area*width_factor)
1879 term = (
m_one + p_1*arg + p_2*arg**2) / (
m_one + q_1*arg + q_2*arg**2 + p_2*arg**3)
1880 v_pcm(ip) = v_pcm(ip) + q_pcm(ia) * term/
sqrt(tess(ia)%area*width_factor)
1891 call mesh_r(mesh, ip, term, origin=tess(ia)%point)
1892 v_pcm(ip) = v_pcm(ip) + q_pcm(ia)/term
1903 subroutine pcm_matrix(eps, tess, n_tess, pcm_mat, localf)
1904 real(real64),
intent(in) :: eps
1906 integer,
intent(in) :: n_tess
1907 real(real64),
intent(out) :: pcm_mat(:,:)
1908 logical,
optional,
intent(in) :: localf
1911 integer,
allocatable :: iwork(:)
1912 real(real64),
allocatable :: mat_tmp(:,:)
1914 real(real64) :: sgn_lf
1919 safe_allocate(s_mat_act(1:n_tess, 1:n_tess))
1923 safe_allocate(sigma(1:n_tess, 1:n_tess))
1924 sigma = s_mat_act/eps
1927 safe_allocate(d_mat_act(1:n_tess, 1:n_tess))
1931 safe_allocate(delta(1:n_tess, 1:n_tess))
1936 if (
present(localf))
then
1937 if (localf) sgn_lf = -
m_one
1941 pcm_mat = - sgn_lf * d_mat_act
1944 pcm_mat(i,i) = pcm_mat(i,i) +
m_two*
m_pi
1947 safe_deallocate_a(d_mat_act)
1949 safe_allocate(iwork(1:n_tess))
1954 call dgesv(n_tess, n_tess, s_mat_act, n_tess, iwork, pcm_mat, n_tess,
info)
1956 safe_deallocate_a(iwork)
1958 safe_deallocate_a(s_mat_act)
1962 pcm_mat = -matmul(sigma, pcm_mat)
1965 pcm_mat(i,i) = pcm_mat(i,i) +
m_two*
m_pi
1968 pcm_mat = pcm_mat - sgn_lf * delta
1970 safe_allocate(mat_tmp(1:n_tess,1:n_tess))
1973 safe_allocate(d_mat_act(1:n_tess,1:n_tess))
1976 mat_tmp = transpose(d_mat_act)
1978 mat_tmp = matmul(sigma, mat_tmp)
1982 safe_deallocate_a(d_mat_act)
1984 safe_allocate(s_mat_act(1:n_tess, 1:n_tess))
1987 mat_tmp = mat_tmp +
m_two*
m_pi*s_mat_act - matmul(delta, s_mat_act)
1989 safe_deallocate_a(s_mat_act)
1990 safe_deallocate_a(sigma)
1991 safe_deallocate_a(delta)
1993 safe_allocate(iwork(1:n_tess))
1997 call dgesv(n_tess, n_tess, mat_tmp, n_tess, iwork, pcm_mat, n_tess,
info)
1999 safe_deallocate_a(iwork)
2000 safe_deallocate_a(mat_tmp)
2002 pcm_mat = - sgn_lf * pcm_mat
2005 if (gamess_benchmark)
then
2017 integer,
intent(in) :: n_tess
2027 if (ii /= jj) s_mat_act(jj,ii) = s_mat_act(ii,jj)
2036 integer,
intent(in) :: n_tess
2055 real(real64) function s_mat_elem_I(tessi, tessj)
2059 real(real64),
parameter :: M_SD_DIAG = 1.0694_real64
2060 real(real64),
parameter :: M_DIST_MIN = 0.1_real64
2062 real(real64) :: diff(1:PCM_DIM_SPACE)
2063 real(real64) :: dist
2064 real(real64) :: s_diag
2065 real(real64) :: s_off_diag
2070 diff = tessi%point - tessj%point
2076 s_mat_elem_i = s_diag
2078 if (dist > m_dist_min) s_off_diag =
m_one/dist
2079 s_mat_elem_i = s_off_diag
2087 real(real64) function d_mat_elem_I(tessi, tessj)
2088 type(pcm_tessera_t),
intent(in) :: tessi
2089 type(pcm_tessera_t),
intent(in) :: tessj
2091 real(real64),
parameter :: M_SD_DIAG = 1.0694_real64
2092 real(real64),
parameter :: M_DIST_MIN = 0.04_real64
2094 real(real64) :: diff(1:PCM_DIM_SPACE)
2095 real(real64) :: dist
2096 real(real64) :: d_diag
2097 real(real64) :: d_off_diag
2103 diff = tessi%point - tessj%point
2107 if (abs(dist) <= m_epsilon)
then
2109 d_diag = m_sd_diag*
sqrt(m_four*m_pi*tessi%area)
2110 d_diag = -d_diag/(m_two*tessi%r_sphere)
2115 if (dist > m_dist_min)
then
2116 d_off_diag = dot_product( diff, tessj%normal(:))
2117 d_off_diag = d_off_diag*tessj%area/dist**3
2131 subroutine cav_gen(tess_sphere, tess_min_distance, nesf, sfe, nts, cts, unit_pcminfo)
2132 integer,
intent(in) :: tess_sphere
2133 real(real64) ,
intent(in) :: tess_min_distance
2135 integer,
intent(in) :: nesf
2136 integer,
intent(out) :: nts
2137 type(pcm_tessera_t),
intent(out) :: cts(:)
2138 integer,
intent(in) :: unit_pcminfo
2140 integer,
parameter :: DIM_ANGLES = 24
2141 integer,
parameter :: DIM_TEN = 10
2142 integer,
parameter :: DIM_VERTICES = 122
2143 integer,
parameter :: MAX_VERTICES = 6
2144 integer,
parameter :: MXTS = 10000
2146 real(real64),
save :: thev(1:DIM_ANGLES)
2147 real(real64),
save :: fiv(1:DIM_ANGLES)
2148 real(real64),
save :: fir
2149 real(real64) :: cv(1:DIM_VERTICES, 1:PCM_DIM_SPACE)
2159 real(real64) :: nctst(pcm_dim_space, tess_sphere*
n_tess_sphere)
2161 real(real64) :: pts(1:pcm_dim_space, 1:dim_ten)
2162 real(real64) :: pp(1:pcm_dim_space)
2163 real(real64) :: pp1(1:pcm_dim_space)
2164 real(real64) :: ccc(1:pcm_dim_space, 1:dim_ten)
2168 integer :: isfet(1:dim_ten*dim_angles)
2186 real(real64) :: area
2187 real(real64) :: test2
2189 real(real64) :: dnorm
2199 real(real64) :: stot
2200 real(real64) :: prod
2203 logical :: band_iter
2209 data thev/ 0.6523581398_real64 , 1.107148718_real64 , 1.382085796_real64 , &
2210 1.759506858_real64 , 2.034443936_real64 , 2.489234514_real64 , &
2211 0.3261790699_real64 , 0.5535743589_real64, &
2212 0.8559571251_real64 , 0.8559571251_real64 , 1.017221968_real64 , &
2213 1.229116717_real64 , 1.229116717_real64 , 1.433327788_real64 , &
2214 1.570796327_real64 , 1.570796327_real64 , 1.708264866_real64 , &
2215 1.912475937_real64 , 1.912475937_real64 , 2.124370686_real64 , &
2216 2.285635528_real64 , 2.285635528_real64 , 2.588018295_real64 , &
2217 2.815413584_real64 /
2218 data fiv/ 0.6283185307_real64 , m_zero , &
2219 0.6283185307_real64 , m_zero , 0.6283185307_real64, &
2220 m_zero , 0.6283185307_real64 , m_zero, &
2221 0.2520539002_real64 , 1.004583161_real64 , 0.6283185307_real64, &
2222 0.3293628477_real64 , 0.9272742138_real64 , m_zero, &
2223 0.3141592654_real64 , 0.9424777961_real64 , 0.6283185307_real64, &
2224 0.2989556830_real64 , 0.9576813784_real64 , m_zero, &
2225 0.3762646305_real64 , 0.8803724309_real64 , 0.6283188307_real64, &
2227 data fir / 1.256637061_real64 /
2231 data (idum(ii),ii = 1, 280) / &
2232 1, 6, 2, 32, 36, 37, 1, 2, 3, 33, 32, 38, 1, 3, 4, 34, &
2233 33, 39, 1, 4, 5, 35, 34, 40, 1, 5, 6, 36, 35, 41, 7, 2, 6, 51, &
2234 42, 37, 8, 3, 2, 47, 43, 38, 9, 4, 3, 48, 44, 39, 10, 5, 4, &
2235 49, 45, 40, 11, 6, 5, 50, 46, 41, 8, 2, 12, 62, 47, 52, 9, &
2236 3, 13, 63, 48, 53, 10, 4, 14, 64, 49, 54, 11, 5, 15, 65, 50, &
2237 55, 7, 6, 16, 66, 51, 56, 7, 12, 2, 42, 57, 52, 8, 13, 3, &
2238 43, 58, 53, 9, 14, 4, 44, 59, 54, 10, 15, 5, 45, 60, 55, 11, &
2239 16, 6, 46, 61, 56, 8, 12, 18, 68, 62, 77, 9, 13, 19, 69, 63, &
2240 78, 10, 14, 20, 70, 64, 79, 11, 15, 21, 71, 65, 80, 7, 16, &
2241 17, 67, 66, 81, 7, 17, 12, 57, 67, 72, 8, 18, 13, 58, 68, 73, &
2242 9, 19, 14, 59, 69, 74, 10, 20, 15, 60, 70, 75, 11, 21, 16, &
2243 61, 71, 76, 22, 12, 17, 87, 82, 72, 23, 13, 18, 88, 83, 73, &
2244 24, 14, 19, 89, 84, 74, 25, 15, 20, 90, 85, 75, 26, 16, 21, &
2245 91, 86, 76, 22, 18, 12, 82, 92, 77, 23, 19, 13, 83, 93, 78, &
2246 24, 20, 14, 84, 94, 79, 25, 21, 15, 85, 95, 80, 26, 17, 16, &
2247 86, 96, 81, 22, 17, 27, 102, 87, 97, 23, 18, 28, 103, 88, 98, &
2248 24, 19, 29, 104, 89, 99, 25, 20, 30, 105, 90, 100, 26, 21, &
2249 31, 106, 91, 101, 22, 28, 18, 92, 107, 98, 23, 29, 19, 93 /
2250 data (idum(ii),ii = 281,360) / &
2251 108, 99, 24, 30, 20, 94, 109, 100, 25, 31, 21, 95, 110, 101, &
2252 26, 27, 17, 96, 111, 97, 22, 27, 28, 107, 102, 112, 23, 28, &
2253 29, 108, 103, 113, 24, 29, 30, 109, 104, 114, 25, 30, 31, &
2254 110, 105, 115, 26, 31, 27, 111, 106, 116, 122, 28, 27, 117, &
2255 118, 112, 122, 29, 28, 118, 119, 113, 122, 30, 29, 119, 120, &
2256 114, 122, 31, 30, 120, 121, 115, 122, 27, 31, 121, 117, 116 /
2258 if (mpi_world%is_root())
then
2259 if (tess_sphere == 1)
then
2260 write(unit_pcminfo,
'(A1)')
'#'
2261 write(unit_pcminfo,
'(A34)')
'# Number of tesserae / sphere = 60'
2262 write(unit_pcminfo,
'(A1)')
'#'
2264 write(unit_pcminfo,
'(A1)')
'#'
2265 write(unit_pcminfo,
'(A35)')
'# Number of tesserae / sphere = 240'
2266 write(unit_pcminfo,
'(A1)')
'#'
2275 sfe(:)%x = sfe(:)%x*p_a_b
2276 sfe(:)%y = sfe(:)%y*p_a_b
2277 sfe(:)%z = sfe(:)%z*p_a_b
2278 sfe(:)%r = sfe(:)%r*p_a_b
2282 jvt1 = reshape(idum,(/6,60/))
2305 do ia = 1, dim_angles
2312 if (ja == 1) fi = fiv(ia)
2314 cv(ii,1) = sth*
cos(fi)
2315 cv(ii,2) = sth*
sin(fi)
2334 do i_tes = 1, tess_sphere
2335 if (tess_sphere == 1)
then
2340 if (i_tes == 1)
then
2344 elseif (i_tes == 2)
then
2348 elseif (i_tes == 3)
then
2352 elseif (i_tes == 4)
then
2359 pts(1,1) = cv(n1,1)*ren + xen
2360 pts(2,1) = cv(n1,3)*ren + yen
2361 pts(3,1) = cv(n1,2)*ren + zen
2363 pts(1,2) = cv(n2,1)*ren + xen
2364 pts(2,2) = cv(n2,3)*ren + yen
2365 pts(3,2) = cv(n2,2)*ren + zen
2367 pts(1,3) = cv(n3,1)*ren + xen
2368 pts(2,3) = cv(n3,3)*ren + yen
2369 pts(3,3) = cv(n3,2)*ren + zen
2375 call subtessera(sfe, nsfe, nesf, nv, pts ,ccc, pp, pp1, area)
2377 if (abs(area) <= m_epsilon) cycle
2379 xctst(tess_sphere*(its-1) + i_tes) = pp(1)
2380 yctst(tess_sphere*(its-1) + i_tes) = pp(2)
2381 zctst(tess_sphere*(its-1) + i_tes) = pp(3)
2382 nctst(:,tess_sphere*(its-1) + i_tes) = pp1(:)
2383 ast(tess_sphere*(its-1) + i_tes) = area
2384 isfet(tess_sphere*(its-1) + i_tes) = nsfe
2391 if (abs(ast(its)) <= m_epsilon) cycle
2395 write(message(1),
'(a,I5,a,I5)')
"total number of tesserae", nn,
">",mxts
2396 call messages_warning(1)
2399 cts(nn)%point(1) = xctst(its)
2400 cts(nn)%point(2) = yctst(its)
2401 cts(nn)%point(3) = zctst(its)
2402 cts(nn)%normal(:) = nctst(:,its)
2403 cts(nn)%area = ast(its)
2404 cts(nn)%r_sphere = sfe(isfet(its))%r
2412 test2 = tess_min_distance*tess_min_distance
2415 do while (.not.(band_iter))
2418 loop_ia:
do ia = 1, nts-1
2419 if (abs(cts(ia)%area) <= m_epsilon) cycle
2420 xi = cts(ia)%point(1)
2421 yi = cts(ia)%point(2)
2422 zi = cts(ia)%point(3)
2424 loop_ja:
do ja = ia+1, nts
2425 if (abs(cts(ja)%area) <= m_epsilon) cycle
2426 xj = cts(ja)%point(1)
2427 yj = cts(ja)%point(2)
2428 zj = cts(ja)%point(3)
2430 rij = (xi - xj)**2 + (yi - yj)**2 + (zi - zj)**2
2432 if (rij > test2) cycle
2434 if (mpi_world%is_root())
then
2435 write(unit_pcminfo,
'(A40,I4,A5,I4,A4,F8.4,A13,F8.4,A3)') &
2436 '# Warning: The distance between tesserae', &
2437 ia,
' and ', ja,
' is ',
sqrt(rij),
' A, less than', tess_min_distance,
' A.'
2441 xi = (xi*cts(ia)%area + xj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2442 yi = (yi*cts(ia)%area + yj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2443 zi = (zi*cts(ia)%area + zj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2445 cts(ia)%point(1) = xi
2446 cts(ia)%point(2) = yi
2447 cts(ia)%point(3) = zi
2450 cts(ia)%normal = (cts(ia)%normal*cts(ia)%area + cts(ja)%normal*cts(ja)%area)
2451 dnorm = norm2(cts(ia)%normal)
2452 cts(ia)%normal = cts(ia)%normal/dnorm
2455 cts(ia)%r_sphere = (cts(ia)%r_sphere*cts(ia)%area + cts(ja)%r_sphere*cts(ja)%area) / &
2456 (cts(ia)%area + cts(ja)%area)
2459 cts(ia)%area = cts(ia)%area + cts(ja)%area
2476 prod = dot_product(cts(its)%point, cts(its)%normal)
2477 vol = vol + cts(its)%area * prod / m_three
2478 stot = stot + cts(its)%area
2481 if (mpi_world%is_root())
then
2482 write(unit_pcminfo,
'(A2)')
'# '
2483 write(unit_pcminfo,
'(A29,I4)')
'# Total number of tesserae = ' , nts
2484 write(unit_pcminfo,
'(A30,F12.6)')
'# Cavity surface area (A^2) = ', stot
2485 write(unit_pcminfo,
'(A24,F12.6)')
'# Cavity volume (A^3) = ' , vol
2486 write(unit_pcminfo,
'(A2)')
'# '
2490 cts(:)%area = cts(:)%area*p_ang*p_ang
2491 cts(:)%point(1) = cts(:)%point(1)*p_ang
2492 cts(:)%point(2) = cts(:)%point(2)*p_ang
2493 cts(:)%point(3) = cts(:)%point(3)*p_ang
2494 cts(:)%r_sphere = cts(:)%r_sphere*p_ang
2496 sfe(:)%x=sfe(:)%x*p_ang
2497 sfe(:)%y=sfe(:)%y*p_ang
2498 sfe(:)%z=sfe(:)%z*p_ang
2499 sfe(:)%r=sfe(:)%r*p_ang
2508 subroutine subtessera(sfe, ns, nesf, nv, pts, ccc, pp, pp1, area)
2510 integer,
intent(in) :: ns
2511 integer,
intent(in) :: nesf
2512 integer,
intent(inout) :: nv
2513 real(real64),
intent(inout) :: pts(:,:)
2514 real(real64),
intent(out) :: ccc(:,:)
2515 real(real64),
intent(out) :: pp(:)
2516 real(real64),
intent(out) :: pp1(:)
2517 real(real64),
intent(out) :: area
2519 real(real64),
parameter :: TOL = -1.0e-10_real64
2520 integer,
parameter :: DIM_TEN = 10
2522 integer :: intsph(1:DIM_TEN)
2533 real(real64) :: p1(1:PCM_DIM_SPACE)
2534 real(real64) :: p2(1:PCM_DIM_SPACE)
2535 real(real64) :: p3(1:PCM_DIM_SPACE)
2536 real(real64) :: p4(1:PCM_DIM_SPACE)
2537 real(real64) :: point(1:PCM_DIM_SPACE)
2538 real(real64) :: pscr(1:PCM_DIM_SPACE,1:DIM_TEN)
2539 real(real64) :: cccp(1:PCM_DIM_SPACE,1:DIM_TEN)
2540 real(real64) :: pointl(1:PCM_DIM_SPACE,1:DIM_TEN)
2541 real(real64) :: diff(1:PCM_DIM_SPACE)
2543 integer :: ind(1:DIM_TEN)
2544 integer :: ltyp(1:DIM_TEN)
2545 integer :: intscr(1:DIM_TEN)
2547 real(real64) :: delr
2548 real(real64) :: delr2
2551 real(real64) :: dnorm
2552 real(real64) :: dist
2569 ccc(1,jj) = sfe(ns)%x
2570 ccc(2,jj) = sfe(ns)%y
2571 ccc(3,jj) = sfe(ns)%z
2576 if (nsfe1 == ns) cycle
2578 intscr(jj) = intsph(jj)
2579 pscr(:,jj) = pts(:,jj)
2580 cccp(:,jj) = ccc(:,jj)
2588 delr2 = (pts(1,ii) - sfe(nsfe1)%x)**2 + (pts(2,ii) - sfe(nsfe1)%y)**2 + (pts(3,ii) - sfe(nsfe1)%z)**2
2590 if (delr < sfe(nsfe1)%r)
then
2596 if (icop == nv)
then
2604 if (ll == nv) iv2 = 1
2605 if ((ind(iv1) == 1) .and. (ind(iv2) == 1))
then
2607 else if ((ind(iv1) == 0) .and. (ind(iv2) == 1))
then
2609 else if ((ind(iv1) == 1) .and. (ind(iv2) == 0))
then
2611 else if ((ind(iv1) == 0) .and. (ind(iv2) == 0))
then
2613 diff = ccc(:,ll) - pts(:,ll)
2614 rc2 = dot_product(diff, diff)
2618 point = pts(:,iv1) + ii * (pts(:,iv2) - pts(:,iv1)) / 11
2619 point = point - ccc(:,ll)
2620 dnorm = norm2(point)
2621 point = point * rc / dnorm + ccc(:,ll)
2623 dist =
sqrt((point(1) - sfe(nsfe1)%x)**2 + (point(2) - sfe(nsfe1)%y)**2 + (point(3) - sfe(nsfe1)%z)**2)
2625 if ((dist - sfe(nsfe1)%r) < tol)
then
2627 pointl(:, ll) = point
2637 if ((ltyp(ll) == 1) .or. (ltyp(ll) == 2)) icut = icut + 1
2638 if (ltyp(ll) == 3) icut = icut + 2
2649 if (ltyp(ll) == 0) cycle
2652 if (ll == nv) iv2 = 1
2654 if (ltyp(ll) == 1)
then
2655 pts(:,na) = pscr(:,iv1)
2656 ccc(:,na) = cccp(:,iv1)
2657 intsph(na) = intscr(iv1)
2663 call inter(sfe, p1, p2, p3, p4, nsfe1, 0)
2666 de2 = (sfe(nsfe1)%x - sfe(ns)%x)**2 + ( sfe(nsfe1)%y - sfe(ns)%y)**2 + &
2667 (sfe(nsfe1)%z - sfe(ns)%z)**2
2669 ccc(1,na) = sfe(ns)%x + ( sfe(nsfe1)%x - sfe(ns)%x)* &
2670 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2672 ccc(2,na) = sfe(ns)%y + ( sfe(nsfe1)%y - sfe(ns)%y)* &
2673 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2675 ccc(3,na) = sfe(ns)%z + ( sfe(nsfe1)%z - sfe(ns)%z)* &
2676 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2682 if (ltyp(ll) == 2)
then
2687 call inter(sfe, p1, p2, p3, p4, nsfe1, 1)
2689 ccc(:,na) = cccp(:,iv1)
2690 intsph(na) = intscr(iv1)
2694 if (ltyp(ll) == 3)
then
2695 pts(:,na) = pscr(:,iv1)
2696 ccc(:,na) = cccp(:,iv1)
2697 intsph(na) = intscr(iv1)
2703 call inter(sfe, p1, p2, p3, p4, nsfe1, 0)
2706 de2 = (sfe(nsfe1)%x - sfe(ns)%x)**2 + (sfe(nsfe1)%y - sfe(ns)%y)**2 + (sfe(nsfe1)%z - sfe(ns)%z)**2
2708 ccc(1,na) = sfe(ns)%x + (sfe(nsfe1)%x - sfe(ns)%x) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2710 ccc(2,na) = sfe(ns)%y + (sfe(nsfe1)%y - sfe(ns)%y) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2712 ccc(3,na) = sfe(ns)%z + (sfe(nsfe1)%z - sfe(ns)%z) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2720 call inter(sfe, p1, p2, p3, p4, nsfe1, 1)
2722 ccc(:,na) = cccp(:,iv1)
2723 intsph(na) = intscr(iv1)
2727 if (ltyp(ll) == 4)
then
2728 pts(:,na) = pscr(:,iv1)
2729 ccc(:,na) = cccp(:,iv1)
2730 intsph(na) = intscr(iv1)
2737 message(1) =
"Too many vertices on the tessera"
2738 call messages_fatal(1)
2742 call gaubon(sfe, nv, ns, pts, ccc, pp, pp1, area, intsph)
2752 subroutine inter(sfe, p1, p2, p3, p4, ns, ia)
2754 real(real64),
intent(in) :: p1(1:PCM_DIM_SPACE)
2755 real(real64),
intent(in) :: p2(1:PCM_DIM_SPACE)
2756 real(real64),
intent(in) :: p3(1:PCM_DIM_SPACE)
2757 real(real64),
intent(out) :: p4(1:PCM_DIM_SPACE)
2758 integer,
intent(in) :: ns
2759 integer,
intent(in) :: ia
2761 real(real64),
parameter :: TOL = 1.0e-08_real64
2765 real(real64) :: alpha
2766 real(real64) :: delta
2767 real(real64) :: dnorm
2768 real(real64) :: diff
2769 real(real64) :: diff_vec(1:PCM_DIM_SPACE)
2770 logical :: band_iter
2782 do while(.not.(band_iter))
2783 if (m_iter > 1000)
then
2784 message(1) =
"Too many iterations inside subrotuine inter"
2785 call messages_fatal(1)
2790 alpha = alpha + delta
2792 p4 = p1 + alpha*(p2 - p1) - p3
2794 p4 = p4*r/dnorm + p3
2795 diff = (p4(1) - sfe(ns)%x)**2 + (p4(2) - sfe(ns)%y)**2 + (p4(3) - sfe(ns)%z)**2
2796 diff =
sqrt(diff) - sfe(ns)%r
2798 if (abs(diff) < tol)
then
2804 if (diff > m_zero) delta = m_one/(m_two**(m_iter + 1))
2805 if (diff < m_zero) delta = -m_one/(m_two**(m_iter + 1))
2811 if (diff > m_zero) delta = -m_one/(m_two**(m_iter + 1))
2812 if (diff < m_zero) delta = m_one/(m_two**(m_iter + 1))
2819 end subroutine inter
2829 subroutine gaubon(sfe, nv, ns, pts, ccc, pp, pp1, area, intsph)
2831 real(real64),
intent(in) :: pts(:,:)
2832 real(real64),
intent(in) :: ccc(:,:)
2833 real(real64),
intent(inout) :: pp(:)
2834 real(real64),
intent(inout) :: pp1(:)
2835 integer,
intent(in) :: intsph(:)
2836 real(real64),
intent(out) :: area
2837 integer,
intent(in) :: nv
2838 integer,
intent(in) :: ns
2840 real(real64) :: p1(1:PCM_DIM_SPACE), p2(1:PCM_DIM_SPACE), p3(1:PCM_DIM_SPACE)
2841 real(real64) :: u1(1:PCM_DIM_SPACE), u2(1:PCM_DIM_SPACE)
2842 real(real64) :: point_1(1:PCM_DIM_SPACE), point_2(1:PCM_DIM_SPACE)
2843 real(real64) :: tpi, sum1, dnorm, dnorm1, dnorm2
2844 real(real64) :: cosphin, phin, costn, sum2, betan
2845 integer :: nsfe1, ia, nn, n0, n1, n2
2860 point_1 = pts(:,nn) - ccc(:,nn)
2862 point_2 = pts(:,nn+1) - ccc(:,nn)
2864 point_2 = pts(:,1) - ccc(:,nn)
2867 dnorm1 = norm2(point_1)
2868 dnorm2 = norm2(point_2)
2869 cosphin = dot_product(point_1, point_2) / (dnorm1*dnorm2)
2871 if (cosphin > m_one) cosphin = m_one
2872 if (cosphin < -m_one) cosphin = -m_one
2874 phin =
acos(cosphin)
2877 point_1(1) = sfe(nsfe1)%x - sfe(ns)%x
2878 point_1(2) = sfe(nsfe1)%y - sfe(ns)%y
2879 point_1(3) = sfe(nsfe1)%z - sfe(ns)%z
2881 dnorm1 = norm2(point_1)
2883 if (abs(dnorm1) <= m_epsilon) dnorm1 = m_one
2885 point_2(1) = pts(1,nn) - sfe(ns)%x
2886 point_2(2) = pts(2,nn) - sfe(ns)%y
2887 point_2(3) = pts(3,nn) - sfe(ns)%z
2889 dnorm2 = norm2(point_2)
2891 costn = dot_product(point_1, point_2) / (dnorm1 * dnorm2)
2892 sum1 = sum1 + phin * costn
2903 if (nn > 1) n0 = nn - 1
2904 if (nn == 1) n0 = nv
2905 if (nn < nv) n2 = nn + 1
2906 if (nn == nv) n2 = 1
2908 p1 = pts(:,n1) - ccc(:,n0)
2909 p2 = pts(:,n0) - ccc(:,n0)
2910 call vecp(p1, p2, p3, dnorm)
2913 call vecp(p1, p2, p3, dnorm)
2916 p1 = pts(:,n1) - ccc(:,n1)
2917 p2 = pts(:,n2) - ccc(:,n1)
2918 call vecp(p1, p2, p3, dnorm)
2921 call vecp(p1, p2, p3, dnorm)
2925 sum2 = sum2 + (m_pi - betan)
2929 area = sfe(ns)%r*sfe(ns)%r*(tpi + sum1 - sum2)
2935 pp(1) = pp(1) + (pts(1,ia) - sfe(ns)%x)
2936 pp(2) = pp(2) + (pts(2,ia) - sfe(ns)%y)
2937 pp(3) = pp(3) + (pts(3,ia) - sfe(ns)%z)
2942 pp(1) = sfe(ns)%x + pp(1) * sfe(ns)%r / dnorm
2943 pp(2) = sfe(ns)%y + pp(2) * sfe(ns)%r / dnorm
2944 pp(3) = sfe(ns)%z + pp(3) * sfe(ns)%r / dnorm
2947 pp1(1) = (pp(1) - sfe(ns)%x) / sfe(ns)%r
2948 pp1(2) = (pp(2) - sfe(ns)%y) / sfe(ns)%r
2949 pp1(3) = (pp(3) - sfe(ns)%z) / sfe(ns)%r
2952 if (area < m_zero) area = m_zero
2960 subroutine vecp(p1, p2, p3, dnorm)
2961 real(real64),
intent(in) :: P1(:)
2962 real(real64),
intent(in) :: P2(:)
2963 real(real64),
intent(out) :: P3(:)
2964 real(real64),
intent(out) :: dnorm
2967 p3(1) = p1(2)*p2(3) - p1(3)*p2(2)
2968 p3(2) = p1(3)*p2(1) - p1(1)*p2(3)
2969 p3(3) = p1(1)*p2(2) - p1(2)*p2(1)
2976 type(
pcm_t),
intent(inout) :: pcm
2978 integer :: asc_unit_test, asc_unit_test_sol, asc_unit_test_e, asc_unit_test_n, asc_unit_test_ext
2983 if (pcm%solute .and. pcm%localf)
then
2984 asc_unit_test = io_open(pcm_dir//
'ASC.dat', pcm%namespace, action=
'write')
2985 asc_unit_test_sol = io_open(pcm_dir//
'ASC_sol.dat', pcm%namespace, action=
'write')
2986 asc_unit_test_e = io_open(pcm_dir//
'ASC_e.dat', pcm%namespace, action=
'write')
2987 asc_unit_test_n = io_open(pcm_dir//
'ASC_n.dat', pcm%namespace, action=
'write')
2988 asc_unit_test_ext = io_open(pcm_dir//
'ASC_ext.dat', pcm%namespace, action=
'write')
2989 do ia = 1, pcm%n_tesserae
2990 write(asc_unit_test,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia) + pcm%q_ext(ia), ia
2991 write(asc_unit_test_sol,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia), ia
2992 write(asc_unit_test_e,*) pcm%tess(ia)%point, pcm%q_e(ia), ia
2993 write(asc_unit_test_n,*) pcm%tess(ia)%point, pcm%q_n(ia), ia
2994 write(asc_unit_test_ext,*) pcm%tess(ia)%point, pcm%q_ext(ia), ia
2996 call io_close(asc_unit_test)
2997 call io_close(asc_unit_test_sol)
2998 call io_close(asc_unit_test_e)
2999 call io_close(asc_unit_test_n)
3000 call io_close(asc_unit_test_ext)
3002 else if (pcm%solute .and. .not. pcm%localf)
then
3003 asc_unit_test_sol = io_open(pcm_dir//
'ASC_sol.dat', pcm%namespace, action=
'write')
3004 asc_unit_test_e = io_open(pcm_dir//
'ASC_e.dat', pcm%namespace, action=
'write')
3005 asc_unit_test_n = io_open(pcm_dir//
'ASC_n.dat', pcm%namespace, action=
'write')
3006 do ia = 1, pcm%n_tesserae
3007 write(asc_unit_test_sol,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia), ia
3008 write(asc_unit_test_e,*) pcm%tess(ia)%point, pcm%q_e(ia), ia
3009 write(asc_unit_test_n,*) pcm%tess(ia)%point, pcm%q_n(ia), ia
3011 call io_close(asc_unit_test_sol)
3012 call io_close(asc_unit_test_e)
3013 call io_close(asc_unit_test_n)
3015 else if (.not. pcm%solute .and. pcm%localf)
then
3016 asc_unit_test_ext = io_open(pcm_dir//
'ASC_ext.dat', pcm%namespace, action=
'write')
3017 do ia = 1, pcm%n_tesserae
3018 write(asc_unit_test_ext,*) pcm%tess(ia)%point, pcm%q_ext(ia), ia
3020 call io_close(asc_unit_test_ext)
3023 safe_deallocate_a(pcm%spheres)
3024 safe_deallocate_a(pcm%tess)
3025 safe_deallocate_a(pcm%matrix)
3026 if (.not. is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
3027 safe_deallocate_a(pcm%matrix_d)
3029 safe_deallocate_a(pcm%q_e)
3030 safe_deallocate_a(pcm%q_e_in)
3031 safe_deallocate_a(pcm%q_n)
3032 safe_deallocate_a(pcm%v_e)
3033 safe_deallocate_a(pcm%v_n)
3034 safe_deallocate_a(pcm%v_e_rs)
3035 safe_deallocate_a(pcm%v_n_rs)
3036 if (pcm%localf)
then
3037 safe_deallocate_a(pcm%matrix_lf)
3038 if (.not. is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
3039 safe_deallocate_a(pcm%matrix_lf_d)
3042 safe_deallocate_a(pcm%q_ext)
3043 safe_deallocate_a(pcm%q_ext_in)
3044 safe_deallocate_a(pcm%v_ext)
3045 safe_deallocate_a(pcm%v_ext_rs)
3046 if (pcm%kick_is_present)
then
3047 safe_deallocate_a(pcm%q_kick)
3048 safe_deallocate_a(pcm%v_kick)
3049 safe_deallocate_a(pcm%v_kick_rs)
3054 safe_deallocate_a( pcm%rho_n)
3055 safe_deallocate_a( pcm%rho_e)
3056 if (pcm%localf)
then
3057 safe_deallocate_a( pcm%rho_ext)
3058 if (pcm%kick_is_present)
then
3059 safe_deallocate_a( pcm%rho_kick)
3064 if (pcm%tdlevel ==
pcm_td_eom)
call pcm_eom_end()
3066 if (mpi_world%is_root())
call io_close(pcm%info_unit)
3073 logical function pcm_update(this)
result(update)
3074 type(
pcm_t),
intent(inout) :: this
3076 this%iter = this%iter + 1
3077 update = this%iter <= 6 .or. mod(this%iter, this%update_iter) == 0
3083 real(real64) function
pcm_get_vdw_radius(species, pcm_vdw_type, namespace) result(vdw_r)
3084 class(species_t),
intent(in) :: species
3085 integer,
intent(in) :: pcm_vdw_type
3086 type(namespace_t),
intent(in) :: namespace
3089 integer,
parameter :: upto_xe = 54
3090 real(real64),
save :: vdw_radii(1:upto_xe)
3093 data (vdw_radii(ia), ia=1, upto_xe) / &
3095 1.001_real64, 1.012_real64, &
3097 0.825_real64, 1.408_real64, 1.485_real64, 2.000_real64, 1.583_real64, 1.500_real64, 1.287_real64, 1.243_real64, &
3099 1.144_real64, 1.364_real64, 1.639_real64, 1.716_real64, 1.705_real64, 1.683_real64, 1.639_real64, 1.595_real64, &
3101 1.485_real64, 1.474_real64, &
3103 1.562_real64, 1.562_real64, &
3104 1.562_real64, 1.562_real64, &
3105 1.562_real64, 1.562_real64, &
3106 1.562_real64, 1.562_real64, &
3107 1.562_real64, 1.562_real64, &
3109 1.650_real64, 1.727_real64, 1.760_real64, 1.771_real64, 1.749_real64, 1.727_real64, &
3111 1.628_real64, 1.606_real64, 1.639_real64, 1.639_real64, &
3112 1.639_real64, 1.639_real64, &
3113 1.639_real64, 1.639_real64, &
3114 1.639_real64, 1.639_real64, &
3115 1.639_real64, 1.639_real64, &
3117 2.672_real64, 1.804_real64, 1.881_real64, 1.892_real64, 1.892_real64, 1.881_real64 /
3119 select case (pcm_vdw_type)
3121 if (species%get_z() > upto_xe)
then
3122 write(message(1),
'(a,a)')
"The van der Waals radius is missing for element ", trim(species%get_label())
3123 write(message(2),
'(a)')
"Use PCMVdWRadii = pcm_vdw_species, for other vdw radii values"
3124 call messages_fatal(2, namespace=namespace)
3126 ia = int(species%get_z())
3127 vdw_r = vdw_radii(ia)*p_ang
3130 vdw_r = species%get_vdw_radius()
3131 if (vdw_r < m_zero)
then
3132 call messages_write(
'The default vdW radius for species '//trim(species%get_label())//
':')
3133 call messages_write(
' is not defined. ')
3134 call messages_write(
' Add a positive vdW radius value in %Species block. ')
3135 call messages_fatal(namespace=namespace)
3144 subroutine pcm_dipole(mu_pcm, q_pcm, tess, n_tess)
3145 real(real64),
intent(out) :: mu_pcm(:)
3146 real(real64),
intent(in) :: q_pcm(:)
3147 integer,
intent(in) :: n_tess
3148 type(pcm_tessera_t),
intent(in) :: tess(:)
3156 mu_pcm = mu_pcm + q_pcm(ia) * tess(ia)%point
3164 subroutine pcm_eps(pcm, eps, omega)
3166 complex(real64),
intent(out) :: eps
3167 real(real64),
intent(in) :: omega
3172 if (pcm%which_eps == pcm_debye_model)
then
3174 else if (pcm%which_eps == pcm_drude_model)
then
3190 type(namespace_t),
intent(in) :: namespace
3195 call parse_variable(namespace,
'PCMCalculation', .false., pcm%run_pcm)
3196 call messages_print_with_emphasis(msg=
'PCM', namespace=namespace)
3197 call parse_variable(namespace,
'PCMLocalField', .false., pcm%localf)
3198 call messages_print_var_value(
"PCMLocalField", pcm%localf, namespace=namespace)
3199 if (pcm%localf)
then
3200 call messages_experimental(
"PCM local field effects in the optical spectrum", namespace=namespace)
3201 call messages_write(
'Beware of possible numerical errors in the optical spectrum due to PCM local field effects,')
3202 call messages_new_line()
3203 call messages_write(
'particularly, when static and high-frequency values of the dielectric functions are large')
3204 call messages_write(
' (>~10 in units of the vacuum permittivity \epsilon_0).')
3205 call messages_new_line()
3206 call messages_write(
'However, PCM local field effects in the optical spectrum work well for polar or non-polar solvents')
3207 call messages_new_line()
3208 call messages_write(
'in the nonequilibrium or equation-of-motion TD-PCM propagation schemes.')
3209 call messages_warning(namespace=namespace)
3211 call parse_variable(namespace,
'PCMTDLevel' ,
pcm_td_eq, pcm%tdlevel)
3212 call messages_print_var_value(
"PCMTDLevel", pcm%tdlevel, namespace=namespace)
3215 call parse_variable(namespace,
'PCMStaticEpsilon' , m_one, pcm%deb%eps_0)
3216 call messages_print_var_value(
"PCMStaticEpsilon", pcm%deb%eps_0, namespace=namespace)
3218 call parse_variable(namespace,
'PCMEpsilonModel', pcm_debye_model, pcm%which_eps)
3219 call messages_print_var_value(
"PCMEpsilonModel", pcm%which_eps, namespace=namespace)
3220 if (pcm%which_eps == pcm_debye_model)
then
3221 call parse_variable(namespace,
'PCMDynamicEpsilon', pcm%deb%eps_0, pcm%deb%eps_d)
3222 call messages_print_var_value(
"PCMDynamicEpsilon", pcm%deb%eps_d, namespace=namespace)
3223 call parse_variable(namespace,
'PCMDebyeRelaxTime', m_zero, pcm%deb%tau)
3224 call messages_print_var_value(
"PCMDebyeRelaxTime", pcm%deb%tau, namespace=namespace)
3225 else if (pcm%which_eps == pcm_drude_model)
then
3226 call parse_variable(namespace,
'PCMDrudeLOmega',
sqrt(m_one/(pcm%deb%eps_0-m_one)), pcm%drl%w0)
3227 call messages_print_var_value(
"PCMDrudeLOmega", pcm%drl%w0, namespace=namespace)
3228 call parse_variable(namespace,
'PCMDrudeLDamping', m_zero, pcm%drl%gm)
3229 call messages_print_var_value(
"PCMDrudeLDamping", pcm%drl%gm, namespace=namespace)
3232 call parse_variable(namespace,
'PCMDynamicEpsilon', pcm%deb%eps_0, pcm%deb%eps_d)
3233 call messages_print_var_value(
"PCMDynamicEpsilon", pcm%deb%eps_d, namespace=namespace)
3242 complex(real64),
intent(out) :: eps
3243 type(debye_param_t),
intent(in) :: deb
3244 real(real64),
intent(in) :: omega
3248 eps = deb%eps_d + (deb%eps_0 - deb%eps_d)/(m_one + (omega*deb%tau)**2) + &
3249 m_zi*omega*deb%tau*(deb%eps_0 - deb%eps_d)/(m_one + (omega*deb%tau)**2)
3257 complex(real64),
intent(out) :: eps
3258 type(drude_param_t),
intent(in) :: drl
3259 real(real64),
intent(in) :: omega
3263 eps = m_one + (drl%w0**2 - omega**2)*drl%aa/((drl%w0**2 - omega**2)**2 + (omega*drl%gm)**2) + &
3264 m_zi*omega*drl%gm*drl%aa/((drl%w0**2 - omega**2)**2 + (omega*drl%gm)**2)
Prints out to iunit a message in the form: ["InputVariable" = value] where "InputVariable" is given b...
double acos(double __x) __attribute__((__nothrow__
double exp(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
double floor(double __x) __attribute__((__nothrow__
type(debug_t), save, public debug
real(real64), parameter, public m_two
real(real64), parameter, public m_zero
real(real64), parameter, public m_four
real(real64), parameter, public p_a_b
some physical constants
real(real64), parameter, public m_pi
some mathematical constants
character(len= *), parameter, public pcm_dir
real(real64), parameter, public m_epsilon
real(real64), parameter, public m_half
real(real64), parameter, public m_one
This module implements the underlying real-space grid.
This module implements the index, used for the mesh points.
subroutine, public dio_function_output(how, dir, fname, namespace, space, mesh, ff, unit, ierr, pos, atoms, grp, root)
Top-level IO routine for functions defined on the mesh.
integer(int64) function, public io_function_fill_how(where)
Use this function to quickly plot functions for debugging purposes: call dio_function_output(io_funct...
subroutine, public io_close(iunit, grp)
subroutine, public io_mkdir(fname, namespace, parents)
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
This module is intended to contain "only mathematical" functions and procedures.
This module defines various routines, operating on mesh functions.
subroutine, public mesh_interpolation_init(this, mesh)
subroutine, public mesh_interpolation_end(this)
This module defines the meshes, which are used in Octopus.
integer function, public mesh_local_index_from_coords(mesh, ix)
This function returns the local index of the point for a given vector of integer coordinates.
integer(int64) function, public mesh_global_index_from_coords(mesh, ix)
This function returns the true global index of the point for a given vector of integer coordinates.
pure subroutine, public mesh_r(mesh, ip, rr, origin, coords)
return the distance to the origin for a given grid point
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
character(len=512), private msg
subroutine, public messages_warning(no_lines, all_nodes, namespace)
subroutine, public messages_new_line()
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
subroutine, public messages_input_error(namespace, var, details, row, column)
subroutine, public messages_experimental(name, namespace)
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
type(mpi_grp_t), public mpi_world
Some general things and nomenclature:
integer, parameter, public pcm_external_plus_kick
integer, parameter, public pcm_electrons
integer, parameter, public pcm_kick
integer, parameter, public pcm_nuclei
subroutine, public pcm_charges_propagation(q_t, pot_t, this_dt, this_cts_act, input_asc, this_eom, this_eps, namespace, this_deb, this_drl)
Driving subroutine for the Equation of Motion (EOM) propagation of the polarization charges within th...
integer, parameter, public pcm_external_potential
integer, parameter, public pcm_drude_model
subroutine, public pcm_eom_enough_initial(not_yet_called)
integer, parameter, public pcm_debye_model
subroutine, public pcm_calc_pot_rs(pcm, mesh, psolver, ions, v_h, v_ext, kick, time_present, kick_time)
subroutine pcm_eps_deb(eps, deb, omega)
logical function, public pcm_update(this)
Update pcm potential.
subroutine, public pcm_pot_rs(pcm, v_pcm, q_pcm, rho, mesh, psolver)
Generates the potential 'v_pcm' in real-space.
integer, parameter n_tess_sphere
minimum number of tesserae per sphere
subroutine pcm_eps_drl(eps, drl, omega)
logical function pcm_nn_in_mesh(pcm, mesh)
Check wether the nearest neighbor requested are in the mesh or not.
integer, parameter, public pcm_calc_direct
subroutine, public pcm_charge_density(pcm, q_pcm, q_pcm_tot, mesh, rho)
Generates the polarization charge density smearing the charge with a gaussian distribution on the mes...
real(real64) function, public pcm_get_vdw_radius(species, pcm_vdw_type, namespace)
get the vdw radius
subroutine pcm_matrix(eps, tess, n_tess, pcm_mat, localf)
Generates the PCM response matrix. J. Tomassi et al. Chem. Rev. 105, 2999 (2005).
subroutine, public pcm_dipole(mu_pcm, q_pcm, tess, n_tess)
Computes the dipole moment mu_pcm due to a distribution of charges q_pcm.
subroutine, public pcm_elect_energy(ions, pcm, E_int_ee, E_int_en, E_int_ne, E_int_nn, E_int_e_ext, E_int_n_ext)
Calculates the solute-solvent electrostatic interaction energy .
real(real64) function s_mat_elem_i(tessi, tessj)
electrostatic Green function in vacuo:
subroutine d_i_matrix(n_tess, tess)
integer, parameter, public pcm_td_eom
subroutine, public pcm_charges(q_pcm, q_pcm_tot, v_cav, pcm_mat, n_tess, qtot_nominal, epsilon, renorm_charges, q_tot_tol, deltaQ)
Calculates the polarization charges at each tessera by using the response matrix 'pcm_mat',...
integer, parameter pcm_vdw_species
subroutine, public pcm_v_cav_li(v_cav, v_mesh, pcm, mesh)
Calculates the Hartree/external/kick potential at the tessera representative points by doing a 3D lin...
integer, parameter, public pcm_calc_poisson
subroutine gaubon(sfe, nv, ns, pts, ccc, pp, pp1, area, intsph)
Use the Gauss-Bonnet theorem to calculate the area of the tessera with vertices 'pts(3,...
real(real64), dimension(:,:), allocatable mat_gamess
PCM matrix formatted to be inputed to GAMESS.
subroutine pcm_poisson_sanity_check(pcm, mesh)
Check that all the required nearest neighbors are prensent in the mesh.
subroutine pcm_pot_rs_poisson(namespace, v_pcm, psolver, rho)
Generates the potential 'v_pcm' in real-space solving the poisson equation for rho.
real(real64) function d_mat_elem_i(tessi, tessj)
Gradient of the Green function in vacuo .
subroutine s_i_matrix(n_tess, tess)
subroutine pcm_pot_rs_direct(v_pcm, q_pcm, tess, n_tess, mesh, width_factor)
Generates the potential 'v_pcm' in real-space by direct sum.
subroutine, public pcm_eps(pcm, eps, omega)
subroutine, public pcm_v_nuclei_cav(v_n_cav, ions, tess, n_tess)
Calculates the classical electrostatic potential geneated by the nuclei at the tesserae....
subroutine, public pcm_end(pcm)
integer, parameter pcm_vdw_optimized
subroutine, public pcm_init(pcm, namespace, space, ions, grid, qtot, val_charge, external_potentials_present, kick_present)
Initializes the PCM calculation: reads the VdW molecular cavity and generates the PCM response matrix...
integer, parameter, public pcm_td_neq
subroutine vecp(p1, p2, p3, dnorm)
calculates the vectorial product p3 = p1 x p2
subroutine inter(sfe, p1, p2, p3, p4, ns, ia)
Finds the point 'p4', on the arc 'p1'-'p2' developed from 'p3', which is on the surface of sphere 'ns...
integer, parameter, public pcm_td_eq
subroutine subtessera(sfe, ns, nesf, nv, pts, ccc, pp, pp1, area)
find the uncovered region for each tessera and computes the area, the representative point (pp) and t...
subroutine, public pcm_min_input_parsing_for_spectrum(pcm, namespace)
subroutine cav_gen(tess_sphere, tess_min_distance, nesf, sfe, nts, cts, unit_pcminfo)
It builds the solute cavity surface and calculates the vertices, representative points and areas of t...
subroutine, public dpoisson_solve(this, namespace, pot, rho, all_nodes, kernel, reset)
Calculates the Poisson equation. Given the density returns the corresponding potential.
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
brief This module defines the class unit_t which is used by the unit_systems_oct_m module.
This module defines the unit system, used for input and output.
type(unit_system_t), public units_out
type(unit_system_t), public units_inp
the units systems for reading and writing
type(unit_t), public unit_one
some special units required for particular quantities
Class implementing a box that is a union of spheres. We do this in a specific class instead of using ...
Description of the grid, containing information on derivatives, stencil, and symmetries.
Describes mesh distribution to nodes.
The cavity hosting the solute molecule is built from a set of interlocking spheres with optimized rad...