This page discusses the following topics:

- To do much of anything with discrete functions, one must understand Creation of DiscreteSpace objects.
- Once a DiscreteSpace exists, there are a number of methods of Creation of DiscreteFunctions, including Projection of expressions onto discrete spaces, Reading of discrete functions from files, and Direct creation of discrete functions.
- The vector underlying a DiscreteFunction object can be accessed either read-only or read/write. This is sometimes needed when writing interfaces to iterative algorithms such as nonlinear solvers and optimizers.

// create a discrete space for a scalar field // with Lagrange order 1 basis functions. The vector type is not specified // so the default will be used. DiscreteSpace discSpace(mesh, new Lagrange(1));

// create a discrete space for a 3-component vector field where each component // is represented with Lagrange order 2 basis functions. The vector // type is specified through the vecType argument. DiscreteSpace discSpace(mesh, List(new Lagrange(2), new Lagrange(2), new Lagrange(2)), vecType);

An L2Projector is constructed by specifying a DiscreteSpace and an Expr to be projected onto that space:

// Set up projection on f onto the space of first-order Lagrange basis // functions on our mesh. DiscreteSpace discSpace(mesh, new Lagrange(1)); L2Projector projector(discSpace, f);

` project() `

method, ```
// Do the projections
Expr discreteF = projector.project();
```

There is a certain amount of bookkeeping involved in projection; basically, the overhead required for the setup of the linear problem doing the projection. If you need to do many projections of the same expression (perhaps with changing values of a discrete field or parameter) onto the same space, it is recommended that you create a single L2Projector and reuse it for all of these projections.

// Initialize a DiscreteFunction to a constant value 1.2345 DiscreteSpace discSpace(mesh, new Lagrange(1)); Expr f = new DiscreteFunction(discSpace, 1.2345);

Normally, insertion of a vector into a DiscreteFunction should be done using the vector access methods described in Access to DiscreteFunction vectors

A DiscreteFunction will normally be wrapped in an Expr object, so the first step towards vector access is to extract a DiscreteFunction pointer from an Expr. This can be done with the static method ` discFunc()`

, which has both const and non-const versions:

// Get a read-only pointer to the discrete function inside the Expr handle f0 const DiscreteFunction* discF0 = DiscreteFunction::discFunc(f0);

```
// Get a writable pointer to the discrete function inside the Expr handle f0
DiscreteFunction* discF0 = DiscreteFunction::discFunc(f0);
```

`getVector()`

method. The discrete function can also be given a new vector by means of the `setVector()`

method.
** Note: ** Because Expr has shallow copy behavior, changing the vector of a discrete function will simultaneously change the vector of all copies of that expression. This is a deliberate design feature: it is thereby possible to update the value of a discrete function appearing multiple times inside a complicated expression simply by setting the vector of a single instance of that discrete function.