27 use,
intrinsic :: iso_fortran_env
91 integer,
parameter :: PCM_DIM_SPACE = 3
95 logical,
public :: run_pcm
96 integer,
public :: tdlevel
98 integer,
public :: n_tesserae
99 type(pcm_sphere_t),
allocatable :: spheres(:)
100 type(pcm_tessera_t),
allocatable,
public :: tess(:)
101 real(real64) :: scale_r
102 real(real64),
allocatable :: matrix(:,:)
103 real(real64),
allocatable :: matrix_d(:,:)
104 real(real64),
allocatable :: matrix_lf(:,:)
105 real(real64),
allocatable :: matrix_lf_d(:,:)
106 real(real64),
allocatable,
public :: q_e(:)
107 real(real64),
allocatable :: q_n(:)
108 real(real64),
allocatable,
public :: q_e_in(:)
109 real(real64),
allocatable :: rho_e(:)
110 real(real64),
allocatable :: rho_n(:)
111 real(real64) :: qtot_e
112 real(real64) :: qtot_n
113 real(real64) :: qtot_e_in
114 real(real64) :: q_e_nominal
115 real(real64) :: q_n_nominal
116 logical :: renorm_charges
117 real(real64) :: q_tot_tol
118 real(real64) :: deltaQ_e
119 real(real64) :: deltaQ_n
120 real(real64),
allocatable :: v_e(:)
121 real(real64),
allocatable :: v_n(:)
122 real(real64),
allocatable,
public :: v_e_rs(:)
123 real(real64),
allocatable,
public :: v_n_rs(:)
124 real(real64),
allocatable :: q_ext(:)
125 real(real64),
allocatable :: q_ext_in(:)
126 real(real64),
allocatable :: rho_ext(:)
127 real(real64) :: qtot_ext
128 real(real64) :: qtot_ext_in
129 real(real64),
allocatable :: v_ext(:)
130 real(real64),
allocatable,
public :: v_ext_rs(:)
131 real(real64),
allocatable :: q_kick(:)
132 real(real64),
allocatable :: rho_kick(:)
133 real(real64) :: qtot_kick
134 real(real64),
allocatable :: v_kick(:)
135 real(real64),
allocatable,
public :: v_kick_rs(:)
136 real(real64),
public :: epsilon_0
137 real(real64),
public :: epsilon_infty
138 integer,
public :: which_eps
139 type(debye_param_t) :: deb
140 type(drude_param_t) :: drl
141 logical,
public :: localf
142 logical,
public :: solute
143 logical :: kick_is_present
145 logical,
public :: kick_like
146 integer :: initial_asc
147 real(real64) :: gaussian_width
149 integer,
public :: counter
150 character(len=80) :: input_cavity
151 integer :: update_iter
152 integer,
public :: iter
153 integer :: calc_method
155 real(real64),
public :: dt
159 type(namespace_t),
pointer :: namespace
160 type(space_t) :: space
169 type(debye_param_t) :: deb
170 type(drude_param_t) :: drl
173 real(real64),
allocatable :: s_mat_act(:,:)
174 real(real64),
allocatable :: d_mat_act(:,:)
175 real(real64),
allocatable :: Sigma(:,:)
176 real(real64),
allocatable :: Delta(:,:)
178 logical :: gamess_benchmark
181 integer,
parameter :: &
186 integer,
parameter,
public :: &
190 integer,
parameter :: &
201 subroutine pcm_init(pcm, namespace, space, ions, grid, qtot, val_charge, external_potentials_present, kick_present)
207 real(real64),
intent(in) :: qtot
208 real(real64),
intent(in) :: val_charge
209 logical,
intent(in) :: external_potentials_present
210 logical,
intent(in) :: kick_present
212 integer :: ia, ii, itess, jtess, pcm_vdw_type, subdivider
213 integer :: cav_unit_test, iunit, pcmmat_unit
214 integer :: pcmmat_gamess_unit, cav_gamess_unit
215 real(real64) :: min_distance
217 integer,
parameter :: mxts = 10000
219 real(real64) :: default_value
220 real(real64) :: vdw_radius
225 logical :: add_spheres_h
226 logical :: changed_default_nn
228 integer :: default_nn
229 real(real64) :: max_area
233 pcm%kick_is_present = kick_present
238 pcm%kick_like = .false.
240 pcm%namespace => namespace
256 if (pcm%run_pcm)
then
258 if (pcm%space%dim /= pcm_dim_space)
then
259 message(1) =
"PCM is only available for 3d calculations"
262 select type (box => grid%box)
265 message(1) =
"PCM is only available for BoxShape = minimum"
289 select case (pcm_vdw_type)
291 default_value = 1.2_real64
293 default_value =
m_one
304 call parse_variable(namespace,
'PCMRadiusScaling', default_value, pcm%scale_r)
328 if (pcm%tdlevel /=
pcm_td_eq .and. (.not. pcm%run_pcm))
then
329 call messages_write(
'Sorry, you have set PCMTDLevel /= eq, but PCMCalculation = no.')
331 call messages_write(
'To spare you some time, Octopus will proceed as if PCMCalculation = yes.')
353 call parse_variable(namespace,
'PCMDynamicEpsilon', pcm%epsilon_0, pcm%epsilon_infty)
376 call messages_write(
'Sorry, only Debye or Drude-Lorentz dielectric models are available.')
378 call messages_write(
'To spare you some time, Octopus will proceed with the default choice (Debye).')
380 call messages_write(
'You may change PCMEpsilonModel value for a Drude-Lorentz run.')
385 call messages_write(
'Sorry, inertial/dynamic polarization splitting scheme for TD-PCM')
388 call messages_write(
'require both static and dynamic dielectric constants,')
391 call messages_write(
'Octopus will run using TD-PCM version in equilibrium')
411 call parse_variable(namespace,
'PCMEoMInitialCharges', 0, pcm%initial_asc)
414 if (pcm%initial_asc /= 0)
then
418 call messages_write(
'Sorry, initial polarization charges can only be read')
422 call messages_write(
'Octopus will proceed as if PCMEoMInitialCharges = 0.')
429 pcm%deb%eps_0 = pcm%epsilon_0
430 pcm%deb%eps_d = pcm%epsilon_infty
447 (abs(pcm%deb%tau) <=
m_epsilon .or.
is_close(pcm%deb%eps_0, pcm%deb%eps_d)))
then
449 call messages_write(
'but you have not included all required Debye model parameters.')
451 call messages_write(
'You need PCMEpsilonStatic, PCMEpsilonDynamic')
452 call messages_write(
'and PCMDebyeRelaxTime for an EOM TD-PCM run.')
454 call messages_write(
'Octopus will run using TD-PCM version in equilibrium')
462 message(1) =
"PCMEpsilonStatic = 1 is incompatible with a Drude-Lorentz EOM-PCM run."
481 call messages_write(
'but this is incompatible with a Drude-Lorentz EOM-PCM run.')
484 call messages_write(
'Octopus will run using the default value of PCMDrudeLOmega.')
488 message(1) =
"PCMEpsilonStatic = 1 is incompatible with a Drude-Lorentz EOM-PCM run."
505 pcm%drl%aa = (pcm%epsilon_0 -
m_one)*pcm%drl%w0**2
517 call parse_variable(namespace,
'PCMLocalField', .false., pcm%localf)
520 if (pcm%localf .and. ((.not. external_potentials_present) .and. (.not. pcm%kick_is_present)))
then
521 message(1) =
"Sorry, you have set PCMLocalField = yes, but you have not included any external potentials."
537 if (pcm%run_pcm .and. (.not. pcm%solute))
then
538 call messages_write(
'N.B. This PCM run do not consider the polarization effects due to the solute.')
540 if (.not. pcm%localf)
then
541 message(1) =
"You have activated a PCM run without polarization effects. Octopus will halt."
560 if (pcm%kick_like .and. (.not. pcm%run_pcm))
then
561 message(1) =
"PCMKick option can only be activated when PCMCalculation = yes. Octopus will halt."
565 if (pcm%kick_like .and. (.not. pcm%localf))
then
566 message(1) =
"PCMKick option can only be activated when a PCMLocalField = yes. Octopus will halt."
570 if (pcm%kick_like .and. (.not. pcm%kick_is_present))
then
571 message(1) =
"Sorry, you have set PCMKick = yes, but you have not included any kick."
575 if (pcm%kick_is_present .and. pcm%run_pcm .and. (.not. pcm%localf))
then
576 message(1) =
"You have set up a PCM calculation with a kick without local field effects."
577 message(2) =
"Please, reconsider if you want the kick to be relevant for the PCM run."
588 call parse_variable(namespace,
'PCMUpdateIter', 1, pcm%update_iter)
599 call parse_variable(namespace,
'PCMGamessBenchmark', .false., gamess_benchmark)
612 call parse_variable(namespace,
'PCMRenormCharges', .false., pcm%renorm_charges)
628 if (pcm%renorm_charges)
then
629 message(1) =
"Info: Polarization charges will be renormalized"
630 message(2) =
" if |Q_tot_PCM - Q_M| > PCMQtotTol"
646 if (abs(pcm%gaussian_width) <=
m_epsilon)
then
647 message(1) =
"Info: PCM potential will be defined in terms of polarization point charges"
650 message(1) =
"Info: PCM potential is regularized to avoid Coulomb singularity"
672 if (pcm%input_cavity ==
'')
then
681 call parse_variable(namespace,
'PCMSpheresOnH', .false., add_spheres_h)
685 do ia = 1, ions%natoms
686 if ((.not. add_spheres_h) .and. ions%atom(ia)%label ==
'H') cycle
687 pcm%n_spheres = pcm%n_spheres + 1
690 safe_allocate(pcm%spheres(1:pcm%n_spheres))
697 do ia = 1, ions%natoms
698 if ((.not. add_spheres_h) .and. ions%atom(ia)%label ==
'H') cycle
699 pcm%n_spheres = pcm%n_spheres + 1
702 pcm%spheres(pcm%n_spheres)%x = ions%pos(1, ia)
703 pcm%spheres(pcm%n_spheres)%y = ions%pos(2, ia)
704 pcm%spheres(pcm%n_spheres)%z = ions%pos(3, ia)
707 pcm%spheres(pcm%n_spheres)%r = vdw_radius*pcm%scale_r
711 pcm%info_unit =
io_open(
pcm_dir//
'pcm_info.out', pcm%namespace, action=
'write')
713 write(pcm%info_unit,
'(A35)')
'# Configuration: Molecule + Solvent'
714 write(pcm%info_unit,
'(A35)')
'# ---------------------------------'
715 write(pcm%info_unit,
'(A21,F12.3)')
'# Epsilon(Solvent) = ', pcm%epsilon_0
716 write(pcm%info_unit,
'(A1)')
'#'
717 write(pcm%info_unit,
'(A35,I4)')
'# Number of interlocking spheres = ', pcm%n_spheres
718 write(pcm%info_unit,
'(A1)')
'#'
720 write(pcm%info_unit,
'(A8,3X,A7,8X,A26,20X,A10)')
'# SPHERE',
'ELEMENT',
'CENTER (X,Y,Z) (A)',
'RADIUS (A)'
721 write(pcm%info_unit,
'(A8,3X,A7,4X,A43,7X,A10)')
'# ------',
'-------', &
722 '-------------------------------------------',
'----------'
726 do ia = 1, ions%natoms
727 if ((.not. add_spheres_h) .and. ions%atom(ia)%label ==
'H') cycle
728 pcm%n_spheres = pcm%n_spheres + 1
730 write(pcm%info_unit,
'(A1,2X,I3,7X,A2,3X,F14.8,2X,F14.8,2X,F14.8,4X,F14.8)')
'#', pcm%n_spheres, &
731 ions%atom(ia)%label, &
732 ions%pos(1, ia)*
p_a_b, &
733 ions%pos(2, ia)*
p_a_b, &
734 ions%pos(3, ia)*
p_a_b, &
735 pcm%spheres(pcm%n_spheres)%r*
p_a_b
747 call parse_variable(namespace,
'PCMTessSubdivider', 1, subdivider)
749 safe_allocate(dum2(1:subdivider*
n_tess_sphere*pcm%n_spheres))
759 call parse_variable(namespace,
'PCMTessMinDistance', 0.1_real64, min_distance)
763 call cav_gen(subdivider, min_distance, pcm%n_spheres, pcm%spheres, pcm%n_tesserae, dum2, pcm%info_unit)
765 safe_allocate(pcm%tess(1:pcm%n_tesserae))
767 do ia=1, pcm%n_tesserae
768 pcm%tess(ia)%point =
m_zero
769 pcm%tess(ia)%area =
m_zero
770 pcm%tess(ia)%r_sphere =
m_zero
771 pcm%tess(ia)%normal =
m_zero
774 pcm%tess = dum2(1:pcm%n_tesserae)
776 safe_deallocate_a(dum2)
778 message(1) =
"Info: van der Waals surface has been calculated"
784 iunit =
io_open(trim(pcm%input_cavity), pcm%namespace, action=
'read', status=
'old')
785 read(iunit,*) pcm%n_tesserae
787 if (pcm%n_tesserae > mxts)
then
788 write(
message(1),
'(a,I5,a,I5)')
"total number of tesserae", pcm%n_tesserae,
">", mxts
792 safe_allocate(pcm%tess(1:pcm%n_tesserae))
794 do ia = 1, pcm%n_tesserae
795 pcm%tess(ia)%point =
m_zero
796 pcm%tess(ia)%area =
m_zero
797 pcm%tess(ia)%r_sphere =
m_zero
798 pcm%tess(ia)%normal =
m_zero
801 do ia = 1, pcm%n_tesserae
802 read(iunit,*) pcm%tess(ia)%point(1)
805 do ia = 1, pcm%n_tesserae
806 read(iunit,*) pcm%tess(ia)%point(2)
809 do ia = 1, pcm%n_tesserae
810 read(iunit,*) pcm%tess(ia)%point(3)
813 do ia = 1, pcm%n_tesserae
814 read(iunit,*) pcm%tess(ia)%area
817 do ia = 1, pcm%n_tesserae
818 read(iunit,*) pcm%tess(ia)%r_sphere
821 do ia = 1, pcm%n_tesserae
822 read(iunit,*) pcm%tess(ia)%normal
826 message(1) =
"Info: van der Waals surface has been read from " // trim(pcm%input_cavity)
831 cav_unit_test =
io_open(
pcm_dir//
'cavity_mol.xyz', pcm%namespace, action=
'write')
833 write (cav_unit_test,
'(2X,I4)') pcm%n_tesserae + ions%natoms
834 write (cav_unit_test,
'(2X)')
836 do ia = 1, pcm%n_tesserae
837 write(cav_unit_test,
'(2X,A2,3X,4f15.8,3X,4f15.8,3X,4f15.8)')
'H', pcm%tess(ia)%point*
p_a_b
840 do ia = 1, ions%natoms
841 write(cav_unit_test,
'(2X,A2,3X,4f15.8,3X,4f15.8,3X,4f15.8)') ions%atom(ia)%label, &
842 ions%pos(:, ia)*
p_a_b
847 write(pcm%info_unit,
'(A1)')
'#'
849 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)') &
850 '#',
'iter',
'E_ee',
'E_en',
'E_nn',
'E_ne',
'E_e_ext',
'E_n_ext',
'E_M-solv', &
851 'Q_pol^e',
'deltaQ^e',
'Q_pol^n',
'deltaQ^n',
'Q_pol^ext'
853 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)') &
854 '#',
'iter',
'E_ee',
'E_en',
'E_nn',
'E_ne',
'E_M-solv',
'Q_pol^e',
'deltaQ^e',
'Q_pol^n',
'deltaQ^n'
860 if (gamess_benchmark .and.
mpi_world%is_root())
then
861 cav_gamess_unit =
io_open(
pcm_dir//
'geom_cavity_gamess.out', pcm%namespace, action=
'write')
863 write(cav_gamess_unit,*) pcm%n_tesserae
865 do ia = 1, pcm%n_tesserae
866 write(cav_gamess_unit,*) pcm%tess(ia)%point(1)
869 do ia = 1, pcm%n_tesserae
870 write(cav_gamess_unit,*) pcm%tess(ia)%point(2)
873 do ia = 1, pcm%n_tesserae
874 write(cav_gamess_unit,*) pcm%tess(ia)%point(3)
877 do ia = 1, pcm%n_tesserae
878 write(cav_gamess_unit,*) pcm%tess(ia)%area
881 do ia = 1, pcm%n_tesserae
882 write(cav_gamess_unit,*) pcm%tess(ia)%r_sphere
885 do ia = 1, pcm%n_tesserae
886 write(cav_gamess_unit,*) pcm%tess(ia)%normal
893 if (gamess_benchmark)
then
894 safe_allocate(
mat_gamess(1:pcm%n_tesserae, 1:pcm%n_tesserae))
898 if (.not.
is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
900 safe_allocate(pcm%matrix_d(1:pcm%n_tesserae, 1:pcm%n_tesserae))
903 call pcm_matrix(pcm%epsilon_infty, pcm%tess, pcm%n_tesserae, pcm%matrix_d)
905 if (gamess_benchmark .and.
mpi_world%is_root())
then
906 pcmmat_gamess_unit =
io_open(
pcm_dir//
'pcm_matrix_gamess_dyn.out', pcm%namespace, action=
'write')
908 do jtess = 1, pcm%n_tesserae
909 do itess = 1, pcm%n_tesserae
910 write(pcmmat_gamess_unit,*)
mat_gamess(itess,jtess)
920 safe_allocate(pcm%matrix_lf_d(1:pcm%n_tesserae, 1:pcm%n_tesserae))
923 call pcm_matrix(pcm%epsilon_infty, pcm%tess, pcm%n_tesserae, pcm%matrix_lf_d, .
true.)
927 pcmmat_unit =
io_open(
pcm_dir//
'pcm_matrix_dynamic_lf.out', pcm%namespace, action=
'write')
928 do jtess = 1, pcm%n_tesserae
929 do itess = 1, pcm%n_tesserae
930 write(pcmmat_unit,*) pcm%matrix_lf_d(itess,jtess)
940 safe_allocate(pcm%matrix(1:pcm%n_tesserae, 1:pcm%n_tesserae))
943 call pcm_matrix(pcm%epsilon_0, pcm%tess, pcm%n_tesserae, pcm%matrix)
946 pcmmat_unit =
io_open(
pcm_dir//
'pcm_matrix.out', pcm%namespace, action=
'write')
947 if (gamess_benchmark) pcmmat_gamess_unit =
io_open(
pcm_dir//
'pcm_matrix_gamess.out', &
948 pcm%namespace, action=
'write')
950 do jtess = 1, pcm%n_tesserae
951 do itess = 1, pcm%n_tesserae
952 write(pcmmat_unit,*) pcm%matrix(itess,jtess)
953 if (gamess_benchmark)
write(pcmmat_gamess_unit,*)
mat_gamess(itess,jtess)
957 if (gamess_benchmark)
call io_close(pcmmat_gamess_unit)
961 if (gamess_benchmark)
then
967 safe_allocate(pcm%matrix_lf(1:pcm%n_tesserae, 1:pcm%n_tesserae))
970 call pcm_matrix(pcm%epsilon_0, pcm%tess, pcm%n_tesserae, pcm%matrix_lf, .
true.)
974 pcmmat_unit =
io_open(
pcm_dir//
'pcm_matrix_static_lf.out', pcm%namespace, action=
'write')
975 do jtess = 1, pcm%n_tesserae
976 do itess = 1, pcm%n_tesserae
977 write(pcmmat_unit,*) pcm%matrix_lf(itess,jtess)
985 message(1) =
"Info: PCM response matrices has been evaluated"
1007 do ia = 1, pcm%n_tesserae
1008 if (pcm%tess(ia)%area > max_area) max_area = pcm%tess(ia)%area
1012 default_nn = int(max_area*pcm%gaussian_width/minval(grid%spacing(1:pcm%space%dim)))
1014 changed_default_nn = .false.
1016 do ii = default_nn, 1, -1
1021 changed_default_nn = .
true.
1024 if (changed_default_nn)
then
1025 call messages_write(
'PCM nearest neighbors have been reduced from ')
1035 default_nn = pcm%tess_nn
1049 call parse_variable(namespace,
'PCMChargeSmearNN', default_nn, pcm%tess_nn)
1059 safe_allocate(pcm%rho_n(1:grid%np_part))
1060 safe_allocate(pcm%rho_e(1:grid%np_part))
1061 if (pcm%localf)
then
1062 safe_allocate(pcm%rho_ext(1:grid%np_part))
1063 if (pcm%kick_is_present)
then
1064 safe_allocate(pcm%rho_kick(1:grid%np_part))
1070 safe_allocate(pcm%v_n(1:pcm%n_tesserae))
1071 safe_allocate(pcm%q_n(1:pcm%n_tesserae))
1072 safe_allocate(pcm%v_n_rs(1:grid%np))
1077 safe_allocate(pcm%v_e(1:pcm%n_tesserae))
1078 safe_allocate(pcm%q_e(1:pcm%n_tesserae))
1079 safe_allocate(pcm%v_e_rs(1:grid%np))
1084 safe_allocate(pcm%q_e_in(1:pcm%n_tesserae))
1088 if (pcm%localf)
then
1089 safe_allocate(pcm%v_ext(1:pcm%n_tesserae))
1090 safe_allocate(pcm%q_ext(1:pcm%n_tesserae))
1091 safe_allocate(pcm%v_ext_rs(1:grid%np))
1096 safe_allocate(pcm%q_ext_in(1:pcm%n_tesserae))
1099 if (pcm%kick_is_present)
then
1100 safe_allocate(pcm%v_kick(1:pcm%n_tesserae))
1101 safe_allocate(pcm%q_kick(1:pcm%n_tesserae))
1102 safe_allocate(pcm%v_kick_rs(1:grid%np))
1110 pcm%q_e_nominal = qtot
1111 pcm%q_n_nominal = val_charge
1122 subroutine pcm_calc_pot_rs(pcm, mesh, psolver, ions, v_h, v_ext, kick, time_present, kick_time)
1123 type(
pcm_t),
intent(inout) :: pcm
1124 class(
mesh_t),
intent(in) :: mesh
1126 type(
ions_t),
optional,
intent(in) :: ions
1127 real(real64),
optional,
intent(in) :: v_h(:)
1128 real(real64),
optional,
intent(in) :: v_ext(:)
1129 real(real64),
optional,
intent(in) :: kick(:)
1130 logical,
optional,
intent(in) :: time_present
1131 logical,
optional,
intent(in) :: kick_time
1133 integer,
save :: calc
1135 logical,
save :: input_asc_e
1136 logical,
save :: input_asc_ext
1141 logical,
save :: not_yet_called = .false.
1142 logical,
save :: is_time_for_kick = .false.
1143 logical,
save :: after_kick = .false.
1145 logical,
save :: td_calc_mode = .false.
1147 integer,
save :: asc_vs_t_unit_e
1149 character(len=23),
save :: asc_vs_t_unit_format
1150 character(len=16),
save :: asc_vs_t_unit_format_tail
1156 assert(
present(v_h) .or.
present(ions) .or.
present(v_ext) .or.
present(kick))
1161 if ((.not.
present(v_ext)) .and.
present(kick)) calc =
pcm_kick
1164 if (
present(time_present))
then
1165 if (time_present) td_calc_mode = .
true.
1168 if (
present(kick_time))
then
1169 is_time_for_kick = kick_time
1170 if (kick_time) after_kick = .
true.
1173 select case (pcm%initial_asc)
1175 input_asc_e = .
true.
1176 input_asc_ext = .false.
1178 input_asc_e = .false.
1179 input_asc_ext = .
true.
1181 input_asc_e = .
true.
1182 input_asc_ext = .
true.
1184 input_asc_e = .false.
1185 input_asc_ext = .false.
1190 call pcm_charges(pcm%q_n, pcm%qtot_n, pcm%v_n, pcm%matrix, pcm%n_tesserae, &
1191 pcm%q_n_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_n)
1195 call pcm_pot_rs(pcm, pcm%v_n_rs, pcm%q_n, pcm%rho_n, mesh, psolver)
1200 if (td_calc_mode .and. .not.
is_close(pcm%epsilon_infty, pcm%epsilon_0) .and. pcm%tdlevel /=
pcm_td_eq)
then
1202 select case (pcm%tdlevel)
1204 select case (pcm%which_eps)
1214 pcm%qtot_e = sum(pcm%q_e)
1216 select case (pcm%iter)
1221 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix, pcm%n_tesserae, &
1222 pcm%q_e_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1225 call pcm_charges(pcm%q_e_in, pcm%qtot_e_in, pcm%v_e, pcm%matrix_d, pcm%n_tesserae, &
1226 pcm%q_e_nominal, pcm%epsilon_infty, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1228 pcm%q_e_in = pcm%q_e - pcm%q_e_in
1229 pcm%qtot_e_in = pcm%qtot_e - pcm%qtot_e_in
1232 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix_d, pcm%n_tesserae, &
1233 pcm%q_e_nominal, pcm%epsilon_infty, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1235 pcm%q_e = pcm%q_e + pcm%q_e_in
1236 pcm%qtot_e = pcm%qtot_e + pcm%qtot_e_in
1242 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix, pcm%n_tesserae, &
1243 pcm%q_e_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1249 call pcm_pot_rs(pcm, pcm%v_e_rs, pcm%q_e, pcm%rho_e, mesh, psolver)
1259 if (td_calc_mode .and. .not.
is_close(pcm%epsilon_infty, pcm%epsilon_0) .and. pcm%tdlevel /=
pcm_td_eq)
then
1261 select case (pcm%tdlevel)
1263 select case (pcm%which_eps)
1266 pcm%which_eps, pcm%namespace, this_drl=pcm%drl)
1269 pcm%which_eps, pcm%namespace, this_deb=pcm%deb)
1273 pcm%qtot_ext = sum(pcm%q_ext)
1276 pcm%q_ext = pcm%q_ext + pcm%q_ext_in
1277 pcm%qtot_ext = pcm%qtot_ext + pcm%qtot_ext_in
1280 call pcm_charges(pcm%q_ext, pcm%qtot_ext, pcm%v_ext, pcm%matrix_lf_d, pcm%n_tesserae)
1284 pcm%q_ext = pcm%q_ext + pcm%q_ext_in
1285 pcm%qtot_ext = pcm%qtot_ext + pcm%qtot_ext_in
1292 call pcm_charges(pcm%q_ext, pcm%qtot_ext, pcm%v_ext, pcm%matrix_lf, pcm%n_tesserae)
1295 pcm%q_ext_in = pcm%q_ext
1296 pcm%qtot_ext_in = pcm%qtot_ext
1301 call pcm_pot_rs(pcm, pcm%v_ext_rs, pcm%q_ext, pcm%rho_ext, mesh, psolver)
1308 if (is_time_for_kick)
then
1313 if (pcm%kick_like)
then
1314 if (is_time_for_kick)
then
1316 if (.not.
is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
1317 call pcm_charges(pcm%q_kick, pcm%qtot_kick, pcm%v_kick, pcm%matrix_lf_d, pcm%n_tesserae)
1319 call pcm_charges(pcm%q_kick, pcm%qtot_kick, pcm%v_kick, pcm%matrix_lf, pcm%n_tesserae)
1331 if (after_kick)
then
1333 select case (pcm%which_eps)
1336 pcm%which_eps, pcm%namespace, this_drl=pcm%drl)
1339 pcm%which_eps, pcm%namespace, this_deb=pcm%deb)
1342 pcm%qtot_kick = sum(pcm%q_kick)
1358 call pcm_pot_rs(pcm, pcm%v_kick_rs, pcm%q_kick, pcm%rho_kick, mesh, psolver)
1359 if (.not. pcm%kick_like)
then
1361 pcm%q_ext = pcm%q_ext + pcm%q_kick
1362 pcm%v_ext_rs = pcm%v_ext_rs + pcm%v_kick_rs
1364 pcm%q_ext = pcm%q_kick
1365 pcm%v_ext_rs = pcm%v_kick_rs
1373 write (asc_vs_t_unit_format_tail,
'(I5,A11)') pcm%n_tesserae,
'(1X,F14.8))'
1374 write (asc_vs_t_unit_format,
'(A)')
'(F14.8,'//trim(adjustl(asc_vs_t_unit_format_tail))
1376 if (pcm%solute .and. pcm%localf .and. td_calc_mode .and. calc ==
pcm_electrons)
then
1377 asc_vs_t_unit_e =
io_open(
pcm_dir//
'ASC_e_vs_t.dat', pcm%namespace, &
1378 action=
'write', position=
'append', form=
'formatted')
1379 write(asc_vs_t_unit_e,trim(adjustl(asc_vs_t_unit_format))) pcm%iter*pcm%dt, &
1380 (pcm%q_e(ia) , ia = 1,pcm%n_tesserae)
1392 type(
pcm_t),
intent(in) :: pcm
1393 type(
mesh_t),
intent(in) :: mesh
1394 real(real64),
intent(in) :: v_mesh(:)
1395 real(real64),
intent(out) :: v_cav(:)
1407 do ia = 1, pcm%n_tesserae
1421 real(real64),
intent(out) :: v_n_cav(:)
1422 type(
ions_t),
intent(in) :: ions
1424 integer,
intent(in) :: n_tess
1426 real(real64) :: dist
1434 do ia = 1, ions%natoms
1436 dist = norm2(ions%pos(1:pcm_dim_space, ia) - tess(ik)%point)
1438 v_n_cav(ik) = v_n_cav(ik) - ions%charge(ia)/dist
1450 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)
1451 type(
ions_t),
intent(in) :: ions
1452 type(
pcm_t),
intent(in) :: pcm
1453 real(real64),
intent(out) :: e_int_ee
1454 real(real64),
intent(out) :: e_int_en
1455 real(real64),
intent(out) :: e_int_ne
1456 real(real64),
intent(out) :: e_int_nn
1457 real(real64),
optional,
intent(out) :: e_int_e_ext
1458 real(real64),
optional,
intent(out) :: e_int_n_ext
1460 real(real64) :: dist, z_ia
1470 if (pcm%localf .and. ((.not.
present(e_int_e_ext)) .or. &
1471 (.not.
present(e_int_n_ext))))
then
1472 message(1) =
"pcm_elect_energy: There are lacking terms in subroutine call."
1474 else if (pcm%localf .and. (
present(e_int_e_ext) .and. &
1475 present(e_int_n_ext)))
then
1480 do ik = 1, pcm%n_tesserae
1482 e_int_ee = e_int_ee + pcm%v_e(ik)*pcm%q_e(ik)
1483 e_int_en = e_int_en + pcm%v_e(ik)*pcm%q_n(ik)
1484 if (pcm%localf)
then
1485 e_int_e_ext = e_int_e_ext + pcm%v_e(ik)*pcm%q_ext(ik)
1488 do ia = 1, ions%natoms
1490 dist = norm2(ions%pos(1:pcm_dim_space, ia) - pcm%tess(ik)%point)
1492 z_ia = -ions%charge(ia)
1494 e_int_ne = e_int_ne + z_ia*pcm%q_e(ik) / dist
1495 e_int_nn = e_int_nn + z_ia*pcm%q_n(ik) / dist
1496 if (pcm%localf) e_int_n_ext = e_int_n_ext + z_ia*pcm%q_ext(ik) / dist
1501 e_int_ee =
m_half*e_int_ee
1502 e_int_en =
m_half*e_int_en
1503 e_int_ne =
m_half*e_int_ne
1504 e_int_nn =
m_half*e_int_nn
1509 if (pcm%localf)
then
1510 write(pcm%info_unit, &
1511 '(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)') &
1526 write(pcm%info_unit, &
1527 '(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)') &
1549 subroutine pcm_charges(q_pcm, q_pcm_tot, v_cav, pcm_mat, n_tess, qtot_nominal, epsilon, renorm_charges, q_tot_tol, deltaQ)
1550 real(real64),
intent(out) :: q_pcm(:)
1551 real(real64),
intent(out) :: q_pcm_tot
1552 real(real64),
intent(in) :: v_cav(:)
1553 real(real64),
intent(in) :: pcm_mat(:,:)
1554 integer,
intent(in) :: n_tess
1555 real(real64),
optional,
intent(in) :: qtot_nominal
1556 real(real64),
optional,
intent(in) :: epsilon
1557 logical,
optional,
intent(in) :: renorm_charges
1558 real(real64),
optional,
intent(in) :: q_tot_tol
1559 real(real64),
optional,
intent(out) :: deltaq
1562 real(real64) :: q_pcm_tot_norm
1563 real(real64) :: coeff
1573 q_pcm(ia) = q_pcm(ia) + pcm_mat(ia,ib)*v_cav(ib)
1575 q_pcm_tot = q_pcm_tot + q_pcm(ia)
1578 if (
present(qtot_nominal) .and.
present(epsilon) .and. &
1579 present(renorm_charges) .and.
present(q_tot_tol) .and.
present(deltaq))
then
1581 deltaq = abs(q_pcm_tot) - ((epsilon -
m_one)/epsilon) * abs(qtot_nominal)
1582 if ((renorm_charges) .and. (abs(deltaq) > q_tot_tol))
then
1584 coeff = sign(
m_one, qtot_nominal)*sign(
m_one, deltaq)
1586 q_pcm(ia) = q_pcm(ia) + coeff*q_pcm(ia)/q_pcm_tot*abs(deltaq)
1587 q_pcm_tot_norm = q_pcm_tot_norm + q_pcm(ia)
1589 q_pcm_tot = q_pcm_tot_norm
1600 type(
pcm_t),
intent(in) :: pcm
1601 class(
mesh_t),
intent(in) :: mesh
1603 integer :: ia, nm(pcm%space%dim), ipt, i1, i2, i3
1604 real(real64) :: posrel(pcm%space%dim)
1605 integer(int64) :: pt
1610 do ia = 1, pcm%n_tesserae
1612 posrel(:) = pcm%tess(ia)%point(1:pcm%space%dim)/mesh%spacing(1:pcm%space%dim)
1614 nm(:) =
floor(posrel(:))
1618 do i1 = -pcm%tess_nn + 1 , pcm%tess_nn
1619 do i2 = -pcm%tess_nn + 1 , pcm%tess_nn
1620 do i3 = -pcm%tess_nn + 1 , pcm%tess_nn
1624 if (pt <= 0 .or. pt > mesh%np_part_global)
then
1641 type(
pcm_t),
intent(in) :: pcm
1642 class(
mesh_t),
intent(in) :: mesh
1647 message(1) =
'The simulation box is too small to contain all the requested'
1648 message(2) =
'nearest neighbors for each tessera.'
1649 message(3) =
'Consider using a larger box or reduce PCMChargeSmearNN.'
1660 type(
pcm_t),
intent(inout) :: pcm
1661 real(real64),
intent(in) :: q_pcm(:)
1662 real(real64),
intent(in) :: q_pcm_tot
1663 type(
mesh_t),
intent(in) :: mesh
1664 real(real64),
intent(out) :: rho(:)
1667 real(real64) :: norm, qtot, rr, xx(pcm%space%dim), pp(pcm%space%dim)
1670 integer :: nm(pcm%space%dim)
1671 real(real64) :: posrel(pcm%space%dim)
1673 integer :: i1, i2, i3
1674 integer,
allocatable :: pt(:)
1675 real(real64),
allocatable :: lrho(:)
1676 logical :: inner_point, boundary_point
1684 npt = (2*pcm%tess_nn)**pcm%space%dim
1685 safe_allocate(pt(1:npt))
1686 safe_allocate(lrho(1:npt))
1691 do ia = 1, pcm%n_tesserae
1693 pp(:) = pcm%tess(ia)%point(1:pcm%space%dim)
1694 posrel(:) = pp(:)/mesh%spacing(1:pcm%space%dim)
1696 nm(:) =
floor(posrel(:))
1700 do i1 = -pcm%tess_nn + 1 , pcm%tess_nn
1701 do i2 = -pcm%tess_nn + 1 , pcm%tess_nn
1702 do i3 = -pcm%tess_nn + 1 , pcm%tess_nn
1718 if (pt(ipt) > 0 .and. pt(ipt) <= mesh%np_part)
then
1720 if (mesh%parallel_in_domains)
then
1721 boundary_point = pt(ipt) > mesh%np + mesh%pv%np_ghost
1722 inner_point = pt(ipt) > 0 .and. pt(ipt) <= mesh%np
1724 if (boundary_point .or. inner_point)
then
1725 xx(:) = mesh%x(pt(ipt),:)
1731 xx(:) = mesh%x(pt(ipt), :)
1734 rr = sum((xx(1:pcm%space%dim) - pp(1:pcm%space%dim))**2)
1735 norm = norm +
exp(-rr/(pcm%tess(ia)%area*pcm%gaussian_width))
1736 lrho(ipt) = lrho(ipt) +
exp(-rr/(pcm%tess(ia)%area*pcm%gaussian_width))
1742 call mesh%allreduce(lrho, npt)
1745 norm = sum(lrho(1:npt)) * mesh%volume_element
1747 norm = q_pcm(ia)/norm
1751 lrho(:) = lrho(:) * norm
1756 if (pt(ipt) > 0 .and. pt(ipt) <= mesh%np_part_global)
then
1758 if (mesh%parallel_in_domains)
then
1759 boundary_point = pt(ipt) > mesh%np + mesh%pv%np_ghost
1760 inner_point = pt(ipt) > 0 .and. pt(ipt) <= mesh%np
1761 if (boundary_point .or. inner_point) rho(pt(ipt)) = rho(pt(ipt)) + lrho(ipt)
1763 rho(pt(ipt)) = rho(pt(ipt)) + lrho(ipt)
1771 if (
debug%info)
then
1785 safe_deallocate_a(pt)
1786 safe_deallocate_a(lrho)
1796 subroutine pcm_pot_rs(pcm, v_pcm, q_pcm, rho, mesh, psolver)
1797 type(
pcm_t),
intent(inout) :: pcm
1798 real(real64),
contiguous,
intent(inout) :: v_pcm(:)
1799 real(real64),
contiguous,
intent(in) :: q_pcm(:)
1800 real(real64),
contiguous,
intent(inout) :: rho(:)
1801 type(
mesh_t),
intent(in) :: mesh
1811 select case (pcm%calc_method)
1813 call pcm_pot_rs_direct(v_pcm, q_pcm, pcm%tess, pcm%n_tesserae, mesh, pcm%gaussian_width)
1824 if (
debug%info)
then
1839 real(real64),
contiguous,
intent(inout) :: v_pcm(:)
1841 real(real64),
contiguous,
intent(inout) :: rho(:)
1854 real(real64),
intent(out) :: v_pcm(:)
1855 real(real64),
intent(in) :: q_pcm(:)
1856 real(real64),
intent(in) :: width_factor
1857 integer,
intent(in) :: n_tess
1858 type(
mesh_t),
intent(in) :: mesh
1861 real(real64),
parameter :: p_1 = 0.119763_real64
1862 real(real64),
parameter :: p_2 = 0.205117_real64
1863 real(real64),
parameter :: q_1 = 0.137546_real64
1864 real(real64),
parameter :: q_2 = 0.434344_real64
1866 real(real64) :: term
1879 call mesh_r(mesh, ip, term, origin=tess(ia)%point)
1880 arg = term/
sqrt(tess(ia)%area*width_factor)
1881 term = (
m_one + p_1*arg + p_2*arg**2) / (
m_one + q_1*arg + q_2*arg**2 + p_2*arg**3)
1882 v_pcm(ip) = v_pcm(ip) + q_pcm(ia) * term/
sqrt(tess(ia)%area*width_factor)
1893 call mesh_r(mesh, ip, term, origin=tess(ia)%point)
1894 v_pcm(ip) = v_pcm(ip) + q_pcm(ia)/term
1905 subroutine pcm_matrix(eps, tess, n_tess, pcm_mat, localf)
1906 real(real64),
intent(in) :: eps
1908 integer,
intent(in) :: n_tess
1909 real(real64),
intent(out) :: pcm_mat(:,:)
1910 logical,
optional,
intent(in) :: localf
1913 integer,
allocatable :: iwork(:)
1914 real(real64),
allocatable :: mat_tmp(:,:)
1916 real(real64) :: sgn_lf
1921 safe_allocate(s_mat_act(1:n_tess, 1:n_tess))
1925 safe_allocate(sigma(1:n_tess, 1:n_tess))
1926 sigma = s_mat_act/eps
1929 safe_allocate(d_mat_act(1:n_tess, 1:n_tess))
1933 safe_allocate(delta(1:n_tess, 1:n_tess))
1938 if (
present(localf))
then
1939 if (localf) sgn_lf = -
m_one
1943 pcm_mat = - sgn_lf * d_mat_act
1946 pcm_mat(i,i) = pcm_mat(i,i) +
m_two*
m_pi
1949 safe_deallocate_a(d_mat_act)
1951 safe_allocate(iwork(1:n_tess))
1956 call dgesv(n_tess, n_tess, s_mat_act, n_tess, iwork, pcm_mat, n_tess,
info)
1958 safe_deallocate_a(iwork)
1960 safe_deallocate_a(s_mat_act)
1964 pcm_mat = -matmul(sigma, pcm_mat)
1967 pcm_mat(i,i) = pcm_mat(i,i) +
m_two*
m_pi
1970 pcm_mat = pcm_mat - sgn_lf * delta
1972 safe_allocate(mat_tmp(1:n_tess,1:n_tess))
1975 safe_allocate(d_mat_act(1:n_tess,1:n_tess))
1978 mat_tmp = transpose(d_mat_act)
1980 mat_tmp = matmul(sigma, mat_tmp)
1984 safe_deallocate_a(d_mat_act)
1986 safe_allocate(s_mat_act(1:n_tess, 1:n_tess))
1989 mat_tmp = mat_tmp +
m_two*
m_pi*s_mat_act - matmul(delta, s_mat_act)
1991 safe_deallocate_a(s_mat_act)
1992 safe_deallocate_a(sigma)
1993 safe_deallocate_a(delta)
1995 safe_allocate(iwork(1:n_tess))
1999 call dgesv(n_tess, n_tess, mat_tmp, n_tess, iwork, pcm_mat, n_tess,
info)
2001 safe_deallocate_a(iwork)
2002 safe_deallocate_a(mat_tmp)
2004 pcm_mat = - sgn_lf * pcm_mat
2007 if (gamess_benchmark)
then
2019 integer,
intent(in) :: n_tess
2029 if (ii /= jj) s_mat_act(jj,ii) = s_mat_act(ii,jj)
2038 integer,
intent(in) :: n_tess
2057 real(real64) function s_mat_elem_I(tessi, tessj)
2061 real(real64),
parameter :: M_SD_DIAG = 1.0694_real64
2062 real(real64),
parameter :: M_DIST_MIN = 0.1_real64
2064 real(real64) :: diff(1:PCM_DIM_SPACE)
2065 real(real64) :: dist
2066 real(real64) :: s_diag
2067 real(real64) :: s_off_diag
2072 diff = tessi%point - tessj%point
2078 s_mat_elem_i = s_diag
2080 if (dist > m_dist_min) s_off_diag =
m_one/dist
2081 s_mat_elem_i = s_off_diag
2089 real(real64) function d_mat_elem_I(tessi, tessj)
2090 type(pcm_tessera_t),
intent(in) :: tessi
2091 type(pcm_tessera_t),
intent(in) :: tessj
2093 real(real64),
parameter :: M_SD_DIAG = 1.0694_real64
2094 real(real64),
parameter :: M_DIST_MIN = 0.04_real64
2096 real(real64) :: diff(1:PCM_DIM_SPACE)
2097 real(real64) :: dist
2098 real(real64) :: d_diag
2099 real(real64) :: d_off_diag
2105 diff = tessi%point - tessj%point
2109 if (abs(dist) <= m_epsilon)
then
2111 d_diag = m_sd_diag*
sqrt(m_four*m_pi*tessi%area)
2112 d_diag = -d_diag/(m_two*tessi%r_sphere)
2117 if (dist > m_dist_min)
then
2118 d_off_diag = dot_product( diff, tessj%normal(:))
2119 d_off_diag = d_off_diag*tessj%area/dist**3
2133 subroutine cav_gen(tess_sphere, tess_min_distance, nesf, sfe, nts, cts, unit_pcminfo)
2134 integer,
intent(in) :: tess_sphere
2135 real(real64) ,
intent(in) :: tess_min_distance
2137 integer,
intent(in) :: nesf
2138 integer,
intent(out) :: nts
2139 type(pcm_tessera_t),
intent(out) :: cts(:)
2140 integer,
intent(in) :: unit_pcminfo
2142 integer,
parameter :: DIM_ANGLES = 24
2143 integer,
parameter :: DIM_TEN = 10
2144 integer,
parameter :: DIM_VERTICES = 122
2145 integer,
parameter :: MAX_VERTICES = 6
2146 integer,
parameter :: MXTS = 10000
2148 real(real64),
save :: thev(1:DIM_ANGLES)
2149 real(real64),
save :: fiv(1:DIM_ANGLES)
2150 real(real64),
save :: fir
2151 real(real64) :: cv(1:DIM_VERTICES, 1:PCM_DIM_SPACE)
2161 real(real64) :: nctst(pcm_dim_space, tess_sphere*
n_tess_sphere)
2163 real(real64) :: pts(1:pcm_dim_space, 1:dim_ten)
2164 real(real64) :: pp(1:pcm_dim_space)
2165 real(real64) :: pp1(1:pcm_dim_space)
2166 real(real64) :: ccc(1:pcm_dim_space, 1:dim_ten)
2170 integer :: isfet(1:dim_ten*dim_angles)
2188 real(real64) :: area
2189 real(real64) :: test2
2191 real(real64) :: dnorm
2201 real(real64) :: stot
2202 real(real64) :: prod
2205 logical :: band_iter
2211 data thev/ 0.6523581398_real64 , 1.107148718_real64 , 1.382085796_real64 , &
2212 1.759506858_real64 , 2.034443936_real64 , 2.489234514_real64 , &
2213 0.3261790699_real64 , 0.5535743589_real64, &
2214 0.8559571251_real64 , 0.8559571251_real64 , 1.017221968_real64 , &
2215 1.229116717_real64 , 1.229116717_real64 , 1.433327788_real64 , &
2216 1.570796327_real64 , 1.570796327_real64 , 1.708264866_real64 , &
2217 1.912475937_real64 , 1.912475937_real64 , 2.124370686_real64 , &
2218 2.285635528_real64 , 2.285635528_real64 , 2.588018295_real64 , &
2219 2.815413584_real64 /
2220 data fiv/ 0.6283185307_real64 , m_zero , &
2221 0.6283185307_real64 , m_zero , 0.6283185307_real64, &
2222 m_zero , 0.6283185307_real64 , m_zero, &
2223 0.2520539002_real64 , 1.004583161_real64 , 0.6283185307_real64, &
2224 0.3293628477_real64 , 0.9272742138_real64 , m_zero, &
2225 0.3141592654_real64 , 0.9424777961_real64 , 0.6283185307_real64, &
2226 0.2989556830_real64 , 0.9576813784_real64 , m_zero, &
2227 0.3762646305_real64 , 0.8803724309_real64 , 0.6283188307_real64, &
2229 data fir / 1.256637061_real64 /
2233 data (idum(ii),ii = 1, 280) / &
2234 1, 6, 2, 32, 36, 37, 1, 2, 3, 33, 32, 38, 1, 3, 4, 34, &
2235 33, 39, 1, 4, 5, 35, 34, 40, 1, 5, 6, 36, 35, 41, 7, 2, 6, 51, &
2236 42, 37, 8, 3, 2, 47, 43, 38, 9, 4, 3, 48, 44, 39, 10, 5, 4, &
2237 49, 45, 40, 11, 6, 5, 50, 46, 41, 8, 2, 12, 62, 47, 52, 9, &
2238 3, 13, 63, 48, 53, 10, 4, 14, 64, 49, 54, 11, 5, 15, 65, 50, &
2239 55, 7, 6, 16, 66, 51, 56, 7, 12, 2, 42, 57, 52, 8, 13, 3, &
2240 43, 58, 53, 9, 14, 4, 44, 59, 54, 10, 15, 5, 45, 60, 55, 11, &
2241 16, 6, 46, 61, 56, 8, 12, 18, 68, 62, 77, 9, 13, 19, 69, 63, &
2242 78, 10, 14, 20, 70, 64, 79, 11, 15, 21, 71, 65, 80, 7, 16, &
2243 17, 67, 66, 81, 7, 17, 12, 57, 67, 72, 8, 18, 13, 58, 68, 73, &
2244 9, 19, 14, 59, 69, 74, 10, 20, 15, 60, 70, 75, 11, 21, 16, &
2245 61, 71, 76, 22, 12, 17, 87, 82, 72, 23, 13, 18, 88, 83, 73, &
2246 24, 14, 19, 89, 84, 74, 25, 15, 20, 90, 85, 75, 26, 16, 21, &
2247 91, 86, 76, 22, 18, 12, 82, 92, 77, 23, 19, 13, 83, 93, 78, &
2248 24, 20, 14, 84, 94, 79, 25, 21, 15, 85, 95, 80, 26, 17, 16, &
2249 86, 96, 81, 22, 17, 27, 102, 87, 97, 23, 18, 28, 103, 88, 98, &
2250 24, 19, 29, 104, 89, 99, 25, 20, 30, 105, 90, 100, 26, 21, &
2251 31, 106, 91, 101, 22, 28, 18, 92, 107, 98, 23, 29, 19, 93 /
2252 data (idum(ii),ii = 281,360) / &
2253 108, 99, 24, 30, 20, 94, 109, 100, 25, 31, 21, 95, 110, 101, &
2254 26, 27, 17, 96, 111, 97, 22, 27, 28, 107, 102, 112, 23, 28, &
2255 29, 108, 103, 113, 24, 29, 30, 109, 104, 114, 25, 30, 31, &
2256 110, 105, 115, 26, 31, 27, 111, 106, 116, 122, 28, 27, 117, &
2257 118, 112, 122, 29, 28, 118, 119, 113, 122, 30, 29, 119, 120, &
2258 114, 122, 31, 30, 120, 121, 115, 122, 27, 31, 121, 117, 116 /
2260 if (mpi_world%is_root())
then
2261 if (tess_sphere == 1)
then
2262 write(unit_pcminfo,
'(A1)')
'#'
2263 write(unit_pcminfo,
'(A34)')
'# Number of tesserae / sphere = 60'
2264 write(unit_pcminfo,
'(A1)')
'#'
2266 write(unit_pcminfo,
'(A1)')
'#'
2267 write(unit_pcminfo,
'(A35)')
'# Number of tesserae / sphere = 240'
2268 write(unit_pcminfo,
'(A1)')
'#'
2277 sfe(:)%x = sfe(:)%x*p_a_b
2278 sfe(:)%y = sfe(:)%y*p_a_b
2279 sfe(:)%z = sfe(:)%z*p_a_b
2280 sfe(:)%r = sfe(:)%r*p_a_b
2284 jvt1 = reshape(idum,(/6,60/))
2307 do ia = 1, dim_angles
2314 if (ja == 1) fi = fiv(ia)
2316 cv(ii,1) = sth*
cos(fi)
2317 cv(ii,2) = sth*
sin(fi)
2336 do i_tes = 1, tess_sphere
2337 if (tess_sphere == 1)
then
2342 if (i_tes == 1)
then
2346 elseif (i_tes == 2)
then
2350 elseif (i_tes == 3)
then
2354 elseif (i_tes == 4)
then
2361 pts(1,1) = cv(n1,1)*ren + xen
2362 pts(2,1) = cv(n1,3)*ren + yen
2363 pts(3,1) = cv(n1,2)*ren + zen
2365 pts(1,2) = cv(n2,1)*ren + xen
2366 pts(2,2) = cv(n2,3)*ren + yen
2367 pts(3,2) = cv(n2,2)*ren + zen
2369 pts(1,3) = cv(n3,1)*ren + xen
2370 pts(2,3) = cv(n3,3)*ren + yen
2371 pts(3,3) = cv(n3,2)*ren + zen
2377 call subtessera(sfe, nsfe, nesf, nv, pts ,ccc, pp, pp1, area)
2379 if (abs(area) <= m_epsilon) cycle
2381 xctst(tess_sphere*(its-1) + i_tes) = pp(1)
2382 yctst(tess_sphere*(its-1) + i_tes) = pp(2)
2383 zctst(tess_sphere*(its-1) + i_tes) = pp(3)
2384 nctst(:,tess_sphere*(its-1) + i_tes) = pp1(:)
2385 ast(tess_sphere*(its-1) + i_tes) = area
2386 isfet(tess_sphere*(its-1) + i_tes) = nsfe
2393 if (abs(ast(its)) <= m_epsilon) cycle
2397 write(message(1),
'(a,I5,a,I5)')
"total number of tesserae", nn,
">",mxts
2398 call messages_warning(1)
2401 cts(nn)%point(1) = xctst(its)
2402 cts(nn)%point(2) = yctst(its)
2403 cts(nn)%point(3) = zctst(its)
2404 cts(nn)%normal(:) = nctst(:,its)
2405 cts(nn)%area = ast(its)
2406 cts(nn)%r_sphere = sfe(isfet(its))%r
2414 test2 = tess_min_distance*tess_min_distance
2417 do while (.not.(band_iter))
2420 loop_ia:
do ia = 1, nts-1
2421 if (abs(cts(ia)%area) <= m_epsilon) cycle
2422 xi = cts(ia)%point(1)
2423 yi = cts(ia)%point(2)
2424 zi = cts(ia)%point(3)
2426 loop_ja:
do ja = ia+1, nts
2427 if (abs(cts(ja)%area) <= m_epsilon) cycle
2428 xj = cts(ja)%point(1)
2429 yj = cts(ja)%point(2)
2430 zj = cts(ja)%point(3)
2432 rij = (xi - xj)**2 + (yi - yj)**2 + (zi - zj)**2
2434 if (rij > test2) cycle
2436 if (mpi_world%is_root())
then
2437 write(unit_pcminfo,
'(A40,I4,A5,I4,A4,F8.4,A13,F8.4,A3)') &
2438 '# Warning: The distance between tesserae', &
2439 ia,
' and ', ja,
' is ',
sqrt(rij),
' A, less than', tess_min_distance,
' A.'
2443 xi = (xi*cts(ia)%area + xj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2444 yi = (yi*cts(ia)%area + yj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2445 zi = (zi*cts(ia)%area + zj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2447 cts(ia)%point(1) = xi
2448 cts(ia)%point(2) = yi
2449 cts(ia)%point(3) = zi
2452 cts(ia)%normal = (cts(ia)%normal*cts(ia)%area + cts(ja)%normal*cts(ja)%area)
2453 dnorm = norm2(cts(ia)%normal)
2454 cts(ia)%normal = cts(ia)%normal/dnorm
2457 cts(ia)%r_sphere = (cts(ia)%r_sphere*cts(ia)%area + cts(ja)%r_sphere*cts(ja)%area) / &
2458 (cts(ia)%area + cts(ja)%area)
2461 cts(ia)%area = cts(ia)%area + cts(ja)%area
2478 prod = dot_product(cts(its)%point, cts(its)%normal)
2479 vol = vol + cts(its)%area * prod / m_three
2480 stot = stot + cts(its)%area
2483 if (mpi_world%is_root())
then
2484 write(unit_pcminfo,
'(A2)')
'# '
2485 write(unit_pcminfo,
'(A29,I4)')
'# Total number of tesserae = ' , nts
2486 write(unit_pcminfo,
'(A30,F12.6)')
'# Cavity surface area (A^2) = ', stot
2487 write(unit_pcminfo,
'(A24,F12.6)')
'# Cavity volume (A^3) = ' , vol
2488 write(unit_pcminfo,
'(A2)')
'# '
2492 cts(:)%area = cts(:)%area*p_ang*p_ang
2493 cts(:)%point(1) = cts(:)%point(1)*p_ang
2494 cts(:)%point(2) = cts(:)%point(2)*p_ang
2495 cts(:)%point(3) = cts(:)%point(3)*p_ang
2496 cts(:)%r_sphere = cts(:)%r_sphere*p_ang
2498 sfe(:)%x=sfe(:)%x*p_ang
2499 sfe(:)%y=sfe(:)%y*p_ang
2500 sfe(:)%z=sfe(:)%z*p_ang
2501 sfe(:)%r=sfe(:)%r*p_ang
2510 subroutine subtessera(sfe, ns, nesf, nv, pts, ccc, pp, pp1, area)
2512 integer,
intent(in) :: ns
2513 integer,
intent(in) :: nesf
2514 integer,
intent(inout) :: nv
2515 real(real64),
intent(inout) :: pts(:,:)
2516 real(real64),
intent(out) :: ccc(:,:)
2517 real(real64),
intent(out) :: pp(:)
2518 real(real64),
intent(out) :: pp1(:)
2519 real(real64),
intent(out) :: area
2521 real(real64),
parameter :: TOL = -1.0e-10_real64
2522 integer,
parameter :: DIM_TEN = 10
2524 integer :: intsph(1:DIM_TEN)
2535 real(real64) :: p1(1:PCM_DIM_SPACE)
2536 real(real64) :: p2(1:PCM_DIM_SPACE)
2537 real(real64) :: p3(1:PCM_DIM_SPACE)
2538 real(real64) :: p4(1:PCM_DIM_SPACE)
2539 real(real64) :: point(1:PCM_DIM_SPACE)
2540 real(real64) :: pscr(1:PCM_DIM_SPACE,1:DIM_TEN)
2541 real(real64) :: cccp(1:PCM_DIM_SPACE,1:DIM_TEN)
2542 real(real64) :: pointl(1:PCM_DIM_SPACE,1:DIM_TEN)
2543 real(real64) :: diff(1:PCM_DIM_SPACE)
2545 integer :: ind(1:DIM_TEN)
2546 integer :: ltyp(1:DIM_TEN)
2547 integer :: intscr(1:DIM_TEN)
2549 real(real64) :: delr
2550 real(real64) :: delr2
2553 real(real64) :: dnorm
2554 real(real64) :: dist
2571 ccc(1,jj) = sfe(ns)%x
2572 ccc(2,jj) = sfe(ns)%y
2573 ccc(3,jj) = sfe(ns)%z
2578 if (nsfe1 == ns) cycle
2580 intscr(jj) = intsph(jj)
2581 pscr(:,jj) = pts(:,jj)
2582 cccp(:,jj) = ccc(:,jj)
2590 delr2 = (pts(1,ii) - sfe(nsfe1)%x)**2 + (pts(2,ii) - sfe(nsfe1)%y)**2 + (pts(3,ii) - sfe(nsfe1)%z)**2
2592 if (delr < sfe(nsfe1)%r)
then
2598 if (icop == nv)
then
2606 if (ll == nv) iv2 = 1
2607 if ((ind(iv1) == 1) .and. (ind(iv2) == 1))
then
2609 else if ((ind(iv1) == 0) .and. (ind(iv2) == 1))
then
2611 else if ((ind(iv1) == 1) .and. (ind(iv2) == 0))
then
2613 else if ((ind(iv1) == 0) .and. (ind(iv2) == 0))
then
2615 diff = ccc(:,ll) - pts(:,ll)
2616 rc2 = dot_product(diff, diff)
2620 point = pts(:,iv1) + ii * (pts(:,iv2) - pts(:,iv1)) / 11
2621 point = point - ccc(:,ll)
2622 dnorm = norm2(point)
2623 point = point * rc / dnorm + ccc(:,ll)
2625 dist =
sqrt((point(1) - sfe(nsfe1)%x)**2 + (point(2) - sfe(nsfe1)%y)**2 + (point(3) - sfe(nsfe1)%z)**2)
2627 if ((dist - sfe(nsfe1)%r) < tol)
then
2629 pointl(:, ll) = point
2639 if ((ltyp(ll) == 1) .or. (ltyp(ll) == 2)) icut = icut + 1
2640 if (ltyp(ll) == 3) icut = icut + 2
2651 if (ltyp(ll) == 0) cycle
2654 if (ll == nv) iv2 = 1
2656 if (ltyp(ll) == 1)
then
2657 pts(:,na) = pscr(:,iv1)
2658 ccc(:,na) = cccp(:,iv1)
2659 intsph(na) = intscr(iv1)
2665 call inter(sfe, p1, p2, p3, p4, nsfe1, 0)
2668 de2 = (sfe(nsfe1)%x - sfe(ns)%x)**2 + ( sfe(nsfe1)%y - sfe(ns)%y)**2 + &
2669 (sfe(nsfe1)%z - sfe(ns)%z)**2
2671 ccc(1,na) = sfe(ns)%x + ( sfe(nsfe1)%x - sfe(ns)%x)* &
2672 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2674 ccc(2,na) = sfe(ns)%y + ( sfe(nsfe1)%y - sfe(ns)%y)* &
2675 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2677 ccc(3,na) = sfe(ns)%z + ( sfe(nsfe1)%z - sfe(ns)%z)* &
2678 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2684 if (ltyp(ll) == 2)
then
2689 call inter(sfe, p1, p2, p3, p4, nsfe1, 1)
2691 ccc(:,na) = cccp(:,iv1)
2692 intsph(na) = intscr(iv1)
2696 if (ltyp(ll) == 3)
then
2697 pts(:,na) = pscr(:,iv1)
2698 ccc(:,na) = cccp(:,iv1)
2699 intsph(na) = intscr(iv1)
2705 call inter(sfe, p1, p2, p3, p4, nsfe1, 0)
2708 de2 = (sfe(nsfe1)%x - sfe(ns)%x)**2 + (sfe(nsfe1)%y - sfe(ns)%y)**2 + (sfe(nsfe1)%z - sfe(ns)%z)**2
2710 ccc(1,na) = sfe(ns)%x + (sfe(nsfe1)%x - sfe(ns)%x) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2712 ccc(2,na) = sfe(ns)%y + (sfe(nsfe1)%y - sfe(ns)%y) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2714 ccc(3,na) = sfe(ns)%z + (sfe(nsfe1)%z - sfe(ns)%z) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2722 call inter(sfe, p1, p2, p3, p4, nsfe1, 1)
2724 ccc(:,na) = cccp(:,iv1)
2725 intsph(na) = intscr(iv1)
2729 if (ltyp(ll) == 4)
then
2730 pts(:,na) = pscr(:,iv1)
2731 ccc(:,na) = cccp(:,iv1)
2732 intsph(na) = intscr(iv1)
2739 message(1) =
"Too many vertices on the tessera"
2740 call messages_fatal(1)
2744 call gaubon(sfe, nv, ns, pts, ccc, pp, pp1, area, intsph)
2754 subroutine inter(sfe, p1, p2, p3, p4, ns, ia)
2756 real(real64),
intent(in) :: p1(1:PCM_DIM_SPACE)
2757 real(real64),
intent(in) :: p2(1:PCM_DIM_SPACE)
2758 real(real64),
intent(in) :: p3(1:PCM_DIM_SPACE)
2759 real(real64),
intent(out) :: p4(1:PCM_DIM_SPACE)
2760 integer,
intent(in) :: ns
2761 integer,
intent(in) :: ia
2763 real(real64),
parameter :: TOL = 1.0e-08_real64
2767 real(real64) :: alpha
2768 real(real64) :: delta
2769 real(real64) :: dnorm
2770 real(real64) :: diff
2771 real(real64) :: diff_vec(1:PCM_DIM_SPACE)
2772 logical :: band_iter
2784 do while(.not.(band_iter))
2785 if (m_iter > 1000)
then
2786 message(1) =
"Too many iterations inside subrotuine inter"
2787 call messages_fatal(1)
2792 alpha = alpha + delta
2794 p4 = p1 + alpha*(p2 - p1) - p3
2796 p4 = p4*r/dnorm + p3
2797 diff = (p4(1) - sfe(ns)%x)**2 + (p4(2) - sfe(ns)%y)**2 + (p4(3) - sfe(ns)%z)**2
2798 diff =
sqrt(diff) - sfe(ns)%r
2800 if (abs(diff) < tol)
then
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))
2813 if (diff > m_zero) delta = -m_one/(m_two**(m_iter + 1))
2814 if (diff < m_zero) delta = m_one/(m_two**(m_iter + 1))
2821 end subroutine inter
2831 subroutine gaubon(sfe, nv, ns, pts, ccc, pp, pp1, area, intsph)
2833 real(real64),
intent(in) :: pts(:,:)
2834 real(real64),
intent(in) :: ccc(:,:)
2835 real(real64),
intent(inout) :: pp(:)
2836 real(real64),
intent(inout) :: pp1(:)
2837 integer,
intent(in) :: intsph(:)
2838 real(real64),
intent(out) :: area
2839 integer,
intent(in) :: nv
2840 integer,
intent(in) :: ns
2842 real(real64) :: p1(1:PCM_DIM_SPACE), p2(1:PCM_DIM_SPACE), p3(1:PCM_DIM_SPACE)
2843 real(real64) :: u1(1:PCM_DIM_SPACE), u2(1:PCM_DIM_SPACE)
2844 real(real64) :: point_1(1:PCM_DIM_SPACE), point_2(1:PCM_DIM_SPACE)
2845 real(real64) :: tpi, sum1, dnorm, dnorm1, dnorm2
2846 real(real64) :: cosphin, phin, costn, sum2, betan
2847 integer :: nsfe1, ia, nn, n0, n1, n2
2862 point_1 = pts(:,nn) - ccc(:,nn)
2864 point_2 = pts(:,nn+1) - ccc(:,nn)
2866 point_2 = pts(:,1) - ccc(:,nn)
2869 dnorm1 = norm2(point_1)
2870 dnorm2 = norm2(point_2)
2871 cosphin = dot_product(point_1, point_2) / (dnorm1*dnorm2)
2873 if (cosphin > m_one) cosphin = m_one
2874 if (cosphin < -m_one) cosphin = -m_one
2876 phin =
acos(cosphin)
2879 point_1(1) = sfe(nsfe1)%x - sfe(ns)%x
2880 point_1(2) = sfe(nsfe1)%y - sfe(ns)%y
2881 point_1(3) = sfe(nsfe1)%z - sfe(ns)%z
2883 dnorm1 = norm2(point_1)
2885 if (abs(dnorm1) <= m_epsilon) dnorm1 = m_one
2887 point_2(1) = pts(1,nn) - sfe(ns)%x
2888 point_2(2) = pts(2,nn) - sfe(ns)%y
2889 point_2(3) = pts(3,nn) - sfe(ns)%z
2891 dnorm2 = norm2(point_2)
2893 costn = dot_product(point_1, point_2) / (dnorm1 * dnorm2)
2894 sum1 = sum1 + phin * costn
2905 if (nn > 1) n0 = nn - 1
2906 if (nn == 1) n0 = nv
2907 if (nn < nv) n2 = nn + 1
2908 if (nn == nv) n2 = 1
2910 p1 = pts(:,n1) - ccc(:,n0)
2911 p2 = pts(:,n0) - ccc(:,n0)
2912 call vecp(p1, p2, p3, dnorm)
2915 call vecp(p1, p2, p3, dnorm)
2918 p1 = pts(:,n1) - ccc(:,n1)
2919 p2 = pts(:,n2) - ccc(:,n1)
2920 call vecp(p1, p2, p3, dnorm)
2923 call vecp(p1, p2, p3, dnorm)
2927 sum2 = sum2 + (m_pi - betan)
2931 area = sfe(ns)%r*sfe(ns)%r*(tpi + sum1 - sum2)
2937 pp(1) = pp(1) + (pts(1,ia) - sfe(ns)%x)
2938 pp(2) = pp(2) + (pts(2,ia) - sfe(ns)%y)
2939 pp(3) = pp(3) + (pts(3,ia) - sfe(ns)%z)
2944 pp(1) = sfe(ns)%x + pp(1) * sfe(ns)%r / dnorm
2945 pp(2) = sfe(ns)%y + pp(2) * sfe(ns)%r / dnorm
2946 pp(3) = sfe(ns)%z + pp(3) * sfe(ns)%r / dnorm
2949 pp1(1) = (pp(1) - sfe(ns)%x) / sfe(ns)%r
2950 pp1(2) = (pp(2) - sfe(ns)%y) / sfe(ns)%r
2951 pp1(3) = (pp(3) - sfe(ns)%z) / sfe(ns)%r
2954 if (area < m_zero) area = m_zero
2962 subroutine vecp(p1, p2, p3, dnorm)
2963 real(real64),
intent(in) :: P1(:)
2964 real(real64),
intent(in) :: P2(:)
2965 real(real64),
intent(out) :: P3(:)
2966 real(real64),
intent(out) :: dnorm
2969 p3(1) = p1(2)*p2(3) - p1(3)*p2(2)
2970 p3(2) = p1(3)*p2(1) - p1(1)*p2(3)
2971 p3(3) = p1(1)*p2(2) - p1(2)*p2(1)
2978 type(
pcm_t),
intent(inout) :: pcm
2980 integer :: asc_unit_test, asc_unit_test_sol, asc_unit_test_e, asc_unit_test_n, asc_unit_test_ext
2985 if (pcm%solute .and. pcm%localf)
then
2986 asc_unit_test = io_open(pcm_dir//
'ASC.dat', pcm%namespace, action=
'write')
2987 asc_unit_test_sol = io_open(pcm_dir//
'ASC_sol.dat', pcm%namespace, action=
'write')
2988 asc_unit_test_e = io_open(pcm_dir//
'ASC_e.dat', pcm%namespace, action=
'write')
2989 asc_unit_test_n = io_open(pcm_dir//
'ASC_n.dat', pcm%namespace, action=
'write')
2990 asc_unit_test_ext = io_open(pcm_dir//
'ASC_ext.dat', pcm%namespace, action=
'write')
2991 do ia = 1, pcm%n_tesserae
2992 write(asc_unit_test,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia) + pcm%q_ext(ia), ia
2993 write(asc_unit_test_sol,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia), ia
2994 write(asc_unit_test_e,*) pcm%tess(ia)%point, pcm%q_e(ia), ia
2995 write(asc_unit_test_n,*) pcm%tess(ia)%point, pcm%q_n(ia), ia
2996 write(asc_unit_test_ext,*) pcm%tess(ia)%point, pcm%q_ext(ia), ia
2998 call io_close(asc_unit_test)
2999 call io_close(asc_unit_test_sol)
3000 call io_close(asc_unit_test_e)
3001 call io_close(asc_unit_test_n)
3002 call io_close(asc_unit_test_ext)
3004 else if (pcm%solute .and. .not. pcm%localf)
then
3005 asc_unit_test_sol = io_open(pcm_dir//
'ASC_sol.dat', pcm%namespace, action=
'write')
3006 asc_unit_test_e = io_open(pcm_dir//
'ASC_e.dat', pcm%namespace, action=
'write')
3007 asc_unit_test_n = io_open(pcm_dir//
'ASC_n.dat', pcm%namespace, action=
'write')
3008 do ia = 1, pcm%n_tesserae
3009 write(asc_unit_test_sol,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia), ia
3010 write(asc_unit_test_e,*) pcm%tess(ia)%point, pcm%q_e(ia), ia
3011 write(asc_unit_test_n,*) pcm%tess(ia)%point, pcm%q_n(ia), ia
3013 call io_close(asc_unit_test_sol)
3014 call io_close(asc_unit_test_e)
3015 call io_close(asc_unit_test_n)
3017 else if (.not. pcm%solute .and. pcm%localf)
then
3018 asc_unit_test_ext = io_open(pcm_dir//
'ASC_ext.dat', pcm%namespace, action=
'write')
3019 do ia = 1, pcm%n_tesserae
3020 write(asc_unit_test_ext,*) pcm%tess(ia)%point, pcm%q_ext(ia), ia
3022 call io_close(asc_unit_test_ext)
3025 safe_deallocate_a(pcm%spheres)
3026 safe_deallocate_a(pcm%tess)
3027 safe_deallocate_a(pcm%matrix)
3028 if (.not. is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
3029 safe_deallocate_a(pcm%matrix_d)
3031 safe_deallocate_a(pcm%q_e)
3032 safe_deallocate_a(pcm%q_e_in)
3033 safe_deallocate_a(pcm%q_n)
3034 safe_deallocate_a(pcm%v_e)
3035 safe_deallocate_a(pcm%v_n)
3036 safe_deallocate_a(pcm%v_e_rs)
3037 safe_deallocate_a(pcm%v_n_rs)
3038 if (pcm%localf)
then
3039 safe_deallocate_a(pcm%matrix_lf)
3040 if (.not. is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
3041 safe_deallocate_a(pcm%matrix_lf_d)
3044 safe_deallocate_a(pcm%q_ext)
3045 safe_deallocate_a(pcm%q_ext_in)
3046 safe_deallocate_a(pcm%v_ext)
3047 safe_deallocate_a(pcm%v_ext_rs)
3048 if (pcm%kick_is_present)
then
3049 safe_deallocate_a(pcm%q_kick)
3050 safe_deallocate_a(pcm%v_kick)
3051 safe_deallocate_a(pcm%v_kick_rs)
3056 safe_deallocate_a( pcm%rho_n)
3057 safe_deallocate_a( pcm%rho_e)
3058 if (pcm%localf)
then
3059 safe_deallocate_a( pcm%rho_ext)
3060 if (pcm%kick_is_present)
then
3061 safe_deallocate_a( pcm%rho_kick)
3066 if (pcm%tdlevel ==
pcm_td_eom)
call pcm_eom_end()
3068 if (mpi_world%is_root())
call io_close(pcm%info_unit)
3075 logical function pcm_update(this)
result(update)
3076 type(
pcm_t),
intent(inout) :: this
3078 this%iter = this%iter + 1
3079 update = this%iter <= 6 .or. mod(this%iter, this%update_iter) == 0
3085 real(real64) function
pcm_get_vdw_radius(species, pcm_vdw_type, namespace) result(vdw_r)
3086 class(species_t),
intent(in) :: species
3087 integer,
intent(in) :: pcm_vdw_type
3088 type(namespace_t),
intent(in) :: namespace
3091 integer,
parameter :: upto_xe = 54
3092 real(real64),
save :: vdw_radii(1:upto_xe)
3095 data (vdw_radii(ia), ia=1, upto_xe) / &
3097 1.001_real64, 1.012_real64, &
3099 0.825_real64, 1.408_real64, 1.485_real64, 2.000_real64, 1.583_real64, 1.500_real64, 1.287_real64, 1.243_real64, &
3101 1.144_real64, 1.364_real64, 1.639_real64, 1.716_real64, 1.705_real64, 1.683_real64, 1.639_real64, 1.595_real64, &
3103 1.485_real64, 1.474_real64, &
3105 1.562_real64, 1.562_real64, &
3106 1.562_real64, 1.562_real64, &
3107 1.562_real64, 1.562_real64, &
3108 1.562_real64, 1.562_real64, &
3109 1.562_real64, 1.562_real64, &
3111 1.650_real64, 1.727_real64, 1.760_real64, 1.771_real64, 1.749_real64, 1.727_real64, &
3113 1.628_real64, 1.606_real64, 1.639_real64, 1.639_real64, &
3114 1.639_real64, 1.639_real64, &
3115 1.639_real64, 1.639_real64, &
3116 1.639_real64, 1.639_real64, &
3117 1.639_real64, 1.639_real64, &
3119 2.672_real64, 1.804_real64, 1.881_real64, 1.892_real64, 1.892_real64, 1.881_real64 /
3121 select case (pcm_vdw_type)
3123 if (species%get_z() > upto_xe)
then
3124 write(message(1),
'(a,a)')
"The van der Waals radius is missing for element ", trim(species%get_label())
3125 write(message(2),
'(a)')
"Use PCMVdWRadii = pcm_vdw_species, for other vdw radii values"
3126 call messages_fatal(2, namespace=namespace)
3128 ia = int(species%get_z())
3129 vdw_r = vdw_radii(ia)*p_ang
3132 vdw_r = species%get_vdw_radius()
3133 if (vdw_r < m_zero)
then
3134 call messages_write(
'The default vdW radius for species '//trim(species%get_label())//
':')
3135 call messages_write(
' is not defined. ')
3136 call messages_write(
' Add a positive vdW radius value in %Species block. ')
3137 call messages_fatal(namespace=namespace)
3146 subroutine pcm_dipole(mu_pcm, q_pcm, tess, n_tess)
3147 real(real64),
intent(out) :: mu_pcm(:)
3148 real(real64),
intent(in) :: q_pcm(:)
3149 integer,
intent(in) :: n_tess
3150 type(pcm_tessera_t),
intent(in) :: tess(:)
3158 mu_pcm = mu_pcm + q_pcm(ia) * tess(ia)%point
3166 subroutine pcm_field(e_pcm, q_pcm, ref_point, tess, n_tess)
3167 real(real64),
intent(out) :: e_pcm(:)
3168 real(real64),
intent(in) :: q_pcm(:)
3169 integer,
intent(in) :: n_tess
3170 type(pcm_tessera_t),
intent(in) :: tess(:)
3171 real(real64),
intent(in) :: ref_point(1:3)
3173 real(real64) :: diff(1:3)
3174 real(real64) :: dist
3182 diff = ref_point - tess(ia)%point
3184 e_pcm = e_pcm + q_pcm(ia) * diff / dist**3
3192 subroutine pcm_eps(pcm, eps, omega)
3194 complex(real64),
intent(out) :: eps
3195 real(real64),
intent(in) :: omega
3200 if (pcm%which_eps == pcm_debye_model)
then
3202 else if (pcm%which_eps == pcm_drude_model)
then
3218 type(namespace_t),
intent(in) :: namespace
3223 call parse_variable(namespace,
'PCMCalculation', .false., pcm%run_pcm)
3224 call messages_print_with_emphasis(msg=
'PCM', namespace=namespace)
3225 call parse_variable(namespace,
'PCMLocalField', .false., pcm%localf)
3226 call messages_print_var_value(
"PCMLocalField", pcm%localf, namespace=namespace)
3227 if (pcm%localf)
then
3228 call messages_experimental(
"PCM local field effects in the optical spectrum", namespace=namespace)
3229 call messages_write(
'Beware of possible numerical errors in the optical spectrum due to PCM local field effects,')
3230 call messages_new_line()
3231 call messages_write(
'particularly, when static and high-frequency values of the dielectric functions are large')
3232 call messages_write(
' (>~10 in units of the vacuum permittivity \epsilon_0).')
3233 call messages_new_line()
3234 call messages_write(
'However, PCM local field effects in the optical spectrum work well for polar or non-polar solvents')
3235 call messages_new_line()
3236 call messages_write(
'in the nonequilibrium or equation-of-motion TD-PCM propagation schemes.')
3237 call messages_warning(namespace=namespace)
3239 call parse_variable(namespace,
'PCMTDLevel' ,
pcm_td_eq, pcm%tdlevel)
3240 call messages_print_var_value(
"PCMTDLevel", pcm%tdlevel, namespace=namespace)
3243 call parse_variable(namespace,
'PCMStaticEpsilon' , m_one, pcm%deb%eps_0)
3244 call messages_print_var_value(
"PCMStaticEpsilon", pcm%deb%eps_0, namespace=namespace)
3246 call parse_variable(namespace,
'PCMEpsilonModel', pcm_debye_model, pcm%which_eps)
3247 call messages_print_var_value(
"PCMEpsilonModel", pcm%which_eps, namespace=namespace)
3248 if (pcm%which_eps == pcm_debye_model)
then
3249 call parse_variable(namespace,
'PCMDynamicEpsilon', pcm%deb%eps_0, pcm%deb%eps_d)
3250 call messages_print_var_value(
"PCMDynamicEpsilon", pcm%deb%eps_d, namespace=namespace)
3251 call parse_variable(namespace,
'PCMDebyeRelaxTime', m_zero, pcm%deb%tau)
3252 call messages_print_var_value(
"PCMDebyeRelaxTime", pcm%deb%tau, namespace=namespace)
3253 else if (pcm%which_eps == pcm_drude_model)
then
3254 call parse_variable(namespace,
'PCMDrudeLOmega',
sqrt(m_one/(pcm%deb%eps_0-m_one)), pcm%drl%w0)
3255 call messages_print_var_value(
"PCMDrudeLOmega", pcm%drl%w0, namespace=namespace)
3256 call parse_variable(namespace,
'PCMDrudeLDamping', m_zero, pcm%drl%gm)
3257 call messages_print_var_value(
"PCMDrudeLDamping", pcm%drl%gm, namespace=namespace)
3260 call parse_variable(namespace,
'PCMDynamicEpsilon', pcm%deb%eps_0, pcm%deb%eps_d)
3261 call messages_print_var_value(
"PCMDynamicEpsilon", pcm%deb%eps_d, namespace=namespace)
3270 complex(real64),
intent(out) :: eps
3271 type(debye_param_t),
intent(in) :: deb
3272 real(real64),
intent(in) :: omega
3276 eps = deb%eps_d + (deb%eps_0 - deb%eps_d)/(m_one + (omega*deb%tau)**2) + &
3277 m_zi*omega*deb%tau*(deb%eps_0 - deb%eps_d)/(m_one + (omega*deb%tau)**2)
3285 complex(real64),
intent(out) :: eps
3286 type(drude_param_t),
intent(in) :: drl
3287 real(real64),
intent(in) :: omega
3291 eps = m_one + (drl%w0**2 - omega**2)*drl%aa/((drl%w0**2 - omega**2)**2 + (omega*drl%gm)**2) + &
3292 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_field(e_pcm, q_pcm, ref_point, tess, n_tess)
Computes the field e_pcm at the reference point ref_point due to a distribution of charges q_pcm.
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...