After reading the above list you should have the idea that solving PDEs with the finite-element method is a very open-ended business, and that in designing a simulation you will be faced with a large number of choices. Sundance is intended to let you make those choices by selecting and combining high-level objects rather than by writing low-level code. Note that while Sundance makes it easy for you to try many options for formulation, discretization, and solution, it cannot by itself help you make good choices for a given problem -- for that you will have to rely on your understanding of the problem. Unfortunately, Sundance has no way to detect if you use its components to build an unstable or innaccurate discretization, write ill-posed boundary conditions, or choose a solver that is inefficient for your problem.Sundance components is somewhat different from writing one with FORTRAN subroutines or even lower-level C++ objects than those used in Sundance. Programming with Sundance components is essentially declarative programming. One defines a suite of objects that specify the mesh, equations, boundary conditions, solver, and so on, and marshals them into an object that can produce the solution to a problem. In many cases, it will not be necessary for you as a simulation developer to write any loops, conditionals, or other procedural constructions. Tasks such as looping over mesh cells or deciding where to apply boundary conditions is done inside certain methods of the top-level LinearProblem and NonlinearProblem objects. The iterators and conditionals required to control that process are deduced from information provided by the components from which you assembled the Problem objects.Sundance is written in the C++ programming language. To write your own Sundance simulation, you will have to write and compile C++. However, you need not be an expert C++ programmer, because you can do most things using Sundance's predefined objects. The trick to writing Sundance code is to understand the behavior of the user-level objects. The main purpose of this document is to show you how to use Sundance's user-level objects to set up and solve PDEs.
DiscreteFunctionare classes. Method names and variables begin with lower-case letters, but subsequent words within the name are capitalized. For example:
numCells()are methods. If you forge on to read the developer's documentation or source code, you will need to know that data member names end with an underscore, for example:
myName.Sundance is important for reading and writing Sundance code and browsing the source and class documentation. Handle classes are used in Sundance to simplify user-level polymorphism and provide transparent memory management.
Polymorphism is a buzzword meaning the representation of different but related object types (derived classes, or subclasses) through a common interface (the base class). In C++, you can't use a base-class object to represent a derived class; you have to use a pointer to the base class object to represent a pointer to the derived class. That leads to a rather awkward syntax and also requires attention to memory management. To simplify the interface and make memory management automatic, all user-level polymorphism is done with handle classes. A handle class is simply a class that contains a pointer to a base class, along with an interface providing user-callable methods, and a (presumably) intelligent scheme for memory management.
So if you want to work with a family of Sundance objects, for instance the different flavors of symbolic objects, you need only use:
For example, Sundance symbolic objects are represented with a handle class called
Expr. The different symbolic types derive from a class called
ExprBase, but they are never used directly after construction; they are used only through the
Expr handle class. The code fragment below shows some Exprs being constructed through subclass constructors and then being used in
Expr x = new CoordExpr(0, "x"); Expr f = x + 3.0*sin(x); Expr dx = new Derivative(0); Expr df = dx*f;
Thanks to handles, when writing Sundance code you can always assume that
Expressions are shallow-copied as well. Though not important for conserving memory, shallow copying expression is important for performance because it can help avoid redundant evaluation of complicated expressions. Suppose, for example, that your equation contains in several places. You can define an intermediate expression
Expr f = cos(x + exp(-u)*y*w);
Expr g = v*f + f*(dx*v)*(dx*u) + v*sqrt(1.0 + f*f);
The shallow copy property of Expr has another important application: it allows after-the-fact modification of expressions buried within larger expressions. In particular, it allows the simulator to update values of Parameter and DiscreteFunction expressions in place during the course of run.Sundance written in Java (as it might have been, had Java provided operator overloading), ExprBase wouldn't even exist, and CoordExpr would derive directly from Expr. The introduction of handles is solely a way of getting clean syntax for polymorphism and operator overloading within C++.Sundance can both assemble and solve systems in parallel. Parallel Sundance uses the SPMD paradigm, in which the same code is run on all processors. Communication is done using MPI, accessed through object wrappers in the Teuchos utilities package within Trilinos. To use Sundance's parallel capabilities, Trilinos must be built with MPI enabled. See the installation documentation for help in installing parallel Sundance.
One of the design goals was to make parallel solves look to the user as much as possible like serial solves. In particular, the symbolic description of an equation set and boundary conditions is completely unchanged from serial to parallel runs. To run a problem in parallel, you simply need to use a parallel solver (such as most of the iterative solvers available in Trilinos) and use a partitioned mesh. A subsequent section contains information on creating Distributed Meshes.
Operations such as norms and definite integrals on discrete functions are done such that the result is collected from all processors.