/*BHEADER********************************************************************** * Copyright (c) 2008, Lawrence Livermore National Security, LLC. * Produced at the Lawrence Livermore National Laboratory. * This file is part of HYPRE. See file COPYRIGHT for details. * * HYPRE 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) version 2.1 dated February 1999. * * $Revision: 2.4 $ ***********************************************************************EHEADER*/ /****************************************************************************** * * Member functions for the hypre_BoxNeighbors class. * *****************************************************************************/ #include "headers.h" #define DEBUG 0 #if DEBUG char filename[255]; FILE *file; int my_rank; hypre_Box *box; static int debug_count = 0; #endif /*-------------------------------------------------------------------------- * hypre_RankLinkCreate: *--------------------------------------------------------------------------*/ int hypre_RankLinkCreate( int rank, int prank, hypre_RankLink **rank_link_ptr) { hypre_RankLink *rank_link; rank_link = hypre_TAlloc(hypre_RankLink, 1); hypre_RankLinkRank(rank_link) = rank; hypre_RankLinkPRank(rank_link) = prank; hypre_RankLinkNext(rank_link) = NULL; *rank_link_ptr = rank_link; return 0; } /*-------------------------------------------------------------------------- * hypre_RankLinkDestroy: *--------------------------------------------------------------------------*/ int hypre_RankLinkDestroy( hypre_RankLink *rank_link ) { int ierr = 0; if (rank_link) { hypre_TFree(rank_link); } return ierr; } /*-------------------------------------------------------------------------- * hypre_BoxNeighborsCreate: *--------------------------------------------------------------------------*/ int hypre_BoxNeighborsCreate( hypre_BoxArray *boxes, int *procs, int *ids, int first_local, int num_local, hypre_BoxNeighbors **neighbors_ptr ) { hypre_BoxNeighbors *neighbors; int *boxnums; neighbors = hypre_CTAlloc(hypre_BoxNeighbors, 1); hypre_BoxNeighborsRankLinks(neighbors) = hypre_CTAlloc(hypre_RankLink *, num_local); hypre_BoxNeighborsBoxes(neighbors) = boxes; hypre_BoxNeighborsProcs(neighbors) = procs; hypre_ComputeBoxnums(boxes, procs, &boxnums); hypre_BoxNeighborsBoxnums(neighbors) = boxnums; hypre_BoxNeighborsIDs(neighbors) = ids; hypre_BoxNeighborsFirstLocal(neighbors) = first_local; hypre_BoxNeighborsNumLocal(neighbors) = num_local; *neighbors_ptr = neighbors; return 0; } /*-------------------------------------------------------------------------- * hypre_BoxNeighborsAssemble: * * Add "periodic boxes" to the 'boxes' BoxArray, then find boxes that * are "near" (defined by 'max_distance') the local boxes. The ranks * (in the 'boxes' array) of the nearby boxes of each local box are * stored in a linked list (called 'rank_links') for fast access in * other algorithms. * * If 'prune' is turned on, then only the folowing boxes are kept in * the 'boxes' array: the local boxes, the nearby boxes, and all other * boxes on the same processor as the nearby ones. * * NOTE: A box is not a neighbor of itself. * * NOTE: Periodic boxes are not assigned unique ids. The generating * box and its associated processor/ID information can be found with * index 'i % num_boxes', where 'i' is the index for the periodic box. * *--------------------------------------------------------------------------*/ int hypre_BoxNeighborsAssemble( hypre_BoxNeighbors *neighbors, hypre_Index periodic, int max_distance, int prune ) { hypre_BoxArray *boxes; int *procs; int *boxnums; int *ids; int first_local; int num_local; int num_periods; hypre_Index *pshifts; hypre_IndexRef pshift; int period; int keep_box; int num_boxes; hypre_RankLink **rank_links; hypre_RankLink *rank_link; hypre_Box *local_box; hypre_Box *neighbor_box; int distance; int diff, firstproc, firstproci; int i, j, p, d, ilocal, inew, ii; int px = hypre_IndexX(periodic); int py = hypre_IndexY(periodic); int pz = hypre_IndexZ(periodic); int i_periodic = px ? 1 : 0; int j_periodic = py ? 1 : 0; int k_periodic = pz ? 1 : 0; int ierr = 0; /*-------------------------------------------------- * Create periodic boxes *--------------------------------------------------*/ boxes = hypre_BoxNeighborsBoxes(neighbors); procs = hypre_BoxNeighborsProcs(neighbors); boxnums = hypre_BoxNeighborsBoxnums(neighbors); ids = hypre_BoxNeighborsIDs(neighbors); num_boxes = hypre_BoxArraySize(boxes); num_periods = (1+2*i_periodic) * (1+2*j_periodic) * (1+2*k_periodic); pshifts = hypre_CTAlloc(hypre_Index, num_periods); if( num_periods > 1 ) { int ip, jp, kp; hypre_BoxArraySetSize(boxes, num_periods*num_boxes); procs = hypre_TReAlloc(procs, int, num_periods*num_boxes); p = 1; for (ip = -i_periodic; ip <= i_periodic; ip++) { for (jp = -j_periodic; jp <= j_periodic; jp++) { for (kp = -k_periodic; kp <= k_periodic; kp++) { if( !(ip == 0 && jp == 0 && kp == 0) ) { pshift = pshifts[p]; hypre_SetIndex(pshift, ip*px, jp*py, kp*pz); for (i = 0; i < num_boxes; i++) { inew = i + p*num_boxes; local_box = hypre_BoxArrayBox(boxes, inew); hypre_CopyBox(hypre_BoxArrayBox(boxes, i), local_box); hypre_BoxShiftPos(local_box, pshift); procs[inew] = procs[i]; } p++; } } } } } hypre_BoxNeighborsBoxes(neighbors) = boxes; hypre_BoxNeighborsProcs(neighbors) = procs; hypre_CopyIndex(periodic, hypre_BoxNeighborsPeriodic(neighbors)); hypre_BoxNeighborsNumPeriods(neighbors) = num_periods; hypre_BoxNeighborsPShifts(neighbors) = pshifts; /*----------------------------------------------------------------- * Find neighboring boxes: * * Keep boxes that are nearby plus all other boxes on the same * processor as the nearby boxes. *-----------------------------------------------------------------*/ period = num_boxes; first_local = hypre_BoxNeighborsFirstLocal(neighbors); num_local = hypre_BoxNeighborsNumLocal(neighbors); rank_links = hypre_BoxNeighborsRankLinks(neighbors); inew = 0; num_boxes = 0; firstproc = -1; for (i = 0; i < period; i++) { /* keep all boxes with same process number as nearby boxes */ if (procs[i] > firstproc) { firstproci = i; firstproc = procs[i]; keep_box = 0; } /* loop over box i and its periodic boxes; use ii */ for (p = 0; p < num_periods; p++) { ii = i + p*period; for (j = 0; j < num_local; j++, ilocal++) { ilocal = first_local + j; if (ii == ilocal) { keep_box = 1; } else { local_box = hypre_BoxArrayBox(boxes, ilocal); neighbor_box = hypre_BoxArrayBox(boxes, ii); /* compute distance info */ distance = 0; for (d = 0; d < 3; d++) { diff = hypre_BoxIMinD(neighbor_box, d) - hypre_BoxIMaxD(local_box, d); if (diff > 0) { distance = hypre_max(distance, diff); } diff = hypre_BoxIMinD(local_box, d) - hypre_BoxIMaxD(neighbor_box, d); if (diff > 0) { distance = hypre_max(distance, diff); } } /* if close enough, keep the box */ if (distance <= max_distance) { /* adjust for earlier boxes with same process number */ if (!keep_box) { num_boxes += (i - firstproci); keep_box = 1; } /* create new rank_link and prepend to the list */ hypre_RankLinkCreate(num_boxes, p, &rank_link); hypre_RankLinkNext(rank_link) = rank_links[j]; rank_links[j] = rank_link; } } } } /*----------------------------------------------------------------- * If pruning is on, use procs array to mark the boxes to keep *-----------------------------------------------------------------*/ if (prune) { /* use procs array to store which boxes to keep */ if (keep_box) { if (inew < firstproci) { procs[inew] = firstproci; } inew = i + 1; for (ii = firstproci; ii < inew; ii++) { procs[ii] = -procs[ii]; } firstproci = inew; num_boxes++; } } else { /* keep all of the boxes */ num_boxes++; } } /*----------------------------------------------------------------- * Prune the array of neighbor boxes *-----------------------------------------------------------------*/ if (prune) { for (p = 0; p < num_periods; p++) { i = 0; for (inew = 0; inew < num_boxes; inew++) { if (procs[i] > 0) { i = procs[i]; } hypre_CopyBox(hypre_BoxArrayBox(boxes, i + p*period), hypre_BoxArrayBox(boxes, inew + p*num_boxes)); if (p == 0) { boxnums[inew] = boxnums[i]; ids[inew] = ids[i]; } i++; } } i = 0; for (inew = 0; inew < num_boxes; inew++) { if (procs[i] > 0) { i = procs[i]; } procs[inew] = -procs[i]; if (i == first_local) { first_local = inew; } i++; } for (p = 1; p < num_periods; p++) { for (inew = 0; inew < num_boxes; inew++) { procs[inew + p*num_boxes] = procs[inew]; } } } num_boxes *= num_periods; hypre_BoxArraySetSize(boxes, num_boxes); hypre_BoxNeighborsFirstLocal(neighbors) = first_local; #if DEBUG { int b, k, n; MPI_Comm_rank(MPI_COMM_WORLD, &my_rank); sprintf(filename, "zneighbors.%05d", my_rank); if ((file = fopen(filename, "a")) == NULL) { printf("Error: can't open output file %s\n", filename); exit(1); } fprintf(file, "\n\n============================\n\n"); fprintf(file, "\n\n%d\n\n", debug_count++); fprintf(file, "num_boxes = %d\n", num_boxes); for (i = 0; i < num_boxes; i++) { box = hypre_BoxArrayBox(boxes, i); fprintf(file, "(%d,%d,%d) X (%d,%d,%d) ; (%d,%d); %d\n", hypre_BoxIMinX(box),hypre_BoxIMinY(box),hypre_BoxIMinZ(box), hypre_BoxIMaxX(box),hypre_BoxIMaxY(box),hypre_BoxIMaxZ(box), procs[i], ids[i], hypre_BoxVolume(box)); } fprintf(file, "first_local = %d\n", first_local); fprintf(file, "num_local = %d\n", num_local); fprintf(file, "periodic = %d %d %d\n", periodic[0], periodic[1], periodic[2]); fprintf(file, "num_periods = %d\n", num_periods); fprintf(file, "max_distance = %d\n", max_distance); fprintf(file, "prune = %d\n", prune); fprintf(file, "rank_links:\n"); num_boxes /= num_periods; for (b = 0; b < hypre_BoxNeighborsNumLocal(neighbors); b++) { for (k = -1; k <= 1; k++) { for (j = -1; j <= 1; j++) { for (i = -1; i <= 1; i++) { rank_link = hypre_BoxNeighborsRankLink(neighbors, b, i, j, k); while (rank_link) { n = hypre_RankLinkRank(rank_link) + hypre_RankLinkPRank(rank_link)*num_boxes; fprintf(file, "(%d : %d, %d, %d) = %d\n", b, i, j, k, n); rank_link = hypre_RankLinkNext(rank_link); } } } } } fprintf(file, "\n"); fflush(file); fclose(file); } #endif return ierr; } /*-------------------------------------------------------------------------- * hypre_BoxNeighborsDestroy: *--------------------------------------------------------------------------*/ int hypre_BoxNeighborsDestroy( hypre_BoxNeighbors *neighbors ) { hypre_RankLink *rank_link; hypre_RankLink *next_rank_link; int b; int ierr = 0; if (neighbors) { for (b = 0; b < hypre_BoxNeighborsNumLocal(neighbors); b++) { rank_link = hypre_BoxNeighborsRankLink(neighbors, b); while (rank_link) { next_rank_link = hypre_RankLinkNext(rank_link); hypre_RankLinkDestroy(rank_link); rank_link = next_rank_link; } } hypre_BoxArrayDestroy(hypre_BoxNeighborsBoxes(neighbors)); hypre_TFree(hypre_BoxNeighborsProcs(neighbors)); hypre_TFree(hypre_BoxNeighborsBoxnums(neighbors)); hypre_TFree(hypre_BoxNeighborsIDs(neighbors)); hypre_TFree(hypre_BoxNeighborsPShifts(neighbors)); hypre_TFree(hypre_BoxNeighborsRankLinks(neighbors)); hypre_TFree(neighbors); } return ierr; }