dvjac is called by dvnlsd to compute and process the matrix
p = i - h*rl1*j
, where j is an approximation to the jacobian.
here j is computed by the user-supplied routine jac
if
miter = 1 or 4, or by finite differencing if miter = 2, 3, or 5.
if miter = 3, a diagonal approximation to j is used.
if jsv = -1, j is computed from scratch in all cases.
if jsv = 1 and miter = 1, 2, 4, or 5, and if the saved value of j is
considered acceptable, then p is constructed from the saved j.
j is stored in wm and replaced by p. if miter /= 3, p is then
subjected to lu decomposition in preparation for later solution
of linear systems with p as coefficient matrix. this is done
by dgefa if miter = 1 or 2, and by dgbfa if miter = 4 or 5.
Type | Intent | Optional | Attributes | Name | ||
---|---|---|---|---|---|---|
class(dvode_t), | intent(inout) | :: | me | |||
real(kind=wp), | intent(inout) | :: | y(*) |
vector containing predicted values on entry. |
||
real(kind=wp), | intent(in) | :: | yh(ldyh,*) |
the nordsieck array, an |
||
integer, | intent(in) | :: | ldyh |
a constant >= n, the first dimension of |
||
real(kind=wp), | intent(in) | :: | ewt(*) |
an error weight vector of length |
||
real(kind=wp), | intent(in) | :: | ftem(*) | |||
real(kind=wp), | intent(in) | :: | savf(*) |
array containing f evaluated at predicted y. |
||
real(kind=wp), | intent(inout) | :: | wm(*) |
real work space for matrices. in the output, it contains the inverse diagonal matrix if miter = 3 and the lu decomposition of p if miter is 1, 2 , 4, or 5. storage of matrix elements starts at wm(3). storage of the saved jacobian starts at wm(locjs). wm also contains the following matrix-related data: wm(1) = sqrt(uround), used in numerical jacobian step. wm(2) = h*rl1, saved for later use if miter = 3. |
||
integer, | intent(inout) | :: | iwm(*) |
integer work space containing pivot information, starting at iwm(31), if miter is 1, 2, 4, or 5. iwm also contains band parameters ml = iwm(1) and mu = iwm(2) if miter is 4 or 5. |
||
integer, | intent(out) | :: | ierpj |
output error flag, = 0 if no trouble, 1 if the p matrix is found to be singular. |
subroutine dvjac(me,y,yh,ldyh,ewt,ftem,savf,wm,iwm,ierpj) class(dvode_t),intent(inout) :: me real(wp),intent(inout) :: y(*) !! vector containing predicted values on entry. integer,intent(in) :: ldyh !! a constant >= n, the first dimension of `yh`. real(wp),intent(in) :: yh(ldyh,*) !! the nordsieck array, an `ldyh` by `lmax` array. real(wp),intent(in) :: ewt(*) !! an error weight vector of length `n`. real(wp),intent(in) :: ftem(*) real(wp),intent(in) :: savf(*) !! array containing f evaluated at predicted y. real(wp),intent(inout) :: wm(*) !! real work space for matrices. in the output, it contains !! the inverse diagonal matrix if miter = 3 and the lu !! decomposition of p if miter is 1, 2 , 4, or 5. !! storage of matrix elements starts at wm(3). !! storage of the saved jacobian starts at wm(locjs). !! wm also contains the following matrix-related data: !! wm(1) = sqrt(uround), used in numerical jacobian step. !! wm(2) = h*rl1, saved for later use if miter = 3. integer,intent(inout) :: iwm(*) !! integer work space containing pivot information, !! starting at iwm(31), if miter is 1, 2, 4, or 5. !! iwm also contains band parameters ml = iwm(1) and !! mu = iwm(2) if miter is 4 or 5. integer,intent(out) :: ierpj !! output error flag, = 0 if no trouble, 1 if the p !! matrix is found to be singular. real(wp) :: con , di , fac , hrl1 , r , r0 , & srur , yi , yj , yjj integer :: i , i1 , i2 , ier , ii , j , j1 , jj , jok , lenp , mba , & mband , meb1 , meband , ml , ml3 , mu , np1 real(wp),parameter :: one = 1.0_wp real(wp),parameter :: thou = 1000.0_wp real(wp),parameter :: pt1 = 0.1_wp ierpj = 0 hrl1 = me%dat%h*me%dat%rl1 ! rl1 = 1/el(2) ! see whether j should be evaluated (jok = -1) or not (jok = 1). ------- jok = me%dat%jsv if ( me%dat%jsv==1 ) then if ( me%dat%nst==0 .or. me%dat%nst>me%dat%nslj+me%dat%msbj ) jok = -1 if ( me%dat%icf==1 .and. me%dat%drc<me%dat%ccmxj ) jok = -1 if ( me%dat%icf==2 ) jok = -1 endif ! end of setting jok. -------------------------------------------------- if ( jok==-1 .and. me%dat%miter==1 ) then ! if jok = -1 and miter = 1, call me%jac to evaluate jacobian. ------------ me%dat%nje = me%dat%nje + 1 me%dat%nslj = me%dat%nst me%dat%jcur = 1 lenp = me%dat%n*me%dat%n do i = 1 , lenp wm(i+2) = zero enddo call me%jac(me%dat%n,me%dat%tn,y(1:me%dat%n),0,0,wm(3),me%dat%n) if ( me%dat%jsv==1 ) call dcopy(lenp,wm(3),1,wm(me%dat%locjs),1) endif if ( jok==-1 .and. me%dat%miter==2 ) then ! if miter = 2, make n calls to f to approximate the jacobian. --------- me%dat%nje = me%dat%nje + 1 me%dat%nslj = me%dat%nst me%dat%jcur = 1 fac = me%dvnorm(me%dat%n,savf(1:me%dat%n),ewt(1:me%dat%n)) r0 = thou*abs(me%dat%h)*me%dat%uround*real(me%dat%n,wp)*fac if ( r0==zero ) r0 = one srur = wm(1) j1 = 2 do j = 1 , me%dat%n yj = y(j) r = max(srur*abs(yj),r0/ewt(j)) y(j) = y(j) + r fac = one/r call me%f(me%dat%n,me%dat%tn,y(1:me%dat%n),ftem(1:me%dat%n)) do i = 1 , me%dat%n wm(i+j1) = (ftem(i)-savf(i))*fac enddo y(j) = yj j1 = j1 + me%dat%n enddo me%dat%nfe = me%dat%nfe + me%dat%n lenp = me%dat%n*me%dat%n if ( me%dat%jsv==1 ) call dcopy(lenp,wm(3),1,wm(me%dat%locjs),1) endif if ( jok==1 .and. (me%dat%miter==1 .or. me%dat%miter==2) ) then me%dat%jcur = 0 lenp = me%dat%n*me%dat%n call dcopy(lenp,wm(me%dat%locjs),1,wm(3),1) endif if ( me%dat%miter==1 .or. me%dat%miter==2 ) then ! multiply jacobian by scalar, add identity, and do lu decomposition. -- con = -hrl1 call dscal(lenp,con,wm(3),1) j = 3 np1 = me%dat%n + 1 do i = 1 , me%dat%n wm(j) = wm(j) + one j = j + np1 enddo me%dat%nlu = me%dat%nlu + 1 call dgefa(wm(3),me%dat%n,me%dat%n,iwm(31),ier) if ( ier/=0 ) ierpj = 1 return endif ! end of code block for miter = 1 or 2. -------------------------------- if ( me%dat%miter==3 ) then ! if miter = 3, construct a diagonal approximation to j and p. --------- me%dat%nje = me%dat%nje + 1 me%dat%jcur = 1 wm(2) = hrl1 r = me%dat%rl1*pt1 do i = 1 , me%dat%n y(i) = y(i) + r*(me%dat%h*savf(i)-yh(i,2)) enddo call me%f(me%dat%n,me%dat%tn,y(1:me%dat%n),wm(3)) me%dat%nfe = me%dat%nfe + 1 do i = 1 , me%dat%n r0 = me%dat%h*savf(i) - yh(i,2) di = pt1*r0 - me%dat%h*(wm(i+2)-savf(i)) wm(i+2) = one if ( abs(r0)>=me%dat%uround/ewt(i) ) then if ( abs(di)==zero ) then ierpj = 1 return end if wm(i+2) = pt1*r0/di endif enddo return endif ! end of code block for miter = 3. ------------------------------------- ! set constants for miter = 4 or 5. ------------------------------------ ml = iwm(1) mu = iwm(2) ml3 = ml + 3 mband = ml + mu + 1 meband = mband + ml lenp = meband*me%dat%n if ( jok==-1 .and. me%dat%miter==4 ) then ! if jok = -1 and miter = 4, call me%jac to evaluate jacobian. ------------ me%dat%nje = me%dat%nje + 1 me%dat%nslj = me%dat%nst me%dat%jcur = 1 do i = 1 , lenp wm(i+2) = zero enddo call me%jac(me%dat%n,me%dat%tn,y(1:me%dat%n),ml,mu,wm(ml3),meband) if ( me%dat%jsv==1 ) call dacopy(mband,me%dat%n,wm(ml3),meband,wm(me%dat%locjs),mband) endif if ( jok==-1 .and. me%dat%miter==5 ) then ! if miter = 5, make ml+mu+1 calls to f to approximate the jacobian. --- me%dat%nje = me%dat%nje + 1 me%dat%nslj = me%dat%nst me%dat%jcur = 1 mba = min(mband,me%dat%n) meb1 = meband - 1 srur = wm(1) fac = me%dvnorm(me%dat%n,savf(1:me%dat%n),ewt(1:me%dat%n)) r0 = thou*abs(me%dat%h)*me%dat%uround*real(me%dat%n,wp)*fac if ( r0==zero ) r0 = one do j = 1 , mba do i = j , me%dat%n , mband yi = y(i) r = max(srur*abs(yi),r0/ewt(i)) y(i) = y(i) + r enddo call me%f(me%dat%n,me%dat%tn,y(1:me%dat%n),ftem(1:me%dat%n)) do jj = j , me%dat%n , mband y(jj) = yh(jj,1) yjj = y(jj) r = max(srur*abs(yjj),r0/ewt(jj)) fac = one/r i1 = max(jj-mu,1) i2 = min(jj+ml,me%dat%n) ii = jj*meb1 - ml + 2 do i = i1 , i2 wm(ii+i) = (ftem(i)-savf(i))*fac enddo enddo enddo me%dat%nfe = me%dat%nfe + mba if ( me%dat%jsv==1 ) call dacopy(mband,me%dat%n,wm(ml3),meband,wm(me%dat%locjs),mband) endif if ( jok==1 ) then me%dat%jcur = 0 call dacopy(mband,me%dat%n,wm(me%dat%locjs),mband,wm(ml3),meband) endif ! multiply jacobian by scalar, add identity, and do lu decomposition. con = -hrl1 call dscal(lenp,con,wm(3),1) ii = mband + 2 do i = 1 , me%dat%n wm(ii) = wm(ii) + one ii = ii + meband enddo me%dat%nlu = me%dat%nlu + 1 call dgbfa(wm(3),meband,me%dat%n,ml,mu,iwm(31),ier) if ( ier/=0 ) ierpj = 1 ! end of code block for miter = 4 or 5. -------------------------------- end subroutine dvjac