MPI-SCATCI 2.0
An MPI version of SCATCI
Loading...
Searching...
No Matches
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
22!> \brief Solution handler module
23!> \authors A Al-Refaie
24!> \date 2017
25!>
26!> Manages the eigevalue and eigenvector output. These are passed to individual subroutines
27!> by the caller; solution handler itself contains just a little basic information.
28!>
29!> \note 16/01/2019 - Jakub Benda: Unifom coding style and expanded documentation.
30!>
31module solutionhandler_module
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
40 use baseintegral_module, only: baseintegral
41 use diagonalizerresult_module, only: diagonalizerresult
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
49 !> \brief Solution writer
50 !> \authors A Al-Refaie, J Benda
51 !> \date 2017 - 2019
52 !>
53 !> Provides a comfortable interface to eigenvector disk output.
54 !> By default writes the *fort.25* file.
55 !>
56 type, extends(diagonalizerresult) :: solutionhandler
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
81contains
82
83 !> \brief Set up solution handler
84 !> \authors A Al-Refaie
85 !> \date 2017
86 !>
87 !> Initialize internal parameters, most notably the number of the output unit.
88 !>
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
114 !> \brief Release resources
115 !> \authors J Benda
116 !> \date 2019
117 !>
118 !> Release all allocated memory (phases and the CDENPROP data vector).
119 !>
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
137 !> \brief Start writing eigenvector record
138 !> \authors A Al-Refaie
139 !> \date 2017
140 !>
141 !> Opens or rewinds the output file, positions it to the beginning of the requested record
142 !> and writes basic information about the solution, excluding phase information, eigenvalues
143 !> and eigenvectors.
144 !>
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
236 !> \brief Write basic information into a CI vector
237 !> \authors A Al-Refaie, J Benda
238 !> \date 2017 - 2019
239 !>
240 !> Store general data related to the eigenvectors (like global quantum numbers, nuclear information
241 !> and number of eigenvectors) to the provided CDENPROP data vector. This is used when passing
242 !> data from MPI-SCATCI directly to the CDENPROP library.
243 !>
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
333 !> \brief Shift eigenvalues according to the NAMELIST input ESHIFT
334 !> \authors T Meltzer
335 !> \date 2020
336 !>
337 !> Shift eigenvalues according to the NAMELIST input ESHIFT. This subroutine is called only
338 !> when some of the energy_shifts is non-zero.
339 !>
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
365 !> \brief Save Hamiltonian eigen-energies to disk file
366 !> \authors A Al-Refaie
367 !> \date 2017
368 !>
369 !> Continues the output operation commenced in \ref write_header_sol by writing the phase information,
370 !> eigenvalues and diagonals(?).
371 !>
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
407 !> \brief Write eigevalues and phases to supplied arrays
408 !> \authors A Al-Refaie
409 !> \date 2017
410 !>
411 !> Copies (a subset of) eigenvalues and phases stored in the calling objecst to supplied
412 !> arrays. This is used when preparing diagonalization data for processing in CDENPROP.
413 !>
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
445 !> \brief Save Hamiltonian eigen-vectors to disk file
446 !> \authors A Al-Refaie
447 !> \date 2017
448 !>
449 !> Completes the output operation commenced in \ref write_header_sol by writing the eigenvectors
450 !> (one per a call).
451 !>
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
479 !> \brief Finalize writing the eigenvector disk file
480 !> \authors J Benda
481 !> \date 2019
482 !>
483 !> To avoid concurrent, conflicting accesses to the disk file in case that multiple datasets are to be written to it,
484 !> by different processes, MPI-SCATCI uses a semaphore system. Once a process finishes writing its results into a dataset,
485 !> it notifies the next process in line that wants to write to the same file unit (but into the subsequent dataset).
486 !>
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
503end module solutionhandler_module
MPI SCATCI Constants module.
integer, parameter max_neig
Default limit on the number of eigenvalues printed.
integer, parameter symtype_d2h
This describes D_2_h symmetries.
integer, parameter save_l2_coeffs
Keep only L2 section of the eigenvectors (omit continuum channels)
integer, parameter save_continuum_coeffs
Omit L2 section of the eigenvectors (only keep continuum channels)