exercise3_05

Embed Size (px)

Citation preview

  • 8/10/2019 exercise3_05

    1/4

  • 8/10/2019 exercise3_05

    2/4

    the objectsu,v,p,x,y. One way is to make the function timestepsa friend of the array class. Anotheris to extract the pointers to double from arc by adding a function getv to the array class.

    The Fortran routine is declared in the C++ program through the statement

    extern "C" int RESID(int*, int*, double*, double*, double*, double*,

    double*, double*, double*, double*);

    resid does not do anything on the boundary points. To handle (external, not inter-processor) boundaries,

    you should define a base classbctype,2

    class bctype {

    public:

    bctype(arc *u, int side);

    virtual void impose(arc *u) = 0;

    };

    which serves as a base class for two derived classes bcdirichlet andbcneumann. You should create

    one boundary condition object for each side of the domain. The functionimpose imposes the boundarycondition, and all that the derived classes need to do is to define the function. The bcdirichletclass

    gives a value to the boundary point. Thebcneumann class should give the normal derivative of the

    solution. There, you need to add information on the direction normal to the boundary. To simplify the

    programming, you will be allowed to consider the grid as orthogonal at the boundary, i.e. the normal

    derivative can be computed along a single grid line. At the grid line i=0, the boundary conditionu/n=u/x= 0 would then beu0=u1to first order accuracy, and u0= 4/3u11/3u2for second order accuracy.

    The following boundary conditions should be used:

    At the left boundary (inflow): u=0.1y(3y), v =0, p/n=0

    At the right boundary (outflow): u/n=0, v =0, p=0

    At the upper and lower boundaries (walls):u =v=0, p/n=0.

    Do not forget to check that a boundary is a physical boundary, and not an internal boundary between

    processors.

    Use the initial data

    u(x,y,0) =0.1y(3y)

    v(x,y,0) =0

    p(x,y,0) =0.

    Use forward Euler, or the following two-stage Runge-Kutta method in time

    w(1) =wn +t r(wn)

    w(2) =w(1) +t r(w(1))

    wn+1 = (w(2) +wn)/2.

    I found that this works on a 50 20 grid for = 0.1 with a time step oft=0.002. You may wellexperiment with the stability limit!

    1. Implement the Navier-Stokes solver! Run it with grids of different sizes. Do not forget to adapt the

    time step size. The first three elements ofres provide a monitor to the convergence history. Use

    MPI Reduceto obtain global values for the residual. Monitor them!

    2. Measure the computing times of your codes for various meshes in dependence of the number of

    processors. For that, use appropriate optimisation when compiling. The functionMPI Wtime can

    be used to find the wall clock time. Since one time step is very fast, I recommend that you time, say,

    1000 steps.

    2Compare Chapter 6 of the Lecture Notes.

    2

  • 8/10/2019 exercise3_05

    3/4

    The programming exercises should be done individually, or in groups of two. Hand in a report containing:

    Comments and explanations that you think are necessary for understanding your program.

    Tables containing the computing time versus the number of processors for different grid sizes.

    One (one!) plot with the speedup curves for all different grid sizes. Explain your observations!

    A picture of the steady state solution, using approximately 5020 grid points. How many time steps

    did you use and what are the residuals?

    Program listing.

    E-mail the source code [email protected]

    A. The routine resid

    We give below the head of the routine resid.

    subroutine RESID( ni, nj, u, v, p, res, x, y, eps, dt )

    ***********************************************************************

    ***

    *** Resid computes a forward Euler step of the incompressible

    *** Navier-Stokes equations with artificial compressibility.

    ***

    *** A second order difference method with three point stencil is used.

    ***

    *** Input: ni, nj - Size of grid.

    *** u, v, p - Velocity and pressure at t_n

    *** res - Work space of size 3*ni*nj*** x, y - The grid.

    *** eps - Viscosity parameter, epsilon in the equations.

    *** dt - Time step.

    ***

    *** Output: u, v, p - The velocity and pressure is updated to t_{n+1} by

    *** forward Euler at the points (2..ni-1,2..nj-1)

    *** res(1),res(2),res(3) - The first three elements of the

    *** work space vector contains the maximum norm of the residual

    *** for the three equations respectively.

    ***

    *** NOTE: FORTRAN stores arrays column-wise, i.e., the first index

    *** changes fastest. (ind = i + ni*(j-1) )

    ***

    ***********************************************************************

    implicit none

    integer ni, nj, i, j

    real*8 u(ni,nj), v(ni,nj), p(ni,nj), eps, dt, x(ni,nj), y(ni,nj)

    real*8 res(3,ni,nj)

    B. Call conversion interface for resid

    A small wrapper function can be written to avoid passing scalar arguments as pointers. Such a routine

    may look like

    3

  • 8/10/2019 exercise3_05

    4/4

    void c_resid(int ni, int nj, double *u, double *v, double *p,

    double *res, double *x, double *y, double eps, double dt)

    {

    int ni_tmp = ni;

    int nj_tmp = nj;

    double eps_tmp = eps;

    double dt_tmp = dt;

    RESID(&ni_tmp, &nj_tmp, u, v, p, res, x, y, &eps_tmp, &dt_tmp);

    }

    The function c resid only serves as an interface and resid still does all the computations. Besides

    providing a more familiar interface there are two main reasons for using call conversion interfaces:

    1. residrequire pointer arguments and can not be called with constant input values. resid(50,

    50, ...) would for example result in a compile time error.

    2. The way Fortran 77 routines are called from C++ differs between platforms. Common names gen-

    erated in the compiled object code include resid, resid , RESIDand RESID .3 By calling the

    wrapperc resid instead at most two changes are needed as the program is ported to a different

    platform.

    Even more flexibility can be obtained by using call conversion interfaces defined as preprocessor directives.

    3Test the calling convention in your environment!

    4