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(:,:)
181 integer,
parameter :: &
186 integer,
parameter,
public :: &
187 PCM_CALC_DIRECT = 1, &
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
255 call parse_variable(namespace,
'PCMCalculation', .false., pcm%run_pcm)
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)
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'
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
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)
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')
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)
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"
1000 call parse_variable(namespace,
'PCMCalcMethod', pcm_calc_direct, pcm%calc_method)
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)
1124 type(
pcm_t),
intent(inout) :: pcm
1125 class(
mesh_t),
intent(in) :: mesh
1127 type(
ions_t),
optional,
intent(in) :: ions
1128 real(real64),
optional,
intent(in) :: v_h(:)
1129 real(real64),
optional,
intent(in) :: v_ext(:)
1130 real(real64),
optional,
intent(in) :: kick(:)
1131 logical,
optional,
intent(in) :: time_present
1132 logical,
optional,
intent(in) :: kick_time
1136 logical :: input_asc_e
1137 logical :: input_asc_ext
1142 logical :: not_yet_called = .false.
1143 logical :: is_time_for_kick = .false.
1144 logical :: after_kick = .false.
1146 logical :: td_calc_mode = .false.
1148 integer :: asc_vs_t_unit_e
1150 character(len=23) :: asc_vs_t_unit_format
1151 character(len=16) :: asc_vs_t_unit_format_tail
1157 assert(
present(v_h) .or.
present(ions) .or.
present(v_ext) .or.
present(kick))
1162 if ((.not.
present(v_ext)) .and.
present(kick)) calc =
pcm_kick
1165 if (
present(time_present))
then
1166 if (time_present) td_calc_mode = .
true.
1169 if (
present(kick_time))
then
1170 is_time_for_kick = kick_time
1171 if (kick_time) after_kick = .
true.
1174 select case (pcm%initial_asc)
1176 input_asc_e = .
true.
1177 input_asc_ext = .false.
1179 input_asc_e = .false.
1180 input_asc_ext = .
true.
1182 input_asc_e = .
true.
1183 input_asc_ext = .
true.
1185 input_asc_e = .false.
1186 input_asc_ext = .false.
1191 call pcm_charges(pcm%q_n, pcm%qtot_n, pcm%v_n, pcm%matrix, pcm%n_tesserae, &
1192 pcm%q_n_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_n)
1196 call pcm_pot_rs(pcm, pcm%v_n_rs, pcm%q_n, pcm%rho_n, mesh, psolver)
1201 if (td_calc_mode .and. .not.
is_close(pcm%epsilon_infty, pcm%epsilon_0) .and. pcm%tdlevel /=
pcm_td_eq)
then
1203 select case (pcm%tdlevel)
1205 select case (pcm%which_eps)
1215 pcm%qtot_e = sum(pcm%q_e)
1217 select case (pcm%iter)
1222 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix, pcm%n_tesserae, &
1223 pcm%q_e_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1226 call pcm_charges(pcm%q_e_in, pcm%qtot_e_in, pcm%v_e, pcm%matrix_d, pcm%n_tesserae, &
1227 pcm%q_e_nominal, pcm%epsilon_infty, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1229 pcm%q_e_in = pcm%q_e - pcm%q_e_in
1230 pcm%qtot_e_in = pcm%qtot_e - pcm%qtot_e_in
1233 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix_d, pcm%n_tesserae, &
1234 pcm%q_e_nominal, pcm%epsilon_infty, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1236 pcm%q_e = pcm%q_e + pcm%q_e_in
1237 pcm%qtot_e = pcm%qtot_e + pcm%qtot_e_in
1243 call pcm_charges(pcm%q_e, pcm%qtot_e, pcm%v_e, pcm%matrix, pcm%n_tesserae, &
1244 pcm%q_e_nominal, pcm%epsilon_0, pcm%renorm_charges, pcm%q_tot_tol, pcm%deltaQ_e)
1250 call pcm_pot_rs(pcm, pcm%v_e_rs, pcm%q_e, pcm%rho_e, mesh, psolver)
1260 if (td_calc_mode .and. .not.
is_close(pcm%epsilon_infty, pcm%epsilon_0) .and. pcm%tdlevel /=
pcm_td_eq)
then
1262 select case (pcm%tdlevel)
1264 select case (pcm%which_eps)
1267 pcm%which_eps, pcm%namespace, this_drl=pcm%drl)
1270 pcm%which_eps, pcm%namespace, this_deb=pcm%deb)
1274 pcm%qtot_ext = sum(pcm%q_ext)
1277 pcm%q_ext = pcm%q_ext + pcm%q_ext_in
1278 pcm%qtot_ext = pcm%qtot_ext + pcm%qtot_ext_in
1281 call pcm_charges(pcm%q_ext, pcm%qtot_ext, pcm%v_ext, pcm%matrix_lf_d, pcm%n_tesserae)
1285 pcm%q_ext = pcm%q_ext + pcm%q_ext_in
1286 pcm%qtot_ext = pcm%qtot_ext + pcm%qtot_ext_in
1293 call pcm_charges(pcm%q_ext, pcm%qtot_ext, pcm%v_ext, pcm%matrix_lf, pcm%n_tesserae)
1296 pcm%q_ext_in = pcm%q_ext
1297 pcm%qtot_ext_in = pcm%qtot_ext
1302 call pcm_pot_rs(pcm, pcm%v_ext_rs, pcm%q_ext, pcm%rho_ext, mesh, psolver)
1309 if (is_time_for_kick)
then
1314 if (pcm%kick_like)
then
1315 if (is_time_for_kick)
then
1317 if (.not.
is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
1318 call pcm_charges(pcm%q_kick, pcm%qtot_kick, pcm%v_kick, pcm%matrix_lf_d, pcm%n_tesserae)
1320 call pcm_charges(pcm%q_kick, pcm%qtot_kick, pcm%v_kick, pcm%matrix_lf, pcm%n_tesserae)
1332 if (after_kick)
then
1334 select case (pcm%which_eps)
1337 pcm%which_eps, pcm%namespace, this_drl=pcm%drl)
1340 pcm%which_eps, pcm%namespace, this_deb=pcm%deb)
1343 pcm%qtot_kick = sum(pcm%q_kick)
1359 call pcm_pot_rs(pcm, pcm%v_kick_rs, pcm%q_kick, pcm%rho_kick, mesh, psolver)
1360 if (.not. pcm%kick_like)
then
1362 pcm%q_ext = pcm%q_ext + pcm%q_kick
1363 pcm%v_ext_rs = pcm%v_ext_rs + pcm%v_kick_rs
1365 pcm%q_ext = pcm%q_kick
1366 pcm%v_ext_rs = pcm%v_kick_rs
1374 write (asc_vs_t_unit_format_tail,
'(I5,A11)') pcm%n_tesserae,
'(1X,F14.8))'
1375 write (asc_vs_t_unit_format,
'(A)')
'(F14.8,'//trim(adjustl(asc_vs_t_unit_format_tail))
1377 if (pcm%solute .and. pcm%localf .and. td_calc_mode .and. calc ==
pcm_electrons)
then
1378 asc_vs_t_unit_e =
io_open(
pcm_dir//
'ASC_e_vs_t.dat', pcm%namespace, &
1379 action=
'write', position=
'append', form=
'formatted')
1380 write(asc_vs_t_unit_e,trim(adjustl(asc_vs_t_unit_format))) pcm%iter*pcm%dt, &
1381 (pcm%q_e(ia) , ia = 1,pcm%n_tesserae)
1393 type(
pcm_t),
intent(in) :: pcm
1394 type(
mesh_t),
intent(in) :: mesh
1395 real(real64),
intent(in) :: v_mesh(:)
1396 real(real64),
intent(out) :: v_cav(:)
1408 do ia = 1, pcm%n_tesserae
1422 real(real64),
intent(out) :: v_n_cav(:)
1423 type(
ions_t),
intent(in) :: ions
1425 integer,
intent(in) :: n_tess
1427 real(real64) :: dist
1435 do ia = 1, ions%natoms
1437 dist = norm2(ions%pos(1:pcm_dim_space, ia) - tess(ik)%point)
1439 v_n_cav(ik) = v_n_cav(ik) - ions%charge(ia)/dist
1451 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)
1452 type(
ions_t),
intent(in) :: ions
1453 type(
pcm_t),
intent(in) :: pcm
1454 real(real64),
intent(out) :: e_int_ee
1455 real(real64),
intent(out) :: e_int_en
1456 real(real64),
intent(out) :: e_int_ne
1457 real(real64),
intent(out) :: e_int_nn
1458 real(real64),
optional,
intent(out) :: e_int_e_ext
1459 real(real64),
optional,
intent(out) :: e_int_n_ext
1461 real(real64) :: dist, z_ia
1471 if (pcm%localf .and. ((.not.
present(e_int_e_ext)) .or. &
1472 (.not.
present(e_int_n_ext))))
then
1473 message(1) =
"pcm_elect_energy: There are lacking terms in subroutine call."
1475 else if (pcm%localf .and. (
present(e_int_e_ext) .and. &
1476 present(e_int_n_ext)))
then
1481 do ik = 1, pcm%n_tesserae
1483 e_int_ee = e_int_ee + pcm%v_e(ik)*pcm%q_e(ik)
1484 e_int_en = e_int_en + pcm%v_e(ik)*pcm%q_n(ik)
1485 if (pcm%localf)
then
1486 e_int_e_ext = e_int_e_ext + pcm%v_e(ik)*pcm%q_ext(ik)
1489 do ia = 1, ions%natoms
1491 dist = norm2(ions%pos(1:pcm_dim_space, ia) - pcm%tess(ik)%point)
1493 z_ia = -ions%charge(ia)
1495 e_int_ne = e_int_ne + z_ia*pcm%q_e(ik) / dist
1496 e_int_nn = e_int_nn + z_ia*pcm%q_n(ik) / dist
1497 if (pcm%localf) e_int_n_ext = e_int_n_ext + z_ia*pcm%q_ext(ik) / dist
1502 e_int_ee =
m_half*e_int_ee
1503 e_int_en =
m_half*e_int_en
1504 e_int_ne =
m_half*e_int_ne
1505 e_int_nn =
m_half*e_int_nn
1510 if (pcm%localf)
then
1511 write(pcm%info_unit, &
1512 '(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)') &
1527 write(pcm%info_unit, &
1528 '(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)') &
1550 subroutine pcm_charges(q_pcm, q_pcm_tot, v_cav, pcm_mat, n_tess, qtot_nominal, epsilon, renorm_charges, q_tot_tol, deltaQ)
1551 real(real64),
intent(out) :: q_pcm(:)
1552 real(real64),
intent(out) :: q_pcm_tot
1553 real(real64),
intent(in) :: v_cav(:)
1554 real(real64),
intent(in) :: pcm_mat(:,:)
1555 integer,
intent(in) :: n_tess
1556 real(real64),
optional,
intent(in) :: qtot_nominal
1557 real(real64),
optional,
intent(in) :: epsilon
1558 logical,
optional,
intent(in) :: renorm_charges
1559 real(real64),
optional,
intent(in) :: q_tot_tol
1560 real(real64),
optional,
intent(out) :: deltaq
1563 real(real64) :: q_pcm_tot_norm
1564 real(real64) :: coeff
1574 q_pcm(ia) = q_pcm(ia) + pcm_mat(ia,ib)*v_cav(ib)
1576 q_pcm_tot = q_pcm_tot + q_pcm(ia)
1579 if (
present(qtot_nominal) .and.
present(epsilon) .and. &
1580 present(renorm_charges) .and.
present(q_tot_tol) .and.
present(deltaq))
then
1582 deltaq = abs(q_pcm_tot) - ((epsilon -
m_one)/epsilon) * abs(qtot_nominal)
1583 if ((renorm_charges) .and. (abs(deltaq) > q_tot_tol))
then
1585 coeff = sign(
m_one, qtot_nominal)*sign(
m_one, deltaq)
1587 q_pcm(ia) = q_pcm(ia) + coeff*q_pcm(ia)/q_pcm_tot*abs(deltaq)
1588 q_pcm_tot_norm = q_pcm_tot_norm + q_pcm(ia)
1590 q_pcm_tot = q_pcm_tot_norm
1601 type(
pcm_t),
intent(in) :: pcm
1602 class(
mesh_t),
intent(in) :: mesh
1604 integer :: ia, nm(pcm%space%dim), ipt, i1, i2, i3
1605 real(real64) :: posrel(pcm%space%dim)
1606 integer(int64) :: pt
1611 do ia = 1, pcm%n_tesserae
1613 posrel(:) = pcm%tess(ia)%point(1:pcm%space%dim)/mesh%spacing(1:pcm%space%dim)
1615 nm(:) =
floor(posrel(:))
1619 do i1 = -pcm%tess_nn + 1 , pcm%tess_nn
1620 do i2 = -pcm%tess_nn + 1 , pcm%tess_nn
1621 do i3 = -pcm%tess_nn + 1 , pcm%tess_nn
1625 if (pt <= 0 .or. pt > mesh%np_part_global)
then
1642 type(
pcm_t),
intent(in) :: pcm
1648 message(1) =
'The simulation box is too small to contain all the requested'
1649 message(2) =
'nearest neighbors for each tessera.'
1650 message(3) =
'Consider using a larger box or reduce PCMChargeSmearNN.'
1661 type(
pcm_t),
intent(inout) :: pcm
1662 real(real64),
intent(in) :: q_pcm(:)
1663 real(real64),
intent(in) :: q_pcm_tot
1664 type(
mesh_t),
intent(in) :: mesh
1665 real(real64),
intent(out) :: rho(:)
1668 real(real64) :: norm, qtot, rr, xx(pcm%space%dim), pp(pcm%space%dim)
1671 integer :: nm(pcm%space%dim)
1672 real(real64) :: posrel(pcm%space%dim)
1674 integer :: i1, i2, i3
1675 integer,
allocatable :: pt(:)
1676 real(real64),
allocatable :: lrho(:)
1677 logical :: inner_point, boundary_point
1685 npt = (2*pcm%tess_nn)**pcm%space%dim
1686 safe_allocate(pt(1:npt))
1687 safe_allocate(lrho(1:npt))
1692 do ia = 1, pcm%n_tesserae
1694 pp(:) = pcm%tess(ia)%point(1:pcm%space%dim)
1695 posrel(:) = pp(:)/mesh%spacing(1:pcm%space%dim)
1697 nm(:) =
floor(posrel(:))
1701 do i1 = -pcm%tess_nn + 1 , pcm%tess_nn
1702 do i2 = -pcm%tess_nn + 1 , pcm%tess_nn
1703 do i3 = -pcm%tess_nn + 1 , pcm%tess_nn
1719 if (pt(ipt) > 0 .and. pt(ipt) <= mesh%np_part)
then
1721 if (mesh%parallel_in_domains)
then
1722 boundary_point = pt(ipt) > mesh%np + mesh%pv%np_ghost
1723 inner_point = pt(ipt) > 0 .and. pt(ipt) <= mesh%np
1725 if (boundary_point .or. inner_point)
then
1726 xx(:) = mesh%x(pt(ipt),:)
1732 xx(:) = mesh%x(pt(ipt), :)
1735 rr = sum((xx(1:pcm%space%dim) - pp(1:pcm%space%dim))**2)
1736 norm = norm +
exp(-rr/(pcm%tess(ia)%area*pcm%gaussian_width))
1737 lrho(ipt) = lrho(ipt) +
exp(-rr/(pcm%tess(ia)%area*pcm%gaussian_width))
1743 call mesh%allreduce(lrho, npt)
1746 norm = sum(lrho(1:npt)) * mesh%volume_element
1748 norm = q_pcm(ia)/norm
1752 lrho(:) = lrho(:) * norm
1757 if (pt(ipt) > 0 .and. pt(ipt) <= mesh%np_part_global)
then
1759 if (mesh%parallel_in_domains)
then
1760 boundary_point = pt(ipt) > mesh%np + mesh%pv%np_ghost
1761 inner_point = pt(ipt) > 0 .and. pt(ipt) <= mesh%np
1762 if (boundary_point .or. inner_point) rho(pt(ipt)) = rho(pt(ipt)) + lrho(ipt)
1764 rho(pt(ipt)) = rho(pt(ipt)) + lrho(ipt)
1772 if (
debug%info)
then
1786 safe_deallocate_a(pt)
1787 safe_deallocate_a(lrho)
1797 subroutine pcm_pot_rs(pcm, v_pcm, q_pcm, rho, mesh, psolver)
1798 type(
pcm_t),
intent(inout) :: pcm
1799 real(real64),
contiguous,
intent(inout) :: v_pcm(:)
1800 real(real64),
contiguous,
intent(in) :: q_pcm(:)
1801 real(real64),
contiguous,
intent(inout) :: rho(:)
1802 type(
mesh_t),
intent(in) :: mesh
1812 select case (pcm%calc_method)
1813 case (pcm_calc_direct)
1814 call pcm_pot_rs_direct(v_pcm, q_pcm, pcm%tess, pcm%n_tesserae, mesh, pcm%gaussian_width)
1825 if (
debug%info)
then
1840 real(real64),
contiguous,
intent(inout) :: v_pcm(:)
1842 real(real64),
contiguous,
intent(inout) :: rho(:)
1855 real(real64),
intent(out) :: v_pcm(:)
1856 real(real64),
intent(in) :: q_pcm(:)
1857 real(real64),
intent(in) :: width_factor
1858 integer,
intent(in) :: n_tess
1859 type(
mesh_t),
intent(in) :: mesh
1862 real(real64),
parameter :: p_1 = 0.119763_real64
1863 real(real64),
parameter :: p_2 = 0.205117_real64
1864 real(real64),
parameter :: q_1 = 0.137546_real64
1865 real(real64),
parameter :: q_2 = 0.434344_real64
1867 real(real64) :: term
1880 call mesh_r(mesh, ip, term, origin=tess(ia)%point)
1881 arg = term/
sqrt(tess(ia)%area*width_factor)
1882 term = (
m_one + p_1*arg + p_2*arg**2) / (
m_one + q_1*arg + q_2*arg**2 + p_2*arg**3)
1883 v_pcm(ip) = v_pcm(ip) + q_pcm(ia) * term/
sqrt(tess(ia)%area*width_factor)
1894 call mesh_r(mesh, ip, term, origin=tess(ia)%point)
1895 v_pcm(ip) = v_pcm(ip) + q_pcm(ia)/term
1906 subroutine pcm_matrix(eps, tess, n_tess, pcm_mat, localf)
1907 real(real64),
intent(in) :: eps
1909 integer,
intent(in) :: n_tess
1910 real(real64),
intent(out) :: pcm_mat(:,:)
1911 logical,
optional,
intent(in) :: localf
1914 integer,
allocatable :: iwork(:)
1915 real(real64),
allocatable :: mat_tmp(:,:)
1917 real(real64) :: sgn_lf
1922 safe_allocate(s_mat_act(1:n_tess, 1:n_tess))
1926 safe_allocate(sigma(1:n_tess, 1:n_tess))
1927 sigma = s_mat_act/eps
1930 safe_allocate(d_mat_act(1:n_tess, 1:n_tess))
1934 safe_allocate(delta(1:n_tess, 1:n_tess))
1939 if (
present(localf))
then
1940 if (localf) sgn_lf = -
m_one
1944 pcm_mat = - sgn_lf * d_mat_act
1950 safe_deallocate_a(d_mat_act)
1952 safe_allocate(iwork(1:n_tess))
1957 call dgesv(n_tess, n_tess, s_mat_act, n_tess, iwork, pcm_mat, n_tess,
info)
1959 safe_deallocate_a(iwork)
1961 safe_deallocate_a(s_mat_act)
1965 pcm_mat = -matmul(sigma, pcm_mat)
1968 pcm_mat(i,i) = pcm_mat(i,i) +
m_two*
m_pi
1971 pcm_mat = pcm_mat - sgn_lf * delta
1973 safe_allocate(mat_tmp(1:n_tess,1:n_tess))
1976 safe_allocate(d_mat_act(1:n_tess,1:n_tess))
1979 mat_tmp = transpose(d_mat_act)
1981 mat_tmp = matmul(sigma, mat_tmp)
1985 safe_deallocate_a(d_mat_act)
1987 safe_allocate(s_mat_act(1:n_tess, 1:n_tess))
1990 mat_tmp = mat_tmp +
m_two*
m_pi*s_mat_act - matmul(delta, s_mat_act)
1992 safe_deallocate_a(s_mat_act)
1993 safe_deallocate_a(sigma)
1994 safe_deallocate_a(delta)
1996 safe_allocate(iwork(1:n_tess))
2000 call dgesv(n_tess, n_tess, mat_tmp, n_tess, iwork, pcm_mat, n_tess,
info)
2002 safe_deallocate_a(iwork)
2003 safe_deallocate_a(mat_tmp)
2005 pcm_mat = - sgn_lf * pcm_mat
2020 integer,
intent(in) :: n_tess
2030 if (ii /= jj) s_mat_act(jj,ii) = s_mat_act(ii,jj)
2039 integer,
intent(in) :: n_tess
2058 real(real64) function s_mat_elem_I(tessi, tessj)
2062 real(real64),
parameter :: M_SD_DIAG = 1.0694_real64
2063 real(real64),
parameter :: M_DIST_MIN = 0.1_real64
2065 real(real64) :: diff(1:PCM_DIM_SPACE)
2066 real(real64) :: dist
2067 real(real64) :: s_diag
2068 real(real64) :: s_off_diag
2073 diff = tessi%point - tessj%point
2079 s_mat_elem_i = s_diag
2081 if (dist > m_dist_min) s_off_diag =
m_one/dist
2082 s_mat_elem_i = s_off_diag
2090 real(real64) function d_mat_elem_I(tessi, tessj)
2091 type(pcm_tessera_t),
intent(in) :: tessi
2092 type(pcm_tessera_t),
intent(in) :: tessj
2094 real(real64),
parameter :: M_SD_DIAG = 1.0694_real64
2095 real(real64),
parameter :: M_DIST_MIN = 0.04_real64
2097 real(real64) :: diff(1:PCM_DIM_SPACE)
2098 real(real64) :: dist
2099 real(real64) :: d_diag
2100 real(real64) :: d_off_diag
2106 diff = tessi%point - tessj%point
2110 if (abs(dist) <= m_epsilon)
then
2112 d_diag = m_sd_diag*
sqrt(m_four*m_pi*tessi%area)
2113 d_diag = -d_diag/(m_two*tessi%r_sphere)
2118 if (dist > m_dist_min)
then
2119 d_off_diag = dot_product( diff, tessj%normal(:))
2120 d_off_diag = d_off_diag*tessj%area/dist**3
2134 subroutine cav_gen(tess_sphere, tess_min_distance, nesf, sfe, nts, cts, unit_pcminfo)
2135 integer,
intent(in) :: tess_sphere
2136 real(real64) ,
intent(in) :: tess_min_distance
2138 integer,
intent(in) :: nesf
2139 integer,
intent(out) :: nts
2140 type(pcm_tessera_t),
intent(out) :: cts(:)
2141 integer,
intent(in) :: unit_pcminfo
2143 integer,
parameter :: DIM_ANGLES = 24
2144 integer,
parameter :: DIM_TEN = 10
2145 integer,
parameter :: DIM_VERTICES = 122
2146 integer,
parameter :: MAX_VERTICES = 6
2147 integer,
parameter :: MXTS = 10000
2149 real(real64) :: thev(1:DIM_ANGLES)
2150 real(real64) :: fiv(1:DIM_ANGLES)
2171 integer :: isfet(1:dim_ten*dim_angles)
2189 real(real64) :: area
2190 real(real64) :: test2
2192 real(real64) :: dnorm
2202 real(real64) :: stot
2203 real(real64) :: prod
2206 logical :: band_iter
2212 data thev/ 0.6523581398_real64 , 1.107148718_real64 , 1.382085796_real64 , &
2213 1.759506858_real64 , 2.034443936_real64 , 2.489234514_real64 , &
2214 0.3261790699_real64 , 0.5535743589_real64, &
2215 0.8559571251_real64 , 0.8559571251_real64 , 1.017221968_real64 , &
2216 1.229116717_real64 , 1.229116717_real64 , 1.433327788_real64 , &
2217 1.570796327_real64 , 1.570796327_real64 , 1.708264866_real64 , &
2218 1.912475937_real64 , 1.912475937_real64 , 2.124370686_real64 , &
2219 2.285635528_real64 , 2.285635528_real64 , 2.588018295_real64 , &
2220 2.815413584_real64 /
2221 data fiv/ 0.6283185307_real64 , m_zero , &
2222 0.6283185307_real64 , m_zero , 0.6283185307_real64, &
2223 m_zero , 0.6283185307_real64 , m_zero, &
2224 0.2520539002_real64 , 1.004583161_real64 , 0.6283185307_real64, &
2225 0.3293628477_real64 , 0.9272742138_real64 , m_zero, &
2226 0.3141592654_real64 , 0.9424777961_real64 , 0.6283185307_real64, &
2227 0.2989556830_real64 , 0.9576813784_real64 , m_zero, &
2228 0.3762646305_real64 , 0.8803724309_real64 , 0.6283188307_real64, &
2230 data fir / 1.256637061_real64 /
2234 data (idum(ii),ii = 1, 280) / &
2235 1, 6, 2, 32, 36, 37, 1, 2, 3, 33, 32, 38, 1, 3, 4, 34, &
2236 33, 39, 1, 4, 5, 35, 34, 40, 1, 5, 6, 36, 35, 41, 7, 2, 6, 51, &
2237 42, 37, 8, 3, 2, 47, 43, 38, 9, 4, 3, 48, 44, 39, 10, 5, 4, &
2238 49, 45, 40, 11, 6, 5, 50, 46, 41, 8, 2, 12, 62, 47, 52, 9, &
2239 3, 13, 63, 48, 53, 10, 4, 14, 64, 49, 54, 11, 5, 15, 65, 50, &
2240 55, 7, 6, 16, 66, 51, 56, 7, 12, 2, 42, 57, 52, 8, 13, 3, &
2241 43, 58, 53, 9, 14, 4, 44, 59, 54, 10, 15, 5, 45, 60, 55, 11, &
2242 16, 6, 46, 61, 56, 8, 12, 18, 68, 62, 77, 9, 13, 19, 69, 63, &
2243 78, 10, 14, 20, 70, 64, 79, 11, 15, 21, 71, 65, 80, 7, 16, &
2244 17, 67, 66, 81, 7, 17, 12, 57, 67, 72, 8, 18, 13, 58, 68, 73, &
2245 9, 19, 14, 59, 69, 74, 10, 20, 15, 60, 70, 75, 11, 21, 16, &
2246 61, 71, 76, 22, 12, 17, 87, 82, 72, 23, 13, 18, 88, 83, 73, &
2247 24, 14, 19, 89, 84, 74, 25, 15, 20, 90, 85, 75, 26, 16, 21, &
2248 91, 86, 76, 22, 18, 12, 82, 92, 77, 23, 19, 13, 83, 93, 78, &
2249 24, 20, 14, 84, 94, 79, 25, 21, 15, 85, 95, 80, 26, 17, 16, &
2250 86, 96, 81, 22, 17, 27, 102, 87, 97, 23, 18, 28, 103, 88, 98, &
2251 24, 19, 29, 104, 89, 99, 25, 20, 30, 105, 90, 100, 26, 21, &
2252 31, 106, 91, 101, 22, 28, 18, 92, 107, 98, 23, 29, 19, 93 /
2253 data (idum(ii),ii = 281,360) / &
2254 108, 99, 24, 30, 20, 94, 109, 100, 25, 31, 21, 95, 110, 101, &
2255 26, 27, 17, 96, 111, 97, 22, 27, 28, 107, 102, 112, 23, 28, &
2256 29, 108, 103, 113, 24, 29, 30, 109, 104, 114, 25, 30, 31, &
2257 110, 105, 115, 26, 31, 27, 111, 106, 116, 122, 28, 27, 117, &
2258 118, 112, 122, 29, 28, 118, 119, 113, 122, 30, 29, 119, 120, &
2259 114, 122, 31, 30, 120, 121, 115, 122, 27, 31, 121, 117, 116 /
2261 if (mpi_grp_is_root(mpi_world))
then
2262 if (tess_sphere == 1)
then
2263 write(unit_pcminfo,
'(A1)')
'#'
2264 write(unit_pcminfo,
'(A34)')
'# Number of tesserae / sphere = 60'
2265 write(unit_pcminfo,
'(A1)')
'#'
2267 write(unit_pcminfo,
'(A1)')
'#'
2268 write(unit_pcminfo,
'(A35)')
'# Number of tesserae / sphere = 240'
2269 write(unit_pcminfo,
'(A1)')
'#'
2278 sfe(:)%x = sfe(:)%x*p_a_b
2279 sfe(:)%y = sfe(:)%y*p_a_b
2280 sfe(:)%z = sfe(:)%z*p_a_b
2281 sfe(:)%r = sfe(:)%r*p_a_b
2285 jvt1 = reshape(idum,(/6,60/))
2308 do ia = 1, dim_angles
2315 if (ja == 1) fi = fiv(ia)
2317 cv(ii,1) = sth*
cos(fi)
2318 cv(ii,2) = sth*
sin(fi)
2337 do i_tes = 1, tess_sphere
2338 if (tess_sphere == 1)
then
2343 if (i_tes == 1)
then
2347 elseif (i_tes == 2)
then
2351 elseif (i_tes == 3)
then
2355 elseif (i_tes == 4)
then
2362 pts(1,1) = cv(n1,1)*ren + xen
2363 pts(2,1) = cv(n1,3)*ren + yen
2364 pts(3,1) = cv(n1,2)*ren + zen
2366 pts(1,2) = cv(n2,1)*ren + xen
2367 pts(2,2) = cv(n2,3)*ren + yen
2368 pts(3,2) = cv(n2,2)*ren + zen
2370 pts(1,3) = cv(n3,1)*ren + xen
2371 pts(2,3) = cv(n3,3)*ren + yen
2372 pts(3,3) = cv(n3,2)*ren + zen
2378 call subtessera(sfe, nsfe, nesf, nv, pts ,ccc, pp, pp1, area)
2380 if (abs(area) <= m_epsilon) cycle
2382 xctst(tess_sphere*(its-1) + i_tes) = pp(1)
2383 yctst(tess_sphere*(its-1) + i_tes) = pp(2)
2384 zctst(tess_sphere*(its-1) + i_tes) = pp(3)
2385 nctst(:,tess_sphere*(its-1) + i_tes) = pp1(:)
2386 ast(tess_sphere*(its-1) + i_tes) = area
2387 isfet(tess_sphere*(its-1) + i_tes) = nsfe
2394 if (abs(ast(its)) <= m_epsilon) cycle
2398 write(message(1),
'(a,I5,a,I5)')
"total number of tesserae", nn,
">",mxts
2399 call messages_warning(1)
2402 cts(nn)%point(1) = xctst(its)
2403 cts(nn)%point(2) = yctst(its)
2404 cts(nn)%point(3) = zctst(its)
2405 cts(nn)%normal(:) = nctst(:,its)
2406 cts(nn)%area = ast(its)
2407 cts(nn)%r_sphere = sfe(isfet(its))%r
2415 test2 = tess_min_distance*tess_min_distance
2418 do while (.not.(band_iter))
2421 loop_ia:
do ia = 1, nts-1
2422 if (abs(cts(ia)%area) <= m_epsilon) cycle
2423 xi = cts(ia)%point(1)
2424 yi = cts(ia)%point(2)
2425 zi = cts(ia)%point(3)
2427 loop_ja:
do ja = ia+1, nts
2428 if (abs(cts(ja)%area) <= m_epsilon) cycle
2429 xj = cts(ja)%point(1)
2430 yj = cts(ja)%point(2)
2431 zj = cts(ja)%point(3)
2433 rij = (xi - xj)**2 + (yi - yj)**2 + (zi - zj)**2
2435 if (rij > test2) cycle
2437 if (mpi_grp_is_root(mpi_world))
then
2438 write(unit_pcminfo,
'(A40,I4,A5,I4,A4,F8.4,A13,F8.4,A3)') &
2439 '# Warning: The distance between tesserae', &
2440 ia,
' and ', ja,
' is ',
sqrt(rij),
' A, less than', tess_min_distance,
' A.'
2444 xi = (xi*cts(ia)%area + xj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2445 yi = (yi*cts(ia)%area + yj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2446 zi = (zi*cts(ia)%area + zj*cts(ja)%area) / (cts(ia)%area + cts(ja)%area)
2448 cts(ia)%point(1) = xi
2449 cts(ia)%point(2) = yi
2450 cts(ia)%point(3) = zi
2453 cts(ia)%normal = (cts(ia)%normal*cts(ia)%area + cts(ja)%normal*cts(ja)%area)
2454 dnorm = norm2(cts(ia)%normal)
2455 cts(ia)%normal = cts(ia)%normal/dnorm
2458 cts(ia)%r_sphere = (cts(ia)%r_sphere*cts(ia)%area + cts(ja)%r_sphere*cts(ja)%area) / &
2459 (cts(ia)%area + cts(ja)%area)
2462 cts(ia)%area = cts(ia)%area + cts(ja)%area
2479 prod = dot_product(cts(its)%point, cts(its)%normal)
2480 vol = vol + cts(its)%area * prod / m_three
2481 stot = stot + cts(its)%area
2484 if (mpi_grp_is_root(mpi_world))
then
2485 write(unit_pcminfo,
'(A2)')
'# '
2486 write(unit_pcminfo,
'(A29,I4)')
'# Total number of tesserae = ' , nts
2487 write(unit_pcminfo,
'(A30,F12.6)')
'# Cavity surface area (A^2) = ', stot
2488 write(unit_pcminfo,
'(A24,F12.6)')
'# Cavity volume (A^3) = ' , vol
2489 write(unit_pcminfo,
'(A2)')
'# '
2493 cts(:)%area = cts(:)%area*p_ang*p_ang
2494 cts(:)%point(1) = cts(:)%point(1)*p_ang
2495 cts(:)%point(2) = cts(:)%point(2)*p_ang
2496 cts(:)%point(3) = cts(:)%point(3)*p_ang
2497 cts(:)%r_sphere = cts(:)%r_sphere*p_ang
2499 sfe(:)%x=sfe(:)%x*p_ang
2500 sfe(:)%y=sfe(:)%y*p_ang
2501 sfe(:)%z=sfe(:)%z*p_ang
2502 sfe(:)%r=sfe(:)%r*p_ang
2511 subroutine subtessera(sfe, ns, nesf, nv, pts, ccc, pp, pp1, area)
2513 integer,
intent(in) :: ns
2514 integer,
intent(in) :: nesf
2515 integer,
intent(inout) :: nv
2516 real(real64),
intent(inout) :: pts(:,:)
2517 real(real64),
intent(out) :: ccc(:,:)
2518 real(real64),
intent(out) :: pp(:)
2519 real(real64),
intent(out) :: pp1(:)
2520 real(real64),
intent(out) :: area
2522 real(real64),
parameter :: TOL = -1.0e-10_real64
2523 integer,
parameter :: DIM_TEN = 10
2525 integer :: intsph(1:DIM_TEN)
2536 real(real64) :: p1(1:PCM_DIM_SPACE)
2537 real(real64) :: p2(1:PCM_DIM_SPACE)
2538 real(real64) :: p3(1:PCM_DIM_SPACE)
2539 real(real64) :: p4(1:PCM_DIM_SPACE)
2540 real(real64) :: point(1:PCM_DIM_SPACE)
2541 real(real64) :: pscr(1:PCM_DIM_SPACE,1:DIM_TEN)
2542 real(real64) :: cccp(1:PCM_DIM_SPACE,1:DIM_TEN)
2543 real(real64) :: pointl(1:PCM_DIM_SPACE,1:DIM_TEN)
2544 real(real64) :: diff(1:PCM_DIM_SPACE)
2546 integer :: ind(1:DIM_TEN)
2547 integer :: ltyp(1:DIM_TEN)
2548 integer :: intscr(1:DIM_TEN)
2550 real(real64) :: delr
2551 real(real64) :: delr2
2554 real(real64) :: dnorm
2555 real(real64) :: dist
2572 ccc(1,jj) = sfe(ns)%x
2573 ccc(2,jj) = sfe(ns)%y
2574 ccc(3,jj) = sfe(ns)%z
2579 if (nsfe1 == ns) cycle
2581 intscr(jj) = intsph(jj)
2582 pscr(:,jj) = pts(:,jj)
2583 cccp(:,jj) = ccc(:,jj)
2591 delr2 = (pts(1,ii) - sfe(nsfe1)%x)**2 + (pts(2,ii) - sfe(nsfe1)%y)**2 + (pts(3,ii) - sfe(nsfe1)%z)**2
2593 if (delr < sfe(nsfe1)%r)
then
2599 if (icop == nv)
then
2607 if (ll == nv) iv2 = 1
2608 if ((ind(iv1) == 1) .and. (ind(iv2) == 1))
then
2610 else if ((ind(iv1) == 0) .and. (ind(iv2) == 1))
then
2612 else if ((ind(iv1) == 1) .and. (ind(iv2) == 0))
then
2614 else if ((ind(iv1) == 0) .and. (ind(iv2) == 0))
then
2616 diff = ccc(:,ll) - pts(:,ll)
2617 rc2 = dot_product(diff, diff)
2621 point = pts(:,iv1) + ii * (pts(:,iv2) - pts(:,iv1)) / 11
2622 point = point - ccc(:,ll)
2623 dnorm = norm2(point)
2624 point = point * rc / dnorm + ccc(:,ll)
2626 dist =
sqrt((point(1) - sfe(nsfe1)%x)**2 + (point(2) - sfe(nsfe1)%y)**2 + (point(3) - sfe(nsfe1)%z)**2)
2628 if ((dist - sfe(nsfe1)%r) < tol)
then
2630 pointl(:, ll) = point
2640 if ((ltyp(ll) == 1) .or. (ltyp(ll) == 2)) icut = icut + 1
2641 if (ltyp(ll) == 3) icut = icut + 2
2652 if (ltyp(ll) == 0) cycle
2655 if (ll == nv) iv2 = 1
2657 if (ltyp(ll) == 1)
then
2658 pts(:,na) = pscr(:,iv1)
2659 ccc(:,na) = cccp(:,iv1)
2660 intsph(na) = intscr(iv1)
2666 call inter(sfe, p1, p2, p3, p4, nsfe1, 0)
2669 de2 = (sfe(nsfe1)%x - sfe(ns)%x)**2 + ( sfe(nsfe1)%y - sfe(ns)%y)**2 + &
2670 (sfe(nsfe1)%z - sfe(ns)%z)**2
2672 ccc(1,na) = sfe(ns)%x + ( sfe(nsfe1)%x - sfe(ns)%x)* &
2673 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2675 ccc(2,na) = sfe(ns)%y + ( sfe(nsfe1)%y - sfe(ns)%y)* &
2676 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2678 ccc(3,na) = sfe(ns)%z + ( sfe(nsfe1)%z - sfe(ns)%z)* &
2679 (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2685 if (ltyp(ll) == 2)
then
2690 call inter(sfe, p1, p2, p3, p4, nsfe1, 1)
2692 ccc(:,na) = cccp(:,iv1)
2693 intsph(na) = intscr(iv1)
2697 if (ltyp(ll) == 3)
then
2698 pts(:,na) = pscr(:,iv1)
2699 ccc(:,na) = cccp(:,iv1)
2700 intsph(na) = intscr(iv1)
2706 call inter(sfe, p1, p2, p3, p4, nsfe1, 0)
2709 de2 = (sfe(nsfe1)%x - sfe(ns)%x)**2 + (sfe(nsfe1)%y - sfe(ns)%y)**2 + (sfe(nsfe1)%z - sfe(ns)%z)**2
2711 ccc(1,na) = sfe(ns)%x + (sfe(nsfe1)%x - sfe(ns)%x) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2713 ccc(2,na) = sfe(ns)%y + (sfe(nsfe1)%y - sfe(ns)%y) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2715 ccc(3,na) = sfe(ns)%z + (sfe(nsfe1)%z - sfe(ns)%z) * (sfe(ns)%r**2 - sfe(nsfe1)%r**2 + de2) / (m_two*de2)
2723 call inter(sfe, p1, p2, p3, p4, nsfe1, 1)
2725 ccc(:,na) = cccp(:,iv1)
2726 intsph(na) = intscr(iv1)
2730 if (ltyp(ll) == 4)
then
2731 pts(:,na) = pscr(:,iv1)
2732 ccc(:,na) = cccp(:,iv1)
2733 intsph(na) = intscr(iv1)
2740 message(1) =
"Too many vertices on the tessera"
2741 call messages_fatal(1)
2745 call gaubon(sfe, nv, ns, pts, ccc, pp, pp1, area, intsph)
2755 subroutine inter(sfe, p1, p2, p3, p4, ns, ia)
2757 real(real64),
intent(in) :: p1(1:PCM_DIM_SPACE)
2758 real(real64),
intent(in) :: p2(1:PCM_DIM_SPACE)
2759 real(real64),
intent(in) :: p3(1:PCM_DIM_SPACE)
2760 real(real64),
intent(out) :: p4(1:PCM_DIM_SPACE)
2761 integer,
intent(in) :: ns
2762 integer,
intent(in) :: ia
2764 real(real64),
parameter :: TOL = 1.0e-08_real64
2768 real(real64) :: alpha
2769 real(real64) :: delta
2770 real(real64) :: dnorm
2771 real(real64) :: diff
2772 real(real64) :: diff_vec(1:PCM_DIM_SPACE)
2773 logical :: band_iter
2785 do while(.not.(band_iter))
2786 if (m_iter > 1000)
then
2787 message(1) =
"Too many iterations inside subrotuine inter"
2788 call messages_fatal(1)
2793 alpha = alpha + delta
2795 p4 = p1 + alpha*(p2 - p1) - p3
2797 p4 = p4*r/dnorm + p3
2798 diff = (p4(1) - sfe(ns)%x)**2 + (p4(2) - sfe(ns)%y)**2 + (p4(3) - sfe(ns)%z)**2
2799 diff =
sqrt(diff) - sfe(ns)%r
2801 if (abs(diff) < tol)
then
2807 if (diff > m_zero) delta = m_one/(m_two**(m_iter + 1))
2808 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))
2815 if (diff < m_zero) delta = m_one/(m_two**(m_iter + 1))
2822 end subroutine inter
2832 subroutine gaubon(sfe, nv, ns, pts, ccc, pp, pp1, area, intsph)
2834 real(real64),
intent(in) :: pts(:,:)
2835 real(real64),
intent(in) :: ccc(:,:)
2836 real(real64),
intent(inout) :: pp(:)
2837 real(real64),
intent(inout) :: pp1(:)
2838 integer,
intent(in) :: intsph(:)
2839 real(real64),
intent(out) :: area
2840 integer,
intent(in) :: nv
2841 integer,
intent(in) :: ns
2843 real(real64) :: p1(1:PCM_DIM_SPACE), p2(1:PCM_DIM_SPACE), p3(1:PCM_DIM_SPACE)
2844 real(real64) :: u1(1:PCM_DIM_SPACE), u2(1:PCM_DIM_SPACE)
2845 real(real64) :: point_1(1:PCM_DIM_SPACE), point_2(1:PCM_DIM_SPACE)
2846 real(real64) :: tpi, sum1, dnorm, dnorm1, dnorm2
2847 real(real64) :: cosphin, phin, costn, sum2, betan
2848 integer :: nsfe1, ia, nn, n0, n1, n2
2863 point_1 = pts(:,nn) - ccc(:,nn)
2865 point_2 = pts(:,nn+1) - ccc(:,nn)
2867 point_2 = pts(:,1) - ccc(:,nn)
2870 dnorm1 = norm2(point_1)
2871 dnorm2 = norm2(point_2)
2872 cosphin = dot_product(point_1, point_2) / (dnorm1*dnorm2)
2874 if (cosphin > m_one) cosphin = m_one
2875 if (cosphin < -m_one) cosphin = -m_one
2877 phin =
acos(cosphin)
2880 point_1(1) = sfe(nsfe1)%x - sfe(ns)%x
2881 point_1(2) = sfe(nsfe1)%y - sfe(ns)%y
2882 point_1(3) = sfe(nsfe1)%z - sfe(ns)%z
2884 dnorm1 = norm2(point_1)
2886 if (abs(dnorm1) <= m_epsilon) dnorm1 = m_one
2888 point_2(1) = pts(1,nn) - sfe(ns)%x
2889 point_2(2) = pts(2,nn) - sfe(ns)%y
2890 point_2(3) = pts(3,nn) - sfe(ns)%z
2892 dnorm2 = norm2(point_2)
2894 costn = dot_product(point_1, point_2) / (dnorm1 * dnorm2)
2895 sum1 = sum1 + phin * costn
2906 if (nn > 1) n0 = nn - 1
2907 if (nn == 1) n0 = nv
2908 if (nn < nv) n2 = nn + 1
2909 if (nn == nv) n2 = 1
2911 p1 = pts(:,n1) - ccc(:,n0)
2912 p2 = pts(:,n0) - ccc(:,n0)
2913 call vecp(p1, p2, p3, dnorm)
2916 call vecp(p1, p2, p3, dnorm)
2919 p1 = pts(:,n1) - ccc(:,n1)
2920 p2 = pts(:,n2) - ccc(:,n1)
2921 call vecp(p1, p2, p3, dnorm)
2924 call vecp(p1, p2, p3, dnorm)
2927 betan =
acos(dot_product(u1, u2))
2928 sum2 = sum2 + (m_pi - betan)
2932 area = sfe(ns)%r*sfe(ns)%r*(tpi + sum1 - sum2)
2938 pp(1) = pp(1) + (pts(1,ia) - sfe(ns)%x)
2939 pp(2) = pp(2) + (pts(2,ia) - sfe(ns)%y)
2940 pp(3) = pp(3) + (pts(3,ia) - sfe(ns)%z)
2945 pp(1) = sfe(ns)%x + pp(1) * sfe(ns)%r / dnorm
2946 pp(2) = sfe(ns)%y + pp(2) * sfe(ns)%r / dnorm
2947 pp(3) = sfe(ns)%z + pp(3) * sfe(ns)%r / dnorm
2950 pp1(1) = (pp(1) - sfe(ns)%x) / sfe(ns)%r
2951 pp1(2) = (pp(2) - sfe(ns)%y) / sfe(ns)%r
2952 pp1(3) = (pp(3) - sfe(ns)%z) / sfe(ns)%r
2955 if (area < m_zero) area = m_zero
2963 subroutine vecp(p1, p2, p3, dnorm)
2964 real(real64),
intent(in) :: P1(:)
2965 real(real64),
intent(in) :: P2(:)
2966 real(real64),
intent(out) :: P3(:)
2967 real(real64),
intent(out) :: dnorm
2970 p3(1) = p1(2)*p2(3) - p1(3)*p2(2)
2971 p3(2) = p1(3)*p2(1) - p1(1)*p2(3)
2972 p3(3) = p1(1)*p2(2) - p1(2)*p2(1)
2979 type(
pcm_t),
intent(inout) :: pcm
2981 integer :: asc_unit_test, asc_unit_test_sol, asc_unit_test_e, asc_unit_test_n, asc_unit_test_ext
2986 if (pcm%solute .and. pcm%localf)
then
2987 asc_unit_test = io_open(pcm_dir//
'ASC.dat', pcm%namespace, action=
'write')
2988 asc_unit_test_sol = io_open(pcm_dir//
'ASC_sol.dat', pcm%namespace, action=
'write')
2989 asc_unit_test_e = io_open(pcm_dir//
'ASC_e.dat', pcm%namespace, action=
'write')
2990 asc_unit_test_n = io_open(pcm_dir//
'ASC_n.dat', pcm%namespace, action=
'write')
2991 asc_unit_test_ext = io_open(pcm_dir//
'ASC_ext.dat', pcm%namespace, action=
'write')
2992 do ia = 1, pcm%n_tesserae
2993 write(asc_unit_test,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia) + pcm%q_ext(ia), ia
2994 write(asc_unit_test_sol,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia), ia
2995 write(asc_unit_test_e,*) pcm%tess(ia)%point, pcm%q_e(ia), ia
2996 write(asc_unit_test_n,*) pcm%tess(ia)%point, pcm%q_n(ia), ia
2997 write(asc_unit_test_ext,*) pcm%tess(ia)%point, pcm%q_ext(ia), ia
2999 call io_close(asc_unit_test)
3000 call io_close(asc_unit_test_sol)
3001 call io_close(asc_unit_test_e)
3002 call io_close(asc_unit_test_n)
3003 call io_close(asc_unit_test_ext)
3005 else if (pcm%solute .and. .not. pcm%localf)
then
3006 asc_unit_test_sol = io_open(pcm_dir//
'ASC_sol.dat', pcm%namespace, action=
'write')
3007 asc_unit_test_e = io_open(pcm_dir//
'ASC_e.dat', pcm%namespace, action=
'write')
3008 asc_unit_test_n = io_open(pcm_dir//
'ASC_n.dat', pcm%namespace, action=
'write')
3009 do ia = 1, pcm%n_tesserae
3010 write(asc_unit_test_sol,*) pcm%tess(ia)%point, pcm%q_e(ia) + pcm%q_n(ia), ia
3011 write(asc_unit_test_e,*) pcm%tess(ia)%point, pcm%q_e(ia), ia
3012 write(asc_unit_test_n,*) pcm%tess(ia)%point, pcm%q_n(ia), ia
3014 call io_close(asc_unit_test_sol)
3015 call io_close(asc_unit_test_e)
3016 call io_close(asc_unit_test_n)
3018 else if (.not. pcm%solute .and. pcm%localf)
then
3019 asc_unit_test_ext = io_open(pcm_dir//
'ASC_ext.dat', pcm%namespace, action=
'write')
3020 do ia = 1, pcm%n_tesserae
3021 write(asc_unit_test_ext,*) pcm%tess(ia)%point, pcm%q_ext(ia), ia
3023 call io_close(asc_unit_test_ext)
3026 safe_deallocate_a(pcm%spheres)
3027 safe_deallocate_a(pcm%tess)
3028 safe_deallocate_a(pcm%matrix)
3029 if (.not. is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
3030 safe_deallocate_a(pcm%matrix_d)
3032 safe_deallocate_a(pcm%q_e)
3033 safe_deallocate_a(pcm%q_e_in)
3034 safe_deallocate_a(pcm%q_n)
3035 safe_deallocate_a(pcm%v_e)
3036 safe_deallocate_a(pcm%v_n)
3037 safe_deallocate_a(pcm%v_e_rs)
3038 safe_deallocate_a(pcm%v_n_rs)
3039 if (pcm%localf)
then
3040 safe_deallocate_a(pcm%matrix_lf)
3041 if (.not. is_close(pcm%epsilon_infty, pcm%epsilon_0))
then
3042 safe_deallocate_a(pcm%matrix_lf_d)
3045 safe_deallocate_a(pcm%q_ext)
3046 safe_deallocate_a(pcm%q_ext_in)
3047 safe_deallocate_a(pcm%v_ext)
3048 safe_deallocate_a(pcm%v_ext_rs)
3049 if (pcm%kick_is_present)
then
3050 safe_deallocate_a(pcm%q_kick)
3051 safe_deallocate_a(pcm%v_kick)
3052 safe_deallocate_a(pcm%v_kick_rs)
3057 safe_deallocate_a( pcm%rho_n)
3058 safe_deallocate_a( pcm%rho_e)
3059 if (pcm%localf)
then
3060 safe_deallocate_a( pcm%rho_ext)
3061 if (pcm%kick_is_present)
then
3062 safe_deallocate_a( pcm%rho_kick)
3067 if (pcm%tdlevel ==
pcm_td_eom)
call pcm_eom_end()
3069 if (mpi_grp_is_root(mpi_world))
call io_close(pcm%info_unit)
3076 logical function pcm_update(this)
result(update)
3077 type(
pcm_t),
intent(inout) :: this
3079 this%iter = this%iter + 1
3080 update = this%iter <= 6 .or. mod(this%iter, this%update_iter) == 0
3086 real(real64) function
pcm_get_vdw_radius(species, pcm_vdw_type, namespace) result(vdw_r)
3087 class(species_t),
intent(in) :: species
3088 integer,
intent(in) :: pcm_vdw_type
3089 type(namespace_t),
intent(in) :: namespace
3092 integer,
parameter :: upto_xe = 54
3093 real(real64) :: vdw_radii(1:upto_xe)
3096 data (vdw_radii(ia), ia=1, upto_xe) / &
3098 1.001_real64, 1.012_real64, &
3100 0.825_real64, 1.408_real64, 1.485_real64, 2.000_real64, 1.583_real64, 1.500_real64, 1.287_real64, 1.243_real64, &
3102 1.144_real64, 1.364_real64, 1.639_real64, 1.716_real64, 1.705_real64, 1.683_real64, 1.639_real64, 1.595_real64, &
3104 1.485_real64, 1.474_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, &
3110 1.562_real64, 1.562_real64, &
3112 1.650_real64, 1.727_real64, 1.760_real64, 1.771_real64, 1.749_real64, 1.727_real64, &
3114 1.628_real64, 1.606_real64, 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, &
3118 1.639_real64, 1.639_real64, &
3120 2.672_real64, 1.804_real64, 1.881_real64, 1.892_real64, 1.892_real64, 1.881_real64 /
3122 select case (pcm_vdw_type)
3124 if (species%get_z() > upto_xe)
then
3125 write(message(1),
'(a,a)')
"The van der Waals radius is missing for element ", trim(species%get_label())
3126 write(message(2),
'(a)')
"Use PCMVdWRadii = pcm_vdw_species, for other vdw radii values"
3127 call messages_fatal(2, namespace=namespace)
3129 ia = int(species%get_z())
3130 vdw_r = vdw_radii(ia)*p_ang
3133 vdw_r = species%get_vdw_radius()
3134 if (vdw_r < m_zero)
then
3135 call messages_write(
'The default vdW radius for species '//trim(species%get_label())//
':')
3136 call messages_write(
' is not defined. ')
3137 call messages_write(
' Add a positive vdW radius value in %Species block. ')
3138 call messages_fatal(namespace=namespace)
3147 subroutine pcm_dipole(mu_pcm, q_pcm, tess, n_tess)
3148 real(real64),
intent(out) :: mu_pcm(:)
3149 real(real64),
intent(in) :: q_pcm(:)
3150 integer,
intent(in) :: n_tess
3151 type(pcm_tessera_t),
intent(in) :: tess(:)
3159 mu_pcm = mu_pcm + q_pcm(ia) * tess(ia)%point
3167 subroutine pcm_field(e_pcm, q_pcm, ref_point, tess, n_tess)
3168 real(real64),
intent(out) :: e_pcm(:)
3169 real(real64),
intent(in) :: q_pcm(:)
3170 integer,
intent(in) :: n_tess
3171 type(pcm_tessera_t),
intent(in) :: tess(:)
3172 real(real64),
intent(in) :: ref_point(1:3)
3174 real(real64) :: diff(1:3)
3175 real(real64) :: dist
3183 diff = ref_point - tess(ia)%point
3185 e_pcm = e_pcm + q_pcm(ia) * diff / dist**3
3193 subroutine pcm_eps(pcm, eps, omega)
3195 complex(real64),
intent(out) :: eps
3196 real(real64),
intent(in) :: omega
3201 if (pcm%which_eps == pcm_debye_model)
then
3203 else if (pcm%which_eps == pcm_drude_model)
then
3219 type(namespace_t),
intent(in) :: namespace
3224 call parse_variable(namespace,
'PCMCalculation', .false., pcm%run_pcm)
3225 call messages_print_with_emphasis(msg=
'PCM', namespace=namespace)
3226 call parse_variable(namespace,
'PCMLocalField', .false., pcm%localf)
3227 call messages_print_var_value(
"PCMLocalField", pcm%localf, namespace=namespace)
3228 if (pcm%localf)
then
3229 call messages_experimental(
"PCM local field effects in the optical spectrum", namespace=namespace)
3230 call messages_write(
'Beware of possible numerical errors in the optical spectrum due to PCM local field effects,')
3231 call messages_new_line()
3232 call messages_write(
'particularly, when static and high-frequency values of the dielectric functions are large')
3233 call messages_write(
' (>~10 in units of the vacuum permittivity \epsilon_0).')
3234 call messages_new_line()
3235 call messages_write(
'However, PCM local field effects in the optical spectrum work well for polar or non-polar solvents')
3236 call messages_new_line()
3237 call messages_write(
'in the nonequilibrium or equation-of-motion TD-PCM propagation schemes.')
3238 call messages_warning(namespace=namespace)
3240 call parse_variable(namespace,
'PCMTDLevel' ,
pcm_td_eq, pcm%tdlevel)
3241 call messages_print_var_value(
"PCMTDLevel", pcm%tdlevel, namespace=namespace)
3244 call parse_variable(namespace,
'PCMStaticEpsilon' , m_one, pcm%deb%eps_0)
3245 call messages_print_var_value(
"PCMStaticEpsilon", pcm%deb%eps_0, namespace=namespace)
3247 call parse_variable(namespace,
'PCMEpsilonModel', pcm_debye_model, pcm%which_eps)
3248 call messages_print_var_value(
"PCMEpsilonModel", pcm%which_eps, namespace=namespace)
3249 if (pcm%which_eps == pcm_debye_model)
then
3250 call parse_variable(namespace,
'PCMDynamicEpsilon', pcm%deb%eps_0, pcm%deb%eps_d)
3251 call messages_print_var_value(
"PCMDynamicEpsilon", pcm%deb%eps_d, namespace=namespace)
3252 call parse_variable(namespace,
'PCMDebyeRelaxTime', m_zero, pcm%deb%tau)
3253 call messages_print_var_value(
"PCMDebyeRelaxTime", pcm%deb%tau, namespace=namespace)
3254 else if (pcm%which_eps == pcm_drude_model)
then
3255 call parse_variable(namespace,
'PCMDrudeLOmega',
sqrt(m_one/(pcm%deb%eps_0-m_one)), pcm%drl%w0)
3256 call messages_print_var_value(
"PCMDrudeLOmega", pcm%drl%w0, namespace=namespace)
3257 call parse_variable(namespace,
'PCMDrudeLDamping', m_zero, pcm%drl%gm)
3258 call messages_print_var_value(
"PCMDrudeLDamping", pcm%drl%gm, namespace=namespace)
3261 call parse_variable(namespace,
'PCMDynamicEpsilon', pcm%deb%eps_0, pcm%deb%eps_d)
3262 call messages_print_var_value(
"PCMDynamicEpsilon", pcm%deb%eps_d, namespace=namespace)
3271 complex(real64),
intent(out) :: eps
3272 type(debye_param_t),
intent(in) :: deb
3273 real(real64),
intent(in) :: omega
3277 eps = deb%eps_d + (deb%eps_0 - deb%eps_d)/(m_one + (omega*deb%tau)**2) + &
3278 m_zi*omega*deb%tau*(deb%eps_0 - deb%eps_d)/(m_one + (omega*deb%tau)**2)
3286 complex(real64),
intent(out) :: eps
3287 type(drude_param_t),
intent(in) :: drl
3288 real(real64),
intent(in) :: omega
3292 eps = m_one + (drl%w0**2 - omega**2)*drl%aa/((drl%w0**2 - omega**2)**2 + (omega*drl%gm)**2) + &
3293 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)
logical function mpi_grp_is_root(grp)
Is the current MPI process of grpcomm, root.
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.
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
integer, parameter pcm_dim_space
The resulting cavity is discretized by a set of tesserae defined in 3d.
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.
logical gamess_benchmark
Decide to output pcm_matrix in a GAMESS format.
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...