module ProgressBar_Class !! An inline and updateable command prompt progress bar !! !! Example usage !!```fortran !!use variableKind !!use ProgressBar_Class !!type(ProgressBar) :: P !!integer(i32) :: i, N !!N = 100000 !!call P%set(N, time = .false.) !!call P%print(0) !!do i = 1, N !! Compute some stuff !! call P%print(i) !!enddo !!call P%set(N, time = .true.) !!call P%print(0) !!do i = 1, N !! Compute some stuff !! call P%print(i) !!enddo !!``` use iso_fortran_env, only: output_unit use variableKind, only: i32,i64,r32,r64 use Stopwatch_Class use m_time, only: secondsToHMS implicit none private type, public :: ProgressBar !! A progress bar that displays a moving counter with percentage and optional estimated time remaining private type(Stopwatch) :: clk !! Stopwatch to estimate time remaining character(len=14) :: title !! Give a title for the progress bar integer(i64) :: N !! Total number of iterations integer(i32) :: old1p !! 1% counter integer(i32) :: old10p !! 10% counter integer(i32) :: next1p !! 1% counter integer(i32) :: next10p !! 10% counter logical :: time !! Provide an estimated time remaining? integer(i32) :: iTime !! Counter to estimate time real(r64) :: cumTime !! Cumulative time character(len=88) :: bar !! String to write the progress bar to output contains !generic, public :: set => set_i1_ProgressBar_,set_id1_ProgressBar_ !! Print the progress Bar !procedure, private :: set_i1_ProgressBar_ => set_i1_ProgressBar !procedure, private :: set_id1_ProgressBar_ => set_id1_ProgressBar !! Initialize the Progress Bar generic, public :: print => print_i1_ProgressBar_,print_id1_ProgressBar_ !! Print the progress Bar procedure, private :: print_i1_ProgressBar_ => print_i1_ProgressBar procedure, private :: print_id1_ProgressBar_ => print_id1_ProgressBar end type interface ProgressBar module procedure ProgressBar_i1 !! Interfaced with class instantiation ProgressBar() module procedure ProgressBar_id1 !! Interfaced with class instantiation ProgressBar() end interface contains !====================================================================! function ProgressBar_i1(N,title,time) result(res) !! Interfaced with class instantiation ProgressBar() !====================================================================! integer(i32), intent(in) :: N !! Maximum expected number of iterations character(len=*), intent(in), optional :: title !! Title to give the progress bar logical, intent(in), optional :: time !! Show an estimated time to completion? type(ProgressBar) :: res res=ProgressBar_id1(int(N, i64),title,time) end function !====================================================================! !====================================================================! function ProgressBar_id1(N,title,time) result(res) !! Interfaced with class instantiation ProgressBar() !====================================================================! integer(i64), intent(in) :: N !! Maximum expected number of iterations character(len=*), intent(in), optional :: title !! Title to give the progress bar logical, intent(in), optional :: time !! Show an estimated time to completion? type(ProgressBar) :: res res%old1p=0 res%old10p=0 res%N=N write(res%title,'(14x)') if(present(title)) res%title=title res%time=.false. if (present(time)) then res%time=time ! call res%clk%start() res%cumTime=0.d0 res%iTime=0 end if if (res%time) then res%bar = ' Completed:'//res%title//'- % | | Est. Remaining --:--:--.--- (h:m:s)' write(output_unit,'(a1,a88)',advance='no') char(13),res%bar else res%bar = ' Completed:'//res%title//'- % | |' write(output_unit,'(a1,a48)',advance='no') char(13),res%bar endif flush(output_unit) end function !====================================================================! !====================================================================! subroutine print_i1_ProgressBar(this,i) !! Interfaced with ProgressBar%print() !====================================================================! class(ProgressBar) :: this !! ProgressBar Class integer(i32), intent(in) :: i !! Current iteration number call print_id1_ProgressBar(this,int(i, i64)) end subroutine !====================================================================! !====================================================================! subroutine print_id1_ProgressBar(this,i) !! Interfaced with ProgressBar%print() !====================================================================! class(ProgressBar) :: this !! ProgressBar Class integer(i64), intent(in) :: i !! Current iteration number integer(i32) :: kk real(r64) :: tmp real(r64) :: avgTime integer(i64) :: iTmp logical :: printMe ! If we are estimating the time left till completion printMe=.false. tmp=dble(i)/dble(this%N) ! Get the current 1% discretization this%next1p=int(tmp*100.d0) ! Current 1% ! Get the current 10% discretization this%next10p=int(mod(tmp*10.d0,10.d0)) ! Current 10% ! Check for 100% if (this%next1p == 100) this%next10p=10 ! Avoids write out error ! If the 10% level has changed, add a counter to the progress bar kk=37+this%next10p if (this%next10p > this%old10p) then this%bar(kk:kk)='=' ! Write the bar this%old10p=this%next10p end if ! If the 1% has changed, update the bar and print if (this%next1p > this%old1p) then ! Write % to the bar write(this%bar(32:34),'(i3)') this%next1p ! Update the output this%old1p = this%next1p printMe=.true. end if if (this%time) then this%iTime=this%iTime+1 iTmp=this%N/200 if (this%iTime == iTmp) then ! Get the time for this many iterations this%cumTime=this%cumTime+this%clk%lapInSeconds() ! Get the average time per iteration avgTime=this%cumTime/dble(i) ! Estimate time left my multiplying average time by iterations left. avgTime=avgTime*dble(this%N-i) if (avgTime > 1.d-7) write(this%bar(65:88),'(a22)') secondsToHMS(avgTime) printMe=.true. endif if (this%iTime > iTmp) this%iTime=0 if (this%next10p == 10) this%bar(50:88) = 'Finished in '//this%clk%elapsed() end if if (printMe) then if (this%time) then write(output_unit,'(a1,a88)',advance='no') char(13),this%bar else write(output_unit,'(a1,a48)',advance='no') char(13),this%bar endif flush(output_unit) endif if (this%next10p==10) write(output_unit,*) end subroutine !====================================================================! end module