NAG Library Routine Document

d02nnf  (ivp_stiff_imp_revcom)

 Contents

    1  Purpose
    7  Accuracy

1
Purpose

d02nnf is a reverse communication routine for integrating stiff systems of implicit ordinary differential equations coupled with algebraic equations.

2
Specification

Fortran Interface
Integer, Intent (In):: neq, ldysav, itol, sdysav, nwkjac, njcpvt, itask, itrace
Integer, Intent (Inout):: inform(23), jacpvt(njcpvt), imon, inln, ires, irevcm, ifail
Real (Kind=nag_wp), Intent (In):: rtol(*), atol(*)
Real (Kind=nag_wp), Intent (Inout):: t, tout, y(neq), ydot(neq), rwork(50+4*neq), ysav(ldysav,sdysav), wkjac(nwkjac)
Logical, Intent (Inout):: lderiv(2)
C Header Interface
#include nagmk26.h
void  d02nnf_ ( const Integer *neq, const Integer *ldysav, double *t, double *tout, double y[], double ydot[], double rwork[], const double rtol[], const double atol[], const Integer *itol, Integer inform[], double ysav[], const Integer *sdysav, double wkjac[], const Integer *nwkjac, Integer jacpvt[], const Integer *njcpvt, Integer *imon, Integer *inln, Integer *ires, Integer *irevcm, logical lderiv[], const Integer *itask, const Integer *itrace, Integer *ifail)

3
Description

d02nnf is a general purpose routine for integrating the initial value problem for a stiff system of implicit ordinary differential equations coupled with algebraic equations, written in the form
At,yy=gt,y.  
An outline of a typical calling program is given below:
!     Declarations 

      Call linear algebra setup routine 
      Call integrator setup routine 
      irevcm=0 
 1000 Call d02nnf(neq, neqmax, t, tout, y, ydot, rwork, rtol, 
       atol, itol, inform, ysave, ny2dim, wkjac, nwkjac, jacpvt, 
       njcpvt, imon, inln, ires, irevcm, lderiv, 
       itask, itrace, ifail)

      If (irevcm.gt.0) Then 
        If (irevcm.gt.7 .and. irevcm.lt.11) Then 
          If (irevcm.eq.8) Then 
            supply the Jacobian matrix                        (i) 
          Else If (irevcm.eq.9) Then 
            perform monitoring tasks requested by the user   (ii) 
          Else If (irevcm.eq.10) Then 
            indicates an unsuccessful step 
          End If 
        Else 
          evaluate the residual                             (iii) 
        Endif 
        Go To 1000 
      End If 

!     post processing (optional linear algebra diagnostic call 
!     (sparse case only), optional integrator diagnostic call) 

      Stop 
      End
There are three major operations that may be required of the calling subroutine on an intermediate return (irevcm0) from d02nnf; these are denoted (i), (ii) and (iii).
The following sections describe in greater detail exactly what is required of each of these operations.
(i) Supply the Jacobian matrix
You need only provide this facility if the argument jceval='A' (or jceval='F' if using sparse matrix linear algebra) in a call to the linear algebra setup routine (see jceval in d02nuf). If the Jacobian matrix is to be evaluated numerically by the integrator, then the remainder of section (i) can be ignored.
We must define the system of nonlinear equations which is solved internally by the integrator. The time derivative, y, has the form
y=y-z/hd,  
where h is the current step size and d is an argument that depends on the integration method in use. The vector y is the current solution and the vector z depends on information from previous time steps. This means that d dy ​ ​ = hd ddy ​ ​ .
The system of nonlinear equations that is solved has the form
At,yy-gt,y=0  
but is solved in the form
ft,y = 0 ,  
where f is the function defined by
ft,y = hd A t,y y-z / hd - gt,y .  
It is the Jacobian matrix r y  that you must supply as follows:
fi yj = aijt,y+hd yj k=1neqaikt,yyk-git,y ,  
where t, h and d are located in rwork19, rwork16 and rwork20 respectively and the arrays y and ydot contain the current solution and time derivatives respectively. Only the nonzero elements of the Jacobian need be set, since the locations where it is to be stored are preset to zero.
Hereafter in this document this operation will be referred to as jac.
(ii) Perform tasks requested by you
This operation is essentially a monitoring function and additionally provides the opportunity of changing the current values of y, ydot, hnext (the step size that the integrator proposes to take on the next step), hmin (the minimum step size to be taken on the next step), and hmax (the maximum step size to be taken on the next step). The scaled local error at the end of a time step may be obtained by calling the real function d02zaf as follows:
      ifail = 1
      errloc = d02zaf(neq,rowk(51+neqmax),rwork(51),ifail)
!     CHECK IFAIL BEFORE PROCEEDING
The following gives details of the location within the array rwork of variables that may be of interest to you:
Variable Specification Location
tcurr the current value of the independent variable rwork19
hlast last step size successfully used by the integrator rwork15
hnext step size that the integrator proposes to take on the next step rwork16
hmin minimum step size to be taken on the next step rwork17
hmax maximum step size to be taken on the next step rwork18
nqu the order of the integrator used on the last step rwork10
You are advised to consult the description of monitr in d02ngf for details on what optional input can be made.
If either y or ydot are changed, then imon must be set to 2 before return to d02nnf. If either of the values hmin or hmax are changed, then imon must be set 3 before return to d02nnf. If hnext is changed, then imon must be set to 4 before return to d02nnf.
In addition you can force d02nnf to evaluate the residual vector
At,yy-gt,y  
by setting imon=0 and inln=3 and then returning to d02nnf; on return to this monitoring operation the residual vector will be stored in rwork50+2×neq+i, for i=1,2,,neq.
Hereafter in this document this operation will be referred to as monitr.
(iii) Evaluate the residual
This operation must evaluate the residual
-r = gt,y - At,y y (1)
in one case and the reduced residual
-r^ = -At,y y (2)
in another, where t is located in rwork19. The form of the residual that is returned is determined by the value of ires returned by d02nnf. If ires=-1, then the residual defined by equation (2) above must be returned; if ires=1, then the residual returned by equation (1) above must be returned.
Hereafter in this document this operation will be referred to as resid.

4
References

See the D02M–N Sub-chapter Introduction.

5
Arguments

Note: this routine uses reverse communication. Its use involves an initial entry, intermediate exits and re-entries, and a final exit, as indicated by the argument irevcm. Between intermediate exits and re-entries, all arguments other than ydot, rwork, wkjac, imon, inln and ires must remain unchanged.
1:     neq – IntegerInput
On initial entry: the number of equations to be solved.
Constraint: neq1.
2:     ldysav – IntegerInput
On initial entry: a bound on the maximum number of equations to be solved during the integration.
Constraint: ldysavneq.
3:     t – Real (Kind=nag_wp)Input/Output
On initial entry: t, the value of the independent variable. The input value of t is used only on the first call as the initial point of the integration.
On final exit: the value at which the computed solution y is returned (usually at tout).
4:     tout – Real (Kind=nag_wp)Input/Output
On initial entry: the next value of t at which a computed solution is desired. For the initial t, the input value of tout is used to determine the direction of integration. Integration is permitted in either direction (see also itask).
Constraint: toutt.
On exit: is unaltered unless itask=6 and lderiv2=.TRUE. on entry (see also itask and lderiv) in which case tout will be set to the result of taking a small step at the start of the integration.
5:     yneq – Real (Kind=nag_wp) arrayInput/Output
On initial entry: the values of the dependent variables (solution). On the first call the first neq elements of y must contain the vector of initial values.
On final exit: the computed solution vector evaluated at t (usually t=tout).
6:     ydotneq – Real (Kind=nag_wp) arrayInput/Output
On initial entry: if lderiv1=.TRUE., ydot must contain approximations to the time derivatives y of the vector y. If lderiv1=.FALSE., ydot need not be set on entry.
On final exit: contains the time derivatives y of the vector y at the last integration point.
7:     rwork50+4×neq – Real (Kind=nag_wp) arrayCommunication Array
On initial entry: must be the same array as used by one of the method setup routines d02mvf, d02nvf or d02nwf, and by one of the storage setup routines d02nsf, d02ntf or d02nuf. The contents of rwork must not be changed between any call to a setup routine and the first call to d02nnf.
On intermediate re-entry: must contain residual evaluations as described under the argument irevcm.
On intermediate exit: contains information for jac, resid and monitr operations as described under Section 3 and the argument irevcm.
8:     rtol* – Real (Kind=nag_wp) arrayInput
Note: the dimension of the array rtol must be at least 1 if itol=1 or 2, and at least neq otherwise.
On initial entry: the relative local error tolerance.
Constraint: rtoli0.0 for all relevant i (see itol).
9:     atol* – Real (Kind=nag_wp) arrayInput
Note: the dimension of the array atol must be at least 1 if itol=1 or 3, and at least neq otherwise.
On initial entry: the absolute local error tolerance.
Constraint: atoli0.0 for all relevant i (see itol).
10:   itol – IntegerInput
On initial entry: a value to indicate the form of the local error test. itol indicates to d02nnf whether to interpret either or both of rtol or atol as a vector or a scalar. The error test to be satisfied is ei/wi<1.0, where wi is defined as follows:
itol rtol atol wi
1 scalar scalar rtol1×yi+atol1
2 scalar vector rtol1×yi+atoli
3 vector scalar rtoli×yi+atol1
4 vector vector rtoli×yi+atoli
ei is an estimate of the local error in yi, computed internally, and the choice of norm to be used is defined by a previous call to an integrator setup routine.
Constraint: itol=1, 2, 3 or 4.
11:   inform23 – Integer arrayCommunication Array
12:   ysavldysavsdysav – Real (Kind=nag_wp) arrayCommunication Array
13:   sdysav – IntegerInput
On initial entry: the second dimension of the array ysav as declared in the (sub)program from which d02nnf is called. An appropriate value for sdysav is described in the specifications of the integrator setup routines d02mvf, d02nvf and d02nwf. This value must be the same as that supplied to the integrator setup routine.
14:   wkjacnwkjac – Real (Kind=nag_wp) arrayInput/Output
On intermediate re-entry: elements of the Jacobian as defined under the description of irevcm. If a numerical Jacobian was requested then wkjac is used for workspace.
On intermediate exit: the Jacobian is overwritten.
15:   nwkjac – IntegerInput
On initial entry: the dimension of the array wkjac as declared in the (sub)program from which d02nnf is called. The actual size depends on the linear algebra method used. An appropriate value for nwkjac is described in the specifications of the linear algebra setup routines d02nsf, d02ntf and d02nuf for full, banded and sparse matrix linear algebra respectively. This value must be the same as that supplied to the linear algebra setup routine.
16:   jacpvtnjcpvt – Integer arrayCommunication Array
17:   njcpvt – IntegerInput
On initial entry: the dimension of the array jacpvt as declared in the (sub)program from which d02nnf is called. The actual size depends on the linear algebra method used. An appropriate value for njcpvt is described in the specifications of the linear algebra setup routines d02ntf and d02nuf for banded and sparse matrix linear algebra respectively. This value must be the same as that supplied to the linear algebra setup routine. When full matrix linear algebra is chosen, the array jacpvt is not used and hence njcpvt should be set to 1.
18:   imon – IntegerInput/Output
On intermediate exit: used to pass information between d02nnf and the monitr operation (see Section 3). With irevcm=9, imon contains a flag indicating under what circumstances the return from d02nnf occurred:
imon=-2
Exit from d02nnf after ires=4 (set in the resid operation (see Section 3) caused an early termination (this facility could be used to locate discontinuities).
imon=-1
The current step failed repeatedly.
imon=0
Exit from d02nnf after a call to the internal nonlinear equation solver.
imon=1
The current step was successful.
On intermediate re-entry: may be reset to determine subsequent action in d02nnf.
imon=-2
Integration is to be halted. A return will be made from d02nnf to the calling (sub)program with ifail=12.
imon=-1
Allow d02nnf to continue with its own internal strategy. The integrator will try up to three restarts unless imon-1.
imon=0
Return to the internal nonlinear equation solver, where the action taken is determined by the value of inln.
imon=1
Normal exit to d02nnf to continue integration.
imon=2
Restart the integration at the current time point. The integrator will restart from order 1 when this option is used. The internal initialization module solves for new values of y and y by using the values supplied in y and ydot by the monitr operation (see Section 3) as initial estimates.
imon=3
Try to continue with the same step size and order as was to be used before entering the monitr operation (see Section 3). hmin and hmax may be altered if desired.
imon=4
Continue the integration but using a new value of hnext and possibly new values of hmin and hmax.
19:   inln – IntegerInput/Output
On intermediate re-entry: with imon=0 and irevcm=9, inln specifies the action to be taken by the internal nonlinear equation solver. By setting inln=3 and returning to d02nnf, the residual vector is evaluated and placed in rwork50+2×neq+i, for i=1,2,,neq and then the monitr operation (see Section 3) is invoked again. At present this is the only option available: inln must not be set to any other value.
On intermediate exit: contains a flag indicating the action to be taken, if any, by the internal nonlinear equation solver.
20:   ires – IntegerInput/Output
On intermediate exit: with irevcm=1, 2, 3, 4, 5, 6, 7 or 11, ires specifies the form of the residual to be returned by the resid operation (see Section 3).
If ires=1, -r=gt,y-At,yy must be returned.
If ires=-1, -r^=-At,yy must be returned.
On intermediate re-entry: should be unchanged unless one of the following actions is required of d02nnf in which case ires should be set accordingly.
ires=2
Indicates to d02nnf that control should be passed back immediately to the calling (sub)program with the error indicator set to ifail=11.
ires=3
Indicates to d02nnf that an error condition has occurred in the solution vector, its time derivative or in the value of t. The integrator will use a smaller time step to try to avoid this condition. If this is not possible d02nnf returns to the calling (sub)program with the error indicator set to ifail=7.
ires=4
Indicates to d02nnf to stop its current operation and to enter the monitr operation (see Section 3) immediately.
21:   irevcm – IntegerInput/Output
On initial entry: must contain 0.
On intermediate re-entry: should remain unchanged.
On intermediate exit: indicates what action you must take before re-entering d02nnf. The possible exit values of irevcm are 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or 11 which should be interpreted as follows:
irevcm=1, 2, 3, 4, 5, 6, 7 or 11
Indicates that a resid operation (see Section 3) is required: you must supply the residual of the system. For each of these values of irevcm, yi is located in yi, for i=1,2,,neq.
For irevcm=1, 3, 6 or 11, yi is located in ydoti and ri should be stored in rwork50+2×neq+i, for i=1,2,,neq.
For irevcm=2, yi is located in rwork50+neq+i and ri should be stored in rwork50+2×neq+i, for i=1,2,,neq.
For irevcm=4 or 7, yi is located in ydoti and ri should be stored in rwork50+neq+i, for i=1,2,,neq.
For irevcm=5, yi is located in rwork50+2×neq+i and ri should be stored in ydoti, for i=1,2,,neq.
irevcm=8
Indicates that a jac operation (see Section 3) is required: you must supply the Jacobian matrix.
If full matrix linear algebra is being used, the i,jth element of the Jacobian must be stored in wkjacj-1×neq+i.
If banded matrix linear algebra is being used, the i,jth element of the Jacobian
must be stored in wkjaci-1×mB+k, where mB=mL+mU+1 and k=minmL-i+1,0+j; here mL and mU are the number of subdiagonals and superdiagonals, respectively, in the band.
If sparse matrix linear algebra is being used, d02nrf must be called to determine which column of the Jacobian is required and where it should be stored.
Call d02nrf(j, iplace, inform)
will return in j the number of the column of the Jacobian that is required and will set iplace=1 or 2 (see d02nrf). If iplace=1, you must store the nonzero element i,j of the Jacobian in rwork50+2×neq+i; otherwise it must be stored in rwork50+neq+i.
irevcm=9
Indicates that a monitr operation (see Section 3) can be performed.
irevcm=10
Indicates that the current step was not successful, due to error test failure or convergence test failure. The only information supplied to you on this return is the current value of the variable t, located in rwork19. No values must be changed before re-entering d02nnf; this facility enables you to determine the number of unsuccessful steps.
On final exit: irevcm=0 indicating that the user-specified task has been completed or an error has been encountered (see the descriptions for itask and ifail).
Constraint: 0irevcm11.
Note: any values you return to d02nnf as part of the reverse communication procedure should not include floating-point NaN (Not a Number) or infinity values, since these are not handled by d02nnf. If your code inadvertently does return any NaNs or infinities, d02nnf is likely to produce unexpected results.
22:   lderiv2 – Logical arrayInput/Output
On initial entry: lderiv1 must be set to .TRUE. if you have supplied both an initial y and an initial y. lderiv1 must be set to .FALSE. if only the initial y has been supplied.
lderiv2 must be set to .TRUE. if the integrator is to use a modified Newton method to evaluate the initial y and y. Note that y and y, if supplied, are used as initial estimates. This method involves taking a small step at the start of the integration, and if itask=6 on entry, t and tout will be set to the result of taking this small step. lderiv2 must be set to .FALSE. if the integrator is to use functional iteration to evaluate the initial y and y, and if this fails a modified Newton method will then be attempted. lderiv2=.TRUE. is recommended if there are implicit equations or the initial y and y are zero.
On final exit: lderiv1 is normally unchanged. However if itask=6 and internal initialization was successful then lderiv1=.TRUE..
lderiv2=.TRUE., if implicit equations were detected. Otherwise lderiv2=.FALSE..
23:   itask – IntegerInput
On initial entry: the task to be performed by the integrator.
itask=1
Normal computation of output values of yt at t=tout (by overshooting and interpolating).
itask=2
Take one step only and return.
itask=3
Stop at the first internal integration point at or beyond t=tout and return.
itask=4
Normal computation of output values of yt at t=tout but without overshooting t=tcrit. tcrit must be specified as an option in one of the integrator setup routines before the first call to the integrator, or specified in the optional input routine before a continuation call. tcrit (e.g., see d02nvf) may be equal to or beyond tout, but not before it in the direction of integration.
itask=5
Take one step only and return, without passing tcrit (e.g., see d02nvf). tcrit must be specified under itask=4.
itask=6
The integrator will solve for the initial values of y and y only and then return to the calling (sub)program without doing the integration. This option can be used to check the initial values of y and y. Functional iteration or a ‘small’ backward Euler method used in conjunction with a damped Newton iteration is used to calculate these values (see lderiv). Note that if a backward Euler step is used then the value of t will have been advanced a short distance from the initial point.
Note:  if d02nnf is recalled with a different value of itask (and tout altered) then the initialization procedure is repeated, possibly leading to different initial conditions.
Constraint: 1itask6.
24:   itrace – IntegerInput
On initial entry: the level of output that is printed by the integrator. itrace may take the value -1, 0, 1, 2 or 3.
itrace<-1
-1 is assumed and similarly if itrace>3, 3 is assumed.
itrace=-1
No output is generated.
itrace=0
Only warning messages are printed on the current error message unit (see x04aaf).
itrace>0
Warning messages are printed as above, and on the current advisory message unit (see x04abf) output is generated which details Jacobian entries, the nonlinear iteration and the time integration. The advisory messages are given in greater detail the larger the value of itrace.
25:   ifail – IntegerInput/Output
On entry: ifail must be set to 0, -1​ or ​1. If you are unfamiliar with this argument you should refer to Section 3.4 in How to Use the NAG Library and its Documentation for details.
For environments where it might be inappropriate to halt program execution when an error is detected, the value -1​ or ​1 is recommended. If the output of error messages is undesirable, then the value 1 is recommended. Otherwise, because for this routine the values of the output arguments may be useful even if ifail0 on exit, the recommended value is -1. When the value -1​ or ​1 is used it is essential to test the value of ifail on exit.
On exit: ifail=0 unless the routine detects an error or a warning has been flagged (see Section 6).

6
Error Indicators and Warnings

If on entry ifail=0 or -1, explanatory error messages are output on the current error message unit (as defined by x04aaf).
Errors or warnings detected by the routine:
ifail=1
On entry, the integrator detected an illegal input, or that a linear algebra and/or integrator setup routine has not been called prior to the call to the integrator. If itrace0, the form of the error will be detailed on the current error message unit (see x04aaf).
ifail=2
The maximum number of steps specified has been taken (see the description of optional inputs in the integrator setup routines and the optional input continuation routine, d02nzf).
ifail=3
With the given values of rtol and atol no further progress can be made across the integration range from the current point t. The components y1,y2,,yneq contain the computed values of the solution at the current point t.
ifail=4
There were repeated error test failures on an attempted step, before completing the requested task, but the integration was successful as far as t. The problem may have a singularity, or the local error requirements may be inappropriate.
ifail=5
There were repeated convergence test failures on an attempted step, before completing the requested task, but the integration was successful as far as t. This may be caused by an inaccurate Jacobian matrix or one which is incorrectly computed.
ifail=6
Some error weight wi became zero during the integration (see the description of itol). Pure relative error control (atoli=0.0) was requested on a variable (the ith) which has now vanished. The integration was successful as far as t.
ifail=7
The resid operation (see Section 3) set the error flag ires=3 continually despite repeated attempts by the integrator to avoid this.
ifail=8
lderiv1=.FALSE. on entry but the internal initialization routine was unable to initialize y (more detailed information may be directed to the current error message unit, see x04aaf).
ifail=9
A singular Jacobian r y  has been encountered. You should check the problem formulation and Jacobian calculation.
ifail=10
An error occurred during Jacobian formulation or back-substitution (a more detailed error description may be directed to the current error message unit, see x04aaf).
ifail=11
The resid operation (see Section 3) signalled the integrator to halt the integration and return by setting ires=2. Integration was successful as far as t.
ifail=12
The monitr operation (see Section 3) set imon=-2 and so forced a return but the integration was successful as far as t.
ifail=13
The requested task has been completed, but it is estimated that a small change in rtol and atol is unlikely to produce any change in the computed solution. (Only applies when you are not operating in one step mode, that is when itask2 or 5.)
ifail=14
The values of rtol and atol are so small that d02nnf is unable to start the integration.
ifail=-99
An unexpected error has been triggered by this routine. Please contact NAG.
See Section 3.9 in How to Use the NAG Library and its Documentation for further information.
ifail=-399
Your licence key may have expired or may not have been installed correctly.
See Section 3.8 in How to Use the NAG Library and its Documentation for further information.
ifail=-999
Dynamic memory allocation failed.
See Section 3.7 in How to Use the NAG Library and its Documentation for further information.

7
Accuracy

The accuracy of the numerical solution may be controlled by a careful choice of the arguments rtol and atol, and to a much lesser extent by the choice of norm. You are advised to use scalar error control unless the components of the solution are expected to be poorly scaled. For the type of decaying solution typical of many stiff problems, relative error control with a small absolute error threshold will be most appropriate (that is, you are advised to choose itol=1 with atol1 small but positive).

8
Parallelism and Performance

d02nnf is not thread safe and should not be called from a multithreaded user program. Please see Section 3.12.1 in How to Use the NAG Library and its Documentation for more information on thread safety.
d02nnf is threaded by NAG for parallel execution in multithreaded implementations of the NAG Library.
d02nnf makes calls to BLAS and/or LAPACK routines, which may be threaded within the vendor library used by this implementation. Consult the documentation for the vendor library for further information.
Please consult the X06 Chapter Introduction for information on how to control and interrogate the OpenMP environment used within this routine. Please also consult the Users' Note for your implementation for any additional implementation-specific information.

9
Further Comments

The cost of computing a solution depends critically on the size of the differential system and to a lesser extent on the degree of stiffness of the problem; also on the type of linear algebra being used. For further details see Section 9 in d02ngf, d02nhf and d02njf of the documents for d02ngf (full matrix), d02nhf (banded matrix) or d02njf (sparse matrix).
In general, you are advised to choose the Backward Differentiation Formula option (setup routine d02nvf) but if efficiency is of great importance and especially if it is suspected that y A-1g has complex eigenvalues near the imaginary axis for some part of the integration, you should try the BLEND option (setup routine d02nwf).

10
Example

We solve the well-known stiff Robertson problem written as a differential system in implicit form
r1=a+b+c r2=0.04a-1.0E4bc-3.0E7b2-b r3=0.04a-1.0E4bc-3.0E7b2-c  
over the range 0,10 with initial conditions a=1.0 and b=c=0.0 and with scalar error control (itol=1). We integrate to the first internal integration point past tout=10.0 (itask=3), using a BDF method (setup routine d02mvf) and a modified Newton method. We treat the Jacobian as sparse (setup routine d02nuf) and we calculate it analytically. In this program we also illustrate the monitoring of step failures (irevcm=10) and the forcing of a return when the component falls below 0.9 in the evaluation of the residual by setting ires=2.

10.1
Program Text

Program Text (d02nnfe.f90)

10.2
Program Data

Program Data (d02nnfe.d)

10.3
Program Results

Program Results (d02nnfe.r)

© The Numerical Algorithms Group Ltd, Oxford, UK. 2017