blob: 7344f92e756e4597f1b55620f2c7f6117fcb10cf [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 "block.h"
#include "proto.h"
#include "timer.h"
// This file contains routines that determine which blocks are going to
// be refined and which are going to be coarsened.
void refine(int ts)
{
int i, j, n, in, min_b, max_b, sum_b, num_refine_step, num_split,
nm_r, nm_c, nm_t;
double ratio, t1, t2, t3, t4, t5;
block *bp;
t4 = 0.0;
t1 = timer();
if (ts)
num_refine_step = block_change;
else
num_refine_step = num_refine;
for (i = 0; i < num_refine_step; i++) {
for (j = num_refine; j >= 0; j--)
if (num_blocks[j]) {
cur_max_level = j;
break;
}
reset_all();
if (uniform_refine) {
for (in = 0; in < sorted_index[num_refine+1]; in++) {
n = sorted_list[in].n;
bp = &blocks[n];
if (bp->number >= 0)
if (bp->level < num_refine)
bp->refine = 1;
else
bp->refine = 0;
}
} else {
t2 = timer();
check_objects();
timer_refine_co += timer() - t2;
t4 += timer() - t2;
}
t2 = timer();
num_split = refine_level();
t5 = timer();
timer_refine_mr += t5 - t2;
t4 += t5 - t2;
t2 = timer();
split_blocks();
t5 = timer();
timer_refine_sb += t5 - t2;
t4 += t5 - t2;
t2 = timer();
consolidate_blocks();
t5 = timer();
timer_cb_all += t5 - t2;
t4 += t5 - t2;
}
if (target_active || target_max || target_min) {
if (!my_pe) {
for (j = 0; j <= num_refine; j++)
printf("Number of blocks at level %d before target %d is %d\n",
j, ts, num_blocks[j]);
printf("\n");
}
t2 = timer();
global_active = num_blocks[0];
for (i = 1; i <= num_refine; i++)
global_active += num_blocks[i];
// Will not be able to get to target in all cases, but can get to
// a range of target +- 3 since can add or subtract in units of
// 7 blocks.
if ((target_active && global_active > num_pes*target_active + 3) ||
(target_max && global_active > num_pes*target_max))
nm_t += reduce_blocks();
else if ((target_active && global_active < num_pes*target_active - 3) ||
(target_min && global_active < num_pes*target_min))
add_blocks();
t5 = timer();
timer_target_all += t5 - t2;
t4 += t5 - t2;
}
t2 = timer();
if (num_active > local_max_b)
local_max_b = num_active;
if (local_max_b > global_max_b)
global_max_b = local_max_b;
for (j = 0; j <= num_refine; j++) {
if (!j)
global_active = num_blocks[0];
else
global_active += num_blocks[j];
if (!my_pe && report_perf & 8)
printf("Number of blocks at level %d at timestep %d is %d\n",
j, ts, num_blocks[j]);
}
if (!my_pe && report_perf & 8) printf("\n");
t4 += timer() - t2;
t5 = timer();
timer_refine_cc += t5 - t1 - t4;
}
int refine_level(void)
{
int level, nei, n, i, j, b, c, c1, change, unrefine, sib, p, in;
block *bp, *bp1;
parent *pp;
/* block states:
* 1 block should be refined
* -1 block could be unrefined
* 0 block at level 0 and can not be unrefined or
* at max level and can not be refined
*/
// get list of neighbor blocks (indirect links in from blocks)
for (level = cur_max_level; level >= 0; level--) {
/* check for blocks at this level that will refine
their neighbors at this level can not unrefine
their neighbors at a lower level must refine
*/
do {
change = 0;
for (in = sorted_index[level]; in < sorted_index[level+1]; in++) {
n = sorted_list[in].n;
bp = &blocks[n];
if (bp->number >= 0 && bp->level == level) {
if (bp->refine == 1) {
if (bp->parent != -1 && bp->parent_node == my_pe) {
pp = &parents[bp->parent];
if (pp->refine == -1)
pp->refine = 0;
for (b = 0; b < 8; b++)
if (pp->child_node[b] == my_pe && pp->child[b] >= 0)
if (blocks[pp->child[b]].refine == -1) {
blocks[pp->child[b]].refine = 0;
change++;
}
}
for (i = 0; i < 6; i++)
/* neighbors in level above taken care of already */
/* neighbors in this level can not unrefine */
if (bp->nei_level[i] == level) {
if ((nei = bp->nei[i][0][0]) >= 0) { /* on core */
if (blocks[nei].refine == -1) {
blocks[nei].refine = 0;
change++;
if ((p = blocks[nei].parent) != -1 &&
blocks[nei].parent_node == my_pe) {
if ((pp = &parents[p])->refine == -1)
pp->refine = 0;
for (b = 0; b < 8; b++)
if (pp->child_node[b] == my_pe &&
pp->child[b] >= 0)
if (blocks[pp->child[b]].refine == -1) {
blocks[pp->child[b]].refine = 0;
change++;
}
}
}
}
/* neighbors in level below must refine */
} else if (bp->nei_level[i] == level-1)
if ((nei = bp->nei[i][0][0]) >= 0) {
if (blocks[nei].refine != 1) {
blocks[nei].refine = 1;
change++;
}
}
} else if (bp->refine == -1) {
// check if block can be unrefined
for (i = 0; i < 6; i++)
if (bp->nei_level[i] == level+1) {
bp->refine = 0;
change++;
if ((p = bp->parent) != -1 &&
bp->parent_node == my_pe) {
if ((pp = &parents[p])->refine == -1)
pp->refine = 0;
for (b = 0; b < 8; b++)
if (pp->child_node[b] == my_pe &&
pp->child[b] >= 0 &&
blocks[pp->child[b]].refine == -1)
blocks[pp->child[b]].refine = 0;
}
}
}
}
}
} while (change);
/* Check for blocks at this level that will remain at this level
their neighbors at a lower level can not unrefine
*/
do {
change = 0;
for (in = sorted_index[level]; in < sorted_index[level+1]; in++) {
n = sorted_list[in].n;
bp = &blocks[n];
if (bp->number >= 0)
if (bp->level == level && bp->refine == 0)
for (c = 0; c < 6; c++)
if (bp->nei_level[c] == level-1) {
if ((nei = bp->nei[c][0][0]) >= 0) {
if (blocks[nei].refine == -1) {
blocks[nei].refine = 0;
change++;
if ((p = blocks[nei].parent) != -1 &&
blocks[nei].parent_node == my_pe)
if ((pp = &parents[p])->refine == -1) {
pp->refine = 0;
for (b = 0; b < 8; b++)
if (pp->child_node[b] == my_pe &&
pp->child[b] >= 0 &&
blocks[pp->child[b]].refine == -1)
blocks[pp->child[b]].refine = 0;
}
}
}
} else if (bp->nei_level[c] == level) {
if ((nei = bp->nei[c][0][0]) >= 0)
blocks[nei].nei_refine[(c/2)*2+(c+1)%2] = 0;
} else if (bp->nei_level[c] == level+1) {
c1 = (c/2)*2 + (c+1)%2;
for (i = 0; i < 2; i++)
for (j = 0; j < 2; j++)
if ((nei = bp->nei[c][i][j]) >= 0)
blocks[nei].nei_refine[c1] = 0;
}
}
} while (change);
}
for (i = in = 0; in < sorted_index[num_refine+1]; in++)
if (blocks[sorted_list[in].n].refine == 1)
i++;
return(i);
}
// Reset the neighbor lists on blocks so that matching them against objects
// can set those which can be refined.
void reset_all(void)
{
int n, c, in;
block *bp;
parent *pp;
for (in = 0; in < sorted_index[num_refine+1]; in++) {
n = sorted_list[in].n;
if ((bp= &blocks[n])->number >= 0)
bp->refine = -1;
}
for (n = 0; n < max_active_parent; n++)
if ((pp = &parents[n])->number >= 0) {
pp->refine = -1;
for (c = 0; c < 8; c++)
if (pp->child[c] < 0)
pp->refine = 0;
if (pp->refine == 0)
for (c = 0; c < 8; c++)
if (pp->child[c] >= 0)
if (blocks[pp->child[c]].refine == -1)
blocks[pp->child[c]].refine = 0;
}
}