pfio_server_demo.F90 Source File


This file depends on

sourcefile~~pfio_server_demo.f90~~EfferentGraph sourcefile~pfio_server_demo.f90 pfio_server_demo.F90 sourcefile~mapl_exceptionhandling.f90 MAPL_ExceptionHandling.F90 sourcefile~pfio_server_demo.f90->sourcefile~mapl_exceptionhandling.f90 sourcefile~pfio.f90 pFIO.F90 sourcefile~pfio_server_demo.f90->sourcefile~pfio.f90

Source Code

#include "MAPL_ErrLog.h"
#include "unused_dummy.H"
!>
! Usage:
!```
! mpirun -np 8 ./pfio_server_demo.x -nc 6 -ns 2 -f1 xxx1.nc4 -f2 xxx2.nc4 -v T -s mpi
!```
! The variable should be 4d with lavel>=20
!
module server_demo_CLI
   use MAPL_ExceptionHandling
   use gFTL_StringVector
   implicit none
   private

   public :: CommandLineOptions
   public :: process_command_line
   
   type CommandLineOptions
      character(len=:), allocatable :: file_1, file_2
      type (StringVector) :: requested_variables

      integer :: npes_client
      integer :: npes_server
      logical :: debug
      character(len=6) :: server_type ! 'mpi' or 'openmp'
   end type CommandLineOptions


contains

   ! The following procedure parses the command line to find various
   ! arguments for file names, target grid resolution, etc.
   subroutine process_command_line(options, rc)
      type (CommandLineOptions), intent(inout) :: options
      integer, optional, intent(out) :: rc

      integer :: n_args
      integer :: i_arg
      character(len=:), allocatable :: argument
      character(len=:), allocatable :: buffer

      n_args = command_argument_count()

      i_arg = 0
      do
         if (i_arg > n_args) exit

         argument = get_next_argument()

         select case (argument)
         case ('-nc', '--npes_client')
            buffer = get_next_argument()
            _ASSERT(buffer /= '-', "too many -")
            read(buffer,*) options%npes_client
         case ('-ns', '--npes_server')
            buffer = get_next_argument()
            _ASSERT(buffer /= '-', "too many -")
            read(buffer,*) options%npes_server
         case ('-f1', '--file_1')
            options%file_1 = get_next_argument()
            _ASSERT(options%file_1(1:1) /= '-', "too many -")
         case ('-f2', '--file_2')
            options%file_2 = get_next_argument()
            _ASSERT(options%file_2(1:1) /= '-', "too many -")
         case ('-v', '--var')
            buffer = get_next_argument()
            _ASSERT(buffer(1:1) /= '-', "too many -")
            options%requested_variables = parse_vars(buffer)
         case ('-s', '--server_type')
            options%server_type = get_next_argument()
            _ASSERT(options%server_type /= '-', "too many-")
         case ('-d', '--debug')
            options%debug = .true.
         case default
            ! ignore
         end select

      end do

   contains
      
      function get_next_argument() result(argument)
         character(len=:), allocatable :: argument
         
         integer :: length
         
         i_arg = i_arg + 1
         
         call get_command_argument(i_arg, length=length)
         allocate(character(len=length) :: argument)
         call get_command_argument(i_arg, value=argument)
         
      end function get_next_argument

      function parse_vars(buffer) result(vars)
         type (StringVector) :: vars
         character(len=*), intent(in) :: buffer

         integer :: idx
         character(len=1), parameter :: COMMA = ','
         character(len=:), allocatable :: string

         string = buffer // COMMA
         do
            if (len(string) == 0) exit
            idx = index(string,COMMA)
            call vars%push_back(string(1:idx-1))
            string = string(idx+1:)
         end do

      end function parse_vars


   end subroutine process_command_line
   

end module server_demo_CLI

!#undef I_AM_MAIN
#include "MAPL_ErrLog.h"
module FakeExtDataMod_server
   use MAPL_ExceptionHandling
   use server_demo_CLI
   use pFIO
   use gFTL_StringVector
   use, intrinsic :: iso_fortran_env, only: REAL32
   implicit none
   private

   public :: FakeExtData

   type FakeBundle
      real(kind=REAL32), allocatable :: x(:,:,:,:)
      integer :: request_id
   end type FakeBundle

   type FakeExtData
      type (ClientThread) :: c

      character(len=:), allocatable :: file_1
      character(len=:), allocatable :: file_2

      type (StringVector) :: vars
      type (FakeBundle), allocatable :: bundle(:)

      integer :: comm
      integer :: rank
      integer :: npes

      integer :: nlat
      integer :: nlon

   contains
      procedure :: init
      procedure :: run
      procedure :: finalize

   end type FakeExtData

contains
   

   subroutine init(this, options, comm, d_s)
      use gFTL_StringIntegerMap
      class (FakeExtData), intent(inout) :: this
      type (CommandLineOptions), intent(in) :: options
      integer, intent(in) :: comm
      class (AbstractDirectoryService), target,intent(inout) :: d_s

      integer :: ierror, rc, status
      type (FileMetadata) :: file_metadata
      type (NetCDF4_FileFormatter) :: formatter
      type (StringIntegerMap) :: dims

      this%c = ClientThread()
      call d_s%connect_to_server('i_server', this%c, comm)

      this%file_1 = options%file_1
      this%file_2 = options%file_2
      this%vars = options%requested_variables

      this%comm = comm
      call MPI_Comm_rank(comm,this%rank, ierror)
      _VERIFY(ierror)
      call MPI_Comm_size(comm,this%npes, ierror)
      _VERIFY(ierror)

      allocate(this%bundle(this%vars%size()))

      call formatter%open(this%file_1, pFIO_READ)
      file_metadata = formatter%read()
      call formatter%close()

      dims = file_metadata%get_dimensions()
      this%nlat = dims%at('lat')
      this%nlon = dims%at('lon')
      
   end subroutine init

   subroutine run(this, step)
      class (FakeExtData), target, intent(inout) :: this
      integer, intent(in) :: step
      
      type (ArrayReference) :: ref

      integer :: i_var
      !integer :: i
      integer :: lat0, lat1
      integer :: collection_id
      !character(len=4) :: tmp    
 
      lat0 = 1 + (this%rank*this%nlat)/this%npes
      lat1 = (this%rank+1)*this%nlat/this%npes

      ! Establish the collection
      ! In a real use case the collection name would be the ExtData template.
      ! But the actual name does not matter - it is just used to identify
      ! a group of files that have identical metadata (except for time)
      !do i = 1,9999
      !   tmp= ''
      !   write(tmp,'(I4.4)') i
      !collection_id = this%c%add_ext_collection('collection-name'//tmp)
      !enddo
      collection_id = this%c%add_ext_collection('collection-name')

      select case (step)
      case (1) ! read 1st file; prefetch 2nd

         do i_var = 1, this%vars%size()
            allocate(this%bundle(i_var)%x(this%nlon,lat0:lat1,1,1))
            this%bundle(i_var)%x = -1
            ref = ArrayReference(this%bundle(i_var)%x)
            this%bundle(i_var)%request_id = &
                 & this%c%prefetch_data(collection_id, this%file_1, this%vars%at(i_var), ref, start=[1,lat0,20,1])
         end do
         call this%c%done_prefetch()

         do i_var = 1, this%vars%size()
            call this%c%wait(this%bundle(i_var)%request_id)
         end do

         do i_var = 1, this%vars%size()
            this%bundle(i_var)%x = -1
            ref = ArrayReference(this%bundle(i_var)%x)
            this%bundle(i_var)%request_id = &
                 & this%c%prefetch_data(collection_id, this%file_2, this%vars%at(i_var), ref, start=[1,lat0,20,1])
         end do
         call this%c%done_prefetch()

      case (2) ! wait for 2nd file to complete

         do i_var = 1, this%vars%size()
            call this%c%wait(this%bundle(i_var)%request_id)
         end do

      end select
      
   end subroutine run


   subroutine finalize(this)
      class (FakeExtData), intent(inout) :: this
      deallocate(this%bundle)
      call this%c%terminate()
   end subroutine finalize

end module FakeExtDataMod_server

#define I_AM_MAIN
#include "MAPL_ErrLog.h"
program main
   use mpi
   use pFIO
   use server_demo_CLI
   use FakeExtDataMod_server
   use MAPL_ExceptionHandling
   implicit none

   integer :: rank, npes, ierror, provided
   integer :: status, color, key, rc
   class(BaseServer),allocatable :: s


   type (CommandLineOptions) :: options
   integer, parameter :: SERVER_COLOR = 1
   integer, parameter :: CLIENT_COLOR = 2

   integer :: comm
!C$   integer :: num_threads
   type (FakeExtData), target :: extData
   class(AbstractDirectoryService), pointer :: d_s=>null()

   call MPI_init_thread(MPI_THREAD_MULTIPLE, provided, ierror)
   _VERIFY(ierror)
   call MPI_Comm_rank(MPI_COMM_WORLD, rank, ierror)
   _VERIFY(ierror)
   call MPI_Comm_size(MPI_COMM_WORLD, npes, ierror)
   _VERIFY(ierror)

   call process_command_line(options, rc=status)


   if (rank < options%npes_server) then
      color = SERVER_COLOR
   else
      color = CLIENT_COLOR
   end if
   key = 0

   call MPI_Comm_split(MPI_COMM_WORLD, color, key, comm, ierror)
   _VERIFY(ierror)

!C$   num_threads = 20
   allocate(d_s, source = DirectoryService(MPI_COMM_WORLD))

   if (color == SERVER_COLOR) then
      if(trim(options%server_type) == 'mpi') then
         allocate(s, source=MpiServer(comm, 'i_server'))
         call d_s%publish(PortInfo('i_server', s),s)
         call d_s%connect_to_client('i_server', s)
         print*, "using MpiServer"
      else if(trim(options%server_type) == 'openmp') then
!C$         call omp_set_num_threads(num_threads)
!C$         allocate(s, source=OpenMPServer(comm,d_s))
!C$         print*, "using OpenMPServer"
      else
         print*, options%server_type // '  not implemented'
         stop
      endif    
      call s%start()
   else ! client
      call extData%init(options, comm, d_s)
      call extData%run(step=1)
      call extData%run(step=2)
      call extData%finalize()

      !print*,"terminate_servers"
      !call global_directory_service%terminate_servers(comm)
   end if

   call MPI_finalize(ierror)

end program main