.. role:: option(literal) .. role:: file(literal) .. _TUTORIAL4: Dissecting the Poisson Codes ============================= **Objective:** At the end of this tutorial you will understand how a simple linear solver works in PetIGA. **Assumptions:** I assume that you are familiar with C and in particular understand pointers_. Detailed Look at :file:`Poisson1D.c` ------------------------------------ In this tutorial we will look at the Poisson codes and explain each portion in more detail. It is my hope that in explaining how the demo codes work, this will help you see how you can use PetIGA to address your own problems. In this demo I will be discussing this_ demo code in sections. It might be useful to first scan through this code to familiarize yourself with its organization. In most PetIGA applications, you only need to include :file:`petiga.h`. Including this file will also automatically include :file:`petsc.h`. :: #include "petiga.h" The first function we encounter is the :file:`System` function. This function is the key to understanding how to use PetIGA to solve your own problems. For a linear, steady problem, this function represents the evaluation of the bilinear and linear form at a quadrature point. At a glance, a few things may strike you as strange particularly if you are not familiar with PETSc. First, you will note the :file:`#undef` and :file:`#define` lines before the function declaration. This is a mechanism that PETSc uses such that when its functions fail, the entire call stack is returned to the user. This is typically something that you only get when running the debugger. Having it always return on error reduces the time it takes you to locate errors. You will also see variable types :file:`PetscReal` and :file:`PetscScalar` instead of the expected :file:`double`. These are PETSc types which for most applications are actually of the type :file:`double`. However, you can configure PETSc to use, for example, quadruple precision or complex numbers. In this case, using PETSc types means that your code automatically ports to these situations with no additional work for you. The function has as its arguments a :file:`IGAPoint`, two PetscScalars and a void pointer. For now, ignore the existence of the void pointer. The :file:`IGAPoint p` is the quadrature/collocation point. We have built in all the information that you will need to evaluate the bilinear and linear form at this point. The two PetscScalar pointers are for the discretized bilnear and linear form respectively. The variable :file:`K` can be thought of as a flattened point contribution to the element stiffness matrix. The variable :file:`F` is the point contribution to the element load vector. The basis functions are part of the IGAPoint :file:`p` and so we need to simply assign some pointers to their location. The pointers :file:`N0` and :file:`N1` represent the 0th and 1st order derivative of the basis functions respectively. The pointers used and their casting is a bit technical and ugly, a consequence of using the C language. However, we emphasize that it is sufficient to copy these lines into your own code and understand what it is the pointers address. If a geometry is used, then the basis is mapped and/or made rational if using NURBS. Otherwise, these are just the B-spline basis functions in the parametric space. Your code does not need to know the difference, it is all handled internally. Then we simply code a double loop over the local number of basis functions, :file:`nen`. As a convention, we use :file:`a` to loop over the test functions and :file:`b` to loop over the trial functions. A dot product of the basis function derivatives is assembled into the stiffness matrix and the unit body force is assembled into the load vector. The quadrature weights and potential Jacobian of the mapping are applied internally. :: #undef __FUNCT__ #define __FUNCT__ "System" PetscErrorCode System(IGAPoint p,PetscScalar *K,PetscScalar *F,void *ctx) { const PetscReal *N0,(*N1)[1]; IGAPointGetShapeFuns(p,0,(const PetscReal**)&N0); IGAPointGetShapeFuns(p,1,(const PetscReal**)&N1); PetscInt a,b,nen=p->nen; for (a=0; a