Sophie

Sophie

distrib > Fedora > 18 > i386 > by-pkgid > 9fa01ead33f6cb147c452ccad90c9326 > files > 180

wannier90-2.0.0-1.fc18.i686.rpm

!-*- mode: F90; mode: font-lock; column-number-mode: true -*-!
!                                                            !
! Copyright (C) 2012 Daniel Aberg                            !
!                                                            !
! This file is distributed under the terms of the GNU        !
! General Public License. See the file `LICENSE' in          !
! the root directory of the present distribution, or         !
! http://www.gnu.org/copyleft/gpl.txt .                      !
!                                                            !
!------------------------------------------------------------!
! Code to enable use of the POV-Ray ray-tracing software for !
! the rendering of Wannier function isosurfaces from .xsf    !
! files generated by Wannier90.                              !
!------------------------------------------------------------! 
module m_driver

  use general
  implicit none
  save
  private

  public driver

  ! Crystallographic stuff
  ! alatt = bravais lattice
  real(q) :: alatt(3,3)
  ! alatt = reciprocal lattice
  real(q) :: blatt(3,3)
  ! nspecies = number of atomtypes
  integer :: nspecies
  ! ntype = number of atoms of type i
  integer :: ntype(100)
  ! natoms = number of atoms
  integer :: natoms
  ! posion = atomic positions (real coordinates)
  real(q),allocatable :: posion(:,:)
  ! atomtype
  character, allocatable :: namion(:)*3
  ! Z-value
  integer, allocatable :: Z(:)
  ! Density stuff
  ! nx, ny, nz :: number of grid points
  integer :: nx, ny, nz
  ! denlat = density lattice vectors
  real(q) :: denlatt(3,3)
  ! denorg = density origin
  real(q) :: denorg(3)
  ! density = density
  real(q), allocatable :: density(:,:,:)

  ! bondcut = bond cutoff factor
  real(q) :: bondcut = 0.9_q;
  ! bondrad = bond radius factor
  real(q) :: bondrad = 0.2_q;
  ! atradfac = atomic radial prefactor
  real(q) :: atradfac = 0.5_q;

  ! numwan = number of wannier functions 
  integer :: numwan
  ! wanlist = list of wannier function
  integer,allocatable :: wanlist(:)
  ! wanlevel = list of values for isosurfaces
  real(q), allocatable :: wanlevel(:)
  ! wanpm = list of wannier function to render plus,minus, plus &minus
  integer, allocatable :: wanpm(:)
  ! wancol = list of colors for wannier functions
  real(q),allocatable :: wancol(:,:)
  ! wantrans = list of transparancies for wannier functions
  real(q),allocatable :: wantrans(:)
  ! seedname = name (root) of wannier90 file
  character(len=80) :: seedname
  ! campos = camera position
  integer :: campos
  ! zoom = zoom factor
  real(q) :: zoom
  ! interp = degree of interpolation in povray (default 2)
  integer :: interp
  ! cellim = list (real values) of bounding box for atoms
  real(q) :: cellim(6)
  ! llookat = user supplied own lookat position?
  logical :: llookat
  ! lookat  = lookat position - cartesian coordinates
  real(q) :: lookat(3)
  ! lcutsphere = logical, only include atoms 
  ! within a sphere centered at lookat
  logical :: lcutsphere
  ! cutsphererad = radius of that sphere
  real(q) :: cutsphere
  ! lcage = logical, render lattice vectors?
  logical :: lcage
  ! aspectratio = aspectratio
  real(q) :: aspectratio
contains

  subroutine driver
    implicit none
    integer i,j
    real(q) :: maxv, minv
    character(len=140) :: line

    
    print *
    print 1000
    print *,'reading indata'
    print 1000
    call read_infile
    print *
    print 1000
    print *,'Done reading indata'
    print 1000
    
    
    open(unit=82,file='densities.inc')
    do i=1,numwan

       call read_xsf(wanlist(i))
       call write_df3(nx,ny,nz,wanlist(i),density, maxv, minv)

       if(i.eq.1) then
          call write_unitcell      
       end if


       j=wanlist(i)
       write(82,*)
       write(line,'(a,i3.3,a,F14.7,a)') '#declare max_',j,'=',maxv,';'
       write(82,*) trim(line)
       write(line,'(a,i3.3,a,F14.7,a)') '#declare min_',j,'=',minv,';'
       write(82,*) trim(line)
       write(line,'(a,i3.3,a)') '#declare w',j,'p = function {'
       write(82,*) trim(line)
       write(line,'(a,i3.3,a)') '  pattern { density_file df3 "wan_',j,'p.df3" interpolate interp } }'
       write(82,*) trim(line)
       write(line,'(a,i3.3,a)') '#declare w',j,'m = function {'
       write(82,*) trim(line)
       write(line,'(a,i3.3,a)') '  pattern { density_file df3 "wan_',j,'m.df3" interpolate interp } }'
       write(82,*) trim(line)
       ! Write density lattice

       write(line,'(a,i3.3,3(a,F14.7),a)') '#declare c',j,'_d1 = <',denlatt(1,1),',',denlatt(1,2),',',denlatt(1,3),'>;'
       write(82,*) trim(line)
       write(line,'(a,i3.3,3(a,F14.7),a)') '#declare c',j,'_d2 = <',denlatt(2,1),',',denlatt(2,2),',',denlatt(2,3),'>;'
       write(82,*) trim(line)
       write(line,'(a,i3.3,3(a,F14.7),a)') '#declare c',j,'_d3 = <',denlatt(3,1),',',denlatt(3,2),',',denlatt(3,3),'>;'
       write(82,*) trim(line)
write(line,'(a,i3.3,3(a,F14.7),a)') '#declare co',j,' = <',denorg(1),',',denorg(2),',',denorg(3),'>;'
       write(82,*) trim(line)
       
       
       
       deallocate(posion, density, namion)
    end do
    close(82)
    
    ! write standard definitions
    call write_povscript

    open(unit=82,file='blobs.inc')
    do i=1,numwan
       if(wanpm(i).eq.0) then
          write(82,*)
          cycle
       end if
       write(82,'(a,i3.3,a,3(F4.2,a))') '#declare mine', wanlist(i), &
            ' = color rgbft <',wancol(1,i),',',wancol(2,i),',',wancol(3,i),'>;'

       if(wanpm(i).eq.2) then
          write(82,'(a,F7.4, 3(a,i3.3), 5(a,i3.3),a,i3.3,a,F4.2,a)') &
               'elblobpm(',wanlevel(i),  ',max_',wanlist(i),',min_',wanlist(i), &
               ',w',wanlist(i),'p,w',wanlist(i), &
               'm,c', wanlist(i),'_d1,c',wanlist(i),'_d2,c',wanlist(i), &
               '_d3,co',wanlist(i),',mine',wanlist(i),',',wantrans(i),')'
       else if(wanpm(i).eq.1) then
          write(82,'(a,F7.4,7(a,i3.3),a,F4.2,a)') &
               'elblob1(',wanlevel(i),',max_',wanlist(i), ',w',wanlist(i), &
               'p,c',wanlist(i),'_d1,c',wanlist(i),'_d2,c',wanlist(i),&
               '_d3,co', wanlist(i),',mine', wanlist(i),',',wantrans(i),')'

          ! elblob1(level, maxp, funp, c1, c2, c3, corg, col, trans)
       else if(wanpm(i).eq.-1) then
          write(82,'(a,F7.4,7(a,i3.3),a,F4.2,a)') &
               'elblob1(',wanlevel(i),',min_',wanlist(i), ',w',wanlist(i), &
               'm,c',wanlist(i),'_d1,c',wanlist(i),'_d2,c',wanlist(i),&
               '_d3,co', wanlist(i),',mine', wanlist(i),',',wantrans(i),')'
       end if
    end do
    close(82)


    write(line,'(a,a)') trim(seedname),'.pov'
    open(unit=82,file=trim(line))
    write(82,'(a)') '#version 3.7;'
    write(82,'(a)') 'global_settings { assumed_gamma 1.0 }'
    write(82,'(a)') '// std povray files'
    write(82,'(a)') '#include "colors.inc"'
    write(82,'(a)') '#include "math.inc"'
    write(82,'(a)') ''
    write(82,'(a)') '// wannier stuff'
    write(82,'(a)') '#include "mydefs.inc"'
    write(82,'(a)') '#include "unitcell.inc"'
    write(82,'(a)') '#include "densities.inc"'
    write(82,'(a)') '#include "blobs.inc"'
    close(82)
    
    print *
    print 1000
    print *,'Done. You can now run povray with e.g.'
    if(600*aspectratio .le. 999) then
       write(line,'(a,a,a,I3,a)') '> povray ',trim(seedname),'.pov +H600 +W',int(600*aspectratio),' +A0.14'
    else
       write(line,'(a,a,a,I4,a)') '> povray ',trim(seedname),'.pov +H600 +W',int(600*aspectratio),' +A0.14'
    end if
    print *,trim(line)
    !print *,'>povray <seedname>.pov +H600 +W600 +A0.14'
    print 1000
    print *

1000 format (66('='))

  end subroutine driver
  
  



  subroutine read_xsf(wanfun)
!    use m_readfile , only : split_string
    implicit none

    integer, intent(in) :: wanfun
    integer :: ios, iion, n, i, j, ix, iy, iz
    character(len=140) :: line, str(100)
    integer,parameter  :: iu=81

    write(line,'(a,a,i5.5,a)') trim(seedname),'_',wanfun,'.xsf'
    !---
    open(unit=iu,file=line,status='OLD',iostat=ios)
    if (ios.ne.0) then
       print *,'read_xsf : problems opening xsf file ',trim(line)
       stop
    end if
    !---

    do i=1,6
       read(iu,'(a140)',iostat=ios) line
    end do
    ! Primitive lattice
    n=split_string(line,str)
    if (trim(str(1)).ne.'PRIMVEC') then
       print *,'Error in xsf-file'
       stop
    end if
    do i=1,3
       read(iu,*) (alatt(i,j),j=1,3)
       !write(*,*) (alatt(i,j),j=1,3)
    end do
    ! Conventional lattice (skip)
    do i=1,5
       read(iu,'(a140)',iostat=ios) line
    end do
    ! Read number of atoms    
    read(iu,*) natoms
    ! read atomic labels and positions
    allocate(posion(3,natoms), namion(natoms))
    do i=1,natoms
       read(iu,'(a140)',iostat=ios) line
       n=split_string(line, str)
       do j=1,3
          read(str(1+j),*) posion(j,i)
       end do
       read(str(1),*) namion(i)
    end do
    ! skip a few lines
    do i=1,5
       read(iu,'(a140)',iostat=ios) line
    end do
    n=split_string(line,str)
    if (trim(str(1)).ne.'BEGIN_DATAGRID_3D_UNKNOWN') then
       print *,'Error in xsf-file'
       stop
    end if
    ! read nx, ny, nz
    read(iu,*) nx, ny, nz
    ! print *, 'Gridpoints: ', nx, ny, nz
    ! read density lattice vectors and origin
    read(iu,*) (denorg(i),i=1,3)
    do i=1,3
       read(iu,*) (denlatt(i,j),j=1,3)
    end do
    denlatt(1,:)=denlatt(1,:)*(nx+1)/nx
    denlatt(2,:)=denlatt(2,:)*(ny+1)/ny
    denlatt(3,:)=denlatt(3,:)*(nz+1)/nz
    ! read density
    allocate(density(nx,ny,nz))
    read(iu,*) (((density(ix,iy,iz),ix=1,nx), iy=1,ny), iz=1,nz)

    close(iu)
  end subroutine read_xsf


  
  subroutine write_unitcell
    implicit none

    character(len=300) :: line
    integer :: iion, jion, i, j, ix, iy, iz, natomstmp
    character :: name(150)*3
    integer :: radius(150), fact
    real(q) :: color(3,150), dist, mid(3), rad, rdir(3)
    real(q),allocatable :: tmppos(:,:)
    character, allocatable :: tmpnam(:)*3
    real(q) :: vec1(3), vec2(3), vec3(3)


    name(1:56)=[ character(len=3) :: &
         'H ',                                                                                'He', &
         'Li','Be',                                                  'B ','C ','N ','O ','F ','Ne', &
         'Na','Mg',                                                  'Al','Si','P ','S ','Cl','Ar', &
         'K ','Ca','Sc','Ti','V ','Cr','Mn','Fe','Co','Ni','Cu','Zn','Ga','Ge','As','Se','Br','Kr', &
         'Rb','Sr','Y ','Zr','Nb','Mo','Tc','Ru','Rh','Pd','Ag','Cd','In','Sn','Sb','Te','I ','Xe', &
         'Cs','Ba']
    name(57:71)=[ character(len=3) :: &
         'La','Ce','Pr','Nd','Pm','Sm','Eu','Gd','Tb','Dy','Ho','Er','Tm','Yb','Lu']
    name(89:103)=[ character(len=3) :: &
         'Ac','Th','Pa','U ','Np','Pu','Am','Cm','Bk','Cf','Es','Fm','Md','No','Lr']
    name(72:88)=[ character(len=3) :: &
         'Hf','Ta','W ','Re','Os','Ir','Pt','Au','Hg','Tl','Pb','Bi','Po','At','Rn', &
         'Fr','Ra']
    name(104:115)=[ character(len=3) :: &
         'Rf','Db','Sg','Bh','Hs','Mt','Ds','Rg','Uub','Uut','UUq','UUp']
    ! Covalent radii from www.ccdc.cam.ac.uk/products/csd/radii/table.php4#group
    radius(1:10) =  [1.09,1.40,1.82,2.00,2.00,1.70,1.55,1.52,1.47,1.54]
    radius(11:20)=  [2.27,1.73,2.00,2.10,1.80,1.80,1.75,1.88,2.75,2.00]
    radius(21:30)=  [2.00,2.00,2.00,2.00,2.00,2.00,2.00,1.63,1.40,1.39]
    radius(31:40)=  [1.87,2.00,1.85,1.90,1.85,2.02,2.00,2.00,2.00,2.00]
    radius(41:50)=  [2.00,2.00,2.00,2.00,2.00,1.63,1.72,1.58,1.93,2.17]
    radius(51:60)=  [2.00,2.06,1.98,2.16,2.00,2.00,2.00,2.00,2.00,2.00]
    radius(61:70)=  [2.00,2.00,2.00,2.00,2.00,2.00,2.00,2.00,2.00,2.00]
    radius(71:80)=  [2.00,2.00,2.00,2.00,2.00,2.00,2.00,1.72,1.66,1.55]
    radius(81:90)=  [1.96,2.02,2.00,2.00,2.00,2.00,2.00,2.00,2.00,2.00]
    radius(91:100)= [2.00,1.86,2.00,2.00,2.00,2.00,2.00,2.00,2.00,2.00]
    radius(101:110)=[2.00,2.00,2.00,2.00,2.00,2.00,2.00,2.00,2.00,2.00]
    ! Atomic colors from jmol.sourceforge.net/jscolors
    color(:,1)=[255,255,255];   color(:,2)=[217,255,255];   color(:,3)=[204,128,255]
    color(:,4)=[194,255,0];     color(:,5)=[255,181,181];   color(:,6)=[144,144,144]
    color(:,7)=[48,80,248];     color(:,8)=[255,13,13];     color(:,9)=[144,224,80]
    color(:,10)=[179,227,245];  color(:,11)=[171,92,242];   color(:,12)=[138,255,0]
    color(:,13)=[191,166,166];  color(:,14)=[240,200,160];  color(:,15)=[255,128,0];
    color(:,16)=[255,255,48];   color(:,17)=[31,240,31];    color(:,18)=[128,209,227];
    color(:,19)=[143,64,212];   color(:,20)=[61,255,0];     color(:,21)=[230,230,230];
    color(:,22)=[191,194,199];  color(:,23)=[166,166,171];  color(:,24)=[138,153,199];
    color(:,25)=[156,122,199];  color(:,26)=[224,102,51];   color(:,27)=[240,144,160];
    color(:,28)=[80,208,80];    color(:,29)=[200,128,51];   color(:,30)=[125,128,176];
    color(:,31)=[194,143,143];  color(:,32)=[102,143,143];  color(:,33)=[189,128,227];
    color(:,34)=[255,161,0];    color(:,35)=[166,41,41];    color(:,36)=[92,184,209];
    color(:,37)=[112,46,176];   color(:,38)=[0,255,0];      color(:,39)=[148,255,255];
    color(:,40)=[148,224,224];  color(:,41)=[115,194,201];  color(:,42)=[84,181,181];
    color(:,43)=[59,158,158];   color(:,44)=[36,143,143];   color(:,45)=[10,125,140];
    color(:,46)=[0,105,133];    color(:,47)=[192,192,192];  color(:,48)=[255,217,143];
    color(:,49)=[166,117,115];  color(:,50)=[102,128,128];  color(:,51)=[158,99,181];
    color(:,52)=[212,122,0];    color(:,53)=[148,0,148];    color(:,54)=[66,158,176];
    color(:,55)=[87,23,143];    color(:,56)=[0,201,0];      color(:,57)=[112,212,255];
    color(:,58)=[255,255,199];  color(:,59)=[217,255,199];  color(:,60)=[199,255,199];
    color(:,61)=[163,255,199];  color(:,62)=[143,255,199];  color(:,63)=[97,255,199];
    color(:,64)=[69,255,199];   color(:,65)=[48,255,199];   color(:,66)=[31,255,199];
    color(:,67)=[0,255,156];    color(:,68)=[0,230,117];    color(:,69)=[0,212,82];
    color(:,70)=[0,191,56];     color(:,71)=[0,171,36];     color(:,72)=[77,194,255];
    color(:,73)=[77,166,255];   color(:,74)=[33,148,214];   color(:,75)=[38,125,171];
    color(:,76)=[38,102,150];   color(:,77)=[23,84,135];    color(:,78)=[208,208,224];
    color(:,79)=[255,209,35];   color(:,80)=[184,184,208];  color(:,81)=[166,84,77];
    color(:,82)=[87,89,97];     color(:,83)=[158,79,181];   color(:,84)=[171,92,0];
    color(:,85)=[117,79,69];    color(:,86)=[66,130,150];   color(:,87)=[66,0,102];
    color(:,88)=[0,125,0];      color(:,89)=[112,171,250];  color(:,90)=[0,186,255];
    color(:,91)=[0,161,255];    color(:,92)=[0,143,255];    color(:,93)=[0,128,255];
    color(:,94)=[0,107,255];    color(:,95)=[84,92,242];    color(:,96)=[120,92,227];
    color(:,97)=[138,79,227];   color(:,98)=[161,54,212];   color(:,99)=[179,31,212];
    color(:,100)=[179,31,186];  color(:,101)=[179,13,166];  color(:,102)=[189,13,135];
    color(:,103)=[199,0,102];   color(:,104)=[204,0,89];    color(:,105)=[209,0,79];
    color(:,106)=[217,0,69];    color(:,107)=[224,0,56];    color(:,108)=[230,0,46];
    color(:,109)=[235,0,38];


    fact= &
         (ceiling(cellim(2))-floor(cellim(1))+1) * &
         (ceiling(cellim(4))-floor(cellim(3))+1) * &
         (ceiling(cellim(6))-floor(cellim(5))+1)

    allocate(tmppos(3,natoms*fact), tmpnam(natoms*fact))
    ! calc reciprocal lattice vectors
    call calcinv(blatt, alatt)
    natomstmp=0
    !--
    do iion=1,natoms

       vec1=matmul(posion(:,iion),blatt)

       ! first make sure this atom is inside the box
       do i=1,3 ! in case it's REALLY outside the box
          do ix=1,3
             if(vec1(ix).lt.0.0_q) then
                vec1(ix)=vec1(ix)+1.0_q
             else if (vec1(ix).ge.1.0_q) then
                vec1(ix)=vec1(ix)-1.0_q
             end if
          end do
       end do


       do ix=floor(cellim(1)),ceiling(cellim(2))
          do iy=floor(cellim(3)),ceiling(cellim(4))
             do iz=floor(cellim(5)),ceiling(cellim(6))

                vec2(1)=vec1(1)+real(ix,kind=q)
                vec2(2)=vec1(2)+real(iy,kind=q)
                vec2(3)=vec1(3)+real(iz,kind=q)                
                
                if( &
                     vec2(1) .ge. cellim(1) .and. &
                     vec2(1) .le. cellim(2) .and. &
                     vec2(2) .ge. cellim(3) .and. &
                     vec2(2) .le. cellim(4) .and. &
                     vec2(3) .ge. cellim(5) .and. &
                     vec2(3) .le. cellim(6) ) then
                   
                   natomstmp=natomstmp+1
                   tmppos(:,natomstmp)=matmul(vec2,alatt)
                   write(tmpnam(natomstmp),'(a)') namion(iion)
                   if(lcutsphere) then
                      if(llookat) then
                         vec2=tmppos(:,natomstmp)-lookat
                      else
                         vec2=tmppos(:,natomstmp)- &
                              (alatt(:,1)+alatt(:,2)+alatt(:,3))*0.5_q
                      end if
                      if(sum(vec2**2) .gt. cutsphere**2) then
                         natomstmp=natomstmp-1
                      end if
                   end if
                end if
             end do
          end do
       end do
    end do
    !print *,natoms, natomstmp
    !stop
    deallocate(posion, namion)
    natoms=natomstmp
    allocate(posion(3,natoms), namion(natoms))
    namion(1:natoms)=tmpnam(1:natoms) !(1:natoms)
    posion(1:3,1:natoms)=tmppos(1:3,1:natoms) !(1:3,1:natoms)
 
    print *,'Number of atoms',natoms


    !--
    ! match atoms
    allocate(Z(natoms))
    do iion=1,natoms
       Z(iion)=0
       do i=1,110
          if(trim(namion(iion)).eq.trim(name(i))) then
             Z(iion)=i
             exit
          end if
       end do
       if(Z(iion).eq.0) then 
          print *,'Could not match ion'
          exit
       end if
    end do


    ! calc reciprocal lattice vectors
    call calcinv(blatt, alatt)
   

    open(unit=83,file='unitcell.inc')    
    ! print atoms
    do iion=1,natoms
       i=Z(iion)
       write(line,'(a,7(F9.4,a))') 'atom(',posion(1,iion),',',&
            posion(2,iion),',',posion(3,iion),&
            ',',radius(i)*atradfac,',',color(1,i)/255.0_q,',',&
            color(2,i)/255.0_q,',',color(3,i)/255.0_q,')'
       write(83,*) trim(line)
       
       ! write cartesian coordinate
       write(line,'(a,i5.5,3(a,F14.7),a)') '#declare T',iion,'= <',&
            posion(1,iion),',',posion(2,iion),',',posion(3,iion),'>;'
       write(83,*) trim(line)
       ! write color
       write(line,'(a,i5.5,3(a,F14.7),a)') '#declare atcol',iion,'= <', &
            color(1,i)/255.0_q,',', color(2,i)/255.0_q,','&
            ,color(3,i)/255.0_q,'>;'
       write(83,*) trim(line)
       
       ! write direct coordinates 
       rdir=matmul(posion(:,iion),blatt)
       write(line,'(a,i5.5,3(a,F14.7),a)') '#declare P',iion,'= <',&
            rdir(1),',',rdir(2),',',rdir(3),'>;'
       write(83,*) trim(line)
    end do
    
    ! print bonds 
    do iion=1,natoms
       do jion=1,natoms
          if(iion .eq. jion) cycle
          j=Z(jion)
          dist=sqrt(sum((posion(:,iion)-posion(:,jion))**2))
          if( (bondcut .gt. 0.0_q .and. & 
               dist*bondcut .le. radius(i)+radius(j))&
             .or. (bondcut .lt. 0.0_q .and. dist .le. -bondcut)) then
             
             rad=min(radius(Z(iion)), radius(Z(iion)))*bondrad
             mid=(posion(:,iion)+posion(:,jion))/2.0_q
             write(line,'(a,2(i5.5,a),F9.5,a,2(i5.5,a))') &
                  'bond2p( T',iion,', T',jion, &
                  ',',rad,', atcol',iion,', atcol', jion,')'
             write(83,*) trim(line)
                  
             
          end if
       end do

    end do


    close(83)

  end subroutine write_unitcell

  subroutine write_povscript
    implicit none
    character(len=140) :: line
    integer :: iu=83

    open(unit=iu,file='mydefs.inc')

    write(iu,'(a)') '// degree of interpolation'
    write(iu,'(a,i2,a)') '#declare interp=',interp,';'
    write(iu,'(a)') ''

    ! Write Bravais lattice
    write(iu,*) '// Bravais lattice'
    write(iu,'(3(a,F14.7),a)') '#declare a1 = <',alatt(1,1),',',alatt(1,2),',',alatt(1,3),'>;'
    write(line,'(3(a,F14.7),a)') '#declare a2 = <',alatt(2,1),',',alatt(2,2),',',alatt(2,3),'>;'
    write(iu,*) trim(line)
    write(line,'(3(a,F14.7),a)') '#declare a3 = <',alatt(3,1),',',alatt(3,2),',',alatt(3,3),'>;'
    write(iu,*) trim(line)

    ! write camera and light position
    if(llookat) then
       write(iu,'(3(a,F14.7),a)') '#declare lookpos = <',lookat(1),',',lookat(2),',',lookat(3),'>;'
    else
       write(iu,'(a)') '#declare lookpos=(a1+a2+a3)/2.0;'
    end if
    !-
    write(iu,'(a)') '#declare Width = 600;'
    write(iu,'(a,F14.7,a)') '#declare Height = Width/',aspectratio,';'
    write(iu,'(a)') '#declare minScreenDimension = 600;'
    write(iu,'(a,F14.7,a)') '#declare Scale =',zoom,';'
    write(iu,'(a)') '#declare Ratio = Scale * Width / Height;'
    if(campos .eq. 1) then
       ! camera along x-axis
       write(iu,'(a)') '#declare campos=<Scale,0,0>;'
       write(iu,'(a)') '#declare RIGHT=<0,Ratio,0>;'
       write(iu,'(a)') '#declare UP=<0,0,Scale>;'
    else if (campos .eq. 2) then
       ! camera along y-axis
       write(iu,'(a)') '#declare campos=<0,Scale,0>;'
       write(iu,'(a)') '#declare RIGHT=<0,0,Ratio>;'
       write(iu,'(a)') '#declare UP=<Scale,0,0>;'
    else if (campos .eq. 3) then
       ! camera along y-axis
       write(iu,'(a)') '#declare campos=<0,0,Scale>;'
       write(iu,'(a)') '#declare RIGHT=<Ratio,0,0>;'
       write(iu,'(a)') '#declare UP=<0,Scale,0>;'
    else if (campos .eq. 4) then
       ! camera along a1-axis
       write(iu,'(a)') '#declare campos=vnormalize(a1)*Scale;'
       write(iu,'(a)') '#declare cp=vnormalize(campos);'
       write(iu,'(a)') '#declare RIGHT=vnormalize(a2-vdot(a2,cp)*cp)*Ratio;'
       write(iu,'(a)') '#declare UP=vnormalize(a3-vdot(a3,cp)*cp)*Scale;'
    else if (campos .eq. 5) then
       ! camera along a2-axis
       write(iu,'(a)') '#declare campos=vnormalize(a2)*Scale;'
       write(iu,'(a)') '#declare cp=vnormalize(campos);'
       write(iu,'(a)') '#declare RIGHT=vnormalize(a3-vdot(a3,cp)*cp)*Ratio;'
       write(iu,'(a)') '#declare UP=vnormalize(a1-vdot(a1,cp)*cp)*Scale;'     
    else if (campos .eq. 6) then
       ! camera along a3-axis
       write(iu,'(a)') '#declare campos=vnormalize(a3)*Scale;'
       write(iu,'(a)') '#declare cp=vnormalize(campos);'
       write(iu,'(a)') '#declare RIGHT=vnormalize(a1-vdot(a1,cp)*cp)*Ratio;'
       write(iu,'(a)') '#declare UP=vnormalize(a2-vdot(a2,cp)*cp)*Scale;'      
    end if
    
    

    write(iu,'(a)') 'camera{'
    write(iu,'(a)') ' orthographic' 
    write(iu,'(a)') ' location campos+lookpos'
    write(iu,'(a)') ' right RIGHT'
    write(iu,'(a)') ' up UP'
    write(iu,'(a)') ' sky   UP'
    write(iu,'(a)') ' angle 30'
    write(iu,'(a)') ' look_at lookpos'
    write(iu,'(a)') ' }'
    write(iu,'(a)') ' background { color rgb<1.0,1.0,1.0>}'
    write(iu,'(a)') ' light_source {  campos+(a1+a2+a3)/2.0 rgb <1.0,1.0,1.0> }'

    write(iu,'(a)') ''
    write(iu,'(a)') ''




 
    write(iu,'(a)') '//***********************************************'
    write(iu,'(a)') '// macros for common shapes'
    write(iu,'(a)') '//***********************************************'
    write(iu,'(a)') ''
    write(iu,'(a)') '#macro CW_angle (COLOR,A)'
    write(iu,'(a)') '   #local RGBFT = color COLOR;'
    write(iu,'(a)') '   #local R = (RGBFT.red);'
    write(iu,'(a)') '   #local G = (RGBFT.green);'
    write(iu,'(a)') '   #local B = (RGBFT.blue);'
    write(iu,'(a)') '   #local Min = min(R,min(G,B));'
    write(iu,'(a)') '   #local Max = max(R,max(G,B));'
    write(iu,'(a)') '   #local Span = Max-Min;'
    write(iu,'(a)') '   #local H = CRGB2H (<R,G,B>, Max, Span);'
    write(iu,'(a)') '   #local S = 0; #if (Max!=0) #local S = Span/Max; #end'
    write(iu,'(a)') ''
    write(iu,'(a)') '   #local P = <H+A,S,Max,(RGBFT.filter),(RGBFT.transmit)> ;'
    write(iu,'(a)') ''
    write(iu,'(a)') '   #local HSVFT = color P ;'
    write(iu,'(a)') '#local H = (HSVFT.red);'
    write(iu,'(a)') '   #local S = (HSVFT.green);'
    write(iu,'(a)') '   #local V = (HSVFT.blue);'
    write(iu,'(a)') '   #local SatRGB = CH2RGB(H);'
    write(iu,'(a)') '   #local RGB = ( ((1-S)*<1,1,1> + S*SatRGB) * V );'
    write(iu,'(a)') '   rgb <RGB.red,RGB.green,RGB.blue,(HSVFT.filter),'
    write(iu,'(a)') '       (HSVFT.transmit)>'
    write(iu,'(a)') '#end'
    write(iu,'(a)') ''    
    write(iu,'(a)') '#default { finish {'
    write(iu,'(a)') ' ambient .2 diffuse .6 specular 1 roughness .001 metallic}}'
    write(iu,'(a)') ''
    write(iu,'(a)') '#macro atom(X,Y,Z,RADIUS,R,G,B)'
    write(iu,'(a)') ' sphere{<X,Y,Z>,RADIUS'
    write(iu,'(a)') '  pigment{rgb<R,G,B> } finish { phong 0.7 phong_size 90 }}'
    write(iu,'(a)') '#end'
    write(iu,'(a)') ''


    write(iu,'(a)') '#macro bond1(X1,Y1,Z1,X2,Y2,Z2,RADIUS,R,G,B)'
    write(iu,'(a)') ' cylinder{<X1,Y1,Z1>,<X2,Y2,Z2>,RADIUS'
    write(iu,'(a)') '  pigment{rgb<R,G,B>}}'
    write(iu,'(a)') '  sphere{<X1,Y1,Z1>,RADIUS'
    write(iu,'(a)') '   pigment{rgb<R,G,B>}}'
    write(iu,'(a)') '  sphere{<X2,Y2,Z2>,RADIUS'
    write(iu,'(a)') '   pigment{rgb<R,G,B>}}'
    write(iu,'(a)') '#end'

    write(iu,'(a)') '#macro bond2p(p1,p2,RADIUS,col1,col2)'
    write(iu,'(a)') ' #declare rc=(p1+p2)/2.0;'
    write(iu,'(a)') ' cylinder{p1, rc, RADIUS'
    write(iu,'(a)') '  pigment{rgb col1} finish { phong 0.7 phong_size 90 } }'
    write(iu,'(a)') ' cylinder{rc, p2, RADIUS'
    write(iu,'(a)') '  pigment{rgb col2}finish { phong 0.7 phong_size 90 }}'
    write(iu,'(a)') '  sphere{p1,RADIUS'
    write(iu,'(a)') '   pigment{rgb col1}finish { phong 0.7 phong_size 90 }}'
    write(iu,'(a)') '  sphere{p2,RADIUS'
    write(iu,'(a)') '   pigment{rgb col2}finish { phong 0.7 phong_size 90 }}'
    write(iu,'(a)') '#end'
    write(iu,'(a)') ''
    write(iu,'(a)') ''
    write(iu,'(a)') ''
    if(lcage) then
       write(iu,'(a)') '// make cage'
       write(iu,'(a)') '#declare P = 2.4116;'
       write(iu,'(a)') '#declare thick = 0.05;'
       write(iu,'(a)') '#declare R = 0.5;'
       write(iu,'(a)') '#declare G = 0.5;'
       write(iu,'(a)') '#declare B = 0.5;'
       write(iu,'(a)') ' bond1(0,0,0,a1.x,a1.y,a1.z,thick,R,G,B)'
       write(iu,'(a)') ' bond1(a1.x,a1.y,a1.z, a1.x+a2.x,a1.y+a2.y,a1.z+a2.z,thick,R,G,B)'
       write(iu,'(a)') ' bond1(a1.x+a2.x,a1.y+a2.y,a1.z+a2.z, a2.x,a2.y,a2.z,thick,R,G,B)'
       write(iu,'(a)') ' bond1(0,0,0,a2.x,a2.y,a2.z,thick,R,G,B)'
       write(iu,'(a)') ''
       write(iu,'(a)') ' bond1(a3.x,a3.y,a3.z, a3.x+a1.x, a3.y+a1.y,a3.z+a1.z,thick,R,G,B)'
       write(iu,'(a)') ' bond1(a3.x+a1.x, a3.y+a1.y,a3.z+a1.z, a3.x+a1.x+a2.x, a3.y+a1.y+a2.y,a3.z+a1.z+a2.z ,thick,R,G,B)'
       write(iu,'(a)') ' bond1(a3.x+a1.x+a2.x, a3.y+a1.y+a2.y,a3.z+a1.z+a2.z, a3.x+a2.x, a3.y+a2.y,a3.z+a2.z,thick,R,G,B)'
       write(iu,'(a)') ' bond1(a3.x+a2.x, a3.y+a2.y,a3.z+a2.z,a3.x,a3.y,a3.z,thick,R,G,B)'
       write(iu,'(a)') ''
       write(iu,'(a)') ' bond1(0,0,0,a3.x,a3.y,a3.z,thick,R,G,B)'
       write(iu,'(a)') ' bond1(a1.x,a1.y,a1.z, a1.x+a3.x, a1.y+a3.y,a1.z+a3.z,thick,R,G,B)'
       write(iu,'(a)') ' bond1(a2.x,a2.y,a2.z, a2.x+a3.x, a2.y+a3.y,a2.z+a3.z,thick,R,G,B)'
       write(iu,'(a)') ' bond1(a1.x+a2.x,a1.y+a2.y,a1.z+a2.z,a1.x+a2.x+a3.x,a1.y+a2.y+a3.y,a1.z+a2.z+a3.z,thick,R,G,B)'
       write(iu,'(a)') ''
    end if
    write(iu,'(a)') ''
    write(iu,'(a)') '// My blob'
    write(iu,'(a)') '    #macro elblob1(level, thenorm, fun, c1, c2, c3, corg, col, trans)'
    write(iu,'(a)') 'object{'
    write(iu,'(a)') ''
    write(iu,'(a)') ' isosurface { '
    write(iu,'(a)') '    function { level/abs(thenorm) - fun( x, y, z)  }'
    write(iu,'(a)') '    accuracy 0.00001'
    write(iu,'(a)') '    contained_by { box { <0,0,0>,<1.0,1.0,1.0> } }'
    write(iu,'(a)') '    max_gradient 150.000'
    write(iu,'(a)') '    pigment { rgbt <col.red,col.green,col.blue,trans>}'
    write(iu,'(a)') '    finish { phong 0.7 phong_size 90 }'
    write(iu,'(a)') '    }'
    write(iu,'(a)') '    matrix <      '
    write(iu,'(a)') '     c1.x,c1.y,c1.z,'
    write(iu,'(a)') '     c2.x,c2.y,c2.z,'
    write(iu,'(a)') '     c3.x,c3.y,c3.z,'
    write(iu,'(a)') '     0,0,0>'
    write(iu,'(a)') '     #translate corg'
    write(iu,'(a)') '}'
    write(iu,'(a)') '#end'
    write(iu,'(a)') ''
    write(iu,'(a)') '// A pm blob'
    write(iu,'(a)') '#macro elblobpm(level, maxp, minp, funp, funm, c1, c2, c3, corg, col, trans)'
    write(iu,'(a)') ' elblob1(level, maxp, funp, c1, c2, c3, corg, col, trans)'
    write(iu,'(a)') ' elblob1(level, minp, funm, c1, c2, c3, corg, CW_angle (col,60), trans)'
    write(iu,'(a)') '#end'


    


    close(iu)

  end subroutine write_povscript

! Inverts a 3x3 matrix 
! A is the inverse of B
!

  subroutine calcinv(a,b)
    implicit none

    real(q),intent(out)  :: A(9)
    real(q),intent(in) :: B(9)
    real(q) :: C1
    
    C1=(B(5)*B(9)-B(6)*B(8))*B(1)+(B(6)*B(7)-B(4)*B(9))*B(2) &
         +(B(4)*B(8)-B(5)*B(7))*B(3)
    A(1)=(B(5)*B(9)-B(6)*B(8))/C1
    A(4)=(B(6)*B(7)-B(4)*B(9))/C1
    A(7)=(B(4)*B(8)-B(5)*B(7))/C1
    A(2)=(B(8)*B(3)-B(9)*B(2))/C1
    A(5)=(B(9)*B(1)-B(7)*B(3))/C1
    A(8)=(B(7)*B(2)-B(8)*B(1))/C1
    A(3)=(B(2)*B(6)-B(3)*B(5))/C1
    A(6)=(B(3)*B(4)-B(1)*B(6))/C1
    A(9)=(B(1)*B(5)-B(2)*B(4))/C1
    
  end subroutine calcinv

  subroutine read_infile
    use m_io
    implicit none
    character(len=80),parameter :: infile='w90pov.inp'
    character(len=20) :: str
    integer :: i,j
    logical :: found

    real(q),allocatable ::  tmpcol(:)
    !---
    call param_in_file
    call param_get_keyword('numwan',found,i_value=numwan)
    if(.not. found) then
       print *,'Please specify numwan'
       stop
    end if
     write(*,'(a,i4)') 'Number of wannier functions ',numwan
    !--
    allocate(wanlist(numwan))
    call param_get_keyword_vector('wanlist',found,numwan,i_value=wanlist)
    if(.not. found) then
       print *,'Please specify wanlist'
       stop
    end if
     write(*,'(a,20(1x,I3))') 'wanlist=', wanlist
    !--
    allocate(wanlevel(numwan), wanpm(numwan))
    call param_get_keyword_vector('isolevel',found,numwan,r_value=wanlevel)
    if(.not. found) then
       print *,'Please specify isolevel'
       stop
    end if
    write(*,'(a,20(1x,F7.3))') 'isolevels= ',wanlevel
    !--
    call param_get_keyword_vector('isopm',found,numwan,i_value=wanpm)
    if(.not. found) then
       print *,'Please specify isopm'
       stop
    end if
    write(*,'(a,20(1x,I1))') 'isopm= ',wanpm
    !--
    allocate(wancol(3,numwan),tmpcol(3*numwan))
    call param_get_keyword_vector('wancol',found,numwan*3,r_value=tmpcol)
    if(.not. found) then
       print *,'Please specify wancol'
       stop
    end if
    do i=1,numwan
       wancol(1:3,i)=tmpcol((i-1)*3+1:(i-1)*3+3)
       write(*,'(a,i3,3(1x,F7.3))') 'color ',i,wancol(:,i)
    end do
    !--
    allocate(wantrans(numwan))
    call param_get_keyword_vector('trans',found,numwan,r_value=wantrans)
        if(.not. found) then
       print *,'Please specify trans'
       stop
    end if
    write(*,'(a,20(1x,F7.3))') 'trans= ',wantrans
    !--
    call param_get_keyword('seedname',found,c_value=seedname)
    if(.not. found) then
       print *,'Please specify seedname'
       stop
    end if
    write(*,'(a,a)') 'seedname= ',trim(seedname)
    !--
    call param_get_keyword('camera',found,c_value=str)
    if(.not. found) then
       print *,'Please specify camera'
       stop
    end if
    write(*,'(a,a)') 'camera= ',trim(str)
    !--
    select case (upcase(str(1:1)))
       case('X') 
          campos=1
       case('Y')
          campos=2
       case('Z')
          campos=3
       case('A')
          select case (str(2:2))
          case('1')
             campos=4
          case('2')
             campos=5
          case('3')
             campos=6
          case default
             print *,'str=',trim(str)
             print *,'unknown camera position'
             stop 
          end select
          
       case default
          print *,'str=',trim(str)
          print *,'unknown camera position'
          stop 
     end select
     !--
     bondcut=0.9_q
     call param_get_keyword('bondcut',found,r_value=bondcut)
     if(found) then
        write(*,'(a,1x,F7.3)') 'bondcut= ',bondcut
     end if
     !--
     bondrad=0.2_q
     call param_get_keyword('bondrad',found,r_value=bondrad)
     if(found) then
        write(*,'(a,1x,F7.3)') 'bondrad= ',bondrad
     end if  
     !--
     atradfac=0.5_q
     call param_get_keyword('radialfactor',found,r_value=atradfac)
     if(found) then
        write(*,'(a,1x,F7.3)') 'radialfactor= ',atradfac
     end if  
     !--
     interp=2
     call param_get_keyword('interpolation',found,i_value=interp)
     if(found) then
        write(*,'(a,1x,I2)') 'interpolation= ',interp
        if(interp .lt. 0 .and. interp .gt. 2) then
           print *,'Error, 0<=interp<=2'
           stop
        end if
     end if
     !--
     call param_get_keyword('zoom',found,r_value=zoom)
     if(.not. found) then
        print *,'Please specify zoom'
        stop
     end if
     write(*,'(a,1x,F7.3)') 'zoom= ',zoom
     !-
     cellim=[0.0, 1.0, 0.0, 1.0, 0.0, 1.0]
     call param_get_keyword_vector('cellim',found,6,r_value=cellim)
     if(found) then
        write(*,'(a,6(1x,F7.3))') 'cellim= ',cellim
     end if
     !--
     call param_get_keyword_vector('lookat',found,3,r_value=lookat)
     if(found) then
        llookat=.true.
         write(*,'(a,3(1x,F7.3))') 'lookat= ',lookat
     end if
     !--
     call param_get_keyword('cutsphere',found,r_value=cutsphere)
     if(found) then
        lcutsphere=.true.
        write(*,'(a,3(1x,F7.3))') 'cutsphere= ',cutsphere
     end if
     !--
     lcage=.true.
     call param_get_keyword('lcage',found,l_value=lcage)
     if(found) then
        write(*,'(a,L1)') 'lcage= ',lcage
     end if
     !--
     aspectratio=1.0_q
     call param_get_keyword('aspectratio',found,r_value=aspectratio)
     if(found) then
        write(*,'(a,3(1x,F7.3))') 'aspectratio= ',aspectratio
     end if
  end subroutine read_infile


  integer function split_string(strin, out) result (N)
    implicit none
    character(*),intent(in)  :: strin
    character(*),intent(out) :: out(:)
    integer :: i, i0
    N=0
    i0=0
    do i=1,len(strin)
       if (strin(i:i).eq.' ') then
          if (i-i0.gt.1) then
             N=N+1
             if (N.gt.size(out)) &
                  stop 'split_string2str : strout array too small'
             out(N)=trim(strin(i0+1:i-1))
          end if
          i0=i
       end if
    end do
  end function split_string

end module m_driver