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
c     Subroutines to read a SPICE3 compatible data file into Postmini
c
      subroutine read_spice3file(read_error)
      implicit none
c
      logical read_error
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'data.cmn'
c
c     Prompt for parameters for reading a SPICE3 file, then read it...
c
c     locals
c
c     Menu code items
      character*80 string
      character*40 str
      integer      item_number, int_vec(MAXCOLS),
     1             string_len, ilen
      logical      eof, do_read, delayed_message, lerr,
     1             use_last_input
c
      do_read = .FALSE.
      use_last_input = .FALSE.
c
c     Initialize
      datafile_record = 1
c
100   call clear_screen
      call display_string(1, 1,
     1     '  Read SPICE3 data file',23,0)
      call display_string(3 ,1 ,' 1) File :',10,0)
      call display_string(4 ,1 ,' 2) Dataset           :',23,0)
      call display_string(5 ,1 ,' 3) Binary conversion :',23,0)
c
      call display_string(3,12,binfilename,69,1)
      call display_int(4,25,datafile_record,5)
      if( binfile_convert_type .eq. BINFILE_TYPE_DEFAULT ) then
         str = 'No conversion'
      else if( binfile_convert_type .eq.
     1          BINFILE_TYPE_BIG_ENDIAN_IEEE ) then
         str = 'Big endian IEEE'
      else
         str = '???'
      endif
      call display_string(5 ,25,str,LEN(str),1)
c
c     Display any messaged from before window refresh
      if( delayed_message ) then
         call display_message(string)
         delayed_message = .FALSE.
      endif
c
200   call display_prompt('Enter item number, ' //
     1   'or Repaint, Accept (read file), Quit (don''t read)')
      if( .NOT. use_last_input ) then
         call read_from_input_area(string, eof)
      endif
      if( eof ) goto 200
      call upcase(string)
      if( string(1:1) .eq. 'A') then
         do_read = .TRUE.
         goto 300
      else if( string(1:1) .eq. 'Q') then
         do_read = .FALSE.
         goto 300
      elseif (string(1:1) .eq. 'R' ) then
         goto 100
      else
         read(string,*,err=1000) item_number
         if ( item_number .eq. 1 ) then
c           Filename
            call get_string_with_prompt(binfilename,
     1           'Enter filename')
            call display_string(3,12,binfilename,69,1)
         else if ( item_number .eq. 2 ) then
c           Dataset number
            call get_ints_with_prompt(int_vec, 1,
     1            'Enter dataset number')
            if( int_vec(1) .lt. 1 ) then
               call display_message('Invalid dataset number')
            else
               datafile_record = int_vec(1)
               call display_int(4,25,datafile_record,5)
            endif
         else if ( item_number .eq. 3 ) then
c           Binary conversion type
            call get_ints_with_prompt(int_vec,1,
     1         '1==No conversion, 2==IEEE big endian (e.g. RS/6000)')
            if( int_vec(1) .lt. 1 .or. int_vec(1) .gt. 2 ) then
               call display_message('Invalid conversion type')
            else
               binfile_convert_type = int_vec(1)
               if( binfile_convert_type .eq. BINFILE_TYPE_DEFAULT ) then
                  str = 'No conversion'
               else if( binfile_convert_type .eq.
     1             BINFILE_TYPE_BIG_ENDIAN_IEEE ) then
                  str = 'Big endian IEEE'
               else
                  str = '???'
               endif
               call display_string(5 ,25,str,LEN(str),1)
            endif
         else
            call display_message('Item number out of range')
         endif
      endif
      goto 200
c
1000  call display_message('Illegal input')
      goto 200
c
300   if( do_read ) then
         call do_read_spice3file(.FALSE., read_error)
      endif
c
      return
      end
c
      subroutine do_read_spice3file(batchmode,read_error)
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'data.cmn'
      include 'io.cmn'
      include 'mesh.cmn'
      include 'user.cmn'
      include 'gui.cmn'
      include 'evaluate.cmn'
c
c     read an so-called "raw" SPICE3 data file format(s)
c
      logical batchmode, read_error
c
c     locals
c
      integer i, j, error_code, transient_points, ilen, ilen2, istat,
     1        ind, ierr, int_vec(1)
      integer string_len, pm_put_error_msg
      character*(PM_MAX_PATHLEN) expanded_name
      character*16 bintype
      character*80 msg
c
      integer   fspice3_num_transient_points,
     1          fspice3_get_time_data, fspice3_get_quantity_data
c
c     GUI error level: 0=success, 1=warning, 2=error
      gui_error_level = 0
      call pm_clear_error_msg
c
      prev_binfiletype = binfiletype
      binfiletype = DT_SPICE3
c     get stem of file name (for hardcopy)
      call get_filestem(binfilename, binfilestem)
c
      if( .NOT. lgui ) then
         write(luttyo,10)
10       format(' ','Reading SPICE3 file...',$)
      endif
c
      read_error = .FALSE.
c
      call fspice3_open(binfilename, spice3_file, error_code)
      if( error_code .NE. 0 ) then
         call fspice3_get_error_msg(error_code,msg)
         ilen = string_len(msg)
         write(msgbuf,100) msg(1:ilen)
100      format('Error during open of SPICE3 file: ',a)
         istat = pm_put_error_msg(msgbuf)
         gui_error_level = 2
         goto 20000
      endif
c
      if( spice3_data .ne. 0 ) then
         call fspice3_free_data(spice3_data)
         spice3_data = 0
      endif
c
      call fspice3_load_transient(spice3_file, datafile_record,
     1                  binfile_convert_type, spice3_data, error_code)
      if( error_code .NE. 0 ) then
         call fspice3_get_error_msg(error_code,msg)
         ilen = string_len(msg)
         write(msgbuf,101) msg(1:ilen)
101      format('Error during read of SPICE3 file: ',a)
         istat = pm_put_error_msg(msgbuf)
         gui_error_level = 2
         call fspice3_close(spice3_file)
         goto 20000
      endif
c
      call fspice3_close(spice3_file)
c
      transient_points = fspice3_num_transient_points(spice3_data)
      if( transient_points .GT. COMP_ARRAYSIZE) then
         msgbuf =
     1      'Error: SPICE3 file has too many data points for Postmini'
         istat = pm_put_error_msg(msgbuf)
         gui_error_level = 2
         goto 20000
      endif
c
      if( .not. lgui ) then
         write(luttyo,150)
150      format(' ','done')
      endif
c
c     This variable must be set by all read routines...
      data_is_trigrid = .FALSE.
c
      do j=1,MENUSIZE
         in_binary_file(j) = .FALSE.
      end do
      max_menu_num = 1
      is_data_1d(1) = .TRUE.
c
c     Mesh variables/arrays are set once we read in the specific data values
c     from the SPICE3 file...
c
      if( lfirst_read ) then
         lfirst_read = .FALSE.
         prev_plane_type = plane_type
         prev_binfilename = binfilename
         prev_binfiletype = binfiletype
      endif
c     Force plot to rescale each time we read an SPICE3 file
      oned_lfirst = .TRUE.
      twod_lfirst = .TRUE.
      threed_lfirst = .TRUE.
c
      datafile_loaded = .TRUE.
c
      goto 20000
c
c     errors of commission/omission
c
20000 continue
c
      if( gui_error_level .eq. 2 ) read_error = .TRUE.
c
      return
      end
c
      subroutine load_spice3file_data(error)
      implicit none
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'data.cmn'
      include 'io.cmn'
      include 'mesh.cmn'
      include 'user.cmn'
      include 'gui.cmn'
      include 'evaluate.cmn'
c
c     Transfer data from loaded SPICE3 data file to Postmini storage
c
      logical error
c
c     locals
c
      integer i, j, error_code, transient_points, ilen, ilen2, istat,
     1        ind, ierr
      integer string_len, pm_put_error_msg
      character*80 msg
c
      integer   fspice3_num_transient_points,
     1          fspice3_get_quantity_data
c
c     GUI error level: 0=success, 1=warning, 2=error
      gui_error_level = 0
      call pm_clear_error_msg
c
      error = .FALSE.
c
      if( spice3_data .eq. 0 ) then
         istat = pm_put_error_msg('Error: spice3 file is not loaded')
         gui_error_level = 2
         goto 20000
      endif
c
      transient_points = fspice3_num_transient_points(spice3_data)
      if( transient_points .GT. COMP_ARRAYSIZE) then
         msgbuf =
     1      'Error: Spice3 file has too many data points for Postmini'
         istat = pm_put_error_msg(msgbuf)
         gui_error_level = 2
         goto 20000
      endif
c
      if( user_1d_array_size .eq. 0 ) then
         user_1d_array_size = COMP_ARRAYSIZE
c        pm_malloc takes units of bytes, and these variables are of type REAL
c        (4 bytes per real variable).
         user_1d_data_ptr  = pm_malloc(4*user_1d_array_size)
         user_1d_coord_ptr = pm_malloc(4*user_1d_array_size)
         user_1d_zval_ptr  = pm_malloc(4*user_1d_array_size)
      else if( user_1d_array_size .lt. COMP_ARRAYSIZE ) then
         call pm_free(user_1d_data_ptr)
         call pm_free(user_1d_coord_ptr)
         call pm_free(user_1d_zval_ptr)
         user_1d_array_size = COMP_ARRAYSIZE
         user_1d_data_ptr  = pm_malloc(4*user_1d_array_size)
         user_1d_coord_ptr = pm_malloc(4*user_1d_array_size)
         user_1d_zval_ptr  = pm_malloc(4*user_1d_array_size)
      endif
c
      call zero_real_array(user_1d_coord,COMP_ARRAYSIZE,1)
      call zero_real_array(user_1d_data,COMP_ARRAYSIZE,1)
c
      error_code = fspice3_get_quantity_data(spice3_data,
     1                spice3_x_quantity, user_1d_coord)
      if( error_code .NE. 0 ) then
         call fspice3_get_error_msg(error_code,msg)
         ilen  = string_len(spice3_x_quantity)
         ilen2 = string_len(msg)
         write(msgbuf,102) spice3_x_quantity(1:ilen), msg(1:ilen2)
102      format('Error extracting quantity ',a,' from Spice3 file: ',a)
         istat = pm_put_error_msg(msgbuf)
         gui_error_level = 2
      endif
c
      error_code = fspice3_get_quantity_data(spice3_data,
     1                spice3_y_quantity, user_1d_data)
      if( error_code .NE. 0 ) then
         call fspice3_get_error_msg(error_code,msg)
         ilen  = string_len(spice3_y_quantity)
         ilen2 = string_len(msg)
         write(msgbuf,102) spice3_y_quantity(1:ilen), msg(1:ilen2)
         istat = pm_put_error_msg(msgbuf)
         gui_error_level = 2
      endif
c
      if( gui_error_level .NE. 0 ) goto 20000
c
c     Now, copy data to Postmini main storage area
c
c     Clear out arrays
      do 200 j=1,3
         do 200 i=1,COMP_ARRAYSIZE
            xyz(i,j) = 0.0
            edxyz(i,j) = 0.0
            dxyzm(i,j) = 0.0
200   continue
      do 201 j=1,MENUSIZE
         in_binary_file(j) = .FALSE.
201   continue
      call zero_real_array(arr2d,COMP_ARRAYSIZE,MENUSIZE)
c
      do 203 i=1,transient_points
         xyz(i,1)   = user_1d_coord(i)*MU2CM
         arr2d(i,1) = user_1d_data(i)
203   continue
c
      nx = transient_points
c     Fake second and third dimension
      ny = 1
      xyz(1,2) = 0.0
c
      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) = 0.0
      nxy=nx*ny
      nxytot=nx*nytot
c
c     This variable must be set by all read routines...
      data_is_trigrid = .FALSE.
c
      in_binary_file(1) = .TRUE.
c
c     Load generic mesh pointers, depending on plane type
      call set_3d_index_limits
c
c     Set up boundary limits information
      call coord_limits
c
      nxm = nx - 1
      nym = ny - 1
      nytotm = nytot - 1
c
c     inverse mesh spacing...
c
      do 204 i=1,nxm
         if( (xyz(i+1,1) - xyz(i,1)) .eq. 0.0 ) then
            edxyz(i,1) = PM_MAX_FLOAT
         else
            edxyz(i,1) = 1.0/(xyz(i+1,1) - xyz(i,1))
         endif
204   continue
      do 205 i=1,nytotm
205      edxyz(i,2) = 1.0/(xyz(i+1,2) - xyz(i,2))
      do 206 i=1,nz-1
206      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 207 i=2,nxm
207     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 208 i=2,nytotm
208      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 209 i=2,nz-1
209      dxyzm(i,3) = (xyz(i+1,3) - xyz(i-1,3))/2.0
c
      call load_spice3_specific
c
      datafile_loaded = .TRUE.
c
      goto 20000
c
c     errors of commission/omission
c
20000 continue
c
      if( gui_error_level .eq. 2 ) error = .TRUE.
c
      return
      end
c
      subroutine load_spice3_specific
      implicit none
c
c     Load descriptive arrays with SPICE3 specific data
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'data.cmn'
      include 'user.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
      integer rc, fspice3_get_quantity_units
      character*64 temp
c
c     Number of menu items
      max_menu_num = 1
c     Array index of net doping
      net_dop_array_index = 0
c
c     Get units information
      rc = fspice3_get_quantity_units( spice3_data,
     1      spice3_x_quantity, temp)
      if( rc .NE. 0 ) then
         spice3_x_units = ' '
      else
         if( temp .eq. 'voltage' ) then
            spice3_x_units = 'V'
         else if( temp .eq. 'current' ) then
            spice3_x_units = 'A'
         else if( temp .eq. 'time' ) then
            spice3_x_units = 's'
         else if( temp .eq. 'frequency' ) then
            spice3_x_units = 'Hz'
         else
            spice3_x_units = temp
         endif
      endif
c
      rc = fspice3_get_quantity_units(spice3_data,
     1      spice3_y_quantity, temp)
      if( rc .NE. 0 ) then
         spice3_y_units = ' '
      else
         if( temp .eq. 'voltage' ) then
            spice3_y_units = 'V'
         else if( temp .eq. 'current' ) then
            spice3_y_units = 'A'
         else if( temp .eq. 'time' ) then
            spice3_y_units = 's'
         else if( temp .eq. 'frequency' ) then
            spice3_y_units = 'Hz'
         else
            spice3_y_units = temp
         endif
      endif
c
      call load_desc_arr(1, spice3_y_quantity, spice3_y_quantity,
     1                   spice3_y_units,' ',' ','.dat',
     2                   LIN,NO_OX,NO_JUMP,ONED,1)
c
      return
      end
c
      subroutine pm_select_spice3_data(error)
      implicit none
c
      logical error
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'plot.cmn'
      include 'data.cmn'
      include 'io.cmn'
c
c     locals
c
c     Menu code items
      character*80 string
      character*40 str
      real         real_vec(1)
      integer      i, item_number,
     1             imax, imin, string_len, ilen, sim_type
      integer      fspice3_get_simulation_type
      logical      eof, do_load, lerr, delayed_message,
     2             lfirst
c
      data lfirst/.TRUE./
      save lfirst
c
c     Intialize
      if( lfirst ) then
         sim_type = fspice3_get_simulation_type(spice3_data)
         if( sim_type .eq. 1 ) then
            spice3_x_quantity = 'Time'
         else
            spice3_x_quantity = 'Freq'
         endif
         spice3_y_quantity = ' '
         lfirst = .FALSE.
      endif
c
      do_load = .FALSE.
      delayed_message = .FALSE.
c
100   call clear_screen
      call display_string(2, 1, ' Select SPICE3 data ',22,0)

      call display_string(4 ,1 ,' 1) X axis quantity name :',26,0)
      call display_string(5 ,1 ,' 2) Y axis quantity name :',26,0)
c
      call display_string(4,28,spice3_x_quantity,53,1)
      call display_string(5,28,spice3_y_quantity,53,1)
c
c     Display any messaged from before window refresh
      if( delayed_message ) then
         call display_message(string)
         delayed_message = .FALSE.
      endif
c
200   call display_prompt('Enter item number, ' //
     1   'or Repaint, Accept, List variables, Quit ')
      call read_from_input_area(string, eof)
      if( eof ) goto 200
      call upcase(string)
      if( string(1:1) .eq. 'A') then
         do_load = .TRUE.
         goto 300
      else if( string(1:1) .eq. 'Q') then
         do_load = .FALSE.
         goto 300
      elseif (string(1:1) .eq. 'R' ) then
         goto 100
      elseif (string(1:1) .eq. 'L' ) then
         call pm_list_spice3_variables
         goto 100
      else
         read(string,*,err=1000) item_number
         if ( item_number .eq. 1 ) then
c           X quantity name
            call get_string_with_prompt(spice3_x_quantity,
     1           'Enter quantity to use for X axis')
            call display_string(4,28,spice3_x_quantity,53,1)
         else if ( item_number .eq. 2 ) then
c           Y quantity name
            call get_string_with_prompt(spice3_y_quantity,
     1           'Enter quantity to use for Y axis')
            call display_string(5,28,spice3_y_quantity,53,1)
         else
            call display_message('Item number out of range')
         endif
      endif
      goto 200
c
1000  call display_message('Illegal input')
      goto 200
c
300   if( do_load ) then
         call load_spice3file_data(error)
         if( error ) goto 200
      else
         error = .TRUE.
      endif
c
      return
      end
c
      subroutine pm_list_spice3_variables
      implicit none
c
      integer itype
c
      include 'const.h'
      include 'sysdep.cmn'
      include 'io.cmn'
      include 'data.cmn'
c
      integer i, num_variables, ilen, string_len
      logical break
      character*1 ch
      character*80 name
c
      integer fspice3_num_variables
      external fspice3_num_variables, fspice3_get_name_by_index
c
      num_variables = fspice3_num_variables(spice3_data)
c
      call clear_screen
      write(luttyo,100)
100   format(' ','SPICE3 variables contained in raw file:'/)
c
      i = 0
      break = .FALSE.
      do while( i .lt. num_variables .and. .not. break )
         call fspice3_get_name_by_index(spice3_data,i,name)
         ilen = string_len(name)
         write(luttyo,101) name(1:ilen)
101      format(' ',a)
         if( MOD(i+1,24) .eq. 0 ) then
            call get_char(ch,
     1         'Hit return to continue listing, q to quit... ',0)
            call upcase(ch)
            if( ch .eq. 'Q' ) break = .TRUE.
         endif
         i = i + 1
      end do
c
      if( .NOT. break ) then
         write(luttyo,102)
102      format(' ')
         call get_char(ch,'Hit return to continue',0)
      endif
c
      return
      end
