Skip to content

Commit 42d5e58

Browse files
committed
added an optional bisect_used output
to check if the method failed and bisection was used afterwards. LaTeX table updates
1 parent 90105e8 commit 42d5e58

File tree

2 files changed

+43
-16
lines changed

2 files changed

+43
-16
lines changed

src/root_module.F90

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ end function root_name_to_method
389389

390390
subroutine root_scalar_by_name(method,fun,ax,bx,xzero,fzero,iflag,&
391391
ftol,rtol,atol,maxiter,fax,fbx,&
392-
bisect_on_failure)
392+
bisect_on_failure,bisect_used)
393393

394394
implicit none
395395

@@ -410,6 +410,7 @@ subroutine root_scalar_by_name(method,fun,ax,bx,xzero,fzero,iflag,&
410410
!! it will be retried using the bisection method.
411411
!! (default is False). Note that this can use up
412412
!! to `maxiter` additional function evaluations.
413+
logical,intent(out),optional :: bisect_used !! if the bisection method was used after failure
413414

414415
type(root_method) :: r
415416

@@ -418,7 +419,7 @@ subroutine root_scalar_by_name(method,fun,ax,bx,xzero,fzero,iflag,&
418419
if (r%id /= 0) then
419420
call root_scalar(r,fun,ax,bx,xzero,fzero,iflag,&
420421
ftol,rtol,atol,maxiter,fax,fbx,&
421-
bisect_on_failure)
422+
bisect_on_failure,bisect_used)
422423
else
423424
iflag = -999 ! invalid method
424425
return
@@ -433,7 +434,7 @@ end subroutine root_scalar_by_name
433434

434435
subroutine root_scalar_by_type(method,fun,ax,bx,xzero,fzero,iflag,&
435436
ftol,rtol,atol,maxiter,fax,fbx,&
436-
bisect_on_failure)
437+
bisect_on_failure,bisect_used)
437438

438439
implicit none
439440

@@ -454,6 +455,7 @@ subroutine root_scalar_by_type(method,fun,ax,bx,xzero,fzero,iflag,&
454455
!! it will be retried using the bisection method.
455456
!! (default is False). Note that this can use up
456457
!! to `maxiter` additional function evaluations.
458+
logical,intent(out),optional :: bisect_used !! if the bisection method was used after failure
457459

458460
class(root_solver),allocatable :: s
459461

@@ -486,7 +488,8 @@ subroutine root_scalar_by_type(method,fun,ax,bx,xzero,fzero,iflag,&
486488
end select
487489

488490
call s%initialize(func_wrapper,ftol,rtol,atol,maxiter)
489-
call s%solve(ax,bx,xzero,fzero,iflag,fax,fbx,bisect_on_failure)
491+
call s%solve(ax,bx,xzero,fzero,iflag,fax,fbx,&
492+
bisect_on_failure,bisect_used)
490493

491494
contains
492495

@@ -505,7 +508,7 @@ end subroutine root_scalar_by_type
505508
!>
506509
! Main wrapper routine for all the methods.
507510

508-
subroutine solve(me,ax,bx,xzero,fzero,iflag,fax,fbx,bisect_on_failure)
511+
subroutine solve(me,ax,bx,xzero,fzero,iflag,fax,fbx,bisect_on_failure,bisect_used)
509512

510513
implicit none
511514

@@ -521,10 +524,13 @@ subroutine solve(me,ax,bx,xzero,fzero,iflag,fax,fbx,bisect_on_failure)
521524
!! it will be retried using the bisection method.
522525
!! (default is False). Note that this can use up
523526
!! to `maxiter` additional function evaluations.
527+
logical,intent(out),optional :: bisect_used !! if the bisection method was used after failure
524528

525529
real(wp) :: fa !! `f(ax)` passed to the lower level routine
526530
real(wp) :: fb !! `f(bx)` passed to the lower level routine
527531

532+
if (present(bisect_used)) bisect_used = .false.
533+
528534
if (ax==bx) then
529535
! ax must be /= bx
530536
iflag = -4
@@ -563,13 +569,19 @@ subroutine solve(me,ax,bx,xzero,fzero,iflag,fax,fbx,bisect_on_failure)
563569
! if it failed, then we have the option to then try bisection
564570
if (iflag /= 0) then
565571
if (present(bisect_on_failure)) then
566-
if (bisect_on_failure) then
567-
! use the wrapper routine for that with the input class
568-
call root_scalar(root_method_bisection,&
569-
func_wrapper,ax,bx,xzero,fzero,iflag,&
570-
me%ftol,me%rtol,me%atol,me%maxiter,fa,fb,&
571-
bisect_on_failure = .false.)
572-
end if
572+
select type (me)
573+
class is (bisection_solver)
574+
! can't bisect after failed bisection
575+
class default
576+
if (bisect_on_failure) then
577+
! use the wrapper routine for that with the input class
578+
call root_scalar(root_method_bisection,&
579+
func_wrapper,ax,bx,xzero,fzero,iflag,&
580+
me%ftol,me%rtol,me%atol,me%maxiter,fa,fb,&
581+
bisect_on_failure = .false.)
582+
if (present(bisect_used)) bisect_used = .true.
583+
end if
584+
end select
573585
end if
574586
end if
575587

test/root_tests.f90

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ program root_tests
6868
case(real32)
6969
atol = 1.0e-5_wp
7070
rtol = 1.0e-5_wp
71-
ftol = 1.0e-5_wp
71+
ftol = 1.0e-6_wp
7272
tol_for_check = 1.0e-4_wp
7373
kind_str = 'real32'
7474
case(real64)
@@ -171,6 +171,11 @@ program root_tests
171171
end do
172172

173173
write(iunit_results,'(a)') '\end{longtable}'
174+
175+
write(iunit_results,'(a)') ' '
176+
write(iunit_results,'(a)') '$^*$ indicates that the method failed and bisection was used.'
177+
write(iunit_results,'(a)') ' '
178+
174179
write(iunit_results,'(a)') '\end{landscape}'
175180
write(iunit_results,'(a)') '\end{document}'
176181

@@ -213,6 +218,7 @@ subroutine test()
213218
character(len=1000) :: line
214219
integer,dimension(number_of_methods) :: fevals !! func evals for each case
215220
real(wp),dimension(number_of_methods) :: cases_per_sec !! speed of each case
221+
logical,dimension(number_of_methods) :: bisect_used !! if the method failed and bisection was used
216222
integer :: best_feval, worst_feval
217223
real(wp) :: best_cases_per_second
218224
character(len=:),allocatable :: best,failures
@@ -224,9 +230,11 @@ subroutine test()
224230
character(len=10) :: itmp, nstr
225231
integer :: n_bounds_cases, bounds_cases_first
226232
character(len=30) :: root_str
233+
logical :: bis
227234

228235
integer,parameter :: n_repeat = 1 !! number of times to repeat each test for timing purposes
229236
integer,parameter :: maxiter = 1000 !! maximum number of iterations
237+
logical,parameter :: bisect_on_failure = .true. !! to fall back to bisection if method fails
230238

231239
write(output_unit,fmt) &
232240
repeat('-',20),repeat('-',3),repeat('-',4),repeat('-',16),&
@@ -252,13 +260,16 @@ subroutine test()
252260
call cpu_time(tstart)
253261
do irepeat = 1, n_repeat
254262
ifunc = 0 ! reset func evals counter
255-
call root_scalar(methods(imeth),func,ax,bx,xzero,fzero,iflag,bisect_on_failure=.true., &
263+
call root_scalar(methods(imeth),func,ax,bx,xzero,fzero,iflag,&
264+
bisect_on_failure = bisect_on_failure, &
265+
bisect_used = bis, &
256266
atol = atol, rtol = rtol, ftol = ftol, maxiter = maxiter )
257267
end do
258268
call cpu_time(tfinish)
259269

260270
error = xzero-root
261-
write(line, dfmt) trim(methods(imeth)),nprob,n,error,xzero,fzero,ifunc,iflag,n_repeat / (tfinish-tstart), trim(tmp)
271+
write(line, dfmt) trim(methods(imeth)),nprob,n,error,xzero,fzero,ifunc,iflag,&
272+
n_repeat / (tfinish-tstart), trim(tmp)
262273

263274
root_found = abs(fzero) <= tol_for_check !.and. abs(error) <= tol_for_check
264275

@@ -276,6 +287,7 @@ subroutine test()
276287
fevals(imeth) = huge(1)
277288
cases_per_sec(imeth) = huge(1.0_wp)
278289
end if
290+
bisect_used(imeth) = bis
279291

280292
end do
281293

@@ -314,7 +326,10 @@ subroutine test()
314326
fevals_line = ''
315327
do i = 1, size(fevals)
316328
write(itmp, '(I10)') fevals(i); itmp = trim(adjustl(itmp))
317-
if (fevals(i) == best_feval) then
329+
if (bisect_used(i)) itmp = trim(itmp) // '$^*$'
330+
if (bisect_used(i)) then
331+
fevals_line = fevals_line // '\cellcolor{red!75} ' // itmp // '&' ! always color red if it failed
332+
else if (fevals(i) == best_feval) then
318333
if (count(fevals==best_feval)==1) then
319334
! the sole winner
320335
fevals_line = fevals_line // '\cellcolor{green!75} ' // itmp // '&'

0 commit comments

Comments
 (0)