26 use,
intrinsic :: iso_fortran_env
90 integer,
parameter :: PCM_DIM_SPACE = 3
94 logical,
public :: run_pcm
95 integer,
public :: tdlevel
97 integer,
public :: n_tesserae
98 type(pcm_sphere_t),
allocatable :: spheres(:)
99 type(pcm_tessera_t),
allocatable,
public :: tess(:)
100 real(real64) :: scale_r
101 real(real64),
allocatable :: matrix(:,:)
102 real(real64),
allocatable :: matrix_d(:,:)
103 real(real64),
allocatable :: matrix_lf(:,:)
104 real(real64),
allocatable :: matrix_lf_d(:,:)
105 real(real64),
allocatable,
public :: q_e(:)
106 real(real64),
allocatable :: q_n(:)
107 real(real64),
allocatable,
public :: q_e_in(:)
108 real(real64),
allocatable :: rho_e(:)
109 real(real64),
allocatable :: rho_n(:)
110 real(real64) :: qtot_e
111 real(real64) :: qtot_n
112 real(real64) :: qtot_e_in
113 real(real64) :: q_e_nominal
114 real(real64) :: q_n_nominal
115 logical :: renorm_charges
116 real(real64) :: q_tot_tol
117 real(real64) :: deltaQ_e
118 real(real64) :: deltaQ_n
119 real(real64),
allocatable :: v_e(:)
120 real(real64),
allocatable :: v_n(:)
121 real(real64),
allocatable,
public :: v_e_rs(:)
122 real(real64),
allocatable,
public :: v_n_rs(:)
123 real(real64),
allocatable :: q_ext(:)
124 real(real64),
allocatable :: q_ext_in(:)
125 real(real64),
allocatable :: rho_ext(:)
126 real(real64) :: qtot_ext
127 real(real64) :: qtot_ext_in
128 real(real64),
allocatable :: v_ext(:)
129 real(real64),
allocatable,
public :: v_ext_rs(:)
130 real(real64),
allocatable :: q_kick(:)
131 real(real64),
allocatable :: rho_kick(:)
132 real(real64) :: qtot_kick
133 real(real64),
allocatable :: v_kick(:)
134 real(real64),
allocatable,
public :: v_kick_rs(:)
135 real(real64),
public :: epsilon_0
136 real(real64),
public :: epsilon_infty
137 integer,
public :: which_eps
138 type(debye_param_t) :: deb
139 type(drude_param_t) :: drl
140 logical,
public :: localf
141 logical,
public :: solute
142 logical :: kick_is_present
144 logical,
public :: kick_like
145 integer :: initial_asc
146 real(real64) :: gaussian_width
148 integer,
public :: counter
149 character(len=80) :: input_cavity
150 integer :: update_iter
151 integer,
public :: iter
152 integer :: calc_method
154 real(real64),
public :: dt
158 type(namespace_t),
pointer :: namespace
159 type(space_t) :: space
168 type(debye_param_t) :: deb
169 type(drude_param_t) :: drl
172 real(real64),
allocatable :: s_mat_act(:,:)
173 real(real64),
allocatable :: d_mat_act(:,:)
174 real(real64),
allocatable :: Sigma(:,:)
175 real(real64),
allocatable :: Delta(:,:)
177 logical :: gamess_benchmark
180 integer,
parameter :: &
185 integer,
parameter,
public :: &
189 integer,
parameter :: &
200 subroutine pcm_init(pcm, namespace, space, ions, grid, qtot, val_charge, external_potentials_present, kick_present)
206 real(real64),
intent(in) :: qtot
207 real(real64),
intent(in) :: val_charge
208 logical,
intent(in) :: external_potentials_present
209 logical,
intent(in) :: kick_present
211 integer :: ia, ii, itess, jtess, pcm_vdw_type, subdivider
212 integer :: cav_unit_test, iunit, pcmmat_unit
213 integer :: pcmmat_gamess_unit, cav_gamess_unit
214 real(real64) :: min_distance
216 integer,
parameter :: mxts = 10000
218 real(real64) :: default_value
219 real(real64) :: vdw_radius
224 logical :: add_spheres_h
225 logical :: changed_default_nn
227 integer :: default_nn
228 real(real64) :: max_area
232 pcm%kick_is_present = kick_present
237 pcm%kick_like = .false.
239 pcm%namespace => namespace
255 if (pcm%run_pcm)
then
257 if (pcm%space%dim /= pcm_dim_space)
then
258 message(1) =
"PCM is only available for 3d calculations"
261 select type (box => grid%box)
264 message(1) =
"PCM is only available for BoxShape = minimum"
288 select case (pcm_vdw_type)
290 default_value = 1.2_real64
292 default_value =
m_one
303 call parse_variable(namespace,
'PCMRadiusScaling', default_value, pcm%scale_r)
327 if (pcm%tdlevel /=
pcm_td_eq .and. (.not. pcm%run_pcm))
then
328 call messages_write(
'Sorry, you have set PCMTDLevel /= eq, but PCMCalculation = no.')
330 call messages_write(
'To spare you some time, Octopus will proceed as if PCMCalculation = yes.')
352 call parse_variable(namespace,
'PCMDynamicEpsilon', pcm%epsilon_0, pcm%epsilon_infty)
375 call messages_write(
'Sorry, only Debye or Drude-Lorentz dielectric models are available.')
377 call messages_write(
'To spare you some time, Octopus will proceed with the default choice (Debye).')
379 call messages_write(
'You may change PCMEpsilonModel value for a Drude-Lorentz run.')
384 call messages_write(
'Sorry, inertial/dynamic polarization splitting scheme for TD-PCM')
387 call messages_write(
'require both static and dynamic dielectric constants,')
390 call messages_write(
'Octopus will run using TD-PCM version in equilibrium')
410 call parse_variable(namespace,
'PCMEoMInitialCharges', 0, pcm%initial_asc)
413 if (pcm%initial_asc /= 0)
then
417 call messages_write(
'Sorry, initial polarization charges can only be read')
421 call messages_write(
'Octopus will proceed as if PCMEoMInitialCharges = 0.')
428 pcm%deb%eps_0 = pcm%epsilon_0
429 pcm%deb%eps_d = pcm%epsilon_infty
446 (abs(pcm%deb%tau) <=
m_epsilon .or.
is_close(pcm%deb%eps_0, pcm%deb%eps_d)))
then
448 call messages_write(
'but you have not included all required Debye model parameters.')
450 call messages_write(
'You need PCMEpsilonStatic, PCMEpsilonDynamic')
451 call messages_write(
'and PCMDebyeRelaxTime for an EOM TD-PCM run.')
453 call messages_write(
'Octopus will run using TD-PCM version in equilibrium')
461 message(1) =
"PCMEpsilonStatic = 1 is incompatible with a Drude-Lorentz EOM-PCM run."
480 call messages_write(
'but this is incompatible with a Drude-Lorentz EOM-PCM run.')
483 call messages_write(
'Octopus will run using the default value of PCMDrudeLOmega.')
487 message(1) =
"PCMEpsilonStatic = 1 is incompatible with a Drude-Lorentz EOM-PCM run."
504 pcm%drl%aa = (pcm%epsilon_0 -
m_one)*pcm%drl%w0**2
516 call parse_variable(namespace,
'PCMLocalField', .false., pcm%localf)
519 if (pcm%localf .and. ((.not. external_potentials_present) .and. (.not. pcm%kick_is_present)))
then
520 message(1) =
"Sorry, you have set PCMLocalField = yes, but you have not included any external potentials."
536 if (pcm%run_pcm .and. (.not. pcm%solute))
then
537 call messages_write(
'N.B. This PCM run do not consider the polarization effects due to the solute.')
539 if (.not. pcm%localf)
then
540 message(1) =
"You have activated a PCM run without polarization effects. Octopus will halt."
559 if (pcm%kick_like .and. (.not. pcm%run_pcm))
then
560 message(1) =
"PCMKick option can only be activated when PCMCalculation = yes. Octopus will halt."
564 if (pcm%kick_like .and. (.not. pcm%localf))
then
565 message(1) =
"PCMKick option can only be activated when a PCMLocalField = yes. Octopus will halt."
569 if (pcm%kick_like .and. (.not. pcm%kick_is_present))
then
570 message(1) =
"Sorry, you have set PCMKick = yes, but you have not included any kick."
574 if (pcm%kick_is_present .and. pcm%run_pcm .and. (.not. pcm%localf))
then
575 message(1) =
"You have set up a PCM calculation with a kick without local field effects."
576 message(2) =
"Please, reconsider if you want the kick to be relevant for the PCM run."
587 call parse_variable(namespace,
'PCMUpdateIter', 1, pcm%update_iter)
598 call parse_variable(namespace,
'PCMGamessBenchmark', .false., gamess_benchmark)
611 call parse_variable(namespace,
'PCMRenormCharges', .false., pcm%renorm_charges)
627 if (pcm%renorm_charges)
then
628 message(1) =
"Info: Polarization charges will be renormalized"
629 message(2) =
" if |Q_tot_PCM - Q_M| > PCMQtotTol"
645 if (abs(pcm%gaussian_width) <=
m_epsilon)
then
646 message(1) =
"Info: PCM potential will be defined in terms of polarization point charges"
649 message(1) =
"Info: PCM potential is regularized to avoid Coulomb singularity"
671 if (pcm%input_cavity ==
'')
then
680 call parse_variable(namespace,
'PCMSpheresOnH', .false., add_spheres_h)
684 do ia = 1, ions%natoms
685 if ((.not. add_spheres_h) .and. ions%atom(ia)%label ==
'H') cycle
686 pcm%n_spheres = pcm%n_spheres + 1
689 safe_allocate(pcm%spheres(1:pcm%n_spheres))
696 do ia = 1, ions%natoms
697 if ((.not. add_spheres_h) .and. ions%atom(ia)%label ==
'H') cycle
698 pcm%n_spheres = pcm%n_spheres + 1
701 pcm%spheres(pcm%n_spheres)%x = ions%pos(1, ia)
702 pcm%spheres(pcm%n_spheres)%y = ions%pos(2, ia)
703 pcm%spheres(pcm%n_spheres)%z = ions%pos(3, ia)
706 pcm%spheres(pcm%n_spheres)%r = vdw_radius*pcm%scale_r
710 pcm%info_unit =
io_open(
pcm_dir//
'pcm_info.out', pcm%namespace, action=
'write')
712 write(pcm%info_unit,
'(A35)')
'# Configuration: Molecule + Solvent'
713 write(pcm%info_unit,
'(A35)')
'# ---------------------------------'
714 write(pcm%info_unit,
'(A21,F12.3)')
'# Epsilon(Solvent) = ', pcm%epsilon_0
715 write(pcm%info_unit,
'(A1)')
'#'
716 write(pcm%info_unit,
'(A35,I4)')
'# Number of interlocking spheres = ', pcm%n_spheres
717 write(pcm%info_unit,
'(A1)')
'#'
719 write(pcm%info_unit,
'(A8,3X,A7,8X,A26,20X,A10)')
'# SPHERE',
'ELEMENT',
'CENTER (X,Y,Z) (A)',
'RADIUS (A)'
720 write(pcm%info_unit,
'(A8,3X,A7,4X,A43,7X,A10)')
'# ------',
'-------', &
721 '-------------------------------------------',
'----------'
725 do ia = 1, ions%natoms
726 if ((.not. add_spheres_h) .and. ions%atom(ia)%label ==
'H') cycle
727 pcm%n_spheres = pcm%n_spheres + 1
729 write(pcm%info_unit,
'(A1,2X,I3,7X,A2,3X,F14.8,2X,F14.8,2X,F14.8,4X,F14.8)')
'#', pcm%n_spheres, &
730 ions%atom(ia)%label, &
731 ions%pos(1, ia)*
p_a_b, &
732 ions%pos(2, ia)*
p_a_b, &
733 ions%pos(3, ia)*
p_a_b, &
734 pcm%spheres(pcm%n_spheres)%r*
p_a_b
746 call parse_variable(namespace,
'PCMTessSubdivider', 1, subdivider)
748 safe_allocate(dum2(1:subdivider*
n_tess_sphere*pcm%n_spheres))
758 call parse_variable(namespace,
'PCMTessMinDistance', 0.1_real64, min_distance)
762 call cav_gen(subdivider, min_distance, pcm%n_spheres, pcm%spheres, pcm%n_tesserae, dum2, pcm%info_unit)
764 safe_allocate(pcm%tess(1:pcm%n_tesserae))
766 do ia=1, pcm%n_tesserae
767 pcm%tess(ia)%point =
m_zero
768 pcm%tess(ia)%area =
m_zero
769 pcm%tess(ia)%r_sphere =
m_zero
770 pcm%tess(ia)%normal =
m_zero
773 pcm%tess = dum2(1:pcm%n_tesserae)
775 safe_deallocate_a(dum2)
777 message(1) =
"Info: van der Waals surface has been calculated"
783 iunit =
io_open(trim(pcm%input_cavity), pcm%namespace, action=
'read', status=
'old')
784 read(iunit,*) pcm%n_tesserae
786 if (pcm%n_tesserae > mxts)
then
787 write(
message(1),
'(a,I5,a,I5)')
"total number of tesserae", pcm%n_tesserae,
">", mxts
791 safe_allocate(pcm%tess(1:pcm%n_tesserae))
793 do ia = 1, pcm%n_tesserae
794 pcm%tess(ia)%point =
m_zero
795 pcm%tess(ia)%area =
m_zero
796 pcm%tess(ia)%r_sphere =
m_zero
797 pcm%tess(ia)%normal =
m_zero
800 do ia = 1, pcm%n_tesserae
801 read(iunit,*) pcm%tess(ia)%point(1)
804 do ia = 1, pcm%n_tesserae
805 read(iunit,*) pcm%tess(ia)%point(2)
808 do ia = 1, pcm%n_tesserae
809 read(iunit,*) pcm%tess(ia)%point(3)
812 do ia = 1, pcm%n_tesserae
813 read(iunit,*) pcm%tess(ia)%area
816 do ia = 1, pcm%n_tesserae
817 read(iunit,*) pcm%tess(ia)%r_sphere
820 do ia = 1, pcm%n_tesserae
821 read(iunit,*) pcm%tess(ia)%normal
825 message(1) =
"Info: van der Waals surface has been read from " // trim(pcm%input_cavity)
830 cav_unit_test =
io_open(
pcm_dir//
'cavity_mol.xyz', pcm%namespace, action=
'write')
832 write (cav_unit_test,
'(2X,I4)') pcm%n_tesserae + ions%natoms
833 write (cav_unit_test,
'(2X)')
835 do ia = 1, pcm%n_tesserae
836 write(cav_unit_test,
'(2X,A2,3X,4f15.8,3X,4f15.8,3X,4f15.8)')
'H', pcm%tess(ia)%point*
p_a_b
839 do ia = 1, ions%natoms
840 write(cav_unit_test,
'(2X,A2,3X,4f15.8,3X,4f15.8,3X,4f15.8)') ions%atom(ia)%label, &
841 ions%pos(:, ia)*
p_a_b
846 write(pcm%info_unit,
'(A1)')
'#'
848 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)') &
849 '#',
'iter',
'E_ee',
'E_en',
'E_nn',
'E_ne',
'E_e_ext',
'E_n_ext',
'E_M-solv', &
850 'Q_pol^e',
'deltaQ^e',
'Q_pol^n',
'deltaQ^n',
'Q_pol^ext'
852 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)') &
853 '#',
'iter',
'E_ee',
'E_en',
'E_nn',
'E_ne',
'E_M-solv',
'Q_pol^e',
'deltaQ^e',
'Q_pol^n',
'deltaQ^n'
859 if (gamess_benchmark .and.
mpi_world%is_root())
then
860 cav_gamess_unit =
io_open(
pcm_dir//
'geom_cavity_gamess.out', pcm%namespace, action=
'write')
862 write(cav_gamess_unit,*) pcm%n_tesserae
864 do ia = 1, pcm%n_tesserae
865 write(cav_gamess_unit,*) pcm%tess(ia)%point(1)
868 do ia = 1, pcm%n_tesserae
869 write(cav_gamess_unit,*) pcm%tess(ia)%point(2)
872 do ia = 1, pcm%n_tesserae
873 write(cav_gamess_unit,*) pcm%tess(ia)%point(3)
876 do ia = 1, pcm%n_tesserae
877 write(cav_gamess_unit,*) pcm%tess(ia)%area
880 do ia = 1, pcm%n_tesserae
881 write(cav_gamess_unit,*) pcm%tess(ia)%r_sphere
884 do ia = 1, pcm%n_tesserae
885 write(cav_gamess_unit,*) pcm%tess(ia)%normal
892 if (gamess_benchmark)
then
893 safe_allocate(
mat_gamess(1:pcm%n_tesserae, 1:pcm%n_tesserae))
897 if (.not.
is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
899 safe_allocate(pcm%matrix_d(1:pcm%n_tesserae, 1:pcm%n_tesserae))
902 call pcm_matrix(pcm%epsilon_infty, pcm%tess, pcm%n_tesserae, pcm%matrix_d)
904 if (gamess_benchmark .and.
mpi_world%is_root())
then
905 pcmmat_gamess_unit =
io_open(
pcm_dir//
'pcm_matrix_gamess_dyn.out', pcm%namespace, action=
'write')
907 do jtess = 1, pcm%n_tesserae
908 do itess = 1, pcm%n_tesserae
909 write(pcmmat_gamess_unit,*)
mat_gamess(itess,jtess)
919 safe_allocate(pcm%matrix_lf_d(1:pcm%n_tesserae, 1:pcm%n_tesserae))
922 call pcm_matrix(pcm%epsilon_infty, pcm%tess, pcm%n_tesserae, pcm%matrix_lf_d, .
true.)
926 pcmmat_unit =
io_open(
pcm_dir//
'pcm_matrix_dynamic_lf.out', pcm%namespace, action=
'write')
927 do jtess = 1, pcm%n_tesserae
928 do itess = 1, pcm%n_tesserae
929 write(pcmmat_unit,*) pcm%matrix_lf_d(itess,jtess)
939 safe_allocate(pcm%matrix(1:pcm%n_tesserae, 1:pcm%n_tesserae))
942 call pcm_matrix(pcm%epsilon_0, pcm%tess, pcm%n_tesserae, pcm%matrix)
945 pcmmat_unit =
io_open(
pcm_dir//
'pcm_matrix.out', pcm%namespace, action=
'write')
946 if (gamess_benchmark) pcmmat_gamess_unit =
io_open(
pcm_dir//
'pcm_matrix_gamess.out', &
947 pcm%namespace, action=
'write')
949 do jtess = 1, pcm%n_tesserae
950 do itess = 1, pcm%n_tesserae
951 write(pcmmat_unit,*) pcm%matrix(itess,jtess)
952 if (gamess_benchmark)
write(pcmmat_gamess_unit,*)
mat_gamess(itess,jtess)
956 if (gamess_benchmark)
call io_close(pcmmat_gamess_unit)
960 if (gamess_benchmark)
then
966 safe_allocate(pcm%matrix_lf(1:pcm%n_tesserae, 1:pcm%n_tesserae))
969 call pcm_matrix(pcm%epsilon_0, pcm%tess, pcm%n_tesserae, pcm%matrix_lf, .
true.)
973 pcmmat_unit =
io_open(
pcm_dir//
'pcm_matrix_static_lf.out', pcm%namespace, action=
'write')
974 do jtess = 1, pcm%n_tesserae
975 do itess = 1, pcm%n_tesserae
976 write(pcmmat_unit,*) pcm%matrix_lf(itess,jtess)
984 message(1) =
"Info: PCM response matrices has been evaluated"
1006 do ia = 1, pcm%n_tesserae
1007 if (pcm%tess(ia)%area > max_area) max_area = pcm%tess(ia)%area
1011 default_nn = int(max_area*pcm%gaussian_width/minval(grid%spacing(1:pcm%space%dim)))
1013 changed_default_nn = .false.
1015 do ii = default_nn, 1, -1
1020 changed_default_nn = .
true.
1023 if (changed_default_nn)
then
1024 call messages_write(
'PCM nearest neighbors have been reduced from ')
1034 default_nn = pcm%tess_nn
1048 call parse_variable(namespace,
'PCMChargeSmearNN', default_nn, pcm%tess_nn)
1058 safe_allocate(pcm%rho_n(1:grid%np_part))
1059 safe_allocate(pcm%rho_e(1:grid%np_part))
1060 if (pcm%localf)
then
1061 safe_allocate(pcm%rho_ext(1:grid%np_part))
1062 if (pcm%kick_is_present)
then
1063 safe_allocate(pcm%rho_kick(1:grid%np_part))
1069 safe_allocate(pcm%v_n(1:pcm%n_tesserae))
1070 safe_allocate(pcm%q_n(1:pcm%n_tesserae))
1071 safe_allocate(pcm%v_n_rs(1:grid%np))
1076 safe_allocate(pcm%v_e(1:pcm%n_tesserae))
1077 safe_allocate(pcm%q_e(1:pcm%n_tesserae))
1078 safe_allocate(pcm%v_e_rs(1:grid%np))
1083 safe_allocate(pcm%q_e_in(1:pcm%n_tesserae))
1087 if (pcm%localf)
then
1088 safe_allocate(pcm%v_ext(1:pcm%n_tesserae))
1089 safe_allocate(pcm%q_ext(1:pcm%n_tesserae))
1090 safe_allocate(pcm%v_ext_rs(1:grid%np))
1095 safe_allocate(pcm%q_ext_in(1:pcm%n_tesserae))
1098 if (pcm%kick_is_present)
then
1099 safe_allocate(pcm%v_kick(1:pcm%n_tesserae))
1100 safe_allocate(pcm%q_kick(1:pcm%n_tesserae))
1101 safe_allocate(pcm%v_kick_rs(1:grid%np))
1109 pcm%q_e_nominal = qtot
1110 pcm%q_n_nominal = val_charge
1121 subroutine pcm_calc_pot_rs(pcm, mesh, psolver, ions, v_h, v_ext, kick, time_present, kick_time)
1122 type(
pcm_t),
intent(inout) :: pcm
1123 class(
mesh_t),
intent(in) :: mesh
1125 type(
ions_t),
optional,
intent(in) :: ions
1126 real(real64),
optional,
intent(in) :: v_h(:)
1127 real(real64),
optional,
intent(in) :: v_ext(:)
1128 real(real64),
optional,
intent(in) :: kick(:)
1129 logical,
optional,
intent(in) :: time_present
1130 logical,
optional,
intent(in) :: kick_time
1132 integer,
save :: calc
1134 logical,
save :: input_asc_e
1135 logical,
save :: input_asc_ext
1140 logical,
save :: not_yet_called = .false.
1141 logical,
save :: is_time_for_kick = .false.
1142 logical,
save :: after_kick = .false.
1144 logical,
save :: td_calc_mode = .false.
1146 integer,
save :: asc_vs_t_unit_e
1148 character(len=23),
save :: asc_vs_t_unit_format
1149 character(len=16),
save :: asc_vs_t_unit_format_tail
1155 assert(
present(v_h) .or.
present(ions) .or.
present(v_ext) .or.
present(kick))
1160 if ((.not.
present(v_ext)) .and.
present(kick)) calc =
pcm_kick
1163 if (
present(time_present))
then
1164 if (time_present) td_calc_mode = .
true.
1167 if (
present(kick_time))
then
1168 is_time_for_kick = kick_time
1169 if (kick_time) after_kick = .
true.
1172 select case (pcm%initial_asc)
1174 input_asc_e = .
true.
1175 input_asc_ext = .false.
1177 input_asc_e = .false.
1178 input_asc_ext = .
true.
1180 input_asc_e = .
true.
1181 input_asc_ext = .
true.
1183 input_asc_e = .false.
1184 input_asc_ext = .false.
1189 call pcm_charges(pcm%q_n, pcm%qtot_n, pcm%v_n, pcm%matrix, pcm%n_tesserae, &
1190 pcm%q_n_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_n)
1194 call pcm_pot_rs(pcm, pcm%v_n_rs, pcm%q_n, pcm%rho_n, mesh, psolver)
1199 if (td_calc_mode .and. .not.
is_close(pcm%epsilon_infty, pcm%epsilon_0) .and. pcm%tdlevel /=
pcm_td_eq)
then
1201 select case (pcm%tdlevel)
1203 select case (pcm%which_eps)
1213 pcm%qtot_e = sum(pcm%q_e)
1215 select case (pcm%iter)
1220 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix, pcm%n_tesserae, &
1221 pcm%q_e_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1224 call pcm_charges(pcm%q_e_in, pcm%qtot_e_in, pcm%v_e, pcm%matrix_d, pcm%n_tesserae, &
1225 pcm%q_e_nominal, pcm%epsilon_infty, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1227 pcm%q_e_in = pcm%q_e - pcm%q_e_in
1228 pcm%qtot_e_in = pcm%qtot_e - pcm%qtot_e_in
1231 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix_d, pcm%n_tesserae, &
1232 pcm%q_e_nominal, pcm%epsilon_infty, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1234 pcm%q_e = pcm%q_e + pcm%q_e_in
1235 pcm%qtot_e = pcm%qtot_e + pcm%qtot_e_in
1241 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix, pcm%n_tesserae, &
1242 pcm%q_e_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1248 call pcm_pot_rs(pcm, pcm%v_e_rs, pcm%q_e, pcm%rho_e, mesh, psolver)
1258 if (td_calc_mode .and. .not.
is_close(pcm%epsilon_infty, pcm%epsilon_0) .and. pcm%tdlevel /=
pcm_td_eq)
then
1260 select case (pcm%tdlevel)
1262 select case (pcm%which_eps)
1265 pcm%which_eps, pcm%namespace, this_drl=pcm%drl)
1268 pcm%which_eps, pcm%namespace, this_deb=pcm%deb)
1272 pcm%qtot_ext = sum(pcm%q_ext)
1275 pcm%q_ext = pcm%q_ext + pcm%q_ext_in
1276 pcm%qtot_ext = pcm%qtot_ext + pcm%qtot_ext_in
1279 call pcm_charges(pcm%q_ext, pcm%qtot_ext, pcm%v_ext, pcm%matrix_lf_d, pcm%n_tesserae)
1283 pcm%q_ext = pcm%q_ext + pcm%q_ext_in
1284 pcm%qtot_ext = pcm%qtot_ext + pcm%qtot_ext_in
1291 call pcm_charges(pcm%q_ext, pcm%qtot_ext, pcm%v_ext, pcm%matrix_lf, pcm%n_tesserae)
1294 pcm%q_ext_in = pcm%q_ext
1295 pcm%qtot_ext_in = pcm%qtot_ext
1300 call pcm_pot_rs(pcm, pcm%v_ext_rs, pcm%q_ext, pcm%rho_ext, mesh, psolver)
1307 if (is_time_for_kick)
then
1312 if (pcm%kick_like)
then
1313 if (is_time_for_kick)
then
1315 if (.not.
is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
1316 call pcm_charges(pcm%q_kick, pcm%qtot_kick, pcm%v_kick, pcm%matrix_lf_d, pcm%n_tesserae)
1318 call pcm_charges(pcm%q_kick, pcm%qtot_kick, pcm%v_kick, pcm%matrix_lf, pcm%n_tesserae)
1330 if (after_kick)
then
1332 select case (pcm%which_eps)
1335 pcm%which_eps, pcm%namespace, this_drl=pcm%drl)
1338 pcm%which_eps, pcm%namespace, this_deb=pcm%deb)
1341 pcm%qtot_kick = sum(pcm%q_kick)
1357 call pcm_pot_rs(pcm, pcm%v_kick_rs, pcm%q_kick, pcm%rho_kick, mesh, psolver)
1358 if (.not. pcm%kick_like)
then
1360 pcm%q_ext = pcm%q_ext + pcm%q_kick
1361 pcm%v_ext_rs = pcm%v_ext_rs + pcm%v_kick_rs
1363 pcm%q_ext = pcm%q_kick
1364 pcm%v_ext_rs = pcm%v_kick_rs
1372 write (asc_vs_t_unit_format_tail,
'(I5,A11)') pcm%n_tesserae,
'(1X,F14.8))'
1373 write (asc_vs_t_unit_format,
'(A)')
'(F14.8,'//trim(adjustl(asc_vs_t_unit_format_tail))
1375 if (pcm%solute .and. pcm%localf .and. td_calc_mode .and. calc ==
pcm_electrons)
then
1376 asc_vs_t_unit_e =
io_open(
pcm_dir//
'ASC_e_vs_t.dat', pcm%namespace, &
1377 action=
'write', position=
'append', form=
'formatted')
1378 write(asc_vs_t_unit_e,trim(adjustl(asc_vs_t_unit_format))) pcm%iter*pcm%dt, &
1379 (pcm%q_e(ia) , ia = 1,pcm%n_tesserae)
1391 type(
pcm_t),
intent(in) :: pcm
1392 type(
mesh_t),
intent(in) :: mesh
1393 real(real64),
intent(in) :: v_mesh(:)
1394 real(real64),
intent(out) :: v_cav(:)
1406 do ia = 1, pcm%n_tesserae
1420 real(real64),
intent(out) :: v_n_cav(:)
1421 type(
ions_t),
intent(in) :: ions
1423 integer,
intent(in) :: n_tess
1425 real(real64) :: dist
1433 do ia = 1, ions%natoms
1435 dist = norm2(ions%pos(1:pcm_dim_space, ia) - tess(ik)%point)
1437 v_n_cav(ik) = v_n_cav(ik) - ions%charge(ia)/dist
1449 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)
1450 type(
ions_t),
intent(in) :: ions
1451 type(
pcm_t),
intent(in) :: pcm
1452 real(real64),
intent(out) :: e_int_ee
1453 real(real64),
intent(out) :: e_int_en
1454 real(real64),
intent(out) :: e_int_ne
1455 real(real64),
intent(out) :: e_int_nn
1456 real(real64),
optional,
intent(out) :: e_int_e_ext
1457 real(real64),
optional,
intent(out) :: e_int_n_ext
1459 real(real64) :: dist, z_ia
1469 if (pcm%localf .and. ((.not.
present(e_int_e_ext)) .or. &
1470 (.not.
present(e_int_n_ext))))
then
1471 message(1) =
"pcm_elect_energy: There are lacking terms in subroutine call."
1473 else if (pcm%localf .and. (
present(e_int_e_ext) .and. &
1474 present(e_int_n_ext)))
then
1479 do ik = 1, pcm%n_tesserae
1481 e_int_ee = e_int_ee + pcm%v_e(ik)*pcm%q_e(ik)
1482 e_int_en = e_int_en + pcm%v_e(ik)*pcm%q_n(ik)
1483 if (pcm%localf)
then
1484 e_int_e_ext = e_int_e_ext + pcm%v_e(ik)*pcm%q_ext(ik)
1487 do ia = 1, ions%natoms
1489 dist = norm2(ions%pos(1:pcm_dim_space, ia) - pcm%tess(ik)%point)
1491 z_ia = -ions%charge(ia)
1493 e_int_ne = e_int_ne + z_ia*pcm%q_e(ik) / dist
1494 e_int_nn = e_int_nn + z_ia*pcm%q_n(ik) / dist
1495 if (pcm%localf) e_int_n_ext = e_int_n_ext + z_ia*pcm%q_ext(ik) / dist
1500 e_int_ee =
m_half*e_int_ee
1501 e_int_en =
m_half*e_int_en
1502 e_int_ne =
m_half*e_int_ne
1503 e_int_nn =
m_half*e_int_nn
1508 if (pcm%localf)
then
1509 write(pcm%info_unit, &
1510 '(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)') &
1525 write(pcm%info_unit, &
1526 '(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)') &
1548 subroutine pcm_charges(q_pcm, q_pcm_tot, v_cav, pcm_mat, n_tess, qtot_nominal, epsilon, renorm_charges, q_tot_tol, deltaQ)
1549 real(real64),
intent(out) :: q_pcm(:)
1550 real(real64),
intent(out) :: q_pcm_tot
1551 real(real64),
intent(in) :: v_cav(:)
1552 real(real64),
intent(in) :: pcm_mat(:,:)
1553 integer,
intent(in) :: n_tess
1554 real(real64),
optional,
intent(in) :: qtot_nominal
1555 real(real64),
optional,
intent(in) :: epsilon
1556 logical,
optional,
intent(in) :: renorm_charges
1557 real(real64),
optional,
intent(in) :: q_tot_tol
1558 real(real64),
optional,
intent(out) :: deltaq
1561 real(real64) :: q_pcm_tot_norm
1562 real(real64) :: coeff
1569 q_pcm_tot = sum(q_pcm(1:n_tess))
1571 if (
present(qtot_nominal) .and.
present(epsilon) .and. &
1572 present(renorm_charges) .and.
present(q_tot_tol) .and.
present(deltaq))
then
1574 deltaq = abs(q_pcm_tot) - ((epsilon -
m_one)/epsilon) * abs(qtot_nominal)
1575 if ((renorm_charges) .and. (abs(deltaq) > q_tot_tol))
then
1577 coeff = sign(
m_one, qtot_nominal)*sign(
m_one, deltaq)
1579 q_pcm(ia) = q_pcm(ia) + coeff*q_pcm(ia)/q_pcm_tot*abs(deltaq)
1580 q_pcm_tot_norm = q_pcm_tot_norm + q_pcm(ia)
1582 q_pcm_tot = q_pcm_tot_norm
1593 type(
pcm_t),
intent(in) :: pcm
1594 class(
mesh_t),
intent(in) :: mesh
1596 integer :: ia, nm(pcm%space%dim), ipt, i1, i2, i3
1597 real(real64) :: posrel(pcm%space%dim)
1598 integer(int64) :: pt
1603 do ia = 1, pcm%n_tesserae
1605 posrel(:) = pcm%tess(ia)%point(1:pcm%space%dim)/mesh%spacing(1:pcm%space%dim)
1607 nm(:) =
floor(posrel(:))
1611 do i1 = -pcm%tess_nn + 1 , pcm%tess_nn
1612 do i2 = -pcm%tess_nn + 1 , pcm%tess_nn
1613 do i3 = -pcm%tess_nn + 1 , pcm%tess_nn
1617 if (pt <= 0 .or. pt > mesh%np_part_global)
then
1634 type(
pcm_t),
intent(in) :: pcm
1635 class(
mesh_t),
intent(in) :: mesh
1640 message(1) =
'The simulation box is too small to contain all the requested'
1641 message(2) =
'nearest neighbors for each tessera.'
1642 message(3) =
'Consider using a larger box or reduce PCMChargeSmearNN.'
1653 type(
pcm_t),
intent(inout) :: pcm
1654 real(real64),
intent(in) :: q_pcm(:)
1655 real(real64),
intent(in) :: q_pcm_tot
1656 type(
mesh_t),
intent(in) :: mesh
1657 real(real64),
intent(out) :: rho(:)
1660 real(real64) :: norm, qtot, rr, xx(pcm%space%dim), pp(pcm%space%dim)
1663 integer :: nm(pcm%space%dim)
1664 real(real64) :: posrel(pcm%space%dim)
1666 integer :: i1, i2, i3
1667 integer,
allocatable :: pt(:)
1668 real(real64),
allocatable :: lrho(:)
1669 logical :: inner_point, boundary_point
1677 npt = (2*pcm%tess_nn)**pcm%space%dim
1678 safe_allocate(pt(1:npt))
1679 safe_allocate(lrho(1:npt))
1684 do ia = 1, pcm%n_tesserae
1686 pp(:) = pcm%tess(ia)%point(1:pcm%space%dim)
1687 posrel(:) = pp(:)/mesh%spacing(1:pcm%space%dim)
1689 nm(:) =
floor(posrel(:))
1693 do i1 = -pcm%tess_nn + 1 , pcm%tess_nn
1694 do i2 = -pcm%tess_nn + 1 , pcm%tess_nn
1695 do i3 = -pcm%tess_nn + 1 , pcm%tess_nn
1711 if (pt(ipt) > 0 .and. pt(ipt) <= mesh%np_part)
then
1713 if (mesh%parallel_in_domains)
then
1714 boundary_point = pt(ipt) > mesh%np + mesh%pv%np_ghost
1715 inner_point = pt(ipt) > 0 .and. pt(ipt) <= mesh%np
1717 if (boundary_point .or. inner_point)
then
1718 xx(:) = mesh%x(:, pt(ipt))
1724 xx(:) = mesh%x(:, pt(ipt))
1727 rr = sum((xx(1:pcm%space%dim) - pp(1:pcm%space%dim))**2)
1728 norm = norm +
exp(-rr/(pcm%tess(ia)%area*pcm%gaussian_width))
1729 lrho(ipt) = lrho(ipt) +
exp(-rr/(pcm%tess(ia)%area*pcm%gaussian_width))
1735 call mesh%allreduce(lrho, npt)
1738 norm = sum(lrho(1:npt)) * mesh%volume_element
1740 norm = q_pcm(ia)/norm
1744 lrho(:) = lrho(:) * norm
1749 if (pt(ipt) > 0 .and. pt(ipt) <= mesh%np_part_global)
then
1751 if (mesh%parallel_in_domains)
then
1752 boundary_point = pt(ipt) > mesh%np + mesh%pv%np_ghost
1753 inner_point = pt(ipt) > 0 .and. pt(ipt) <= mesh%np
1754 if (boundary_point .or. inner_point) rho(pt(ipt)) = rho(pt(ipt)) + lrho(ipt)
1756 rho(pt(ipt)) = rho(pt(ipt)) + lrho(ipt)
1764 if (
debug%info)
then
1778 safe_deallocate_a(pt)
1779 safe_deallocate_a(lrho)
1789 subroutine pcm_pot_rs(pcm, v_pcm, q_pcm, rho, mesh, psolver)
1790 type(
pcm_t),
intent(inout) :: pcm
1791 real(real64),
contiguous,
intent(inout) :: v_pcm(:)
1792 real(real64),
contiguous,
intent(in) :: q_pcm(:)
1793 real(real64),
contiguous,
intent(inout) :: rho(:)
1794 type(
mesh_t),
intent(in) :: mesh
1804 select case (pcm%calc_method)
1806 call pcm_pot_rs_direct(v_pcm, q_pcm, pcm%tess, pcm%n_tesserae, mesh, pcm%gaussian_width)
1817 if (
debug%info)
then
1832 real(real64),
contiguous,
intent(inout) :: v_pcm(:)
1834 real(real64),
contiguous,
intent(inout) :: rho(:)
1847 real(real64),
intent(out) :: v_pcm(:)
1848 real(real64),
intent(in) :: q_pcm(:)
1849 real(real64),
intent(in) :: width_factor
1850 integer,
intent(in) :: n_tess
1851 type(
mesh_t),
intent(in) :: mesh
1854 real(real64),
parameter :: p_1 = 0.119763_real64
1855 real(real64),
parameter :: p_2 = 0.205117_real64
1856 real(real64),
parameter :: q_1 = 0.137546_real64
1857 real(real64),
parameter :: q_2 = 0.434344_real64
1859 real(real64) :: term
1872 call mesh_r(mesh, ip, term, origin=tess(ia)%point)
1873 arg = term/
sqrt(tess(ia)%area*width_factor)
1874 term = (
m_one + p_1*arg + p_2*arg**2) / (
m_one + q_1*arg + q_2*arg**2 + p_2*arg**3)
1875 v_pcm(ip) = v_pcm(ip) + q_pcm(ia) * term/
sqrt(tess(ia)%area*width_factor)
1886 call mesh_r(mesh, ip, term, origin=tess(ia)%point)
1887 v_pcm(ip) = v_pcm(ip) + q_pcm(ia)/term
1898 subroutine pcm_matrix(eps, tess, n_tess, pcm_mat, localf)
1899 real(real64),
intent(in) :: eps
1901 integer,
intent(in) :: n_tess
1902 real(real64),
intent(out) :: pcm_mat(:,:)
1903 logical,
optional,
intent(in) :: localf
1906 integer,
allocatable :: iwork(:)
1907 real(real64),
allocatable :: mat_tmp(:,:)
1909 real(real64) :: sgn_lf
1914 safe_allocate(s_mat_act(1:n_tess, 1:n_tess))
1918 safe_allocate(sigma(1:n_tess, 1:n_tess))
1919 sigma = s_mat_act/eps
1922 safe_allocate(d_mat_act(1:n_tess, 1:n_tess))
1926 safe_allocate(delta(1:n_tess, 1:n_tess))
1931 if (
present(localf))
then
1932 if (localf) sgn_lf = -
m_one
1936 pcm_mat = - sgn_lf * d_mat_act
1939 pcm_mat(i,i) = pcm_mat(i,i) +
m_two*
m_pi
1942 safe_deallocate_a(d_mat_act)
1944 safe_allocate(iwork(1:n_tess))
1949 call dgesv(n_tess, n_tess, s_mat_act, n_tess, iwork, pcm_mat, n_tess,
info)
1951 safe_deallocate_a(iwork)
1953 safe_deallocate_a(s_mat_act)
1957 pcm_mat = -matmul(sigma, pcm_mat)
1960 pcm_mat(i,i) = pcm_mat(i,i) +
m_two*
m_pi
1963 pcm_mat = pcm_mat - sgn_lf * delta
1965 safe_allocate(mat_tmp(1:n_tess,1:n_tess))
1968 safe_allocate(d_mat_act(1:n_tess,1:n_tess))
1971 mat_tmp = transpose(d_mat_act)
1973 mat_tmp = matmul(sigma, mat_tmp)
1977 safe_deallocate_a(d_mat_act)
1979 safe_allocate(s_mat_act(1:n_tess, 1:n_tess))
1982 mat_tmp = mat_tmp +
m_two*
m_pi*s_mat_act - matmul(delta, s_mat_act)
1984 safe_deallocate_a(s_mat_act)
1985 safe_deallocate_a(sigma)
1986 safe_deallocate_a(delta)
1988 safe_allocate(iwork(1:n_tess))
1992 call dgesv(n_tess, n_tess, mat_tmp, n_tess, iwork, pcm_mat, n_tess,
info)
1994 safe_deallocate_a(iwork)
1995 safe_deallocate_a(mat_tmp)
1997 pcm_mat = - sgn_lf * pcm_mat
2000 if (gamess_benchmark)
then
2012 integer,
intent(in) :: n_tess
2022 if (ii /= jj) s_mat_act(jj,ii) = s_mat_act(ii,jj)
2031 integer,
intent(in) :: n_tess
2050 real(real64) function s_mat_elem_I(tessi, tessj)
2054 real(real64),
parameter :: M_SD_DIAG = 1.0694_real64
2055 real(real64),
parameter :: M_DIST_MIN = 0.1_real64
2057 real(real64) :: diff(1:PCM_DIM_SPACE)
2058 real(real64) :: dist
2059 real(real64) :: s_diag
2060 real(real64) :: s_off_diag
2065 diff = tessi%point - tessj%point
2071 s_mat_elem_i = s_diag
2073 if (dist > m_dist_min) s_off_diag =
m_one/dist
2074 s_mat_elem_i = s_off_diag
2082 real(real64) function d_mat_elem_I(tessi, tessj)
2083 type(pcm_tessera_t),
intent(in) :: tessi
2084 type(pcm_tessera_t),
intent(in) :: tessj
2086 real(real64),
parameter :: M_SD_DIAG = 1.0694_real64
2087 real(real64),
parameter :: M_DIST_MIN = 0.04_real64
2089 real(real64) :: diff(1:PCM_DIM_SPACE)
2090 real(real64) :: dist
2091 real(real64) :: d_diag
2092 real(real64) :: d_off_diag
2098 diff = tessi%point - tessj%point
2102 if (abs(dist) <= m_epsilon)
then
2104 d_diag = m_sd_diag*
sqrt(m_four*m_pi*tessi%area)
2105 d_diag = -d_diag/(m_two*tessi%r_sphere)
2110 if (dist > m_dist_min)
then
2111 d_off_diag = dot_product( diff, tessj%normal(:))
2112 d_off_diag = d_off_diag*tessj%area/dist**3
2126 subroutine cav_gen(tess_sphere, tess_min_distance, nesf, sfe, nts, cts, unit_pcminfo)
2127 integer,
intent(in) :: tess_sphere
2128 real(real64) ,
intent(in) :: tess_min_distance
2130 integer,
intent(in) :: nesf
2131 integer,
intent(out) :: nts
2132 type(pcm_tessera_t),
intent(out) :: cts(:)
2133 integer,
intent(in) :: unit_pcminfo
2135 integer,
parameter :: DIM_ANGLES = 24
2136 integer,
parameter :: DIM_TEN = 10
2137 integer,
parameter :: DIM_VERTICES = 122
2138 integer,
parameter :: MAX_VERTICES = 6
2139 integer,
parameter :: MXTS = 10000
2141 real(real64),
save :: thev(1:DIM_ANGLES)
2142 real(real64),
save :: fiv(1:DIM_ANGLES)
2143 real(real64),
save :: fir
2144 real(real64) :: cv(1:DIM_VERTICES, 1:PCM_DIM_SPACE)
2154 real(real64) :: nctst(pcm_dim_space, tess_sphere*
n_tess_sphere)
2156 real(real64) :: pts(1:pcm_dim_space, 1:dim_ten)
2157 real(real64) :: pp(1:pcm_dim_space)
2158 real(real64) :: pp1(1:pcm_dim_space)
2159 real(real64) :: ccc(1:pcm_dim_space, 1:dim_ten)
2163 integer :: isfet(1:dim_ten*dim_angles)
2181 real(real64) :: area
2182 real(real64) :: test2
2184 real(real64) :: dnorm
2194 real(real64) :: stot
2195 real(real64) :: prod
2198 logical :: band_iter
2204 data thev/ 0.6523581398_real64 , 1.107148718_real64 , 1.382085796_real64 , &
2205 1.759506858_real64 , 2.034443936_real64 , 2.489234514_real64 , &
2206 0.3261790699_real64 , 0.5535743589_real64, &
2207 0.8559571251_real64 , 0.8559571251_real64 , 1.017221968_real64 , &
2208 1.229116717_real64 , 1.229116717_real64 , 1.433327788_real64 , &
2209 1.570796327_real64 , 1.570796327_real64 , 1.708264866_real64 , &
2210 1.912475937_real64 , 1.912475937_real64 , 2.124370686_real64 , &
2211 2.285635528_real64 , 2.285635528_real64 , 2.588018295_real64 , &
2212 2.815413584_real64 /
2213 data fiv/ 0.6283185307_real64 , m_zero , &
2214 0.6283185307_real64 , m_zero , 0.6283185307_real64, &
2215 m_zero , 0.6283185307_real64 , m_zero, &
2216 0.2520539002_real64 , 1.004583161_real64 , 0.6283185307_real64, &
2217 0.3293628477_real64 , 0.9272742138_real64 , m_zero, &
2218 0.3141592654_real64 , 0.9424777961_real64 , 0.6283185307_real64, &
2219 0.2989556830_real64 , 0.9576813784_real64 , m_zero, &
2220 0.3762646305_real64 , 0.8803724309_real64 , 0.6283188307_real64, &
2222 data fir / 1.256637061_real64 /
2226 data (idum(ii),ii = 1, 280) / &
2227 1, 6, 2, 32, 36, 37, 1, 2, 3, 33, 32, 38, 1, 3, 4, 34, &
2228 33, 39, 1, 4, 5, 35, 34, 40, 1, 5, 6, 36, 35, 41, 7, 2, 6, 51, &
2229 42, 37, 8, 3, 2, 47, 43, 38, 9, 4, 3, 48, 44, 39, 10, 5, 4, &
2230 49, 45, 40, 11, 6, 5, 50, 46, 41, 8, 2, 12, 62, 47, 52, 9, &
2231 3, 13, 63, 48, 53, 10, 4, 14, 64, 49, 54, 11, 5, 15, 65, 50, &
2232 55, 7, 6, 16, 66, 51, 56, 7, 12, 2, 42, 57, 52, 8, 13, 3, &
2233 43, 58, 53, 9, 14, 4, 44, 59, 54, 10, 15, 5, 45, 60, 55, 11, &
2234 16, 6, 46, 61, 56, 8, 12, 18, 68, 62, 77, 9, 13, 19, 69, 63, &
2235 78, 10, 14, 20, 70, 64, 79, 11, 15, 21, 71, 65, 80, 7, 16, &
2236 17, 67, 66, 81, 7, 17, 12, 57, 67, 72, 8, 18, 13, 58, 68, 73, &
2237 9, 19, 14, 59, 69, 74, 10, 20, 15, 60, 70, 75, 11, 21, 16, &
2238 61, 71, 76, 22, 12, 17, 87, 82, 72, 23, 13, 18, 88, 83, 73, &
2239 24, 14, 19, 89, 84, 74, 25, 15, 20, 90, 85, 75, 26, 16, 21, &
2240 91, 86, 76, 22, 18, 12, 82, 92, 77, 23, 19, 13, 83, 93, 78, &
2241 24, 20, 14, 84, 94, 79, 25, 21, 15, 85, 95, 80, 26, 17, 16, &
2242 86, 96, 81, 22, 17, 27, 102, 87, 97, 23, 18, 28, 103, 88, 98, &
2243 24, 19, 29, 104, 89, 99, 25, 20, 30, 105, 90, 100, 26, 21, &
2244 31, 106, 91, 101, 22, 28, 18, 92, 107, 98, 23, 29, 19, 93 /
2245 data (idum(ii),ii = 281,360) / &
2246 108, 99, 24, 30, 20, 94, 109, 100, 25, 31, 21, 95, 110, 101, &
2247 26, 27, 17, 96, 111, 97, 22, 27, 28, 107, 102, 112, 23, 28, &
2248 29, 108, 103, 113, 24, 29, 30, 109, 104, 114, 25, 30, 31, &
2249 110, 105, 115, 26, 31, 27, 111, 106, 116, 122, 28, 27, 117, &
2250 118, 112, 122, 29, 28, 118, 119, 113, 122, 30, 29, 119, 120, &
2251 114, 122, 31, 30, 120, 121, 115, 122, 27, 31, 121, 117, 116 /
2253 if (mpi_world%is_root())
then
2254 if (tess_sphere == 1)
then
2255 write(unit_pcminfo,
'(A1)')
'#'
2256 write(unit_pcminfo,
'(A34)')
'# Number of tesserae / sphere = 60'
2257 write(unit_pcminfo,
'(A1)')
'#'
2259 write(unit_pcminfo,
'(A1)')
'#'
2260 write(unit_pcminfo,
'(A35)')
'# Number of tesserae / sphere = 240'
2261 write(unit_pcminfo,
'(A1)')
'#'
2270 sfe(:)%x = sfe(:)%x*p_a_b
2271 sfe(:)%y = sfe(:)%y*p_a_b
2272 sfe(:)%z = sfe(:)%z*p_a_b
2273 sfe(:)%r = sfe(:)%r*p_a_b
2277 jvt1 = reshape(idum,(/6,60/))
2300 do ia = 1, dim_angles
2307 if (ja == 1) fi = fiv(ia)
2309 cv(ii,1) = sth*
cos(fi)
2310 cv(ii,2) = sth*
sin(fi)
2329 do i_tes = 1, tess_sphere
2330 if (tess_sphere == 1)
then
2335 if (i_tes == 1)
then
2339 elseif (i_tes == 2)
then
2343 elseif (i_tes == 3)
then
2347 elseif (i_tes == 4)
then
2354 pts(1,1) = cv(n1,1)*ren + xen
2355 pts(2,1) = cv(n1,3)*ren + yen
2356 pts(3,1) = cv(n1,2)*ren + zen
2358 pts(1,2) = cv(n2,1)*ren + xen
2359 pts(2,2) = cv(n2,3)*ren + yen
2360 pts(3,2) = cv(n2,2)*ren + zen
2362 pts(1,3) = cv(n3,1)*ren + xen
2363 pts(2,3) = cv(n3,3)*ren + yen
2364 pts(3,3) = cv(n3,2)*ren + zen
2370 call subtessera(sfe, nsfe, nesf, nv, pts ,ccc, pp, pp1, area)
2372 if (abs(area) <= m_epsilon) cycle
2374 xctst(tess_sphere*(its-1) + i_tes) = pp(1)
2375 yctst(tess_sphere*(its-1) + i_tes) = pp(2)
2376 zctst(tess_sphere*(its-1) + i_tes) = pp(3)
2377 nctst(:,tess_sphere*(its-1) + i_tes) = pp1(:)
2378 ast(tess_sphere*(its-1) + i_tes) = area
2379 isfet(tess_sphere*(its-1) + i_tes) = nsfe
2386 if (abs(ast(its)) <= m_epsilon) cycle
2390 write(message(1),
'(a,I5,a,I5)')
"total number of tesserae", nn,
">",mxts
2391 call messages_warning(1)
2394 cts(nn)%point(1) = xctst(its)
2395 cts(nn)%point(2) = yctst(its)
2396 cts(nn)%point(3) = zctst(its)
2397 cts(nn)%normal(:) = nctst(:,its)
2398 cts(nn)%area = ast(its)
2399 cts(nn)%r_sphere = sfe(isfet(its))%r
2407 test2 = tess_min_distance*tess_min_distance
2410 do while (.not.(band_iter))
2413 loop_ia:
do ia = 1, nts-1
2414 if (abs(cts(ia)%area) <= m_epsilon) cycle
2415 xi = cts(ia)%point(1)
2416 yi = cts(ia)%point(2)
2417 zi = cts(ia)%point(3)
2419 loop_ja:
do ja = ia+1, nts
2420 if (abs(cts(ja)%area) <= m_epsilon) cycle
2421 xj = cts(ja)%point(1)
2422 yj = cts(ja)%point(2)
2423 zj = cts(ja)%point(3)
2425 rij = (xi - xj)**2 + (yi - yj)**2 + (zi - zj)**2
2427 if (rij > test2) cycle
2429 if (mpi_world%is_root())
then
2430 write(unit_pcminfo,
'(A40,I4,A5,I4,A4,F8.4,A13,F8.4,A3)') &
2431 '# Warning: The distance between tesserae', &
2432 ia,
' and ', ja,
' is ',
sqrt(rij),
' A, less than', tess_min_distance,
' A.'
2436 xi = (xi*cts(ia)%area + xj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2437 yi = (yi*cts(ia)%area + yj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2438 zi = (zi*cts(ia)%area + zj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2440 cts(ia)%point(1) = xi
2441 cts(ia)%point(2) = yi
2442 cts(ia)%point(3) = zi
2445 cts(ia)%normal = (cts(ia)%normal*cts(ia)%area + cts(ja)%normal*cts(ja)%area)
2446 dnorm = norm2(cts(ia)%normal)
2447 cts(ia)%normal = cts(ia)%normal/dnorm
2450 cts(ia)%r_sphere = (cts(ia)%r_sphere*cts(ia)%area + cts(ja)%r_sphere*cts(ja)%area) / &
2451 (cts(ia)%area + cts(ja)%area)
2454 cts(ia)%area = cts(ia)%area + cts(ja)%area
2471 prod = dot_product(cts(its)%point, cts(its)%normal)
2472 vol = vol + cts(its)%area * prod / m_three
2473 stot = stot + cts(its)%area
2476 if (mpi_world%is_root())
then
2477 write(unit_pcminfo,
'(A2)')
'# '
2478 write(unit_pcminfo,
'(A29,I4)')
'# Total number of tesserae = ' , nts
2479 write(unit_pcminfo,
'(A30,F12.6)')
'# Cavity surface area (A^2) = ', stot
2480 write(unit_pcminfo,
'(A24,F12.6)')
'# Cavity volume (A^3) = ' , vol
2481 write(unit_pcminfo,
'(A2)')
'# '
2485 cts(:)%area = cts(:)%area*p_ang*p_ang
2486 cts(:)%point(1) = cts(:)%point(1)*p_ang
2487 cts(:)%point(2) = cts(:)%point(2)*p_ang
2488 cts(:)%point(3) = cts(:)%point(3)*p_ang
2489 cts(:)%r_sphere = cts(:)%r_sphere*p_ang
2491 sfe(:)%x=sfe(:)%x*p_ang
2492 sfe(:)%y=sfe(:)%y*p_ang
2493 sfe(:)%z=sfe(:)%z*p_ang
2494 sfe(:)%r=sfe(:)%r*p_ang
2503 subroutine subtessera(sfe, ns, nesf, nv, pts, ccc, pp, pp1, area)
2505 integer,
intent(in) :: ns
2506 integer,
intent(in) :: nesf
2507 integer,
intent(inout) :: nv
2508 real(real64),
intent(inout) :: pts(:,:)
2509 real(real64),
intent(out) :: ccc(:,:)
2510 real(real64),
intent(out) :: pp(:)
2511 real(real64),
intent(out) :: pp1(:)
2512 real(real64),
intent(out) :: area
2514 real(real64),
parameter :: TOL = -1.0e-10_real64
2515 integer,
parameter :: DIM_TEN = 10
2517 integer :: intsph(1:DIM_TEN)
2528 real(real64) :: p1(1:PCM_DIM_SPACE)
2529 real(real64) :: p2(1:PCM_DIM_SPACE)
2530 real(real64) :: p3(1:PCM_DIM_SPACE)
2531 real(real64) :: p4(1:PCM_DIM_SPACE)
2532 real(real64) :: point(1:PCM_DIM_SPACE)
2533 real(real64) :: pscr(1:PCM_DIM_SPACE,1:DIM_TEN)
2534 real(real64) :: cccp(1:PCM_DIM_SPACE,1:DIM_TEN)
2535 real(real64) :: pointl(1:PCM_DIM_SPACE,1:DIM_TEN)
2536 real(real64) :: diff(1:PCM_DIM_SPACE)
2538 integer :: ind(1:DIM_TEN)
2539 integer :: ltyp(1:DIM_TEN)
2540 integer :: intscr(1:DIM_TEN)
2542 real(real64) :: delr
2543 real(real64) :: delr2
2546 real(real64) :: dnorm
2547 real(real64) :: dist
2564 ccc(1,jj) = sfe(ns)%x
2565 ccc(2,jj) = sfe(ns)%y
2566 ccc(3,jj) = sfe(ns)%z
2571 if (nsfe1 == ns) cycle
2573 intscr(jj) = intsph(jj)
2574 pscr(:,jj) = pts(:,jj)
2575 cccp(:,jj) = ccc(:,jj)
2583 delr2 = (pts(1,ii) - sfe(nsfe1)%x)**2 + (pts(2,ii) - sfe(nsfe1)%y)**2 + (pts(3,ii) - sfe(nsfe1)%z)**2
2585 if (delr < sfe(nsfe1)%r)
then
2591 if (icop == nv)
then
2599 if (ll == nv) iv2 = 1
2600 if ((ind(iv1) == 1) .and. (ind(iv2) == 1))
then
2602 else if ((ind(iv1) == 0) .and. (ind(iv2) == 1))
then
2604 else if ((ind(iv1) == 1) .and. (ind(iv2) == 0))
then
2606 else if ((ind(iv1) == 0) .and. (ind(iv2) == 0))
then
2608 diff = ccc(:,ll) - pts(:,ll)
2609 rc2 = dot_product(diff, diff)
2613 point = pts(:,iv1) + ii * (pts(:,iv2) - pts(:,iv1)) / 11
2614 point = point - ccc(:,ll)
2615 dnorm = norm2(point)
2616 point = point * rc / dnorm + ccc(:,ll)
2618 dist =
sqrt((point(1) - sfe(nsfe1)%x)**2 + (point(2) - sfe(nsfe1)%y)**2 + (point(3) - sfe(nsfe1)%z)**2)
2620 if ((dist - sfe(nsfe1)%r) < tol)
then
2622 pointl(:, ll) = point
2632 if ((ltyp(ll) == 1) .or. (ltyp(ll) == 2)) icut = icut + 1
2633 if (ltyp(ll) == 3) icut = icut + 2
2644 if (ltyp(ll) == 0) cycle
2647 if (ll == nv) iv2 = 1
2649 if (ltyp(ll) == 1)
then
2650 pts(:,na) = pscr(:,iv1)
2651 ccc(:,na) = cccp(:,iv1)
2652 intsph(na) = intscr(iv1)
2658 call inter(sfe, p1, p2, p3, p4, nsfe1, 0)
2661 de2 = (sfe(nsfe1)%x - sfe(ns)%x)**2 + ( sfe(nsfe1)%y - sfe(ns)%y)**2 + &
2662 (sfe(nsfe1)%z - sfe(ns)%z)**2
2664 ccc(1,na) = sfe(ns)%x + ( sfe(nsfe1)%x - sfe(ns)%x)* &
2665 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2667 ccc(2,na) = sfe(ns)%y + ( sfe(nsfe1)%y - sfe(ns)%y)* &
2668 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2670 ccc(3,na) = sfe(ns)%z + ( sfe(nsfe1)%z - sfe(ns)%z)* &
2671 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2677 if (ltyp(ll) == 2)
then
2682 call inter(sfe, p1, p2, p3, p4, nsfe1, 1)
2684 ccc(:,na) = cccp(:,iv1)
2685 intsph(na) = intscr(iv1)
2689 if (ltyp(ll) == 3)
then
2690 pts(:,na) = pscr(:,iv1)
2691 ccc(:,na) = cccp(:,iv1)
2692 intsph(na) = intscr(iv1)
2698 call inter(sfe, p1, p2, p3, p4, nsfe1, 0)
2701 de2 = (sfe(nsfe1)%x - sfe(ns)%x)**2 + (sfe(nsfe1)%y - sfe(ns)%y)**2 + (sfe(nsfe1)%z - sfe(ns)%z)**2
2703 ccc(1,na) = sfe(ns)%x + (sfe(nsfe1)%x - sfe(ns)%x) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2705 ccc(2,na) = sfe(ns)%y + (sfe(nsfe1)%y - sfe(ns)%y) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2707 ccc(3,na) = sfe(ns)%z + (sfe(nsfe1)%z - sfe(ns)%z) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2715 call inter(sfe, p1, p2, p3, p4, nsfe1, 1)
2717 ccc(:,na) = cccp(:,iv1)
2718 intsph(na) = intscr(iv1)
2722 if (ltyp(ll) == 4)
then
2723 pts(:,na) = pscr(:,iv1)
2724 ccc(:,na) = cccp(:,iv1)
2725 intsph(na) = intscr(iv1)
2732 message(1) =
"Too many vertices on the tessera"
2733 call messages_fatal(1)
2737 call gaubon(sfe, nv, ns, pts, ccc, pp, pp1, area, intsph)
2747 subroutine inter(sfe, p1, p2, p3, p4, ns, ia)
2749 real(real64),
intent(in) :: p1(1:PCM_DIM_SPACE)
2750 real(real64),
intent(in) :: p2(1:PCM_DIM_SPACE)
2751 real(real64),
intent(in) :: p3(1:PCM_DIM_SPACE)
2752 real(real64),
intent(out) :: p4(1:PCM_DIM_SPACE)
2753 integer,
intent(in) :: ns
2754 integer,
intent(in) :: ia
2756 real(real64),
parameter :: TOL = 1.0e-08_real64
2760 real(real64) :: alpha
2761 real(real64) :: delta
2762 real(real64) :: dnorm
2763 real(real64) :: diff
2764 real(real64) :: diff_vec(1:PCM_DIM_SPACE)
2765 logical :: band_iter
2777 do while(.not.(band_iter))
2778 if (m_iter > 1000)
then
2779 message(1) =
"Too many iterations inside subrotuine inter"
2780 call messages_fatal(1)
2785 alpha = alpha + delta
2787 p4 = p1 + alpha*(p2 - p1) - p3
2789 p4 = p4*r/dnorm + p3
2790 diff = (p4(1) - sfe(ns)%x)**2 + (p4(2) - sfe(ns)%y)**2 + (p4(3) - sfe(ns)%z)**2
2791 diff =
sqrt(diff) - sfe(ns)%r
2793 if (abs(diff) < tol)
then
2799 if (diff > m_zero) delta = m_one/(m_two**(m_iter + 1))
2800 if (diff < m_zero) delta = -m_one/(m_two**(m_iter + 1))
2806 if (diff > m_zero) delta = -m_one/(m_two**(m_iter + 1))
2807 if (diff < m_zero) delta = m_one/(m_two**(m_iter + 1))
2814 end subroutine inter
2824 subroutine gaubon(sfe, nv, ns, pts, ccc, pp, pp1, area, intsph)
2826 real(real64),
intent(in) :: pts(:,:)
2827 real(real64),
intent(in) :: ccc(:,:)
2828 real(real64),
intent(inout) :: pp(:)
2829 real(real64),
intent(inout) :: pp1(:)
2830 integer,
intent(in) :: intsph(:)
2831 real(real64),
intent(out) :: area
2832 integer,
intent(in) :: nv
2833 integer,
intent(in) :: ns
2835 real(real64) :: p1(1:PCM_DIM_SPACE), p2(1:PCM_DIM_SPACE), p3(1:PCM_DIM_SPACE)
2836 real(real64) :: u1(1:PCM_DIM_SPACE), u2(1:PCM_DIM_SPACE)
2837 real(real64) :: point_1(1:PCM_DIM_SPACE), point_2(1:PCM_DIM_SPACE)
2838 real(real64) :: tpi, sum1, dnorm, dnorm1, dnorm2
2839 real(real64) :: cosphin, phin, costn, sum2, betan
2840 integer :: nsfe1, ia, nn, n0, n1, n2
2855 point_1 = pts(:,nn) - ccc(:,nn)
2857 point_2 = pts(:,nn+1) - ccc(:,nn)
2859 point_2 = pts(:,1) - ccc(:,nn)
2862 dnorm1 = norm2(point_1)
2863 dnorm2 = norm2(point_2)
2864 cosphin = dot_product(point_1, point_2) / (dnorm1*dnorm2)
2866 if (cosphin > m_one) cosphin = m_one
2867 if (cosphin < -m_one) cosphin = -m_one
2869 phin =
acos(cosphin)
2872 point_1(1) = sfe(nsfe1)%x - sfe(ns)%x
2873 point_1(2) = sfe(nsfe1)%y - sfe(ns)%y
2874 point_1(3) = sfe(nsfe1)%z - sfe(ns)%z
2876 dnorm1 = norm2(point_1)
2878 if (abs(dnorm1) <= m_epsilon) dnorm1 = m_one
2880 point_2(1) = pts(1,nn) - sfe(ns)%x
2881 point_2(2) = pts(2,nn) - sfe(ns)%y
2882 point_2(3) = pts(3,nn) - sfe(ns)%z
2884 dnorm2 = norm2(point_2)
2886 costn = dot_product(point_1, point_2) / (dnorm1 * dnorm2)
2887 sum1 = sum1 + phin * costn
2898 if (nn > 1) n0 = nn - 1
2899 if (nn == 1) n0 = nv
2900 if (nn < nv) n2 = nn + 1
2901 if (nn == nv) n2 = 1
2903 p1 = pts(:,n1) - ccc(:,n0)
2904 p2 = pts(:,n0) - ccc(:,n0)
2905 call vecp(p1, p2, p3, dnorm)
2908 call vecp(p1, p2, p3, dnorm)
2911 p1 = pts(:,n1) - ccc(:,n1)
2912 p2 = pts(:,n2) - ccc(:,n1)
2913 call vecp(p1, p2, p3, dnorm)
2916 call vecp(p1, p2, p3, dnorm)
2920 sum2 = sum2 + (m_pi - betan)
2924 area = sfe(ns)%r*sfe(ns)%r*(tpi + sum1 - sum2)
2930 pp(1) = pp(1) + (pts(1,ia) - sfe(ns)%x)
2931 pp(2) = pp(2) + (pts(2,ia) - sfe(ns)%y)
2932 pp(3) = pp(3) + (pts(3,ia) - sfe(ns)%z)
2937 pp(1) = sfe(ns)%x + pp(1) * sfe(ns)%r / dnorm
2938 pp(2) = sfe(ns)%y + pp(2) * sfe(ns)%r / dnorm
2939 pp(3) = sfe(ns)%z + pp(3) * sfe(ns)%r / dnorm
2942 pp1(1) = (pp(1) - sfe(ns)%x) / sfe(ns)%r
2943 pp1(2) = (pp(2) - sfe(ns)%y) / sfe(ns)%r
2944 pp1(3) = (pp(3) - sfe(ns)%z) / sfe(ns)%r
2947 if (area < m_zero) area = m_zero
2955 subroutine vecp(p1, p2, p3, dnorm)
2956 real(real64),
intent(in) :: P1(:)
2957 real(real64),
intent(in) :: P2(:)
2958 real(real64),
intent(out) :: P3(:)
2959 real(real64),
intent(out) :: dnorm
2962 p3(1) = p1(2)*p2(3) - p1(3)*p2(2)
2963 p3(2) = p1(3)*p2(1) - p1(1)*p2(3)
2964 p3(3) = p1(1)*p2(2) - p1(2)*p2(1)
2971 type(
pcm_t),
intent(inout) :: pcm
2973 integer :: asc_unit_test, asc_unit_test_sol, asc_unit_test_e, asc_unit_test_n, asc_unit_test_ext
2978 if (pcm%solute .and. pcm%localf)
then
2979 asc_unit_test = io_open(pcm_dir//
'ASC.dat', pcm%namespace, action=
'write')
2980 asc_unit_test_sol = io_open(pcm_dir//
'ASC_sol.dat', pcm%namespace, action=
'write')
2981 asc_unit_test_e = io_open(pcm_dir//
'ASC_e.dat', pcm%namespace, action=
'write')
2982 asc_unit_test_n = io_open(pcm_dir//
'ASC_n.dat', pcm%namespace, action=
'write')
2983 asc_unit_test_ext = io_open(pcm_dir//
'ASC_ext.dat', pcm%namespace, action=
'write')
2984 do ia = 1, pcm%n_tesserae
2985 write(asc_unit_test,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia) + pcm%q_ext(ia), ia
2986 write(asc_unit_test_sol,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia), ia
2987 write(asc_unit_test_e,*) pcm%tess(ia)%point, pcm%q_e(ia), ia
2988 write(asc_unit_test_n,*) pcm%tess(ia)%point, pcm%q_n(ia), ia
2989 write(asc_unit_test_ext,*) pcm%tess(ia)%point, pcm%q_ext(ia), ia
2991 call io_close(asc_unit_test)
2992 call io_close(asc_unit_test_sol)
2993 call io_close(asc_unit_test_e)
2994 call io_close(asc_unit_test_n)
2995 call io_close(asc_unit_test_ext)
2997 else if (pcm%solute .and. .not. pcm%localf)
then
2998 asc_unit_test_sol = io_open(pcm_dir//
'ASC_sol.dat', pcm%namespace, action=
'write')
2999 asc_unit_test_e = io_open(pcm_dir//
'ASC_e.dat', pcm%namespace, action=
'write')
3000 asc_unit_test_n = io_open(pcm_dir//
'ASC_n.dat', pcm%namespace, action=
'write')
3001 do ia = 1, pcm%n_tesserae
3002 write(asc_unit_test_sol,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia), ia
3003 write(asc_unit_test_e,*) pcm%tess(ia)%point, pcm%q_e(ia), ia
3004 write(asc_unit_test_n,*) pcm%tess(ia)%point, pcm%q_n(ia), ia
3006 call io_close(asc_unit_test_sol)
3007 call io_close(asc_unit_test_e)
3008 call io_close(asc_unit_test_n)
3010 else if (.not. pcm%solute .and. pcm%localf)
then
3011 asc_unit_test_ext = io_open(pcm_dir//
'ASC_ext.dat', pcm%namespace, action=
'write')
3012 do ia = 1, pcm%n_tesserae
3013 write(asc_unit_test_ext,*) pcm%tess(ia)%point, pcm%q_ext(ia), ia
3015 call io_close(asc_unit_test_ext)
3018 safe_deallocate_a(pcm%spheres)
3019 safe_deallocate_a(pcm%tess)
3020 safe_deallocate_a(pcm%matrix)
3021 if (.not. is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
3022 safe_deallocate_a(pcm%matrix_d)
3024 safe_deallocate_a(pcm%q_e)
3025 safe_deallocate_a(pcm%q_e_in)
3026 safe_deallocate_a(pcm%q_n)
3027 safe_deallocate_a(pcm%v_e)
3028 safe_deallocate_a(pcm%v_n)
3029 safe_deallocate_a(pcm%v_e_rs)
3030 safe_deallocate_a(pcm%v_n_rs)
3031 if (pcm%localf)
then
3032 safe_deallocate_a(pcm%matrix_lf)
3033 if (.not. is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
3034 safe_deallocate_a(pcm%matrix_lf_d)
3037 safe_deallocate_a(pcm%q_ext)
3038 safe_deallocate_a(pcm%q_ext_in)
3039 safe_deallocate_a(pcm%v_ext)
3040 safe_deallocate_a(pcm%v_ext_rs)
3041 if (pcm%kick_is_present)
then
3042 safe_deallocate_a(pcm%q_kick)
3043 safe_deallocate_a(pcm%v_kick)
3044 safe_deallocate_a(pcm%v_kick_rs)
3049 safe_deallocate_a( pcm%rho_n)
3050 safe_deallocate_a( pcm%rho_e)
3051 if (pcm%localf)
then
3052 safe_deallocate_a( pcm%rho_ext)
3053 if (pcm%kick_is_present)
then
3054 safe_deallocate_a( pcm%rho_kick)
3059 if (pcm%tdlevel ==
pcm_td_eom)
call pcm_eom_end()
3061 if (mpi_world%is_root())
call io_close(pcm%info_unit)
3068 logical function pcm_update(this)
result(update)
3069 type(
pcm_t),
intent(inout) :: this
3071 this%iter = this%iter + 1
3072 update = this%iter <= 6 .or. mod(this%iter, this%update_iter) == 0
3078 real(real64) function
pcm_get_vdw_radius(species, pcm_vdw_type, namespace) result(vdw_r)
3079 class(species_t),
intent(in) :: species
3080 integer,
intent(in) :: pcm_vdw_type
3081 type(namespace_t),
intent(in) :: namespace
3084 integer,
parameter :: upto_xe = 54
3085 real(real64),
save :: vdw_radii(1:upto_xe)
3088 data (vdw_radii(ia), ia=1, upto_xe) / &
3090 1.001_real64, 1.012_real64, &
3092 0.825_real64, 1.408_real64, 1.485_real64, 2.000_real64, 1.583_real64, 1.500_real64, 1.287_real64, 1.243_real64, &
3094 1.144_real64, 1.364_real64, 1.639_real64, 1.716_real64, 1.705_real64, 1.683_real64, 1.639_real64, 1.595_real64, &
3096 1.485_real64, 1.474_real64, &
3098 1.562_real64, 1.562_real64, &
3099 1.562_real64, 1.562_real64, &
3100 1.562_real64, 1.562_real64, &
3101 1.562_real64, 1.562_real64, &
3102 1.562_real64, 1.562_real64, &
3104 1.650_real64, 1.727_real64, 1.760_real64, 1.771_real64, 1.749_real64, 1.727_real64, &
3106 1.628_real64, 1.606_real64, 1.639_real64, 1.639_real64, &
3107 1.639_real64, 1.639_real64, &
3108 1.639_real64, 1.639_real64, &
3109 1.639_real64, 1.639_real64, &
3110 1.639_real64, 1.639_real64, &
3112 2.672_real64, 1.804_real64, 1.881_real64, 1.892_real64, 1.892_real64, 1.881_real64 /
3114 select case (pcm_vdw_type)
3116 if (species%get_z() > upto_xe)
then
3117 write(message(1),
'(a,a)')
"The van der Waals radius is missing for element ", trim(species%get_label())
3118 write(message(2),
'(a)')
"Use PCMVdWRadii = pcm_vdw_species, for other vdw radii values"
3119 call messages_fatal(2, namespace=namespace)
3121 ia = int(species%get_z())
3122 vdw_r = vdw_radii(ia)*p_ang
3125 vdw_r = species%get_vdw_radius()
3126 if (vdw_r < m_zero)
then
3127 call messages_write(
'The default vdW radius for species '//trim(species%get_label())//
':')
3128 call messages_write(
' is not defined. ')
3129 call messages_write(
' Add a positive vdW radius value in %Species block. ')
3130 call messages_fatal(namespace=namespace)
3139 subroutine pcm_dipole(mu_pcm, q_pcm, tess, n_tess)
3140 real(real64),
intent(out) :: mu_pcm(:)
3141 real(real64),
intent(in) :: q_pcm(:)
3142 integer,
intent(in) :: n_tess
3143 type(pcm_tessera_t),
intent(in) :: tess(:)
3151 mu_pcm = mu_pcm + q_pcm(ia) * tess(ia)%point
3159 subroutine pcm_eps(pcm, eps, omega)
3161 complex(real64),
intent(out) :: eps
3162 real(real64),
intent(in) :: omega
3167 if (pcm%which_eps == pcm_debye_model)
then
3169 else if (pcm%which_eps == pcm_drude_model)
then
3185 type(namespace_t),
intent(in) :: namespace
3190 call parse_variable(namespace,
'PCMCalculation', .false., pcm%run_pcm)
3191 call messages_print_with_emphasis(msg=
'PCM', namespace=namespace)
3192 call parse_variable(namespace,
'PCMLocalField', .false., pcm%localf)
3193 call messages_print_var_value(
"PCMLocalField", pcm%localf, namespace=namespace)
3194 if (pcm%localf)
then
3195 call messages_experimental(
"PCM local field effects in the optical spectrum", namespace=namespace)
3196 call messages_write(
'Beware of possible numerical errors in the optical spectrum due to PCM local field effects,')
3197 call messages_new_line()
3198 call messages_write(
'particularly, when static and high-frequency values of the dielectric functions are large')
3199 call messages_write(
' (>~10 in units of the vacuum permittivity \epsilon_0).')
3200 call messages_new_line()
3201 call messages_write(
'However, PCM local field effects in the optical spectrum work well for polar or non-polar solvents')
3202 call messages_new_line()
3203 call messages_write(
'in the nonequilibrium or equation-of-motion TD-PCM propagation schemes.')
3204 call messages_warning(namespace=namespace)
3206 call parse_variable(namespace,
'PCMTDLevel' ,
pcm_td_eq, pcm%tdlevel)
3207 call messages_print_var_value(
"PCMTDLevel", pcm%tdlevel, namespace=namespace)
3210 call parse_variable(namespace,
'PCMStaticEpsilon' , m_one, pcm%deb%eps_0)
3211 call messages_print_var_value(
"PCMStaticEpsilon", pcm%deb%eps_0, namespace=namespace)
3213 call parse_variable(namespace,
'PCMEpsilonModel', pcm_debye_model, pcm%which_eps)
3214 call messages_print_var_value(
"PCMEpsilonModel", pcm%which_eps, namespace=namespace)
3215 if (pcm%which_eps == pcm_debye_model)
then
3216 call parse_variable(namespace,
'PCMDynamicEpsilon', pcm%deb%eps_0, pcm%deb%eps_d)
3217 call messages_print_var_value(
"PCMDynamicEpsilon", pcm%deb%eps_d, namespace=namespace)
3218 call parse_variable(namespace,
'PCMDebyeRelaxTime', m_zero, pcm%deb%tau)
3219 call messages_print_var_value(
"PCMDebyeRelaxTime", pcm%deb%tau, namespace=namespace)
3220 else if (pcm%which_eps == pcm_drude_model)
then
3221 call parse_variable(namespace,
'PCMDrudeLOmega',
sqrt(m_one/(pcm%deb%eps_0-m_one)), pcm%drl%w0)
3222 call messages_print_var_value(
"PCMDrudeLOmega", pcm%drl%w0, namespace=namespace)
3223 call parse_variable(namespace,
'PCMDrudeLDamping', m_zero, pcm%drl%gm)
3224 call messages_print_var_value(
"PCMDrudeLDamping", pcm%drl%gm, namespace=namespace)
3227 call parse_variable(namespace,
'PCMDynamicEpsilon', pcm%deb%eps_0, pcm%deb%eps_d)
3228 call messages_print_var_value(
"PCMDynamicEpsilon", pcm%deb%eps_d, namespace=namespace)
3237 complex(real64),
intent(out) :: eps
3238 type(debye_param_t),
intent(in) :: deb
3239 real(real64),
intent(in) :: omega
3243 eps = deb%eps_d + (deb%eps_0 - deb%eps_d)/(m_one + (omega*deb%tau)**2) + &
3244 m_zi*omega*deb%tau*(deb%eps_0 - deb%eps_d)/(m_one + (omega*deb%tau)**2)
3252 complex(real64),
intent(out) :: eps
3253 type(drude_param_t),
intent(in) :: drl
3254 real(real64),
intent(in) :: omega
3258 eps = m_one + (drl%w0**2 - omega**2)*drl%aa/((drl%w0**2 - omega**2)**2 + (omega*drl%gm)**2) + &
3259 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...