nonlin 1.5.2
A library that provides routines to compute the solutions to systems of nonlinear equations.
Loading...
Searching...
No Matches
nonlin_vecfcn_helper.f90
1! nonlin_vecfcn_helper.f90
2
3submodule(nonlin_core) nonlin_vecfcn_helper
4 implicit none
5contains
6! ------------------------------------------------------------------------------
7 module subroutine vfh_set_fcn(this, fcn, nfcn, nvar)
8 class(vecfcn_helper), intent(inout) :: this
9 procedure(vecfcn), intent(in), pointer :: fcn
10 integer(int32), intent(in) :: nfcn, nvar
11 this%m_fcn => fcn
12 this%m_nfcn = nfcn
13 this%m_nvar = nvar
14 end subroutine
15
16! ------------------------------------------------------------------------------
17 module subroutine vfh_set_jac(this, jac)
18 class(vecfcn_helper), intent(inout) :: this
19 procedure(jacobianfcn), intent(in), pointer :: jac
20 this%m_jac => jac
21 end subroutine
22
23! ------------------------------------------------------------------------------
24 module function vfh_is_fcn_defined(this) result(x)
25 class(vecfcn_helper), intent(in) :: this
26 logical :: x
27 x = associated(this%m_fcn)
28 end function
29
30! ------------------------------------------------------------------------------
31 module function vfh_is_jac_defined(this) result(x)
32 class(vecfcn_helper), intent(in) :: this
33 logical :: x
34 x = associated(this%m_jac)
35 end function
36
37! ------------------------------------------------------------------------------
38 module subroutine vfh_fcn(this, x, f)
39 class(vecfcn_helper), intent(in) :: this
40 real(real64), intent(in), dimension(:) :: x
41 real(real64), intent(out), dimension(:) :: f
42 if (this%is_fcn_defined()) then
43 call this%m_fcn(x, f)
44 end if
45 end subroutine
46
47! ------------------------------------------------------------------------------
48 module subroutine vfh_jac_fcn(this, x, jac, fv, work, olwork, err)
49 ! Arguments
50 class(vecfcn_helper), intent(in) :: this
51 real(real64), intent(inout), dimension(:) :: x
52 real(real64), intent(out), dimension(:,:) :: jac
53 real(real64), intent(in), dimension(:), optional, target :: fv
54 real(real64), intent(out), dimension(:), optional, target :: work
55 integer(int32), intent(out), optional :: olwork, err
56
57 ! Parameters
58 real(real64), parameter :: zero = 0.0d0
59
60 ! Local Variables
61 integer(int32) :: j, m, n, lwork, flag
62 real(real64) :: eps, epsmch, h, temp
63 real(real64), pointer, dimension(:) :: fptr, f1ptr
64 real(real64), allocatable, target, dimension(:) :: wrk
65
66 ! Initialization
67 if (present(err)) err = 0
68 ! m = this%m_nfcn
69 ! n = this%m_nvar
70 m = this%get_equation_count()
71 n = this%get_variable_count()
72
73 ! Input Checking
74 flag = 0
75 if (size(x) /= n) then
76 flag = 2
77 else if (size(jac, 1) /= m .or. size(jac, 2) /= n) then
78 flag = 3
79 end if
80 if (flag /= 0) then
81 ! ERROR: Incorrectly sized input arrays
82 if (present(err)) err = flag
83 return
84 end if
85
86 ! Process
87 if (.not.this%is_fcn_defined()) return
88 if (associated(this%m_jac)) then
89 ! Workspace Query
90 if (present(olwork)) then
91 olwork = 0
92 return
93 end if
94
95 ! Call the user-defined Jacobian routine
96 call this%m_jac(x, jac)
97 else
98 ! Compute the Jacobian via finite differences
99 if (present(fv)) then
100 lwork = m
101 else
102 lwork = 2 * m
103 end if
104
105 if (present(olwork)) then
106 ! The user is just making a workspace query. Simply return the
107 ! workspace length, and exit the routine.
108 olwork = lwork
109 return
110 end if
111
112 ! Local Memory Allocation
113 if (present(work)) then
114 if (size(work) < lwork) then
115 ! ERROR: Workspace is too small
116 if (present(err)) err = 5
117 return
118 end if
119 f1ptr => work(1:m)
120 if (present(fv)) then
121 if (size(fv) < m) then
122 ! ERROR: Function vector too small
123 if (present(err)) err = 4
124 return
125 end if
126 fptr => fv(1:m)
127 else
128 fptr => work(m+1:2*m)
129 call this%fcn(x, fptr)
130 end if
131 else
132 allocate(wrk(lwork), stat = flag)
133 if (flag /= 0) then
134 ! ERROR: Memory issues
135 if (present(err)) err = -1
136 return
137 end if
138 f1ptr => wrk(1:m)
139 if (present(fv)) then
140 fptr => fv(1:m)
141 else
142 fptr => wrk(m+1:2*m)
143 call this%fcn(x, fptr)
144 end if
145 end if
146
147 ! Establish step size factors
148 epsmch = epsilon(epsmch)
149 eps = sqrt(epsmch)
150
151 ! Compute the derivatives via finite differences
152 do j = 1, n
153 temp = x(j)
154 h = eps * abs(temp)
155 if (h == zero) h = eps
156 x(j) = temp + h
157 call this%fcn(x, f1ptr)
158 x(j) = temp
159 jac(:,j) = (f1ptr - fptr) / h
160 end do
161 end if
162 end subroutine
163
164! ------------------------------------------------------------------------------
165 module function vfh_get_nfcn(this) result(n)
166 class(vecfcn_helper), intent(in) :: this
167 integer(int32) :: n
168 n = this%m_nfcn
169 end function
170
171! ------------------------------------------------------------------------------
172 module function vfh_get_nvar(this) result(n)
173 class(vecfcn_helper), intent(in) :: this
174 integer(int32) :: n
175 n = this%m_nvar
176 end function
177end submodule
nonlin_core