Skip to content

Commit 65c6c2c

Browse files
committed
added a simple bounds check mode
Fixes #25 needs testing
1 parent 2b5b934 commit 65c6c2c

File tree

1 file changed

+50
-1
lines changed

1 file changed

+50
-1
lines changed

src/nlesolver_module.F90

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,15 @@ module nlesolver_module
108108
character(len=:),allocatable :: message !! latest status message
109109
integer :: istat = -999 !! latest status message
110110

111+
integer :: bounds_mode = 0 !! how to handle the `x` variable bounds:
112+
!!
113+
!! * 0 = ignore bounds.
114+
!! * 1 = use bounds (if specified) by adjusting the `x` vector
115+
!! at each function evaluation so that each individual `x`
116+
!! component is within its bounds.
117+
real(wp),dimension(:),allocatable :: xlow !! lower bounds for `x` (size is `n`). only used if `bounds_mode>0`.
118+
real(wp),dimension(:),allocatable :: xupp !! upper bounds for `x` (size is `n`). only used if `bounds_mode>0`.
119+
111120
procedure(func_func),pointer :: func => null() !! user-supplied routine to compute the function
112121
procedure(export_func),pointer :: export_iteration => null() !! user-supplied routine to export iterations
113122
procedure(wait_func),pointer :: user_input_check => null() !! user-supplied routine to enable user to stop iterations
@@ -167,6 +176,7 @@ module nlesolver_module
167176
procedure,public :: status => get_status
168177

169178
procedure :: set_status
179+
procedure :: adjust_x_for_bounds
170180

171181
end type nlesolver_type
172182
!*********************************************************
@@ -361,7 +371,8 @@ subroutine initialize_nlesolver_variables(me,&
361371
verbose,iunit,n_uphill_max,n_intervals,&
362372
sparsity_mode,irow,icol,&
363373
atol,btol,conlim,damp,itnlim,nout,&
364-
lusol_method,localSize,custom_solver_sparse )
374+
lusol_method,localSize,custom_solver_sparse,&
375+
bounds_mode,xlow,xupp)
365376

366377
implicit none
367378

@@ -437,6 +448,14 @@ subroutine initialize_nlesolver_variables(me,&
437448
!! At most `min(m,n)` vectors will be allocated.
438449
procedure(sparse_solver_func),optional :: custom_solver_sparse !! for `sparsity_mode=5`, this is the
439450
!! user-provided linear solver.
451+
logical,intent(in),optional :: bounds_mode !! how to handle the `x` variable bounds:
452+
!!
453+
!! * 0 = ignore bounds
454+
!! * 1 = use bounds (if specified) by adjusting the `x` vector
455+
!! at each step so that each individual `x` component is within
456+
!! the bounds
457+
real(wp),dimension(n),intent(in),optional :: xlow !! lower bounds for `x` (size is `n`). only used if `bounds_mode>0`.
458+
real(wp),dimension(n),intent(in),optional :: xupp !! upper bounds for `x` (size is `n`). only used if `bounds_mode>0`.
440459

441460
logical :: status_ok !! true if there were no errors
442461

@@ -453,6 +472,14 @@ subroutine initialize_nlesolver_variables(me,&
453472

454473
!optional:
455474

475+
if (present(bounds_mode) .and. present(xlow) .and. present(xupp)) then
476+
me%bounds_mode = bounds_mode
477+
me%xupp = xupp
478+
me%xlow = xlow
479+
else
480+
me%bounds_mode = 0 ! default
481+
end if
482+
456483
if (present(step_mode)) then
457484
select case (step_mode)
458485
case(1) ! = use the specified `alpha` (0,1]
@@ -672,6 +699,7 @@ subroutine nlesolver_solver(me,x)
672699
end if
673700

674701
! evaluate the function:
702+
call me%adjust_x_for_bounds(x) ! if the guess is out of bounds it may also be adjusted first.
675703
call me%func(x,fvec)
676704
f = norm2(fvec)
677705

@@ -923,6 +951,22 @@ subroutine nlesolver_solver(me,x)
923951
end subroutine nlesolver_solver
924952
!*****************************************************************************************
925953

954+
!*****************************************************************************************
955+
!>
956+
! if necessary, adjust the `x` vector to be within the bounds.
957+
958+
subroutine adjust_x_for_bounds(me,x)
959+
960+
implicit none
961+
962+
class(nlesolver_type),intent(inout) :: me
963+
real(wp),dimension(me%n),intent(inout) :: x !! the `x` vector to adjust
964+
965+
if (me%bounds_mode==1) x = min(max(x,me%xlow),me%xupp)
966+
967+
end subroutine adjust_x_for_bounds
968+
!*****************************************************************************************
969+
926970
!*****************************************************************************************
927971
!>
928972
! Destructor
@@ -1042,6 +1086,7 @@ subroutine simple_step(me,xold,p,x,f,fvec,fjac,fjac_sparse)
10421086
real(wp),dimension(:),intent(in),optional :: fjac_sparse !! jacobian matrix [sparse]
10431087

10441088
x = xold + p * me%alpha
1089+
call me%adjust_x_for_bounds(x)
10451090

10461091
!evaluate the function at the new point:
10471092
call me%func(x,fvec)
@@ -1115,6 +1160,7 @@ subroutine backtracking_linesearch(me,xold,p,x,f,fvec,fjac,fjac_sparse)
11151160
do
11161161

11171162
xtmp = xold + p * alpha
1163+
call me%adjust_x_for_bounds(xtmp)
11181164
call me%func(xtmp,fvectmp)
11191165
ftmp = norm2(fvectmp)
11201166

@@ -1183,6 +1229,7 @@ subroutine exact_linesearch(me,xold,p,x,f,fvec,fjac,fjac_sparse)
11831229
if (me%verbose) write(me%iunit,'(1P,*(A,1X,E16.6))') ' alpha_min = ', alpha_min
11841230

11851231
x = xold + p * alpha_min
1232+
call me%adjust_x_for_bounds(x)
11861233
if (all(x==xnew)) then
11871234
! already computed in the func
11881235
else
@@ -1198,6 +1245,7 @@ real(wp) function func_for_fmin(alpha)
11981245
real(wp),intent(in) :: alpha !! indep variable
11991246

12001247
xnew = xold + p * alpha
1248+
call me%adjust_x_for_bounds(xnew)
12011249
call me%func(xnew,fvec)
12021250
func_for_fmin = norm2(fvec) ! return result
12031251

@@ -1260,6 +1308,7 @@ subroutine fixed_point_linesearch(me,xold,p,x,f,fvec,fjac,fjac_sparse)
12601308
do i = 1, n_points
12611309

12621310
x_tmp = xold + p * alphas_to_try(i)
1311+
call me%adjust_x_for_bounds(x_tmp)
12631312

12641313
! evaluate the function at tthis point:
12651314
call me%func(x_tmp,fvec_tmp)

0 commit comments

Comments
 (0)