! ==================================
! TREEIO: I/O routines for TREECODE.
! ==================================

! --------------------------------------------------------------------
! INPARM: read in following input parameters:
!
!        hdline    : identification string for the run.
!        nsteps    : number of timesteps.
!        nout      : output system state once every nout steps.
!        dtime     : the timestep.
!        theta     : error tolerance; 0.0 => exact (PP) calculation.
!        eps       : potential softening parameter.
!        usquad    : option to include (.TRUE.) quadrupole terms.

! --------------------------------------------------------------------

        SUBROUTINE INPARM
 		IMPLICIT NONE
	    INCLUDE 'treedefs.f90'
        CHARACTER(8), PARAMETER :: PARSFL = 'treepars'
       
 
!       -----------------------------------------------------
!       Open parameter file, read parameters, close the file.
!       -----------------------------------------------------
        OPEN(UNIT = UPARS, FILE = PARSFL, STATUS = 'OLD')
        READ (UPARS, '(A)') HDLINE

        READ (UPARS, *) NSTEPS, NOUT, DTIME, THETA, EPS, USQUAD

        CLOSE(UNIT = UPARS)
        END SUBROUTINE INPARM

! ---------------------------------------------------------
! GETBDS: read in particle data, assumed to be of the form:
!
!       nbody		: number of bodies.
!       ndim		: number of space dimensions.
!       time		: initial value of time.
!       mass(1)		: mass of first particle.
!       .......	
!       mass(n)		: mass of last particle.
!       x(1) y(1) z(1)	: position of first particle.
!       ..............
!       x(n) y(n) z(n)	: position of last particle.
!       u(1) v(1) w(1)	: velocity of first particle.
!       ..............
!       u(n) v(n) w(n)	: velocity of last particle.
! ---------------------------------------------------------

        SUBROUTINE GETBDS
		IMPLICIT NONE
	    INCLUDE 'treedefs.f90'
        CHARACTER(8), PARAMETER :: BODIFL = 'treebodi'
        INTEGER :: INDIM, P, K

!       --------------------
!       Open body data file.
!       --------------------

        OPEN(UNIT = UBODI, FILE = BODIFL, STATUS = 'OLD')

!       ------------------
!       Read in body data.
!       ------------------

        READ (UBODI, *) NBODY
        READ (UBODI, *) INDIM

!       ----------------------------------------------------------
!       Terminate the simulation if NBODY or INDIM not consistent.
!       ----------------------------------------------------------
        IF (NBODY .LE. 0 .OR. NBODY .GT. MXBODY .OR. INDIM .NE. NDIM) &
         CALL TERROR(' GETBDS: INCONSISTENT OR ILLEGAL INPUTS')
!       --------------------------------------------
!       Read time, masses, positions and velocities.
!       --------------------------------------------

        READ (UBODI, *) TNOW
        DO P = 1, NBODY
          READ (UBODI, *) MASS(P)
        END DO
        DO P = 1, NBODY
          READ (UBODI, *) (POS(P,K), K = 1, NDIM)
        END DO
        DO P = 1, NBODY
          READ (UBODI, *) (VEL(P,K), K = 1, NDIM)
        END DO

!       --------------------
!       Close up input file.
!       --------------------
        CLOSE(UNIT = UBODI)
        END SUBROUTINE GETBDS

! ----------------------------------------------------
! BEGOUT: initialize disk files for subsequent output.
! ----------------------------------------------------

        SUBROUTINE BEGOUT 
		IMPLICIT NONE
	    INCLUDE 'treedefs.f90'
        CHARACTER(8), PARAMETER :: BODOFL = 'treebodo'
        CHARACTER(8), PARAMETER :: BODFFL = 'treebodf'
        CHARACTER(8), PARAMETER :: LGFILE = 'treelogs'

!       --------------------------------
!       Open log file and output header.
!       --------------------------------
        OPEN(UNIT = ULOG, FILE = LGFILE, STATUS = 'NEW')
        CALL OUTHDR
!       ----------------------------
!       Open body data output files.
!       ----------------------------

        OPEN(UNIT=UBODO,FILE=BODOFL,STATUS='replace',form="unformatted")
! ************* CHANGE *******************
!       OPEN(UNIT = UBODO, FILE = BODOFL, STATUS = 'NEW')
        OPEN(UNIT = UBODF, FILE = BODFFL, STATUS = 'NEW')
		
		OPEN(UNIT = PROC_RECV,FILE= "ProcessedRecieves", STATUS = 'NEW')
		OPEN(UNIT = RAW_SEND, FILE = "RawSends",STATUS = 'NEW')
        END SUBROUTINE BEGOUT
 
! ----------------------------------------------------------
! OUTHDR: write header to log file listing input parameters.
! ----------------------------------------------------------

        SUBROUTINE OUTHDR
  		IMPLICIT NONE
	    INCLUDE 'treedefs.f90'
 
        WRITE (ULOG, '(/)')
        WRITE (ULOG, '(1X,72(''*''))')
        WRITE (ULOG, '(1X,''*'',70X,''*'')')
        WRITE (ULOG, '(1X,''*'',19X,1A32,19X,''*'')') HDLINE
        WRITE (ULOG, '(1X,''*'',70X,''*'')')
        WRITE (ULOG, '(1X,72(''*''))')
        WRITE (ULOG, '(1X,''*'',70X,''*'')')
        WRITE (ULOG, 30) NBODY, NSTEPS, NOUT, DTIME
 30     FORMAT(1X, '*', 4X, 'NBODY =', 1I7, 4X, 'NSTEPS =', 1I4, 4X, &
              'NOUT =', 1I4, 4X, 'DTIME =', 1F7.3, 4X, '*')
        WRITE (ULOG, '(1X,''*'',70X,''*'')')

        WRITE (ULOG, 40) USQUAD, EPS, THETA
 40     FORMAT(1X, '*', 4X, 'USEQUAD =', 1L2, 7X, 'EPS =', 1F6.3, 5X, &
              'THETA =', 1F5.2, 2X, 7X, 3X, 8X, '*')

        WRITE (ULOG, '(1X,''*'',70X,''*'')')

	    WRITE (ULOG, '(1X,''*'',4X,1A10,1A30,26X,''*'')') &
     	       'OPTIONS:  ', 'IMPROVED ACCEPTANCE CRITERION '

        WRITE (ULOG, '(1X,''*'',70X,''*'')')
        WRITE (ULOG, '(1X,72(''*''))')
        END SUBROUTINE OUTHDR

! ---------------------------------------------------
! OUTTIM: write force calculation timing to log file.
! ---------------------------------------------------
 
        SUBROUTINE OUTTIM
		IMPLICIT NONE
	    INCLUDE 'treedefs.f90'

        WRITE (ULOG, '(/,1X,''     CPU TIME USED:'',3A16)') &
              'MKTREE', 'ACCEL', 'TOTAL'
        WRITE (ULOG, '(1X,''       (SECONDS)   '',3F16.2)') &
              CPUMKT, CPUACC, CPUMKT + CPUACC
        END SUBROUTINE OUTTIM

! --------------------------------------------------------
! OUTLOG: write force calculation diagnostics to log file.
! --------------------------------------------------------

        SUBROUTINE OUTLOG
 		IMPLICIT NONE
	    INCLUDE 'treedefs.f90'
        DOUBLE PRECISION :: CPUT
 
!       -----------------------------
!       Get system-specific cpu time.
!       -----------------------------
!        CALL SECOND(CPUT)
!        CALL SECNDS(CPUT)
        CPUT=MPI_WTIME()       
        CPUT = CPUT - CPUT0
!       -------------------------------------------------
!       OUTPUT CPU TIME AND FORCE EVALUATION DIAGNOSTICS.
!       -------------------------------------------------
        WRITE (ULOG, '(//)')

        WRITE (ULOG, '(1X,2A9,2A10,2A8,A9)') 'TIME', 'NCELL', &
             'NBTOT', 'NCTOT', 'NTMAX', 'NTAVG', 'CPUTIME'
        WRITE (ULOG, '(1X,F9.3,I9,2I10,2I8,F9.2)')  TNOW, NCELL, &
                   NBTOT, NCTOT, NTMAX, NTAVG, CPUT/60.0

        END SUBROUTINE OUTLOG

! -------------------------------------------------
! OUTDAG: write N-body diagnostic data to log file.
! -------------------------------------------------
 
        SUBROUTINE OUTDAG
		IMPLICIT NONE
	    INCLUDE 'treedefs.f90'
!        INTEGER K, IPRINT
         INTEGER :: K
!        DATA IPRINT /0/

        WRITE (*, '(1X,I4,1X,6(1PE12.4))') IPRINT, &
                   (CMPOS(K), K = 1, NDIM), (CMVEL(K), K = 1, NDIM)
        IPRINT = IPRINT+1
!       ----------------------------------------------------------------
!       Write mass, energy, angular momentum, center of mass quantities.
!       ----------------------------------------------------------------
        WRITE (ULOG, '(/)')
        WRITE (ULOG, '(1X,4A16)') 'ETOT', 'EKIN', 'EPOT', 'MASS'
        WRITE (ULOG, '(1X,3F16.8,F16.8)') ETOT, EKTOT, EPTOT, MTOT
        WRITE (ULOG, '(/)')
        WRITE (ULOG, '(1X,16X,3A16)') 'X', 'Y', 'Z'
        WRITE (ULOG, '(1X, 8X,A8,3E16.6)') &
              'JTOT', AMVEC(1), AMVEC(2), AMVEC(3)
        WRITE (ULOG, '(1X, 8X,A8,3E16.6)') &
              'CMPOS', (CMPOS(K), K = 1, NDIM)
        WRITE (ULOG, '(1X, 8X,A8,3E16.6)') &
              'CMVEL', (CMVEL(K), K = 1, NDIM)
        END SUBROUTINE OUTDAG

! -----------------------------------------------------------
! OUTERR: output error messages to the log file and terminal.
! -----------------------------------------------------------

        SUBROUTINE OUTERR(MSG)
        IMPLICIT NONE
        CHARACTER(*) :: MSG
	    INCLUDE 'treedefs.f90'
 
!       ------------------------------------------------------
!       Write the message, surrounded by stars for visibility.
!       ------------------------------------------------------
        WRITE (ULOG, '(/,1X,72(''*''))')
        WRITE (ULOG, '(/,A)') MSG
        WRITE (ULOG, '(/,1X,72(''*''))')
!       ---------------------------
!       Repeat message to terminal.
!	---------------------------
        WRITE (UTERM, '(/,1X,72(''*''))')
        WRITE (UTERM, '(/,A)') MSG
        WRITE (UTERM, '(/,1X,72(''*''))')
        END SUBROUTINE OUTERR

! -----------------------------------------------
! OUTCPU: output cpu timing data to the log file.
! -----------------------------------------------

        SUBROUTINE OUTCPU
		IMPLICIT NONE
	    INCLUDE 'treedefs.f90'
        DOUBLE PRECISION :: CPUT

!       -----------------------------
!       Get system-specific cpu time.
!       -----------------------------
!        CALL SECOND(CPUT)
!        CALL SECNDS(CPUT)
! ************* CHANGE *******************
        CPUT=MPI_WTIME()
        CPUT = CPUT - CPUT0
        WRITE (ULOG, '(//,'' ELAPSED CPU TIME (SECONDS) : '',F16.2)') &
                   CPUT
        END SUBROUTINE OUTCPU

! ------------------------------------------------------
! PUTBDS: write body data to output file or final file.
! ------------------------------------------------------

         SUBROUTINE PUTBDS(FINAL)
         IMPLICIT NONE
         INCLUDE 'treedefs.f90'
         LOGICAL :: FINAL
!       ------------------------------------
!       Decide which file to use for output.
!       ------------------------------------
         IF (FINAL) THEN
!         -------------------------------------------
!         Output final coordinates, including masses.
!         -------------------------------------------

          WRITE (UBODF,  '(I20)') NBODY
          WRITE (UBODF,  '(I20)') NDIM
          WRITE (UBODF,  '(E20.12E2)') TNOW

          CALL PUTMAS(UBODF)
          CALL PUTPOS_FINAL(UBODF)
          CALL PUTVEL(UBODF)
	      ELSE
!	  ---------------------------------
!	  Output particle coordinates only.
!	  ---------------------------------

!          WRITE (UBODO,  '(I20)') NBODY
!          WRITE (UBODO,  '(I20)') NDIM
!          WRITE (UBODO,  '(E20.12E2)') TNOW

!           write(ubodo) pos
          CALL PUTPOS(UBODO)
! ************* CHANGE *******************
!          CALL PUTVEL(UBODO)
          ENDIF
          END SUBROUTINE PUTBDS

! -------------------------------
! PUTMAS: output body mass array.
! -------------------------------

        SUBROUTINE PUTMAS(UBODY)
        IMPLICIT NONE
        INCLUDE 'treedefs.f90'
        INTEGER :: UBODY, P

        DO P = 1, NBODY
          WRITE (UBODY,  '(E20.12E2)') MASS(P)
        END DO

        END SUBROUTINE PUTMAS

! -----------------------------------
! PUTPOS: output body position array unformatted
! -----------------------------------

        SUBROUTINE PUTPOS(UBODY)
        IMPLICIT NONE
	    INCLUDE 'treedefs.f90'
        INTEGER :: UBODY
        INTEGER :: K, P

           WRITE (UBODY) POS(1:NBODY,1:NDIM)

        END SUBROUTINE PUTPOS

! -----------------------------------
! PUTPOS_FINAL: output body position array in ASCII
! -----------------------------------

        SUBROUTINE PUTPOS_FINAL(UBODY)
        IMPLICIT NONE
	    INCLUDE 'treedefs.f90'
        INTEGER :: UBODY
        INTEGER :: K, P
		
		DO P=1,NBODY
         WRITE (UBODY,  '(3E20.12E2)') (POS(P,K), K = 1, NDIM)
        END DO

        END SUBROUTINE PUTPOS_FINAL

! -----------------------------------
! PUTVEL: output body velocity array.
! -----------------------------------

        SUBROUTINE PUTVEL(UBODY)
        IMPLICIT NONE
	    INCLUDE 'treedefs.f90'
	    
        INTEGER :: UBODY
        INTEGER :: K, P


        DO P = 1, NBODY
          WRITE (UBODY,  '(3E20.12E2)') (VEL(P,K), K = 1, NDIM)
        END DO

        END SUBROUTINE PUTVEL
 
! ----------------------------------------------
! STPOUT: terminate output and close open files.
! ----------------------------------------------

        SUBROUTINE STPOUT
 		IMPLICIT NONE
	    INCLUDE 'treedefs.f90'
 
        WRITE (ULOG, '(//,1X,''CALCULATION TERMINATED'')')
!       ---------------------
!       Close the open files.
!       ---------------------
        CLOSE(UNIT = UBODO)
        CLOSE(UNIT = UBODF)
        CLOSE(UNIT = ULOG)
        CLOSE(UNIT = RAW_SEND)
        CLOSE(UNIT = PROC_RECV)
        END SUBROUTINE STPOUT
