7 module subroutine ns_solve(this, fcn, x, fvec, ib, err)
9 class(newton_solver),
intent(inout) :: this
10 class(vecfcn_helper),
intent(in) :: fcn
11 real(real64),
intent(inout),
dimension(:) :: x
12 real(real64),
intent(out),
dimension(:) :: fvec
13 type(iteration_behavior),
optional :: ib
14 class(errors),
intent(inout),
optional,
target :: err
17 real(real64),
parameter :: zero = 0.0d0
18 real(real64),
parameter :: half = 0.5d0
19 real(real64),
parameter :: one = 1.0d0
20 real(real64),
parameter :: mintol = 1.0d-12
21 real(real64),
parameter :: factor = 1.0d2
24 logical :: check, xcnvrg, fcnvrg, gcnvrg
25 integer(int32) :: i, neqn, nvar, lwork, flag, neval, iter, maxeval, njac
26 integer(int32),
allocatable,
dimension(:) :: ipvt
27 real(real64),
allocatable,
dimension(:) :: dir, grad, xold, work
28 real(real64),
allocatable,
dimension(:,:) :: jac
29 real(real64) :: ftol, xtol, gtol, f, fold, stpmax, xnorm, fnorm, temp, test
30 type(iteration_behavior) :: lib
31 class(errors),
pointer :: errmgr
32 type(errors),
target :: deferr
33 character(len = 256) :: errmsg
34 class(line_search),
allocatable :: ls
40 neqn = fcn%get_equation_count()
41 nvar = fcn%get_variable_count()
45 ftol = this%get_fcn_tolerance()
46 xtol = this%get_var_tolerance()
47 gtol = this%get_gradient_tolerance()
48 maxeval = this%get_max_fcn_evals()
52 ib%jacobian_count = njac
54 ib%converge_on_fcn = fcnvrg
55 ib%converge_on_chng = xcnvrg
56 ib%converge_on_zero_diff = gcnvrg
58 if (
present(err))
then
63 if (this%get_use_line_search())
then
64 if (.not.this%is_line_search_defined()) &
65 call this%set_default_line_search()
66 call this%get_line_search(ls)
70 if (.not.fcn%is_fcn_defined())
then
72 call errmgr%report_error(
"ns_solve", &
73 "No function has been defined.", &
74 nl_invalid_operation_error)
77 if (nvar /= neqn)
then
79 write(errmsg, 100)
"The number of equations (", neqn, &
80 ") does not match the number of unknowns (", nvar,
")."
81 call errmgr%report_error(
"ns_solve", trim(errmsg), &
82 nl_invalid_input_error)
86 if (
size(x) /= nvar)
then
88 else if (
size(fvec) /= neqn)
then
93 write(errmsg, 101)
"Input number ", flag, &
94 " is not sized correctly."
95 call errmgr%report_error(
"ns_solve", trim(errmsg), &
101 allocate(ipvt(nvar), stat = flag)
102 if (flag == 0)
allocate(dir(nvar), stat = flag)
103 if (flag == 0)
allocate(grad(nvar), stat = flag)
104 if (flag == 0)
allocate(xold(nvar), stat = flag)
105 if (flag == 0)
allocate(jac(nvar, neqn), stat = flag)
107 call fcn%jacobian(x, jac, fv = fvec, olwork = lwork)
108 allocate(work(lwork), stat = flag)
112 call errmgr%report_error(
"ns_solve", &
113 "Insufficient memory available.", nl_out_of_memory_error)
118 call fcn%fcn(x, fvec)
119 f = half * dot_product(fvec, fvec)
123 test = max(abs(fvec(i)), test)
125 if (test < ftol)
then
131 if (.not.fcnvrg)
then
133 stpmax = factor * max(norm2(x), real(nvar, real64))
141 call fcn%jacobian(x, jac, fvec, work)
146 grad(i) = dot_product(jac(:,i), fvec)
150 call lu_factor(jac, ipvt, errmgr)
151 if (errmgr%has_warning_occurred())
then
167 call solve_lu(jac, ipvt, dir)
170 if (this%get_use_line_search())
then
172 temp = dot_product(dir, dir)
173 if (temp > stpmax) dir = dir * (stpmax / temp)
176 call limit_search_vector(dir, stpmax)
177 call ls%search(fcn, xold, grad, dir, x, fvec, &
178 fold, f, lib, errmgr)
179 neval = neval + lib%fcn_count
183 call fcn%fcn(x, fvec)
184 f = half * dot_product(fvec, fvec)
189 call test_convergence(x, xold, fvec, grad, .true., xtol, &
190 ftol, gtol, check, xcnvrg, fcnvrg, gcnvrg, xnorm, fnorm)
194 else if (gcnvrg)
then
198 "It appears the solution has settled to " // &
199 "a point where the slope of the gradient " // &
200 "is effectively zero. " // new_line(
'c') // &
201 "Function evaluations performed: ", neval, &
202 "." // new_line(
'c') // &
203 "Change in Variable: ", xnorm, &
204 new_line(
'c') //
"Residual: ", fnorm
205 call errmgr%report_warning(
"ns_solve", trim(errmsg), &
206 nl_spurious_convergence_error)
210 if (this%get_print_status())
then
211 call print_status(iter, neval, njac, xnorm, fnorm)
215 if (neval >= maxeval)
then
223 if (
present(ib))
then
226 ib%jacobian_count = njac
227 ib%gradient_count = 0
228 ib%converge_on_fcn = fcnvrg
229 ib%converge_on_chng = xcnvrg
230 ib%converge_on_zero_diff = gcnvrg
235 write(errmsg, 102)
"The algorithm failed to " // &
236 "converge. Function evaluations performed: ", neval, &
237 "." // new_line(
'c') //
"Change in Variable: ", xnorm, &
238 new_line(
'c') //
"Residual: ", fnorm
239 call errmgr%report_error(
"ns_solve", trim(errmsg), &
240 nl_convergence_error)
244100
format(a, i0, a, i0, a)
246102
format(a, i0, a, e10.3, a, e10.3)