Line data Source code
1 : !!****m* ABINIT/m_bse_io
2 : !! NAME
3 : !! m_bse_io
4 : !!
5 : !! FUNCTION
6 : !! This module provides routines to read the Bethe-Salpeter Hamiltonian from file
7 : !!
8 : !! COPYRIGHT
9 : !! Copyright (C) 2008-2026 ABINIT group (MG)
10 : !! This file is distributed under the terms of the
11 : !! GNU General Public License, see ~abinit/COPYING
12 : !! or http://www.gnu.org/copyleft/gpl.txt .
13 : !!
14 : !! SOURCE
15 :
16 : #if defined HAVE_CONFIG_H
17 : #include "config.h"
18 : #endif
19 :
20 : #include "abi_common.h"
21 :
22 : MODULE m_bse_io
23 :
24 : use, intrinsic :: iso_c_binding
25 : use defs_basis
26 : USE_MPI
27 : use m_xmpi
28 : use m_errors
29 : use m_abicore
30 : use netcdf
31 : use m_nctk
32 : use m_hdr
33 :
34 : use m_time, only : cwtime
35 : use m_fstrings, only : toupper
36 : use m_io_tools, only : open_file
37 : use m_numeric_tools, only : arth
38 : use m_special_funcs, only : gaussian
39 : use m_bs_defs, only : excparam
40 : use m_bz_mesh, only : kmesh_t
41 :
42 : implicit none
43 :
44 : #if defined HAVE_MPI1
45 : include 'mpif.h'
46 : #endif
47 :
48 : private
49 :
50 : public :: exc_read_rblock_fio ! Reads the entire resonant sub-block from file using Fortran IO.
51 : public :: exc_read_rcblock ! Reads a distributed sub-block of the excitonic Hamiltonian from file.
52 : public :: exc_fullh_from_blocks ! Initialize the specified sub-blocks of the *full* matrix (reso+anti-reso) from file.
53 : public :: rrs_of_glob ! [+1,-1,0] if (row_glob,col_glob) belongs to the [ resonant, anti-resonant, (anti)coupling block ]
54 : public :: ccs_of_glob ! [+1,-1,0] if (row_glob,col_glob) belongs to the [ coupling, anti-coupling, (anti)resonant block ]
55 : public :: offset_in_file ! Function used to describe the way the Hamiltonian is stored on disk.
56 : public :: exc_write_bshdr ! Writes the Header of the (BSR|BSC) files storing the excitonic Hamiltonian.
57 : public :: exc_read_bshdr ! Reads the Header of the (BSR|BSC) files.
58 : public :: exc_skip_bshdr ! Skip the Header of the (BSR|BSC) files. Fortran version.
59 : public :: exc_skip_bshdr_mpio ! Skip the Header of the (BSR|BSC) files. MPI-IO version.
60 : public :: exc_read_eigen ! Read selected energies and eigenvectors from the BSEIG file.
61 : public :: exc_amplitude ! Calculate the amplitude function F(w) = \sum_t |<t|exc_vec>|^2 \delta(ww- ene_t) where t is the eh transition.
62 : public :: exc_write_optme ! Writes the OME file storing the optical matrix elements
63 : public :: exc_ham_ncwrite ! Writes the hamiltonian in NETCDF format
64 : !!***
65 :
66 : CONTAINS !====================================================================
67 : !!***
68 :
69 : !----------------------------------------------------------------------
70 :
71 : !!****f* m_bse_io/exc_write_bshdr
72 : !! NAME
73 : !! exc_write_bshdr
74 : !!
75 : !! FUNCTION
76 : !! Writes the header of the (BSR|BSC) files storing the excitonic Hamiltonian.
77 : !!
78 : !! INPUTS
79 : !! funt=Fortran unit number.
80 : !! Bsp<excparam>=Structure storing the parameters of the run.
81 : !! Hdr<hdr_type>=The abinit header.
82 : !!
83 : !! OUTPUT
84 : !! Only writing
85 : !!
86 : !! SOURCE
87 :
88 22 : subroutine exc_write_bshdr(funt,Bsp,Hdr)
89 :
90 : !Arguments ------------------------------------
91 : integer,intent(in) :: funt
92 : type(excparam),intent(in) :: BSp
93 : type(hdr_type),intent(inout) :: Hdr
94 :
95 : !Local variables ------------------------------
96 : !scalars
97 : integer :: fform_1002 = 1002 ! TODO: change setup_bse so that Hdr_bse reflects the parameters of the run.
98 : integer :: ierr
99 : character(len=500) :: errmsg
100 : ! *************************************************************************
101 :
102 22 : call hdr%fort_write(funt, fform_1002, ierr)
103 22 : ABI_CHECK(ierr == 0, "hdr_fort_write returned ierr != 0")
104 22 : write(funt, err=10, iomsg=errmsg) BSp%nreh,BSp%nkbz
105 :
106 22 : return
107 :
108 : ! Handle IO Error
109 : 10 continue
110 0 : ABI_ERROR(errmsg)
111 :
112 : end subroutine exc_write_bshdr
113 : !!***
114 :
115 : !----------------------------------------------------------------------
116 :
117 : !!****f* m_bse_io/exc_read_bshdr
118 : !! NAME
119 : !! exc_read_bshdr
120 : !!
121 : !! FUNCTION
122 : !! Reads the header of the (BSR|BSC) files storing the excitonic Hamiltonian.
123 : !! and performs basilar consistency checks.
124 : !!
125 : !! INPUTS
126 : !! funt=Unit number.
127 : !! Bsp<excparam>=Structure storing the parameters of the run.
128 : !! Hdr<hdr_type>=The abinit header.
129 : !!
130 : !! OUTPUT
131 : !! fform=Integer defining the file format.
132 : !! ierr=Status error.
133 : !!
134 : !! SOURCE
135 :
136 51 : subroutine exc_read_bshdr(funt,Bsp,fform,ierr)
137 :
138 : !Arguments ------------------------------------
139 : integer,intent(in) :: funt
140 : integer,intent(out) :: fform,ierr
141 : type(excparam),intent(in) :: BSp
142 :
143 : !Local variables ------------------------------
144 : !scalars
145 : integer :: nkbz_read
146 : character(len=500) :: errmsg
147 51 : type(hdr_type) :: Hdr
148 : !arrays
149 102 : integer :: nreh_read(SIZE(BSp%nreh))
150 : ! *************************************************************************
151 :
152 51 : ierr=0
153 :
154 : ! Read the header and perform consistency checks.
155 51 : call hdr%fort_read(funt, fform, rewind=.True.)
156 51 : ABI_CHECK(fform /= 0, "hdr_fort_read returned fform == 0")
157 :
158 51 : read(funt, err=10, iomsg=errmsg) nreh_read, nkbz_read
159 51 : call Hdr%free()
160 :
161 104 : if (ANY(nreh_read /= BSp%nreh)) then
162 0 : call wrtout(std_out,"Wrong number of e-h transitions")
163 0 : ierr = ierr + 1
164 : end if
165 :
166 : return
167 :
168 0 : 10 ierr = 1
169 0 : ABI_WARNING(errmsg)
170 :
171 51 : end subroutine exc_read_bshdr
172 : !!***
173 :
174 : !----------------------------------------------------------------------
175 :
176 : !!****f* m_bse_io/exc_skip_bshdr
177 : !! NAME
178 : !! exc_skip_bshdr
179 : !!
180 : !! FUNCTION
181 : !! Skip the header of the (BSR|BSC) files storing the excitonic Hamiltonian. Fortran version.
182 : !!
183 : !! INPUTS
184 : !! funt=Unit number.
185 : !!
186 : !! OUTPUT
187 : !! ierr=Status error.
188 : !!
189 : !! SIDE EFFECTS
190 : !! Skip the header.
191 : !!
192 : !! SOURCE
193 :
194 22 : subroutine exc_skip_bshdr(funt,ierr)
195 :
196 : !Arguments ------------------------------------
197 : integer,intent(in) :: funt
198 : integer,intent(out) :: ierr
199 :
200 : !Local variables-------------------------------
201 : character(len=500) :: errmsg
202 : ! *************************************************************************
203 :
204 22 : call hdr_skip(funt,ierr)
205 44 : if (ierr/=0) RETURN
206 22 : read(funt, err=10, iomsg=errmsg)
207 :
208 22 : return
209 :
210 : ! Handle IO Error
211 : 10 continue
212 0 : ierr = 0
213 0 : ABI_WARNING(errmsg)
214 :
215 : end subroutine exc_skip_bshdr
216 : !!***
217 :
218 : !----------------------------------------------------------------------
219 :
220 : !!****f* m_bse_io/exc_skip_bshdr_mpio
221 : !! NAME
222 : !! exc_skip_bshdr_mpio
223 : !!
224 : !! FUNCTION
225 : !! Skip the header of the (BSR|BSC) files storing the excitonic Hamiltonian. MPI-IO version.
226 : !!
227 : !! INPUTS
228 : !! mpifh=MPI-IO file handler.
229 : !! at_option
230 : !!
231 : !! SIDE EFFECTS
232 : !! ehdr_offset
233 : !!
234 : !! SOURCE
235 :
236 0 : subroutine exc_skip_bshdr_mpio(mpifh,at_option,ehdr_offset)
237 :
238 : !Arguments ------------------------------------
239 : integer,intent(in) :: mpifh,at_option
240 : integer(XMPI_OFFSET_KIND),intent(inout) :: ehdr_offset
241 :
242 : !Local variables ------------------------------
243 : integer :: fform,ierr
244 : #ifdef HAVE_MPI_IO
245 : integer(XMPI_OFFSET_KIND) :: fmarker
246 : #endif
247 : ! *************************************************************************
248 :
249 0 : call hdr_mpio_skip(mpifh,fform,ehdr_offset)
250 :
251 : #ifdef HAVE_MPI_IO
252 0 : call xmpio_read_frm(mpifh,ehdr_offset,at_option,fmarker,ierr)
253 : !write(std_out,*)"fmarker last record ",fmarker
254 : #else
255 : ABI_ERROR("You should not be here")
256 : #endif
257 :
258 0 : end subroutine exc_skip_bshdr_mpio
259 : !!***
260 :
261 : !----------------------------------------------------------------------
262 :
263 : !!****f* m_bse_io/exc_read_eigen
264 : !! NAME
265 : !! exc_read_eigen
266 : !!
267 : !! FUNCTION
268 : !! Read selected energies and eigenvectors from the BSEIG file.
269 : !!
270 : !! INPUTS
271 : !! eig_fname=The name of the file storing the excitonic eigenvectors.
272 : !! hsize=Size of the Hamiltonian.
273 : !! nvec=Number of excitonic states to analyze.
274 : !! vec_idx(nvec)=List with the indices of the excitonic states sorted in ascending order.
275 : !! [Bsp]<excparam>=Structure storing the parameters of the run. If present the
276 : !! routine will perform additional consistency checks to make sure that
277 : !! the content of the file is consistent with the present run.
278 : !!
279 : !! OUTPUT
280 : !! [ene_list(nvec)]=Excitonic energies
281 : !! vec_list(hsize,nvec)=Excitonic eigenvectors.
282 : !!
283 : !! SOURCE
284 :
285 0 : subroutine exc_read_eigen(eig_fname,hsize,nvec,vec_idx,vec_list,ene_list,Bsp)
286 :
287 : !Arguments ------------------------------------
288 : !scalars
289 : integer,intent(in) :: nvec,hsize
290 : character(len=*),intent(in) :: eig_fname
291 : type(excparam),optional,intent(in) :: BSp
292 : ! arrays
293 : integer,intent(in) :: vec_idx(nvec)
294 : real(dp),optional,intent(out) :: ene_list(nvec)
295 : complex(dp),intent(out) :: vec_list(hsize,nvec)
296 :
297 : !Local variables ------------------------------
298 : !scalars
299 : integer :: eig_unt,hsize_read,neig_read,ll,vec
300 : character(len=500) :: msg,errmsg
301 : !arrays
302 : !real(dp),allocatable :: exc_ene(:)
303 0 : complex(dp),allocatable :: exc_ene_cplx(:)
304 : ! *************************************************************************
305 :
306 : ABI_UNUSED(BSp%nline)
307 :
308 0 : if (open_file(eig_fname,msg,newunit=eig_unt,form="unformatted",status="old",action="read") /= 0) then
309 0 : ABI_ERROR(msg)
310 : end if
311 :
312 0 : read(eig_unt, err=10, iomsg=errmsg)hsize_read,neig_read
313 : !write(std_out,*)hsize_read, neig_read
314 :
315 0 : if (hsize_read/=hsize) then
316 0 : write(msg,'(a,2(1x,i0))')" hsize_read/=hsize: ",hsize_read,hsize
317 0 : ABI_ERROR(msg)
318 : end if
319 :
320 : ! Read eigenvalues, ignore possibly small imaginary part.
321 0 : ABI_MALLOC(exc_ene_cplx,(neig_read))
322 0 : read(eig_unt, err=10, iomsg=errmsg) exc_ene_cplx
323 :
324 0 : if (PRESENT(ene_list)) then
325 0 : do vec=1,nvec
326 0 : ll = vec_idx(vec)
327 0 : ene_list(vec) = DBLE(exc_ene_cplx(ll))
328 : end do
329 : end if
330 0 : ABI_FREE(exc_ene_cplx)
331 :
332 0 : vec=1
333 0 : do ll=1,neig_read ! Read the selected excitons.
334 0 : if (ll==vec_idx(vec)) then
335 0 : read(eig_unt, err=10, iomsg=errmsg) vec_list(:,vec)
336 0 : if (vec==nvec) EXIT
337 0 : vec=vec+1
338 : else
339 0 : read(eig_unt, err=10, iomsg=errmsg)
340 : end if
341 : end do
342 :
343 0 : close(eig_unt, err=10, iomsg=errmsg)
344 :
345 0 : if (vec/=nvec) then
346 0 : write(msg,'(a,2(1x,i0))')" vec_idx is wrong, vec/=nvec ",vec,nvec+1
347 0 : ABI_ERROR(msg)
348 : end if
349 :
350 : return
351 :
352 : ! Handle IO-error
353 : 10 continue
354 0 : ABI_ERROR(errmsg)
355 :
356 0 : end subroutine exc_read_eigen
357 : !!***
358 :
359 : !----------------------------------------------------------------------
360 :
361 : !!****f* m_bse_io/exc_read_rcblock
362 : !! NAME
363 : !! exc_read_rcblock
364 : !!
365 : !! FUNCTION
366 : !! Reads the excitonic Hamiltonian from file
367 : !!
368 : !! INPUTS
369 : !! fname=File name.
370 : !! diago_is_real=.TRUE. if diagonal elements are real (used only if is_resonant==.TRUE.)
371 : !! nreh(nsppol)=Number of resonant transition for the two spins.
372 : !! is_resonant=Set to .TRUE. if the block is resonant.
373 : !! hsize=Dimension of the block.
374 : !! nsppol=2 for spin polarized systems. 1 otherwise.
375 : !! my_t1,my_t2=The first and the last columns of the matrix treated by this node.
376 : !! use_mpio=.TRUE. is MPI-IO routines are used.
377 : !! comm=MPI communicator.
378 : !!
379 : !! OUTPUT
380 : !! hmat(hsize,my_t1:my_t2)=The block read from file fname.
381 : !!
382 : !! TODO
383 : !! Remove Bsp
384 : !!
385 : !! SOURCE
386 :
387 30 : subroutine exc_read_rcblock(fname,Bsp,is_resonant,diago_is_real,nsppol,nreh,hsize,my_t1,my_t2,hmat,use_mpio,comm)
388 :
389 : !Arguments ------------------------------------
390 : !scalars
391 : integer,intent(in) :: comm,hsize,my_t1,my_t2,nsppol
392 : logical,intent(in) :: is_resonant,use_mpio,diago_is_real
393 : character(len=*),intent(in) :: fname
394 : type(excparam),intent(in) :: Bsp
395 : !arrays
396 : integer,intent(in) :: nreh(nsppol)
397 : complex(dp),intent(out) :: hmat(hsize,my_t1:my_t2)
398 :
399 : !Local variables ------------------------------
400 : !scalars
401 : integer,parameter :: master=0
402 : integer :: it,itp,funit,nproc,my_rank,neh1,neh2
403 : integer :: fform,my_nt
404 : integer :: row,col,block,spad,spin_dim,ierr,size_exp
405 : real(dp) :: cputime,walltime,gflops
406 : character(len=500) :: msg,errmsg
407 : !type(Hdr_type) :: bse_Hdr
408 : !arrays
409 30 : complex(dp),allocatable :: buffer_dpc(:)
410 : logical :: have_row,have_col
411 : #ifdef HAVE_MPI_IO
412 : integer :: mpierr,mpifh,ham_type,my_nel,old_type,etype,offset_err,amode
413 : integer :: irec,nrec !,ncount
414 : integer(XMPI_OFFSET_KIND) :: ehdr_offset,my_offset,my_offpad,fsize
415 30 : integer(XMPI_OFFSET_KIND),allocatable :: bsize_frecord(:)
416 : integer :: glob_sizes(2),my_cols(2), block_sizes(2,3), status(MPI_STATUS_SIZE)
417 : #endif
418 : !************************************************************************
419 :
420 30 : nproc = xmpi_comm_size(comm); my_rank= xmpi_comm_rank(comm)
421 :
422 : ! Compute the (Expected) size of the hamiltonian.
423 30 : neh1 = nreh(1)
424 30 : neh2 = neh1; if (nsppol==2) neh2=nreh(2)
425 :
426 30 : size_exp=neh1; if (nsppol==2) size_exp=SUM(nreh)
427 :
428 30 : ABI_CHECK(hsize==size_exp,"Wrong hsize")
429 30 : if (neh1/=neh2) then
430 0 : ABI_ERROR("BSE code does not support different number of transitions for the two spin channels")
431 : end if
432 :
433 30 : my_nt = my_t2-my_t1+1
434 : !hmat = HUGE(zero)
435 :
436 30 : if (.not.use_mpio) then
437 :
438 30 : if (is_resonant) then
439 30 : call wrtout(std_out,". Reading resonant block from file: "//TRIM(fname)//" using Fortran-IO")
440 : else
441 0 : call wrtout(std_out,". Reading coupling block from file: "//TRIM(fname)//" using Fortran-IO")
442 : end if
443 :
444 30 : if (open_file(fname,msg,newunit=funit,form="unformatted",status="old",action="read") /= 0) then
445 0 : ABI_ERROR(msg)
446 : end if
447 : !
448 : ! Read the header and perform consistency checks.
449 30 : call exc_read_bshdr(funit,Bsp,fform,ierr)
450 30 : ABI_CHECK(ierr==0,"Wrong BSE header")
451 : !
452 : ! Construct full excitonic Hamiltonian using symmetries.
453 30 : if (nsppol==1) then
454 30 : call cwtime(cputime,walltime,gflops,"start")
455 : !
456 90 : ABI_MALLOC(buffer_dpc,(neh1))
457 8990 : do itp=1,hsize
458 8960 : read(funit, err=10, iomsg=errmsg) buffer_dpc(1:itp)
459 : !
460 : ! Fill the upper triangle if I have this column.
461 8960 : if (itp>=my_t1 .and. itp<=my_t2) then
462 1704832 : do it=1,itp
463 1704832 : hmat(it,itp) = buffer_dpc(it)
464 : end do
465 : ! Force the diagonal to be real.
466 7424 : if (is_resonant .and.diago_is_real) hmat(itp,itp) = DBLE(hmat(itp,itp))
467 : end if
468 : !
469 : ! Reconstruct the rows below the diagonal (diagonal part is not touched here).
470 8990 : if (is_resonant) then ! Use Hermiticity.
471 1993088 : do it=1,itp-1
472 1993088 : if (it>=my_t1 .and. it<=my_t2) hmat(itp,it) = CONJG(buffer_dpc(it))
473 : end do
474 : else ! Coupling is symmetric.
475 0 : do it=1,itp-1
476 0 : if (it>=my_t1 .and. it<=my_t2) hmat(itp,it) = buffer_dpc(it)
477 : end do
478 : end if
479 : !
480 : end do ! itp
481 30 : ABI_FREE(buffer_dpc)
482 :
483 30 : call cwtime(cputime,walltime,gflops,"stop")
484 30 : write(msg,'(2(a,f9.1),a)')" Fortran-IO completed. cpu_time ",cputime,"[s], walltime ",walltime," [s]"
485 90 : call wrtout(std_out, msg, do_flush=.True.)
486 : else
487 : ! Spin polarized case.
488 : !
489 : ! The file contains
490 : ! A) The up-up and the down-down block in packed form
491 : ! (only the upper triangle is stored since the blocks are Hermitian)
492 : ! B) The entire up-down exchange block (no symmetry here)
493 : !
494 : ! A) Construct resonant blocks from the upper triangles stored on file.
495 : ! FIXME this part won't work if we have a different number of e-h pairs
496 0 : if (.not.is_resonant) then
497 0 : ABI_ERROR("exc_read_rcblock does not support coupling.")
498 : end if
499 : ! It should be checked.
500 0 : spin_dim=neh1
501 0 : do block=1,2
502 0 : ABI_MALLOC(buffer_dpc,(neh1))
503 0 : if (block==1) spad=0
504 0 : if (block==2) spad=neh1
505 0 : do itp=1,spin_dim
506 : !
507 0 : read(funit, err=10, iomsg=errmsg) buffer_dpc(1:itp)
508 : !
509 : ! Fill the upper triangle if this node treats this column
510 0 : col = itp+spad
511 0 : if (col>=my_t1 .and. col<=my_t2) then
512 0 : do it=1,itp
513 0 : row = it + spad
514 0 : hmat(row,col) = buffer_dpc(it)
515 : end do
516 : ! Force the diagonal to be real.
517 0 : if (is_resonant .and.diago_is_real) hmat(col,col) = DBLE(hmat(col,col))
518 : end if
519 : !
520 : ! Reconstruct the rows below the diagonal (diagonal part is not touched here).
521 0 : row = itp + spad
522 0 : if (is_resonant) then ! Hermitian
523 0 : do it=1,itp-1
524 0 : col = it + spad
525 0 : if (col>=my_t1 .and. col<=my_t2) hmat(row,col) = CONJG(buffer_dpc(it))
526 : end do
527 : else ! Coupling is symmetric.
528 0 : do it=1,itp-1
529 0 : col = it + spad
530 0 : if (col>=my_t1 .and. col<=my_t2) hmat(row,col) = buffer_dpc(it)
531 : end do
532 : end if
533 : !
534 : end do ! itp
535 0 : ABI_FREE(buffer_dpc)
536 : end do ! block
537 : !
538 : ! B) Kx_{down up} = Kx_{up down}^H.
539 : ! FIXME this part won't work if we have a different number of e-h pairs
540 0 : spad=neh1
541 0 : spin_dim=neh1
542 0 : ABI_MALLOC(buffer_dpc,(neh1))
543 0 : do itp=1,spin_dim
544 0 : read(funit, err=10, iomsg=errmsg) buffer_dpc(1:spin_dim)
545 0 : have_col = (spad+itp>=my_t1 .and. spad+itp<=my_t2)
546 0 : if (have_col) hmat(1:spin_dim,spad+itp) = buffer_dpc(1:spin_dim)
547 : ! Construct and store the lower block
548 0 : if (is_resonant) then ! Hermitian
549 0 : do it=1,spin_dim
550 0 : have_row = (it>=my_t1 .and. it<=my_t2)
551 0 : if (have_row) hmat(spad+itp,it) = CONJG(buffer_dpc(it))
552 : end do
553 : else ! Symmetric
554 0 : do it=1,spin_dim
555 0 : have_row = (it>=my_t1 .and. it<=my_t2)
556 0 : if (have_row) hmat(spad+itp,it) = buffer_dpc(it)
557 : end do
558 : end if
559 : end do
560 0 : ABI_FREE(buffer_dpc)
561 : end if
562 :
563 30 : close(funit)
564 :
565 : else
566 : #ifdef HAVE_MPI_IO
567 0 : if (is_resonant) then
568 0 : call wrtout(std_out,". Reading resonant block from file "//TRIM(fname)//" using MPI-IO")
569 : else
570 0 : call wrtout(std_out,". Reading coupling block from file "//TRIM(fname)//" using MPI-IO")
571 : end if
572 :
573 0 : amode=MPI_MODE_RDONLY
574 0 : call MPI_FILE_OPEN(comm,fname,amode,MPI_INFO_NULL,mpifh,mpierr)
575 0 : msg = " FILE_OPEN "//TRIM(fname)
576 0 : ABI_CHECK_MPI(mpierr,msg)
577 :
578 0 : call MPI_FILE_GET_SIZE(mpifh,fsize,mpierr)
579 : !write(std_out,*)" file size is ",fsize
580 : !
581 : ! Skip the header and find the offset for reading the matrix.
582 0 : call exc_skip_bshdr_mpio(mpifh,xmpio_collective,ehdr_offset)
583 : !
584 : ! Read my columns from file.
585 0 : old_type=MPI_DOUBLE_COMPLEX
586 0 : glob_sizes = (/hsize,hsize/); my_cols=(/my_t1,my_t2/)
587 :
588 0 : if (nsppol==1) then
589 0 : call xmpio_create_coldistr_from_fpacked(glob_sizes,my_cols,old_type,ham_type,my_offpad,offset_err)
590 : else
591 0 : ABI_WARNING("nsppol==2 => calling fp3blocks")
592 0 : write(std_out,*)"neh, hsize",neh1,neh2,hsize
593 :
594 0 : nrec=neh1+2*neh2
595 0 : ABI_MALLOC(bsize_frecord,(nrec))
596 0 : bsize_frecord(1:neh1) = (/(irec*xmpi_bsize_dpc, irec=1,neh1)/)
597 0 : bsize_frecord(neh1+1:neh1+neh2) = (/(irec*xmpi_bsize_dpc, irec=1,neh2)/)
598 0 : bsize_frecord(neh1+neh2+1:) = neh1*xmpi_bsize_dpc
599 0 : call xmpio_check_frmarkers(mpifh,ehdr_offset,xmpio_collective,nrec,bsize_frecord,ierr)
600 0 : ABI_CHECK(ierr==0,"Error in Fortran markers")
601 0 : ABI_FREE(bsize_frecord)
602 0 : ABI_COMMENT("Marker check ok")
603 0 : call xmpi_barrier(comm)
604 :
605 0 : block_sizes(:,1) = (/neh1,neh1/)
606 0 : block_sizes(:,2) = (/neh2,neh2/)
607 0 : block_sizes(:,3) = (/neh1,neh2/)
608 0 : ABI_ERROR("fp3blocks is buggy")
609 0 : call xmpio_create_coldistr_from_fp3blocks(glob_sizes,block_sizes,my_cols,old_type,ham_type,my_offpad,offset_err)
610 : end if
611 :
612 0 : if (offset_err/=0) then
613 : write(msg,"(3a)")&
614 0 : "Global position index cannot be stored in a standard Fortran integer ",ch10,&
615 0 : "Excitonic matrix cannot be read with a single MPI-IO call."
616 0 : ABI_ERROR(msg)
617 : end if
618 : !
619 : ! The offset used for reading.
620 0 : my_offset = ehdr_offset + my_offpad
621 0 : write(std_out,*)"my_offset= ",my_offset
622 :
623 0 : etype=MPI_BYTE
624 0 : call MPI_FILE_SET_VIEW(mpifh, my_offset, etype, ham_type, 'native', MPI_INFO_NULL, mpierr)
625 0 : ABI_CHECK_MPI(mpierr,"SET_VIEW")
626 :
627 : ! Release the MPI filetype.
628 0 : call MPI_TYPE_FREE(ham_type,mpierr)
629 0 : ABI_CHECK_MPI(mpierr,"TYPE_FREE")
630 :
631 0 : my_nel = my_nt*hsize
632 0 : call MPI_FILE_READ_ALL(mpifh, hmat, my_nel, MPI_DOUBLE_COMPLEX, status, mpierr)
633 0 : ABI_CHECK_MPI(mpierr,"READ_ALL")
634 :
635 : !call MPI_GET_COUNT(status, MPI_DOUBLE_COMPLEX, ncount, mpierr)
636 : !write(std_out,*)"count, my_nel ",ncount,my_nel
637 : !ABI_CHECK_MPI(mpierr,"READ_ALL")
638 : !
639 : ! Close the file.
640 0 : call MPI_FILE_CLOSE(mpifh, mpierr)
641 0 : ABI_CHECK_MPI(mpierr,"FILE_CLOSE")
642 : !
643 : ! Use the symmetries of the block to reconstruct the local buffer.
644 : ! Coupling does not require in-place symmetrization since it is symmetric.
645 0 : if (is_resonant) then
646 0 : do itp=my_t1,my_t2
647 0 : if (itp+1<=hsize) hmat(itp+1:,itp) = DCONJG(hmat(itp+1:,itp)) ! Lower triangle using Hermiticity.
648 0 : if (diago_is_real) hmat(itp,itp) = DBLE(hmat(itp,itp)) ! The diagonal is forced to be real when energies are real.
649 : end do
650 : end if
651 :
652 0 : call xmpi_barrier(comm)
653 : #else
654 : ABI_ERROR("MPI-IO support not enabled")
655 : #endif
656 : end if
657 :
658 : !BEGINDEBUG
659 : ! if ( ANY(hmat==HUGE(zero)) ) then
660 : ! write(std_out,*)"COUNT",COUNT(hmat==HUGE(zero))," hsize= ",hsize
661 : ! ABI_ERROR("Something wrong in the reading")
662 : ! end if
663 : !ENDDEBUG
664 :
665 30 : call xmpi_barrier(comm)
666 :
667 : return
668 :
669 : ! Handle IO Error
670 : 10 continue
671 0 : ABI_ERROR(errmsg)
672 :
673 0 : end subroutine exc_read_rcblock
674 : !!***
675 :
676 : !----------------------------------------------------------------------
677 :
678 : !!****f* m_bse_io/exc_fullh_from_blocks
679 : !! NAME
680 : !! exc_fullh_from_blocks
681 : !!
682 : !! FUNCTION
683 : !! Construct the matrix F H
684 : !!
685 : !! INPUTS
686 : !! funt
687 : !! nsppol
688 : !! block_type
689 : !! "Resonant"
690 : !! "Coupling"
691 : !! row_sign
692 : !! -1 to read ( R C )
693 : !! (-C* -R*)
694 : !!
695 : !! +1 to read ( R C )
696 : !! ( C* R*)
697 : !! diago_is_real=Used when block_type=resonat to specify whether the diagonal matrix elements are
698 : !! real or complex (when QP linewidth are included)
699 : !! nreh(nsppol)
700 : !! exc_size=Size of the full excitonic Hamiltonian.
701 : !!
702 : !! SIDE EFFECTS
703 : !! exc_ham(exc_size,exc_size)
704 : !!
705 : !! NOTES
706 : !!
707 : !! SOURCE
708 :
709 2 : subroutine exc_fullh_from_blocks(funt,block_type,nsppol,row_sign,diago_is_real,nreh,exc_size,exc_ham)
710 :
711 : !Arguments ------------------------------------
712 : !scalars
713 : integer,intent(in) :: funt,exc_size,nsppol,row_sign
714 : logical,intent(in) :: diago_is_real
715 : character(len=*),intent(in) :: block_type
716 : !arrays
717 : integer,intent(in) :: nreh(nsppol)
718 : complex(dp),intent(inout) :: exc_ham(exc_size,exc_size)
719 :
720 : !Local variables-------------------------------
721 : !scalars
722 : integer :: it,itp,szbuf,neh,pad_c1,pad_r1,spin_dim,spad_r,spad_c
723 : integer :: block,spad,row1,col1,row2,col2,spin_stride,ierr
724 : complex(dp) :: cttp
725 : character(len=500) :: errmsg
726 : !arrays
727 2 : complex(dp),allocatable :: cbuff_dpc(:)
728 : ! *********************************************************************
729 :
730 2 : szbuf=exc_size ! FIXME oversized!
731 2 : neh = nreh(1)
732 :
733 2 : if (nsppol==2) then
734 0 : ABI_WARNING("nsppol==2 is very experimental")
735 : end if
736 4 : if (ANY(nreh(1)/=nreh)) then
737 0 : ABI_ERROR(" different nreh are not supported")
738 : end if
739 :
740 6 : ABI_MALLOC_OR_DIE(cbuff_dpc,(exc_size), ierr)
741 : !
742 : ! The two cases nsppol==1,2 can be merged but we keep them
743 : ! separated to keep to code readable.
744 :
745 5 : SELECT CASE (toupper(block_type))
746 : CASE ("RESONANT")
747 :
748 1 : if (nsppol==1) then
749 : !
750 : ! Construct resonant block from the upper triangle stored on file.
751 385 : neh = nreh(1)
752 385 : do itp=1,neh
753 384 : read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
754 73920 : do it=1,itp-1 ! The diagonal is treated below.
755 73536 : cttp = cbuff_dpc(it)
756 73536 : exc_ham(it ,itp) = cttp ! R
757 73536 : exc_ham(itp ,it ) = CONJG(cttp) ! row_sign R*
758 73536 : exc_ham(neh+it ,neh+itp) = row_sign*CONJG(cttp)
759 73920 : exc_ham(neh+itp,neh+it ) = row_sign*cttp
760 : end do
761 385 : if (diago_is_real) then
762 384 : exc_ham(itp ,itp) = DBLE(cbuff_dpc(itp))
763 384 : exc_ham(neh+itp,neh+itp) = row_sign*DBLE(cbuff_dpc(itp))
764 : else
765 0 : exc_ham(itp,itp) = cbuff_dpc(itp)
766 0 : exc_ham(neh+itp,neh+itp) = row_sign*(CONJG(cbuff_dpc(itp)))
767 : end if
768 : end do
769 : !
770 : !
771 : else
772 : ! FIXME this part won't work if we have a different number of e-h pairs
773 0 : ABI_CHECK(ALL(nreh==nreh(1)),"Different number of transitions")
774 : ! The file contains
775 : ! A) The up-up and the down-down block in packed form
776 : ! (only the upper triangle is stored since these blocks are Hermitian)
777 : ! B) The entire up-down exchange block (no symmetry here)
778 : !
779 : ! The resonant block is given by:
780 : ! | (v'c' up) | (v'c' dwn) |
781 : ! ------------------------------ where v_{-+} = v_{+-}^H when the momentum of the photon is neglected.
782 : ! | [T-W+v]++ | v+- | (vc up) Note that v_{+-} is not Hermitian due to the presence of different spins.
783 : ! R = ------------------------------ Actually it reduces to a Hermitian matrix when the system is not spin polarized.
784 : ! | v-+ | [T-W+v]-- | (vc dwn) [T-W+v] is Hermitian provided the the QP energies are purely real.
785 : ! ------------------------------
786 : !
787 : ! *) Fill the diagonal blocks.
788 : ! only the upper triangle is stored on file.
789 : ! row1,col1 refer to the resonant block.
790 : ! row2,col2 refer to the anti-resonant block.
791 0 : do block=1,2
792 0 : if (block==1) then
793 0 : spad=0
794 0 : spin_stride=SUM(nreh)
795 : end if
796 0 : if (block==2) then
797 0 : spad=nreh(1)
798 0 : spin_stride=2*nreh(1) + nreh(2)
799 : end if
800 0 : do itp=1,nreh(block)
801 0 : read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
802 0 : col1 = itp+spad
803 0 : col2 = itp+spin_stride
804 0 : do it=1,itp-1
805 0 : cttp = cbuff_dpc(it)
806 0 : row1 = it + spad
807 0 : row2 = it + spin_stride
808 0 : exc_ham(row1,col1) = cttp ! [T-W+v]
809 0 : exc_ham(col1,row1) = CONJG(cttp)
810 0 : exc_ham(row2,col2) = row_sign*CONJG(cttp) ! row_sign [T-W+v]*
811 0 : exc_ham(col2,row2) = row_sign*cttp
812 : end do
813 0 : if (diago_is_real) then
814 0 : exc_ham(col1,col1) = DBLE(cbuff_dpc(itp))
815 0 : exc_ham(col2,col2) = row_sign*DBLE(cbuff_dpc(itp))
816 : else
817 0 : exc_ham(col1,col1) = cbuff_dpc(itp)
818 0 : exc_ham(col2,col2) = row_sign*CONJG(cbuff_dpc(itp))
819 : end if
820 : end do
821 : end do
822 : !
823 : ! Read v+- and reconstruct resonant and anti-resonat blocks.
824 : ! TODO recheck this
825 0 : pad_r1=SUM(nreh)
826 0 : pad_c1=2*nreh(1) + nreh(2)
827 :
828 0 : spin_dim=nreh(1)
829 0 : do itp=1,spin_dim
830 0 : read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:spin_dim)
831 0 : exc_ham(1:spin_dim,nreh(1)+itp) = cbuff_dpc(1:spin_dim) ! upper reso
832 0 : exc_ham(1+pad_r1:pad_r1+spin_dim,pad_c1+itp) = row_sign*CONJG(cbuff_dpc(1:spin_dim)) ! upper anti-reso
833 0 : col1 = itp+nreh(1)
834 0 : col2 = itp+(2*nreh(1) + nreh(2))
835 0 : do it=1,spin_dim
836 0 : cttp = cbuff_dpc(it)
837 0 : row1 = it
838 0 : exc_ham(col1,row1) = CONJG(cttp) ! lower reso.
839 0 : row2 = it + SUM(nreh)
840 0 : exc_ham(col2,row2) = row_sign*cttp ! lower anti-reso.
841 : end do
842 : end do
843 : end if
844 :
845 : CASE ("COUPLING")
846 : !
847 1 : if (nsppol==1) then
848 : !
849 385 : do itp=1,neh
850 384 : read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
851 74305 : do it=1,itp
852 73920 : cttp = cbuff_dpc(it)
853 73920 : exc_ham(it ,neh+itp) = cttp
854 73920 : exc_ham(itp ,neh+it ) = cttp
855 73920 : exc_ham(neh+it ,itp ) = row_sign*CONJG(cttp)
856 74304 : exc_ham(neh+itp,it ) = row_sign*CONJG(cttp)
857 : end do
858 : end do
859 : !
860 : else
861 : ! The coupling block is given by:
862 : ! | (c'v' up) | (c'v dwn) |
863 : ! ----------------------------------- where v_{-+} = v_{+-}^t when the momentum of the photon is neglected.
864 : ! | [-W+v]++ | v+- | (vc up) The entire matrix v_{+-} is stored on file.
865 : ! C = -----------------------------------
866 : ! | v-+ | [-W+v]-- | (vc dwn)
867 : ! -----------------------------------
868 : !
869 : ! *) Fill blocks that are diagonal in spin coordinates.
870 : ! row1,col1 refer to the resonat block.
871 : ! row2,col2 refer to the anti-resonant block.
872 0 : do block=1,2
873 0 : if (block==1) then
874 0 : spad_r=0
875 0 : spad_c=SUM(nreh)
876 : end if
877 0 : if (block==2) then
878 0 : spad_r=nreh(1)
879 0 : spad_c=2*nreh(1)+nreh(2)
880 : end if
881 0 : do itp=1,nreh(block)
882 0 : read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
883 0 : col1 = itp+spad_c
884 0 : row2 = itp+spad_r
885 0 : do it=1,itp-1
886 0 : cttp = cbuff_dpc(it)
887 0 : row1 = it + spad_r
888 0 : col2 = it + spad_c
889 0 : exc_ham(row1,col1) = cttp ! upper coupling
890 0 : exc_ham(row2,col2) = cttp ! lower coupling (symmetric)
891 0 : exc_ham(col1,row1) = row_sign*CONJG(cttp) ! lower anti-coupling
892 0 : exc_ham(col2,row2) = row_sign*CONJG(cttp) ! upper anti-couling
893 : end do
894 : ! TODO recheck this
895 0 : row1 = itp+spad_r
896 0 : exc_ham(row1,col1) = cbuff_dpc(itp) ! Diagonals of the block.
897 0 : col2 = itp+spad_c
898 0 : exc_ham(col2,row2) = row_sign*CONJG(cbuff_dpc(itp))
899 : end do
900 : end do
901 : !
902 : ! Read Full v+- and reconstruct resonant and anti-resonat blocks.
903 : ! TODO recheck this
904 0 : spad=2*nreh(1) + nreh(2)
905 0 : pad_r1=SUM(nreh)
906 0 : pad_c1=2*nreh(1) + nreh(2)
907 :
908 0 : spin_dim=nreh(1)
909 0 : do itp=1,spin_dim
910 0 : read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:spin_dim)
911 0 : exc_ham(1:spin_dim,spad+itp) = cbuff_dpc(1:spin_dim) ! upper block reso
912 0 : exc_ham(1+pad_r1:pad_r1+spin_dim,nreh(1)+itp) = row_sign*CONJG(cbuff_dpc(1:spin_dim)) ! upper block anti-reso
913 0 : col1 = itp+spad
914 0 : row2 = itp+nreh(1)
915 0 : do it=1,spin_dim
916 0 : cttp = cbuff_dpc(it)
917 0 : row1 = it
918 0 : exc_ham(col1,row1) = row_sign*CONJG(cttp) ! lower anti-reso.
919 0 : col2 = it + SUM(nreh)
920 0 : exc_ham(row2,col2) = cttp ! lower reso.
921 : end do
922 : end do
923 : !
924 : end if
925 :
926 : CASE DEFAULT
927 2 : ABI_ERROR("Unknown block_type: "//TRIM(block_type))
928 : END SELECT
929 :
930 2 : ABI_FREE(cbuff_dpc)
931 :
932 : return
933 :
934 : ! Handle IO Error
935 : 10 continue
936 0 : ABI_ERROR(errmsg)
937 :
938 0 : end subroutine exc_fullh_from_blocks
939 : !!***
940 :
941 : !----------------------------------------------------------------------
942 :
943 : !!****f* m_bse_io/rrs_of_glob
944 : !! NAME
945 : !! rrs_of_glob
946 : !!
947 : !! FUNCTION
948 : !! [+1,-1,0] if (row_glob,col_glob) belongs to the [ resonant, anti-resonant, (anti)coupling block ]
949 : !!
950 : !! INPUTS
951 : !!
952 : !! OUTPUT
953 : !!
954 : !! SOURCE
955 :
956 0 : pure function rrs_of_glob(row_glob,col_glob,size_glob)
957 :
958 : !Arguments ------------------------------------
959 : integer :: rrs_of_glob
960 : integer,intent(in) :: row_glob,col_glob
961 : integer,intent(in) :: size_glob(2)
962 :
963 : !Local variables ------------------------------
964 : integer :: nreh1,nreh2
965 : ! *************************************************************************
966 :
967 0 : nreh1=size_glob(1)/2 ! Matrix is square and nreh1==nreh2 but oh well.
968 0 : nreh2=size_glob(2)/2
969 :
970 0 : if (row_glob<=nreh1 .and. col_glob<=nreh2) then
971 : rrs_of_glob=+1 ! Resonant.
972 0 : else if (row_glob >nreh1 .and. col_glob >nreh2) then
973 : rrs_of_glob=-1 ! anti-Resonant.
974 : else
975 0 : rrs_of_glob=0
976 : end if
977 :
978 0 : end function rrs_of_glob
979 : !!***
980 :
981 : !----------------------------------------------------------------------
982 :
983 : !!****f* m_bse_io/ccs_of_glob
984 : !! NAME
985 : !!! ccs_of_glob
986 : !!
987 : !! FUNCTION
988 : !! [+1,-1,0] if (row_glob,col_glob) belongs to the [ coupling, anti-coupling, (anti)resonant block ]
989 : !!
990 : !! INPUTS
991 : !!
992 : !! OUTPUT
993 : !!
994 : !! SOURCE
995 :
996 0 : pure function ccs_of_glob(row_glob,col_glob,size_glob)
997 :
998 : !Arguments ------------------------------------
999 : integer :: ccs_of_glob
1000 : integer,intent(in) :: row_glob,col_glob
1001 : integer,intent(in) :: size_glob(2)
1002 :
1003 : !Local variables ------------------------------
1004 : integer :: nreh1,nreh2
1005 : ! *************************************************************************
1006 :
1007 0 : nreh1=size_glob(1)/2 ! Matrix is square and nreh1==nreh2 but oh well.
1008 0 : nreh2=size_glob(2)/2
1009 :
1010 0 : if (row_glob<=nreh1 .and. col_glob >nreh2) then ! Coupling.
1011 : ccs_of_glob = +1
1012 0 : else if (row_glob >nreh1 .and. col_glob<=nreh2) then ! anti-Coupling
1013 : ccs_of_glob = -1
1014 : else
1015 0 : ccs_of_glob = 0
1016 : end if
1017 :
1018 0 : end function ccs_of_glob
1019 : !!***
1020 :
1021 : !----------------------------------------------------------------------
1022 :
1023 : !!****f* m_bse_io/offset_in_file
1024 : !! NAME
1025 : !! offset_in_file
1026 : !!
1027 : !! FUNCTION
1028 : !! Return the offset of the matrix element (row_glob,col_glob)
1029 : !! size_glob(2) gives the number of row and column of the global matrix
1030 : !! nsblocks is the number of sublocks, used for nsppol==2 (not used if 1)
1031 : !! sub_block(2,2,nsblocks)= For each subblock the coordinates of the first and last element.
1032 : !!
1033 : !! INPUTS
1034 : !!
1035 : !! OUTPUT
1036 : !!
1037 : !! SOURCE
1038 :
1039 0 : function offset_in_file(row_glob,col_glob,size_glob,nsblocks,sub_block,bsize_elm,bsize_frm)
1040 :
1041 : !Arguments ------------------------------------
1042 : integer(XMPI_OFFSET_KIND) :: offset_in_file
1043 : integer,intent(in) :: row_glob,col_glob,nsblocks,bsize_elm,bsize_frm
1044 : integer,intent(in) :: size_glob(2),sub_block(2,2,nsblocks)
1045 :
1046 : !Local variables ------------------------------
1047 : !scalars
1048 : integer :: ii,jj,ijp_glob,swap
1049 : integer(XMPI_OFFSET_KIND) :: my_offset
1050 : ! *************************************************************************
1051 :
1052 0 : if (nsblocks==1) then
1053 0 : ii = row_glob
1054 0 : jj = col_glob
1055 0 : if (ii>size_glob(1)/2) ii = ii - size_glob(1)/2 ! Wrap the index.
1056 0 : if (jj>size_glob(2)/2) jj = jj - size_glob(2)/2
1057 0 : if (jj<ii) then ! Exchange the indices since the symmetric element is read.
1058 0 : swap = jj
1059 0 : jj = ii
1060 0 : ii = swap
1061 : end if
1062 0 : ijp_glob = ii + jj*(jj-1)/2 ! Index for packed storage mode.
1063 0 : my_offset = (ijp_glob-1)*bsize_elm + (jj-1)*2*bsize_frm
1064 : else
1065 : ABI_UNUSED(sub_block(1,1,1))
1066 0 : ABI_ERROR("nsppol==2 not coded")
1067 : end if
1068 :
1069 0 : offset_in_file = my_offset
1070 :
1071 0 : end function offset_in_file
1072 : !!***
1073 :
1074 : !----------------------------------------------------------------------
1075 :
1076 : !!****f* m_bse_io/exc_read_rblock_fio
1077 : !! NAME
1078 : !! exc_read_rblock_fio
1079 : !!
1080 : !! FUNCTION
1081 : !! Reads the resonant block from file using Fortran IO.
1082 : !!
1083 : !! INPUTS
1084 : !! funt=Fortran unit number.
1085 : !! nsppol=Number of spins
1086 : !! exc_size=Size of the resonant bock.
1087 : !! diago_is_real=.TRUE. if diagonal elements are real.
1088 : !! nreh(nsppol)=Number of resonant transitions for each spin.
1089 : !!
1090 : !! OUTPUT
1091 : !! ierr=Status error
1092 : !! exc_mat(exc_size,exc_size)=The resonant block.
1093 : !!
1094 : !! SOURCE
1095 :
1096 19 : subroutine exc_read_rblock_fio(funt,diago_is_real,nsppol,nreh,exc_size,exc_mat,ierr)
1097 :
1098 : !Arguments ------------------------------------
1099 : !scalars
1100 : integer,intent(in) :: funt,nsppol,exc_size
1101 : logical,intent(in) :: diago_is_real
1102 : integer,intent(out) :: ierr
1103 : !arrays
1104 : integer,intent(in) :: nreh(nsppol)
1105 : complex(dp),intent(out) :: exc_mat(exc_size,exc_size)
1106 :
1107 : !Local variables ------------------------------
1108 : !scalars
1109 : integer :: itp,it,block,col,row,spad
1110 : complex(dp) :: ctemp
1111 : character(len=500) :: errmsg
1112 : !arrays
1113 19 : complex(dp),allocatable :: cbuff_dpc(:)
1114 : ! *************************************************************************
1115 :
1116 19 : ierr=0
1117 :
1118 : ! Construct full resonant block using Hermiticity. File is always in double precision.
1119 57 : ABI_MALLOC(cbuff_dpc,(exc_size))
1120 :
1121 19 : if (nsppol==1) then ! Construct resonant block from the upper triangle stored on file.
1122 : !
1123 2801 : do itp=1,nreh(1)
1124 2784 : read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
1125 356208 : do it=1,itp-1 ! Diagonal is treated below.
1126 353424 : ctemp = cbuff_dpc(it)
1127 353424 : exc_mat(it,itp) = ctemp
1128 356208 : exc_mat(itp,it) = CONJG(ctemp)
1129 : end do
1130 2801 : if (diago_is_real) then
1131 2784 : exc_mat(itp,itp) = DBLE(cbuff_dpc(itp))
1132 : else
1133 0 : exc_mat(itp,itp) = cbuff_dpc(itp)
1134 : end if
1135 : end do
1136 : !
1137 : else
1138 : ! The file contains
1139 : ! A) The up-up and the down-down block in packed form
1140 : ! (only the upper triangle is stored since these blocks are Hermitian)
1141 : ! B) The entire up-down exchange block (no symmetry here)
1142 : !
1143 : ! A) Construct resonant blocks from the upper triangles stored on file.
1144 : ! FIXME this part won't work if we have a different number of e-h pairs
1145 : !ABI_CHECK(ALL(nreh==nreh(1)),"Different number of transitions")
1146 :
1147 6 : do block=1,2
1148 4 : if (block==1) spad=0
1149 2 : if (block==2) spad=nreh(1)
1150 1542 : do itp=1,nreh(block)
1151 1536 : read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:itp)
1152 1536 : col = itp+spad
1153 295680 : do it=1,itp-1 ! diagonal is treated below.
1154 294144 : ctemp = cbuff_dpc(it)
1155 294144 : row = it + spad
1156 294144 : exc_mat(row,col) = ctemp
1157 295680 : exc_mat(col,row) = CONJG(ctemp)
1158 : end do
1159 1540 : if (diago_is_real) then
1160 1536 : exc_mat(col,col) = DBLE(cbuff_dpc(itp))
1161 : else
1162 0 : exc_mat(col,col) = cbuff_dpc(itp)
1163 : end if
1164 : end do
1165 : end do
1166 : !
1167 : ! read v+- that is a matrix with shape nreh(1) X nreh(2)
1168 2 : spad=nreh(1)
1169 770 : do itp=1,nreh(2)
1170 768 : read(funt, err=10, iomsg=errmsg) cbuff_dpc(1:nreh(1))
1171 295682 : exc_mat(1:nreh(1),spad+itp) = cbuff_dpc(1:nreh(1))
1172 : end do
1173 :
1174 : end if
1175 :
1176 19 : ABI_FREE(cbuff_dpc)
1177 :
1178 : return
1179 :
1180 : ! Raise the error.
1181 : 10 continue
1182 0 : ierr = 1
1183 0 : ABI_WARNING(errmsg)
1184 :
1185 0 : end subroutine exc_read_rblock_fio
1186 : !!***
1187 :
1188 : !----------------------------------------------------------------------
1189 :
1190 : !!****f* m_bse_io/exc_amplitude
1191 : !! NAME
1192 : !! exc_amplitude
1193 : !!
1194 : !! FUNCTION
1195 : !! Calculate the amplitude function of the excitonic eigenstate |exc_vec\>
1196 : !! F(w) = \sum_t |<t|exc_vec>|^2 \delta(ww- ene_t) where the sum over t is done
1197 : !! of the full set of transitions used to construct the BS Hamiltoniam.
1198 : !!
1199 : !! INPUTS
1200 : !! Bsp<excparam>=Structure storing the parameters of the run.
1201 : !! eig_fname=The name of the file storing the excitonic eigenvectors.
1202 : !! nvec=Number of excitonic states to analyze.
1203 : !! vec_idx(nvec)=List with the indices of the excitonic states sorted in ascending order.
1204 : !! out_fname=The name of the file where the results are written.
1205 : !!
1206 : !! OUTPUT
1207 : !! Only writing.
1208 : !!
1209 : !! SOURCE
1210 :
1211 0 : subroutine exc_amplitude(Bsp,eig_fname,nvec,vec_idx,out_fname)
1212 :
1213 : !Arguments ------------------------------------
1214 : !scalars
1215 : integer,intent(in) :: nvec
1216 : character(len=*),intent(in) :: eig_fname,out_fname
1217 : type(excparam),intent(in) :: BSp
1218 : ! arrays
1219 : integer,intent(in) :: vec_idx(nvec)
1220 :
1221 : !Local variables ------------------------------
1222 : !scalars
1223 : integer :: vec,art_idx,ierr
1224 : integer :: spin,iw,it,nw,pos_w,neg_w,out_unt,rt_idx,hsize
1225 : real(dp) :: ene_rt,ampl_eh,ampl_he,xx,stdev,w_max,w_min,step
1226 : character(len=500) :: msg
1227 : !arrays
1228 0 : real(dp),allocatable :: wmesh(:),amplitude(:),ene_list(:)
1229 0 : complex(dp),allocatable :: vec_list(:,:)
1230 : ! *************************************************************************
1231 :
1232 : ! Setup of the frequency mesh for F(w).
1233 0 : w_min=greatest_real; w_max=smallest_real
1234 0 : do spin=1,BSp%nsppol
1235 0 : do it=1,BSp%nreh(spin)
1236 0 : ene_rt = Bsp%Trans(it,spin)%en
1237 0 : w_min = MIN(w_min,ene_rt)
1238 0 : w_max = MAX(w_max,ene_rt)
1239 : end do
1240 : end do
1241 :
1242 0 : step = Bsp%domega
1243 0 : if (Bsp%use_coupling==0) then
1244 0 : nw = (w_max - w_min)/step + 1
1245 0 : ABI_MALLOC(wmesh,(nw))
1246 0 : wmesh = arth(w_min,step,nw)
1247 : else
1248 : ! Both positive and negative frequencies are needed.
1249 0 : pos_w = (w_max - w_min)/step + 1
1250 0 : neg_w = pos_w; if (ABS(w_min) < tol6) neg_w=neg_w-1 ! zero should not included twice.
1251 0 : nw = neg_w + pos_w
1252 0 : ABI_MALLOC(wmesh,(nw))
1253 0 : wmesh(1:neg_w) = arth(-w_max,step,neg_w)
1254 0 : wmesh(neg_w+1:) = arth( w_min,step,pos_w)
1255 : end if
1256 : !
1257 : ! Read selected eigenvectors.
1258 0 : hsize = SUM(Bsp%nreh); if (Bsp%use_coupling>0) hsize=2*hsize
1259 :
1260 0 : ABI_MALLOC(ene_list,(nvec))
1261 0 : ABI_MALLOC_OR_DIE(vec_list,(hsize,nvec), ierr)
1262 :
1263 0 : call exc_read_eigen(eig_fname,hsize,nvec,vec_idx,vec_list,ene_list,Bsp=Bsp)
1264 :
1265 0 : ABI_FREE(ene_list)
1266 :
1267 0 : if (open_file(out_fname,msg,newunit=out_unt,form="formatted",action="write") /= 0) then
1268 0 : ABI_ERROR(msg)
1269 : end if
1270 :
1271 0 : write(out_unt,*)"# Amplitude functions F(w) = \sum_t |<t|exc_vec>|^2 \delta(ww- ene_t), w is given in eV. "
1272 0 : write(out_unt,*)"# Number of excitonic eigenvectors analyzed: ",nvec
1273 :
1274 0 : ABI_MALLOC(amplitude,(nw))
1275 0 : stdev = BSp%broad ! Broadening for the gaussian.
1276 :
1277 0 : do vec=1,nvec
1278 : !
1279 : ! amplitude(ww) = \sum_t |<t|exc_vec>|^2 \delta(ww- ene_t)
1280 0 : amplitude = zero
1281 0 : do spin=1,BSp%nsppol
1282 0 : do it=1,BSp%nreh(spin)
1283 0 : ene_rt = Bsp%Trans(it,spin)%en
1284 0 : rt_idx = it + (spin-1)*Bsp%nreh(1)
1285 0 : ampl_eh = (ABS(vec_list(rt_idx,vec)))**2
1286 0 : if (Bsp%use_coupling>0) then ! Need the index and the amplitude of the anti-resonant component.
1287 0 : art_idx = it + (spin-1)*Bsp%nreh(1) + SUM(Bsp%nreh)
1288 0 : ampl_he = (ABS(vec_list(art_idx,vec)))**2
1289 : end if
1290 : !
1291 0 : do iw=1,nw ! Accumulate
1292 0 : xx = wmesh(iw) - ene_rt
1293 0 : amplitude(iw) = amplitude(iw) + ampl_eh * gaussian(xx, stdev)
1294 0 : if (Bsp%use_coupling>0) then
1295 0 : xx = wmesh(iw) + ene_rt
1296 0 : amplitude(iw) = amplitude(iw) + ampl_he * gaussian(xx, stdev)
1297 : end if
1298 : end do
1299 : !
1300 : end do
1301 : end do
1302 : !
1303 : ! Write results
1304 0 : write(out_unt,*)"# Amplitude function F(w) for exc_vector index ",vec_idx(vec)
1305 0 : do iw=1,nw
1306 0 : write(out_unt,*)wmesh(iw)*Ha_eV,amplitude(iw)
1307 : end do
1308 0 : write(out_unt,*)"#"
1309 : end do
1310 :
1311 0 : close(out_unt)
1312 :
1313 0 : ABI_FREE(amplitude)
1314 0 : ABI_FREE(wmesh)
1315 0 : ABI_FREE(vec_list)
1316 :
1317 0 : end subroutine exc_amplitude
1318 : !!***
1319 :
1320 : !----------------------------------------------------------------------
1321 :
1322 : !!****f* m_bse_io/exc_write_optme
1323 : !! NAME
1324 : !! exc_write_optme
1325 : !!
1326 : !! FUNCTION
1327 : !! Writes the optical matrix elements in the OME.nc file.
1328 : !! Note that this is only available when NetCDF is available
1329 : !!
1330 : !! INPUTS
1331 : !! filename=filename used to write the optical matrix elements
1332 : !! minb,maxb=minimum and max band index that have been calculated.
1333 : !! nkbz=Number of points in the full Brillouin zone.
1334 : !! nsppol=Number of independent spin polarizations.
1335 : !! nq=Number of "small" q for optical limit.
1336 : !! opt_cvk=Optical matrix elements to be written
1337 : !!
1338 : !! OUTPUT
1339 : !! ierr=return status of the writing process.
1340 : !! => 0 if everything was ok
1341 : !! => -1 if NetCDF is not available
1342 : !! => 1 if NetCDF is available
1343 : !!
1344 : !! SOURCE
1345 :
1346 0 : subroutine exc_write_optme(filename,minb,maxb,nkbz,nsppol,nq,opt_cvk,ierr)
1347 :
1348 : !Arguments ------------------------------------
1349 : integer,intent(in) :: minb,maxb,nkbz,nsppol,nq
1350 : character(len=fnlen),intent(in) :: filename
1351 : complex(dp),intent(in) :: opt_cvk(minb:maxb,minb:maxb,nkbz,nsppol,nq)
1352 : integer,intent(out) :: ierr
1353 :
1354 : !Local variables ------------------------------
1355 : !scalars
1356 : integer :: ncid,cmplx_id,nband_id,nkbz_id,nsppol_id,nq_id,xyz_id
1357 : integer :: minb_id,maxb_id,ome_id,iq,is,ik,ib,jb
1358 : integer :: dimOME(6),dimKPT(2),dimQPT(2),dimSCA(0),start6(6),count6(6)
1359 : real(dp) :: complex2(2)
1360 : ! *************************************************************************
1361 :
1362 0 : ierr = 1
1363 :
1364 : !1. Create netCDF file
1365 0 : NCF_CHECK_MSG(nctk_open_create(ncid, filename, xmpi_comm_self), " create netcdf OME file")
1366 :
1367 : !2. Define dimensions
1368 0 : NCF_CHECK(nf90_def_dim(ncid,"xyz",3,xyz_id))
1369 0 : NCF_CHECK(nf90_def_dim(ncid,"cmplx",2,cmplx_id))
1370 0 : NCF_CHECK(nf90_def_dim(ncid,"nband",maxb-minb+1,nband_id))
1371 0 : NCF_CHECK(nf90_def_dim(ncid,"nkbz",nkbz,nkbz_id))
1372 0 : NCF_CHECK(nf90_def_dim(ncid,"nq",nq,nq_id))
1373 0 : NCF_CHECK(nf90_def_dim(ncid,"nsppol",nsppol,nsppol_id))
1374 :
1375 : !Dimensions for optical matrix elements
1376 0 : dimOME = (/ cmplx_id, nband_id, nband_id, nkbz_id, nsppol_id, nq_id /)
1377 : !Dimensions for kpoint positions
1378 0 : dimKPT = (/ xyz_id, nkbz_id /)
1379 : !Dimensions for qpoints for the optical limit
1380 0 : dimQPT = (/ xyz_id, nq_id /)
1381 :
1382 : !3. Define variables
1383 :
1384 : call ab_define_var(ncid, dimOME, ome_id, NF90_DOUBLE,&
1385 0 : "OME", "Values of optical matrix elements","Tobedone")
1386 :
1387 : call ab_define_var(ncid, dimSCA, minb_id, NF90_INT,"minb",&
1388 0 : "Minimum band index for the optical matrix elements", "Dimensionless")
1389 :
1390 : call ab_define_var(ncid, dimSCA, maxb_id, NF90_INT,"maxb",&
1391 0 : "Maximum band index for the optical matrix elements", "Dimensionless")
1392 :
1393 : !4. End define mode
1394 0 : NCF_CHECK(nf90_enddef(ncid))
1395 :
1396 : !5 Write scalars (minb and maxb)
1397 :
1398 0 : NCF_CHECK(nf90_put_var(ncid, minb_id, minb))
1399 0 : NCF_CHECK(nf90_put_var(ncid, maxb_id, maxb))
1400 :
1401 : !6 Write optical matrix elements
1402 :
1403 0 : do iq=1,nq
1404 0 : do is=1,nsppol
1405 0 : do ik=1,nkbz
1406 0 : do ib=minb,maxb
1407 0 : do jb=minb,maxb
1408 0 : start6 = (/ 1, ib-minb+1, jb-minb+1, ik, is, iq /)
1409 0 : count6 = (/ 2, 1, 1, 1, 1, 1 /)
1410 0 : complex2 = (/ REAL(opt_cvk(ib,jb,ik,is,iq)),AIMAG(opt_cvk(ib,jb,ik,is,iq)) /)
1411 0 : NCF_CHECK(nf90_put_var(ncid, ome_id, complex2, start = start6, count = count6))
1412 : end do
1413 : end do
1414 : end do
1415 : end do
1416 : end do
1417 :
1418 : !7 Close file
1419 0 : NCF_CHECK(nf90_close(ncid))
1420 0 : ierr = 0
1421 :
1422 0 : end subroutine exc_write_optme
1423 : !!***
1424 :
1425 : !----------------------------------------------------------------------
1426 :
1427 : !!****f* m_hexc/exc_ham_ncwrite
1428 : !! NAME
1429 : !! exc_ham_ncwrite
1430 : !!
1431 : !! FUNCTION
1432 : !! Writes the content of a hexc object to a NETCDF file
1433 : !! according to the ETSF-IO specifications.
1434 : !!
1435 : !! INPUTS
1436 : !! ncid =NC file handle
1437 : !!
1438 : !! OUTPUT
1439 : !!
1440 : !! SOURCE
1441 :
1442 0 : subroutine exc_ham_ncwrite(ncid,Kmesh,BSp,hsize,nreh,vcks2t,hreso,diag)
1443 :
1444 : !Arguments ------------------------------------
1445 : !scalars
1446 : integer,intent(in) :: ncid
1447 : integer,intent(in) :: hsize
1448 : type(kmesh_t),intent(in) :: Kmesh
1449 : type(excparam),intent(in) :: BSp
1450 : integer,intent(in) :: nreh(BSp%nsppol)
1451 : integer,target,intent(in) :: vcks2t(BSp%maxnbndv,BSp%maxnbndc,Kmesh%nbz,BSp%nsppol)
1452 : complex(dp),target,intent(in) :: hreso(hsize,hsize)
1453 : complex(dp),target,intent(in) :: diag(hsize)
1454 :
1455 : !Local variables-------------------------------
1456 : integer :: ncerr
1457 : integer :: max_nreh, sum_nreh
1458 0 : real(dp), contiguous, pointer :: r2vals(:,:),r3vals(:,:,:)
1459 : ! *************************************************************************
1460 :
1461 : ! ==============================================
1462 : ! === Write the dimensions specified by ETSF ===
1463 : ! ==============================================
1464 0 : max_nreh = MAXVAL(nreh)
1465 0 : sum_nreh = SUM(nreh)
1466 :
1467 : ncerr = nctk_def_dims(ncid, [nctkdim_t("number_of_reduced_dimensions", 3), nctkdim_t("number_of_spins", bsp%nsppol),&
1468 : nctkdim_t("number_of_kpoints", kmesh%nbz), nctkdim_t("max_number_of_valence_bands", bsp%maxnbndv),&
1469 : nctkdim_t("max_number_of_conduction_bands", bsp%maxnbndc), nctkdim_t("max_number_of_transitions", max_nreh),&
1470 0 : nctkdim_t("total_number_of_transitions", sum_nreh), nctkdim_t("cplex", 2)], defmode=.True.)
1471 0 : NCF_CHECK(ncerr)
1472 :
1473 : ncerr = nctk_def_arrays(ncid, [&
1474 : nctkarr_t('vcks2t', "i", 'max_number_of_valence_bands, max_number_of_conduction_bands, number_of_kpoints, number_of_spins'),&
1475 : nctkarr_t('hamiltonian', "dp", 'cplex total_number_of_transitions total_number_of_transitions'),&
1476 : nctkarr_t('diagonal', "dp", 'cplex total_number_of_transitions'),&
1477 : nctkarr_t('lomo', "dp", 'number_of_spins'), &
1478 : nctkarr_t('homo', "dp", 'number_of_spins'), &
1479 : nctkarr_t('lumo', "dp", 'number_of_spins'), &
1480 : nctkarr_t('humo', "dp", 'number_of_spins'), &
1481 : nctkarr_t("reduced_coordinates_of_kpoints", "dp", "number_of_reduced_dimensions, number_of_kpoints"), &
1482 : nctkarr_t("kpoint_weights", "dp", "number_of_kpoints") &
1483 0 : ])
1484 0 : NCF_CHECK(ncerr)
1485 :
1486 : ! Write data
1487 0 : NCF_CHECK(nctk_set_datamode(ncid))
1488 0 : NCF_CHECK(nf90_put_var(ncid, vid('vcks2t'), vcks2t))
1489 0 : NCF_CHECK(nf90_put_var(ncid, vid('lomo'), BSp%lomo_spin))
1490 0 : NCF_CHECK(nf90_put_var(ncid, vid('homo'), BSp%homo_spin))
1491 0 : NCF_CHECK(nf90_put_var(ncid, vid('lumo'), BSp%lumo_spin))
1492 0 : NCF_CHECK(nf90_put_var(ncid, vid('humo'), BSp%humo_spin))
1493 :
1494 0 : call c_f_pointer(c_loc(hreso(1,1)), r3vals, shape=[2, hsize, hsize])
1495 0 : NCF_CHECK(nf90_put_var(ncid, vid("hamiltonian"), r3vals))
1496 :
1497 0 : call c_f_pointer(c_loc(diag(1)), r2vals, shape=[2, hsize])
1498 0 : NCF_CHECK(nf90_put_var(ncid, vid("diag"), r2vals))
1499 :
1500 : ! Write K-points
1501 0 : NCF_CHECK(nf90_put_var(ncid, vid("reduced_coordinates_of_kpoints"), kmesh%bz))
1502 0 : NCF_CHECK(nf90_put_var(ncid, vid("kpoint_weights"), kmesh%wt))
1503 0 : NCF_CHECK(ncerr)
1504 :
1505 : contains
1506 0 : integer function vid(vname)
1507 : character(len=*),intent(in) :: vname
1508 0 : vid = nctk_idname(ncid, vname)
1509 : end function vid
1510 :
1511 : end subroutine exc_ham_ncwrite
1512 : !!***
1513 :
1514 : !----------------------------------------------------------------------
1515 :
1516 : END MODULE m_bse_io
1517 : !!***
|