# Components and Data Structures

Introduction | Iterating Solutions |

Example | Getting Solution Functions |

ProcessEquations | NDSolve`StateData Properties |

Reinitialize |

## Introduction

NDSolve is broken up into several basic steps. For advanced usage, it can sometimes be advantageous to access components to carry out each of these steps separately.

NDSolve performs each of these steps internally, hiding the details from a casual user.

Here are the low-level functions that are used to break up these steps.

classifies the differential system into initial value problem, boundary value problem, differential-algebraic problem, partial differential problem, etc. It also chooses appropriate default integration methods and constructs the main data structure.

advances the numerical solution. The first invocation (there can be several) initializes the numerical integration methods.

converts numerical data into an InterpolatingFunction to represent each solution.

Note that can take a significant portion of the overall time to solve a differential system. In such cases, it can be useful to perform this step only once and use to repeatedly solve for different options or initial conditions.

## Example

In[1]:= |

Out[1]= |

In[2]:= |

In[3]:= |

Out[3]= |

In[4]:= |

Out[4]= |

## ProcessEquations

The first stage of any solution using NDSolve is processing the equations specified into a form that can be efficiently accessed by the actual integration algorithms. This stage minimally involves determining the differential order of each variable, making substitutions needed to get a first-order system, solving for the time derivatives of the functions in terms of the functions, and forming the result into a object. If you want to save the time of repeating this process for the same set of equations, or if you want more control over the numerical integration process, the processing stage can be executed separately with .

NDSolve`ProcessEquations[{eqn_{1},_{2},…},{u_{1},u_{2},…},t] | |

process the differential equations for the functions into a normal form; return a list of objects containing the solution and data associated with each solution for the time derivatives of the functions in terms of the functions; t may be specified in a list with a range of values as in NDSolve | |

NDSolve`ProcessEquations[{eqn_{1},_{2},…},{u_{1},u_{2},…},{x_{1},x_{1min},x_{1max}},{x_{2},x_{2min},x_{2max}},…] | |

process the partial differential equations for the functions into a normal form; return a list of objects containing the solution and data associated with each solution for the time derivatives of the functions in terms of the functions; if is the temporal variable, it need not be specified with the boundaries |

Processing equations for NDSolve.

In[5]:= |

Out[5]= |

## Reinitialize

It is not uncommon that the solution to a more sophisticated problem involves solving the same differential equation repeatedly, but with different initial conditions. In some cases, processing equations may be as time consuming as numerically integrating the differential equations. In these situations, it is a significant advantage to be able to simply give new initial values.

NDSolve`Reinitialize[state,conditions] | assuming the equations and variables are the same as the ones used to create the object state, form a list of new objects, one for each of the possible solutions for the initial values of the functions of the equations conditions |

In[6]:= |

Out[6]= |

In[7]:= |

Out[7]= |

Using may save computation time when you need to solve the same differential equation for many different initial conditions, as you might in a shooting method for boundary value problems.

A subset of NDSolve options can be specified as options to .

In[8]:= |

Out[8]= |

## Iterating Solutions

One important use of objects is to have more control of the integration. For some problems, it is appropriate to check the solution and start over or change parameters, depending on certain conditions.

NDSolve`Iterate[state,] | compute the solution of the differential equation in an object that has been assigned as the value of the variable state from the current time up to time t |

Iterating solutions to differential equations.

In[9]:= |

Out[9]= |

Note that when you use , you do not need to give the range of the variable explicitly because that information is not needed to set up the equations in a form ready to solve. (For PDEs, you do have to give the ranges of all spatial variables, however, since that information is essential for determining an appropriate discretization.)

In[10]:= |

does not return a value because it modifies the object assigned to the variable state. Thus, the command affects the value of the variable in a manner similar to setting parts of a list, as described in "Manipulating Lists by Their Indices". You can see that the value of state has changed, since it now displays the current time to which it is integrated.

In[11]:= |

Out[11]= |

If you want to integrate further, you can call again, but with a larger value for time.

In[12]:= |

You can specify a time that is earlier than the first current time, in which case the integration proceeds backward with respect to time.

In[13]:= |

allows you to specify intermediate times at which to stop. This can be useful, for example, to avoid discontinuities. Typically, this strategy is more effective with so-called one-step methods, such as the explicit Runge–Kutta method used in this example. However, it generally works with the default NDSolve method as well.

In[14]:= |

## Getting Solution Functions

Once you have integrated a system up to a certain time, typically you want to be able to look at the current solution values and generate an approximate function representing the solution computed so far. The command allows you to do both.

NDSolve`ProcessSolutions[state] | give the solutions that have been computed in state as a list of rules with InterpolatingFunction objects |

Getting solutions as InterpolatingFunction objects.

In[15]:= |

Out[15]= |

In[16]:= |

Out[16]= |

Just as when using NDSolve directly, there will be a rule for each function you specified in the second argument to . Only the specified components of the solutions are saved in such a way that an InterpolatingFunction object can be created.

NDSolve`ProcessSolutions[state,dir] | give the solutions that have been most recently computed in direction in as a list of rules with values for both the functions and their derivatives |

Obtaining the current solution values.

In[17]:= |

Out[17]= |

The choices you can give for the direction dir are and , which refer to the integration forward and backward from the initial condition.

"Forward" | integration in the direction of increasing values of the temporal variable |

"Backward" | integration in the direction of decreasing values of the temporal variable |

"Active" | integration in the direction that is currently being integrated; typically, this value should only be called from method initialization that is used during an active integration |

Integration direction specifications.

The output given by is always given in terms of the dependent variables, either at a specific value of the independent variable, or interpolated over all of the saved values. This means that when a partial differential equation is being integrated, you will get results representing the dependent variables over the spatial variables.

In[18]:= |

In[20]:= |

Out[20]= |

The solution is given as an InterpolatingFunction object that interpolates over the spatial variable .

In[21]:= |

Out[21]= |

When you process the current solution for partial differential equations, the spatial error estimate is checked. (It is not generally checked except when solutions are produced because doing so would be quite time consuming.) Since it is excessive, the NDSolve::eerr message is issued. The typical association of the word "backward" with the heat equation as implying instability gives a clue to what is wrong in this example.

In[22]:= |

Out[22]= |

The plot of the solution shows that instability is indeed the problem.

Even though the heat equation example is simple enough to know that the solution backward in time is problematic, using and to monitor the solution of a PDE can be done to save computing a solution that turns out not to be as accurate as desired. Another simple form of monitoring follows.

In[23]:= |

Out[25]= |

When you monitor a solution in this way, it is usually possible to interrupt the computation if you see that the solution found is sufficient. You can still use the object to get the solutions that have been computed.

## NDSolve`StateData Properties

An object contains a lot of information, but it is arranged in a manner that makes it easy to iterate solutions, and not in a manner that makes it easy to understand where the information is kept. However, sometimes you will want to get information from the state data object: for this reason several properties have been defined to make accessing the information easy.

One of the most important uses of the information from an object is to set up integration methods. Examples are shown in "The NDSolve Method Plugin Framework".

state@"Variables" | gives a list of lists all of the variables structured according to the solution data |

state@"VariableDimensions" | gives lists of the dimensions of each of the variables |

state@"VariablePositions" | give lists of the positions in the solution data for each of the variables |

state@"NumericalFunction" | give the NumericalFunction object used to evaluate the derivatives of the solution vector with respect to the temporal variable t |

state@"ProcessExpression"[args,expr,dims] | |

process the expression expr using the same variable transformations that used to generate state to give a NumericalFunction object for numerically evaluating expr; args are the arguments for the numerical function and should either be All or a list of arguments that are dependent variables of the system; dims should be Automatic or an explicit list giving the expected dimensions of the numerical function result | |

state@"SystemSize" | give the effective number of first-order ordinary differential equations being solved |

state@"MaxSteps" | give the maximum number of steps allowed for iterating the differential equations |

state@"WorkingPrecision" | give the working precision used to solve the equations |

state@"Norm" | give the scaled norm to use for gauging error |

Properties for an object state.

In[26]:= |

Out[26]= |

In[27]:= |

Out[27]= |

The system size is 2 because there are two scalar ODEs.

Much of the available information depends on the current solution values. NDSolve saves different data for the forward and backward (from the initial condition time) integration directions. These can be accessed by the following directional properties.

state@"SolutionData"[dir] | give the current value of the solution data in the integration direction dir |

state@"TimeStep"[dir] | give the time step size for the next step in the integration direction dir |

state@"TimeStepsUsed"[dir] | give the number of time steps used to get to the current time in the integration direction dir |

state@"MethodData"[dir] | give the method data object used in the integration direction dir |

Directional properties for an object state.

If the direction argument is omitted, the functions will return a list with the data for both directions (a list with a single element at the initial condition). Otherwise, the direction can be , , or as specified in the previous subsection.

In[28]:= |

Out[28]= |

In[29]:= |

Out[30]= |

In[31]:= |

Out[31]= |

In[32]:= |

Out[32]= |

### Solution Data

The solution data consists of a list of the lists of values for each type of solution component. The solution data components are different types of variables, such as time, dependent variables, and discrete variables. Any component that is not being used for a particular problem will be given as an empty list () or None.

NDSolve`SolutionDataComponent[sd,c] | get the solution component c from solution data sd |

NDSolve`SetSolutionDataComponent[sd,c,v] | set the solution component c to v in the solution data assigned to the symbol sd |

nf@"SolutionDataComponents" | give the solution data components used as arguments for the NumericalFunction nf used in NDSolve |

Getting and setting solution data components.

The components of solution data are given in the following table.

short name | full name | component |

"T" | "Time" | current time |

"S" | "Space" | spatial discretization |

"X" | "DependentVariables" | current values of dependent variables other than discrete |

"X'" | "TemporalDerivatives" | the time derivatives of the dependent variables |

"D" | "DiscreteVariables" | the discrete variables that take on a continuous range of values |

"ID" | "IndexedDiscreteVariables" | the discrete variables that take on a finite set of values |

"P" | "Parameters" | the parameters other than ones for which senstivity is being computed |

"SP" | "SensitivityParameters" | the parameters for which sensitivity is being computed |

In[33]:= |

Out[35]= |

In[36]:= |

Out[36]= |

In[37]:= |

Out[37]= |

In[38]:= |

Out[38]= |

In[39]:= |

Out[39]= |

In[40]:= |

Out[40]= |

In[41]:= |

Out[41]= |

Note that the solution data is effectively the raw data that NDSolve uses to compute the solution. In the example above, the dependent variables component is a list of length 2 because the second-order equation is automatically reduced to a first-order system. If you want to have a clear identification of the parts of the current solution, you can use .

In[42]:= |

Out[42]= |

### NumericalFunction

When doing time integration, the methods NDSolve uses work with a right-hand side function for ODEs such that or a residual function for DAEs such that , where is real and , , and other solution data components used are vectors. The actual variables represented by the vectors and may have more complicated structure, so NDSolve uses an intermediate NumericalFunction object that takes vector arguments and returns vectors based on any underlying function.

In[43]:= |

Out[43]= |

In[44]:= |

Out[44]= |

The NumericalFunction that NDSolve constructs for evaluation only uses as arguments the solution data components that are actually used in the problem. You can find what components it actually uses by using the property.

In[45]:= |

Out[45]= |

In[46]:= |

Out[46]= |

In[47]:= |

Out[47]= |

Note that the indexed discrete variable was introduced as a variable by the automatic discontinuity handling for the Sign function. (See the solution shown below.)

In[48]:= |

Out[48]= |

In[49]:= |

Out[49]= |

To make it easier to evaluate with the solution data for a given problem, two convenience functions have been included that evaluate with the solution data.

NDSolve`EvaluateWithSolutionData[nf,sd] | evaluate the NumericalFunction nf with arguments from the solution data list sd |

NDSolve`EvaluateJacobianWithSolutionData[nf,sd,c] | evaluate the Jacobian derivative with respect to all the variables in the the solution data component c |

Evaluating with solution data.

In[50]:= |

Out[50]= |

One of the things that NumericalFunction does is to handle derivatives automatically. By default, symbolic derivatives are used if they can be found, and otherwise finite differences are used.

In[51]:= |

Out[51]= |

In this example, finite differences are used because of the vector arguments and Dot products.

In[52]:= |

Out[53]= |

It is sometimes useful to set up NumericalFunction to evaluate some function of the NDSolve variables, which can be done using .

Many of the built-in methods do this during method initialization so that the function can be evaluated efficiently repeated times. For example, the "projection" method sets up a function to evaluate the deviation of the invariants from their initial values and uses the derivatives to implement the projection after each step.

In[54]:= |

In[55]:= |

Out[55]= |

In[56]:= |

Out[56]= |

In[57]:= |

Out[57]= |

In[58]:= |

Out[58]= |