blob: 9675f808ed701d5fecb74e2bc6244996b468f9d0 [file] [log] [blame]
// ************************************************************************
//
// miniAMR: stencil computations with boundary exchange and AMR.
//
// Copyright (2014) Sandia Corporation. Under the terms of Contract
// DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
// retains certain rights in this software.
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation; either version 2.1 of the
// License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Questions? Contact Courtenay T. Vaughan (ctvaugh@sandia.gov)
// Richard F. Barrett (rfbarre@sandia.gov)
//
// ************************************************************************
#include <stdio.h>
#include <stdlib.h>
#include "block.h"
#include "proto.h"
#include "timer.h"
// This routine splits blocks that are being refined into 8 new blocks,
// copies the data over to the new blocks, and then disconnects the
// original block from the mesh and connects the new blocks to the
// mesh. The information in old block is also transferred to a parent
// block, which also contains information to identify its children.
void split_blocks(void)
{
static int side[6][2][2] = { { {0, 2}, {4, 6} }, { {1, 3}, {5, 7} },
{ {0, 1}, {4, 5} }, { {2, 3}, {6, 7} },
{ {0, 1}, {2, 3} }, { {4, 5}, {6, 7} } };
static int off[6] = {1, -1, 2, -2, 4, -4};
int i, j, k, m, n, o, v, nl, xp, yp, zp, c, c1, other,
i1, i2, j1, j2, k1, k2, dir, fcase, pe, f, p,
level, sib[8], offset, d, half_size;
block *bp, *bp1;
parent *pp;
// have to do this by level, else could have a block at a level split and
// its offspring try to connect to a block at a lower (that will be split)
for (m = level = 0; level <= cur_max_level; level++) {
// can not use sorted list here since this routine changes the list
for (n = 0; n < max_active_block; n++)
if (blocks[n].number >= 0 && blocks[n].level == level) {
bp = &blocks[n];
if (bp->refine == 1) {
nl = bp->number - block_start[level];
zp = nl/((p2[level]*npx*init_block_x)*
(p2[level]*npy*init_block_y));
yp = (nl%((p2[level]*npx*init_block_x)*
(p2[level]*npy*init_block_y)))/
(p2[level]*npx*init_block_x);
xp = nl%(p2[level]*npx*init_block_x);
if ((num_active + 8) > max_num_blocks) {
printf("ERROR: Need more blocks %d %d on %d\n", num_active, max_num_blocks, my_pe);
exit(-1);
}
if ((num_active + 8) > local_max_b)
local_max_b = num_active + 8;
del_sorted_list(bp->number, level);
num_active += 7;
num_blocks[level]--;
num_blocks[level+1] += 8;
for (p = 0; p < max_active_parent; p++)
if (parents[p].number < 0)
break;
if (p == max_num_parents) {
printf("ERROR: Need more parents\n");
exit(-1);
}
if (p == max_active_parent)
max_active_parent++;
num_parents++;
num_refined++;
pp = &parents[p];
pp->number = bp->number;
pp->level = bp->level;
pp->parent = bp->parent;
pp->parent_node = bp->parent_node;
pp->child_number = bp->child_number;
parents[pp->parent].child[pp->child_number] = -1 - p;
pp->refine = 0;
pp->cen[0] = bp->cen[0];
pp->cen[1] = bp->cen[1];
pp->cen[2] = bp->cen[2];
// Define the 8 children
for (o = 0; o < 8; o++) {
for ( ; m < max_num_blocks; m++)
if (blocks[m].number < 0)
break;
if (m == max_num_blocks) {
printf("Error: No inactive blocks available %d %d %d\n", m, num_active, max_num_blocks);
exit(-1);
}
if ((m+1) > max_active_block)
max_active_block = m+1;
bp1 = &blocks[m];
sib[o] = m;
pp->child[o] = m;
pp->child_node[o] = my_pe;
bp1->refine = 0;
bp1->level = level + 1;
bp1->parent = p;
bp1->parent_node = my_pe;
bp1->child_number = o;
i1 = (o%2);
j1 = ((o/2)%2);
k1 = (o/4);
bp1->number = ((2*zp+k1)*(p2[level+1]*npy*init_block_y) +
(2*yp+j1))*(p2[level+1]*npx*init_block_x) +
2*xp + i1 + block_start[level+1];
add_sorted_list(m, bp1->number, (level+1));
bp1->cen[0] = bp->cen[0] +
(2*i1 - 1)*p2[num_refine - level - 1];
bp1->cen[1] = bp->cen[1] +
(2*j1 - 1)*p2[num_refine - level - 1];
bp1->cen[2] = bp->cen[2] +
(2*k1 - 1)*p2[num_refine - level - 1];
half_size = p2[num_refine - level - 1];
i1 *= x_block_half;
j1 *= y_block_half;
k1 *= z_block_half;
for (v = 0; v < num_vars; v++)
for (i2 = i = 1; i <= x_block_half; i++, i2+=2)
for (j2 = j = 1; j <= y_block_half; j++, j2+=2)
for (k2 = k = 1; k <= z_block_half; k++, k2+=2)
bp1->array[v][i2 ][j2 ][k2 ] =
bp1->array[v][i2+1][j2 ][k2 ] =
bp1->array[v][i2 ][j2+1][k2 ] =
bp1->array[v][i2+1][j2+1][k2 ] =
bp1->array[v][i2 ][j2 ][k2+1] =
bp1->array[v][i2+1][j2 ][k2+1] =
bp1->array[v][i2 ][j2+1][k2+1] =
bp1->array[v][i2+1][j2+1][k2+1] =
bp->array[v][i+i1][j+j1][k+k1]/8.0;
}
// children all defined - connect children & disconnect parent
for (c = 0; c < 6; c++) {
// deal with internal connections amoung 8 siblings
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++) {
blocks[sib[side[c][i][j]+off[c]]].nei_level[c] =
level + 1;
blocks[sib[side[c][i][j]+off[c]]].nei[c][0][0] =
sib[side[c][i][j]];
}
// deal with external connections
if (bp->nei_level[c] == -2) // external boundary
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++) {
blocks[sib[side[c][i][j]]].nei_level[c] = -2;
blocks[sib[side[c][i][j]]].nei[c][0][0] = 0;
}
else if (bp->nei_level[c] == level-1) { // level less parent
if (bp->nei[c][0][0] >= 0) { // error
printf("%d ERROR: internal misconnect block %d num %d c %d %d\n",
my_pe, n, bp->number, c, bp->nei[c][0][0]);
exit(-1);
}
} else if (bp->nei_level[c] == level) { // paretn level
if (bp->nei[c][0][0] >= 0) {
other = bp->nei[c][0][0];
c1 = (c/2)*2 + (c+1)%2;
blocks[other].nei_level[c1] = level + 1;
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++) {
bp1 = &blocks[sib[side[c][i][j]]];
bp1->nei_level[c] = level;
bp1->nei[c][0][0] = other;
blocks[other].nei[c1][i][j] = sib[side[c][i][j]];
}
}
} else if (bp->nei_level[c] == level+1) { // child level
dir = c/2;
fcase = (c%2)*10;
c1 = (c/2)*2 + (c+1)%2;
d = 2*(c%2) - 1;
for (k = fcase+6, i = 0; i < 2; i++)
for (j = 0; j < 2; j++, k++)
if (bp->nei[c][i][j] >= 0) {
other = bp->nei[c][i][j];
bp1 = &blocks[sib[side[c][i][j]]];
bp1->nei_level[c] = level+1;
bp1->nei[c][0][0] = other;
blocks[other].nei_level[c1] = level + 1;
blocks[other].nei[c1][0][0] = sib[side[c][i][j]];
}
} else {
printf("%d ERROR: misconnected b %d %d l %d nei[%d] %d\n",
my_pe, n, bp->number, level, c, bp->nei_level[c]);
exit(-1);
}
}
/* children all defined and connected - inactivate block */
bp->number = -1;
if (n < m)
m = n;
}
}
}
}
// This routine takes blocks that are to be coarsened and recombines them.
// Before this routine can be called, all of the child blocks need to be on
// the same processor as the parent. A new block is created and the parent
// and child blocks are inactivated.
void consolidate_blocks(void)
{
static int side[6][2][2] = { { {0, 2}, {4, 6} }, { {1, 3}, {5, 7} },
{ {0, 1}, {4, 5} }, { {2, 3}, {6, 7} },
{ {0, 1}, {2, 3} }, { {4, 5}, {6, 7} } };
int n, p, i, j, k, i1, j1, k1, i2, j2, k2, level, o, v, f, c, offset,
other, c1, dir, fcase, pe, nl, pos[3], d, in;
block *bp, *bp1;
parent *pp;
if (stencil == 7) // add to face case when diags are needed
f = 0;
else
f = 1;
// assume that blocks were moved back to node with parent
for (level = cur_max_level; level >= 0; level--)
for (p = 0; p < max_active_parent; p++)
if ((pp = &parents[p])->number >= 0 && pp->level == level &&
pp->refine == -1) {
for (n = 0; n < max_num_blocks; n++)
if (blocks[n].number < 0) // found inactive block
break;
if (n == max_num_blocks) {
printf("Out of free blocks in consolidate_blocks %d\n", my_pe);
exit(-1);
} else
bp = &blocks[n];
if ((n+1) > max_active_block)
max_active_block = n+1;
if ((num_active + 1) > local_max_b)
local_max_b = num_active + 1;
num_active -= 7;
num_reformed++;
num_blocks[level]++;
num_blocks[level+1] -= 8;
bp->number = pp->number;
pp->number = -1;
bp->level = pp->level;
bp->parent = pp->parent;
bp->parent_node = pp->parent_node;
bp->child_number = pp->child_number;
parents[bp->parent].child[bp->child_number] = n;
add_sorted_list(n, bp->number, level);
bp->refine = 0;
bp->cen[0] = pp->cen[0];
bp->cen[1] = pp->cen[1];
bp->cen[2] = pp->cen[2];
// Copy child arrays back to new block.
for (o = 0; o < 8; o++) {
bp1 = &blocks[pp->child[o]];
del_sorted_list(bp1->number, (level+1));
bp1->number = -1;
i1 = (o%2)*x_block_half;
j1 = ((o/2)%2)*y_block_half;
k1 = (o/4)*z_block_half;
for (v = 0; v < num_vars; v++)
for (i2 = i = 1; i <= x_block_half; i++, i2+=2)
for (j2 = j = 1; j <= y_block_half; j++, j2+=2)
for (k2 = k = 1; k <= z_block_half; k++, k2+=2)
bp->array[v][i+i1][j+j1][k+k1] =
bp1->array[v][i2 ][j2 ][k2 ] +
bp1->array[v][i2+1][j2 ][k2 ] +
bp1->array[v][i2 ][j2+1][k2 ] +
bp1->array[v][i2+1][j2+1][k2 ] +
bp1->array[v][i2 ][j2 ][k2+1] +
bp1->array[v][i2+1][j2 ][k2+1] +
bp1->array[v][i2 ][j2+1][k2+1] +
bp1->array[v][i2+1][j2+1][k2+1];
}
// now figure out communication
for (c = 0; c < 6; c++) {
other = pp->child[side[c][0][0]]; // first child on this side
// four options - boundary, level of parent, level of children,
// and level of children + 1 (that are offnode and unrefining)
if (blocks[other].nei_level[c] == -2) {
// external boundary (only need to check one child)
bp->nei_level[c] = -2;
bp->nei_refine[c] = 0;
} else if (blocks[other].nei_level[c] == level) {
// same level as parent
if (blocks[other].nei[c][0][0] >= 0) {
// on node - if it gets consolidated later, it will fix
// the connections at that point
c1 = (c/2)*2 + (c+1)%2;
bp->nei[c][0][0] = blocks[other].nei[c][0][0];
bp->nei_level[c] = level;
bp->nei_refine[c] = 0;
blocks[blocks[other].nei[c][0][0]].nei[c1][0][0] = n;
blocks[blocks[other].nei[c][0][0]].nei_level[c1] = level;
blocks[blocks[other].nei[c][0][0]].nei_refine[c1] = 0;
}
} else {
dir = c/2;
fcase = (c%2)*10;
offset = p2[num_refine - level - 1];
for (k = fcase+6, i = 0; i < 2; i++)
for (j = 0; j < 2; j++, k++) {
other = pp->child[side[c][i][j]];
if (blocks[other].nei[c][0][0] >= 0) {
if (blocks[other].nei_level[c] == level+2) {
printf("%d ERROR: %d con %d block %d c %d wrong level %d\n",
my_pe, p, n, other, c, level);
exit(-1);
}
c1 = (c/2)*2 + (c+1)%2;
bp->nei[c][i][j] = blocks[other].nei[c][0][0];
bp->nei_level[c] = level + 1;
bp->nei_refine[c] = 0;
blocks[blocks[other].nei[c][0][0]].nei[c1][0][0] =
n;
blocks[blocks[other].nei[c][0][0]].nei_level[c1] =
level;
blocks[blocks[other].nei[c][0][0]].nei_refine[c1] =
0;
}
}
}
}
}
}
void add_sorted_list(int n, int number, int level)
{
int i, j;
for (i = sorted_index[level]; i < sorted_index[level+1]; i++)
if (number > sorted_list[i].number)
break;
for (j = sorted_index[num_refine+1]; j > i; j--) {
sorted_list[j].number = sorted_list[j-1].number;
sorted_list[j].n = sorted_list[j-1].n;
}
sorted_list[i].number = number;
sorted_list[i].n = n;
for (i = level+1; i <= (num_refine+1); i++)
sorted_index[i]++;
}
void del_sorted_list(int number, int level)
{
int i, j;
for (i = sorted_index[level]; i < sorted_index[level+1]; i++)
if (number == sorted_list[i].number)
break;
if (number != sorted_list[i].number) {
printf("ERROR: del_sorted_list on %d - number %d not found\n",
my_pe, number);
exit(-1);
}
for (j = level+1; j <= (num_refine+1); j++)
sorted_index[j]--;
for (j = i; j < sorted_index[num_refine+1]; j++) {
sorted_list[j].number = sorted_list[j+1].number;
sorted_list[j].n = sorted_list[j+1].n;
}
}
int find_sorted_list(int number, int level)
{
int i;
for (i = sorted_index[level]; i < sorted_index[level+1]; i++)
if (number == sorted_list[i].number)
return sorted_list[i].n;
printf("ERROR: find_sorted_list on %d - number %d not found\n",
my_pe, number);
exit(-1);
}