SourceForge

A TUTORIAL

In this tutorial you will be led through the process of developing a simple 2D diffusion solver using the PARAMESH package. Follow the steps outlined below. When you are finished you will have created and run a simple calculation with an adaptive mesh.

As explained in the introduction, PARAMESH enables you to build your application with or without permanently allocated memory for storing guardcell data. This first tutorial assumes you will allocate permanent guardcell storage space. A second tutorial which can be accessed from the bottom of this page takes you through the steps required to build the same application without permanent guardcell storage. A third tutorial is also available from the bottom of this page which takes you through the process of using PARAMESH as a library. Finally, a fourth tutorial is available on the following pages which describes how to add flux conservation to the previous tutorials.


The simple problem we tackle here is to integrate a 2D diffusion equation.

We will use grid blocks of size 4x4 with 1 guard cell at each boundary. The data points defining U are assumed to be known at cell centers. We use a very simple explicit time integration scheme, and a 4-pt centered second order accurate difference to represent the operator, ie.

  U(i,j,t+dt) = U(i,j,t) + dt * A /(dx*dx)

A = U(i+1,j,t) + U(i-1,j,t) + U(i,j+1,t) + U(i,j-1,t) - 4*U(i,j,t)

In the tutorial described on this page, we will assume that you will be using MPI. You must have a version of MPI installed on your system to use this tutorial. You can get a freely available version of MPI which can be installed on most systems from the MPICH web site

Step 1. - Preparations


Step 2. - Edit the header file paramesh_preprocessor.fh.

All other settings in this file can be left with their default values.


Step 3. - Create and Edit the tutorial's main makefile.

Explanation:
This routine is needed as part of the mechanism by which the User supplies any non-periodic boundary conditions which might be required. In our example, we are using periodic boundary conditions. These are implemented by identifying blocks at the left boundary as neighbors of blocks at the right boundary, and vice versa. Because we have no blocks whose neighbors addresses will satisfy the ibc if test in this example, this routine will do nothing. We include this step in the tutorial merely to introduce you to the mechanism you must use when setting up aperiodic boundary conditions.


Step 7. - Build the executable.


Step 8. - Run the executable.

Congratulations, you have now begun to do amr !

If everything went according to plan you should have generated a short output listing which concludes with something equivalent to the following lines (the order in which the blocks are listed may vary slightly, from one machine to another):


 pe / blk / blk-coords / blk-sizes
 0,  1,  2*0.E+0,  2*8.
 0,  2,  2*-3.,  2*2.
 0,  3,  2*-2.,  2*4.
 0,  4,  -1.,  -3.,  2*2.
 0,  5,  -3.,  -1.,  2*2.
 0,  6,  2*-1.,  2*2.
 0,  7,  2.,  -2.,  2*4.
 0,  8,  1.,  -3.,  2*2.
 0,  9,  3.,  -3.,  2*2.
 0,  10,  1.,  -1.,  2*2.
 0,  11,  3.,  -1.,  2*2.
 0,  12,  -3.,  1.,  2*2.
 0,  13,  -2.,  2.,  2*4.
 0,  14,  -1.,  1.,  2*2.
 0,  15,  -3.,  3.,  2*2.
 0,  16,  -1.,  3.,  2*2.
 0,  17,  2*2.,  2*4.
 0,  18,  2*1.,  2*2.
 0,  19,  3.,  1.,  2*2.
 0,  20,  1.,  3.,  2*2.
 0,  21,  2*3.,  2*2.

The full grid is shown here with block boundaries drawn in black and grid cells outlined in red.

This is a list of all the grid blocks that you have created. Since we are currently only using 1 processor, all the blocks are listed as being on processor 0. The second integer on each line is the block address on processor 0, the next 2 floating point numbers specify the x and y coordinates of the center of each block, and the last two numbers are the block lengths along the x and y axes.


Step 9. - Initializing the solution.


Step 10. - Edit amr_initial_soln.F90

Explanation:
This step has modified the routine amr_initial_soln to generate the initial solution we want.


Step 11. - Edit tutorial.F

Explanation:
In steps 8,9,and 10 we modified the routine amr_initial_soln to generate the initial solution we want, and the I/O loop we added in the main program will verify that the value of the initial solution for a block centered at coordinates (1.0,1.0) has the correct values.


Step 12. - Remake and run.

You have now initialized the solution array unk(1,:,:,:,:) on all the grid blocks of the initial grid. As proof, the last six lines of your output show the data values on the centered at (1.0,1.0). It should look like this:

 
   1   0.0000   0.0000   0.0000   0.0000   0.0000   0.0000
   2   0.0000  10.0000  10.0000   1.0000   1.0000   0.0000
   3   0.0000  10.0000  10.0000   1.0000   1.0000   0.0000
   4   0.0000   1.0000   1.0000   1.0000   1.0000   0.0000
   5   0.0000   1.0000   1.0000   1.0000   1.0000   0.0000
   6   0.0000   0.0000   0.0000   0.0000   0.0000   0.0000

This block is located at 0 < x < 2 and 0 < y < 2. It straddles one corner of the high density region. Notice, the 4x4 block interior has been initialized with non-zero values and there is a layer of guard cells surrounding the block which are currently all set to 0.0.

The complete initial state is shown here, with the block boundaries superimposed in black and the grid cells outlined in red.


Step 13. - Filling Guardcells

Edit tutorial.F90

Step 14. - Remake and run.

Now the last 6 lines which report the solution array in our selected block looks like this.

 
   1  10.0000  10.0000  10.0000   1.0000   1.0000   1.0000
   2  10.0000  10.0000  10.0000   1.0000   1.0000   1.0000
   3  10.0000  10.0000  10.0000   1.0000   1.0000   1.0000
   4   1.0000   1.0000   1.0000   1.0000   1.0000   1.0000
   5   1.0000   1.0000   1.0000   1.0000   1.0000   1.0000
   6   1.0000   1.0000   1.0000   1.0000   1.0000   1.0000

Notice, the guard cell layer has been filled with the correct data from the neighboring blocks.


Step 15. - Constructing a routine to test refinement levels.

Explanation:
This routines function is to set the logical arrays 'refine' and 'derefine' to be true or false for each grid block. It does this by computing a local error measure and testing to see if the acceptable limits on this error measure are violated anywhere within each leaf block. There is one subtle feature of this example which we should mention. The data used as input for the error calculation is first placed in the 'work' array. This is a special cell centered data-structure, because, unlike 'unk', when the guardcell filling routines operate on 'work' they limit their scope to 1 data word per grid cell. 'work' is dimensioned inside the header file workspace.fh. It can have a number of guard cell layers set differently from that of the solution data-structure. By using 'work' here, and setting its guard cell number to be larger than the number of layers guarding the solution data-structure, we can help grid blocks to refine in advance of the arrival of disturbances.

We will use a very simple error measure here, based on variation of the solution between neighboring grid cells.


Step 16. - Edit tutorial.F90


Step 17. - Set the number of guard cell layers for 'work'


Step 18. - Remake and run.

Explanation:
The changes that you have just made, analyzed the error estimate on each existing grid block, and marked some blocks for additional refinement. In your new output there will be a section looking like this (the order of lines may be slightly different) :

 
  pe  blk    refine  derefine  curr.ref.level
   0    1         F         F            1
   0    2         F         T            3
   0    3         T         F            2
   0    4         F         T            3
   0    5         F         T            3
   0    6         T         F            3
   0    7         T         F            2
   0    8         F         T            3
   0    9         F         T            3
   0   10         T         F            3
   0   11         F         T            3
   0   12         F         T            3
   0   13         T         F            2
   0   14         T         F            3
   0   15         F         T            3
   0   16         F         T            3
   0   17         T         F            2
   0   18         T         F            3
   0   19         F         T            3
   0   20         F         T            3
   0   21         F         T            3

This is telling you that the test in amr_test_refinement marked blocks 3, 6, 7, 10, 13, 14, 17, and 18 for further refinement. However blocks 3, 7, 13, and 17 are parent blocks at level 2 and so their refinement flags will be ignored. Blocks 6, 10, 14 and 18 will be refined. Notice also that blocks 2,4,5,8,9,11,12,15,16,19,20 and 21 have been marked for derefinement. However each of these blocks has a sibling which has not been marked for derefinement ( in fact all their siblings have been marked for refinement ), and so these particular derefinement choices will be cancelled by PARAMESH. You can see that this is the case in the listing of the new grid which follows. The next section of output reports some details of the refinement procedure, and the final section is a list of the new grid, which now has 37 blocks in total.
 
 pe / blk / blk-coords / blk-sizes
 0,  1,  2*0.E+0,  2*8.
 0,  2,  2*-3.,  2*2.
 0,  3,  2*-2.,  2*4.
 0,  4,  -1.,  -3.,  2*2.
 0,  5,  -3.,  -1.,  2*2.
 0,  6,  2*-1.5,  2*1.
 0,  7,  2*-1.,  2*2.
 0,  8,  -0.5,  -1.5,  2*1.
 0,  9,  -1.5,  -0.5,  2*1.
 0,  10,  2*-0.5,  2*1.
 0,  11,  2.,  -2.,  2*4.
 0,  12,  1.,  -3.,  2*2.
 0,  13,  3.,  -3.,  2*2.
 0,  14,  0.5,  -1.5,  2*1.
 0,  15,  1.,  -1.,  2*2.
 0,  16,  1.5,  -1.5,  2*1.
 0,  17,  0.5,  -0.5,  2*1.
 0,  18,  1.5,  -0.5,  2*1.
 0,  19,  3.,  -1.,  2*2.
 0,  20,  -3.,  1.,  2*2.
 0,  21,  -2.,  2.,  2*4.
 0,  22,  -1.5,  0.5,  2*1.
 0,  23,  -1.,  1.,  2*2.
 0,  24,  -0.5,  0.5,  2*1.
 0,  25,  -1.5,  1.5,  2*1.
 0,  26,  -0.5,  1.5,  2*1.
 0,  27,  -3.,  3.,  2*2.
 0,  28,  -1.,  3.,  2*2.
 0,  29,  2*1.,  2*2.
 0,  30,  2*0.5,  2*1.
 0,  31,  2*2.,  2*4.
 0,  32,  1.5,  0.5,  2*1.
 0,  33,  0.5,  1.5,  2*1.
 0,  34,  2*1.5,  2*1.
 0,  35,  3.,  1.,  2*2.
 0,  36,  1.,  3.,  2*2.
 0,  37,  2*3.,  2*2.

The complete new grid is illustrated below.


Step 19. - Create the routine to update the solution.


Step 20. - Create the timestep routine.


Step 21. - Modify main program to call the advance_soln routine.


Step 22. - Remake and run.

Explanation:
You have now advanced the solution through 1 timestep, and the output section immediately after the call to advance_soln will show how the data on the block centered on (1.0,1.0) has been diffused. The data should look like this:

 
 dt =  2.500000037E-2
   1  10.0000  10.0000  10.0000   1.0000   1.0000   1.0000
   2  10.0000  10.0000   9.1000   1.9000   1.0000   1.0000
   3  10.0000   9.1000   8.2000   1.9000   1.0000   1.0000
   4   1.0000   1.9000   1.9000   1.0000   1.0000   1.0000
   5   1.0000   1.0000   1.0000   1.0000   1.0000   1.0000
   6   1.0000   1.0000   1.0000   1.0000   1.0000   1.0000

Note, at this point the cell interior (indeces 2-5 in both x and y) are correct, but the guardcells (indeces 1 and 6) have not yet been updated.

After the solution has been advanced on the block interiors, we test the solution to see if refinement is required. In this case refinement is selected for the 4 blocks around the center of the domain. These are refined, and the solution is prolonged to the newly created blocks there. The complete updated solution after these steps is shown here.


Step 23. - Run for 250 timesteps.

Explanation:
In your output you will notice that before the first timestep we had 21 blocks, with uniform refinement at level 3 throughout the computational domain. On the first timestep (iteration 1) the 4 blocks at the center containing the high data values were refined, adding 16 blocks to make a total of 37. After the seventeenth timestep the solution has diffused outward so that all the outer level 3 blocks, except for those on the corners, are now all marked for refinement, adding another 32 child blocks at level 4, for a total of 69.

After 250 timesteps, we can see from the final block listing below that block number 53 is a leaf block located near the origin (it has coordinates x=0.5, y=0.5 ; the line order may be slightly different in your output).

 
 pe / blk / blk-coords / blk-sizes
 0,  1,  2*-3.,  2*2.
 0,  2,  2*-2.,  2*4.
 0,  3,  2*0.E+0,  2*8.
 0,  4,  -1.,  -3.,  2*2.
 0,  5,  -1.5,  -3.5,  2*1.
 0,  6,  -0.5,  -3.5,  2*1.
 0,  7,  -1.5,  -2.5,  2*1.
 0,  8,  -0.5,  -2.5,  2*1.
 0,  9,  -3.,  -1.,  2*2.
 0,  10,  -3.5,  -1.5,  2*1.
 0,  11,  -2.5,  -1.5,  2*1.
 0,  12,  -3.5,  -0.5,  2*1.
 0,  13,  -2.5,  -0.5,  2*1.
 0,  14,  2*-1.5,  2*1.
 0,  15,  2*-1.,  2*2.
 0,  16,  -0.5,  -1.5,  2*1.
 0,  17,  -1.5,  -0.5,  2*1.
 0,  18,  2*-0.5,  2*1.
 0,  19,  1.,  -3.,  2*2.
 0,  20,  0.5,  -3.5,  2*1.
 0,  21,  2.,  -2.,  2*4.
 0,  22,  1.5,  -3.5,  2*1.
 0,  23,  0.5,  -2.5,  2*1.
 0,  24,  1.5,  -2.5,  2*1.
 0,  25,  3.,  -3.,  2*2.
 0,  26,  0.5,  -1.5,  2*1.
 0,  27,  1.,  -1.,  2*2.
 0,  28,  1.5,  -1.5,  2*1.
 0,  29,  0.5,  -0.5,  2*1.
 0,  30,  1.5,  -0.5,  2*1.
 0,  31,  2.5,  -1.5,  2*1.
 0,  32,  3.,  -1.,  2*2.
 0,  33,  3.5,  -1.5,  2*1.
 0,  34,  2.5,  -0.5,  2*1.
 0,  35,  3.5,  -0.5,  2*1.
 0,  36,  -2.,  2.,  2*4.
 0,  37,  -3.5,  0.5,  2*1.
 0,  38,  -3.,  1.,  2*2.
 0,  39,  -2.5,  0.5,  2*1.
 0,  40,  -3.5,  1.5,  2*1.
 0,  41,  -2.5,  1.5,  2*1.
 0,  42,  -1.5,  0.5,  2*1.
 0,  43,  -1.,  1.,  2*2.
 0,  44,  -0.5,  0.5,  2*1.
 0,  45,  -1.5,  1.5,  2*1.
 0,  46,  -0.5,  1.5,  2*1.
 0,  47,  -3.,  3.,  2*2.
 0,  48,  -1.5,  2.5,  2*1.
 0,  49,  -1.,  3.,  2*2.
 0,  50,  -0.5,  2.5,  2*1.
 0,  51,  -1.5,  3.5,  2*1.
 0,  52,  -0.5,  3.5,  2*1.
 0,  53,  2*0.5,  2*1.
 0,  54,  2*1.,  2*2.
 0,  55,  2*2.,  2*4.
 0,  56,  1.5,  0.5,  2*1.
 0,  57,  0.5,  1.5,  2*1.
 0,  58,  2*1.5,  2*1.
 0,  59,  3.,  1.,  2*2.
 0,  60,  2.5,  0.5,  2*1.
 0,  61,  3.5,  0.5,  2*1.
 0,  62,  2.5,  1.5,  2*1.
 0,  63,  3.5,  1.5,  2*1.
 0,  64,  1.,  3.,  2*2.
 0,  65,  0.5,  2.5,  2*1.
 0,  66,  1.5,  2.5,  2*1.
 0,  67,  0.5,  3.5,  2*1.
 0,  68,  1.5,  3.5,  2*1.
 0,  69,  2*3.,  2*2.


Step 24. - Check solution.

Explanation:
Your final lines of output should look like this if you are using single precision,

 
   1   2.6343   2.6343   2.6062   2.5514   2.4728   2.3744
   2   2.6343   2.6343   2.6062   2.5514   2.4728   2.3744
   3   2.6062   2.6062   2.5785   2.5247   2.4475   2.3508
   4   2.5514   2.5514   2.5247   2.4727   2.3982   2.3049
   5   2.4728   2.4728   2.4475   2.3982   2.3275   2.2391
   6   2.3744   2.3744   2.3508   2.3049   2.2391   2.1567

or like this with double precision (after modifying the format statement)
 
   1   2.63432009   2.63432009   2.60617704   2.55138273   2.47279885   2.37442856
   2   2.63432009   2.63432009   2.60617704   2.55138273   2.47279885   2.37442856
   3   2.60617704   2.60617704   2.57852729   2.52469358   2.44748775   2.35084293
   4   2.55138273   2.55138273   2.52469358   2.47273061   2.39820857   2.30492442
   5   2.47279885   2.47279885   2.44748775   2.39820857   2.32753714   2.23907542
   6   2.37442856   2.37442856   2.35084293   2.30492442   2.23907542   2.15665446

The final solution is displayed here.


Step 25. - A Parallel Run

The code you have just developed will run in parallel.

Run the code using the command:

mpirun -np X tutor  where X is the number of processors you wish to use.

Check that the last 6 lines of output are the same as before. If they are, then you have successfully completed this tutorial.


Step 26. - Adding Graphics

You can view the results of the code you constructed in the tutorial above.  This requires installing the graphics support for the Chombovis graphics package.  For instuctions on how to install and use Chombovis see http://seesar.lbl.gov/anag/chombo/chomboVis/UsersGuide.html .
You also need to install HDF5 (see: http://www.hdfgroup.org/) and link to its libraries in order for this to work.

Once you have Chombovis installed and working you must execute the following steps:
NOTE: The graphics package VISIT (see:http://www.llnl.gov/visit/) also has the capability to view chombovis files and can be used to view the file that you have just produced.


You can continue with,

A TUTORIAL WITH NO PERMANENT GUARDCELL STORAGE

or go onto,

A TUTORIAL WHICH EXPLAINS USING PARAMESH AS A LIBRARY.

Return to Main Page.