c
c     Copyright (c) 1999,2000, Compaq Computer Corporation
c
c     See the file "license.terms" for information on usage and redistribution
c     of this file, and for a DISCLAIMER OF ALL WARRANTIES.
c
      subroutine read_vlsicap(batchmode, read_error)
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'mesh.cmn'
      include 'data.cmn'
      include 'io.cmn'
      include 'plot.cmn'
c
c     Read VLSICAP L3D file. From code by Marden Seavey.
c
      logical batchmode, read_error
c
c     locals
c
      integer i
      real real_vec(2)
      character*10 format_array(2)
c
      if( .NOT. batchmode ) then
         real_vec(1) = 0.0
         format_array(1) = 'f9.3'
         call get_reals_with_default(real_vec, 1,
     1     'Enter horizontal coord at edge of gate in cm: ',
     2     format_array, 0)
         vlsi_edge = real_vec(1)
c
         real_vec(1) = 0.0
         format_array(1) = 'f9.3'
         call get_reals_with_default(real_vec, 1,
     1     'Enter vertical coord at Si-SiO2 interface in cm: ',
     2     format_array, 0)
         vlsi_yint = real_vec(1)
      endif
c
c     Read data file
      call read_vlsi_l3d(read_error)
c
c     Read input file to get boundary information
      if( .NOT. read_error ) call read_vlsi_inp(read_error)
      if( read_error ) then
         read_vlsi_inp_file = .FALSE.
      else
         read_vlsi_inp_file = .TRUE.
      endif
c
c     compute some stuff related to mesh...
c
c     set up boundary limits information
      call coord_limits
c
      do i=1,nx
         xyz(i,1) = xyz(i,1) - vlsi_edge
      end do
c
      do i=1,ny
         xyz(i,2) = (vlsi_yint - xyz(i,2))
      end do
c
      if( read_vlsi_inp_file ) then
         do i=1,nvertex
            vertex_coords(i,1) = vertex_coords(i,1) - vlsi_edge
            vertex_coords(i,2) = (vlsi_yint - vertex_coords(i,2))
         end do
      endif
c
      nxm = nx - 1
      nym = ny - 1
      nytotm = nytot - 1
c
c     inverse mesh spacing...
c
      do 210 i=1,nxm
210      edxyz(i,1) = 1.0/(xyz(i+1,1) - xyz(i,1))
      do 211 i=1,nytotm
211      edxyz(i,2) = 1.0/(xyz(i+1,2) - xyz(i,2))
      do 212 i=1,nz-1
212      edxyz(i,3) = 1.0/(xyz(i+1,3) - xyz(i,3))
c
c     average mesh spacing...
c
      dxyzm(1,1)  = (xyz(2,1)  - xyz(1,1))/2.0
      dxyzm(nx,1) = (xyz(nx,1) - xyz(nx-1,1))/2.0
      do 220 i=2,nxm
220      dxyzm(i,1) = (xyz(i+1,1) - xyz(i-1,1))/2.0
c
      dxyzm(1,2)     = (xyz(2,2)  - xyz(1,2))/2.0
      dxyzm(nytot,2) = (xyz(nytot,2) - xyz(nytot-1,2))/2.0
      do 221 i=2,nytotm
221      dxyzm(i,2) = (xyz(i+1,2) - xyz(i-1,2))/2.0
c
      dxyzm(1,3)     = (xyz(2,3)  - xyz(1,3))/2.0
      dxyzm(nz,3) = (xyz(nz,3) - xyz(nz-1,3))/2.0
      do 222 i=2,nz-1
222      dxyzm(i,3) = (xyz(i+1,3) - xyz(i-1,3))/2.0
c
      call load_vlsi_specific
c
      if( lfirst_read .eq. .TRUE. ) then
         lfirst_read = .FALSE.
         prev_plane_type = plane_type
         prev_binfilename = binfilename
         prev_binfiletype = binfiletype
      endif
      if( prev_binfiletype .ne. binfiletype ) then
         oned_lfirst = .TRUE.
         twod_lfirst = .TRUE.
         threed_lfirst = .TRUE.
      endif
      datafile_loaded = .TRUE.
c
10000 return
      end
c
      subroutine read_vlsi_l3d(read_error)
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'mesh.cmn'
      include 'data.cmn'
      include 'io.cmn'
      include 'plot.cmn'
c
c     read ASCII VLSICAP L3D file
c
      logical read_error
c
c     locals
c
      integer i, j, ilen, ioerr, string_len, ioff1, ioff2, ioff3, ierr,
     1        nrecl
      character*132 buffer
      character*(PM_MAX_PATHLEN) expanded_name
c
      write(luttyo,10)
10    format(' ','Reading VLSICAP L3D file...',$)
c
c     Append .L3D if no extension
      call add_extension(binfilename,'.l3d')
c
      nrecl=0
      call pm_open_file(binfil, binfilename,
     1               'OLD','FORMATTED','READ','FORTRAN','NONSHARED',
     2               nrecl, ioerr, ierr)
      if( ierr .ne. 0 ) goto 10000
      datafile_record = 1
c
c     get stem of binary file name
      call get_filestem(binfilename, binfilestem)
c
c     clear out arrays
      do 45 j=1,3
         do 45 i=1,COMP_ARRAYSIZE
            xyz(i,j) = 0.0
            edxyz(i,j) = 0.0
            dxyzm(i,j) = 0.0
45    continue
      do 51 j=1,MENUSIZE
         in_binary_file(j) = .FALSE.
51       continue
c
c     1. first read title from binary file
      read(binfil,100,err=10010,iostat=ioerr) title
100   format(a)
c
c     Extract solution cycle number from title
      read(title(31:42),*,err=120,end=120) vlsi_cycle
      goto 121
120   vlsi_cycle = 0
121   continue
c
c     2. now nx, ny
      read(binfil,*,err=10010,iostat=ioerr) nx,ny
      nx = nx+1
      ny = ny+1
      nz = 1
      nt = ny
      nyoxm = 0
      nytot= ny
      nxsp = 1
      nxsoxm = 1
      plane_index = 1
      prev_plane_type = plane_type
      plane_type = XY_PLANE
      xyz(1,3) = -xw/2.0
c
c     Is array storage large enough?
      if( MAX(nx,nytot,nz) .gt. COMP_ARRAYSIZE .or.
     1    (nx*ny) .gt. ARR2DSIZE ) then
         write(luttyo,10050)
10050    format(' ','Error: binary file too large for POSTMINI arrays')
         read_error = .TRUE.  ! go back
         close(unit=binfil)
         return
      endif
c
      nxy=nx*ny
      nxytot=nx*nytot
c
      call allocate_rect_arrays(nx,ny,3,ierr)
      if( ierr .ne. 0 ) then
c        Failure during array allocation
         write(luttyo,10050)
         read_error = .TRUE.
         close(unit=binfil)
         return
      endif
c     Zero array (not really necessary)
      call zero_real_array(arrdat,nx*ny*3,1)
c
c     3. read potential
      do j=ny,1,-1
         ioff1 = arrind(1) + (j-1)*nx - 1
         ioff2 = arrind(2) + (j-1)*nx - 1
         ioff3 = arrind(3) + (j-1)*nx - 1
         do i=1,nx
c           Read data first into character buffer, so we can handle
c           "OUTSIDE DOMAIN" messages...
            read (binfil,200,err=10010,iostat=ioerr) buffer
200         format(a)
            read(buffer,*,err=10010,iostat=ioerr)
     1         xyz(i,1),xyz(j,2),
     2         arrdat(ioff1+i),arrdat(ioff2+i),arrdat(ioff3+i)
c           Check for non blank characters in this field (OUTSIDE DOMAIN)
            if( buffer(66:66) .ne. ' ' ) then
               arrdat(ioff1+i) = 0.0
               arrdat(ioff2+i) = 0.0
               arrdat(ioff3+i) = 0.0
            endif
        enddo
      enddo
      in_binary_file(1) = .TRUE.
      in_binary_file(2) = .TRUE.
      in_binary_file(3) = .TRUE.
c
c     Convert from meters to cm
      do i=1,nx
         xyz(i,1) = 100.0*xyz(i,1)
      end do
      do i=1,ny
         xyz(i,2) = 100.0*xyz(i,2)
      end do
c
c     Load generic mesh pointers, depending on plane type
c
      call set_3d_index_limits
      cut_plane_axis = charb
c     This variable must be set by all read routines...
      data_is_trigrid = .FALSE.
c
      write(luttyo,110)
110   format(' ','...done')
      read_error = .FALSE.
      close(unit=binfil)
      goto 10100
c
c     errors of commission/omission
c
c     I/O error on open of L3D file
10000 continue
      call expand_filename(binfilename,expanded_name)
      ilen = string_len(expanded_name)
      write(luttyo,10001) ioerr, expanded_name(1:ilen)
10001 format(/' ','FORTRAN I/O error #',i5,' on open of L3D file:'/
     1       ' ',a)
      write(luttyo,10002)
10002 format(' ','Check for these errors:'/
     1       ' ','   - Incorrect file, directory or disk name'/
     1       ' ','   - You must have read permission on the file'/)
      read_error = .TRUE.  ! go back and get new name...
      goto 10100
c
c
c     I/O error on read of L3D file
10010 write(luttyo,10011) ioerr
10011 format(/' ','FORTRAN I/O error #',i5,' on read of L3D file')
      if( ioerr .eq. 24 ) then       ! End-of-file during read
         write(luttyo,10012)
10012    format(' ','Unexpected end-of-file during read...'/
     1          ' ','File may not be a VLSICAP L3D file'/)
      else if( ioerr .eq. 67 ) then  ! Not enough data in record
         write(luttyo,10014)
10014    format(' ','Insufficient data in record'/)
      else if( ioerr .eq. -1 ) then  ! End of file at start of read
         write(luttyo,10015)
10015    format(' ','Unexpected end-of-file'/
     1     ' ','File may not have been written completely by MINIMOS'/)
      endif
      read_error = .TRUE.  ! go back and get new name...
      close(unit=binfil)
      goto 10100
c
10100 continue
      return
      end
c
      subroutine read_vlsi_inp(read_error)
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'mesh.cmn'
      include 'data.cmn'
      include 'io.cmn'
      include 'plot.cmn'
c
c     read ASCII VLSICAP INP file
c
      logical read_error
c
c     locals
c
      real real_dummy(2*MAXVERTEX)
      integer i, ilen, ioerr, string_len, idummy, nlist, nrecl, ierr
      character*(PM_MAX_PATHLEN) expanded_name, input_data_name
c
      write(luttyo,10)
10    format(' ','Reading VLSICAP INPUT file...',$)
c
c     Form INP filespec (assumed to be in sibling directory 'input')
      call get_parent_directory(binfilename,input_data_name)
      call add_subdirectory(input_data_name,'input')
      ilen = string_len(input_data_name)
      input_data_name = input_data_name(1:ilen) // binfilestem
      call add_extension(input_data_name,'.inp')
c
      nrecl=0
      call pm_open_file(binfil, input_data_name,
     1               'OLD','FORMATTED','READ','FORTRAN','NONSHARED',
     2               nrecl, ioerr, ierr)
      if( ierr .ne. 0 ) goto 10000
c
      nvertex = 0
      npolygon = 0
      ndomain = 0
c
c     1. first read title from input file
      read(binfil,100,err=10010,iostat=ioerr) title
100   format(a)
c
c     2. list of polygons
200      read(binfil,*,err=10010,iostat=ioerr) idummy
         if( idummy .eq. 0 ) goto 201
         npolygon = npolygon + 1
         if( npolygon .gt. MAXPOLY ) goto 10020
         polygon2vertex(npolygon,1) = nvertex + 1
         if( idummy   .gt. MAXVERTEX ) goto 10020
         read(binfil,*,err=10010,iostat=ioerr)
     1       (real_dummy(i),i=1,2*idummy)
         do i=1,idummy
            nvertex = nvertex + 1
            if( nvertex .gt. MAXVERTEX ) goto 10020
c           Convert from meters to cm
            vertex_coords(nvertex,1) = 100.0*real_dummy(2*i-1)
            vertex_coords(nvertex,2) = 100.0*real_dummy(2*i)
         end do
         polygon2vertex(npolygon,2) = nvertex
      goto 200
201   continue
c
c     3. Two comment lines
      read(binfil,*,end=10010)
      read(binfil,*,end=10010)
c
c     4. User defined dielectric constants
      read(binfil,*,end=10010)
c
c     5. list of domains
300      read(binfil,*,err=10010,end=10010,iostat=ioerr) idummy
         if( idummy .eq. 0 ) goto 301
         ndomain = ndomain + 1
         if( ndomain .gt. MAXDOM ) goto 10020
         domaintype(ndomain) = idummy
         read(binfil,*,err=10010,end=10010,iostat=ioerr) nlist,
     1       (polygon_list(ndomain,i),i=1,nlist)
c        Test for array overflow (a little late, because we could
c        have already overwritten polygon_list).
         if( nlist .gt. MAX_POLYLIST-1 ) goto 10020
c        Terminate polygon list with a zero
         polygon_list(ndomain,nlist+1) = 0
      goto 300
301   continue
c
c     6. list of sheet conductors
400      read(binfil,*,err=10010,end=10010,iostat=ioerr) idummy
         if( idummy .eq. 0 ) goto 401
         ndomain = ndomain + 1
         if( ndomain .gt. MAXDOM ) goto 10020
         domaintype(ndomain) = -11 ! 11 is code for polygon conductor
         if( idummy .gt. MAX_POLYLIST-1 ) goto 10020
         read(binfil,*,err=10010,end=10010,iostat=ioerr)
     1      (polygon_list(ndomain,i), i=1,idummy)
         polygon_list(ndomain,idummy+1) = 0
      goto 400
401   continue
c
      write(luttyo,20)
20    format(' ','...done')
      read_error = .FALSE.
      close(unit=binfil)
      goto 10100
c
c     errors of commission/omission
c
c     I/O error on open of input file
10000 continue
      call expand_filename(input_data_name,expanded_name)
      ilen = string_len(expanded_name)
      write(luttyo,10001) ioerr, expanded_name(1:ilen)
10001 format(/' ','FORTRAN I/O error #',i5,' on open of input file:'/
     1       ' ',a)
      write(luttyo,10002)
10002 format(' ','Check for these errors:'/
     1       ' ','   - Incorrect file, directory or disk name'/
     1       ' ','   - You must have read permission on the file'/)
      read_error = .TRUE.  ! go back and get new name...
      goto 10100
c
c
c     I/O error on read of input file
10010 write(luttyo,10011) ioerr
10011 format(/' ','FORTRAN I/O error #',i5,' on read of input file')
      if( ioerr .eq. 24 ) then       ! End-of-file during read
         write(luttyo,10012)
10012    format(' ','Unexpected end-of-file during read...'/
     1          ' ','File may not be a VLSICAP INP file'/)
      else if( ioerr .eq. 67 ) then  ! Not enough data in record
         write(luttyo,10014)
10014    format(' ','Insufficient data in record'/)
      else if( ioerr .eq. -1 ) then  ! End of file at start of read
         write(luttyo,10015)
10015    format(' ','Unexpected end-of-file'/
     1     ' ','File may not have been written completely by VLSICAP'/)
      endif
      read_error = .TRUE.  ! go back and get new name...
      close(unit=binfil)
      goto 10100
c
c
c     Data exceeds array dimensions
10020 write(luttyo,10021)
10021 format(/' ','Data from VLSICAP input file exceeds POSTMINI',
     1        ' array sizes')
      read_error = .TRUE.
      close(unit=binfil)
      goto 10100
c
10100 continue
      return
      end
c
      subroutine load_vlsi_specific
      implicit none
c
c     Load descriptive arrays with VLSICAP specific data
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'data.cmn'
c
c     Data varies linear or logarithmic
      logical LOG, LIN
      parameter (LOG = .TRUE., LIN = .FALSE.)
c     Data has value in oxide, or not
      logical OX, NO_OX
      parameter (OX = .TRUE., NO_OX = .FALSE.)
c     Data jumps at oxide interfaces
      logical JUMP, NO_JUMP
      parameter (JUMP = .TRUE., NO_JUMP = .FALSE.)
c     Data is 1D or 2D
      logical ONED, TWOD
      parameter (ONED = .TRUE., TWOD = .FALSE.)
c
c     Number of menu items
      max_menu_num = 3
c     Array index of net doping (none in this case)
      net_dop_array_index = 0
c     File has 2D data
      three_d = .FALSE.
c
      call load_desc_arr(1, 'Potential', 'POTENTIAL',
     1                   'V','V cm','V cm^{2} ','.psi',
     2                   LIN,OX,NO_JUMP,TWOD,1)
c
      call load_desc_arr(2, 'Electric field (x-comp)', 'EX',
     1                   'V/cm','V','V cm','.ex',
     2                   LIN,OX,NO_JUMP,TWOD,2)
c
      call load_desc_arr(3, 'Electric field (y-comp)', 'EY',
     1                   'V/cm','V','V cm','.ey',
     2                   LIN,OX,NO_JUMP,TWOD,3)
      return
      end
