!||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| module POP_IOUnitsMod 28,3 !BOP ! ! !MODULE: POP_IOUnitsMod ! ! !DESCRIPTION: ! This module contains an I/O unit manager for tracking, assigning ! and reserving I/O unit numbers. ! ! There are three reserved I/O units set as parameters in this ! module. The default units for standard input (stdin), standard ! output (stdout) and standard error (stderr). These are currently ! set as units 5,6,6, respectively as that is the most commonly ! used among vendors. However, the user may change these if those ! default units are conflicting with other models or if the ! vendor is using different values. ! ! The maximum number of I/O units per node is currently set by ! the parameter POP\_IOMaxUnits. ! ! !REFDOC: ! ! !REVISION HISTORY: ! SVN:$Id: POP_IOUnitsMod.F90 21322 2010-02-26 22:55:09Z njn01 $ ! 2006-08-21: Phil Jones ! added wrapper for system flush routine ! 2006-08-15: Phil Jones ! fixed problem in case construct for duplicate unit numbers ! stripped DOS line feed-CR stuff ! 2006-07-05: Phil Jones ! added new IO unit manager to follow new naming conventions ! and check to see if unit assigned by another component ! if POP is being called as subroutine in a coupled context ! !USES: use POP_KindsMod #ifdef CCSMCOUPLED use shr_sys_mod use shr_file_mod #endif implicit none private save ! !PUBLIC MEMBER FUNCTIONS: public :: POP_IOUnitsGet, & POP_IOUnitsRelease, & POP_IOUnitsReserve, & POP_IOUnitsRedirect, & POP_IOUnitsFlush ! !PUBLIC DATA MEMBERS: #ifdef CCSMCOUPLED integer (POP_i4), public :: & #else integer (POP_i4), parameter, public :: & #endif POP_stdin = 5, &! reserved unit for standard input POP_stdout = 6, &! reserved unit for standard output POP_stderr = 6 ! reserved unit for standard error ! common formats for writing to stdout, stderr character (9), parameter, public :: & POP_delimFormat = "(72('-'))", & POP_delimFormatNew = "(72('='))" character (5), parameter, public :: & POP_blankFormat = "(' ')" !EOP !BOC !----------------------------------------------------------------------- ! ! private io unit manager variables ! !----------------------------------------------------------------------- integer (POP_i4), parameter :: & POP_IOUnitsMinUnits = 11, & ! do not use unit numbers below this POP_IOUnitsMaxUnits = 99 ! maximum number of open units logical (POP_Logical) :: & POP_IOUnitsInitialized = .false. logical (POP_Logical), dimension(POP_IOUnitsMaxUnits) :: & POP_IOUnitsInUse ! flag=.true. if unit currently open !EOC !*********************************************************************** contains !*********************************************************************** !BOP ! !IROUTINE: POP_IOUnitsGet ! !INTERFACE: subroutine POP_IOUnitsGet(iunit) 1,1 ! !DESCRIPTION: ! This routine returns the next available i/o unit and marks it as ! in use to prevent any later use. ! Note that {\em all} processors must call this routine even if only ! the master task is doing the i/o. This is necessary insure that ! the units remain synchronized for other parallel I/O functions. ! ! !REVISION HISTORY: ! same as module ! !OUTPUT PARAMETERS: integer (POP_i4), intent(out) :: & iunit ! next free i/o unit !EOP !BOC !----------------------------------------------------------------------- ! ! local variables ! !----------------------------------------------------------------------- integer (POP_i4) :: n ! dummy loop index logical (POP_Logical) :: alreadyInUse !----------------------------------------------------------------------- ! ! check to see if units initialized and initialize if necessary ! !----------------------------------------------------------------------- if (.not. POP_IOUnitsInitialized) then POP_IOUnitsInUse = .false. POP_IOUnitsInUse(POP_stdin) = .true. POP_IOUnitsInUse(POP_stdout) = .true. POP_IOUnitsInUse(POP_stderr) = .true. POP_IOUnitsInitialized = .true. endif !----------------------------------------------------------------------- ! ! find next free unit ! !----------------------------------------------------------------------- #ifdef CCSMCOUPLED iunit = shr_file_getUnit() #else srch_units: do n=POP_IOUnitsMinUnits, POP_IOUnitsMaxUnits if (.not. POP_IOUnitsInUse(n)) then ! I found one, I found one !*** make sure not in use by library or calling routines INQUIRE (unit=n,OPENED=alreadyInUse) if (.not. alreadyInUse) then iunit = n ! return the free unit number POP_IOUnitsInUse(iunit) = .true. ! mark iunit as being in use exit srch_units else !*** if inquire shows this unit in use, mark it as !*** in use to prevent further queries POP_IOUnitsInUse(n) = .true. endif endif end do srch_units if (iunit > POP_IOUnitsMaxUnits) stop 'POP_IOUnitsGet: No free units' #endif !----------------------------------------------------------------------- !EOC end subroutine POP_IOUnitsGet !*********************************************************************** !BOP ! !IROUTINE: POP_IOUnitsRelease ! !INTERFACE: subroutine POP_IOUnitsRelease(iunit) 1,1 ! !DESCRIPTION: ! This routine releases an i/o unit (marks it as available). ! Note that {\em all} processors must call this routine even if only ! the master task is doing the i/o. This is necessary insure that ! the units remain synchronized for other parallel I/O functions. ! ! !REVISION HISTORY: ! same as module ! !INPUT PARAMETER: integer (POP_i4), intent(in) :: & iunit ! i/o unit to be released !EOP !BOC !----------------------------------------------------------------------- ! ! check for proper unit number ! !----------------------------------------------------------------------- if (iunit < 1 .or. iunit > POP_IOUnitsMaxUnits) then stop 'POP_IOUnitsRelease: bad unit' endif !----------------------------------------------------------------------- ! ! mark the unit as not in use ! !----------------------------------------------------------------------- #ifdef CCSMCOUPLED call shr_file_freeUnit(iunit) #else POP_IOUnitsInUse(iunit) = .false. ! that was easy... #endif !----------------------------------------------------------------------- !EOC end subroutine POP_IOUnitsRelease !*********************************************************************** !BOP ! !IROUTINE: POP_IOUnitsReserve ! !INTERFACE: subroutine POP_IOUnitsReserve(iunit) ! !DESCRIPTION: ! This routine marks an IO unit as in use to reserve its use ! for purposes outside of POP IO. This is necessary for ! cases where you might be importing code developed elsewhere ! that performs its own I/O and open/closes units. ! Note that {\em all} processors must call this routine even if only ! the master task is doing the i/o. This is necessary insure that ! the units remains synchronized for other parallel I/O functions. ! ! !REVISION HISTORY: ! same as module ! !INPUT PARAMETER: integer (POP_i4), intent(in) :: & iunit ! i/o unit to be reserved !EOP !BOC !----------------------------------------------------------------------- ! ! local variables ! !----------------------------------------------------------------------- logical (POP_Logical) :: alreadyInUse !----------------------------------------------------------------------- ! ! check for proper unit number ! !----------------------------------------------------------------------- if (iunit < POP_IOUnitsMinUnits .or. iunit > POP_IOUnitsMaxUnits) then stop 'POP_IOUnitsReserve: invalid unit' endif !----------------------------------------------------------------------- ! ! check to see if POP already using this unit ! !----------------------------------------------------------------------- if (POP_IOUnitsInUse(iunit)) then stop 'POP_IOUnitsReserve: unit already in use by POP' endif !----------------------------------------------------------------------- ! ! check to see if others already using this unit ! !----------------------------------------------------------------------- INQUIRE (unit=iunit, OPENED=alreadyInUse) if (alreadyInUse) then stop 'POP_IOUnitsReserve: unit already in use by others' endif !----------------------------------------------------------------------- ! ! mark the unit as in use ! !----------------------------------------------------------------------- POP_IOUnitsInUse(iunit) = .true. ! that was easy... !----------------------------------------------------------------------- !EOC end subroutine POP_IOUnitsReserve !*********************************************************************** !BOP ! !IROUTINE: POP_IOUnitsRedirect ! !INTERFACE: subroutine POP_IOUnitsRedirect(iunit, filename) ! !DESCRIPTION: ! This routine enables a user to redirect stdin, stdout, stderr to ! a file instead of to the terminal. It is only permitted for these ! special units. The POP IO file operators should be used for ! normal I/O. ! Note that {\em all} processors must call this routine even if only ! the master task is doing the i/o. This is necessary insure that ! the units remains synchronized for other parallel I/O functions. ! ! !REVISION HISTORY: ! same as module ! !INPUT PARAMETER: integer (POP_i4), intent(in) :: & iunit ! i/o unit to be redirected to file character (*), intent(in) :: & filename ! filename, including path, to which ! i/o should be directed !EOP !BOC !----------------------------------------------------------------------- ! ! check for proper unit number and open file ! !----------------------------------------------------------------------- if (iunit == POP_stdin) then ! open input file for stdin open(unit=iunit, file=filename, status='old', form='formatted') else if (iunit == POP_stdout) then ! open output file for stdout open(unit=iunit, file=filename, status='unknown', form='formatted') else if (iunit == POP_stderr .and. POP_stderr /= POP_stdout) then ! open output file for stderr open(unit=iunit, file=filename, status='unknown', form='formatted') else stop 'POP_IOUnitsRedirect: invalid unit' endif !----------------------------------------------------------------------- !EOC end subroutine POP_IOUnitsRedirect !*********************************************************************** !BOP ! !IROUTINE: POP_IOUnitsFlush ! !INTERFACE: subroutine POP_IOUnitsFlush(iunit) 158,1 ! !DESCRIPTION: ! This routine enables a user to flush the output from an IO unit ! (typically stdout) to force output when the system is buffering ! such output. Because this system function is system dependent, ! we only support this wrapper and users are welcome to insert the ! code relevant to their local machine. In the case where the CCSM ! libraries are available, the shared routine for sys flush can be ! used (and is provided here under a preprocessor option). ! ! !REVISION HISTORY: ! same as module ! !INPUT PARAMETER: integer (POP_i4), intent(in) :: & iunit ! i/o unit to be flushed !EOP !BOC !----------------------------------------------------------------------- ! ! insert your system code here ! !----------------------------------------------------------------------- #ifdef CCSMCOUPLED call shr_sys_flush(iunit) #endif !----------------------------------------------------------------------- !EOC end subroutine POP_IOUnitsFlush !*********************************************************************** end module POP_IOUnitsMod !|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||