The routine Simulation_initBlock is called by the Grid unit to apply initial conditions to the physical domain. If the AMR grid PARAMESH is being used, the formation of the physical domain starts at the lowest level of refinement. Initial conditions are applied to each block at this level by calling Simulation_initBlock. The Grid unit then checks the refinement criteria in the blocks it has created and refines the blocks if the criteria are met. It then calls Simulation_initBlock to initialize the newly created blocks. This process repeats until the grid reaches the required refinement level in the areas marked for refinement. The Uniform Grid has only one level, with same resolution everywhere. Therefore, only one block per processor is created and Simulation_initBlock is called to initialize this single block. It is important to note that a problem's Simulation_initBlock routine is the same regardless of whether PARAMESH or Uniform Grid is being used. The Grid unit handles these differences, not the Simulation unit.
The basic structure of the routine Simulation_initBlock should be as follows:
We continue to look at the Sod setup and describe its Simulation_initBlock in detail. The first part of the routine contains all the declarations as shown below. The first statement in routine is the use statement, which provides access to the runtime parameters and other unit scope variables initialized in the Simulation_init routine. The include files bring in the needed constants, and then the arguments are defined. The declaration of the local variables is next, with allocatable arrays for each block.
subroutine Simulation_initBlock(blockID)
! get the needed unit scope data
use Simulation_data, ONLY: sim_posn, sim_xCos, sim_yCos, sim_zCos,&
sim_rhoLeft, sim_pLeft, sim_uLeft, &
sim_rhoRight, sim_pRight, sim_uRight, &
sim_smallX, sim_gamma, sim_smallP
use Grid_interfaces, ONLY : Grid_getBlkIndexLimits, Grid_getCellCoords, &
Grid_putPointData
implicit none
! get all the constants
#include "constants.h"
#include "Flash.h"
! define arguments and indicate whether they are input or output
integer, intent(in) :: blockID
! declare all local variables.
integer :: i, j, k, n
integer :: iMax, jMax, kMax
real :: xx, yy, zz, xxL, xxR
real :: lPosn0, lPosn
! arrays to hold coordinate information for the block
real, allocatable, dimension(:) :: xCenter, xLeft, xRight, yCoord, zCoord
! array to get integer indices defining the beginning and the end
! of a block.
integer, dimension(2,MDIM) :: blkLimits, blkLimitsGC
! the number of grid points along each dimension
integer :: sizeX, sizeY, sizeZ
integer, dimension(MDIM) :: axis
integer :: dataSize
logical :: gcell = .true.
! these variables store the calculated initial values of physical
! variables a grid point at a time.
real :: rhoZone, velxZone, velyZone, velzZone, presZone, &
enerZone, ekinZone
Note that FLASH promotes all floating point variables to double precision at compile time for maximum portability. We therefore declare all floating point variables with real in the source code. In the next part of the code we allocate the arrays that will hold the coordinates.
! get the integer endpoints of the block in all dimensions ! the array blkLimits returns the interior end points ! whereas array blkLimitsGC returns endpoints including guardcells call Grid_getBlkIndexLimits(blockId,blkLimits,blkLimitsGC) ! get the size along each dimension for allocation and then allocate sizeX = blkLimitsGC(HIGH,IAXIS) sizeY = blkLimitsGC(HIGH,JAXIS) sizeZ = blkLimitsGC(HIGH,KAXIS) allocate(xLeft(sizeX)) allocate(xRight(sizeX)) allocate(xCenter(sizeX)) allocate(yCoord(sizeY)) allocate(zCoord(sizeZ))
The next part of the routine involves setting up the initial conditions. This section could be code for interpolating a given set of initial conditions, constructing some analytic model, or reading in a table of initial values. In the present example, we begin by getting the coordinates for the cells in the current block. This is done by a set of calls to Grid_getCellCoords . Next we create loops that compute appropriate values for each grid point, since we are constructing initial conditions from a model. Note that we use the blkLimits array from Grid_getBlkIndexLimits in looping over the spatial indices to initialize only the interior cells in the block. To initialize the entire block, including the guardcells, the blkLimitsGC array should be used.
xCoord(:) = 0.0
yCoord(:) = 0.0
zCoord(:) = 0.0
call Grid_getCellCoords(IAXIS, blockID, LEFT_EDGE, gcell, xLeft, sizeX)
call Grid_getCellCoords(IAXIS, blockID, CENTER, gcell, xCenter, sizeX)
call Grid_getCellCoords(IAXIS, blockID, RIGHT_EDGE, gcell, xRight, sizeX)
call Grid_getCellCoords(JAXIS, blockID, CENTER, gcell, yCoord, sizeY)
call Grid_getCellCoords(KAXIS, blockID, CENTER, gcell, zCoord, sizeZ)
!---------------------------------------
! loop over all of the zones in the current block and set the variables.
!---------------------------------------
do k = blkLimits(LOW,KAXIS),blkLimits(HIGH,KAXIS)
zz = zCoord(k) ! coordinates of the cell center in the z-direction
lPosn0 = sim_posn - zz*sim_zCos/sim_xCos ! Where along the x-axis
! the shock intersects
! the xz-plane at the current z.
do j = blkLimits(LOW,JAXIS),blkLimits(HIGH,JAXIS)
yy = yCoord(j) ! center coordinates in the y-direction
lPosn = lPosn0 - yy*sim_yCos/sim_xCos ! The position of the
! shock in the current yz-row.
dataSize = 1 ! for Grid put data function, we are
! initializing a single cell at a time and
! sending it to Grid
do i = blkLimits(LOW,IAXIS),blkLimits(HIGH,IAXIS)
xx = xCenter(i) ! center coordinate along x
xxL = xLeft(i) ! left coordinate along y
xxR = xRight(i) ! right coordinate along z
For the present problem, we create a discontinuity along the shock plane. We do this by initializing the grid points to the left of the shock plane with one value, and the grid points to the right of the shock plane with another value. Recall that the runtime parameters which provide these values are available to us through the Simulation_data module. At this point we can initialize all independent physical variables at each grid point. The following code shows the contents of the loops. Don't forget to store the calculated values in the Grid data structure!
if (xxR <= lPosn) then
rhoZone = sim_rhoLeft
presZone = sim_pLeft
velxZone = sim_uLeft * sim_xCos
velyZone = sim_uLeft * sim_yCos
velzZone = sim_uLeft * sim_zCos
! initialize cells which straddle the shock. Treat them as though 1/2 of
! the cell lay to the left and 1/2 lay to the right.
elseif ((xxL < lPosn) .and. (xxR > lPosn)) then
rhoZone = 0.5 * (sim_rhoLeft+sim_rhoRight)
presZone = 0.5 * (sim_pLeft+sim_pRight)
velxZone = 0.5 *(sim_uLeft+sim_uRight) * sim_xCos
velyZone = 0.5 *(sim_uLeft+sim_uRight) * sim_yCos
velzZone = 0.5 *(sim_uLeft+sim_uRight) * sim_zCos
! initialize cells to the right of the initial shock.
else
rhoZone = sim_rhoRight
presZone = sim_pRight
velxZone = sim_uRight * sim_xCos
velyZone = sim_uRight * sim_yCos
velzZone = sim_uRight * sim_zCos
endif
axis(IAXIS) = i ! Get the position of the cell in the block
axis(JAXIS) = j
axis(KAXIS) = k
! Compute the gas energy and set the gamma-values
! needed for the equation of state.
ekinZone = 0.5 * (velxZone**2 + velyZone**2 + velzZone**2)
enerZone = presZone / (sim_gamma-1.)
enerZone = enerZone / rhoZone
enerZone = enerZone + ekinZone
enerZone = max(enerZone, sim_smallP)
! store the variables in the current zone via the Grid_putPointData method
call Grid_putPointData(blockId, CENTER, DENS_VAR, EXTERIOR, axis, rhoZone)
call Grid_putPointData(blockId, CENTER, PRES_VAR, EXTERIOR, axis, presZone)
call Grid_putPointData(blockId, CENTER, VELX_VAR, EXTERIOR, axis, velxZone)
call Grid_putPointData(blockId, CENTER, VELY_VAR, EXTERIOR, axis, velyZone)
call Grid_putPointData(blockId, CENTER, VELZ_VAR, EXTERIOR, axis, velzZone)
call Grid_putPointData(blockId, CENTER, ENER_VAR, EXTERIOR, axis, enerZone)
call Grid_putPointData(blockId, CENTER, GAME_VAR, EXTERIOR, axis, sim_gamma)
call Grid_putPointData(blockId, CENTER, GAMC_VAR, EXTERIOR, axis, sim_gamma)
When Simulation_initBlock returns, the Grid data structures for physical variables have the values of the initial model for the current block. As mentioned before, Simulation_initBlock is called for every block that is created as the code refines the initial model.