MPI-SCATCI  2.0
An MPI version of SCATCI
SolutionHandler_module.f90
Go to the documentation of this file.
1 ! Copyright 2019
2 !
3 ! For a comprehensive list of the developers that contributed to these codes
4 ! see the UK-AMOR website.
5 !
6 ! This file is part of UKRmol-in (UKRmol+ suite).
7 !
8 ! UKRmol-in is free software: you can redistribute it and/or modify
9 ! it under the terms of the GNU General Public License as published by
10 ! the Free Software Foundation, either version 3 of the License, or
11 ! (at your option) any later version.
12 !
13 ! UKRmol-in is distributed in the hope that it will be useful,
14 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 ! GNU General Public License for more details.
17 !
18 ! You should have received a copy of the GNU General Public License
19 ! along with UKRmol-in (in source/COPYING). Alternatively, you can also visit
20 ! <https://www.gnu.org/licenses/>.
21 
32 
33  use cdenprop_defs, only: civect, maxnuc
34  use const_gbl, only: stdout
36  use precisn, only: wp
37  use mpi_gbl, only: master, mpi_xermsg, mpi_mod_isend, mpi_mod_recv
38  use params, only: ccidata, c8stars, cblank, cpoly
39  use scatci_routines, only: movep, civio, movew
42  use options_module, only: options
43  use parallelization_module, only: grid => process_grid
44  use sweden_module, only: swedenintegral
45  use ukrmol_module, only: ukrmolintegral
46 
47  implicit none
48 
57  integer :: io_unit = 25
58  integer :: symmetry_type
59  integer :: num_eigenpairs
60  real(wp), allocatable :: energy_shifts(:)
61  real(wp) :: core_energy
62  real(wp) :: energy_shift
63  integer, allocatable :: phase(:)
64  integer :: size_phase
65  integer :: vec_dimen
66  integer :: nciset
67  integer :: current_eigenvector = 0
68  integer :: print_all_eigs = 0
69  contains
70  procedure, public :: construct
71  procedure, public :: write_header => write_header_sol
72  procedure, public :: export_header => export_header_sol
73  procedure, public :: export_eigenvalues
74  procedure, public :: shift_eigenvalues
75  procedure, public :: handle_eigenvalues => write_eigenvalues
76  procedure, public :: handle_eigenvector => write_eigenvector
77  procedure, public :: finalize_solutions => finalize_solutions_sol
78  procedure, public :: destroy
79  end type solutionhandler
80 
81 contains
82 
89  subroutine construct (this, opts)
90 
91  class(solutionhandler) :: this
92  class(options), intent(in) :: opts
93 
94  integer :: n
95 
96  this % symmetry_type = opts % sym_group_flag
97  this % io_unit = opts % ci_output_unit
98  this % continuum_dimen = opts % seq_num_last_continuum_csf
99  this % vec_dimen = opts % contracted_mat_size
100  this % num_eigenpairs = opts % num_eigenpairs
101  this % vector_storage = opts % vector_storage_method
102  this % print_all_eigs = opts % print_flags(2)
103 
104  if (.not.(allocated(this % energy_shifts))) then
105  allocate(this % energy_shifts(this % num_eigenpairs))
106  n = min(this % num_eigenpairs, size(opts % energy_shifts))
107  this % energy_shifts = 0.0_wp
108  this % energy_shifts(1:n) = opts % energy_shifts(1:n)
109  end if
110 
111  end subroutine construct
112 
113 
120  subroutine destroy (this)
121 
122  class(solutionhandler), intent(inout) :: this
123 
124  if (allocated(this % energy_shifts)) then
125  deallocate (this % energy_shifts)
126  end if
127 
128  if (allocated(this % phase)) then
129  deallocate (this % phase)
130  end if
131 
132  call this % ci_vec % final_CV
133 
134  end subroutine destroy
135 
136 
145  subroutine write_header_sol (this, option, integrals)
146 
147  class(solutionhandler) :: this
148  class(options), intent(in) :: option
149  class(baseintegral), intent(in) :: integrals
150  integer :: Nset = 1
151  integer :: print_header
152  integer :: nnuc, nrec, i, buf(1), n = 1, tag = 0
153  integer :: ierror, nth, nhd(10)
154 
155  !first lets quickly grab the core_energy while we're here
156  this % core_energy = integrals % get_core_energy()
157 
158  if (grid % grank /= master) return
159  this % nciset = option % output_ci_set_number
160  if (option % output_ci_set_number < 0) return
161 
162  ! If output unit dataset for these solutions follows after another dataset in the same unit, we need to wait
163  ! for a signal from master of the MPI group responsible for writing of that dataset first, so that we do not
164  ! access the unit concurrently.
165  if (option % preceding_writer >= 0) then
166  call mpi_mod_recv(option % preceding_writer, tag, buf, n)
167  end if
168 
169  this % size_phase = min(size(option % phase_index), this % vec_dimen)
170 
171  if (.not.(allocated(this % phase))) then
172  allocate(this % phase(this % vec_dimen))
173  this % phase = 0
174  this % phase(1:this % size_phase) = option % phase_index(1:this % size_phase)
175  end if
176 
177  nset = option % output_ci_set_number
178  nth = nset
179 
180  print_header = option % print_dataset_heading
181 
182  if (this % symmetry_type >= symtype_d2h) then
183 
184  ! Move to the correct position in the file. The subroutine movep can, in theory, change the value of "nth". However,
185  ! OptionsSet should have made sure that the values of output_ci_set_number are such that this will never happen.
186  ! (I.e. that we are writing always the next unit in line.) Otherwise we would risk locking of the MPI groups and/or
187  ! overwriting some MPI group results by other MPI groups.
188  call movep(this % io_unit, nth, ierror, print_header, stdout)
189 
190  if (ierror /= 0) then
191  call mpi_xermsg('SolutionHandler_module', 'write_header_sol', &
192  ' ERROR POSITIONING FOR OUTPUT OF CI COEFFICIENTS', 1, 1)
193  end if
194 
195  nset = nth
196  nnuc = integrals % get_num_nuclei()
197  nrec = nnuc + this % num_eigenpairs + 1
198 
199  write (this % io_unit) c8stars, cblank, cblank, ccidata
200  write (this % io_unit) nset, nrec, option % diag_name(1:120), nnuc, option % contracted_mat_size, &
201  this % num_eigenpairs, option % lambda, option % spin, option % spin_z, &
202  option % num_electrons, this % core_energy, option % num_target_sym, &
203  (option % lambda_continuum_orbitals_target(i), &
204  option % num_continuum_orbitals_target(i), i = 1, option % num_target_sym)
205 
206  call integrals % write_geometries(this % io_unit)
207 
208  else
209 
210  ! Move to the correct position in the file
211  call movew(this % io_unit, nth, ierror, print_header, stdout)
212 
213  if (ierror /= 0) then
214  call mpi_xermsg('SolutionHandler_module', 'write_header_sol', &
215  ' ERROR POSITIONING FOR OUTPUT OF CI COEFFICIENTS', 2, 1)
216  end if
217 
218  nhd( :) = 0
219  nhd( 2) = option % contracted_mat_size
220  nhd( 3) = this % num_eigenpairs
221  nhd( 4) = option % num_syms
222  nhd( 8) = option % contracted_mat_size
223  nhd( 9) = integrals % get_num_nuclei()
224  nhd(10) = merge(1, 0, this % num_eigenpairs < option % contracted_mat_size)
225 
226  ! We are using alchemy integrals
227  write (this % io_unit) nth, nhd, option % diag_name(1:120), integrals % NHE, integrals % DTNUC
228 
229  end if
230 
231  write (stdout, "(' CI data will be stored as set number',I3)") nset
232 
233  end subroutine write_header_sol
234 
235 
244  subroutine export_header_sol (this, option, integrals)
245 
246  class(solutionhandler) :: this
247  class(options), intent(in) :: option
248  class(baseintegral), intent(in) :: integrals
249 
250  integer :: err, i
251 
252  !first lets quickly grab the core_energy while we're here
253  this % core_energy = integrals % get_core_energy()
254  this % size_phase = min(size(option % phase_index), this % vec_dimen)
255 
256  if (.not.(allocated(this % phase))) then
257  allocate(this % phase(this % vec_dimen), stat = err)
258  if (err /= 0) then
259  call mpi_xermsg('SolutionHandler_module', 'export_header_sol', &
260  'Error allocating internal phase array', 1, 1)
261  end if
262  this % phase = 0
263  this % phase(1:this % size_phase) = option % phase_index(1:this % size_phase)
264  end if
265 
266  if (this % symmetry_type >= symtype_d2h) then
267  this % ci_vec % Nset = option % output_ci_set_number
268  this % ci_vec % nrec = integrals % get_num_nuclei() + this % num_eigenpairs + 1
269  this % ci_vec % name = option % diag_name
270  this % ci_vec % nnuc = integrals % get_num_nuclei()
271  this % ci_vec % nocsf = option % contracted_mat_size
272  this % ci_vec % nstat = this % num_eigenpairs
273  this % ci_vec % mgvn = option % lambda
274  this % ci_vec % s = option % spin
275  this % ci_vec % sz = option % spin_z
276  this % ci_vec % nelt = option % num_electrons
277  this % ci_vec % e0 = this % core_energy
278 
279  if (this % ci_vec % nnuc > maxnuc) then
280  call mpi_xermsg('SolutionHandler_module', 'export_header_sol', &
281  'Increase the value of maxnuc in cdenprop_defs and recompile', 2, 1)
282  end if
283 
284  select type (integrals)
285  type is (ukrmolintegral)
286  this % ci_vec % cname (1:this % ci_vec % nnuc) = integrals % cname (1:this % ci_vec % nnuc)
287  this % ci_vec % charge(1:this % ci_vec % nnuc) = integrals % charge(1:this % ci_vec % nnuc)
288  this % ci_vec % xnuc (1:this % ci_vec % nnuc) = integrals % xnuc (1:this % ci_vec % nnuc)
289  this % ci_vec % ynuc (1:this % ci_vec % nnuc) = integrals % ynuc (1:this % ci_vec % nnuc)
290  this % ci_vec % znuc (1:this % ci_vec % nnuc) = integrals % znuc (1:this % ci_vec % nnuc)
291  type is (swedenintegral)
292  this % ci_vec % cname (1:this % ci_vec % nnuc) = integrals % cname (1:this % ci_vec % nnuc)
293  this % ci_vec % charge(1:this % ci_vec % nnuc) = integrals % charge(1:this % ci_vec % nnuc)
294  this % ci_vec % xnuc (1:this % ci_vec % nnuc) = integrals % xnuc (1:this % ci_vec % nnuc)
295  this % ci_vec % ynuc (1:this % ci_vec % nnuc) = integrals % ynuc (1:this % ci_vec % nnuc)
296  this % ci_vec % znuc (1:this % ci_vec % nnuc) = integrals % znuc (1:this % ci_vec % nnuc)
297  class default
298  call mpi_xermsg('SolutionHandler_module', 'export_header_sol', &
299  'Geometry export implemented only for UKRMOLIntegral, SWEDENIntegral', 3, 1)
300  end select
301 
302  write (stdout, '(/,"CI VECTOR HEADER DATA:")')
303  write (stdout, '("----------------------")')
304  write (stdout, *) this % ci_vec % nset, &
305  this % ci_vec % nrec, &
306  this % ci_vec % NAME, &
307  this % ci_vec % nnuc, &
308  this % ci_vec % nocsf, &
309  this % ci_vec % nstat, &
310  this % ci_vec % mgvn, &
311  this % ci_vec % s, &
312  this % ci_vec % sz, &
313  this % ci_vec % nelt, &
314  this % ci_vec % e0
315  do i = 1, this % ci_vec % nnuc
316  write (stdout, *) this % ci_vec % cname(i), &
317  this % ci_vec % xnuc(i), &
318  this % ci_vec % ynuc(i), &
319  this % ci_vec % znuc(i), &
320  this % ci_vec % charge(i)
321  end do
322  write (stdout, '("----------------------")')
323  else
324  call mpi_xermsg('SolutionHandler_module', 'export_header_sol', &
325  'Output of ALCHEMY header not implemented yet', 4, 1)
326  end if
327 
328  write (stdout, '(" CI data will be stored in memory for use in subsequent subroutines")')
329 
330  end subroutine export_header_sol
331 
332 
340  subroutine shift_eigenvalues (this, output_eigenvalues, num_eigenpairs)
341 
342  class(solutionhandler) :: this
343  integer, intent(in) :: num_eigenpairs
344  real(wp), intent(inout) :: output_eigenvalues(num_eigenpairs)
345  integer :: ido, jdo, neig
346 
347  if (grid % grank /= master) return
348  if (this % nciset < 0) return
349 
350  output_eigenvalues = output_eigenvalues + this % energy_shifts
351 
352  neig = this % num_eigenpairs
353  if (this % print_all_eigs == 0) then
354  neig = min(this % num_eigenpairs, max_neig)
355  end if
356 
357  write (stdout, '("ENERGY SHIFTS TO BE APPLIED")')
358  do ido = 1, neig, 5
359  write (stdout, "(5F20.10)") (this % energy_shifts(jdo), jdo = ido, min(ido + 4, neig))
360  end do
361 
362  end subroutine shift_eigenvalues
363 
364 
372  subroutine write_eigenvalues (this, eigenvalues, diagonals, num_eigenpairs, vec_dimen)
373 
374  class(solutionhandler) :: this
375  integer, intent(in) :: num_eigenpairs, vec_dimen
376  real(wp), intent(in) :: eigenvalues(num_eigenpairs), diagonals(vec_dimen)
377  real(wp) :: output_eigenvalues(num_eigenpairs)
378  integer :: ido, jdo, neig
379 
380  if (grid % grank /= master) return
381  if (this % nciset < 0) return
382 
383  output_eigenvalues = eigenvalues
384 
385  neig = this % num_eigenpairs
386  if (this % print_all_eigs == 0) then
387  neig = min(this % num_eigenpairs, max_neig)
388  end if
389 
390  if (sum(abs(this % energy_shifts)) .gt. 0_wp) then
391  write (stdout, '("ORIGINAL EIGEN-ENERGIES")')
392  do ido = 1, neig, 5
393  write (stdout, "(16X,5F20.10)") (output_eigenvalues(jdo) + this % core_energy, jdo = ido, min(ido + 4, neig))
394  end do
395  call this % shift_eigenvalues(output_eigenvalues, num_eigenpairs)
396  end if
397 
398  write (stdout, '("EIGEN-ENERGIES")')
399  do ido = 1, neig, 5
400  write (stdout, "(16X,5F20.10)") (output_eigenvalues(jdo) + this % core_energy, jdo = ido, min(ido + 4, neig))
401  end do
402  write (this % io_unit) this % phase, output_eigenvalues, diagonals
403 
404  end subroutine write_eigenvalues
405 
406 
414  subroutine export_eigenvalues (this, eigenvalues, diagonals, num_eigenpairs, vec_dimen, ei, iphz)
415 
416  class(solutionhandler) :: this
417  integer, intent(in) :: num_eigenpairs, vec_dimen
418  real(wp), intent(in) :: eigenvalues(num_eigenpairs), diagonals(vec_dimen)
419  real(wp), allocatable :: ei(:)
420  real(wp) :: output_eigenvalues(num_eigenpairs)
421  integer, allocatable :: iphz(:)
422  integer :: ido, jdo, err
423 
424  output_eigenvalues = eigenvalues
425 
426  if (sum(abs(this % energy_shifts)) .gt. 0_wp) then
427  call this % shift_eigenvalues(output_eigenvalues, num_eigenpairs)
428  end if
429 
430  if (allocated(ei)) deallocate(ei)
431  allocate(ei, source = output_eigenvalues, stat = err)
432  if (err /= 0) then
433  call mpi_xermsg('SolutionHandler_module', 'export_eigenvalues', 'Error allocating ei', size(output_eigenvalues), 1)
434  end if
435 
436  if (allocated(iphz)) deallocate(iphz)
437  allocate(iphz, source = this % phase, stat = err)
438  if (err /= 0) then
439  call mpi_xermsg('SolutionHandler_module', 'export_eigenvalues', 'Error allocating iphz', size(this % phase), 1)
440  end if
441 
442  end subroutine export_eigenvalues
443 
444 
452  subroutine write_eigenvector (this, eigenvector, vec_dimen)
453 
454  class(solutionhandler) :: this
455  integer, intent(in) :: vec_dimen
456  real(wp), intent(in) :: eigenvector(vec_dimen)
457  integer :: start_dimen, end_dimen, ido, j
458 
459  if (grid % grank /= master) return
460  if (this % nciset < 0) return
461 
462  this % current_eigenvector = this % current_eigenvector + 1
463 
464  start_dimen = 1
465  end_dimen = this % vec_dimen
466 
467  if (iand(this % vector_storage, save_l2_coeffs) == 0) then
468  end_dimen = this % continuum_dimen
469  end if
470  if (iand(this % vector_storage, save_continuum_coeffs) == 0) then
471  start_dimen = this % continuum_dimen + 1
472  end if
473 
474  write (this % io_unit) this % current_eigenvector, (eigenvector(j), j = start_dimen, end_dimen)
475 
476  end subroutine write_eigenvector
477 
478 
487  subroutine finalize_solutions_sol (this, option)
488 
489  class(solutionhandler) :: this
490  class(options), intent(in) :: option
491 
492  integer :: buf(1), tag = 0, n = 1
493 
494  flush(this % io_unit)
495  close(this % io_unit)
496 
497  if (option % following_writer >= 0) then
498  call mpi_mod_isend(option % following_writer, buf, tag, n)
499  end if
500 
501  end subroutine finalize_solutions_sol
502 
503 end module solutionhandler_module
consts_mpi_ci::max_neig
integer, parameter max_neig
Default limit on the number of eigenvalues printed.
Definition: consts_mpi_ci.f90:43
diagonalizerresult_module::diagonalizerresult
Output from diagonalization.
Definition: DiagonalizerResult_module.f90:48
consts_mpi_ci::save_l2_coeffs
integer, parameter save_l2_coeffs
Keep only L2 section of the eigenvectors (omit continuum channels)
Definition: consts_mpi_ci.f90:112
solutionhandler_module::solutionhandler
Solution writer.
Definition: SolutionHandler_module.f90:56
solutionhandler_module::construct
subroutine construct(this, opts)
Set up solution handler.
Definition: SolutionHandler_module.f90:90
solutionhandler_module::finalize_solutions_sol
subroutine finalize_solutions_sol(this, option)
Finalize writing the eigenvector disk file.
Definition: SolutionHandler_module.f90:488
sweden_module::swedenintegral
Definition: SWEDEN_Module.F90:47
diagonalizerresult_module::handle_eigenvector
Main build routine of the hamiltonian.
Definition: DiagonalizerResult_module.f90:87
consts_mpi_ci::symtype_d2h
integer, parameter symtype_d2h
This describes D_2_h symmetries.
Definition: consts_mpi_ci.f90:57
options_module::options
Calculation setup for a single Hamiltonian diagonalization.
Definition: Options_module.f90:74
solutionhandler_module::write_eigenvalues
subroutine write_eigenvalues(this, eigenvalues, diagonals, num_eigenpairs, vec_dimen)
Save Hamiltonian eigen-energies to disk file.
Definition: SolutionHandler_module.f90:373
solutionhandler_module::export_header_sol
subroutine export_header_sol(this, option, integrals)
Write basic information into a CI vector.
Definition: SolutionHandler_module.f90:245
ukrmol_module::ukrmolintegral
Definition: UKRMOL_module.f90:43
ukrmol_module
UKRmol+ integral module.
Definition: UKRMOL_module.f90:30
consts_mpi_ci::save_continuum_coeffs
integer, parameter save_continuum_coeffs
Omit L2 section of the eigenvectors (only keep continuum channels)
Definition: consts_mpi_ci.f90:108
parallelization_module::process_grid
type(processgrid) process_grid
Definition: Parallelization_module.F90:80
consts_mpi_ci
MPI SCATCI Constants module.
Definition: consts_mpi_ci.f90:31
solutionhandler_module::write_header_sol
subroutine write_header_sol(this, option, integrals)
Start writing eigenvector record.
Definition: SolutionHandler_module.f90:146
diagonalizerresult_module::export_eigenvalues
build routine of the hamiltonian
Definition: DiagonalizerResult_module.f90:103
baseintegral_module
Base integral module.
Definition: BaseIntegral_module.f90:28
parallelization_module
Distribution of processes into a grid.
Definition: Parallelization_module.F90:29
solutionhandler_module::write_eigenvector
subroutine write_eigenvector(this, eigenvector, vec_dimen)
Save Hamiltonian eigen-vectors to disk file.
Definition: SolutionHandler_module.f90:453
options_module::phase
?
Definition: Options_module.f90:61
diagonalizerresult_module
Diagonalizer result data object.
Definition: DiagonalizerResult_module.f90:28
baseintegral_module::baseintegral
Definition: BaseIntegral_module.f90:41
sweden_module
SWEDEN integral module.
Definition: SWEDEN_Module.F90:28
solutionhandler_module::destroy
subroutine destroy(this)
Release resources.
Definition: SolutionHandler_module.f90:121
solutionhandler_module
Solution handler module.
Definition: SolutionHandler_module.f90:31
options_module
Options module.
Definition: Options_module.f90:41
diagonalizerresult_module::handle_eigenvalues
Main build routine of the hamiltonian.
Definition: DiagonalizerResult_module.f90:71
solutionhandler_module::shift_eigenvalues
subroutine shift_eigenvalues(this, output_eigenvalues, num_eigenpairs)
Shift eigenvalues according to the NAMELIST input ESHIFT.
Definition: SolutionHandler_module.f90:341