Multidip  1.0
Multi-photon matrix elements
multidip_io.F90
Go to the documentation of this file.
1 ! Copyright 2020
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-out (UKRmol+ suite).
7 !
8 ! UKRmol-out 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-out 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-out (in source/COPYING). Alternatively, you can also visit
20 ! <https://www.gnu.org/licenses/>.
21 !
30 
31  use, intrinsic :: iso_c_binding, only: c_double, c_int, c_f_pointer
32  use, intrinsic :: iso_fortran_env, only: input_unit, int32, int64, real64, output_unit, iostat_end
33 
34  ! GBTOlib
35  use blas_lapack_gbl, only: blasint
36 #ifdef WITH_MMAP
37  use file_mapping_gbl, only: file_mapping
38 #endif
39  use phys_const_gbl, only: pi, imu, to_ev
40  use precisn_gbl, only: wp, wp_bytes
41 
42  implicit none
43 
44 #ifdef WITH_SCALAPACK
45  integer(blasint), external :: numroc
46 #endif
47 
48  integer :: myproc = 1
49  integer :: nprocs = 1
50 
58  type kmatrix
59  integer :: mgvn, stot, nescat, nchan, nopen, ndopen, nchsq, lukmt, nkset, maxne
60  real(wp), allocatable :: escat(:)
61  contains
62  procedure :: get_kmatrix
63  procedure :: read_kmatrix_file
65  end type kmatrix
66 
67 
76  real(wp), allocatable :: rea(:, :, :), ima(:, :, :), evchl(:)
77  integer, allocatable :: ichl(:), lvchl(:), mvchl(:)
78  integer :: mgvn, nesc, nchan, nstat, lusct
79  contains
80  procedure :: get_wfncoeffs
81  procedure :: read_wfncoeffs_file
83  end type scatakcoeffs
84 
85 
96  real(real64), pointer :: mat(:, :) => null()
97 #ifdef WITH_MMAP
98  type(file_mapping) :: mapping
99 #endif
100  logical :: distributed = .false.
101  integer(blasint) :: desc(9) = 0
102  integer(blasint) :: row_context = 0
103  integer(blasint) :: blk_context = 0
104  integer(blasint) :: block_size = 0
105  contains
106  procedure :: load => load_mapped_matrix
108  end type mappedmatrix
109 
110 
127 
128  ! inner transition dipoles storage
129  type(mappedmatrix), allocatable :: dipx(:), dipy(:), dipz(:)
130  integer(int32), allocatable :: iidipx(:), iidipy(:), iidipz(:)
131  integer(int32), allocatable :: ifdipx(:), ifdipy(:), ifdipz(:)
132 
133  ! boundary amplitudes
134  type(mappedmatrix), allocatable :: wamp(:)
135  type(mappedmatrix), allocatable :: wmat2(:, :)
136 
137  ! number of electrons, number of protons
138  integer(int32) :: nelc, nz
139 
140  ! other data
141  real(real64) :: rmatr
142  real(real64), allocatable :: crlv(:,:,:), eig(:,:), rg(:), etarg(:), gaunt(:, :, :), r_points(:)
143  integer(int32), allocatable :: mgvns(:), stot(:), mnp1(:), nchan(:), l2p(:,:), m2p(:,:), ichl(:,:), lm_rg(:,:)
144 
145  end type moleculardata
146 
147 contains
148 
157  subroutine load_mapped_matrix (this, filename, u, offset, rows, cols)
158 
159 #ifdef WITH_SCALAPACK
160  use mpi
161  use mpi_gbl, only: mpi_xermsg
162 
163  integer, parameter :: mpiint = kind(mpi_comm_world)
164  integer, parameter :: mpiofs = mpi_offset_kind
165 
166  character(len=200) :: msg
167 
168  integer(mpiint) :: ndims, gsizes(2), distrb(2), dargs(2), psizes(2), locsiz, fh, ierr, datype
169  integer(mpiint) :: comm_size, comm_rank, stat(MPI_STATUS_SIZE), mtwo = 2, dims(2)
170  integer(mpiofs) :: offs
171 #endif
172 
173  class(mappedmatrix), intent(inout) :: this
174  character(len=*), intent(in) :: filename
175  integer(int32), intent(in) :: u, rows, cols
176  integer(int64), intent(in) :: offset
177 
178  integer(int64) :: length
179  integer(blasint) :: zero = 0, one = 1, nprow, npcol, lrows, lcols, min_block_size, max_block_size, ld, info, myprow, mypcol
180  integer(blasint) :: brows, bcols
181 
182 #ifdef WITH_SCALAPACK
183  if (this % distributed) then
184  call mpi_comm_size(mpi_comm_world, comm_size, ierr)
185  call assert_status('Failed to obtain world communicator size: ', int(ierr))
186  call mpi_comm_rank(mpi_comm_world, comm_rank, ierr)
187  call assert_status('Failed to obtain world communicator rank: ', int(ierr))
188 
189  dims = 0
190  call mpi_dims_create(comm_size, mtwo, dims, ierr)
191  call assert_status('Failed to reshape world communicator to rectangular grid: ', int(ierr))
192  nprow = maxval(dims)
193  npcol = minval(dims)
194 
195  if (npcol * nprow /= nprocs) then
196  write (msg, '(a,3(i0,a))') 'BLACS grid ', nprow, 'x', npcol, ' does not use all ', nprocs, ' processes. Fix it.'
197  call mpi_xermsg('multidip_io', 'load_mapped_matrix', trim(msg), 1, 1);
198  end if
199 
200  call blacs_get(zero, zero, this % row_context)
201  call blacs_get(zero, zero, this % blk_context)
202  call blacs_gridinit(this % row_context, 'R', one, nprow * npcol)
203  call blacs_gridinit(this % blk_context, 'R', nprow, npcol)
204  call blacs_gridinfo(this % blk_context, nprow, npcol, myprow, mypcol)
205 
206  min_block_size = 1
207  max_block_size = 512 ! rather arbitrary, but this particular choice coincides with a common page size (4 kiB)
208 
209  this % block_size = min(rows / nprow, cols / npcol)
210  this % block_size = min(this % block_size, max_block_size)
211  this % block_size = max(this % block_size, min_block_size)
212 
213  brows = rows
214  bcols = cols
215  lrows = numroc(brows, this % block_size, myprow, zero, nprow)
216  lcols = numroc(bcols, this % block_size, mypcol, zero, npcol)
217  ld = max(one, lrows)
218 
219  if (int(lrows, int64)*int(lcols, int64) > huge(1_int32)) then
220  print '(a,i0,a,i0,a)', 'WARNING: Local portion of the dipole matrix has size ', lrows, ' x ', lcols, '.'
221  print '(9x,a)', 'This means that it cannot be indexed with 4-byte integers.'
222  print '(9x,a,/)', 'If reading fails, try distributing the calculation more.'
223  end if
224 
225  call descinit(this % desc, brows, bcols, this % block_size, this % block_size, zero, zero, this % blk_context, ld, info)
226 
227  allocate (this % mat(ld, lcols))
228 
229  offs = offset - 1
230  ndims = 2
231  gsizes = [ rows, cols ]
232  distrb = [ mpi_distribute_cyclic, mpi_distribute_cyclic ]
233  dargs = [ this % block_size, this % block_size ]
234  psizes = [ nprow, npcol ]
235  locsiz = lrows * lcols
236 
237  call mpi_file_open(mpi_comm_world, filename, mpi_mode_rdonly, mpi_info_null, fh, ierr)
238  call assert_status('Failed to open file for MPI-IO: ', int(ierr))
239  call mpi_type_create_darray(comm_size, comm_rank, ndims, gsizes, distrb, dargs, &
240  psizes, mpi_order_fortran, mpi_real8, datype, ierr)
241  call assert_status('Failed to define distributed array data type: ', int(ierr))
242  call mpi_type_commit(datype, ierr)
243  call assert_status('Failed to commit distributed array data type: ', int(ierr))
244  call mpi_file_set_view(fh, offs, mpi_real8, datype, 'native', mpi_info_null, ierr)
245  call assert_status('Failed to define file view: ', int(ierr))
246  call mpi_file_read_all(fh, this % mat, locsiz, mpi_real8, stat, ierr)
247  call assert_status('Failed to read from file: ', int(ierr))
248  call mpi_type_free(datype, ierr)
249  call assert_status('Failed to release distributed array data type: ', int(ierr))
250  call mpi_file_close(fh, ierr)
251  call assert_status('Failed to close file: ', int(ierr))
252  else
253 #endif
254 #ifdef WITH_MMAP
255  length = int(rows, int64) * int(cols, int64) * wp_bytes
256  call this % mapping % init(filename, offset - 1, length)
257  call c_f_pointer(this % mapping % ptr, this % mat, [rows, cols])
258 #else
259  allocate (this % mat(rows, cols))
260  read (u) this % mat
261 #endif
262 #ifdef WITH_SCALAPACK
263  end if
264 #endif
265 
266  end subroutine load_mapped_matrix
267 
268 
277  subroutine destruct_mapped_matrix (this)
278 
279  type(mappedmatrix), intent(inout) :: this
280 
281 #ifdef WITH_SCALAPACK
282  if (this % distributed) then
283  deallocate (this % mat)
284  else
285 #endif
286 #ifndef WITH_MMAP
287  if (associated(this % mat)) then
288  deallocate (this % mat)
289  end if
290 #endif
291 #ifdef WITH_SCALAPACK
292  end if
293 #endif
294  nullify (this % mat)
295 
296  end subroutine destruct_mapped_matrix
297 
298 
307  subroutine read_kmatrices (km, lukmt, nkset)
308 
309  use mpi_gbl, only: mpi_xermsg
310 
311  type(kmatrix), allocatable, intent(inout) :: km(:)
312  integer, intent(in) :: lukmt(:), nkset(:)
313 
314  character(len=200) :: msg
315  integer :: i
316 
317  do i = 1, size(km)
318 
319  km(i) % lukmt = lukmt(i)
320  km(i) % nkset = nkset(i)
321 
322  call km(i) % read_kmatrix_file
323 
324  if (km(i) % nescat /= km(1) % nescat) then
325  write (msg, '(a,2(i0,a))') 'ERROR: K-matrix units ', lukmt(1), ' and ', lukmt(i), &
326  ' hold different number of scattering energies!'
327  call mpi_xermsg('multidip_io', 'read_kmatrices', trim(msg), 1, 1)
328  end if
329 
330  if (any(km(i) % escat(1 : km(i) % nescat) /= km(1) % escat(1 : km(1) % nescat))) then
331  write (msg, '(a,2(i0,a))') 'ERROR: K-matrix units ', lukmt(1), ' and ', lukmt(i), &
332  ' hold different scattering energies!'
333  call mpi_xermsg('multidip_io', 'read_kmatrices', trim(msg), 1, 1)
334  end if
335 
336  end do
337 
338  end subroutine read_kmatrices
339 
340 
350  subroutine read_kmatrix_file (km)
351 
352  use mpi_gbl, only: mpi_xermsg
353 
354  class(kmatrix), intent(inout) :: km
355 
356  integer :: k, n, ifail, key, nset, nrec, ninfo, ndata, ntarg, nvib, ndis, ie, gutot, ion
357  integer :: nopen, ndopen, nchsq, a, b, c, mye, nene, ierr
358  logical :: iwarn
359  real(wp) :: dE1, dE2, r, rmass, en
360  real(wp), allocatable :: kmat(:)
361  character(len=80) :: title, msg
362 
363  print '(/,A,I0,A,I0,/)', 'Reading K-matrices from unit ', km % lukmt, ', set ', km % nkset
364 
365  call getset(km % lukmt, km % nkset, 11, 'UNFORMATTED', ifail)
366 
367  read (km % lukmt) key, nset, nrec, ninfo, ndata
368  read (km % lukmt) title
369  read (km % lukmt) km % mgvn, km % stot, gutot, ion, r, rmass
370  read (km % lukmt) ntarg, nvib, ndis, km % nchan, km % maxne
371 
372  print '(2x,A,I0)', 'mgvn = ', km % mgvn
373  print '(2x,A,I0)', 'stot = ', km % stot
374  print '(2x,A,I0)', 'ntarg = ', ntarg
375  print '(2x,A,I0)', 'nvib = ', nvib
376  print '(2x,A,I0)', 'ndis = ', ndis
377  print '(2x,A,I0)', 'nchan = ', km % nchan
378  print '(2x,A,I0)', 'maxne = ', km % maxne
379 
380  print '(/,2x,A,/)', 'Energy ranges:'
381 
382  km % nescat = 0
383  do ie = 1, km % maxne
384  read (km % lukmt) k, n, de1, de2
385  print '(4x,I4,I8,F8.3,F8.3)', k, n, de1, de2
386  km % nescat = km % nescat + n
387  end do
388 
389  nene = (km % nescat + nprocs - 1) / nprocs
390  allocate (km % escat(km % nescat), kmat(km % nchan * (km % nchan + 1)))
391 
392  iwarn = .true.
393  mye = 0
394  do ie = 1, km % nescat
395  read (km % lukmt, iostat = ierr) nopen, ndopen, nchsq, en!, kmat(1:nchsq)
396  if (ierr == iostat_end) then
397  print '(/,2x,A,I0,A,I0,A)', 'WARNING: Unit ', km % lukmt, ' contains only ', ie - 1, ' K-matrices.'
398  print '(11x,A)', 'This means that CFASYM failed during RSOLVE for some energies.'
399  print '(11x,A)', 'The scattering energies MUST be consistent across symmetries!'
400  km % nescat = ie - 1
401  exit
402  else if (ierr /= 0) then
403  write (msg, '(2x,a,i0,a)') 'ERROR ', ierr, ' while reading K-matrix file.'
404  call mpi_xermsg('multidip_io', 'read_kmatrix_file', trim(msg), 1, 1)
405  end if
406  km % escat(ie) = en/2 ! Ry -> a.u.
407  if (iwarn .and. nopen < km % nchan) then
408  print '(/,2x,A,I0,A)', 'WARNING: Unit ', km % lukmt, ' contains only open-open subset of the full K-matrix.'
409  print '(11x,A)', 'Use IKTYPE = 1 in RSOLVE to save full K-matrices.'
410  print '(11x,A)', 'You may get spurious below-threshold noise.'
411  iwarn = .false.
412  end if
413  end do
414 
415  deallocate (kmat)
416 
417  end subroutine read_kmatrix_file
418 
419 
428  subroutine reset_kmatrix_position (km, skip)
429 
430  class(kmatrix), intent(in) :: km
431  integer, optional, intent(in) :: skip
432 
433  integer :: i
434 
435  ! rewind to the beginning of the K-matrix unit
436  call getset(km % lukmt, km % nkset, 11, 'UNFORMATTED', i)
437 
438  read (km % lukmt)
439  read (km % lukmt)
440  read (km % lukmt)
441  read (km % lukmt)
442 
443  do i = 1, km % maxne
444  read (km % lukmt)
445  end do
446 
447  if (present(skip)) then
448  do i = 1, skip
449  read (km % lukmt)
450  end do
451  end if
452 
453  end subroutine reset_kmatrix_position
454 
455 
463  subroutine get_kmatrix (km, kmat, skip)
464 
465  use mpi_gbl, only: mpi_xermsg
466 
467  class(kmatrix), intent(in) :: km
468  real(wp), allocatable, intent(inout) :: kmat(:, :)
469  integer, optional, intent(in) :: skip
470 
471  real(wp), allocatable :: buffer(:)
472  character(len=200) :: msg
473 
474  real(wp) :: en
475  integer :: a, b, c, i, ierr, nopen, ndopen, nchsq
476 
477  allocate (buffer(km % nchan * (km % nchan + 1)))
478 
479  read (km % lukmt, iostat = ierr) nopen, ndopen, nchsq, en, buffer(1:nchsq)
480 
481  if (ierr == iostat_end) then
482  write (msg, '(a,i0,a)') 'ERROR: Unit ', km % lukmt, ' ended while reading K-matrix!'
483  call mpi_xermsg('multidip_io', 'get_kmatrix', trim(msg), 1, 1)
484  else if (ierr /= 0) then
485  write (msg, '(2x,a,2(i0,a))') 'ERROR ', ierr, ' while reading K-matrix file unit ', km % lukmt, '!'
486  call mpi_xermsg('multidip_io', 'get_kmatrix', trim(msg), 1, 1)
487  end if
488 
489  if (allocated(kmat)) then
490  if (size(kmat, 1) /= km % nchan .or. size(kmat, 2) /= km % nchan) then
491  deallocate (kmat)
492  end if
493  end if
494 
495  if (.not. allocated(kmat)) then
496  allocate (kmat(km % nchan, km % nchan))
497  end if
498 
499  c = 0
500  do a = 1, nopen
501  do b = 1, a
502  c = c + 1
503  kmat(a, b) = buffer(c)
504  kmat(b, a) = buffer(c)
505  end do
506  end do
507 
508  if (present(skip)) then
509  do i = 1, skip
510  read (km % lukmt, iostat = ierr) ! ignore EOF
511  end do
512  end if
513 
514  end subroutine get_kmatrix
515 
516 
525  subroutine read_wfncoeffs (ak, lusct)
526 
527  type(scatakcoeffs), allocatable, intent(inout) :: ak(:)
528  integer, intent(in) :: lusct(:)
529  integer :: i
530 
531  do i = 1, size(ak)
532  ak(i) % lusct = lusct(i)
533  call ak(i) % read_wfncoeffs_file
534  end do
535 
536  end subroutine read_wfncoeffs
537 
538 
551  subroutine read_bndcoeffs (bnd, Ei, lubnd, mgvn0, stot0)
552 
553  real(wp), intent(out) :: bnd(:), Ei
554  integer, intent(in) :: lubnd, mgvn0, stot0
555 
556  real(wp), allocatable :: xvec(:), etot(:), vtemp(:)
557  real(wp) :: rr
558  integer :: nbset, nchan, mgvn, stot, gutot, nstat, nbound, iprint, iwrite, ifail
559  character(len=11) :: bform
560 
561  bform = 'unformatted'
562  nbset = 1
563  iprint = 0
564  iwrite = output_unit
565 
566  open (lubnd, action = 'read', form = bform)
567 
568  call readbh(lubnd, nbset, nchan, mgvn, stot, gutot, nstat, nbound, rr, bform, iprint, iwrite, ifail)
569 
570  if (mgvn /= mgvn0 .or. stot /= stot0) then
571  print '(*(a,i0))', 'ERROR: Bound coefficients at unit ', lubnd, ' are for MGVN = ', mgvn, ', STOT = ', stot, &
572  ', but I am looking for MGVN = ', mgvn0, ', STOT = ', stot0
573  stop 1
574  end if
575 
576  nbound = 1 ! read just the first bound state, ignore the rest
577  allocate (xvec(nbound*nchan), vtemp(nbound), etot(nbound))
578 
579  call readbc(nstat, etot, vtemp, bnd, nbound, nchan, xvec)
580 
581  ei = etot(1)
582 
583  close (lubnd)
584 
585  end subroutine read_bndcoeffs
586 
587 
592  subroutine read_wfncoeffs_file (ak)
593 
594  class(scatakcoeffs), intent(inout) :: ak
595 
596  real(wp), allocatable :: ReA(:), ImA(:)
597  real(wp) :: rr
598  integer :: i, j, keysc, nset, nrec, ninfo, ndata, stot, gutot, nscat, ich, ie, mye, nene
599  character(len=80) :: header
600 
601  print '(/,A,I0,/)', 'Reading wave function coefficients from unit ', ak % lusct
602 
603  open (ak % lusct, status = 'old', action = 'read', form = 'unformatted')
604 
605  read (ak % lusct) keysc, nset, nrec, ninfo, ndata
606  read (ak % lusct) header
607  read (ak % lusct) nscat, ak % mgvn, stot, gutot, ak % nstat, ak % nchan, ak % nesc
608 
609  print '(2x,A,I0)', 'mgvn = ', ak % mgvn
610  print '(2x,A,I0)', 'stot = ', stot
611  print '(2x,A,I0)', 'nstat = ', ak % nstat
612  print '(2x,A,I0)', 'nchan = ', ak % nchan
613  print '(2x,A,I0)', 'nesc = ', ak % nesc
614 
615  read (ak % lusct) rr
616 
617  if (allocated(ak % ichl)) deallocate (ak % ichl)
618  if (allocated(ak % lvchl)) deallocate (ak % lvchl)
619  if (allocated(ak % mvchl)) deallocate (ak % mvchl)
620  if (allocated(ak % evchl)) deallocate (ak % evchl)
621 
622  allocate (ak % ichl(ak % nchan))
623  allocate (ak % lvchl(ak % nchan))
624  allocate (ak % mvchl(ak % nchan))
625  allocate (ak % evchl(ak % nchan))
626 
627  read (ak % lusct) ak % ichl, ak % lvchl, ak % mvchl, ak % evchl
628 
629  print '(/,2x,A)', 'channel table'
630  do j = 1, ak % nchan
631  print '(2x,4I6,F15.7)', j, ak % ichl(j), ak % lvchl(j), ak % mvchl(j), ak % evchl(j)
632  end do
633 
634  close (ak % lusct)
635 
636  end subroutine read_wfncoeffs_file
637 
638 
647  subroutine reset_wfncoeffs_position (ak, skip)
648 
649  class(scatakcoeffs), intent(in) :: ak
650  integer, optional, intent(in) :: skip
651 
652  integer :: i, ich
653 
654  ! rewind to the beginning of the K-matrix unit
655  call getset(ak % lusct, 1, 88, 'UNFORMATTED', i)
656 
657  read (ak % lusct)
658  read (ak % lusct)
659  read (ak % lusct)
660  read (ak % lusct)
661  read (ak % lusct)
662 
663  if (present(skip)) then
664  do i = 1, skip
665  do ich = 1, ak % nchan
666  read (ak % lusct)
667  read (ak % lusct)
668  end do
669  end do
670  end if
671 
672  end subroutine reset_wfncoeffs_position
673 
674 
682  subroutine get_wfncoeffs (ak, E, Re_Ak, Im_Ak, skip)
683 
684  use mpi_gbl, only: mpi_xermsg
685 
686  class(scatakcoeffs), intent(in) :: ak
687  real(wp), allocatable, intent(inout) :: Re_Ak(:, :), Im_Ak(:, :)
688  integer, optional, intent(in) :: skip
689  real(wp), intent(inout) :: E
690 
691  character(len=250) :: msg, iomsg
692 
693  integer :: i, ich, ierr
694 
695  do ich = 1, ak % nchan
696  read (ak % lusct, iostat = ierr, iomsg = iomsg) e, i, re_ak(:, ich)
697  read (ak % lusct, iostat = ierr, iomsg = iomsg) e, i, im_ak(:, ich)
698  if (ierr == iostat_end) then
699  write (msg, '(2x,a,i0,a)') 'ERROR: Unit ', ak % lusct, ' ended while reading Ak-coeffs!'
700  call mpi_xermsg('multidip_io', 'get_wfncoeffs', trim(msg), 1, 1)
701  else if (ierr /= 0) then
702  write (msg, '(2x,a,2(i0,a),a)') 'ERROR ', ierr, ' while reading Ak-coeffs file unit ', ak % lusct, ': ', iomsg
703  call mpi_xermsg('multidip_io', 'get_wfncoeffs', trim(msg), 1, 1)
704  end if
705  end do
706 
707  if (present(skip)) then
708  do i = 1, skip
709  do ich = 1, ak % nchan
710  read (ak % lusct, iostat = ierr) ! ignore EOF
711  read (ak % lusct, iostat = ierr) ! ignore EOF
712  end do
713  end do
714  end if
715 
716  end subroutine get_wfncoeffs
717 
718 
726  subroutine read_molecular_data (moldat, filename, mpiio, read_wmat2)
727 
728  use multidip_params, only: check_dipoles
729 
730  type(moleculardata), intent(inout) :: moldat
731  character(*), intent(in) :: filename
732  logical, intent(in) :: mpiio, read_wmat2
733 
734  integer(int32), allocatable :: ltarg(:), starg(:), nconat(:)
735  real(real64), allocatable :: r_points(:), cf(:, :, :)
736 
737  integer(int32) :: i, j, u, s, s1, s2, ntarg, nrg, lrang2, lamax, inast, nchmx, nstmx, lmaxp1, nfdm
738  integer(int32) :: lrgl, nspn, npty
739  integer(int64) :: offset, length
740  real(real64) :: bbloch, delta_r
741 
742  open (newunit = u, file = filename, access = 'stream', status = 'old', action = 'read')
743 
744  print '(/,3A,/)', 'Reading file "', filename, '"'
745 
746  read (u) s, s1, s2
747  length = int(s1, int64) * int(s2, int64) * wp_bytes
748  allocate (moldat % iidipy(s), moldat % ifdipy(s), moldat % dipy(s))
749  read (u) moldat % iidipy, moldat % ifdipy
750  inquire (u, pos = offset)
751  do i = 1, s
752  moldat % dipy(i) % distributed = mpiio
753  call moldat % dipy(i) % load(filename, u, offset, s1, s2)
754  offset = offset + length
755  end do
756  print '(2x,A,*(1x,I0))', '[m = -1] iidip =', moldat % iidipy
757  print '(2x,A,*(1x,I0))', ' ifdip =', moldat % ifdipy
758 
759  if (check_dipoles) then
760  do i = 1, s
761  if (sum(abs(moldat % dipy(i) % mat)) == 0) then
762  print '(/,2x,A,/)', 'WARNING: Norm of some Y dipoles is zero. Something went wrong in CDENPROP?'
763  end if
764  end do
765  end if
766 
767  read (u, pos = offset) s, s1, s2
768  length = int(s1, int64) * int(s2, int64) * wp_bytes
769  allocate (moldat % iidipz(s), moldat % ifdipz(s), moldat % dipz(s))
770  read (u) moldat % iidipz, moldat % ifdipz
771  inquire (u, pos = offset)
772  do i = 1, s
773  moldat % dipz(i) % distributed = mpiio
774  call moldat % dipz(i) % load(filename, u, offset, s1, s2)
775  offset = offset + length
776  end do
777  print '(2x,A,*(1x,I0))', '[m = 0] iidip =', moldat % iidipz
778  print '(2x,A,*(1x,I0))', ' ifdip =', moldat % ifdipz
779 
780  if (check_dipoles) then
781  do i = 1, s
782  if (sum(abs(moldat % dipz(i) % mat)) == 0) then
783  print '(/,2x,A,/)', 'WARNING: Norm of some Z dipoles is zero. Something went wrong in CDENPROP?'
784  end if
785  end do
786  end if
787 
788  read (u, pos = offset) s, s1, s2
789  length = int(s1, int64) * int(s2, int64) * wp_bytes
790  allocate (moldat % iidipx(s), moldat % ifdipx(s), moldat % dipx(s))
791  read (u) moldat % iidipx, moldat % ifdipx
792  inquire (u, pos = offset)
793  do i = 1, s
794  moldat % dipx(i) % distributed = mpiio
795  call moldat % dipx(i) % load(filename, u, offset, s1, s2)
796  offset = offset + length
797  end do
798  print '(2x,A,*(1x,I0))', '[m = +1] iidip =', moldat % iidipx
799  print '(2x,A,*(1x,I0))', ' ifdip =', moldat % ifdipx
800 
801  if (check_dipoles) then
802  do i = 1, s
803  if (sum(abs(moldat % dipx(i) % mat)) == 0) then
804  print '(/,2x,A,/)', 'WARNING: Norm of some X dipoles is zero. Something went wrong in CDENPROP?'
805  end if
806  end do
807  end if
808 
809  read (u, pos = offset) ntarg
810  print '(/,2x,A,I0)', 'ntarg = ', ntarg
811  allocate (moldat % crlv(ntarg, ntarg, 3))
812  read (u) moldat % crlv
813 
814  read (u) nrg
815  allocate (moldat % rg(nrg), moldat % lm_rg(6, nrg))
816  read (u) moldat % rg, moldat % lm_rg
817 
818  read (u) moldat % nelc, moldat % nz, lrang2, lamax, ntarg, inast, nchmx, nstmx, lmaxp1
819  read (u) moldat % rmatr, bbloch
820  allocate (moldat % etarg(ntarg), ltarg(ntarg), starg(ntarg))
821  read (u) moldat % etarg, ltarg, starg
822  read (u) nfdm, delta_r
823  allocate (moldat % r_points(nfdm + 1))
824  read (u) moldat % r_points
825  print '(2x,A,*(1x,F8.3))', 'sampling radii:', moldat % r_points
826 
827  print '(/,2x,A)', 'number of inner eigenstates per symmetry'
828 
829  allocate (nconat(ntarg), moldat % l2p(nchmx, inast), moldat % m2p(nchmx, inast), moldat % eig(nstmx, inast), &
830  moldat % wamp(inast), cf(nchmx, nchmx, lamax), moldat % ichl(nchmx, inast), &
831  moldat % mgvns(inast), moldat % stot(inast), moldat % nchan(inast), moldat % mnp1(inast), &
832  moldat % wmat2(nfdm, inast))
833 
834  inquire (u, pos = offset)
835 
836  length = int(nchmx, int64) * int(nstmx, int64) * wp_bytes
837 
838  do i = 1, inast
839 
840  read (u, pos = offset) lrgl, nspn, npty, moldat % nchan(i), moldat % mnp1(i)
841  moldat % mgvns(i) = lrgl - 1
842  moldat % stot(i) = nspn
843  print '(4x,I3,I8)', moldat % mgvns(i), moldat % mnp1(i)
844  read (u) nconat, moldat % l2p(:, i), moldat % m2p(:, i)
845  read (u) moldat % eig(:, i)
846  inquire (u, pos = offset)
847  call moldat % wamp(i) % load(filename, u, offset, nchmx, nstmx)
848  offset = offset + length
849  read (u, pos = offset) cf, moldat % ichl(:, i)
850  read (u) s1, s2
851  inquire (u, pos = offset)
852 
853  ! read or map wmat2 only when explicitly required; it is large and used only for debugging
854  if (read_wmat2) then
855  do j = 1, nfdm
856  call moldat % wmat2(j, i) % load(filename, u, offset, s1, s2)
857  offset = offset + int(s1, int64) * int(s2, int64) * wp_bytes
858  end do
859  else
860  offset = offset + int(s1, int64) * int(s2, int64) * nfdm * wp_bytes
861  end if
862 
863  end do
864 
865  do i = 1, inast
866  print '(/,2x,A,I0,A,I0,A)', 'channels in symmetry #', i, ' (IRR ', moldat % mgvns(i), '):'
867  do j = 1, moldat % nchan(i)
868  print '(2x,I4,A,I6,I3,SP,I6)', j, ':', moldat % ichl(j, i), moldat % l2p(j, i), moldat % m2p(j, i)
869  if (moldat % ichl(j, i) > ntarg) then
870  print '(4(A,I0),A)', 'Warning: Channel ', j, ' in symmetry ', moldat % mgvns(i), ' is coupled to state ', &
871  moldat % ichl(j, i), ', which is beyond the number of targets ', ntarg, ' (bug in mpi-scatci!)'
872  moldat % ichl(j, i) = ntarg
873  end if
874  end do
875  end do
876 
877  close (u)
878 
879  call setup_angular_integrals(moldat)
880 
881  end subroutine read_molecular_data
882 
883 
890  subroutine setup_angular_integrals (moldat)
891 
892  use mpi_gbl, only: mpi_xermsg
893 
894  type(moleculardata), intent(inout) :: moldat
895 
896  integer :: maxl, i, l1, m1, l2, m2, l3, m3
897 
898  maxl = max(0_int32, maxval(moldat % lm_rg))
899 
900  allocate (moldat % gaunt((maxl + 1)**2, (maxl + 1)**2, -1:1))
901 
902  moldat % gaunt = 0
903 
904  do i = 1, size(moldat % rg)
905  l1 = moldat % lm_rg(1, i); m1 = moldat % lm_rg(2, i)
906  l2 = moldat % lm_rg(3, i); m2 = moldat % lm_rg(4, i)
907  l3 = moldat % lm_rg(5, i); m3 = moldat % lm_rg(6, i)
908  if (l3 /= 1 .or. abs(m3) > 1) then
909  call mpi_xermsg('multidip_io', 'setup_angular_integrals', &
910  'Unexpected layout of the angular integral storage in molecular_data', 1, 1)
911  end if
912  moldat % gaunt(l1*(l1+1) + m1 + 1, l2*(l2+1) + m2 + 1, m3) = moldat % rg(i)
913  end do
914 
915  end subroutine setup_angular_integrals
916 
917 
926  subroutine get_diptrans (moldat, I, iidip, ifdip)
927 
928  type(moleculardata), intent(in) :: moldat
929  integer, intent(in) :: I
930  integer, allocatable, intent(inout) :: iidip(:), ifdip(:)
931 
932  if (allocated(iidip)) deallocate (iidip)
933  if (allocated(ifdip)) deallocate (ifdip)
934 
935  select case (i)
936  case (1)
937  iidip = moldat % iidipx
938  ifdip = moldat % ifdipx
939  case (2)
940  iidip = moldat % iidipy
941  ifdip = moldat % ifdipy
942  case (3)
943  iidip = moldat % iidipz
944  ifdip = moldat % ifdipz
945  end select
946 
947  end subroutine get_diptrans
948 
949 
984  subroutine apply_dipole_matrix (moldat, component, irrpair, transp, nf, nn, X, Y)
985 
986  use multidip_params, only: rone, rzero
987  use multidip_special, only: blas_dgemm => dgemm
988 
989  integer(blasint), parameter :: one = 1, zero = 0
990 
991  type(moleculardata), intent(in) :: moldat
992  integer, intent(in) :: component, irrpair, nf, nn
993  character(len=1), intent(in) :: transp
994  real(wp), intent(inout) :: X(:, :, :), Y(:, :, :)
995 
996  integer(blasint) :: lda, ldb, ldc, m, n, k, info, Xdesc(9), Xdesc2D(9), Ydesc(9), Ydesc2D(9), desc(9), gn
997  integer(blasint) :: Xlocr, Xlocc, Ylocr, Ylocc, ldX, ldY, rctx, bctx, rbksz, cbksz, myprow, mypcol, nprow, npcol
998  logical :: dist
999 
1000  real(wp), allocatable :: Xloc(:, :), Yloc(:, :)
1001  real(wp), pointer :: dips(:, :)
1002 
1003  ldb = size(x, 1)
1004  ldc = size(y, 1)
1005 
1006  m = nf
1007  n = size(x, 2) * size(x, 3)
1008  k = nn
1009 
1010  ! pick the correct inner dipole block (or its local portion if MPI-IO was used)
1011  select case (component)
1012  case (1)
1013  dist = moldat % dipx(irrpair) % distributed
1014  desc = moldat % dipx(irrpair) % desc
1015  rctx = moldat % dipx(irrpair) % row_context
1016  bctx = moldat % dipx(irrpair) % blk_context
1017  lda = size(moldat % dipx(irrpair) % mat, 1)
1018  dips => moldat % dipx(irrpair) % mat(:, :)
1019  case (2)
1020  dist = moldat % dipy(irrpair) % distributed
1021  desc = moldat % dipy(irrpair) % desc
1022  rctx = moldat % dipy(irrpair) % row_context
1023  bctx = moldat % dipy(irrpair) % blk_context
1024  lda = size(moldat % dipy(irrpair) % mat, 1)
1025  dips => moldat % dipy(irrpair) % mat(:, :)
1026  case (3)
1027  dist = moldat % dipz(irrpair) % distributed
1028  desc = moldat % dipz(irrpair) % desc
1029  rctx = moldat % dipz(irrpair) % row_context
1030  bctx = moldat % dipz(irrpair) % blk_context
1031  lda = size(moldat % dipz(irrpair) % mat, 1)
1032  dips => moldat % dipz(irrpair) % mat(:, :)
1033  end select
1034 
1035 #ifdef WITH_SCALAPACK
1036  if (dist) then
1037  ! total number of columns in X, Y (summed over all parallel images)
1038  gn = n * nprocs
1039 
1040  ! get information about the BLACS process grid
1041  call blacs_gridinfo(bctx, nprow, npcol, myprow, mypcol)
1042 
1043  ! set up descriptors for the MULTIDIP distribution of vectors X and Y (round-robin in energies)
1044  call descinit(xdesc, k, gn, ldb, n, zero, zero, rctx, ldb, info)
1045  call assert_status('Failed to set up X BLACS descriptor: ', int(info))
1046  call descinit(ydesc, m, gn, ldc, n, zero, zero, rctx, ldc, info)
1047  call assert_status('Failed to set up Y BLACS descriptor: ', int(info))
1048 
1049  ! pick a reasonable block size for good load balancing (aim at one ScaLAPACK block per process at least)
1050  rbksz = clip(min(nf, nn) / int(nprow), 1, 64)
1051  cbksz = clip(int(gn / npcol), 1, 64)
1052 
1053  ! find out the number of rows and columns in the local portion of the redistributed X matrix
1054  xlocr = numroc(k, rbksz, myprow, zero, nprow); ldx = max(one, xlocr)
1055  xlocc = numroc(gn, cbksz, mypcol, zero, npcol)
1056 
1057  ! find out the number of rows and columns in the local portion of the redistributed Y matrix
1058  ylocr = numroc(m, rbksz, myprow, zero, nprow); ldy = max(one, ylocr)
1059  ylocc = numroc(gn, cbksz, mypcol, zero, npcol)
1060 
1061  ! allocate the local portions of the redistributed X and Y matrices
1062  allocate (xloc(ldx, xlocc), yloc(ldy, ylocc))
1063 
1064  ! set up descriptors for the ScaLAPACK distribution of vectors X and Y (proper two-dimensional block-cyclic)
1065  call descinit(xdesc2d, k, gn, rbksz, cbksz, zero, zero, bctx, ldx, info)
1066  call assert_status('Failed to set up X2D BLACS descriptor: ', int(info))
1067  call descinit(ydesc2d, m, gn, rbksz, cbksz, zero, zero, bctx, ldy, info)
1068  call assert_status('Failed to set up Y2D BLACS descriptor: ', int(info))
1069 
1070  ! redistribute X -> Xloc; multiply; redistribute Yloc -> Y
1071  call pdgemr2d(k, gn, x, one, one, xdesc, xloc, one, one, xdesc2d, bctx)
1072  call pdgemm(transp, 'N', m, gn, k, rone, dips, one, one, desc, xloc, one, one, xdesc2d, rzero, yloc, one, one, ydesc2d)
1073  call pdgemr2d(m, gn, yloc, one, one, ydesc2d, y, one, one, ydesc, bctx)
1074  else
1075 #endif
1076  call blas_dgemm(transp, 'N', m, n, k, rone, dips, lda, x, ldb, rzero, y, ldc)
1077 #ifdef WITH_SCALAPACK
1078  end if
1079 #endif
1080 
1081  end subroutine apply_dipole_matrix
1082 
1083 
1090  subroutine assert_status (message, errcode)
1091 
1092  use mpi_gbl, only: mpi_xermsg
1093 
1094  character(len=*), intent(in) :: message
1095  integer, intent(in) :: errcode
1096 
1097  if (errcode /= 0) then
1098  call mpi_xermsg('multidip_io', 'assert_status', trim(message), errcode, 1)
1099  end if
1100 
1101  end subroutine assert_status
1102 
1103 
1108  integer function clip (x, a, b) result (y)
1109 
1110  integer :: x, a, b
1111 
1112  y = max(a, min(x, b))
1113 
1114  end function clip
1115 
1116 
1126  subroutine apply_boundary_amplitudes (moldat, irr, transp, X, Y)
1127 
1128  use multidip_special, only: blas_dgemm => dgemm
1129 
1130  type(moleculardata), intent(in) :: moldat
1131  integer, intent(in) :: irr
1132  character(len=1), intent(in) :: transp
1133  real(wp), intent(inout) :: X(:,:), Y(:,:)
1134 
1135  integer(blasint) :: m, n, k, lda, ldb, ldc
1136  real(wp) :: alpha = 1, beta = 0
1137  real(wp), pointer :: wamp(:, :)
1138 
1139  if (transp == 'T') then
1140  m = moldat % mnp1(irr)
1141  n = size(x, 2)
1142  k = moldat % nchan(irr)
1143  else
1144  m = moldat % nchan(irr)
1145  n = size(x, 2)
1146  k = moldat % mnp1(irr)
1147  end if
1148 
1149  lda = size(moldat % wamp(irr) % mat, 1)
1150  ldb = size(x, 1)
1151  ldc = size(y, 1)
1152 
1153  if (lda < merge(m, k, transp == 'N') .or. ldb < k .or. ldc < m) then
1154  print '(a)', 'ERROR: Incompatible matrix dimensions in apply_boundary_amplitudes'
1155  print '(7x,a,6(", ",a,1x,i0))', transp, 'm =', m, 'n =', n, 'k =', k, 'lda =', lda, 'ldb =', ldb, 'ldc =', ldc
1156  stop 1
1157  end if
1158 
1159  wamp => moldat % wamp(irr) % mat(:, :)
1160 
1161  call blas_dgemm(transp, 'N', m, n, k, alpha, wamp, lda, x, ldb, beta, y, ldc)
1162 
1163  end subroutine apply_boundary_amplitudes
1164 
1165 
1173  subroutine scale_boundary_amplitudes (moldat, irr, v, vw)
1174 
1175  type(moleculardata), intent(in) :: moldat
1176  integer, intent(in) :: irr
1177  real(wp), allocatable, intent(in) :: v(:)
1178  real(wp), allocatable, intent(inout) :: vw(:, :)
1179 
1180  integer :: k, nstat, p, nchan
1181 
1182  nstat = moldat % mnp1(irr)
1183  nchan = moldat % nchan(irr)
1184 
1185  !$omp parallel default(none) private(p, k) firstprivate(nchan, nstat, irr) shared(vw, v, moldat)
1186  !$omp do collapse(2)
1187  do p = 1, nchan
1188  do k = 1, nstat
1189  vw(k, p) = v(k) * moldat % wamp(irr) % mat(p, k)
1190  end do
1191  end do
1192  !$omp end do
1193  !$omp end parallel
1194 
1195  end subroutine scale_boundary_amplitudes
1196 
1197 
1204  subroutine write_energy_grid (escat)
1205 
1206  real(wp), intent(in) :: escat(:)
1207 
1208  integer :: u
1209 
1210  open (newunit = u, file = 'pe_energies.txt', action = 'write', form = 'formatted')
1211  write (u, '(E25.15)') escat
1212  close (u)
1213 
1214  end subroutine write_energy_grid
1215 
1216 
1223  subroutine write_partial_wave_moments (moldat, M, nesc, suffix)
1224 
1225  use mpi_gbl, only: mpi_reduce_inplace_sum_wp
1226 
1227  type(moleculardata), intent(in) :: moldat
1228  character(len=*), intent(in) :: suffix
1229  integer, intent(in) :: nesc
1230  complex(wp), allocatable, intent(in) :: M(:, :, :)
1231 
1232  complex(wp), allocatable :: val(:)
1233  real(wp), allocatable :: reval(:), imval(:)
1234 
1235  integer :: ie, irr, mgvn, u, ichan, ichlf, lf, mf, mye
1236  character(len=100) :: filename
1237 
1238  allocate (val(nesc))
1239 
1240  ! there is one file per irreducible representation and channel
1241  do irr = 1, size(moldat % mgvns)
1242  mgvn = moldat % mgvns(irr)
1243  do ichan = 1, size(m, 1)
1244  val = 0
1245  mye = 0
1246  do ie = myproc, nesc, nprocs
1247  mye = mye + 1
1248  val(ie) = m(ichan, mye, mgvn)
1249  end do
1250 
1251  ! combine data from all images to master
1252  reval = real(val)
1253  imval = aimag(val)
1254  call mpi_reduce_inplace_sum_wp(reval, nesc)
1255  call mpi_reduce_inplace_sum_wp(imval, nesc)
1256  val = cmplx(reval, imval, wp)
1257 
1258  ! the first image performs the writing
1259  if (myproc == 1 .and. any(val /= 0)) then
1260  ichlf = moldat % ichl(ichan, irr)
1261  lf = moldat % l2p(ichan, irr)
1262  mf = moldat % m2p(ichan, irr)
1263  write (filename, '(3(A,I0),A,SP,I0,3A)') 'pwdip-', mgvn, '-(', ichlf, ',', lf, ',', mf, ')', suffix, '.txt'
1264  open (newunit = u, file = filename, action = 'write', form = 'formatted')
1265  write (u, '(2E25.15)') val
1266  close (u)
1267  end if
1268  end do
1269  end do
1270 
1271  end subroutine write_partial_wave_moments
1272 
1273 
1280  subroutine write_raw_dipoles (M, chains, nesc, stem)
1281 
1282  use mpi_gbl, only: mpi_reduce_inplace_sum_wp
1283 
1284  character(len=*), intent(in) :: stem
1285  integer, allocatable, intent(in) :: chains(:, :)
1286  complex(wp), allocatable, intent(in) :: M(:, :, :, :)
1287  integer, intent(in) :: nesc
1288 
1289  character(len=100) :: filename, history
1290  character(len=1), parameter :: xyz(-1:1) = [ 'y', 'z', 'x' ]
1291  character(len=1), parameter :: sph(-1:1) = [ 'm', '0', 'p' ]
1292 
1293  complex(wp), allocatable :: val(:)
1294  real(wp), allocatable :: reval(:), imval(:)
1295 
1296  integer :: u, itarg, ntarg, ichain, nchain, ipw, npw, icomp, lf, mf, ie, mye
1297 
1298  npw = size(m, 2)
1299  nchain = size(m, 3)
1300  ntarg = size(m, 4)
1301 
1302  allocate (val(nesc))
1303 
1304  ! there is one output file per target, absorption chain and partial wave
1305  do itarg = 1, ntarg
1306  do ichain = 1, nchain
1307  do ipw = 1, npw
1308 
1309  val = 0
1310  mye = 0
1311  do ie = myproc, nesc, nprocs
1312  mye = mye + 1
1313  val(ie) = m(mye, ipw, ichain, itarg)
1314  end do
1315 
1316  ! combine data from all images to master
1317  reval = real(val)
1318  imval = aimag(val)
1319  call mpi_reduce_inplace_sum_wp(reval, nesc)
1320  call mpi_reduce_inplace_sum_wp(imval, nesc)
1321  val = cmplx(reval, imval, wp)
1322 
1323  ! the first image performs the writing
1324  if (myproc == 1 .and. any(val /= 0)) then
1325  lf = int(sqrt(real(ipw - 1, wp)))
1326  mf = ipw - lf*lf - lf - 1
1327  history = ''
1328  do icomp = 1, size(chains, 1)
1329  select case (trim(stem))
1330  case ('xyz'); history = xyz(chains(icomp, ichain)) // trim(history)
1331  case ('sph'); history = sph(chains(icomp, ichain)) // trim(history)
1332  end select
1333  end do
1334  write (filename, '(3A,I0,A,I0,A,SP,I0,A)') 'rawdip-', trim(history), '-(', itarg, ',', lf, ',', mf, ').txt'
1335  open (newunit = u, file = filename, action = 'write', form = 'formatted')
1336  write (u, '(2E25.15)') val
1337  close (u)
1338  end if
1339 
1340  end do
1341  end do
1342  end do
1343 
1344  end subroutine write_raw_dipoles
1345 
1346 
1353  subroutine write_cross_section (cs, nesc, erange, filename)
1354 
1355  use mpi_gbl, only: mpi_reduce_inplace_sum_wp
1356 
1357  character(len=*), intent(in) :: filename
1358  real(wp), intent(in) :: cs(:, :)
1359  integer, intent(in) :: nesc, erange(2)
1360 
1361  real(wp), allocatable :: csg(:, :), buffer(:)
1362 
1363  integer :: u, ie, mye, nene, ntgt
1364 
1365  ntgt = size(cs, 1)
1366  nene = size(cs, 2)
1367 
1368  ! a local copy of 'cs' for gathering data from parallel images
1369  allocate (csg(ntgt, nesc))
1370  csg = 0
1371  mye = 0
1372  do ie = myproc, nesc, nprocs
1373  mye = mye + 1
1374  csg(:, ie) = cs(:, mye)
1375  end do
1376 
1377  ! combine data from all images to master
1378  buffer = reshape(csg, [size(csg)])
1379  call mpi_reduce_inplace_sum_wp(buffer, size(buffer))
1380  csg = reshape(buffer, shape(csg))
1381 
1382  ! the first image now writes (non-zero) cross sections to file
1383  if (myproc == 1 .and. any(csg(2:, :) /= 0)) then
1384  open (newunit = u, file = filename, action = 'write', form = 'formatted')
1385  do ie = max(1, erange(1)), min(nesc, erange(2))
1386  write (u, '(*(E25.15))') csg(:, ie)
1387  end do
1388  close (u)
1389  end if
1390 
1391  end subroutine write_cross_section
1392 
1393 end module multidip_io
I/O routines used by MULTIDIP.
Definition: multidip_io.F90:29
subroutine get_kmatrix(km, kmat, skip)
Read single K-matrix from the K-matrix file.
subroutine read_bndcoeffs(bnd, Ei, lubnd, mgvn0, stot0)
Read inner bound wave function coefficients.
subroutine assert_status(message, errcode)
Check for error code.
subroutine write_raw_dipoles(M, chains, nesc, stem)
Write raw transition dipole moments.
subroutine read_wfncoeffs(ak, lusct)
Read wave function coefficients from files.
subroutine load_mapped_matrix(this, filename, u, offset, rows, cols)
Read or map a matrix from file.
subroutine write_partial_wave_moments(moldat, M, nesc, suffix)
Write partial wave moments.
subroutine get_wfncoeffs(ak, E, Re_Ak, Im_Ak, skip)
Read single Ak-matrix from the Ak-coeffs file.
subroutine reset_wfncoeffs_position(ak, skip)
Reset I/O pointer to start of Ak-coeffs.
subroutine read_kmatrix_file(km)
Read K-matrix file.
subroutine read_wfncoeffs_file(ak)
Read wave function coefficients for a single symmetry from a file.
subroutine destruct_mapped_matrix(this)
Finalize a (potentially mapped) matrix object.
subroutine scale_boundary_amplitudes(moldat, irr, v, vw)
Scale boundary amplitudes matrix by a diagonal matrix.
subroutine setup_angular_integrals(moldat)
Store the angular integrals in a more convenient shape.
subroutine get_diptrans(moldat, I, iidip, ifdip)
Return dipole transition descriptors.
subroutine write_cross_section(cs, nesc, erange, filename)
Write cross sections to a file.
integer function clip(x, a, b)
Clamp value in range.
subroutine apply_dipole_matrix(moldat, component, irrpair, transp, nf, nn, X, Y)
Multiply by dipole matrix.
subroutine reset_kmatrix_position(km, skip)
Reset I/O pointer to start of K-matrices.
subroutine apply_boundary_amplitudes(moldat, irr, transp, X, Y)
Multiply by boundary amplitudes.
integer nprocs
Definition: multidip_io.F90:49
integer myproc
Definition: multidip_io.F90:48
subroutine read_molecular_data(moldat, filename, mpiio, read_wmat2)
Read RMT molecular_data file.
subroutine read_kmatrices(km, lukmt, nkset)
Read K-matrix files.
subroutine write_energy_grid(escat)
Write photoelectron energies to file.
Hard-coded parameters of MULTIDIP.
real(wp), parameter rone
logical check_dipoles
Check that all dipole matrices in molecular_data are nonzero.
real(wp), parameter rzero
Special functions and objects used by MULTIDIP.
K-matrix file.
Definition: multidip_io.F90:58
Auxiliary data structure for matrix (potentially memory-mapped, or distributed)
Definition: multidip_io.F90:95
RMT molecular data file.
Photoionization wave function coefficients.
Definition: multidip_io.F90:75