## Cheetah template for skeletal writer in fortran
## See the Cheetah documentation for proper syntax

!!
!! Automatically generated by skel. Modify at your own risk.


program skel


  use mpi
  use adios_write_mod
  IMPLICIT NONE

  real*8 :: skel_init_timer = 0, &
    skel_open_timer = 0, &
    skel_access_timer = 0, &
    skel_close_timer = 0, &
    skel_total_timer = 0

  CHARACTER(LEN=128) :: skel_filename

  integer*4 :: skel_mpi_size, skel_mpi_rank, skel_i
  integer*4 :: error
  integer*8 :: adios_error
  integer*8 :: adios_groupsize
#if $noxml
  integer*8 :: skel_adios_group
#end if

  integer :: comm

  integer*8 :: adios_handle, &
    skel_total_size
  real*8 :: skel_total_init, skel_total_open, skel_total_access, skel_total_close, skel_total_total

! Scalar declarations
#for v in filter (lambda x: x.get_dims() is None, $bpy.get_vars() ):
  $v.get_fortran_type() :: $v.get_safe_name()
#end for

! Skel variables for global array management
#for v in filter (lambda x: x.get_dims() is not None, $bpy.get_vars() ):
    #for sv in $v.get_offset_vars()
  integer*4 :: $sv ($bpy.get_num_procs())
    #end for
#end for

! Array declarations
#for v in filter (lambda x: x.get_dims() is not None, $bpy.get_vars() ):
  $v.get_fortran_type(), ALLOCATABLE, DIMENSION(:#for d in range(int($v.get_ndims())-1)#,:#end for#) :: $v.get_safe_name()
#end for

  call MPI_INIT (error)

! Time the init
  call MPI_BARRIER (MPI_COMM_WORLD, error)
  skel_init_timer = skel_init_timer - MPI_Wtime();

#if $noxml
  call adios_init_noxml (MPI_COMM_WORLD, error)
#else
  call adios_init ("${project}_skel.xml", MPI_COMM_WORLD, error)
#end if

  skel_init_timer = skel_init_timer + MPI_WTIME();
  call MPI_Comm_rank (MPI_COMM_WORLD, skel_mpi_rank, error)
  call MPI_Comm_size (MPI_COMM_WORLD, skel_mpi_size, error)

! Initialize the scalars
#for v in filter (lambda x: x.get_dims() is None, $bpy.get_vars() ):
    #if not v.get_value(): 
    $v.get_safe_name = 16 <% sys.stderr.write ('No value found for variable "%s", using default value.\n' % v.get_name()) %>
    #else:
    $v.get_safe_name = $v.get_value()
    #end if
#end for

! Initialize Skel variables
#for v in filter (lambda x: x.get_dims() is not None, $bpy.get_vars() ):
    #for sv in $v.get_offset_vars()
    $sv = (/ $v.get_offset_values_str($sv) /)
    #end for
#end for
 

! Initialize the arrays
#for v in filter (lambda x: x.get_dims() is not None, $bpy.get_vars() ):
    allocate ($v.get_safe_name()(#echo ','.join (str(x) for x in $v.get_dims() )#))
#end for

  skel_total_timer = skel_total_timer - MPI_Wtime()

 skel_i = 0


#if $noxml

call adios_allocate_buffer ($bpy.get_buf_size_mb(), error);
call adios_declare_group (skel_adios_group, "${bpy.get_group_name()}", "", 1, error);
call adios_select_method (skel_adios_group, "$bpy.get_method()", "$bpy.get_parameters()", "", error);

## This loop generates any needed skel auxiliary variables
#for v in $bpy.get_vars():
    #if $v.has_global_bounds():
        #for sv in $v.get_offset_vars()
call adios_define_var (skel_adios_group, "$sv", "", adios_integer, "", "", "", adios_error)
        #end for
    #end if
#end for

## This loop handles the user defined variables
    #for v in $bpy.get_vars():
call adios_define_var (skel_adios_group, &
                       "$v.get_name()", "", &
                       $v.get_adios_type(), "$v.get_dims_str()", &
                       "$v.get_global_dims_str()", "$v.get_offset_vars_str()", adios_error)
    #end for


#end if



 DO
  skel_i = skel_i + 1
  IF (skel_i .GT. 1) EXIT

! Time the opens
  call MPI_Barrier (MPI_COMM_WORLD, error)
  skel_open_timer = skel_open_timer - MPI_Wtime()

  write (skel_filename, '(I0)') skel_i
  skel_filename = "out_${bpy.get_group_name()}_write_"//skel_filename//".bp"
 call MPI_Comm_dup (MPI_COMM_WORLD, comm, error)
  call adios_open(adios_handle, "${bpy.get_group_name()}", skel_filename, "w", comm, error);
  skel_open_timer = skel_open_timer + MPI_Wtime()

! Time the writes
  skel_access_timer = skel_access_timer - MPI_Wtime()

! Set the adios group size
  adios_groupsize = &
#for v in $bpy.get_vars():
                     $v.get_size() + &
#end for
#for v in filter (lambda x: x.get_dims() is not None, $bpy.get_vars() ):
    #for sv in $v.get_offset_vars()
                     4 + &
    #end for
#end for
                     0

  call adios_group_size (adios_handle, adios_groupsize, skel_total_size, error)

! Write each variable
! First the scalars
#for v in filter (lambda x: x.get_dims() is None, $bpy.get_vars() ):
    call adios_write (adios_handle, "$v.get_name", $v.get_safe_name(), error)
#end for

! Next Skel variables
#for v in filter (lambda x: x.get_dims() is not None, $bpy.get_vars() ):
    #for sv in $v.get_offset_vars()
    call adios_write (adios_handle, &
                      "$sv", &
                       $sv (skel_mpi_rank+1), &
                       error)
    #end for
#end for

! Now the arrays
#for v in filter (lambda x: x.get_dims() is not None, $bpy.get_vars() ):
    call adios_write (adios_handle, "$v.get_name", $v.get_safe_name(), error)
#end for


! Stop timing the writes
  skel_access_timer = skel_access_timer + MPI_Wtime()

! Time the closes
  skel_close_timer = skel_close_timer - MPI_Wtime()
  call adios_close (adios_handle, error)
  skel_close_timer = skel_close_timer + MPI_Wtime()

 END DO

  skel_total_timer = skel_total_timer + MPI_Wtime()

! Output results

  call skel_write_coarse_xml_data_f (skel_open_timer, skel_access_timer, skel_close_timer, skel_total_timer)

  call MPI_Reduce (skel_init_timer, skel_total_init, 1, MPI_DOUBLE_PRECISION, MPI_MAX, 0, MPI_COMM_WORLD, error)
  call MPI_Reduce (skel_open_timer, skel_total_open, 1, MPI_DOUBLE_PRECISION, MPI_MAX, 0, MPI_COMM_WORLD, error)
  call MPI_Reduce (skel_access_timer, skel_total_access, 1, MPI_DOUBLE_PRECISION, MPI_MAX, 0, MPI_COMM_WORLD, error)
  call MPI_Reduce (skel_close_timer, skel_total_close, 1, MPI_DOUBLE_PRECISION, MPI_MAX, 0, MPI_COMM_WORLD, error)
  call MPI_Reduce (skel_total_timer, skel_total_total, 1, MPI_DOUBLE_PRECISION, MPI_MAX, 0, MPI_COMM_WORLD, error)

  if (skel_mpi_rank == 0) then
!    write (*,*) '\n'
    write (*,*) '**************************'
    write (*,*) '  Groupsize: ', adios_groupsize
    write (*,*) '  Open Time: ', skel_total_open
    write (*,*) 'Access Time: ', skel_total_access
    write (*,*) ' Close Time: ', skel_total_close
    write (*,*) ' Total Time: ', skel_total_total
    write (*,*) '**************************'
!    write (*,*) '\n'
  endif

! Clean up
  call adios_finalize(0, error)
  call MPI_Finalize(error)

end program skel
