Sparse Navier-Stokes Jacobian Assembly

NSASM is a MATLAB library which carries out the finite element assembly of the jacobian matrix used in a Newton iteration to solve the steady state incompressible Navier Stokes equations in a 2D region, by Per-Olof Persson.

The finite element approximation uses the P2-P1 triangular element, also known as the Taylor-Hood element. The velocities are approximated quadratically, and the pressures linearly.

The sparse matrix format used is known as the compressed column format, in which the nonzero entries and their row indices are stored in order by columns.

The software assumes that a suitable mesh has been set up for the region, with arrays P and T defining that mesh, that an array defining the boundary constraints has been set up, and that an initial estimate of the flow has been made available.

Invoking the Library

The software is designed to be compiled via MATLAB's mex facility. This means you have to have access to the MATLAB compiler mex; you also have to have a compiler on your computer; and you have to have (just once) set up your mex option by starting MATLAB and issuing the command "mbuild -setup".

Then you need to make a compiled copy of the nsasm code. You do this with the MATLAB command

        mex -largeArrayDims nsasm.c
which, on my Macintosh computer, results in the creation of the compiled file "nsasm.mexmaci64", although the name used on your system may differ. In any case, once this file has been created, MATLAB can invoke it as though it were a MATLAB M-file, with input and output arguments.

The C code in NSASM sets up a linear system which is intended to be solved by MATLAB. Thus, the Newton iteration could have the following form in a MATLAB program:

        for ii = 1 : 8
          [ K, L ] = nsasm ( p, t, np0, e, u, mu );
          du = - lusolve ( K, L );
          u = u + du;
          disp ( sprintf ( '%20.10g  %20.10g', norm ( L, inf ), ...
            norm ( du, inf ) ) );

Indexing Conventions

The software makes some particular assumptions about the numbering of nodes, variables, and local element nodes

(Indexing of nodes) It is assumed that the mesh was generated by starting with a set of nodes, triangulating them, and then computing the midsides of the triangles and adding these midsides to the list of nodes. In particular, the program therefore assumes that the numbering of the nodes reflects this process, so that all vertex nodes are numbered first, followed by the midside nodes.

(Indexing of global variables) It is assumed that every node has an associated horizontal velocity variable "U", that every node has an associated vertical velocity variable "V", and that only vertex nodes or "pressure nodes" have an associated pressure variable "P". The variables are stored in a single vector, first all the U's, then all the V's, then the P's. Thus variable 1 is the value of U at node 1, variable NP+1 is the value of V at node 1, and variable 2*NP+1 is the value of P at node 1.

Notice that there are even more global variables than you might think, since the boundary conditions and other constraints are handled by adding a Lagrange multiplier for each one. Thus the number of variables is actually 2*NP+NP0+NE.

(Numerical codes for U,V,P) In the E vector used to define constraints, the numeric codes 0, 1 and 2 are used for U, V and P variables respectively.

(Local numbering of nodes) When listing the 6 nodes that make up a triangle, the ordering should be as follows:

         | \
         |  \
        N5   N4
         |    \
         |     \
         |      \


[ K, L ] = nsasm ( p, t, np0, e, u, nu );


NSASM is available in a C version and a FORTRAN90 version and a MATLAB version.

Related Data and Programs:


Original C+MATLAB version by Per-Olof Persson.
This MATLAB version by John Burkardt and Hyung-Chun Lee.


  1. Per-Olof Persson,
    Implementation of Finite Element-Based Navier-Stokes Solver,
    April 2002.
  2. Michael Schaefer, Stefan Turek,
    Benchmark Computations of Laminar Flow Around a Cylinder,
    Notes on Numerical Fluid Mechanics,
    Volume 52, 1996, pages 547-566.

Source Code:

Examples and Tests:

The SMALL test defines a small sparse matrix, with NP = 25 nodes, NT = 8 elements, NE = 33 constraints, NP0 = 9, NU = 100.0.

The BIG_CONSTRAINT_FILE_MAKER program was set up because I lost or never had a copy of the "big_constraints.txt" file, and I had to guess the problem type (driven cavity) and the location of the boundary nodes on left, bottom and right, and then manufacture the appropriate constraint data:

The BIG test defines a relatively large sparse matrix, with NP = 2049 nodes, NT = 960 elements, NE = 387 constraints, NP0 = 545, NU = 500.0, a version of the driven cavity problem, with an unstructured mesh.

The element data for the big problem is quadratic, and the assumption is made that the midside nodes are the midpoints of the corresponding vertices. That is, the 6-noded triangles have straight sides, with the mid-side nodes actually at the geometric middles of their sides. The easiest way to guarantee such a triangulation is to generate a triangulation with 3-noded triangles, and then generate the midside nodes in the obvious way. Here we include the original 3-noded triangulation information.

You can go up one level to the MATLAB source codes.

Last revised on 22 September 2013.