mod_calconfs.F90 Source File


Source Code

!-----------------------------------------------------------------------------------------!
! Copyright (c) 2016 Peter Grünberg Institut, Forschungszentrum Jülich, Germany           !
! This file is part of kk-prime@juKKR and available as free software under the conditions !
! of the MIT license as expressed in the LICENSE file in more detail.                     !
!-----------------------------------------------------------------------------------------!


module mod_calconfs

  use mod_ioformat, only: MODE_INT, MODE_VIS
  implicit none

  private
  public :: calc_on_fsurf_inputcard, calc_on_fsurf, get_nsqa, calc_spinvalue_state, calculate_spinmixing_int, calculate_spinmixing_vis, calculate_response_functions_CRTA_int, calculate_response_functions_CRTA_vis, order_lines, calculate_dos_int

  integer, parameter :: SPCZMAX=1, SPCXY0=2, ROT_NO=0, ROT_FULLBZ=1, ROT_SPEC=2

  type :: cfg_TYPE

    integer :: N1 = 16
    integer :: lspin=-1
    integer :: lfvel=-1
    integer :: lrashba=-1
    integer :: lspinperatom=-1
    integer :: ltorqperatom=-1
    integer :: ltorq=-1
    integer :: lspinflux=-1
    integer :: lalpha=-1
    integer :: nsqa=-1
    integer :: mode=-1
    integer :: rotatemode=-1
    integer :: ilayer=-1
    double precision :: dk_fv = -1d0
    logical :: saveeigv=.false.
    logical :: simpson=.false.

    integer :: N2 = 3
    integer,          allocatable :: ispincomb(:)
    double precision, allocatable :: nvect(:,:)

  end type cfg_TYPE

  logical, save :: cfg_read=.false.

  type(cfg_type), save :: cfg




contains



  subroutine calc_on_fsurf_inputcard(inc,lattice,cluster,tgmatrx,nkpts,kpoints)

    use type_inc,       only: inc_type
    use type_data,      only: lattice_type, cluster_type, tgmatrx_type
    use mod_symmetries, only: symmetries_type, set_symmetries, rotate_kpoints, expand_visarrays, expand_areas
    use mod_read,       only: read_kpointsfile_vis, read_kpointsfile_int
    use mod_parutils,   only: distribute_linear_on_tasks
    use mod_mympi,      only: myrank, nranks, master
    use mod_ioformat,   only: filemode_vis, filemode_int, filemode_rot, filename_vtkonfs, ext_vtkxml, fmt_fn_sub_ext
    use mod_iohelp,     only: getBZvolume
    use mod_vtkxml,     only: write_pointdata_rot
#ifdef CPP_MPI
    use mpi
#endif
    implicit none

    type(inc_type),     intent(in) :: inc
    type(lattice_type), intent(in) :: lattice
    type(cluster_type), intent(in) :: cluster
    type(tgmatrx_type), intent(in) :: tgmatrx

    integer,                       intent(inout) :: nkpts
    double precision, allocatable, intent(inout) :: kpoints(:,:)

    integer                       :: nkpts1, nkpts_all1, nkpts_all
    integer,          allocatable :: kpt2irr1(:), irr2kpt1(:), kpt2irr(:), irr2kpt(:), kpt2irr_ord(:), band_indices(:)
    double precision, allocatable :: kpoints1(:,:)


    type(symmetries_type) :: symmetries
    double precision, allocatable :: fermivel(:,:), spinval(:,:,:), spinmix(:), torqval(:,:,:),&
                                   & torqval_atom(:,:,:,:), spinvec(:,:,:,:), spinvec_atom(:,:,:,:),&
                                   & spinflux_atom(:,:,:,:), alphaval(:,:,:)
    double precision, allocatable :: areas1(:), areas(:)

    integer :: nsym, ii, iatom, ierr, ikp, isqa
    double precision :: integ, dos, vabs, BZVol
    integer, allocatable :: isym(:)
    character(len=256) :: filename

    integer                       :: nscalar, nvector, iscalar, ivector
    double precision, allocatable :: scalardata(:,:), &
                                   & vectordata(:,:,:)
    character(len=256) :: filemode
    character(len=256), allocatable :: scalarstring(:), vectorstring(:)

    call set_symmetries(inc, lattice, symmetries)
    BZVol = getBZvolume(lattice%recbv)

    if(.not.cfg_read) call read_cfg()

    if(cfg%lspin/=1 .and. cfg%lfvel/=1) return

    !read in the (irreducible) k-points and apply symmetry operations to expand to full BZ
    select case (cfg%mode)

    case (MODE_VIS)
      filemode = filemode_vis
      if(cfg%rotatemode==ROT_FULLBZ)then
        call read_kpointsfile_vis(nkpts_all1, nkpts1, kpoints1, nsym, isym, kpt2irr1, irr2kpt1)
        call rotate_kpoints(symmetries%rotmat, nkpts1, kpoints1, nsym, isym, nkpts, kpoints)
        call expand_visarrays(nsym, nkpts_all1, nkpts1, kpt2irr1, irr2kpt1, kpt2irr, irr2kpt)
        nkpts_all = nsym*nkpts_all1
        deallocate(kpt2irr1, irr2kpt1,kpoints1)
      elseif(cfg%rotatemode==ROT_NO)then
        call read_kpointsfile_vis(nkpts_all, nkpts, kpoints, nsym, isym, kpt2irr, irr2kpt)
      else
        stop 'cfg%rotatemode not known!'
      end if

    case (MODE_INT)
      filemode = filemode_int
      if(cfg%rotatemode==ROT_FULLBZ)then
        call read_kpointsfile_int(nkpts1, kpoints1, areas1, nsym, isym)
        call rotate_kpoints(symmetries%rotmat, nkpts1, kpoints1, nsym, isym, nkpts, kpoints)
        call expand_areas(nsym,nkpts1,areas1,areas)
        deallocate(areas1,kpoints1)
      elseif(cfg%rotatemode==ROT_NO)then
        call read_kpointsfile_int(nkpts, kpoints, areas, nsym, isym)
      else
        stop 'cfg%rotatemode not known!'
      end if

    case default; stop 'case not known in select case (cfg%mode)'
    end select

    if(cfg%rotatemode==ROT_FULLBZ)then
      !redefine symmetries (set to unit transformation only)
      nsym = 1
      deallocate(isym)
      allocate(isym(nsym))
      isym = (/ 1 /)
    end if

    !calculate the properties
    nvector=0
    nscalar=0

    if(cfg%lfvel==1)then
      nvector=nvector+1
      allocate(fermivel(3,nkpts), STAT=ierr)
      if(ierr/=0) stop 'Problem allocating fermivel'
    endif!cfg%lfvel==1

    if(cfg%lalpha==1)then
      nvector=nvector+1
      allocate(alphaval(3,inc%ndegen,nkpts), STAT=ierr)
      if(ierr/=0) stop 'Problem allocating alphaval'
    endif!cfg%lalpha==1

    if(cfg%lspin==1)then
      nscalar=nscalar+cfg%nsqa
      nvector=nvector+cfg%nsqa
      allocate( spinval(inc%ndegen,cfg%nsqa,nkpts),   &
              & spinvec(3,inc%ndegen,cfg%nsqa,nkpts), &
              & STAT=ierr                             )
      if(ierr/=0) stop 'Problem allocating spinval and spinvec'
    endif!cfg%lspin==1

    if(cfg%lspinperatom==1)then
      nvector = nvector+inc%natypd
      allocate( spinvec_atom(3,inc%natypd,inc%ndegen,nkpts), STAT=ierr )
      if(ierr/=0) stop 'Problem allocating spinvec_atom etc.'
    endif!cfg%lspinperatom==1

    if(cfg%ltorq==1)then
      nvector = nvector+1
      allocate(torqval(3,inc%ndegen,nkpts), STAT=ierr)
      if(ierr/=0) stop 'Problem allocating torqval'
    endif!cfg%ltorq==1

    if(cfg%ltorqperatom==1)then
      nvector = nvector+inc%natypd
      allocate( torqval_atom(3,inc%natypd,inc%ndegen,nkpts), STAT=ierr )
      if(ierr/=0) stop 'Problem allocating torqval_atom'
    endif!cfg%ltorqperatom==1

    if(cfg%lspinflux==1)then
      nvector = nvector+inc%natypd
      allocate( spinflux_atom(3,inc%natypd,inc%ndegen,nkpts), STAT=ierr )
      if(ierr/=0) stop 'Problem allocating spinflux_atom'
    endif!cfg%lspinflux==1

    call calc_on_fsurf( inc,lattice,cluster,tgmatrx,nkpts,kpoints,                       &
                      & fermivelocity=fermivel,spinvalue=spinval,save_eigv=cfg%saveeigv, &
                      & spinvec=spinvec,spinvec_atom=spinvec_atom,torqvalue=torqval,     &
                      & torqvalue_atom=torqval_atom,spinflux_atom=spinflux_atom,         &
                      & alphavalue=alphaval                                              )

    allocate( scalarstring(nscalar), vectorstring(nvector), STAT=ierr)
    if(ierr/=0) stop 'Problem allocating scalarstring etc.'


    !save the calculated properties to a file
    if(cfg%lfvel==1   .and. myrank==master) call save_fermivelocity(trim(filemode), nkpts, fermivel, nsym, isym)
    if(cfg%lalpha==1  .and. myrank==master) call save_alpha(trim(filemode), nkpts, inc%ndegen, alphaval, nsym, isym)
    if(cfg%lfvel==1   .and. myrank==master .and. cfg%mode==MODE_INT) call calculate_and_save_weights(nkpts,nsym,isym,areas,fermivel)
    if(cfg%lspin==1   .and. myrank==master)then
       call save_spinvalue(trim(filemode), nkpts, cfg%nsqa, inc%ndegen, cfg%ispincomb, cfg%nvect, spinval, nsym, isym)
       call save_spinvec  (trim(filemode), nkpts, cfg%nsqa, inc%ndegen, cfg%ispincomb, cfg%nvect, spinvec, nsym, isym)
    end if!cfg%lspin==1 .and. myrank==master
    if(cfg%lspinperatom==1 .and. myrank==master) call save_spinvec_atom(trim(filemode), nkpts, inc%ndegen, inc%natypd, spinvec_atom, nsym, isym)
    if(cfg%ltorq==1        .and. myrank==master) call save_torqvalue(trim(filemode), nkpts, inc%ndegen, torqval, nsym, isym)
    if(cfg%ltorqperatom==1 .and. myrank==master) call save_torqvalue_atom(trim(filemode), nkpts, inc%ndegen, inc%natypd, torqval_atom, nsym, isym)
    if(cfg%lspinflux==1    .and. myrank==master) call save_spinflux_atom(trim(filemode), nkpts, inc%ndegen, inc%natypd, spinflux_atom, nsym, isym)


    !calculate averages
    if(myrank==master .and. cfg%lfvel==1 .and. cfg%lspin==1) then

      allocate(spinmix(cfg%nsqa), STAT=ierr)
      if(ierr/=0) stop 'Problem allocating spinmix'

      if(cfg%mode==MODE_INT) call calculate_spinmixing_int(nsym,inc%ndegen,cfg%nsqa,nkpts,areas,fermivel,spinval,spinmix,dos,.true.,BZVol)
      if(cfg%mode==MODE_VIS) call calculate_spinmixing_vis(nsym,inc%ndegen,cfg%nsqa,nkpts,nkpts_all,kpt2irr,kpoints,fermivel,spinval,spinmix,dos,.true.,BZVol,inc%nBZdim)

    elseif(myrank==master .and. cfg%lfvel==1 .and. cfg%lspin==0) then

      if(cfg%mode==MODE_INT) call calculate_dos_int(nsym,isym,symmetries%rotmat,lattice%alat,BZVol,nkpts,areas,fermivel,inc%nBZdim)
      if(cfg%mode==MODE_VIS) call calculate_dos_vis(nsym,nkpts,nkpts_all,kpt2irr,kpoints,fermivel,dos,.true.,BZVol)

    end if

!    if(myrank==master .and. cfg%lfvel==1 .and. cfg%ltorq==1) then
    if(myrank==master.and.cfg%lfvel==1) then
      if(cfg%mode==MODE_INT) call calculate_response_functions_CRTA_int(nsym,isym,symmetries%rotmat,lattice%alat,BZVol,inc%ndegen,inc%natypd,nkpts,areas,fermivel,torqval,torqval_atom,spinvec_atom,spinflux_atom)
!BZcomment: order changed to avoid simpson=T and 3D-case
      if(cfg%mode==MODE_VIS)then
        if(cfg%simpson .and. inc%nBZdim==2)then
          write(*,*) 'Simpson rule is implemented only for torkance and damping. Only these quantities will be computed.'
          call calculate_torkance_CRTA_vis_simpson2D(nsym,isym,symmetries%rotmat,lattice%alat,BZVol,inc%ndegen,nkpts,nkpts_all,kpt2irr,irr2kpt,kpoints,fermivel,torqval)
        else!cfg%simpson==.true.
          if(cfg%simpson) write(*,*) 'Simpson rule is not implemented for inc%nBZdim =/= 2. Taking standard (=linear) integration.'
          call calculate_response_functions_CRTA_vis(inc%nBZdim,nsym,isym,symmetries%rotmat,lattice%alat,BZVol,inc%ndegen,inc%natypd,nkpts,nkpts_all,kpt2irr,irr2kpt,kpoints,fermivel,torqval,torqval_atom,spinvec_atom,spinflux_atom)
!          call calculate_response_functions_CRTA_vis(inc%nBZdim,nsym,isym,symmetries%rotmat,lattice%alat,BZVol,inc%ndegen,inc%natypd,nkpts,nkpts_all,kpt3irr,irr2kpt,kpoints,alphaval(:,1,:),torqval,torqval_atom,spinvec_atom,spinflux_atom)
        end if!cfg%simpson==.true.
      end if!cfg%mode==MODE_VIS
    end if!myrank==master

    !output 3D visualization data
    if(myrank==master .and. cfg%mode==MODE_VIS .and. inc%nBZdim==3) then

      !===================================================================
      !allocate arrays
      if(nvector>0) then
        allocate(vectordata(3,nkpts,nvector), STAT=ierr)
        if(ierr/=0) stop 'Problem allocating vectordata'
      end if

      if(nscalar>0) then
        allocate(scalardata(nkpts,nscalar), STAT=ierr)
        if(ierr/=0) stop 'Problem allocating scalardata'
      end if
      !===================================================================

      iscalar=0
      ivector=0

      !===================================================================
      if(cfg%lfvel==1) then
        ivector = ivector+1
        vectordata(:,:,ivector) = fermivel
        vectorstring(ivector) = 'fvelocity'
      end if!cfg%lfvel
      !===================================================================

      !===================================================================
      if(cfg%lalpha==1) then
        ivector = ivector+1
        vectordata(:,:,ivector) = alphaval(:,1,:)
        vectorstring(ivector) = 'alpha'
      end if!cfg%lalpha
      !===================================================================


      !===================================================================
      if(cfg%lspin==1)then


        !*****************************!
        !*** save scalar spinvalue ***!
        if(inc%ndegen==2) then
          do isqa=1,cfg%nsqa
            iscalar = iscalar+1
            scalardata(:,iscalar) = (1d0-spinval(1,isqa,:))/2
            write(scalarstring(iscalar),'(A,I0)') 'Eyaf_',isqa
          end do!isqa
        else!inc%ndegen==2
          do isqa=1,cfg%nsqa
            iscalar = iscalar+1
            scalardata(:,iscalar) = spinval(1,isqa,:)
            write(scalarstring(iscalar),'(A,I0)') 'Spin_',isqa
          end do!isqa
        end if!inc%ndegen==2
        !*** save scalar spinvalue ***!
        !*****************************!


        !************************!
        !*** save spin vector ***!
        do isqa=1,cfg%nsqa
          ivector = ivector+1
          vectordata(:,:,ivector) = spinvec(:,1,isqa,:)
          write(vectorstring(ivector),'(A,I0)') 'Spinv_',isqa
        end do!isqa
        !*** save spin vector ***!
        !************************!

      end if!cfg%lspin
      !===================================================================



      !===================================================================
      if(cfg%lspinperatom==1)then
        do iatom=1,inc%natyp
          ivector = ivector+1
          vectordata(:,:,ivector) = spinvec_atom(:,iatom,1,:)
          write(vectorstring(ivector),'(A,I0)') 'Spinvec_atom_', iatom
        end do!iatom
      end if!cfg%lspinperatom==1
      !===================================================================



      !===================================================================
      if(cfg%ltorq==1)then
        ivector = ivector+1
        vectordata(:,:,ivector) = torqval(:,1,:)
        vectorstring(ivector) = 'torq'
      end if!cfg%ltorq==1
      !===================================================================


      !===================================================================
      if(cfg%ltorqperatom==1)then
        do iatom=1,inc%natyp
          ivector = ivector+1
          vectordata(:,:,ivector) = torqval_atom(:,iatom,1,:)
          write(vectorstring(ivector),'(A,I0)') 'torq_atom_', iatom
        end do!iatom
      end if!cfg%ltorqperatom==1
      !===================================================================

      !===================================================================
      if(cfg%lspinflux==1)then
        do iatom=1,inc%natyp
          ivector = ivector+1
          vectordata(:,:,ivector) = spinflux_atom(:,iatom,1,:)
          write(vectorstring(ivector),'(A,I0)') 'spinflux_atom_', iatom
        end do!iatom
      end if!cfg%lspinflux==1
      !===================================================================

      write(filename,fmt_fn_sub_ext) filename_vtkonfs, filemode_rot, ext_vtkxml
      call write_pointdata_rot( trim(filename),nkpts,kpoints,   &
                              & nscalar,scalardata,scalarstring,&
                              & nvector,vectordata,vectorstring,&
                              & nsym,symmetries%rotmat,isym,    &
                              & nkpts_all, kpt2irr              )

    end if!myrank==master .and. cfg%mode==MODE_VIS

  end subroutine calc_on_fsurf_inputcard





  subroutine calc_on_fsurf(inc,lattice,cluster,tgmatrx,nkpts,kpoints,fermivelocity,spinvalue,save_eigv,spinvec,spinvec_atom,torqvalue,torqvalue_atom,spinflux_atom,alphavalue)

    use type_inc,       only: inc_type
    use type_data,      only: lattice_type, cluster_type, tgmatrx_type
    use mod_symmetries, only: symmetries_type
    use mod_parutils,   only: distribute_linear_on_tasks
    use mod_mympi,      only: myrank, nranks, master
    use mod_kkrmat,     only: compute_kkr_eigenvectors2
    use mod_mathtools,  only: findminindex, bubblesort
    use mod_ioformat,   only: filename_eigvect, filemode_int, filemode_vis
#ifdef CPP_MPI
    use mod_iohelp,     only: open_mpifile_setview, close_mpifile
    use mpi
#endif
    implicit none

    type(inc_type),     intent(in) :: inc
    type(lattice_type), intent(in) :: lattice
    type(cluster_type), intent(in) :: cluster
    type(tgmatrx_type), intent(in) :: tgmatrx

    integer,          intent(in) :: nkpts
    double precision, intent(in) :: kpoints(3,nkpts)
    double precision, allocatable, intent(inout) :: fermivelocity(:,:),&!fermivelocity(3,nkpts),&
                                   & spinvalue(:,:,:),       &!spinvalue(inc%ndegen,cfg%nsqa,nkpts),&
                                   & spinvec(:,:,:,:),       &!spinvec(3,inc%ndegen,cfg%nsqa,nkpts),&
                                   & spinvec_atom(:,:,:,:),  &!spinvec_atom(3,inc%natypd,inc%ndegen,nkpts),  &
                                   & torqvalue(:,:,:),       &!torqvalue(3,inc%ndegen,nkpts),                &
                                   & torqvalue_atom(:,:,:,:),&!torqvalue_atom(3,inc%natypd,inc%ndegen,nkpts),&
                                   & spinflux_atom(:,:,:,:), &!spinflux_atom(3,inc%natypd,inc%ndegen,nkpts), &
                                   & alphavalue(:,:,:)        !alphavalue(3,inc%ndegen,nkpts)
    logical,          intent(in), optional  :: save_eigv
!   double complex,   intent(out), optional :: eigenvectors(inc%lmmaxso,inc%natypd,inc%ndegen,cfg%nsqa,nkpts)

    double precision, allocatable :: fermivel_tmp(:,:),&
                                   & spinval_tmp(:,:,:),&
                                   & spinvec_tmp(:,:,:,:),&
                                   & spinvec_atom_tmp(:,:,:,:),&
                                   & torqval_tmp(:,:,:),       &
                                   & torqval_atom_tmp(:,:,:,:),&
                                   & spinflux_atom_tmp(:,:,:,:),&
                                   & alphaval_tmp(:,:,:)

    integer :: nkpt, ioff, ntot_pT(0:nranks-1), ioff_pT(0:nranks-1)
    double precision :: kpoint(3)

    integer          :: lm_fs, lm_fs2
    double precision, allocatable :: spinvec_tmp1(:,:,:),      &!spinvec_tmp1(3,inc%ndegen,cfg%nsqa),        &
                                   & spinvec_atom_tmp1(:,:,:), &!spinvec_atom_tmp1(3,inc%natypd,inc%ndegen), &
                                   & torqval_tmp1(:,:),        &!torqval_tmp1(3,inc%ndegen),                 &
                                   & torqval_atom_tmp1(:,:,:), &!torqval_atom_tmp1(3,inc%natypd,inc%ndegen), &
                                   & spinflux_atom_tmp1(:,:,:),&!spinflux_atom_tmp1(3,inc%natypd,inc%ndegen),&
                                   & alphaval_tmp1(:,:)         !alphaval_tmp1(3,inc%ndegen) 

    double complex   :: eigwEF(inc%almso),           &
                      & LVeigEF(inc%almso,inc%almso),&
                      & RVeigEF(inc%almso,inc%almso),&
                      & rveig(inc%almso,inc%ndegen)

    integer          :: printstep, ikp, ierr, i3dim(3), itmp, irecv(0:nranks-1), idispl(0:nranks-1)
    integer          :: indsort(inc%almso)
    double precision :: deigsort(inc%almso)
    character(len=256) :: filename

    logical :: l_save_eigv
#ifdef CPP_MPI
    integer :: fh_eigv, irveigel, dimens(4)
    double complex, allocatable :: rveigrot(:,:,:,:)
    integer :: mpistatus(MPI_STATUS_SIZE)
#endif

    !Checks
    if(.not.cfg_read)                                         stop 'cfg not read when entering calc_on_fsurf'
    if(allocated(torqvalue).and.cfg%nsqa>1)                     stop 'cfg%nsqa must be 1 if torquevalue is present in calc_on_fsurf'
    if(allocated(torqvalue).and..not.inc%ltorq)                 stop 'TBKKR_torq-file not present'
    if(allocated(spinvalue).and..not.inc%lrhod)                 stop 'TBKKR_rhod-file not present'
    if(allocated(torqvalue).and.(.not.allocated(spinvalue)))      stop 'For torqvalue also spinvalue must be present in calc_on_fsurf'
    if(allocated(spinvec).and.(.not.allocated(spinvalue)))        stop 'For spinvec also spinvalue must be present in calc_on_fsurf'
    if(allocated(spinvec_atom).and.(.not.allocated(spinvalue)))   stop 'For spinvec_atom also spinvalue must be present in calc_on_fsurf'
    if(allocated(torqvalue_atom).and.(.not.allocated(torqvalue))) stop 'For torqvalue_atom also torqvalue must be present in calc_on_fsurf'
    if(allocated(spinflux_atom).and..not.inc%lspinflux)         stop 'TBkkr_spinflux-file not present'
    if(cfg%lrashba==1 .and. cfg%nsqa>1)                       stop 'cfg%nsqa must be 1 if cfg%lrashba=1 in calc_on_fsurf'
    if(allocated(spinvec_atom) .and. cfg%nsqa>1)                stop 'cfg%nsqa must be 1 for spinvec_atom in calc_on_fsurf'
    if(allocated(alphavalue).and..not.inc%lalpha)               stop 'TBkkr_alpha-file not present'

    !Parallelize
    call distribute_linear_on_tasks(nranks,myrank,master,nkpts,ntot_pT,ioff_pT,.true.)
    nkpt = ntot_pT(myrank)
    ioff = ioff_pT(myrank)

    !flag whether eigenvalues shall be saved to file
    l_save_eigv = .false.
#ifdef CPP_MPI
    if(present(save_eigv))then
      if(save_eigv) l_save_eigv = .true.
    else 
      l_save_eigv = cfg%saveeigv
    end if
#endif

    !allocate task-local arrays
    if(allocated(fermivelocity))then
      allocate( fermivel_tmp(3,nkpt), STAT=ierr )
      if(ierr/=0) stop 'Problem allocating fermivel_tmp'
      fermivelocity = 0d0
      fermivel_tmp  = 0d0
    end if

    if(allocated(spinvalue))then
      allocate( spinval_tmp(inc%ndegen,cfg%nsqa,nkpt), STAT=ierr )
      if(ierr/=0) stop 'Problem allocating spinval_tmp'
      spinvalue   = 0d0
      spinval_tmp = 0d0
    end if

    if(allocated(spinvec))then
      allocate( spinvec_tmp(3,inc%ndegen,cfg%nsqa,nkpt), &
              & spinvec_tmp1(3,inc%ndegen,cfg%nsqa), STAT=ierr )
      if(ierr/=0) stop 'Problem allocating spinvec_tmp'
      spinvec      = 0d0
      spinvec_tmp  = 0d0
      spinvec_tmp1 = 0d0
    end if

    if(allocated(spinvec_atom))then
      allocate( spinvec_atom_tmp(3,inc%natypd,inc%ndegen,nkpt), &
              & spinvec_atom_tmp1(3,inc%natypd,inc%ndegen), STAT=ierr )
      if(ierr/=0) stop 'Problem allocating spinvec_atom_tmp'
      spinvec_atom      = 0d0
      spinvec_atom_tmp  = 0d0
      spinvec_atom_tmp1 = 0d0
    end if

    if(allocated(torqvalue))then
      allocate( torqval_tmp(3,inc%ndegen,nkpt), &
              & torqval_tmp1(3,inc%ndegen),STAT=ierr )
      if(ierr/=0) stop 'Problem allocating torqval_tmp'
      torqvalue    = 0d0
      torqval_tmp  = 0d0
      torqval_tmp1 = 0d0
    end if

    if(allocated(torqvalue_atom))then
      allocate( torqval_atom_tmp(3,inc%natypd,inc%ndegen,nkpt), &
              & torqval_atom_tmp1(3,inc%natypd,inc%ndegen), STAT=ierr )
      if(ierr/=0) stop 'Problem allocating torqval_atom_tmp'
      torqvalue_atom    = 0d0
      torqval_atom_tmp  = 0d0
      torqval_atom_tmp1 = 0d0
    end if

    if(allocated(spinflux_atom))then
      allocate( spinflux_atom_tmp(3,inc%natypd,inc%ndegen,nkpt), &
              & spinflux_atom_tmp1(3,inc%natypd,inc%ndegen), STAT=ierr )
      if(ierr/=0) stop 'Problem allocating spinflux_atom_tmp'
      spinflux_atom      = 0d0
      spinflux_atom_tmp  = 0d0
      spinflux_atom_tmp1 = 0d0
    end if

    if(allocated(alphavalue))then
      allocate( alphaval_tmp(3,inc%ndegen,nkpt), &
              & alphaval_tmp1(3,inc%ndegen), STAT=ierr )
      if(ierr/=0) stop 'Problem allocating alphaval_tmp'
      alphavalue    = 0d0
      alphaval_tmp  = 0d0
      alphaval_tmp1 = 0d0
    end if


#ifdef CPP_MPI
    !open the mpi-io file to store the eigenvector
    if(l_save_eigv)then
      allocate( rveigrot(inc%lmmaxso,inc%natypd,inc%ndegen,cfg%nsqa), STAT=ierr ) 
      if(ierr/=0) stop 'Problem allocating rveigrot'
      dimens = (/ inc%lmmaxso,inc%natypd,inc%ndegen,cfg%nsqa /)
      irveigel = product(dimens)
      if(cfg%mode==MODE_INT) write(filename,'(A,A)') filename_eigvect, filemode_int
      if(cfg%mode==MODE_VIS) write(filename,'(A,A)') filename_eigvect, filemode_vis
      call open_mpifile_setview( trim(filename), 'write', 4, dimens, ntot_pT, MPI_DOUBLE_COMPLEX, &
                               & myrank, nranks, MPI_COMM_WORLD, fh_eigv                          )
    end if!l_save_eigv
#endif

    !******************************************!
    !*************** B E G I N ****************!
    !******************************************!
    !*** (parallelized) loop over FS points ***!
    !******************************************!
    printstep = nkpt/50
    if(printstep==0) printstep=1
    !print header of statusbar
    if(myrank==master) write(*,'("Loop over points:|",5(1X,I2,"%",5X,"|"),1X,I3,"%")') 0, 20, 40, 60, 80, 100
    if(myrank==master) write(*,FMT=190) !beginning of statusbar
    do ikp=1,nkpt
      !update statusbar
      if(mod(ikp,printstep)==0 .and. myrank==master) write(*,FMT=200)

      kpoint = kpoints(:,ikp+ioff)

      !===============================================================!
      !=== find the eigenvector and eigenvalue at the fermi energy ===!
      !===============================================================!
      call compute_kkr_eigenvectors2( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
                                    & tgmatrx%tmat(:,:,1), kpoint,                 &
                                    & eigwEF, LVeigEF, RVeigEF                     )
      deigsort = abs(eigwEF)
      call findminindex(inc%almso, deigsort, lm_fs)
!     write(*,'(A,2ES25.16)') 'minimal eigenvector=', eigwEF(lm_fs)



      !====================================!
      !=== Calculate the fermi-velocity ===!
      !====================================!
      if(allocated(fermivelocity))then

        call calc_fermivel( inc,lattice,cluster,tgmatrx,kpoint,   &
                              & eigwEF(lm_fs), LVeigEF(:,lm_fs),      &
                              & RVeigEF(:,lm_fs), fermivel_tmp(:,ikp) )

      end if!present(fermivelocity)



      !============================================!
      !===   Calculate the expectation values   ===!
      !============================================!

      if(allocated(spinvalue).or.allocated(spinvec).or.allocated(spinvec_atom).or.&
        &allocated(torqvalue).or.allocated(torqvalue_atom).or.allocated(alphavalue))then
        !copy the band
        rveig(:,1) = RVeigEF(:,lm_fs)

        !find degenerate band for degnerate cases
        if(inc%ndegen==2)then
          deigsort = abs(eigwEF-eigwEF(lm_fs))
          call bubblesort(inc%almso, deigsort, indsort)
          lm_fs2 = indsort(2)
          rveig(:,2) = RVeigEF(:,lm_fs2)
        end if

#ifdef CPP_MPI
        if(l_save_eigv)then
          call calc_spinvalue_state_generalized( inc, tgmatrx, rveig, &
                                     & spinval_tmp(:,:,ikp),          &
                                     & spinvec_tmp1,                  &
                                     & spinvec_atom_tmp1,             &
                                     & torqval_tmp1,                  &
                                     & torqval_atom_tmp1,             &
                                     & spinflux_atom_tmp1,            &
                                     & alphaval_tmp1,                 &
                                     & eigvect_rot=rveigrot           )
          call MPI_File_write( fh_eigv, rveigrot, irveigel,        &
                             & MPI_DOUBLE_COMPLEX, mpistatus, ierr )

        else!l_save_eigv
#endif
          call calc_spinvalue_state_generalized( inc, tgmatrx, rveig,  &
                                     & spinval_tmp(:,:,ikp),             &
                                     & spinvec=spinvec_tmp1,             &
                                     & spinvec_atom=spinvec_atom_tmp1,   &
                                     & torq_value=torqval_tmp1,          &
                                     & torq_value_atom=torqval_atom_tmp1,&
                                     & spinflux_atom=spinflux_atom_tmp1, &
                                     & alpha_value=alphaval_tmp1         )
#ifdef CPP_MPI
        end if!l_save_eigv
#endif
        if(allocated(spinvec))        spinvec_tmp(:,:,:,ikp) = spinvec_tmp1
        if(allocated(spinvec_atom))   spinvec_atom_tmp(:,:,:,ikp) = spinvec_atom_tmp1
        if(allocated(torqvalue))      torqval_tmp(:,:,ikp) = torqval_tmp1
        if(allocated(torqvalue_atom)) torqval_atom_tmp(:,:,:,ikp) = torqval_atom_tmp1
        if(allocated(spinflux_atom))  spinflux_atom_tmp(:,:,:,ikp) = spinflux_atom_tmp1
        if(allocated(alphavalue))     alphaval_tmp(:,:,ikp) = alphaval_tmp1 

      end if!allocated(spinvalue).or.allocated(spinvec).or.allocated(spinvec_atom).or.
            !allocated(torqvalue).or.allocated(torqvalue_atom).or.allocated(alphavalue)
 
    end do!ikp
    if(myrank==master) write(*,*) ''
!   write(*,*) 'after loop, myrank=', myrank
    !******************************************!
    !*** (parallelized) loop over FS points ***!
    !******************************************!
    !***************** E N D ******************!
    !******************************************!


    !close the eigenvector-file
#ifdef CPP_MPI
    if(l_save_eigv) call close_mpifile(fh_eigv)
#endif


    !gather the fermi-velocity from the processes
    if(allocated(fermivelocity))then
#ifdef CPP_MPI
      irecv  = 3*ntot_pT
      idispl = 3*ioff_pT
      call MPI_Allgatherv( fermivel_tmp, 3*nkpt, MPI_DOUBLE_PRECISION, &
                         & fermivelocity, irecv, idispl,               &
                         & MPI_DOUBLE_PRECISION, MPI_COMM_WORLD, ierr  )
      if(ierr/=MPI_SUCCESS) stop 'Problem in allgatherv fermivelocity'
#else
      fermivelocity = fermivel_tmp
#endif
    end if!present(fermivelocity)


    !gather the spinvalue from the processes
    if(allocated(spinvalue))then
#ifdef CPP_MPI
      itmp   = inc%ndegen*cfg%nsqa
      irecv  = itmp*ntot_pT
      idispl = itmp*ioff_pT
      call MPI_Allgatherv( spinval_tmp, itmp*nkpt, MPI_DOUBLE_PRECISION, &
                         & spinvalue, irecv, idispl,                     &
                         & MPI_DOUBLE_PRECISION, MPI_COMM_WORLD, ierr    )
      if(ierr/=MPI_SUCCESS) stop 'Problem in allgatherv spinvalue'
#else
      spinvalue= spinval_tmp
#endif
    end if!present(spinvalue)


    !gather the spinvec from the processes
    if(allocated(spinvec))then
#ifdef CPP_MPI
      itmp   = 3*inc%ndegen*cfg%nsqa
      irecv  = itmp*ntot_pT
      idispl = itmp*ioff_pT
      call MPI_Allgatherv( spinvec_tmp, itmp*nkpt, MPI_DOUBLE_PRECISION, &
                         & spinvec, irecv, idispl,                       &
                         & MPI_DOUBLE_PRECISION, MPI_COMM_WORLD, ierr    )
      if(ierr/=MPI_SUCCESS) stop 'Problem in allgatherv spinvec'
#else
      spinvec= spinvec_tmp
#endif
    end if!present(spinvec)


    !gather the spinvec_atom from the processes
    if(allocated(spinvec_atom))then
#ifdef CPP_MPI
      itmp   = 3*inc%ndegen*inc%natypd
      irecv  = itmp*ntot_pT
      idispl = itmp*ioff_pT
      call MPI_Allgatherv( spinvec_atom_tmp, itmp*nkpt, MPI_DOUBLE_PRECISION, &
                         & spinvec_atom, irecv, idispl,                       &
                         & MPI_DOUBLE_PRECISION, MPI_COMM_WORLD, ierr         )
      if(ierr/=MPI_SUCCESS) stop 'Problem in allgatherv spinvec_atom'
#else
      spinvec_atom= spinvec_atom_tmp
#endif
    end if!present(spinvec_atom)


    !gather the torquevalue from the processes
    if(allocated(torqvalue))then
#ifdef CPP_MPI
      itmp   = 3*inc%ndegen
      irecv  = itmp*ntot_pT
      idispl = itmp*ioff_pT
      call MPI_Allgatherv( torqval_tmp, itmp*nkpt, MPI_DOUBLE_PRECISION, &
                         & torqvalue, irecv, idispl,                     &
                         & MPI_DOUBLE_PRECISION, MPI_COMM_WORLD, ierr    )
      if(ierr/=MPI_SUCCESS) stop 'Problem in allgatherv torqvalue'
#else
      torqvalue= torqval_tmp
#endif
    end if!present(torqvalue)

    !gather the torquevalue_atom from the processes
    if(allocated(torqvalue_atom))then
#ifdef CPP_MPI
      itmp   = 3*inc%ndegen*inc%natypd
      irecv  = itmp*ntot_pT
      idispl = itmp*ioff_pT
      call MPI_Allgatherv( torqval_atom_tmp, itmp*nkpt, MPI_DOUBLE_PRECISION, &
                         & torqvalue_atom, irecv, idispl,                     &
                         & MPI_DOUBLE_PRECISION, MPI_COMM_WORLD, ierr    )
      if(ierr/=MPI_SUCCESS) stop 'Problem in allgatherv torqvalue_atom'
#else
      torqvalue_atom= torqval_atom_tmp
#endif
    end if!present(torqvalue_atom)

    !gather the spinflux_atom from the processes
    if(allocated(spinflux_atom))then
#ifdef CPP_MPI
      itmp   = 3*inc%ndegen*inc%natypd
      irecv  = itmp*ntot_pT
      idispl = itmp*ioff_pT
      call MPI_Allgatherv( spinflux_atom_tmp, itmp*nkpt, MPI_DOUBLE_PRECISION, &
                         & spinflux_atom, irecv, idispl,                     &
                         & MPI_DOUBLE_PRECISION, MPI_COMM_WORLD, ierr    )
      if(ierr/=MPI_SUCCESS) stop 'Problem in allgatherv spinflux_atom'
#else
      spinflux_atom= spinflux_atom_tmp
#endif
    end if!present(spinflux_atom)

    !gather the alphavalue from the processes
    if(allocated(alphavalue))then
#ifdef CPP_MPI
      itmp   = 3*inc%ndegen
      irecv  = itmp*ntot_pT
      idispl = itmp*ioff_pT
      call MPI_Allgatherv( alphaval_tmp, itmp*nkpt, MPI_DOUBLE_PRECISION, &
                         & alphavalue, irecv, idispl,                     &
                         & MPI_DOUBLE_PRECISION, MPI_COMM_WORLD, ierr     )
      if(ierr/=MPI_SUCCESS) stop 'Problem in allgatherv alphavalue'
#else
      alphavalue= alphaval_tmp
#endif
    end if!present(alphavalue)


190 FORMAT('                 |'$)
200 FORMAT('|'$)
  end subroutine calc_on_fsurf

  subroutine calc_spinvalue_state(inc,tgmatrx,rveig_in,spin_value,eigvect_rot)

    use type_inc,       only: inc_type
    use type_data,      only: tgmatrx_type
    use mod_eigvects,   only: rewrite_eigv_atom, orthgonalize_wavefunc, normalize_wavefunc, calc_proj_wavefunc, calc_norm_wavefunc
    use mod_spintools,  only: spin_expectationvalue, spin_crossterm, Spinrot_AlphaBeta, Spinrot_AlphaBeta_Rashba, rotate_wavefunction
    use mod_mympi, only: myrank
    implicit none
    type(inc_type),     intent(in)  :: inc
    type(tgmatrx_type), intent(in)  :: tgmatrx
    double complex,     intent(in)  :: rveig_in(inc%almso,inc%ndegen)
    double precision,   intent(out) :: spin_value(inc%ndegen,cfg%nsqa)
    double complex,     intent(out), optional :: eigvect_rot(inc%lmmaxso,inc%natypd,inc%ndegen,cfg%nsqa)

    double complex :: rveig_atom_unrot(inc%lmmaxso,inc%natypd,inc%ndegen), &
                    & rveig_atom_rot(inc%lmmaxso,inc%natypd,inc%ndegen)
    double complex :: Spin_ini(3,2), Spin_ini_atom(3,inc%natypd,2), Scross(3), Scross_atom(3,inc%natypd), Spin_final(3,inc%ndegen), Spin_final_atom(3,inc%natypd,inc%ndegen)
    double precision :: alpha, beta, Spin_estimated
    integer :: isqa, ient

    if(.not.cfg_read) call read_cfg()

    call rewrite_eigv_atom(inc,inc%ndegen,rveig_in,rveig_atom_unrot)

    select case (inc%ndegen)
    case( 1 ); !do nothing
    case( 2 ); call orthgonalize_wavefunc(inc, tgmatrx%rhod(:,:,:,1), rveig_atom_unrot)
    case default; stop 'inc%ndegen /= (1,2) not implemented'
    end select
    call normalize_wavefunc(inc, inc%ndegen, tgmatrx%rhod(:,:,:,1), rveig_atom_unrot)


    if(inc%ndegen==1)then
      !************************************************************************
      !* in this case, the wave-functions are already uniquely defined        *
      !* (except an overall phase, which does not influence the final result) *
      !************************************************************************

      !calculate spin-expectation value (vector-form)
      spin_value = 0d0
      call spin_expectationvalue(inc, inc%ndegen, tgmatrx%rhod, rveig_atom_unrot, Spin_final, Spin_atom=Spin_final_atom)

      !make a projection onto the SQA
      do isqa=1,cfg%nsqa
        spin_value(1,isqa) = sum(cfg%nvect(:,isqa)*dble(Spin_final(:,1)))

        !save the eigenvector into the array
        if(present(eigvect_rot)) then
          eigvect_rot(:,:,:,isqa) = rveig_atom_unrot
        end if!present(eigvect_rot)

      end do!isqa

    elseif(inc%ndegen==2)then
      !******************************************************************************
      !* In this case, all states are two-fold degenerate and any linear            *
      !* combination is also an eigenstat of the Hamiltonian. Therefore, we have    *
      !* to find the (correct) linear combination first to find the wave functions. *
      !******************************************************************************
      
      !calculate spin-expectation values of the (initial) wavefunctions
      call spin_expectationvalue(inc, inc%ndegen, tgmatrx%rhod, rveig_atom_unrot, Spin_ini, Spin_ini_atom)
      call spin_crossterm(inc, tgmatrx%rhod, rveig_atom_unrot, Scross, Scross_atom)

      do isqa=1,cfg%nsqa

        ! find parameter alpha and beta to perform the linear combination
        if(cfg%lrashba==1)then
          call Spinrot_AlphaBeta_Rashba(Spin_ini_atom(:,cfg%ilayer,:), Scross_atom(:,cfg%ilayer), alpha, beta)
        else!cfg%lrashba
          call Spinrot_AlphaBeta( cfg%ispincomb(isqa), cfg%nvect(:,isqa), Spin_ini, &
                                & Scross, alpha, beta, Spin_estimated               )
        end if!cfg%lrashba

        ! perform the linear combination of the degenerate wavefunctions
        call rotate_wavefunction(inc%lmmaxso, inc%natypd, alpha, beta, rveig_atom_unrot, rveig_atom_rot)

        ! calculate the true (=final) spin-expectation value
        call spin_expectationvalue(inc, inc%ndegen, tgmatrx%rhod, rveig_atom_rot, Spin_final, Spin_final_atom)

        ! project onto direction n and save to output-array
        do ient=1,2
          spin_value(ient,isqa) = sum(cfg%nvect(:,isqa)*dble(Spin_final(:,ient)))
        end do!ient

        !save the eigenvector into the array
        if(present(eigvect_rot)) then
          eigvect_rot(:,:,:,isqa) = rveig_atom_rot
        end if!present(eigvect_rot)

      end do!isqa

    end if!inc%ndegen==2

  end subroutine calc_spinvalue_state



  subroutine calc_spinvalue_state_generalized(inc,tgmatrx,rveig_in,spin_value,spinvec,spinvec_atom,torq_value,torq_value_atom,spinflux_atom,alpha_value,eigvect_rot)

    use type_inc,       only: inc_type
    use type_data,      only: tgmatrx_type
    use mod_eigvects,   only: rewrite_eigv_atom, orthgonalize_wavefunc, normalize_wavefunc, calc_proj_wavefunc, calc_norm_wavefunc
    use mod_spintools,  only: spin_expectationvalue, spin_crossterm, Spinrot_AlphaBeta, Spinrot_AlphaBeta_Rashba, rotate_wavefunction,&
                            & torq_expectationvalue, spinflux_expectationvalue, alpha_expectationvalue
    use mod_mympi, only: myrank
    implicit none
    type(inc_type),     intent(in)  :: inc
    type(tgmatrx_type), intent(in)  :: tgmatrx
    double complex,     intent(in)  :: rveig_in(inc%almso,inc%ndegen)
    double precision,   intent(out) :: spin_value(inc%ndegen,cfg%nsqa)
    double complex,     intent(inout), optional    :: eigvect_rot(:,:,:,:)  !eigvect_rot(inc%lmmaxso,inc%natypd,inc%ndegen,cfg%nsqa)
    double precision,   allocatable, intent(inout) :: spinvec(:,:,:)        !spinvec(3,inc%ndegen,cfg%nsqa)
    double precision,   allocatable, intent(inout) :: spinvec_atom(:,:,:)   !spinvec_atom(3,inc%natypd,inc%ndegen)
    double precision,   allocatable, intent(inout) :: torq_value(:,:)       !torq_value(3,inc%ndegen)
    double precision,   allocatable, intent(inout) :: torq_value_atom(:,:,:)!torq_value_atom(3,inc%natypd,inc%ndegen)
    double precision,   allocatable, intent(inout) :: spinflux_atom(:,:,:)  !spinflux_atom(3,inc%natypd,inc%ndegen)
    double precision,   allocatable, intent(inout) :: alpha_value(:,:)      !alpha_value(3,inc%ndegen)

    double complex :: rveig_atom_unrot(inc%lmmaxso,inc%natypd,inc%ndegen), &
                    & rveig_atom_rot(inc%lmmaxso,inc%natypd,inc%ndegen)
    double complex :: Spin_ini(3,2), Spin_ini_atom(3,inc%natypd,2), Scross(3), Scross_atom(3,inc%natypd), Spin_final(3,inc%ndegen), Spin_final_atom(3,inc%natypd,inc%ndegen), Torq_final(3,inc%ndegen), Torq_atom(3,inc%natypd,inc%ndegen), Spinfluxes_atom(3,inc%natypd,inc%ndegen), Alpha_Final(3,inc%ndegen)
    double precision :: alpha, beta, Spin_estimated
    integer :: isqa, ient

    if(.not.cfg_read) call read_cfg()

    call rewrite_eigv_atom(inc,inc%ndegen,rveig_in,rveig_atom_unrot)

    select case (inc%ndegen)
    case( 1 ); !do nothing
    case( 2 ); call orthgonalize_wavefunc(inc, tgmatrx%rhod(:,:,:,1), rveig_atom_unrot)
    case default; stop 'inc%ndegen /= (1,2) not implemented'
    end select
    call normalize_wavefunc(inc, inc%ndegen, tgmatrx%rhod(:,:,:,1), rveig_atom_unrot)


    if(inc%ndegen==1)then
      !************************************************************************
      !* in this case, the wave-functions are already uniquely defined        *
      !* (except an overall phase, which does not influence the final result) *
      !************************************************************************

      !calculate spin-expectation value (vector-form)
      spin_value = 0d0
      call spin_expectationvalue(inc, inc%ndegen, tgmatrx%rhod, rveig_atom_unrot, Spin_final, Spin_atom=Spin_final_atom)


      !make a projection onto the SQA
      do isqa=1,cfg%nsqa
        spin_value(1,isqa) = sum(cfg%nvect(:,isqa)*dble(Spin_final(:,1)))

        !save the eigenvector into the array
        if(present(eigvect_rot)) then
          eigvect_rot(:,:,:,isqa) = rveig_atom_unrot
        end if!present(eigvect_rot)

        if(allocated(spinvec)) spinvec(:,:,isqa)=dble(Spin_final)
        if(allocated(spinvec_atom) .and. isqa==1) spinvec_atom(:,:,:)=dble(Spin_final_atom)
      end do!isqa

      !calculate torque expectation value
      if(allocated(torq_value)) then
        call torq_expectationvalue(inc, inc%ndegen, tgmatrx%torq, rveig_atom_unrot, Torq_final, Torq_atom=Torq_atom)
        torq_value(:,:)=dble(Torq_final(:,:))
        if(allocated(torq_value_atom)) torq_value_atom(:,:,:)=dble(Torq_atom(:,:,:))
      end if!present(torq_value)

      !calculate spinflux expectation value
      if(allocated(spinflux_atom)) then
        call spinflux_expectationvalue(inc, inc%ndegen, tgmatrx%spinflux, rveig_atom_unrot, Spinflux_atom=Spinfluxes_atom)
        spinflux_atom(:,:,:)=dble(Spinfluxes_atom(:,:,:))
      end if!present(spinflux_atom)

      !calculate alpha expectation value
      if(allocated(alpha_value)) then
        call alpha_expectationvalue(inc, inc%ndegen, tgmatrx%alpha, rveig_atom_unrot, Alpha_final)
        alpha_value(:,:)=dble(Alpha_final(:,:))
      end if!present(alpha_value)

    elseif(inc%ndegen==2)then
      !******************************************************************************
      !* In this case, all states are two-fold degenerate and any linear            *
      !* combination is also an eigenstat of the Hamiltonian. Therefore, we have    *
      !* to find the (correct) linear combination first to find the wave functions. *
      !******************************************************************************
      
      !calculate spin-expectation values of the (initial) wavefunctions
      call spin_expectationvalue(inc, inc%ndegen, tgmatrx%rhod, rveig_atom_unrot, Spin_ini, Spin_ini_atom)
      call spin_crossterm(inc, tgmatrx%rhod, rveig_atom_unrot, Scross, Scross_atom)

      do isqa=1,cfg%nsqa

        ! find parameter alpha and beta to perform the linear combination
        if(cfg%lrashba==1)then
          call Spinrot_AlphaBeta_Rashba(Spin_ini_atom(:,cfg%ilayer,:), Scross_atom(:,cfg%ilayer), alpha, beta)
        else!cfg%lrashba
          call Spinrot_AlphaBeta( cfg%ispincomb(isqa), cfg%nvect(:,isqa), Spin_ini, &
                                & Scross, alpha, beta, Spin_estimated               )
        end if!cfg%lrashba

        ! perform the linear combination of the degenerate wavefunctions
        call rotate_wavefunction(inc%lmmaxso, inc%natypd, alpha, beta, rveig_atom_unrot, rveig_atom_rot)

        ! calculate the true (=final) spin-expectation value
        call spin_expectationvalue(inc, inc%ndegen, tgmatrx%rhod, rveig_atom_rot, Spin_final, Spin_final_atom)

        ! project onto direction n and save to output-array
        do ient=1,2
          spin_value(ient,isqa) = sum(cfg%nvect(:,isqa)*dble(Spin_final(:,ient)))
        end do!ient

        !save the result to the putput-arrays
        if(allocated(spinvec)) spinvec(:,:,isqa)=dble(Spin_final)
        if(allocated(spinvec_atom) .and. isqa==1) spinvec_atom(:,:,:)=dble(Spin_final_atom)

        !save the eigenvector into the array
        if(present(eigvect_rot)) then
          eigvect_rot(:,:,:,isqa) = rveig_atom_rot
        end if!present(eigvect_rot)

        ! calculate the torque expectation value
        ! ATTENTION!!!!! This is not properly implemented. If it made sense to calculate the torque
        !                also when there is the two-fold conjugation degeneracy (AFMs?), this implementation
        !                would only store the torque of the last SQA. Therefore, in "read_cfg", we check 
        !                that cfg%nsqa=1 if ltorq=1.
        if(allocated(torq_value)) then
          call torq_expectationvalue(inc, inc%ndegen, tgmatrx%torq, rveig_atom_unrot, Torq_final, Torq_atom)
          torq_value(:,:)=dble(Torq_final(:,:))
          if(allocated(torq_value_atom)) torq_value_atom(:,:,:)=dble(Torq_atom(:,:,:))
        end if!present(torq_value)

        if(allocated(torq_value_atom)) then
          call spinflux_expectationvalue(inc, inc%ndegen, tgmatrx%spinflux, rveig_atom_unrot, Spinfluxes_atom)
          spinflux_atom(:,:,:)=dble(Spinfluxes_atom(:,:,:))
        end if!present(torq_value_atom)

        if(allocated(alpha_value)) then
          call alpha_expectationvalue(inc, inc%ndegen, tgmatrx%spinflux, rveig_atom_unrot, Alpha_final)
          alpha_value(:,:)=dble(Alpha_final(:,:))
        end if!present(alpha_value)

      end do!isqa

    end if!inc%ndegen==2

  end subroutine calc_spinvalue_state_generalized




  subroutine calc_fermivel_new(inc,lattice,cluster,tgmatrx,kpoint,eigw_in,LVin,RVin,fermi_velocity)

    use type_inc,       only: inc_type
    use type_data,      only: lattice_type, cluster_type, tgmatrx_type
    use mod_mympi,      only: myrank, nranks, master
    use mod_kkrmat,     only: compute_kkr_eigenvectors2, compute_kkr_eigenvectors2_dk
    use mod_eigvects,   only: compare_eigv
    use mod_mathtools,  only: bubblesort
    implicit none

    type(inc_type),     intent(in) :: inc
    type(lattice_type), intent(in) :: lattice
    type(cluster_type), intent(in) :: cluster
    type(tgmatrx_type), intent(in) :: tgmatrx

    double precision, intent(in) :: kpoint(3)
    double complex,   intent(in) :: eigw_in, LVin(inc%almso), RVin(inc%almso)
    
    double precision, intent(out) :: fermi_velocity(3)

    double precision :: Delta_k(3), kpoint_dk(3), fac_fv
    double complex   :: eigwPT(inc%almso), LVeigPT(inc%almso,inc%almso), RVeigPT(inc%almso,inc%almso)

    double complex   :: Delta_lambda_kxyz(3), Delta_lambda_E(2)

    integer :: ikxyz, ipm, LMout

    logical, save :: first=.true.

!   integer          :: sortind(inc%almso)
!   double precision :: dtmp(inc%almso)

!   integer, parameter :: dimenk=3

    !==================================================!
    !+++         FERMI-VELOCITY-CALULATION          +++!
    !==================================================!
    !  a) perturb the eigenvalue w.r.t. the k-point    !
    !  b) perturb the eigenvalue w.r.t. the energy     !
    !  c) determine the fermi-velocity by              !
    !                     \nabla_k lambda              !
    !        v_F = --------------------------------    !
    !                (\delta lambda) / (\delta E)      !
    !==================================================!


    !++++++++++++++++!
    !+++ BEGIN a) +++!
    !++++++++++++++++!

    call compute_kkr_eigenvectors2_dk( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
                                     & tgmatrx%tmat(:,:,1), kpoint_dk, LVin, RVin,  &
                                     & Delta_lambda_kxyz                            )

    write(6000,'(6ES25.16)') Delta_lambda_kxyz

    !++++++++++++++++!
    !+++ BEGIN b) +++!
    !++++++++++++++++!
    do ipm=1,2

      !calculate the eigenvalue at the perturbed k-point
      call compute_kkr_eigenvectors2( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1+ipm),&
                                    & tgmatrx%tmat(:,:,1+ipm), kpoint,                 &
                                    & eigwPT, LVeigPT, RVeigPT                         )

!     dtmp = abs(eigwPT)
!     call bubblesort(inc%almso, dtmp, sortind)
!     write(*,'(4X,"sorted abs(eigw)=", 6ES18.9)') abs(eigwPT(sortind(1:6)))

      call compare_eigv(inc, LVin, RVeigPT, LMout)

!     write(*,'(2X,"pert e= (",2ES18.9,"), lmo= ",I0)') eigwPT(LMout), LMout

      Delta_lambda_E(ipm) = eigwPT(LMout) - eigw_in
      
    end do!ipm
 

    !++++++++++++++++!
    !+++ BEGIN c) +++!
    !++++++++++++++++!
    fac_fv = 2*dble(tgmatrx%energies(2) - tgmatrx%energies(1))
    fermi_velocity(:) = -dble(   Delta_lambda_kxyz(:) / (Delta_lambda_E(1)-Delta_lambda_E(2)) ) *fac_fv
    write(7000,'(6ES25.16)') Delta_lambda_kxyz(:) / (Delta_lambda_E(1)-Delta_lambda_E(2))*fac_fv

  end subroutine calc_fermivel_new





  subroutine calc_fermivel(inc,lattice,cluster,tgmatrx,kpoint,eigw_in,LVin,RVin,fermi_velocity)

    use type_inc,       only: inc_type
    use type_data,      only: lattice_type, cluster_type, tgmatrx_type
    use mod_mympi,      only: myrank, nranks, master
    use mod_kkrmat,     only: compute_kkr_eigenvectors2
    use mod_eigvects,   only: compare_eigv
    use mod_mathtools,  only: bubblesort
    implicit none

    type(inc_type),     intent(in) :: inc
    type(lattice_type), intent(in) :: lattice
    type(cluster_type), intent(in) :: cluster
    type(tgmatrx_type), intent(in) :: tgmatrx

    double precision, intent(in) :: kpoint(3)
    double complex,   intent(in) :: eigw_in, LVin(inc%almso), RVin(inc%almso)
    
    double precision, intent(out) :: fermi_velocity(3)

    double precision :: Delta_k(3), kpoint_dk(3), fac_fv
    double complex   :: eigwPT(inc%almso), LVeigPT(inc%almso,inc%almso), RVeigPT(inc%almso,inc%almso)

    double complex   :: Delta_lambda_kxyz(3,2), Delta_lambda_E(2)

    integer :: ikxyz, ipm, LMout
!   integer          :: sortind(inc%almso)
!   double precision :: dtmp(inc%almso)

!   integer, parameter :: dimenk=3

    !==================================================!
    !+++         FERMI-VELOCITY-CALULATION          +++!
    !==================================================!
    !  a) perturb the eigenvalue w.r.t. the k-point    !
    !  b) perturb the eigenvalue w.r.t. the energy     !
    !  c) determine the fermi-velocity by              !
    !                     \nabla_k lambda              !
    !        v_F = --------------------------------    !
    !                (\delta lambda) / (\delta E)      !
    !==================================================!


    !++++++++++++++++!
    !+++ BEGIN a) +++!
    !++++++++++++++++!
    Delta_lambda_kxyz = (0d0,0d0)
    do ikxyz=1,inc%nBZdim!dimenk
      do ipm=1,2
        !determine the perturbed k-point
        Delta_k = 0d0
        Delta_k(ikxyz) = dble(3-2*ipm)*cfg%dk_fv ! = +-Delta_k_pert depending on ipm=i_plus_minus
        kpoint_dk = kpoint + Delta_k

        !calculate the eigenvalue at the perturbed k-point
        call compute_kkr_eigenvectors2( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1),&
                                      & tgmatrx%tmat(:,:,1), kpoint_dk,              &
                                      & eigwPT, LVeigPT, RVeigPT                     )

        call compare_eigv(inc, LVin, RVeigPT, LMout)

!       write(*,'(2X,"pert k= (",2ES18.9,"), lmo= ",I0)') eigwPT(LMout), LMout

        Delta_lambda_kxyz(ikxyz,ipm) = eigwPT(LMout) - eigw_in

      end do!ipm
    end do!ikxyz


!   write(6001,'(6ES25.16)') Delta_lambda_kxyz(:,1)-Delta_lambda_kxyz(:,2)/(2*cfg%dk_fv)

    !++++++++++++++++!
    !+++ BEGIN b) +++!
    !++++++++++++++++!
    do ipm=1,2

      !calculate the eigenvalue at the perturbed k-point
      call compute_kkr_eigenvectors2( inc, lattice, cluster, tgmatrx%ginp(:,:,:,1+ipm),&
                                    & tgmatrx%tmat(:,:,1+ipm), kpoint,                 &
                                    & eigwPT, LVeigPT, RVeigPT                         )

!     dtmp = abs(eigwPT)
!     call bubblesort(inc%almso, dtmp, sortind)
!     write(*,'(4X,"sorted abs(eigw)=", 6ES18.9)') abs(eigwPT(sortind(1:6)))

      call compare_eigv(inc, LVin, RVeigPT, LMout)

!     write(*,'(2X,"pert e= (",2ES18.9,"), lmo= ",I0)') eigwPT(LMout), LMout

      Delta_lambda_E(ipm) = eigwPT(LMout) - eigw_in
      
    end do!ipm
 

    !++++++++++++++++!
    !+++ BEGIN c) +++!
    !++++++++++++++++!
    fac_fv = dble(tgmatrx%energies(2) - tgmatrx%energies(1))/cfg%dk_fv
    fermi_velocity(:) = -dble( (Delta_lambda_kxyz(:,1) - Delta_lambda_kxyz(:,2))/(Delta_lambda_E(1)-Delta_lambda_E(2)))*fac_fv
!   write(7001,'(6ES25.16)') -(Delta_lambda_kxyz(:,1) - Delta_lambda_kxyz(:,2))/(Delta_lambda_E(1)-Delta_lambda_E(2))*fac_fv

  end subroutine calc_fermivel





  subroutine read_cfg(force_spinread)

    use mod_ioinput, only: IoInput
    use mod_mympi,   only: myrank, nranks, master
#ifdef CPP_MPI
    use mpi
#endif
    implicit none

    logical, intent(in), optional :: force_spinread

    integer :: nspincomb, angrep, idir, inum, ierr
    double precision :: dtmpin(3), theta, phi
    character(len=80) :: uio
    double precision, allocatable :: vectintmp(:,:)
    logical :: force_spin

    if(myrank==master) then
      force_spin = .false.
      if(present(force_spinread)) force_spin=force_spinread

      call IoInput('LFVEL     ',uio,1,7,ierr)
      read(unit=uio,fmt=*) cfg%lfvel
      if(cfg%lfvel==1)then
        call IoInput('DKFVEL    ',uio,1,7,ierr)
        read(unit=uio,fmt=*) cfg%dk_fv
      end if!lfvel==1



      call IoInput('LSPIN     ',uio,1,7,ierr)
      read(unit=uio,fmt=*) cfg%lspin
      if(cfg%lspin==1 .or. force_spin) then

        call IoInput('LSPINATOM ',uio,1,7,ierr)
        if(ierr==0) then
          read(unit=uio,fmt=*) cfg%lspinperatom
        else ! ensures compatibility of old format input files
          write(*,*) "Warning : LSPINATOM set to 0 by default !"
          cfg%lspinperatom=0
        end if!ierr==0

        call IoInput('LTORQ     ',uio,1,7,ierr)
        if(ierr==0) then
          read(unit=uio,fmt=*) cfg%ltorq
        else ! ensures compatibility of old format input files
          write(*,*) "Warning : LTORQ set to 0 by default !"
          cfg%ltorq=0
        end if!ierr==0

        call IoInput('LTORQATOM ',uio,1,7,ierr)
        if(ierr==0) then
          read(unit=uio,fmt=*) cfg%ltorqperatom
        else ! ensures compatibility of old format input files
          write(*,*) "Warning : LTORQATOM set to 0 by default !"
          cfg%ltorqperatom=0
        end if!ierr==0

        call IoInput('LSPINFLUX ',uio,1,7,ierr)
        if(ierr==0) then
          read(unit=uio,fmt=*) cfg%lspinflux
        else ! ensures compatibility of old format input files
          write(*,*) "Warning : LSPINFLUX set to 0 by default !"
          cfg%lspinflux=0
        end if!ierr==0

        call IoInput('LALPHA    ',uio,1,7,ierr)
        if(ierr==0) then
          read(unit=uio,fmt=*) cfg%lalpha
        else ! ensures compatibility of old format input files
          write(*,*) "Warning : LALPHA set to 0 by default !"
          cfg%lalpha=0
        end if!ierr==0

        call IoInput('SIMPSON   ',uio,1,7,ierr)
        if(ierr==0) then
          read(unit=uio,fmt=*) cfg%simpson
        else ! ensures compatibility of old format input files
          write(*,*) "Warning : SIMPSON set to F by default !"
          cfg%simpson = .false.
        end if!ierr==0

        call IoInput('LSAVEEIGV ',uio,1,7,ierr)
        read(unit=uio,fmt=*) inum
        if(inum==1)then
           cfg%saveeigv=.true.
        else
           cfg%saveeigv=.false.
        end if

        call IoInput('LRASHBA   ',uio,1,7,ierr)
        if(ierr==0) then
          read(unit=uio,fmt=*) cfg%lrashba
        else ! ensures compatibility of old format input files
          write(*,*) "Warning : LRASHBA set to F by default !"
          cfg%lrashba = 0
        end if!ierr==0
        if(cfg%lrashba==1)then
          call IoInput('ILAYER    ',uio,1,7,ierr)
          read(unit=uio,fmt=*) cfg%ilayer
        end if!lrashba==1

        call IoInput('NSQA      ',uio,1,7,ierr)
        read(unit=uio,fmt=*) cfg%nsqa
        write(6,*)"cfg%nsqa=",cfg%nsqa
        allocate(vectintmp(3,cfg%nsqa), STAT=ierr)
        if(ierr/=0) stop 'Problem allocating vectintmp'

        !check consistency of NSQA and LRASHBA
        if(cfg%lrashba==1 .and. cfg%nsqa>1)then
          write(*,'(A)') 'WARNING! setting NSQA=1 for option LRASHBA'
          cfg%nsqa=1
        end if

        !check consistency of NSQA and LSPINATOM
        if(cfg%lspinperatom==1 .and. cfg%nsqa>1)then
          write(*,'(A)') 'WARNING! setting NSQA=1 for option LSPINATOM'
          cfg%nsqa=1
        end if

        call IoInput('SPINCOMB  ',uio,1,7,ierr)
        read(unit=uio,fmt=*) nspincomb

        call IoInput('ANGREP    ',uio,1,7,ierr)
        read(unit=uio,fmt=*) angrep

        !read in vectors
        do idir=1,cfg%nsqa
          if(angrep==0) then
            call IoInput('ANISOVECS ',uio,1+idir,7,ierr)
            read (unit=uio,fmt=*) inum, dtmpin(1:2)
          elseif(angrep==1) then
            call IoInput('ANISOVECS ',uio,1+idir,7,ierr)
            read (unit=uio,fmt=*) inum, dtmpin(1:3)
          end if
          call convert_nvect(angrep,dtmpin,vectintmp(:,idir))
        end do!idir

        !check consistency of NSQA and LTORQ
        if(cfg%ltorq==1 .and. cfg%nsqa>1)then
          write(*,'(A)') 'WARNING! setting NSQA=1 for option LTORQ'
          cfg%nsqa=1
          if(nspincomb==0)then
            write(*,'(A)') 'WARNING! option SPINCOMB=0 not allaowed for LTORQ. Assunming SPINCOMB=1'
            nspincomb=1
          end if!nspincomb==0
        end if!cfg%ltorq==1 .and. cfg%nsqa>1

        !combine the spin-sqa-data
        if( nspincomb==0 )then
          !case that both conditions shall be treated

          allocate(cfg%ispincomb(2*cfg%nsqa), cfg%nvect(3,2*cfg%nsqa), STAT=ierr)
          if(ierr/=0) stop 'Problem allocating cfg%ispincomb etc. on master'

          do idir=1,cfg%nsqa
            cfg%nvect(:,2*idir-1) = vectintmp(:,idir)
            cfg%nvect(:,2*idir  ) = vectintmp(:,idir)
            cfg%ispincomb(2*idir-1) = 1
            cfg%ispincomb(2*idir  ) = 2
          end do!idir

          cfg%nsqa = 2*cfg%nsqa

        else!nspincomb
          !case that only one condition shall be treated

          allocate(cfg%ispincomb(cfg%nsqa), cfg%nvect(3,cfg%nsqa), STAT=ierr)
          if(ierr/=0) stop 'Problem allocating cfg%ispincomb etc. on master'

          cfg%nvect = vectintmp
          cfg%ispincomb = nspincomb

        end if!nspincomb

      end if!lspin==1


      if(cfg%lfvel==1 .or. cfg%lspin==1)then
        call IoInput('ONFSMODE  ',uio,1,7,ierr)
        read(unit=uio,fmt=*) cfg%mode
        call IoInput('ROTMODE   ',uio,1,7,ierr)
        read(unit=uio,fmt=*) cfg%rotatemode
      end if

    end if!myrank==master

#ifdef CPP_MPI
    call myBcast_cfg(cfg)
#endif

    cfg_read = .true.

  end subroutine read_cfg





  subroutine convert_nvect(angrep,dtmpin,nvect)
    use mod_mathtools, only: pi
    implicit none
    integer, intent(in) :: angrep
    double precision, intent(in) :: dtmpin(3)
    double precision, intent(out) :: nvect(3)

    double precision :: theta, phi, norm

    if(angrep==0) then
      theta = dtmpin(1)
      phi   = dtmpin(2)
      nvect(1) = dsin(theta*pi)*dcos(phi*pi)
      nvect(2) = dsin(theta*pi)*dsin(phi*pi)
      nvect(3) = dcos(theta*pi)
    elseif(angrep==1) then
      norm = sqrt(sum(dtmpin**2))
      nvect = dtmpin/norm
    end if
    
  end subroutine convert_nvect





#ifdef CPP_MPI
  subroutine myBcast_cfg(cfg)

    use mpi
    use mod_mympi,   only: myrank, nranks, master
    implicit none

    type(cfg_type), intent(inout)  :: cfg

    integer :: blocklen1(cfg%N1), etype1(cfg%N1), myMPItype1
    integer :: blocklen2(cfg%N2), etype2(cfg%N2), myMPItype2
    integer :: ierr
    integer(kind=MPI_ADDRESS_KIND) :: disp1(cfg%N1), disp2(cfg%N2), base

    call MPI_Get_address(cfg%N1,           disp1(1), ierr)
    call MPI_Get_address(cfg%lspin,        disp1(2), ierr)
    call MPI_Get_address(cfg%lfvel,        disp1(3), ierr)
    call MPI_Get_address(cfg%lrashba,      disp1(4), ierr)
    call MPI_Get_address(cfg%lspinperatom, disp1(5), ierr)
    call MPI_Get_address(cfg%ltorqperatom, disp1(6), ierr)
    call MPI_Get_address(cfg%ltorq,        disp1(7), ierr)
    call MPI_Get_address(cfg%lspinflux,    disp1(8), ierr)
    call MPI_Get_address(cfg%lalpha,       disp1(9), ierr)
    call MPI_Get_address(cfg%nsqa,         disp1(10), ierr)
    call MPI_Get_address(cfg%mode,         disp1(11), ierr)
    call MPI_Get_address(cfg%rotatemode,   disp1(12), ierr)
    call MPI_Get_address(cfg%ilayer,       disp1(13), ierr)
    call MPI_Get_address(cfg%dk_fv,        disp1(14), ierr)
    call MPI_Get_address(cfg%saveeigv,     disp1(15), ierr)
    call MPI_Get_address(cfg%simpson,      disp1(16), ierr)

    base  = disp1(1)
    disp1 = disp1 - base

    blocklen1(1:16)=1

    etype1(1:13) = MPI_INTEGER
    etype1(14)   = MPI_DOUBLE_PRECISION
    etype1(15:16)= MPI_LOGICAL

    call MPI_Type_create_struct(cfg%N1, blocklen1, disp1, etype1, myMPItype1, ierr)
    if(ierr/=MPI_SUCCESS) stop 'Problem in create_mpimask_cfg_1'

    call MPI_Type_commit(myMPItype1, ierr)
    if(ierr/=MPI_SUCCESS) stop 'error commiting create_mpimask_cfg_1'

    call MPI_Bcast(cfg%N1, 1, myMPItype1, master, MPI_COMM_WORLD, ierr)
    if(ierr/=MPI_SUCCESS) stop 'error brodcasting cfg_1'

    call MPI_Type_free(myMPItype1, ierr)

    if(cfg%lspin==1)then

      if(myrank/=master) then
        allocate( cfg%ispincomb(cfg%nsqa), cfg%nvect(3,cfg%nsqa), STAT=ierr )
        if(ierr/=0) stop 'Problem allocating cfg_arrays on slaves'
      end if

      call MPI_Get_address(cfg%N2,        disp2(1), ierr)
      call MPI_Get_address(cfg%ispincomb, disp2(2), ierr)
      call MPI_Get_address(cfg%nvect,     disp2(3), ierr)

      base  = disp2(1)
      disp2 = disp2 - base

      blocklen2(1)=1
      blocklen2(2)=size(cfg%ispincomb)
      blocklen2(3)=size(cfg%nvect)

      etype2(1:2) = MPI_INTEGER
      etype2(3)   = MPI_DOUBLE_PRECISION

      call MPI_Type_create_struct(cfg%N2, blocklen2, disp2, etype2, myMPItype2, ierr)
      if(ierr/=MPI_SUCCESS) stop 'Problem in create_mpimask_cfg_2'

      call MPI_Type_commit(myMPItype2, ierr)
      if(ierr/=MPI_SUCCESS) stop 'error commiting create_mpimask_cfg_2'

      call MPI_Bcast(cfg%N2, 1, myMPItype2, master, MPI_COMM_WORLD, ierr)
      if(ierr/=MPI_SUCCESS) stop 'error brodcasting cfg_2'

      call MPI_Type_free(myMPItype2, ierr)

    end if!cfg%lspin==1

  end subroutine myBcast_cfg
#endif





  subroutine save_fermivelocity(filemode, nkpts, fermivel, nsym, isym)

    use mod_ioformat,   only: fmt_fn_sub_ext, ext_formatted, filename_fvel
    implicit none

    character(len=*), intent(in) :: filemode
    integer,          intent(in) :: nkpts, nsym, isym(nsym)
    double precision, intent(in) :: fermivel(3,nkpts)

    integer :: ii
    character(len=256) :: filename

    write(filename,fmt_fn_sub_ext) filename_fvel, filemode, ext_formatted
    open(unit=326528, file=trim(filename), form='formatted', action='write')
    write(326528,'(2I8)') nkpts, nsym
    write(326528,'(12I8)') isym
    write(326528,'(3ES25.16)') fermivel
    close(326528)

  end subroutine save_fermivelocity





  subroutine save_spinvalue(filemode, nkpts, nsqa, ndegen, ispincomb, nvect, spinval, nsym, isym)

    use mod_ioformat,   only: fmt_fn_sub_ext, ext_formatted, filename_spin
    implicit none

    character(len=*), intent(in) :: filemode
    integer,          intent(in) :: nkpts, nsqa, ndegen, nsym, isym(nsym), ispincomb(nsqa)
    double precision, intent(in) :: nvect(3,nsqa), spinval(ndegen,nsqa,nkpts)


    integer :: ii
    character(len=256) :: filename

    write(filename,fmt_fn_sub_ext) filename_spin, filemode, ext_formatted
    open(unit=326529, file=trim(filename), form='formatted', action='write')
    write(326529,'(2I8)') nkpts, nsym, nsqa, ndegen
    write(326529,'(12I8)') isym
    write(326529,'(10I8)') ispincomb
    write(326529,'(3ES25.16)') nvect
    write(326529,'(ES25.16)') spinval
    close(326529)

  end subroutine save_spinvalue



  subroutine save_spinvec(filemode, nkpts, nsqa, ndegen, ispincomb, nvect, spinvec, nsym, isym)

    use mod_ioformat,   only: fmt_fn_sub_ext, ext_formatted, filename_spinvec
    implicit none

    character(len=*), intent(in) :: filemode
    integer,          intent(in) :: nkpts, nsqa, ndegen, nsym, isym(nsym), ispincomb(nsqa)
    double precision, intent(in) :: nvect(3,nsqa), spinvec(3,ndegen,nsqa,nkpts)

    integer :: ii
    character(len=256) :: filename

    write(filename,fmt_fn_sub_ext) filename_spinvec, filemode, ext_formatted
    open(unit=326529, file=trim(filename), form='formatted', action='write')
    write(326529,'(2I8)') nkpts, nsym, nsqa, ndegen
    write(326529,'(12I8)') isym
    write(326529,'(10I8)') ispincomb
    write(326529,'(3ES25.16)') nvect
    write(326529,'(3ES25.16)') spinvec
    close(326529)

  end subroutine save_spinvec



  subroutine save_spinvec_atom(filemode, nkpts, ndegen, natyp, spinvec_atom, nsym, isym)

    use mod_ioformat,   only: fmt_fn_atom_sub_ext, ext_formatted, filename_spinvec
    implicit none

    character(len=*), intent(in) :: filemode
    integer,          intent(in) :: nkpts, ndegen, nsym, isym(nsym), natyp
    double precision, intent(in) :: spinvec_atom(3,natyp,ndegen,nkpts)

    integer :: ii
    character(len=256) :: filename

    do ii=1,natyp
      write(filename,fmt_fn_atom_sub_ext) filename_spinvec, ii, filemode, ext_formatted
      open(unit=326529, file=trim(filename), form='formatted', action='write')
      write(326529,'(3I8)') nkpts, nsym, ndegen
      write(326529,'(12I8)') isym
      write(326529,'(3ES25.16)') spinvec_atom(:,ii,:,:)
      close(326529)
   end do!ii=1,natyp

  end subroutine save_spinvec_atom



  subroutine save_torqvalue(filemode, nkpts, ndegen, torqval, nsym, isym)

    use mod_ioformat,   only: fmt_fn_sub_ext, ext_formatted, filename_torq
    implicit none

    character(len=*), intent(in) :: filemode
    integer,          intent(in) :: nkpts, ndegen, nsym, isym(nsym)
    double precision, intent(in) :: torqval(3,ndegen,nkpts)

    integer :: ii
    character(len=256) :: filename

    write(filename,fmt_fn_sub_ext) filename_torq, filemode, ext_formatted
    open(unit=326529, file=trim(filename), form='formatted', action='write')
    write(326529,'(3I8)') nkpts, nsym, ndegen
    write(326529,'(12I8)') isym
    write(326529,'(3ES25.16)') torqval
    close(326529)

  end subroutine save_torqvalue


  subroutine save_torqvalue_atom(filemode, nkpts, ndegen, natyp, torqval_atom, nsym, isym)

    use mod_ioformat,   only: fmt_fn_atom_sub_ext, ext_formatted, filename_torq
    implicit none

    character(len=*), intent(in) :: filemode
    integer,          intent(in) :: nkpts, ndegen, nsym, isym(nsym), natyp
    double precision, intent(in) :: torqval_atom(3,natyp,ndegen,nkpts)

    integer :: ii
    character(len=256) :: filename

    do ii=1,natyp
      write(filename,fmt_fn_atom_sub_ext) filename_torq, ii, filemode, ext_formatted
      open(unit=326529, file=trim(filename), form='formatted', action='write')
      write(326529,'(3I8)') nkpts, nsym, ndegen
      write(326529,'(12I8)') isym
      write(326529,'(3ES25.16)') torqval_atom(:,ii,:,:)
      close(326529)
    end do!ii=1,natyp

  end subroutine save_torqvalue_atom

  subroutine save_spinflux_atom(filemode, nkpts, ndegen, natyp, spinflux_atom, nsym, isym)

    use mod_ioformat,   only: fmt_fn_atom_sub_ext, ext_formatted, filename_spinflux
    implicit none

    character(len=*), intent(in) :: filemode
    integer,          intent(in) :: nkpts, ndegen, nsym, isym(nsym), natyp
    double precision, intent(in) :: spinflux_atom(3,natyp,ndegen,nkpts)

    integer :: ii
    character(len=256) :: filename

    do ii=1,natyp
      write(filename,fmt_fn_atom_sub_ext) filename_spinflux, ii, filemode, ext_formatted
      open(unit=326529, file=trim(filename), form='formatted', action='write')
      write(326529,'(3I8)') nkpts, nsym, ndegen
      write(326529,'(12I8)') isym
      write(326529,'(3ES25.16)') spinflux_atom(:,ii,:,:)
      close(326529)
    end do!ii=1,natyp

  end subroutine save_spinflux_atom

  subroutine save_alpha(filemode, nkpts, ndegen, alpha, nsym, isym)

    use mod_ioformat,   only: fmt_fn_sub_ext, ext_formatted, filename_alpha
    implicit none

    character(len=*), intent(in) :: filemode
    integer,          intent(in) :: nkpts, ndegen, nsym, isym(nsym)
    double precision, intent(in) :: alpha(3,ndegen,nkpts)

    integer :: ii
    character(len=256) :: filename

    write(filename,fmt_fn_sub_ext) filename_alpha, filemode, ext_formatted
    open(unit=326529, file=trim(filename), form='formatted', action='write')
    write(326529,'(A)') '# To adapt this file to the fermivelocity.vis.txt format:'
    write(326529,'(A)') '# if ndegen==1 : just remove the 1 on the second line'
    write(326529,'(A)') '# if ndegen==2 : remove the 2 on the second line'
    write(326529,'(A)') '#                and remove second half of the data'
    write(326529,'(2I8)') nkpts, nsym, ndegen
    write(326529,'(12I8)') isym
    do ii=1,ndegen
      write(326529,'(3ES25.16)') alpha(:,ii,:)
    end do
    close(326529)

  end subroutine save_alpha

  subroutine calculate_response_functions_CRTA_int(nsym,isym,rotmat,alat,BZVol,ndeg,natyp,nkpts,areas,fermivel,torqval,torqval_atom,spinvec_atom,spinflux)
    use mpi
    use mod_mympi,      only: myrank, master
    use mod_mathtools,  only: tpi
    use mod_symmetries, only: rotate_kpoints, expand_areas
    implicit none

    integer,          intent(in)  :: nsym, ndeg, natyp, nkpts, isym(nsym)
    double precision, intent(in)  :: alat, BZVol
    double precision, intent(in)  :: rotmat(64,3,3), areas(nkpts), fermivel(3,nkpts)
    double precision, allocatable, intent(in)  :: torqval(:,:,:)      !torqval(3,ndeg,nkpts)
    double precision, allocatable, intent(in)  :: torqval_atom(:,:,:,:) !torqval_atom(3,natypd,ndeg,nkpts)
    double precision, allocatable, intent(in)  :: spinvec_atom(:,:,:,:) !spinvec_atom(3,natypd,ndeg,nkpts)
    double precision, allocatable, intent(in)  :: spinflux(:,:,:,:)   !spinflux(3,natypd,ndegen,nkpts)

    double precision, allocatable :: fermivel_r(:,:), areas_r(:), arrtmp1(:,:), arrtmp2(:,:)
    double precision, allocatable :: torqval_r(:,:,:), torqval_atom_r(:,:,:,:), spinvec_atom_r(:,:,:,:), spinflux_r(:,:,:,:)

    integer :: ierr, ikp, i1, i2, ideg, itmp, nkpts_tmp, nkpts_r
    double precision :: torkance(3,3), torkance_atom(3,3,natyp), damping(3,3), spinacc_atom(3,3,natyp), spinflux_resp(3,3,natyp)
    double precision :: integ_torkance(3,3), integ_torkance_atom(3,3,natyp), integ_damping(3,3), integ_spinacc_atom(3,3,natyp), integ_spinflux(3,3,natyp)
    double precision :: vabs
    double precision, parameter :: RyToinvfs = 20.67068667282055d0
    integer, parameter :: iounit=13517

    if(nsym>1)then
      !apply symmetries to fermivel and areas
      call rotate_kpoints(rotmat, nkpts, fermivel, nsym, isym, nkpts_r, fermivel_r)
      call expand_areas(nsym,nkpts,areas,areas_r)

      if(allocated(torqval))then
        !next apply symmetries to torqval; as a first step, flatten the array
        itmp = size(torqval)/3
        allocate(arrtmp1(3,itmp), STAT=ierr)
        if(ierr/=0) stop 'problem alloaction arrtmp1'
        arrtmp1 = reshape(torqval, (/3, itmp/))

        !now apply the symmetries
        call rotate_kpoints(rotmat, nkpts*ndeg, arrtmp1, nsym, isym, nkpts_tmp, arrtmp2)
        if(nkpts_r*ndeg /= nkpts_tmp) stop 'nkpts_r*ndeg /= nkpts_tmp'

        !transform back to old shape
        allocate(torqval_r(3,ndeg,nkpts_r), STAT=ierr)
        if(ierr/=0) stop 'problem allocating torqval_r'
        torqval_r = reshape(arrtmp2,(/3,ndeg,nkpts_r/))

        deallocate(arrtmp1, arrtmp2)
      end if!allocated(torqval)

      if(allocated(torqval_atom))then
        !next apply symmetries to torqval_atom; as a first step, flatten the array
        itmp = size(torqval_atom)/3
        allocate(arrtmp1(3,itmp), STAT=ierr)
        if(ierr/=0) stop 'problem alloaction arrtmp1'
        arrtmp1 = reshape(torqval_atom, (/3, itmp/))

        !now apply the symmetries
        call rotate_kpoints(rotmat, nkpts*ndeg*natyp, arrtmp1, nsym, isym, nkpts_tmp, arrtmp2)
        if(nkpts_r*ndeg*natyp /= nkpts_tmp) stop 'nkpts_r*ndeg /= nkpts_tmp'

        !transform back to old shape
        allocate(torqval_atom_r(3,natyp,ndeg,nkpts_r), STAT=ierr)
        if(ierr/=0) stop 'problem allocating torqval_atom_r'
        torqval_atom_r = reshape(arrtmp2,(/3,natyp,ndeg,nkpts_r/))

        deallocate(arrtmp1, arrtmp2)
      end if!allocated(torqval_atom)

      if(allocated(spinvec_atom))then
        !next apply symmetries to spinvec_atom; as a first step, flatten the array
        itmp = size(spinvec_atom)/3
        allocate(arrtmp1(3,itmp), STAT=ierr)
        if(ierr/=0) stop 'problem alloaction arrtmp1'
        arrtmp1 = reshape(spinvec_atom, (/3, itmp/))

        !now apply the symmetries
        call rotate_kpoints(rotmat, nkpts*ndeg*natyp, arrtmp1, nsym, isym, nkpts_tmp, arrtmp2)
        if(nkpts_r*ndeg*natyp /= nkpts_tmp) stop 'nkpts_r*ndeg /= nkpts_tmp'

        !transform back to old shape
        allocate(spinvec_atom_r(3,natyp,ndeg,nkpts_r), STAT=ierr)
        if(ierr/=0) stop 'problem allocating spinvec_atom_r'
        spinvec_atom_r = reshape(arrtmp2,(/3,natyp,ndeg,nkpts_r/))

        deallocate(arrtmp1, arrtmp2)
      end if!allocated(spinvec_atom)

      if(allocated(spinflux))then
        !next apply symmetries to spinflux; as a first step, flatten the array
        itmp = size(spinflux)/3
        allocate(arrtmp1(3,itmp), STAT=ierr)
        if(ierr/=0) stop 'problem alloaction arrtmp1'
        arrtmp1 = reshape(spinflux, (/3, itmp/))

        !now apply the symmetries
        call rotate_kpoints(rotmat, nkpts*ndeg*natyp, arrtmp1, nsym, isym, nkpts_tmp, arrtmp2)
        if(nkpts_r*ndeg*natyp /= nkpts_tmp) stop 'nkpts_r*ndeg*natyp /= nkpts_tmp'

        !transform back to old shape
        allocate(spinflux_r(3,natyp,ndeg,nkpts_r), STAT=ierr)
        if(ierr/=0) stop 'problem allocating spinflux_r'
        spinflux_r = reshape(arrtmp2,(/3,natyp,ndeg,nkpts_r/))

        deallocate(arrtmp1, arrtmp2)
      end if!allocated(spinflux)

    else
      nkpts_r = nkpts

      allocate(fermivel_r(3,nkpts_r), areas_r(nkpts_r))
      fermivel_r = fermivel
      areas_r = areas

      if(allocated(torqval)) then
        allocate(torqval_r(3,ndeg,nkpts_r))
        torqval_r  = torqval
      end if!(allocated(torqval))

      if(allocated(torqval_atom)) then
        allocate(torqval_atom_r(3,natyp,ndeg,nkpts_r))
        torqval_atom_r  = torqval_atom
      end if!(allocated(torqval))

      if(allocated(spinvec_atom)) then
        allocate(spinvec_atom_r(3,natyp,ndeg,nkpts_r))
        spinvec_atom_r  = spinvec_atom
      end if!(allocated(spinvec))

      if(allocated(spinflux)) then
        allocate(spinflux_r(3,natyp,ndeg,nkpts_r))
        spinflux_r = spinflux
      end if!(allocated(spinflux))
    end if!nsym>1

    !compute response functions
    integ_torkance      = 0d0
    integ_torkance_atom = 0d0
    integ_damping       = 0d0
    integ_spinacc_atom  = 0d0
    integ_spinflux      = 0d0

    do ikp=1,nkpts_r
     vabs = sqrt(sum(fermivel_r(:,ikp)**2))
     do ideg=1,ndeg
      do i1=1,3
       do i2=1,3
        if(allocated(torqval))      &
        &  integ_torkance(i2,i1)        = integ_torkance(i2,i1)        + areas_r(ikp)*torqval_r(i1,ideg,ikp)*fermivel_r(i2,ikp)/(vabs)
        if(allocated(torqval_atom)) &
        &  integ_torkance_atom(i2,i1,:) = integ_torkance_atom(i2,i1,:) + areas_r(ikp)*torqval_atom_r(i1,:,ideg,ikp)*fermivel_r(i2,ikp)/(vabs)
        if(allocated(torqval))      &
        &  integ_damping(i2,i1)         = integ_damping(i2,i1)         + areas_r(ikp)*torqval_r(i1,ideg,ikp)*torqval_r(i2,ideg,ikp)/(vabs)
        if(allocated(spinvec_atom)) &
        &  integ_spinacc_atom(i2,i1,:)  = integ_spinacc_atom(i2,i1,:)  + areas_r(ikp)*spinvec_atom_r(i1,:,ideg,ikp)*fermivel_r(i2,ikp)/(vabs)
        if(allocated(spinflux))     &
        &  integ_spinflux(i2,i1,:)      = integ_spinflux(i2,i1,:)      + areas_r(ikp)*spinflux_r(i1,:,ideg,ikp)*fermivel_r(i2,ikp)/(vabs)
       end do!i2
      end do!i1
     end do!ideg
    end do!ikp

    if(allocated(torqval)) then
      torkance = integ_torkance/BZVol*alat/tpi

      if(myrank==master)then
        if(nsym/=1) write(*,*) 'ATTENTION: nsym =/= 1, make sure the following output is correct'
        write(*,'(A)')
        write(*,'(A)') "Torkance / relaxation time [in constant relaxation time approximation]:"
        write(*,'(A)') "  in units of e*abohr Rydberg:"
        write(*,'(3(ES25.16))') torkance
        write(*,'(A)')   
        write(*,'(A)') "  in units of e*abohr / fs:     "
        write(*,'(3(ES25.16))') torkance*RyToinvfs
        write(*,'(A)')
        write(*,'(A)') "Torkance at room temperature [in constant relaxation time approximation]:"
        write(*,'(A)') "  in units of e*abohr using hbar/(2*tau) = 25 meV:"
        write(*,'(3(ES25.16))') torkance*13.60569253/(2*25*0.001)
        write(*,'(A)')
      end if!myrank==master
    end if!allocated(torqval)

    if(allocated(torqval_atom)) then
      torkance_atom = integ_torkance_atom/BZVol*alat/tpi

      if(myrank==master)then
        open(unit=iounit,file="torkance.CRTA.int.dat",form='formatted',action='write')
        write(iounit,'(1I8)') natyp
        write(iounit,'(9(ES25.16))') torkance_atom*13.60569253/(2*25*0.001)
        close(iounit)
      end if!myrank==master
    end if!allocated(torqval_atom)

    if(allocated(torqval)) then
      damping = integ_damping/BZVol

      if(myrank==master)then
        if(nsym/=1) write(*,*) 'ATTENTION: nsym =/= 1, make sure the following output is correct'
        write(*,'(A)') "Gilbert damping in constant relaxation time approximation:"
        write(*,'(A)') "In units of  Rydberg:"
        write(*,'(3(ES25.16))') damping
        write(*,'(A)') "In units of eV:"
        write(*,'(3(ES25.16))') damping*13.60569253
        write(*,'(A)') "For room temperature (hbar/(2*tau) = 25 meV):"
        write(*,'(3(ES25.16))') damping*13.60569253/(2*25*0.001)
      end if!myrank==master
    end if!allocated(torqval)

    if(allocated(spinvec_atom)) then
!      spinacc_atom = -integ_spinacc_atom/BZVol*alat/tpi ! units of (e a_0 mu_B)/(Rd)
!     change sign because magnetic moment and angular momentum have opposite sign
      spinacc_atom = integ_spinacc_atom/BZVol*alat/tpi ! units of (e a_0 mu_B)/(Rd)

      if(myrank==master)then
        open(unit=iounit,file="spinacc_resp.CRTA.int.dat",form='formatted',action='write')
        write(iounit,'(1I8)') natyp
        write(iounit,'(9(ES25.16))') spinacc_atom*13.60569253/(2*25*0.001)
        close(iounit)
      end if!myrank==master
    end if!allocated(spinvec_atom)

    if(allocated(spinflux)) then
!      spinflux_resp = integ_spinflux/BZVol*alat/tpi
!     change sign because we want the spin flux that flows INTO the MT
      spinflux_resp = -integ_spinflux/BZVol*alat/tpi

      if(myrank==master)then
        open(unit=iounit,file="spinflux_resp.CRTA.int.dat",form='formatted',action='write')
        write(iounit,'(1I8)') natyp
        write(iounit,'(9(ES25.16))') spinflux_resp*13.60569253/(2*25*0.001)
        close(iounit)
      end if!myrank==master
    end if!allocated(spinflux)

  end subroutine calculate_response_functions_CRTA_int


  subroutine calculate_response_functions_CRTA_vis(nBZdim,nsym,isym,rotmat,alat,BZVol,ndeg,natyp,nkpts,nkpts_all,kpt2irr,irr2kpt,kpoints,fermivel,torqval,torqval_atom,spinvec_atom,spinflux)
    use mpi
    use mod_mympi,      only: myrank, master
    use mod_mathtools,  only: tpi, crossprod
    use mod_symmetries, only: rotate_kpoints, expand_visarrays
    use mod_mathtools,  only: simple_integration_general
    implicit none

    integer,          intent(in)  :: nBZdim, nsym, ndeg, natyp, nkpts, nkpts_all, kpt2irr(nkpts_all), irr2kpt(nkpts), isym(nsym)
    double precision, intent(in)  :: alat, BZVol, kpoints(3,nkpts)
    double precision, intent(in)  :: rotmat(64,3,3), fermivel(3,nkpts)
!    double precision, allocatable, intent(in)  :: torqval(:,:,:)      !torqval(3,ndeg,nkpts)
    double precision, allocatable, intent(in)  :: torqval(:,:,:)      !torqval(3,ndeg,nkpts)
    double precision, allocatable, intent(in)  :: torqval_atom(:,:,:,:) !torqval_atom(3,natypd,ndeg,nkpts)
    double precision, allocatable, intent(in)  :: spinvec_atom(:,:,:,:) !spinvec_atom(3,natypd,ndeg,nkpts)
    double precision, allocatable, intent(in)  :: spinflux(:,:,:,:)   !spinflux(3,natypd,ndegen,nkpts)

    integer,          allocatable :: irr2kpt_r(:), kpt2irr_r(:)
    double precision, allocatable :: kpoints_r(:,:), fermivel_r(:,:), arrtmp1(:,:), arrtmp2(:,:)
    double precision, allocatable :: torqval_r(:,:,:), torqval_atom_r(:,:,:,:), spinvec_atom_r(:,:,:,:), spinflux_r(:,:,:,:)

    integer :: ierr, ikp, i1, i2, i3, iat, ideg, itmp, nkpts_tmp, nkpts_r, nkpts_all_r, iline
    integer :: pointspick(nBZdim)
    double precision :: kpoints_corners(3,nBZdim), fermi_velocity_corners(3,nBZdim), torq_corners(3,ndeg,nBZdim), torq_corners_atom(3,natyp,ndeg,nBZdim), spinvec_corners_atom(3,natyp,ndeg,nBZdim), spinflux_corners(3,natyp,ndeg,nBZdim)
    double precision :: k21(3), k31(3), kcross(3), area, integrand(nBZdim), dinteg, d_dos, dos
    double precision :: torkance(3,3), torkance_atom(3,3,natyp), damping(3,3), spinacc_atom(3,3,natyp), spinflux_resp(3,3,natyp)
    double precision :: integ_torkance(3,3), integ_torkance_atom(3,3,natyp), integ_damping(3,3), integ_spinacc_atom(3,3,natyp), integ_spinflux(3,3,natyp)
    double precision :: vabs
    double precision, parameter :: RyToinvfs = 20.67068667282055d0
    integer, parameter :: iounit=13518

    if(nsym>1)then
      !apply symmetries to kpoints and visarray
      call rotate_kpoints(rotmat, nkpts, kpoints, nsym, isym, nkpts_r, kpoints_r)
      call expand_visarrays(nsym, nkpts_all, nkpts, kpt2irr, irr2kpt, kpt2irr_r, irr2kpt_r)

      !apply symmetries to fermivel and areas
      call rotate_kpoints(rotmat, nkpts, fermivel, nsym, isym, nkpts_r, fermivel_r)

      if(allocated(torqval))then
        !next apply symmetries to torqval; as a first step, flatten the array
        itmp = size(torqval)/3
        allocate(arrtmp1(3,itmp), STAT=ierr)
        if(ierr/=0) stop 'problem alloaction arrtmp1'
        arrtmp1 = reshape(torqval, (/3, itmp/))

        !now apply the symmetries
        call rotate_kpoints(rotmat, nkpts*ndeg, arrtmp1, nsym, isym, nkpts_tmp, arrtmp2)
        if(nkpts_r*ndeg /= nkpts_tmp) stop 'nkpts_r*ndeg /= nkpts_tmp'

        !transform back to old shape
        allocate(torqval_r(3,ndeg,nkpts_r), STAT=ierr)
        if(ierr/=0) stop 'problem allocating torqval_r'
        torqval_r = reshape(arrtmp2,(/3,ndeg,nkpts_r/))

        deallocate(arrtmp1, arrtmp2)
      end if!allocated(torqval)

      if(allocated(torqval_atom))then
        !next apply symmetries to torqval_atom; as a first step, flatten the array
        itmp = size(torqval_atom)/3
        allocate(arrtmp1(3,itmp), STAT=ierr)
        if(ierr/=0) stop 'problem alloaction arrtmp1'
        arrtmp1 = reshape(torqval_atom, (/3, itmp/))

        !now apply the symmetries
        call rotate_kpoints(rotmat, nkpts*ndeg*natyp, arrtmp1, nsym, isym, nkpts_tmp, arrtmp2)
        if(nkpts_r*ndeg*natyp /= nkpts_tmp) stop 'nkpts_r*ndeg /= nkpts_tmp'

        !transform back to old shape
        allocate(torqval_atom_r(3,natyp,ndeg,nkpts_r), STAT=ierr)
        if(ierr/=0) stop 'problem allocating torqval_atom_r'
        torqval_atom_r = reshape(arrtmp2,(/3,natyp,ndeg,nkpts_r/))

        deallocate(arrtmp1, arrtmp2)
      end if!allocated(torqval_atom)

      if(allocated(spinvec_atom))then
        !next apply symmetries to spinvec_atom; as a first step, flatten the array
        itmp = size(spinvec_atom)/3
        allocate(arrtmp1(3,itmp), STAT=ierr)
        if(ierr/=0) stop 'problem alloaction arrtmp1'
        arrtmp1 = reshape(spinvec_atom, (/3, itmp/))

        !now apply the symmetries
        call rotate_kpoints(rotmat, nkpts*ndeg*natyp, arrtmp1, nsym, isym, nkpts_tmp, arrtmp2)
        if(nkpts_r*ndeg*natyp /= nkpts_tmp) stop 'nkpts_r*ndeg /= nkpts_tmp'

        !transform back to old shape
        allocate(spinvec_atom_r(3,natyp,ndeg,nkpts_r), STAT=ierr)
        if(ierr/=0) stop 'problem allocating spinvec_atom_r'
        spinvec_atom_r = reshape(arrtmp2,(/3,natyp,ndeg,nkpts_r/))

        deallocate(arrtmp1, arrtmp2)
      end if!allocated(spinvec_atom)

      if(allocated(spinflux))then
        !next apply symmetries to spinflux; as a first step, flatten the array
        itmp = size(spinflux)/3
        allocate(arrtmp1(3,itmp), STAT=ierr)
        if(ierr/=0) stop 'problem alloaction arrtmp1'
        arrtmp1 = reshape(spinflux, (/3, itmp/))

        !now apply the symmetries
        call rotate_kpoints(rotmat, nkpts*ndeg*natyp, arrtmp1, nsym, isym, nkpts_tmp, arrtmp2)
        if(nkpts_r*ndeg*natyp /= nkpts_tmp) stop 'nkpts_r*ndeg*natyp /= nkpts_tmp'

        !transform back to old shape
        allocate(spinflux_r(3,natyp,ndeg,nkpts_r), STAT=ierr)
        if(ierr/=0) stop 'problem allocating spinflux_r'
        spinflux_r = reshape(arrtmp2,(/3,natyp,ndeg,nkpts_r/))

        deallocate(arrtmp1, arrtmp2)
      end if!allocated(spinflux)

      nkpts_all_r = nkpts_all*nsym

    else
      nkpts_r = nkpts
      allocate(fermivel_r(3,nkpts_r), kpoints_r(3,nkpts), kpt2irr_r(nkpts_all))
      kpoints_r  = kpoints
      kpt2irr_r  = kpt2irr
      nkpts_all_r = nkpts_all*nsym
      fermivel_r = fermivel

      if(allocated(torqval)) then
        allocate(torqval_r(3,ndeg,nkpts_r))
        torqval_r  = torqval
      end if!(allocated(torqval))

      if(allocated(torqval_atom)) then
        allocate(torqval_atom_r(3,natyp,ndeg,nkpts_r))
        torqval_atom_r  = torqval_atom
      end if!(allocated(torqval))

      if(allocated(spinvec_atom)) then
        allocate(spinvec_atom_r(3,natyp,ndeg,nkpts_r))
        spinvec_atom_r  = spinvec_atom
      end if!(allocated(spinvec))

      if(allocated(spinflux)) then
        allocate(spinflux_r(3,natyp,ndeg,nkpts_r))
        spinflux_r = spinflux
      end if!(allocated(spinflux))
    end if

    !compute response functions
    integ_torkance      = 0d0
    integ_torkance_atom = 0d0
    integ_damping       = 0d0
    integ_spinacc_atom  = 0d0
    integ_spinflux      = 0d0

    dos    = 0d0
    do iline=1,nkpts_all_r/nBZdim

      do i3=1,nBZdim
        pointspick(i3) = kpt2irr_r((iline-1)*nBZdim+i3)
      end do!i3

      !rewrite corner point data
      kpoints_corners(:,:)        = kpoints_r(:,pointspick(:))
      fermi_velocity_corners(:,:) = fermivel_r(:,pointspick(:))
      if(allocated(torqval)) torq_corners(:,:,:) = torqval_r(:,:,pointspick(:))
      if(allocated(torqval_atom)) torq_corners_atom(:,:,:,:) = torqval_atom_r(:,:,:,pointspick(:))
      if(allocated(spinvec_atom)) spinvec_corners_atom(:,:,:,:) = spinvec_atom_r(:,:,:,pointspick(:))
      if(allocated(spinflux)) spinflux_corners(:,:,:,:) = spinflux_r(:,:,:,pointspick(:))

      if(nBZdim==3)then
        !compute area
        k21 = kpoints_corners(:,2) - kpoints_corners(:,1)
        k31 = kpoints_corners(:,3) - kpoints_corners(:,1)
        call crossprod(k21, k31, kcross)
        area = 0.5d0*sqrt(sum(kcross**2))
      elseif(nBZdim==2)then
        area = sqrt(sum((kpoints_corners(:,2) - kpoints_corners(:,1))**2))
      else!nBZdim
        stop 'nBZdim is neither 2 nor 3'
      end if!nBZdim

      do ideg=1,ndeg
       do i1=1,3
        do i2=1,3
         if(allocated(torqval))then
           integrand(:) = torq_corners(i1,ideg,:)*fermi_velocity_corners(i2,:)
           call simple_integration_general(nBZdim, area, fermi_velocity_corners, integrand, dinteg, d_dos)
           integ_torkance(i2,i1) = integ_torkance(i2,i1) + dinteg
         end if!allocated(torqval)
         if(allocated(torqval_atom))then
           do iat=1,natyp
             integrand(:) = torq_corners_atom(i1,iat,ideg,:)*fermi_velocity_corners(i2,:)
             call simple_integration_general(nBZdim, area, fermi_velocity_corners, integrand, dinteg, d_dos)
             integ_torkance_atom(i2,i1,iat) = integ_torkance_atom(i2,i1,iat) + dinteg
           end do!iat
         end if!allocated(torqval_atom)
         if(allocated(torqval))then
           integrand(:) = torq_corners(i1,ideg,:)*torq_corners(i2,ideg,:)
           call simple_integration_general(nBZdim, area, fermi_velocity_corners, integrand, dinteg, d_dos)
           integ_damping(i2,i1) = integ_damping(i2,i1) + dinteg
         end if!allocated(torqval)
         if(allocated(spinvec_atom))then
           do iat=1,natyp
             integrand(:) = spinvec_corners_atom(i1,iat,ideg,:)*fermi_velocity_corners(i2,:)
             call simple_integration_general(nBZdim, area, fermi_velocity_corners, integrand, dinteg, d_dos)
             integ_spinacc_atom(i2,i1,iat) = integ_spinacc_atom(i2,i1,iat) + dinteg
           end do!iat
         end if!allocated(spinvec_atom)
         if(allocated(spinflux))then
           do iat=1,natyp
             integrand(:) = spinflux_corners(i1,iat,ideg,:)*fermi_velocity_corners(i2,:)
             call simple_integration_general(nBZdim, area, fermi_velocity_corners, integrand, dinteg, d_dos)
             integ_spinflux(i2,i1,iat) = integ_spinflux(i2,i1,iat) + dinteg
           end do!iat
         end if!allocated(spinflux)
        end do!i2
       end do!i1
      end do!ideg
      dos = dos+d_dos
    end do!iline
    if(allocated(torqval)) then
      torkance = integ_torkance/BZVol*alat/tpi

      if(myrank==master)then
        if(nsym/=1) write(*,*) 'ATTENTION: nsym =/= 1, make sure the following output is correct'
        write(*,'(A)')
        write(*,'(A)') "Torkance / relaxation time [in constant relaxation time approximation]:"
        write(*,'(A)') "  in units of e*abohr Rydberg:"
        write(*,'(3(ES25.16))') torkance
        write(*,'(A)')
        write(*,'(A)') "In units of e*abohr / fs:"
        write(*,'(3(ES25.16))') torkance*RyToinvfs
        write(*,'(A)')
        write(*,'(A)') "Torkance at room temperature [in constant relaxation time approximation]:"
        write(*,'(A)') "  in units of e*abohr using hbar/(2*tau) = 25 meV:"
        write(*,'(3(ES25.16))') torkance*13.60569253/(2*25*0.001)
      end if!myrank==master
    end if!allocated(torqval)
    
    if(allocated(torqval_atom)) then
      torkance_atom = integ_torkance_atom/BZVol*alat/tpi

      if(myrank==master)then
        open(unit=iounit,file="torkance.CRTA.vis.dat",form='formatted',action='write')
        write(iounit,'(1I8)') natyp
        write(iounit,'(9(ES25.16))') torkance_atom*13.60569253/(2*25*0.001)
        close(iounit)
      end if!myrank==master
    end if!allocated(torqval_atom)

    if(allocated(torqval)) then
      damping = integ_damping/BZVol

      if(myrank==master)then
        write(*,'(A)') "Gilbert damping in constant relaxation time approximation:"
        write(*,'(A)') "In units of  Rydberg:"
        write(*,'(3(ES25.16))') damping
        write(*,'(A)') "In units of eV:"
        write(*,'(3(ES25.16))') damping*13.60569253
        write(*,'(A)') "For room temperature (hbar/(2*tau) = 25 meV):"
        write(*,'(3(ES25.16))') damping*13.60569253/(2*25*0.001)
      end if!myrank==master
    end if!allocated(torqval)

    if(allocated(spinvec_atom)) then
!      spinacc_atom = -integ_spinacc_atom*(2)**0.5/BZVol*alat/tpi ! sqrt(2) for mu_B
!     change sign because magnetic moment and angular momentum have opposite sign
      spinacc_atom = integ_spinacc_atom/BZVol*alat/tpi

      if(myrank==master)then
        open(unit=iounit,file="spinacc_resp.CRTA.vis.dat",form='formatted',action='write')
        write(iounit,'(1I8)') natyp
        write(iounit,'(9(ES25.16))') spinacc_atom*13.60569253/(2*25*0.001)
        close(iounit)
      end if!myrank==master
    end if!allocated(spinvec_atom)

    if(allocated(spinflux)) then
      spinflux_resp = integ_spinflux/BZVol*alat/tpi

      if(myrank==master)then
        open(unit=iounit,file="spinflux_resp.CRTA.vis.dat",form='formatted',action='write')
        write(iounit,'(1I8)') natyp
        write(iounit,'(9(ES25.16))') spinflux_resp*13.60569253/(2*25*0.001)
        close(iounit)
      end if!myrank==master
    end if!allocated(spinflux)

  end subroutine calculate_response_functions_CRTA_vis

  subroutine calculate_torkance_CRTA_vis_simpson2D(nsym,isym,rotmat,alat,BZVol,ndeg,nkpts,nkpts_all,kpt2irr,irr2kpt,kpoints,fermivel,torqval)
    use mpi
    use mod_mympi,      only: myrank, master
    use mod_mathtools,  only: tpi, crossprod
    use mod_symmetries, only: rotate_kpoints, expand_visarrays
    use mod_mathtools,  only: simple_integration_general, simpson2D_integration
    implicit none

    integer,          intent(in)  :: nsym, ndeg, nkpts, nkpts_all, kpt2irr(nkpts_all), irr2kpt(nkpts), isym(nsym)
    double precision, intent(in)  :: alat, BZVol, kpoints(3,nkpts)
    double precision, intent(in)  :: rotmat(64,3,3), fermivel(3,nkpts), torqval(3,ndeg,nkpts)

    integer,          allocatable :: irr2kpt_r(:), kpt2irr_r(:),  kpt2irr_r_ord(:), band_indices_r(:), nkpts_band(:)
    double precision, allocatable :: kpoints_r(:,:), fermivel_r(:,:), torqval_r(:,:,:), arrtmp1(:,:), arrtmp2(:,:)

    integer :: ierr, ikp, i1, i2, i3, ideg, itmp, nkpts_tmp, nkpts_r, nkpts_all_r, nparts, ipart, iband, nbands, offset
    integer :: pointspick(3)
    logical :: fourmultiple
    double precision :: kpoints_corners(3,3), fermi_velocity_corners(3,3), torq_corners(3,ndeg,3), k21(3), k31(3), kcross(3)
    double precision :: d(2), integrand(3), integrand_damping(3), dinteg, dinteg_damping, d_dos, dos
    double precision :: torkance(3,3), damping(3,3)
    double precision :: integ(3,3), integ_damping(3,3), vabs
    double precision, parameter :: RyToinvfs = 20.67068667282055d0

    nkpts_all_r = nkpts_all*nsym

    if(nsym>1)then
      !apply symmetries to kpoints and visarray
      call rotate_kpoints(rotmat, nkpts, kpoints, nsym, isym, nkpts_r, kpoints_r)
      call expand_visarrays(nsym, nkpts_all, nkpts, kpt2irr, irr2kpt, kpt2irr_r, irr2kpt_r)

      allocate(kpt2irr_r_ord(nkpts_all_r),band_indices_r(nkpts_all_r), STAT=ierr)
      if(ierr/=0) stop 'problem allocating kpt2irr_r_ord and band_indices_r'

      !order kpoints according to lines
      call order_lines(kpt2irr_r, nkpts_all_r, kpt2irr_r_ord, band_indices_r, nkpts_band, nbands)
      write(*,*) 'ordered k-points according to bands'
      write(*,*) 'number of bands that were found : ', nbands

      !apply symmetries to fermivel and areas
      call rotate_kpoints(rotmat, nkpts, fermivel, nsym, isym, nkpts_r, fermivel_r)

      !next apply symmetries to torqval; as a first step, flatten the array
      itmp = size(torqval)/3
      allocate(arrtmp1(3,itmp), STAT=ierr)
      if(ierr/=0) stop 'problem alloaction arrtmp1'
      arrtmp1 = reshape(torqval, (/3, itmp/))

      !now apply the symmetries
      call rotate_kpoints(rotmat, nkpts*ndeg, arrtmp1, nsym, isym, nkpts_tmp, arrtmp2)
      if(nkpts_r*ndeg /= nkpts_tmp) stop 'nkpts_r*ndeg /= nkpts_tmp'

      !transform back to old shape
      allocate(torqval_r(3,ndeg,nkpts_r), STAT=ierr)
      if(ierr/=0) stop 'problem allocating torqval_r'
      torqval_r = reshape(arrtmp2,(/3,ndeg,nkpts_r/))

      deallocate(arrtmp1, arrtmp2)

      !nkpts_all_r = nkpts_all*nsym

    else
      write(*,*) 'it seems you want to use Simpson rule integration with nsym=1'
      write(*,*) 'this is not implemented yet (closed bands can not be found)'
      nkpts_r = nkpts
      allocate(fermivel_r(3,nkpts_r), torqval_r(3,ndeg,nkpts_r), kpoints_r(3,nkpts), kpt2irr_r(nkpts_all))
      kpoints_r  = kpoints
      kpt2irr_r  = kpt2irr
      fermivel_r = fermivel
      torqval_r  = torqval
      !nkpts_all_r = nkpts_all*nsym
    end if

    !torkance and damping
    integ  = 0d0
    integ_damping = 0d0
    dos    = 0d0


    do iband=1, nbands     
      if(MOD(nkpts_band(iband), 4).ne.0) fourmultiple=.true.
      if(MOD(nkpts_band(iband), 4) == 0) fourmultiple=.false.
      !find how many parts of 3 or 2 kpts are in the band
      if(fourmultiple) nparts=nkpts_band(iband)/4
      if(.not.fourmultiple) nparts=(nkpts_band(iband)+2)/4

      do ipart=1,nparts
        if(iband>1)offset=sum(nkpts_band(1:iband-1))
        if(iband==1)offset=0
        pointspick(1) = kpt2irr_r_ord(offset+(ipart-1)*4+1)
        pointspick(2) = kpt2irr_r_ord(offset+(ipart-1)*4+2)
        if(.not.fourmultiple .and. ipart==nparts) then 
          !if no more kpt to save, save the same twice (but won't be used)
          pointspick(3) = kpt2irr_r_ord(offset+(ipart-1)*4+2)
        else
          pointspick(3) = kpt2irr_r_ord(offset+(ipart-1)*4+4)
        end if

        !rewrite corner point data
        kpoints_corners(:,:)        = kpoints_r(:,pointspick(:))
        fermi_velocity_corners(:,:) = fermivel_r(:,pointspick(:))
        torq_corners(:,:,:)         = torqval_r(:,:,pointspick(:))

        d(1) = sqrt(sum((kpoints_corners(:,2) - kpoints_corners(:,1))**2))
        d(2) = sqrt(sum((kpoints_corners(:,3) - kpoints_corners(:,2))**2))

        do ideg=1,ndeg
         do i1=1,3
          do i2=1,3
           integrand(:) = torq_corners(i1,ideg,:)*fermi_velocity_corners(i2,:)
           integrand_damping(:) = torq_corners(i1,ideg,:)*torq_corners(i2,ideg,:)
         
           if (.not.fourmultiple .and. ipart==nparts) then
             call simple_integration_general(2, d(1), fermi_velocity_corners(:,1:2), integrand(1:2), dinteg, d_dos)
             call simple_integration_general(2, d(1), fermi_velocity_corners(:,1:2), integrand_damping(1:2), dinteg_damping, d_dos)
           else
             call simpson2D_integration(d,fermi_velocity_corners,integrand, dinteg, d_dos)
             call simpson2D_integration(d,fermi_velocity_corners,integrand_damping, dinteg_damping, d_dos)
           end if

           integ(i2,i1) = integ(i2,i1) + dinteg
           integ_damping(i2,i1) = integ_damping(i2,i1) + dinteg_damping
          end do!i2
         end do!i1
        end do!ideg
        dos = dos+d_dos
      end do!ipart
    end do!iband

    deallocate(kpt2irr_r_ord,band_indices_r)

    torkance = integ/BZVol*alat/tpi

    if(myrank==master)then
      if(nsym/=1) write(*,*) 'ATTENTION: nsym =/= 1, make sure the following output is correct'
!      write(*,'(A)') "Torkance per relaxation time in constant relaxation time approximation:"
!      write(*,'(A)') "In units of e*abohr Rydberg:"
      write(*,'(A)')
      write(*,'(A)') "Torkance / relaxation time [in constant relaxation time approximation]:"
      write(*,'(A)') "  in units of e*abohr Rydberg:"
      write(*,'(3(ES25.16))') torkance
      write(*,'(A)')
      write(*,'(A)') "  in units of e*abohr / fs:     "
!      write(*,'(A)') "In units of e*abohr / fs:"
      write(*,'(3(ES25.16))') torkance*RyToinvfs
!      write(*,'(A)') "In units of e*abohr for room temperature (hbar/(2*tau) = 25 meV) :"
      write(*,'(A)')
      write(*,'(A)') "Torkance at room temperature [in constant relaxation time approximation]:"
      write(*,'(A)') "  in units of e*abohr using hbar/(2*tau) = 25 meV:"
      write(*,'(3(ES25.16))') torkance*13.60569253/(2*25*0.001)
    end if!myrank==master

    damping = integ_damping/BZVol

    if(myrank==master)then
      if(nsym/=1) write(*,*) 'ATTENTION: nsym =/= 1, make sure the following output is correct'
      write(*,'(A)') "Gilbert damping in constant relaxation time approximation:"
      write(*,'(A)') "In units of  Rydberg:"
      write(*,'(3(ES25.16))') damping
      write(*,'(A)') "In units of eV:"
      write(*,'(3(ES25.16))') damping*13.60569253
      write(*,'(A)') "For room temperature (hbar/(2*tau) = 25 meV):"
      write(*,'(3(ES25.16))') damping*13.60569253/(2*25*0.001)
    end if!myrank==master

  end subroutine calculate_torkance_CRTA_vis_simpson2D


  subroutine order_lines(kpt2irr, nkpts_all, kpt2irr_ord, band_indices, nkpts_band, nbands)
    integer,         intent(in)       :: kpt2irr(nkpts_all)
    integer,         intent(in)       :: nkpts_all
    integer,         intent(out)      :: band_indices(nkpts_all), kpt2irr_ord(nkpts_all), nbands
    integer,         allocatable      :: nkpts_band(:)
    logical                           :: beginning_of_band
    integer                           :: i1, i2, i3, i_ord, i_band, ierr, i_ord_new

    ! This subroutine order k-pts according to the band to which they belong
    ! Output  : kpt2irr_ord contains the ordered k-pts
    !           band_indices contains the band indices
    !           nkpts_band(nbands) contain the nb of kpts in each band
    ! Comment : At the moment works only if no band makes a loop in the IBZ

    i_ord =1
    i_band=1    
    !loop over the k-points to find the beginning of bands
    do i1=1,nkpts_all
      beginning_of_band=.true.

      ! check if i1 is the beginning of a band
      do i2=1,nkpts_all
        if(kpt2irr(i2)==kpt2irr(i1) .and. i1/=i2)then
          beginning_of_band=.false.
          exit
        end if!kpt2irr(i2)==kpt2irr(i1)
      end do!i2=i1+1,nkpts_all

      ! check if i1 was not already treated (it could be the end of a band)
      if (i_ord>1)then
        do i3=1, i_ord-1
          if(kpt2irr_ord(i3)==kpt2irr(i1))then
            beginning_of_band=.false.
            exit
          end if!kpt2irr_ord(i3)==kpt2irr(i1)
        end do!i3=1, i_ord-1
      end if!i_ord>1

      !save all kpts from the band
      if(beginning_of_band)then
        call traceback_band(i_ord,i_band,i1,kpt2irr,nkpts_all,kpt2irr_ord,band_indices,i_ord_new)
        i_ord=i_ord_new
        i_band=i_band+1
      end if!end_of_band=.true.

    end do!i1=1,nkpts_all    

    nbands=i_band-1
    allocate(nkpts_band(nbands), STAT=ierr)
    if(ierr/=0) stop 'problem allocating nkpts_band'

    ! count number of kpts for each band
    nkpts_band = 0
    do i1=1,nkpts_all
      do i_band=1, nbands
        if(band_indices(i1)==i_band) nkpts_band(i_band) = nkpts_band(i_band)+1
      end do!i_band=1, nbands
    end do! i1=1,nkpts_all

    if (sum(nkpts_band(:))/=nkpts_all) stop 'Some kpts were not found in order_lines(). Probably there is band that makes a loop in the IBZ. '
    
  end subroutine

  recursive subroutine traceback_band(i_ord, i_band, i, kpt2irr, nkpts_all, kpt2irr_ord, band_indices, i_ord_new)
    integer,         intent(in)   :: kpt2irr(nkpts_all)
    integer,         intent(in)   :: nkpts_all
    integer,         intent(in)   :: i_ord, i_band, i
    integer,         intent(out)  :: band_indices(nkpts_all), kpt2irr_ord(nkpts_all)
    integer                       :: i_ord_new
    integer                       :: i_sameline, j          
    logical                       :: end_of_band

    ! This routine calls itself recursively until the end of the band is reached 

    if(MOD(i, 2).ne.0) i_sameline = i+1 ! i is odd
    if(MOD(i, 2) == 0) i_sameline = i-1 ! i is even
    
    ! save the 2 kpts of the current line and the band indices 
    kpt2irr_ord(i_ord)=kpt2irr(i)
    kpt2irr_ord(i_ord+1)=kpt2irr(i_sameline) 
    band_indices(i_ord)=i_band
    band_indices(i_ord+1)=i_band

    end_of_band=.true.
    ! check if i_sameline is the end of a band
    do j=1,nkpts_all
      if(kpt2irr(j)==kpt2irr(i_sameline) .and. j.ne.i_sameline)then
        end_of_band=.false.
        exit
      end if!kpt2irr(j)==kpt2irr(i_sameline) .and. j.ne.i_sameline
    end do!j=1,nkpts_all

    if(.not.end_of_band)then
      call traceback_band(i_ord+2, i_band, j, kpt2irr, nkpts_all, kpt2irr_ord, band_indices, i_ord_new) 
    else
      i_ord_new=i_ord+2
    end if!end_of_band==.false. 
 
  end subroutine



  subroutine calculate_spinmixing_int(nsym, ndeg,nsqa,nkpts,areas,fermivel,spinval,spinmix,dos,printout,BZVol)
    use mpi
    use mod_mympi, only: myrank, master
    implicit none

    integer,          intent(in)  :: nsym,ndeg, nsqa, nkpts
    double precision, intent(in)  :: areas(nkpts), fermivel(3,nkpts), spinval(ndeg,nsqa,nkpts)
    double precision, intent(out) :: spinmix(nsqa), dos
    logical,          intent(in)  :: printout
    double precision, intent(in), optional :: BZVol

    integer :: isqa, ikp
    double precision :: integ(nsqa), vabs

    integ  = 0d0
    dos  = 0d0
    do ikp=1,nkpts
      vabs = sqrt(sum(fermivel(:,ikp)**2))
      dos  = dos +areas(ikp)/vabs
      integ(:) = integ(:)+areas(ikp)*(1d0-abs(spinval(1,:,ikp)))/(2*vabs)
    end do!ikp

    spinmix = integ/dos

    if(printout .and. myrank==master)then
      write(*,'(A,ES25.16,A)') "DOS(E_F)=", nsym*dos, " [unnormalized]"
      if(present(BZVol)) write(*,'(A,ES25.16,A)') "DOS(E_F)=", nsym*dos/BZVol, " [normalized]"
      do isqa=1,nsqa
        write(*,'(A,I4,3(A,ES25.16))') "Elliott-Yafet parameter: isqa= ", isqa,", b^2= ", nsym*integ(isqa)," [unnormalized], ", spinmix(isqa), " [normalized by DOS]"
      end do!isqa
    end if!printout

  end subroutine calculate_spinmixing_int





  subroutine calculate_dos_int(nsym,isym,rotmat,alat,BZVol,nkpts,areas,fermivel,BZdim)
    use mpi
    use mod_mympi,      only: myrank, master
    use mod_mathtools,  only: tpi
    use mod_symmetries, only: rotate_kpoints, expand_areas
    implicit none

    integer,          intent(in)  :: nsym,nkpts, isym(nsym), BZdim
    double precision, intent(in)  :: rotmat(64,3,3), alat, BZVol, areas(nkpts), fermivel(3,nkpts)

    integer :: ikp, i1, i2, nkpts_r
    double precision :: dos, vabs, conductivity(3,3), dtmp

    double precision, allocatable :: fermivel_r(:,:), areas_r(:)

    double precision, parameter :: e2byhbar = 2.434134807664281d-4, abohr = 0.52917721092d-10, RyToinvfs = 20.67068667282055d0

    dos  = 0d0
    do ikp=1,nkpts
      vabs = sqrt(sum(fermivel(:,ikp)**2))
      dos  = dos +areas(ikp)/vabs
    end do!ikp

    if(myrank==master)then
      write(*,'(A,ES25.16,A)') "DOS(E_F)=", nsym*dos, " [unnormalized]"
      write(*,'(A,ES25.16,A)') "DOS(E_F)=", nsym*dos/BZVol, " [normalized]"
    end if!myrank==master

    if(myrank==master) write(*,'(A,I0,A,48I4)') 'nsym=', nsym, ', isym=', isym

    if(nsym>1)then
      call rotate_kpoints(rotmat, nkpts, fermivel, nsym, isym, nkpts_r, fermivel_r)
      call expand_areas(nsym,nkpts,areas,areas_r)
    else
      nkpts_r = nkpts
      allocate(fermivel_r(3,nkpts_r), areas_r(nkpts_r))
      fermivel_r = fermivel
      areas_r    = areas
    end if

    conductivity=0d0
    do ikp=1,nkpts_r
      vabs = sqrt(sum(fermivel_r(:,ikp)**2))
      dtmp = areas_r(ikp)/vabs
      do i1=1,3
        do i2=1,3
          conductivity(i2,i1) = conductivity(i2,i1) + dtmp*fermivel_r(i2,ikp)*fermivel_r(i1,ikp)
        end do!i2
      end do!i1
    end do!ikp

    if(BZdim==3)then    
      conductivity = conductivity/(alat*tpi**2)

      if(myrank==master)then
        write(*,'(A)') "Conductivity / relaxation time  [in constant relaxation time approximation]:"
        write(*,'(A)') "  in Rydberg:"
        write(*,'(3ES25.16)') conductivity*2 !factor 2 because e^2 = 2 in Rydberg units
        write(*,'(A)') "  in siemens/(meter * femtosecond):"
        write(*,'(3ES25.16)') conductivity*e2byhbar/abohr*RyToinvfs
        write(*,'(A)') "  in siemens/meter for room temperature (hbar/(2*tau) = 25 meV) :"
        write(*,'(3ES25.16)') conductivity*e2byhbar/abohr*13.60569253/(2*25*0.001)
      end if!myrank==master

    elseif (BZdim==2)then
      conductivity = conductivity*e2byhbar/(tpi**2)/alat/abohr

      if(myrank==master)then
        write(*,'(A)')
        write(*,'(A)') "2D MODE : The following values have to be divided by the thickness of the film"
        write(*,'(A)') "          in unit of the lattice constant (ALAT) to obtain the conductivity"
        write(*,'(A)') "          in the corresponding units."
        write(*,'(A)')
        write(*,'(A)') "Conductivity / relaxation time [in constant relaxation time approximation]:"
        write(*,'(A)') "  in (siemens/m)*Rydberg:"
        write(*,'(3ES25.16)') conductivity
        write(*,'(A)')
        write(*,'(A)') "  in (siemens/m)/(femtosecond):"
        write(*,'(3ES25.16)') conductivity*RyToinvfs
        write(*,'(A)')
        write(*,'(A)') "Conductivity at room temperature [in constant relaxation time approximation]:"
        write(*,'(A)') "  in (siemens/m) using hbar/(2*tau) = 25 meV :"
        write(*,'(3ES25.16)') conductivity*13.60569253/(2*25*0.001)
        write(*,'(A)')
      end if!myrank==master
    else
      stop 'BZdim is neiter 2 nor 3 !'
    endif

  end subroutine calculate_dos_int





  subroutine calculate_spinmixing_vis(nsym, ndeg,nsqa,nkpts,nkpts_all,kpt2irr,kpoints,fermivel,spinval,spinmix,dos,printout,BZVol,nBZdim)
    use mpi
    use mod_mympi, only: myrank, master
    use mod_mathtools, only: crossprod, simple_integration_general
    implicit none

    integer,          intent(in)  :: nsym,ndeg, nsqa, nkpts, nkpts_all, kpt2irr(nkpts_all), nBZdim
    double precision, intent(in)  :: kpoints(3,nkpts), fermivel(3,nkpts), spinval(ndeg,nsqa,nkpts)
    double precision, intent(out) :: spinmix(nsqa), dos
    logical,          intent(in)  :: printout
    double precision, intent(in)  :: BZVol

    integer :: isqa, iii, itri, pointspick(nBZdim)
    double precision :: integ(nsqa), vabs, kpoints_triangle(3,nBZdim), fermi_velocity_triangle(3,nBZdim), eyaf_triangle(nBZdim), k21(3), k31(3), kcross(3), area, d_integ, d_dos

    integ  = 0d0
    dos  = 0d0
    do itri=1,nkpts_all/nBZdim

      do iii=1,nBZdim
        pointspick(iii) = kpt2irr((itri-1)*nBZdim+iii)
      end do!iii

      !rewrite corner point data
      kpoints_triangle(:,:)        = kpoints(:,pointspick(:))
      fermi_velocity_triangle(:,:) = fermivel(:,pointspick(:))

      !compute area
      if(nBZdim==3)then
        k21 = kpoints_triangle(:,2) - kpoints_triangle(:,1)
        k31 = kpoints_triangle(:,3) - kpoints_triangle(:,1)
        call crossprod(k21, k31, kcross)
        area = 0.5d0*sqrt(sum(kcross**2))
      else if(nBZdim==2)then
        area = sqrt(sum((kpoints_triangle(:,2) - kpoints_triangle(:,1))**2))
      else
        stop 'nBZdim must be 2 or 3 in calculate_spinmixing_vis'
      end if

      do isqa=1,nsqa
        eyaf_triangle(:) = (1d0-abs(spinval(1,isqa,pointspick(:))))/2
        call simple_integration_general(nBZdim, area, fermi_velocity_triangle, eyaf_triangle, d_integ, d_dos)
        integ(isqa) = integ(isqa)+d_integ
      end do!isqa

      dos = dos+d_dos
    end do!ikp

    spinmix = integ/dos

    if(printout .and. myrank==master)then
      write(*,'(A,ES25.16,A)') "DOS(E_F)=", nsym*dos, " [unnormalized]"
      write(*,'(A,ES25.16,A)') "DOS(E_F)=", nsym*dos/BZVol, " [normalized]"
      do isqa=1,nsqa
        write(*,'(A,I4,3(A,ES25.16))') "Elliott-Yafet parameter: isqa= ", isqa,", b^2= ", nsym*integ(isqa)," [unnormalized], ", spinmix(isqa), " [normalized by DOS]"
      end do!isqa
    end if!printout

  end subroutine calculate_spinmixing_vis




  subroutine calculate_dos_vis(nsym,nkpts,nkpts_all,kpt2irr,kpoints,fermivel,dos,printout,BZVol)
    use mod_mympi, only: myrank, master
    use mod_mathtools, only: crossprod, simple_integration
    use mpi
    implicit none

    integer,          intent(in)  :: nsym, nkpts, nkpts_all, kpt2irr(nkpts_all)
    double precision, intent(in)  :: kpoints(3,nkpts), fermivel(3,nkpts)
    double precision, intent(out) :: dos
    logical,          intent(in)  :: printout
    double precision, intent(in), optional :: BZVol

    integer :: itri, pointspick(3)
    double precision :: integ, vabs, kpoints_triangle(3,3), fermi_velocity_triangle(3,3), dtmp3(3), k21(3), k31(3), kcross(3), area, dtmp, d_dos

    dtmp3 = 0d0
    dos  = 0d0

    do itri=1,nkpts_all/3

      pointspick(1) = kpt2irr((itri-1)*3+1)
      pointspick(2) = kpt2irr((itri-1)*3+2)
      pointspick(3) = kpt2irr((itri-1)*3+3)

      !rewrite corner point data
      kpoints_triangle(:,:)        = kpoints(:,pointspick(:))
      fermi_velocity_triangle(:,:) = fermivel(:,pointspick(:))

      !compute area
      k21 = kpoints_triangle(:,2) - kpoints_triangle(:,1)
      k31 = kpoints_triangle(:,3) - kpoints_triangle(:,1)
      call crossprod(k21, k31, kcross)
      area = 0.5d0*sqrt(sum(kcross**2))

      call simple_integration(area, fermi_velocity_triangle, dtmp3, dtmp, d_dos)
      dos = dos+d_dos

    end do!ikp

    if(printout .and. myrank==master)then
      write(*,'(A,ES25.16,A)') "DOS(E_F)=", nsym*dos, " [unnormalized]"
      if(present(BZVol)) write(*,'(A,ES25.16,A)') "DOS(E_F)=", nsym*dos/BZVol, " [normalized]"
    end if!printout

  end subroutine calculate_dos_vis



  integer function get_nsqa()
    implicit none
    if(.not.cfg_read .or. cfg%nsqa==-1 ) then
      call read_cfg(force_spinread=.true.)
    end if
    get_nsqa =cfg%nsqa
  end function



  subroutine calculate_and_save_weights(nkpts,nsym,isym,areas,fermivel)
    use mod_ioformat, only: fmt_fn_ext, filename_weights, ext_formatted
    implicit none
    integer, intent(in) :: nkpts, nsym, isym(nsym)
    double precision, intent(in) :: areas(nkpts), fermivel(3,nkpts)

    integer :: ikp
    double precision :: weights(nkpts)
    character(len=256) :: filename
    integer, parameter :: iounit=13516

    do ikp=1,nkpts
      weights(ikp) = areas(ikp)/sqrt(sum(fermivel(:,ikp)**2))
    end do

    write(filename,fmt_fn_ext) filename_weights, ext_formatted
    open(unit=iounit,file=trim(filename),form='formatted',action='write')
    write(iounit,'(2I8)') nkpts, nsym
    write(iounit,'(12I8)') isym
    write(iounit,'(10ES25.16)') weights
    close(iounit)

  end subroutine calculate_and_save_weights


end module mod_calconfs