//============================================================================== int AztecDVBR_Matrix::getBlockSize(int blkRow, int blkCol, int& ptRows, int& ptCols) { int index; ptRows = 0; ptCols = 0; if (!inUpdate(blkRow, index)) { fei::console_out() << "AztecDVBR_Matrix::getBlockSize: ERROR: blkRow " << blkRow << " not in local update list." << FEI_ENDL; return(1); } ptRows = Amat_->rpntr[index+1] - Amat_->rpntr[index]; int local = inUpdate(blkCol, index); if (local) { ptCols = Amat_->rpntr[index+1] - Amat_->rpntr[index]; } else { index = AZ_find_index(blkCol, remoteInds_, numRemoteBlocks_); if (index < 0) return(1); else ptCols = remoteBlockSizes_[index]; } return(0); }
//============================================================================== void AztecDVBR_Matrix::readMatrixData(FILE* infile) { int blkRows, blkCols, rows, cols; int br, bc, pr, pc, nnz, index; double* blockValues = NULL; char line[256]; do { fgets(line,256,infile); } while(strchr(line,'%')); sscanf(line,"%d %d %d %d",&blkRows, &blkCols, &rows, &cols); while (!feof(infile)) { do { fgets(line,256,infile); } while(strchr(line,'%')); if(feof(infile))break; sscanf(line, "%d %d %d %d %d", &br, &bc, &pr, &pc, &nnz); if (inUpdate(br, index)){ //br (block-row) is in the local row-space, so let's //plug this block into our matrix data structure. blockValues = new double[nnz]; getValuesFromString(line, std::strlen(line)+1, blockValues, nnz); putBlockRow(br, blockValues, &bc, 1); delete [] blockValues; } } }
//============================================================================== int AztecDVBR_Matrix::getBlockRow(int blkRow, double* val, int* blkColInds, int numNzBlks) const { if (!isAllocated()) return(1); int index; if (!inUpdate(blkRow, index)) { fei::console_out() << "AztecDVBR_Matrix::getBlockRow: ERROR: blkRow " << blkRow << " not in local update list." << FEI_ENDL; return(1); } //for each block, we need to find its block column index //in the bindx array, then go to that same position in the indx //array to find out how many point-entries are in that block. //We can then use the indx entry to go to the val array and get //the data. int nnzBlks = 0, nnzPts = 0; int err = getNumBlocksPerRow(blkRow, nnzBlks); if (err) return(err); err = getNumNonzerosPerRow(blkRow, nnzPts); if (err) return(err); if (numNzBlks != nnzBlks) return(1); int offset = 0; int blkCounter = 0; const int* blkUpdate = amap_->getBlockUpdate(); for(int indb = Amat_->bpntr[index]; indb<Amat_->bpntr[index+1]; indb++) { int numEntries = Amat_->indx[indb+1] - Amat_->indx[indb]; int valOffset = Amat_->indx[indb]; if (isLoaded()) { int ind = Amat_->bindx[indb]; if (ind < N_update_) { blkColInds[blkCounter++] = blkUpdate[orderingUpdate_[ind]]; } else { blkColInds[blkCounter++] = external_[ind-N_update_]; } } else { blkColInds[blkCounter++] = Amat_->bindx[indb]; } //ok, now we're ready to get the stuff. for(int i=0; i<numEntries; i++) { val[offset + i] = Amat_->val[valOffset + i]; } offset += numEntries; } return(0); }
//============================================================================== int AztecDVBR_Matrix::sumIntoBlockRow(int blkRow, double* val, int* blkColInds, int numNzBlks) const { // //This function is the same as putBlockRow, except the values //are summed into any existing values rather than overwriting //them. // if (!isAllocated()) return(1); int index; if (!inUpdate(blkRow, index)) { fei::console_out() << "AztecDVBR_Matrix::sumIntoBlockRow: ERROR: blkRow " << blkRow << " not in local update list." << FEI_ENDL; return(1); } //for each incoming block, we need to find its block column index //in the bindx array, then go to that same position in the indx //array to find out how many (point) entries are in that block. //We can then use the indx entry to go to the val array and store //the data. int offset = 0; for(int blk = 0; blk<numNzBlks; blk++) { int indb = getBindxOffset(blkColInds[blk], Amat_->bpntr[index], Amat_->bpntr[index+1]-1); if (indb < 0) { fei::console_out() << "AztecDVBR_Matrix::sumIntoBlockRow: blk col " << blkColInds[blk] << " not found in row " << blkRow << FEI_ENDL; abort(); } int numEntries = Amat_->indx[indb+1] - Amat_->indx[indb]; int valOffset = Amat_->indx[indb]; //ok, now we're ready to store the stuff. for(int i=0; i<numEntries; i++) { Amat_->val[valOffset + i] += val[offset + i]; } offset += numEntries; } return(0); }
//============================================================================== void AztecDVBR_Matrix::calcRemoteInds(int*& remoteInds, int& len) { // //Form a list of the block column indices that are not in the local //update set. // int nnzBlks = Amat_->bpntr[amap_->getNumLocalBlocks()]; int local; for(int i=0; i<nnzBlks; i++) { if (!inUpdate(Amat_->bindx[i], local)) { insertList(Amat_->bindx[i], remoteInds, len); } } }
//============================================================================== int AztecDVBR_Matrix::getNumBlocksPerRow(int blkRow, int& nnzBlksPerRow) const { // //On return, nnzBlksPerRow will be the number of nonzero blocks in row blkRow. // if (!isAllocated()) return(1); int index; if (!inUpdate(blkRow, index)) { fei::console_out() << "AztecDVBR_Matrix::getNumBlocksPerRow: ERROR: blkRow " << blkRow << " not in local update list." << FEI_ENDL; return(1); } nnzBlksPerRow = Amat_->bpntr[index+1] - Amat_->bpntr[index]; return(0); }
//============================================================================== int AztecDVBR_Matrix::getNumNonzerosPerRow(int blkRow, int& nnzPerRow) const { // //This function finds nnzPerRow, the number of nonzero *point* entries for //row 'blkRow'. // if (!isAllocated()) return(1); int index; if (!inUpdate(blkRow, index)) { fei::console_out() << "AztecDVBR_Matrix::getNumNonzerosPerRow: ERROR: blkRow " << blkRow << " not in local update list." << FEI_ENDL; return(1); } nnzPerRow = nnzPerRow_[index]; return(0); }
//============================================================================== void AztecDVBR_Matrix::calcIndx(int nnzBlks) { // //This function allocates and fills the Amat_->indx array, which holds info //on the number of entries in each nonzero block. // //indx[0..bpntr[M]], (where M = number of local block rows) //indx[0] = 0 //indx[k+1]-indx[k] = number of entries in nonzero block k // Amat_->indx = new int[nnzBlks+1]; //we need to obtain block sizes for all local nonzero blocks. rpntr //gives us the sizes for the blocks with column indices in the local //update set, but we'll have to do some message passing to obtain the //sizes of blocks with column indices in other procs' update sets. int numProcs = amap_->getProcConfig()[AZ_N_procs]; if (numProcs > 1) { //form a list of the column indices that are not local. calcRemoteInds(remoteInds_, numRemoteBlocks_); //now get sizes of blocks that correspond to remote rows. remoteBlockSizes_ = new int[numRemoteBlocks_]; getRemoteBlkSizes(remoteBlockSizes_, remoteInds_, numRemoteBlocks_); } //now we're ready to set the block sizes in Amat_->indx. int index; Amat_->indx[0] = 0; for(int i=0; i<amap_->getNumLocalBlocks(); i++) { int rowBlkSize = Amat_->rpntr[i+1] - Amat_->rpntr[i]; int colStart = Amat_->bpntr[i]; int colEnd = Amat_->bpntr[i+1] - 1; for(int j=colStart; j<=colEnd; j++) { if (inUpdate(Amat_->bindx[j], index)) { int colBlkSize = Amat_->rpntr[index+1] - Amat_->rpntr[index]; Amat_->indx[j+1] = Amat_->indx[j] + rowBlkSize*colBlkSize; } else { //it's a remoteIndex if (numProcs == 1) { char mesg[80]; sprintf(mesg,"calcIndx: blk col index %d not in update set.", Amat_->bindx[j]); messageAbort(mesg); } index = AZ_find_index(Amat_->bindx[j], remoteInds_, numRemoteBlocks_); if (index >= 0) { Amat_->indx[j+1] = Amat_->indx[j] + rowBlkSize*remoteBlockSizes_[index]; } else { //if it wasn't in update or remoteInds, then panic! messageAbort("calcIndx: block column index not found."); } } } // end for j loop nnzPerRow_[i] = Amat_->indx[colEnd+1] - Amat_->indx[colStart]; } // end for i loop localNNZ_ = Amat_->indx[nnzBlks]; }
//============================================================================== void AztecDVBR_Matrix::readAllocateInfo(FILE* infile, int*& num_nz_blocks, int*& blk_col_inds) { // //This function will read through infile and construct the lists //num_nz_blocks (which is the number of nonzero blocks per row) and //blk_col_inds (which is the block-column indices of those blocks). // //It is assumed that these two lists are empty when this function is //called. int i; if (num_nz_blocks) delete [] num_nz_blocks; if (blk_col_inds) delete [] blk_col_inds; num_nz_blocks = new int[N_update_]; //we'll use a 2-D array for constructing the set of block column indices, //because we need to keep them grouped by rows, and we aren't guaranteed //that they'll be grouped by rows in the file. int totalNumBlks = 0; int** blkColInds = new int*[N_update_]; for(i=0; i<N_update_; i++) { num_nz_blocks[i] = 0; blkColInds[i] = NULL; } int blkRows, blkCols, rows, cols; char line[256]; do { fgets(line,256,infile); } while(strchr(line,'%')); sscanf(line,"%d %d %d %d",&blkRows, &blkCols, &rows, &cols); if ((blkRows != blkCols) || (rows != cols)) messageAbort("readAllocateInfo: non-square matrix not allowed."); int br, bc, pr, pc, index; while (!feof(infile)) { do { fgets(line,256,infile); } while(strchr(line,'%')); if(feof(infile))break; sscanf(line, "%d %d %d %d", &br, &bc, &pr, &pc); if (inUpdate(br, index)) { if ((bc < 0) || bc >= blkCols) { char mesg[80]; sprintf(mesg,"readAllocateInfo: blkCols %d, 0-based col ind %d", blkCols, bc); fclose(infile); messageAbort(mesg); } insertList(bc, blkColInds[index], num_nz_blocks[index]); totalNumBlks++; } } //so we've read the whole file, now flatten the 2-D list blkColInds //into the required 1-D list blk_col_inds. blk_col_inds = new int[totalNumBlks]; int offset = 0; for(i=0; i<N_update_; i++) { for(int j=0; j<num_nz_blocks[i]; j++) { blk_col_inds[offset++] = blkColInds[i][j]; } delete [] blkColInds[i]; } delete [] blkColInds; }
//============================================================================== void AztecDVBR_Matrix::getRemoteBlkSizes(int* remoteBlkSizes, int* remoteInds, int len) { // //remoteInds is a sorted list of indices that correspond to rows //in remote processors' update lists. This function will spread the //indices to all processors so that they can provide the blk sizes, //then spread that information back to all processors. // #ifdef FEI_SER return; #else int numProcs = amap_->getProcConfig()[AZ_N_procs]; int thisProc = amap_->getProcConfig()[AZ_node]; MPI_Comm comm = amap_->getCommunicator(); int* lengths = new int[numProcs]; lengths[0] = 0; //gather up the lengths of the lists that each proc will be sending. MPI_Allgather(&len, 1, MPI_INT, lengths, 1, MPI_INT, comm); //now form a list of the offset at which each proc's contribution will //be placed in the all-gathered list. int* offsets = new int[numProcs]; offsets[0] = 0; int totalLength = lengths[0]; for(int i=1; i<numProcs; i++) { offsets[i] = offsets[i-1] + lengths[i-1]; totalLength += lengths[i]; } //now we can allocate the list to recv into. int* recvBuf = new int[totalLength]; //now we're ready to do the gather. MPI_Allgatherv(remoteInds, len, MPI_INT, recvBuf, lengths, offsets, MPI_INT, comm); //now we'll run through the list and put block sizes into a list of //the same length as the total recvBuf list. int* blkSizes = new int[totalLength]; int index; for(int j=0; j<totalLength; j++) { if (inUpdate(recvBuf[j], index)) { blkSizes[j] = Amat_->rpntr[index+1]-Amat_->rpntr[index]; } else blkSizes[j] = 0; } //now we'll reduce this info back onto all processors. We'll use MPI_SUM. //Since the sizes we did NOT supply hold a 0, and each spot in the list //should only have a nonzero size from 1 processor, the result will be //that each spot in the result list has the correct value. int* recvSizes = new int[totalLength]; MPI_Allreduce(blkSizes, recvSizes, totalLength, MPI_INT, MPI_SUM, comm); //and finally, we just need to run our section of the list of recv'd sizes, //and transfer them into the remoteBlkSizes list. int offset = offsets[thisProc]; for(int k=0; k<len; k++) { remoteBlkSizes[k] = recvSizes[offset + k]; if (recvSizes[offset+k] <= 0) messageAbort("getRemoteBlkSizes: recvd a size <= 0."); } delete [] lengths; delete [] offsets; delete [] recvBuf; delete [] blkSizes; delete [] recvSizes; #endif }
// update for input-only block/stream algorithms void BSafe::BSafeContext::update(const CssmData &data) { opStarted = true; check(inUpdate(bsAlgorithm, POINTER(data.data()), data.length(), bsSurrender)); }