44 #include <fei_trilinos_macros.hpp>
45 #include <fei_iostream.hpp>
47 #ifdef HAVE_FEI_AZTECOO
58 #define AZTEC_MPI AZTEC_MPI
67 #include <fei_Aztec_Map.hpp>
68 #include <fei_Aztec_BlockMap.hpp>
69 #include <fei_Aztec_LSVector.hpp>
70 #include <fei_AztecDVBR_Matrix.hpp>
72 namespace fei_trilinos {
78 N_update_(map->getNumLocalBlocks()),
83 orderingUpdate_(NULL),
90 remoteBlockSizes_(NULL)
92 nnzPerRow_ =
new int[N_update_];
94 for(
int i=0; i<N_update_; i++) {
98 Amat_ = AZ_matrix_create(N_update_);
99 Amat_->matrix_type = AZ_VBR_MATRIX;
101 (void(*)(
double*,
double*,AZ_MATRIX_STRUCT*,
int*))AZ_VBR_matvec_mult;
109 AztecDVBR_Matrix::AztecDVBR_Matrix(
const AztecDVBR_Matrix& src)
112 N_update_(src.N_update_),
117 orderingUpdate_(NULL),
118 isLoaded_(src.isLoaded_),
119 isAllocated_(src.isAllocated_),
120 localNNZ_(src.localNNZ_),
124 remoteBlockSizes_(NULL)
137 nnzPerRow_ =
new int[N_update_];
140 for(i=0; i<N_update_; i++) {
141 nnzPerRow_[i] = src.nnzPerRow_[i];
144 Amat_ = AZ_matrix_create(N_update_);
145 Amat_->matrix_type = AZ_VBR_MATRIX;
147 (void(*)(
double*,
double*,AZ_MATRIX_STRUCT*,
int*))AZ_VBR_matvec_mult;
153 Amat_->bpntr =
new int[N_update_+1];
154 for(i=0; i<N_update_+1; i++) Amat_->bpntr[i] = src.Amat_->bpntr[i];
156 int totalNNZBlks = Amat_->bpntr[N_update_];
157 Amat_->bindx =
new int[totalNNZBlks];
158 for(i=0; i<totalNNZBlks; i++) Amat_->bindx[i] = src.Amat_->bindx[i];
160 Amat_->indx =
new int[totalNNZBlks+1];
161 for(i=0; i<totalNNZBlks+1; i++) Amat_->indx[i] = src.Amat_->indx[i];
163 Amat_->val =
new double[localNNZ_];
164 for(i=0; i<localNNZ_; i++) Amat_->val[i] = 0.0;
168 int dataOrgLength = src.data_org_[AZ_total_send] + AZ_send_list;
169 data_org_ = (
int*) AZ_allocate(dataOrgLength *
sizeof(
int));
170 for(i=0; i<dataOrgLength; i++) data_org_[i] = src.data_org_[i];
172 Amat_->data_org = data_org_;
174 int extLength = src.data_org_[AZ_N_ext_blk];
175 external_ = (
int*) AZ_allocate(extLength *
sizeof(
int));
176 extern_index_ = (
int*) AZ_allocate(extLength *
sizeof(
int));
177 for(i=0; i<extLength; i++) {
178 external_[i] = src.external_[i];
179 extern_index_[i] = src.extern_index_[i];
182 update_index_ = (
int*) AZ_allocate(N_update_ *
sizeof(
int));
183 orderingUpdate_ =
new int[N_update_];
184 for(i=0; i<N_update_; i++) {
185 update_index_[i] = src.update_index_[i];
186 orderingUpdate_[i] = src.orderingUpdate_[i];
189 int cpntrLength = N_update_ + src.data_org_[AZ_N_ext_blk] + 1;
190 Amat_->cpntr = (
int*) AZ_allocate(cpntrLength *
sizeof(
int));
191 for(i=0; i<cpntrLength; i++) Amat_->cpntr[i] = src.Amat_->cpntr[i];
196 AztecDVBR_Matrix::~AztecDVBR_Matrix(){
199 delete [] Amat_->val;
200 delete [] Amat_->bindx;
201 delete [] Amat_->rpntr;
202 delete [] Amat_->bpntr;
203 delete [] Amat_->indx;
205 delete [] remoteInds_;
206 delete [] remoteBlockSizes_;
217 delete [] orderingUpdate_;
222 delete [] nnzPerRow_;
225 AZ_matrix_destroy(&Amat_);
230 int AztecDVBR_Matrix::getNumBlocksPerRow(
int blkRow,
int& nnzBlksPerRow)
const {
234 if (!isAllocated())
return(1);
238 if (!inUpdate(blkRow, index)) {
239 fei::console_out() <<
"AztecDVBR_Matrix::getNumBlocksPerRow: ERROR: blkRow "
240 << blkRow <<
" not in local update list." << FEI_ENDL;
244 nnzBlksPerRow = Amat_->bpntr[index+1] - Amat_->bpntr[index];
250 int AztecDVBR_Matrix::getNumBlocksPerRow(
int* nnzBlksPerRow)
const {
257 if (!isAllocated())
return(1);
259 for(
int i=0; i<amap_->getNumLocalBlocks(); i++) {
260 nnzBlksPerRow[i] = Amat_->bpntr[i+1] - Amat_->bpntr[i];
267 int AztecDVBR_Matrix::getNumNonzerosPerRow(
int blkRow,
int& nnzPerRow)
const {
272 if (!isAllocated())
return(1);
276 if (!inUpdate(blkRow, index)) {
277 fei::console_out() <<
"AztecDVBR_Matrix::getNumNonzerosPerRow: ERROR: blkRow "
278 << blkRow <<
" not in local update list." << FEI_ENDL;
282 nnzPerRow = nnzPerRow_[index];
288 int AztecDVBR_Matrix::getNumNonzerosPerRow(
int* nnzPerRow)
const {
296 if (!isAllocated())
return(1);
298 for(
int i=0; i<amap_->getNumLocalBlocks(); i++) {
299 nnzPerRow[i] = nnzPerRow_[i];
306 int AztecDVBR_Matrix::getBlockSize(
int blkRow,
int blkCol,
307 int& ptRows,
int& ptCols) {
313 if (!inUpdate(blkRow, index)) {
315 << blkRow <<
" not in local update list." << FEI_ENDL;
319 ptRows = Amat_->rpntr[index+1] - Amat_->rpntr[index];
321 int local = inUpdate(blkCol, index);
324 ptCols = Amat_->rpntr[index+1] - Amat_->rpntr[index];
327 index = AZ_find_index(blkCol, remoteInds_, numRemoteBlocks_);
329 if (index < 0)
return(1);
330 else ptCols = remoteBlockSizes_[index];
337 void AztecDVBR_Matrix::matvec(
const Aztec_LSVector& x, Aztec_LSVector& y)
const {
343 int *proc_config = amap_->getProcConfig();
344 double *b = (
double*)x.startPointer();
345 double *c = (
double*)y.startPointer();
347 AZ_VBR_matvec_mult(b, c, Amat_, proc_config);
353 void AztecDVBR_Matrix::put(
double s){
355 if (!isAllocated())
return;
357 for(
int i=0; i<localNNZ_; i++) {
365 int AztecDVBR_Matrix::getBlockRow(
int blkRow,
368 int numNzBlks)
const {
370 if (!isAllocated())
return(1);
374 if (!inUpdate(blkRow, index)) {
376 << blkRow <<
" not in local update list." << FEI_ENDL;
386 int nnzBlks = 0, nnzPts = 0;
387 int err = getNumBlocksPerRow(blkRow, nnzBlks);
388 if (err)
return(err);
389 err = getNumNonzerosPerRow(blkRow, nnzPts);
390 if (err)
return(err);
392 if (numNzBlks != nnzBlks)
return(1);
396 const int* blkUpdate = amap_->getBlockUpdate();
397 for(
int indb = Amat_->bpntr[index]; indb<Amat_->bpntr[index+1]; indb++) {
399 int numEntries = Amat_->indx[indb+1] - Amat_->indx[indb];
400 int valOffset = Amat_->indx[indb];
403 int ind = Amat_->bindx[indb];
404 if (ind < N_update_) {
405 blkColInds[blkCounter++] = blkUpdate[orderingUpdate_[ind]];
408 blkColInds[blkCounter++] = external_[ind-N_update_];
412 blkColInds[blkCounter++] = Amat_->bindx[indb];
416 for(
int i=0; i<numEntries; i++) {
417 val[offset + i] = Amat_->val[valOffset + i];
420 offset += numEntries;
427 int AztecDVBR_Matrix::putBlockRow(
int blkRow,
430 int numNzBlks)
const {
432 if (!isAllocated())
return(1);
436 if (!inUpdate(blkRow, index)) {
438 << blkRow <<
" not in local update list." << FEI_ENDL;
449 for(
int blk = 0; blk<numNzBlks; blk++) {
450 int indb = getBindxOffset(blkColInds[blk],
451 Amat_->bpntr[index], Amat_->bpntr[index+1]-1);
453 if (indb < 0) messageAbort(
"putBlockRow: blk col not found in row.");
455 int numEntries = Amat_->indx[indb+1] - Amat_->indx[indb];
456 int valOffset = Amat_->indx[indb];
459 for(
int i=0; i<numEntries; i++) {
460 Amat_->val[valOffset + i] = val[offset + i];
463 offset += numEntries;
470 int AztecDVBR_Matrix::sumIntoBlockRow(
int blkRow,
480 if (!isAllocated())
return(1);
484 if (!inUpdate(blkRow, index)) {
486 << blkRow <<
" not in local update list." << FEI_ENDL;
498 for(
int blk = 0; blk<numNzBlks; blk++) {
499 int indb = getBindxOffset(blkColInds[blk],
500 Amat_->bpntr[index], Amat_->bpntr[index+1]-1);
504 << blkColInds[blk] <<
" not found in row " << blkRow << FEI_ENDL;
508 int numEntries = Amat_->indx[indb+1] - Amat_->indx[indb];
509 int valOffset = Amat_->indx[indb];
512 for(
int i=0; i<numEntries; i++) {
513 Amat_->val[valOffset + i] += val[offset + i];
516 offset += numEntries;
523 void AztecDVBR_Matrix::allocate(
int* numNzBlks,
int* blkColInds) {
531 calcBpntr(numNzBlks);
535 int totalNumNzBlks = Amat_->bpntr[N_update_];
538 setBindx(totalNumNzBlks, blkColInds);
542 calcIndx(totalNumNzBlks);
545 Amat_->val =
new double[localNNZ_];
547 for(
int i=0; i<localNNZ_; i++) {
556 void AztecDVBR_Matrix::loadComplete() {
562 MPI_Comm thisComm = amap_->getCommunicator();
566 MPI_Barrier(thisComm);
570 MPI_Comm_rank(thisComm, &thisProc);
573 AZ_transform(amap_->getProcConfig(), &external_, Amat_->bindx, Amat_->val,
574 amap_->getBlockUpdate(), &update_index_, &extern_index_, &data_org_,
575 N_update_, Amat_->indx, Amat_->bpntr, Amat_->rpntr,
576 &(Amat_->cpntr), AZ_VBR_MATRIX);
578 data_org_[AZ_internal_use] = 1;
580 Amat_->data_org = data_org_;
587 orderingUpdate_ =
new int[N_update_];
588 for(
int ii=0; ii<N_update_; ii++)
589 orderingUpdate_[update_index_[ii]] = ii;
593 MPI_Barrier(thisComm);
602 bool AztecDVBR_Matrix::readFromFile(
const char *filename){
615 MPI_Comm thisComm = amap_->getCommunicator();
617 MPI_Barrier(thisComm);
619 infile = fopen(filename,
"r");
620 if (!infile) messageAbort(
"readFromFile: couldn't open file.");
622 int* num_nz_blocks = NULL;
623 int* blk_col_inds = NULL;
625 readAllocateInfo(infile, num_nz_blocks, blk_col_inds);
627 allocate(num_nz_blocks, blk_col_inds);
629 delete [] num_nz_blocks;
630 delete [] blk_col_inds;
633 infile = fopen(filename,
"r");
635 readMatrixData(infile);
645 void AztecDVBR_Matrix::readAllocateInfo(FILE* infile,
647 int*& blk_col_inds) {
658 if (num_nz_blocks)
delete [] num_nz_blocks;
659 if (blk_col_inds)
delete [] blk_col_inds;
661 num_nz_blocks =
new int[N_update_];
666 int totalNumBlks = 0;
667 int** blkColInds =
new int*[N_update_];
669 for(i=0; i<N_update_; i++) {
670 num_nz_blocks[i] = 0;
671 blkColInds[i] = NULL;
674 int blkRows, blkCols, rows, cols;
678 fgets(line,256,infile);
679 }
while(strchr(line,
'%'));
680 sscanf(line,
"%d %d %d %d",&blkRows, &blkCols, &rows, &cols);
682 if ((blkRows != blkCols) || (rows != cols))
683 messageAbort(
"readAllocateInfo: non-square matrix not allowed.");
685 int br, bc, pr, pc, index;
687 while (!feof(infile)) {
689 fgets(line,256,infile);
690 }
while(strchr(line,
'%'));
692 if(feof(infile))
break;
694 sscanf(line,
"%d %d %d %d", &br, &bc, &pr, &pc);
696 if (inUpdate(br, index)) {
697 if ((bc < 0) || bc >= blkCols) {
699 sprintf(mesg,
"readAllocateInfo: blkCols %d, 0-based col ind %d",
704 insertList(bc, blkColInds[index], num_nz_blocks[index]);
711 blk_col_inds =
new int[totalNumBlks];
714 for(i=0; i<N_update_; i++) {
715 for(
int j=0; j<num_nz_blocks[i]; j++) {
716 blk_col_inds[offset++] = blkColInds[i][j];
719 delete [] blkColInds[i];
722 delete [] blkColInds;
726 void AztecDVBR_Matrix::readMatrixData(FILE* infile) {
728 int blkRows, blkCols, rows, cols;
729 int br, bc, pr, pc, nnz, index;
730 double* blockValues = NULL;
734 fgets(line,256,infile);
735 }
while(strchr(line,
'%'));
736 sscanf(line,
"%d %d %d %d",&blkRows, &blkCols, &rows, &cols);
738 while (!feof(infile)) {
740 fgets(line,256,infile);
741 }
while(strchr(line,
'%'));
743 if(feof(infile))
break;
745 sscanf(line,
"%d %d %d %d %d", &br, &bc, &pr, &pc, &nnz);
747 if (inUpdate(br, index)){
751 blockValues =
new double[nnz];
752 getValuesFromString(line, std::strlen(line)+1, blockValues, nnz);
754 putBlockRow(br, blockValues, &bc, 1);
756 delete [] blockValues;
762 void AztecDVBR_Matrix::getValuesFromString(
char *line,
int len,
double *values,
771 char *offset = &line[0];
773 offset = strchr(offset,
' ');
778 for(i=0; i<lenValues; i++){
779 sscanf(offset,
"%le",&(values[i]));
780 offset = strchr(offset,
' ');
788 bool AztecDVBR_Matrix::writeToFile(
const char *fileName)
const {
790 int thisProc = amap_->getProcConfig()[AZ_node];
791 int numProcs = amap_->getProcConfig()[AZ_N_procs];
792 MPI_Comm thisComm = amap_->getCommunicator();
794 int numGlobalBlocks = amap_->getNumGlobalBlocks();
795 int numGlobalPtEqns = amap_->globalSize();
797 int numLocalBlocks = N_update_;
801 for(
int p=0; p<numProcs; p++) {
802 MPI_Barrier(thisComm);
809 file = fopen(fileName,
"w");
810 fprintf(file,
"%d %d %d %d\n", numGlobalBlocks, numGlobalBlocks,
811 numGlobalPtEqns, numGlobalPtEqns);
815 file = fopen(fileName,
"a");
827 for(
int brow=0; brow<numLocalBlocks; brow++) {
828 int bcolind1 = Amat_->bpntr[brow];
829 int bcolind2 = Amat_->bpntr[brow+1];
831 for(
int ind=bcolind1; ind<bcolind2; ind++) {
832 int nnzPts = Amat_->indx[ind+1] - Amat_->indx[ind];
834 if (nnzPts <= 0)
continue;
836 int blkRowSize = Amat_->rpntr[brow+1]-Amat_->rpntr[brow];
839 int lookup = Amat_->bindx[ind];
841 if (lookup < N_update_) {
842 globCol = amap_->getBlockUpdate()[orderingUpdate_[lookup]];
845 globCol = external_[lookup-N_update_];
852 int globalRow = amap_->getBlockUpdate()[brow];
853 if (isLoaded()) globalRow = amap_->getBlockUpdate()[orderingUpdate_[brow]];
855 fprintf(file,
"%d %d %d %d ", globalRow, globCol,
858 int offset = Amat_->indx[ind];
859 for(
int i=0; i<nnzPts; i++) {
860 fprintf(file,
"%20.13e ", Amat_->val[offset+i]);
874 int AztecDVBR_Matrix::inUpdate(
int globalIndex,
int& localIndex)
const {
882 localIndex = AZ_find_index(globalIndex, amap_->getBlockUpdate(), N_update_);
884 if(localIndex==-1)
return(0);
887 localIndex = update_index_[localIndex];
894 void AztecDVBR_Matrix::calcRpntr() {
903 const int* blkSizes = amap_->getBlockSizes();
905 Amat_->rpntr =
new int[N_update_+1];
909 for(
int i=0; i<N_update_; i++) {
910 Amat_->rpntr[i+1] = Amat_->rpntr[i] + blkSizes[i];
912 messageAbort(
"allocate: negative block size.");
917 void AztecDVBR_Matrix::calcBpntr(
int* numNzBlks) {
925 Amat_->bpntr =
new int[N_update_+1];
929 for(
int i=0; i<N_update_; i++) {
930 Amat_->bpntr[i+1] = Amat_->bpntr[i] + numNzBlks[i];
935 void AztecDVBR_Matrix::setBindx(
int nnzBlks,
int* blkColInds) {
939 Amat_->bindx =
new int[nnzBlks];
941 for(
int i=0; i<nnzBlks; i++) {
942 Amat_->bindx[i] = blkColInds[i];
943 if (blkColInds[i] < 0)
944 messageAbort(
"setBindx: negative block col index.");
949 void AztecDVBR_Matrix::messageAbort(
const char* mesg)
const {
950 fei::console_out() <<
"AztecDVBR_Matrix: ERROR: " << mesg <<
" Aborting." << FEI_ENDL;
955 void AztecDVBR_Matrix::calcIndx(
int nnzBlks) {
965 Amat_->indx =
new int[nnzBlks+1];
972 int numProcs = amap_->getProcConfig()[AZ_N_procs];
976 calcRemoteInds(remoteInds_, numRemoteBlocks_);
979 remoteBlockSizes_ =
new int[numRemoteBlocks_];
980 getRemoteBlkSizes(remoteBlockSizes_, remoteInds_, numRemoteBlocks_);
988 for(
int i=0; i<amap_->getNumLocalBlocks(); i++) {
989 int rowBlkSize = Amat_->rpntr[i+1] - Amat_->rpntr[i];
991 int colStart = Amat_->bpntr[i];
992 int colEnd = Amat_->bpntr[i+1] - 1;
994 for(
int j=colStart; j<=colEnd; j++) {
995 if (inUpdate(Amat_->bindx[j], index)) {
996 int colBlkSize = Amat_->rpntr[index+1] - Amat_->rpntr[index];
998 Amat_->indx[j+1] = Amat_->indx[j] + rowBlkSize*colBlkSize;
1001 if (numProcs == 1) {
1003 sprintf(mesg,
"calcIndx: blk col index %d not in update set.",
1008 index = AZ_find_index(Amat_->bindx[j], remoteInds_,
1011 Amat_->indx[j+1] = Amat_->indx[j] +
1012 rowBlkSize*remoteBlockSizes_[index];
1015 messageAbort(
"calcIndx: block column index not found.");
1020 nnzPerRow_[i] = Amat_->indx[colEnd+1] - Amat_->indx[colStart];
1023 localNNZ_ = Amat_->indx[nnzBlks];
1027 int AztecDVBR_Matrix::getBindxOffset(
int blkInd,
1028 int bpntrStart,
int bpntrEnd)
const {
1035 for(
int i=bpntrStart; i<=bpntrEnd; i++) {
1036 int ind = Amat_->bindx[i];
1039 if (ind < N_update_) {
1040 globalCol = amap_->getBlockUpdate()[orderingUpdate_[ind]];
1043 globalCol = external_[ind-N_update_];
1046 else globalCol = ind;
1048 if (globalCol == blkInd)
return(i);
1055 void AztecDVBR_Matrix::calcRemoteInds(
int*& remoteInds,
int& len) {
1060 int nnzBlks = Amat_->bpntr[amap_->getNumLocalBlocks()];
1063 for(
int i=0; i<nnzBlks; i++) {
1064 if (!inUpdate(Amat_->bindx[i], local)) {
1065 insertList(Amat_->bindx[i], remoteInds, len);
1071 void AztecDVBR_Matrix::getRemoteBlkSizes(
int* remoteBlkSizes,
1084 int numProcs = amap_->getProcConfig()[AZ_N_procs];
1085 int thisProc = amap_->getProcConfig()[AZ_node];
1086 MPI_Comm comm = amap_->getCommunicator();
1088 int* lengths =
new int[numProcs];
1092 MPI_Allgather(&len, 1, MPI_INT, lengths, 1, MPI_INT, comm);
1096 int* offsets =
new int[numProcs];
1099 int totalLength = lengths[0];
1100 for(
int i=1; i<numProcs; i++) {
1101 offsets[i] = offsets[i-1] + lengths[i-1];
1102 totalLength += lengths[i];
1106 int* recvBuf =
new int[totalLength];
1109 MPI_Allgatherv(remoteInds, len, MPI_INT, recvBuf, lengths, offsets,
1114 int* blkSizes =
new int[totalLength];
1117 for(
int j=0; j<totalLength; j++) {
1118 if (inUpdate(recvBuf[j], index)) {
1119 blkSizes[j] = Amat_->rpntr[index+1]-Amat_->rpntr[index];
1121 else blkSizes[j] = 0;
1128 int* recvSizes =
new int[totalLength];
1130 MPI_Allreduce(blkSizes, recvSizes, totalLength, MPI_INT, MPI_SUM, comm);
1134 int offset = offsets[thisProc];
1135 for(
int k=0; k<len; k++) {
1136 remoteBlkSizes[k] = recvSizes[offset + k];
1137 if (recvSizes[offset+k] <= 0)
1138 messageAbort(
"getRemoteBlkSizes: recvd a size <= 0.");
1145 delete [] recvSizes;
1150 void AztecDVBR_Matrix::insertList(
int item,
int*& list,
int& len) {
1167 int index = AZ_find_index(item, list, len);
1169 if (index >= 0)
return;
1171 int* newList =
new int[len+1];
1176 for(
int i=0; i<len; i++) {
1178 if (list[i] < item) newList[i] = list[i];
1184 else newList[i] = list[i-1];
1188 if (inserted) newList[len] = list[len-1];
1189 else newList[len] = item;
1192 if (len > 0)
delete [] list;
std::ostream & console_out()
int numProcs(MPI_Comm comm)