1 #include <../src/mat/impls/elemental/matelemimpl.h> /*I "petscmat.h" I*/ 2 3 /* 4 The variable Petsc_Elemental_keyval is used to indicate an MPI attribute that 5 is attached to a communicator, in this case the attribute is a Mat_Elemental_Grid 6 */ 7 static PetscMPIInt Petsc_Elemental_keyval = MPI_KEYVAL_INVALID; 8 9 /*@C 10 PetscElementalInitializePackage - Initialize Elemental package 11 12 Logically Collective 13 14 Level: developer 15 16 .seealso: MATELEMENTAL, PetscElementalFinalizePackage() 17 @*/ 18 PetscErrorCode PetscElementalInitializePackage(void) 19 { 20 PetscErrorCode ierr; 21 22 PetscFunctionBegin; 23 if (El::Initialized()) PetscFunctionReturn(0); 24 El::Initialize(); /* called by the 1st call of MatCreate_Elemental */ 25 ierr = PetscRegisterFinalize(PetscElementalFinalizePackage);CHKERRQ(ierr); 26 PetscFunctionReturn(0); 27 } 28 29 /*@C 30 PetscElementalFinalizePackage - Finalize Elemental package 31 32 Logically Collective 33 34 Level: developer 35 36 .seealso: MATELEMENTAL, PetscElementalInitializePackage() 37 @*/ 38 PetscErrorCode PetscElementalFinalizePackage(void) 39 { 40 PetscFunctionBegin; 41 El::Finalize(); /* called by PetscFinalize() */ 42 PetscFunctionReturn(0); 43 } 44 45 static PetscErrorCode MatView_Elemental(Mat A,PetscViewer viewer) 46 { 47 PetscErrorCode ierr; 48 Mat_Elemental *a = (Mat_Elemental*)A->data; 49 PetscBool iascii; 50 51 PetscFunctionBegin; 52 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 53 if (iascii) { 54 PetscViewerFormat format; 55 ierr = PetscViewerGetFormat(viewer,&format);CHKERRQ(ierr); 56 if (format == PETSC_VIEWER_ASCII_INFO) { 57 /* call elemental viewing function */ 58 ierr = PetscViewerASCIIPrintf(viewer,"Elemental run parameters:\n");CHKERRQ(ierr); 59 ierr = PetscViewerASCIIPrintf(viewer," allocated entries=%d\n",(*a->emat).AllocatedMemory());CHKERRQ(ierr); 60 ierr = PetscViewerASCIIPrintf(viewer," grid height=%d, grid width=%d\n",(*a->emat).Grid().Height(),(*a->emat).Grid().Width());CHKERRQ(ierr); 61 if (format == PETSC_VIEWER_ASCII_FACTOR_INFO) { 62 /* call elemental viewing function */ 63 ierr = PetscPrintf(PetscObjectComm((PetscObject)viewer),"test matview_elemental 2\n");CHKERRQ(ierr); 64 } 65 66 } else if (format == PETSC_VIEWER_DEFAULT) { 67 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 68 El::Print( *a->emat, "Elemental matrix (cyclic ordering)" ); 69 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 70 if (A->factortype == MAT_FACTOR_NONE){ 71 Mat Adense; 72 ierr = PetscPrintf(PetscObjectComm((PetscObject)viewer),"Elemental matrix (explicit ordering)\n");CHKERRQ(ierr); 73 ierr = MatConvert(A,MATDENSE,MAT_INITIAL_MATRIX,&Adense);CHKERRQ(ierr); 74 ierr = MatView(Adense,viewer);CHKERRQ(ierr); 75 ierr = MatDestroy(&Adense);CHKERRQ(ierr); 76 } 77 } else SETERRQ(PetscObjectComm((PetscObject)viewer),PETSC_ERR_SUP,"Format"); 78 } else { 79 /* convert to dense format and call MatView() */ 80 Mat Adense; 81 ierr = PetscPrintf(PetscObjectComm((PetscObject)viewer),"Elemental matrix (explicit ordering)\n");CHKERRQ(ierr); 82 ierr = MatConvert(A,MATDENSE,MAT_INITIAL_MATRIX,&Adense);CHKERRQ(ierr); 83 ierr = MatView(Adense,viewer);CHKERRQ(ierr); 84 ierr = MatDestroy(&Adense);CHKERRQ(ierr); 85 } 86 PetscFunctionReturn(0); 87 } 88 89 static PetscErrorCode MatGetInfo_Elemental(Mat A,MatInfoType flag,MatInfo *info) 90 { 91 Mat_Elemental *a = (Mat_Elemental*)A->data; 92 93 PetscFunctionBegin; 94 info->block_size = 1.0; 95 96 if (flag == MAT_LOCAL) { 97 info->nz_allocated = (double)(*a->emat).AllocatedMemory(); /* locally allocated */ 98 info->nz_used = info->nz_allocated; 99 } else if (flag == MAT_GLOBAL_MAX) { 100 //ierr = MPIU_Allreduce(isend,irecv,5,MPIU_REAL,MPIU_MAX,PetscObjectComm((PetscObject)matin));CHKERRQ(ierr); 101 /* see MatGetInfo_MPIAIJ() for getting global info->nz_allocated! */ 102 //SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP," MAT_GLOBAL_MAX not written yet"); 103 } else if (flag == MAT_GLOBAL_SUM) { 104 //SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP," MAT_GLOBAL_SUM not written yet"); 105 info->nz_allocated = (double)(*a->emat).AllocatedMemory(); /* locally allocated */ 106 info->nz_used = info->nz_allocated; /* assume Elemental does accurate allocation */ 107 //ierr = MPIU_Allreduce(isend,irecv,1,MPIU_REAL,MPIU_SUM,PetscObjectComm((PetscObject)A));CHKERRQ(ierr); 108 //PetscPrintf(PETSC_COMM_SELF," ... [%d] locally allocated %g\n",rank,info->nz_allocated); 109 } 110 111 info->nz_unneeded = 0.0; 112 info->assemblies = (double)A->num_ass; 113 info->mallocs = 0; 114 info->memory = ((PetscObject)A)->mem; 115 info->fill_ratio_given = 0; /* determined by Elemental */ 116 info->fill_ratio_needed = 0; 117 info->factor_mallocs = 0; 118 PetscFunctionReturn(0); 119 } 120 121 PetscErrorCode MatSetOption_Elemental(Mat A,MatOption op,PetscBool flg) 122 { 123 Mat_Elemental *a = (Mat_Elemental*)A->data; 124 125 PetscFunctionBegin; 126 switch (op) { 127 case MAT_NEW_NONZERO_LOCATIONS: 128 case MAT_NEW_NONZERO_LOCATION_ERR: 129 case MAT_NEW_NONZERO_ALLOCATION_ERR: 130 case MAT_SYMMETRIC: 131 break; 132 case MAT_ROW_ORIENTED: 133 a->roworiented = flg; 134 break; 135 default: 136 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"unknown option %s",MatOptions[op]); 137 } 138 PetscFunctionReturn(0); 139 } 140 141 static PetscErrorCode MatSetValues_Elemental(Mat A,PetscInt nr,const PetscInt *rows,PetscInt nc,const PetscInt *cols,const PetscScalar *vals,InsertMode imode) 142 { 143 Mat_Elemental *a = (Mat_Elemental*)A->data; 144 PetscInt i,j,rrank,ridx,crank,cidx,erow,ecol,numQueues=0; 145 146 PetscFunctionBegin; 147 // TODO: Initialize matrix to all zeros? 148 149 // Count the number of queues from this process 150 if (a->roworiented) { 151 for (i=0; i<nr; i++) { 152 if (rows[i] < 0) continue; 153 P2RO(A,0,rows[i],&rrank,&ridx); 154 RO2E(A,0,rrank,ridx,&erow); 155 if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Incorrect row translation"); 156 for (j=0; j<nc; j++) { 157 if (cols[j] < 0) continue; 158 P2RO(A,1,cols[j],&crank,&cidx); 159 RO2E(A,1,crank,cidx,&ecol); 160 if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Incorrect col translation"); 161 if (!a->emat->IsLocal(erow,ecol) ){ /* off-proc entry */ 162 /* printf("Will later remotely update (%d,%d)\n",erow,ecol); */ 163 if (imode != ADD_VALUES) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only ADD_VALUES to off-processor entry is supported"); 164 ++numQueues; 165 continue; 166 } 167 /* printf("Locally updating (%d,%d)\n",erow,ecol); */ 168 switch (imode) { 169 case INSERT_VALUES: a->emat->Set(erow,ecol,(PetscElemScalar)vals[i*nc+j]); break; 170 case ADD_VALUES: a->emat->Update(erow,ecol,(PetscElemScalar)vals[i*nc+j]); break; 171 default: SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support for InsertMode %d",(int)imode); 172 } 173 } 174 } 175 176 /* printf("numQueues=%d\n",numQueues); */ 177 a->emat->Reserve( numQueues ); 178 for (i=0; i<nr; i++) { 179 if (rows[i] < 0) continue; 180 P2RO(A,0,rows[i],&rrank,&ridx); 181 RO2E(A,0,rrank,ridx,&erow); 182 for (j=0; j<nc; j++) { 183 if (cols[j] < 0) continue; 184 P2RO(A,1,cols[j],&crank,&cidx); 185 RO2E(A,1,crank,cidx,&ecol); 186 if ( !a->emat->IsLocal(erow,ecol) ) { /*off-proc entry*/ 187 /* printf("Queueing remotely update of (%d,%d)\n",erow,ecol); */ 188 a->emat->QueueUpdate( erow, ecol, vals[i*nc+j] ); 189 } 190 } 191 } 192 } else { /* columnoriented */ 193 for (j=0; j<nc; j++) { 194 if (cols[j] < 0) continue; 195 P2RO(A,1,cols[j],&crank,&cidx); 196 RO2E(A,1,crank,cidx,&ecol); 197 if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Incorrect col translation"); 198 for (i=0; i<nr; i++) { 199 if (rows[i] < 0) continue; 200 P2RO(A,0,rows[i],&rrank,&ridx); 201 RO2E(A,0,rrank,ridx,&erow); 202 if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_PLIB,"Incorrect row translation"); 203 if (!a->emat->IsLocal(erow,ecol) ){ /* off-proc entry */ 204 /* printf("Will later remotely update (%d,%d)\n",erow,ecol); */ 205 if (imode != ADD_VALUES) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Only ADD_VALUES to off-processor entry is supported"); 206 ++numQueues; 207 continue; 208 } 209 /* printf("Locally updating (%d,%d)\n",erow,ecol); */ 210 switch (imode) { 211 case INSERT_VALUES: a->emat->Set(erow,ecol,(PetscElemScalar)vals[i+j*nr]); break; 212 case ADD_VALUES: a->emat->Update(erow,ecol,(PetscElemScalar)vals[i+j*nr]); break; 213 default: SETERRQ1(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"No support for InsertMode %d",(int)imode); 214 } 215 } 216 } 217 218 /* printf("numQueues=%d\n",numQueues); */ 219 a->emat->Reserve( numQueues ); 220 for (j=0; j<nc; j++) { 221 if (cols[j] < 0) continue; 222 P2RO(A,1,cols[j],&crank,&cidx); 223 RO2E(A,1,crank,cidx,&ecol); 224 225 for (i=0; i<nr; i++) { 226 if (rows[i] < 0) continue; 227 P2RO(A,0,rows[i],&rrank,&ridx); 228 RO2E(A,0,rrank,ridx,&erow); 229 if ( !a->emat->IsLocal(erow,ecol) ) { /*off-proc entry*/ 230 /* printf("Queueing remotely update of (%d,%d)\n",erow,ecol); */ 231 a->emat->QueueUpdate( erow, ecol, vals[i+j*nr] ); 232 } 233 } 234 } 235 } 236 PetscFunctionReturn(0); 237 } 238 239 static PetscErrorCode MatMult_Elemental(Mat A,Vec X,Vec Y) 240 { 241 Mat_Elemental *a = (Mat_Elemental*)A->data; 242 PetscErrorCode ierr; 243 const PetscElemScalar *x; 244 PetscElemScalar *y; 245 PetscElemScalar one = 1,zero = 0; 246 247 PetscFunctionBegin; 248 ierr = VecGetArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr); 249 ierr = VecGetArray(Y,(PetscScalar **)&y);CHKERRQ(ierr); 250 { /* Scoping so that constructor is called before pointer is returned */ 251 El::DistMatrix<PetscElemScalar,El::VC,El::STAR> xe, ye; 252 xe.LockedAttach(A->cmap->N,1,*a->grid,0,0,x,A->cmap->n); 253 ye.Attach(A->rmap->N,1,*a->grid,0,0,y,A->rmap->n); 254 El::Gemv(El::NORMAL,one,*a->emat,xe,zero,ye); 255 } 256 ierr = VecRestoreArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr); 257 ierr = VecRestoreArray(Y,(PetscScalar **)&y);CHKERRQ(ierr); 258 PetscFunctionReturn(0); 259 } 260 261 static PetscErrorCode MatMultTranspose_Elemental(Mat A,Vec X,Vec Y) 262 { 263 Mat_Elemental *a = (Mat_Elemental*)A->data; 264 PetscErrorCode ierr; 265 const PetscElemScalar *x; 266 PetscElemScalar *y; 267 PetscElemScalar one = 1,zero = 0; 268 269 PetscFunctionBegin; 270 ierr = VecGetArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr); 271 ierr = VecGetArray(Y,(PetscScalar **)&y);CHKERRQ(ierr); 272 { /* Scoping so that constructor is called before pointer is returned */ 273 El::DistMatrix<PetscElemScalar,El::VC,El::STAR> xe, ye; 274 xe.LockedAttach(A->rmap->N,1,*a->grid,0,0,x,A->rmap->n); 275 ye.Attach(A->cmap->N,1,*a->grid,0,0,y,A->cmap->n); 276 El::Gemv(El::TRANSPOSE,one,*a->emat,xe,zero,ye); 277 } 278 ierr = VecRestoreArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr); 279 ierr = VecRestoreArray(Y,(PetscScalar **)&y);CHKERRQ(ierr); 280 PetscFunctionReturn(0); 281 } 282 283 static PetscErrorCode MatMultAdd_Elemental(Mat A,Vec X,Vec Y,Vec Z) 284 { 285 Mat_Elemental *a = (Mat_Elemental*)A->data; 286 PetscErrorCode ierr; 287 const PetscElemScalar *x; 288 PetscElemScalar *z; 289 PetscElemScalar one = 1; 290 291 PetscFunctionBegin; 292 if (Y != Z) {ierr = VecCopy(Y,Z);CHKERRQ(ierr);} 293 ierr = VecGetArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr); 294 ierr = VecGetArray(Z,(PetscScalar **)&z);CHKERRQ(ierr); 295 { /* Scoping so that constructor is called before pointer is returned */ 296 El::DistMatrix<PetscElemScalar,El::VC,El::STAR> xe, ze; 297 xe.LockedAttach(A->cmap->N,1,*a->grid,0,0,x,A->cmap->n); 298 ze.Attach(A->rmap->N,1,*a->grid,0,0,z,A->rmap->n); 299 El::Gemv(El::NORMAL,one,*a->emat,xe,one,ze); 300 } 301 ierr = VecRestoreArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr); 302 ierr = VecRestoreArray(Z,(PetscScalar **)&z);CHKERRQ(ierr); 303 PetscFunctionReturn(0); 304 } 305 306 static PetscErrorCode MatMultTransposeAdd_Elemental(Mat A,Vec X,Vec Y,Vec Z) 307 { 308 Mat_Elemental *a = (Mat_Elemental*)A->data; 309 PetscErrorCode ierr; 310 const PetscElemScalar *x; 311 PetscElemScalar *z; 312 PetscElemScalar one = 1; 313 314 PetscFunctionBegin; 315 if (Y != Z) {ierr = VecCopy(Y,Z);CHKERRQ(ierr);} 316 ierr = VecGetArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr); 317 ierr = VecGetArray(Z,(PetscScalar **)&z);CHKERRQ(ierr); 318 { /* Scoping so that constructor is called before pointer is returned */ 319 El::DistMatrix<PetscElemScalar,El::VC,El::STAR> xe, ze; 320 xe.LockedAttach(A->rmap->N,1,*a->grid,0,0,x,A->rmap->n); 321 ze.Attach(A->cmap->N,1,*a->grid,0,0,z,A->cmap->n); 322 El::Gemv(El::TRANSPOSE,one,*a->emat,xe,one,ze); 323 } 324 ierr = VecRestoreArrayRead(X,(const PetscScalar **)&x);CHKERRQ(ierr); 325 ierr = VecRestoreArray(Z,(PetscScalar **)&z);CHKERRQ(ierr); 326 PetscFunctionReturn(0); 327 } 328 329 static PetscErrorCode MatMatMultNumeric_Elemental(Mat A,Mat B,Mat C) 330 { 331 Mat_Elemental *a = (Mat_Elemental*)A->data; 332 Mat_Elemental *b = (Mat_Elemental*)B->data; 333 Mat_Elemental *c = (Mat_Elemental*)C->data; 334 PetscElemScalar one = 1,zero = 0; 335 336 PetscFunctionBegin; 337 { /* Scoping so that constructor is called before pointer is returned */ 338 El::Gemm(El::NORMAL,El::NORMAL,one,*a->emat,*b->emat,zero,*c->emat); 339 } 340 C->assembled = PETSC_TRUE; 341 PetscFunctionReturn(0); 342 } 343 344 static PetscErrorCode MatMatMultSymbolic_Elemental(Mat A,Mat B,PetscReal fill,Mat *C) 345 { 346 PetscErrorCode ierr; 347 Mat Ce; 348 MPI_Comm comm; 349 350 PetscFunctionBegin; 351 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 352 ierr = MatCreate(comm,&Ce);CHKERRQ(ierr); 353 ierr = MatSetSizes(Ce,A->rmap->n,B->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 354 ierr = MatSetType(Ce,MATELEMENTAL);CHKERRQ(ierr); 355 ierr = MatSetUp(Ce);CHKERRQ(ierr); 356 *C = Ce; 357 PetscFunctionReturn(0); 358 } 359 360 static PetscErrorCode MatMatMult_Elemental(Mat A,Mat B,MatReuse scall,PetscReal fill,Mat *C) 361 { 362 PetscErrorCode ierr; 363 364 PetscFunctionBegin; 365 if (scall == MAT_INITIAL_MATRIX){ 366 ierr = PetscLogEventBegin(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr); 367 ierr = MatMatMultSymbolic_Elemental(A,B,1.0,C);CHKERRQ(ierr); 368 ierr = PetscLogEventEnd(MAT_MatMultSymbolic,A,B,0,0);CHKERRQ(ierr); 369 } 370 ierr = PetscLogEventBegin(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr); 371 ierr = MatMatMultNumeric_Elemental(A,B,*C);CHKERRQ(ierr); 372 ierr = PetscLogEventEnd(MAT_MatMultNumeric,A,B,0,0);CHKERRQ(ierr); 373 PetscFunctionReturn(0); 374 } 375 376 static PetscErrorCode MatMatTransposeMultNumeric_Elemental(Mat A,Mat B,Mat C) 377 { 378 Mat_Elemental *a = (Mat_Elemental*)A->data; 379 Mat_Elemental *b = (Mat_Elemental*)B->data; 380 Mat_Elemental *c = (Mat_Elemental*)C->data; 381 PetscElemScalar one = 1,zero = 0; 382 383 PetscFunctionBegin; 384 { /* Scoping so that constructor is called before pointer is returned */ 385 El::Gemm(El::NORMAL,El::TRANSPOSE,one,*a->emat,*b->emat,zero,*c->emat); 386 } 387 C->assembled = PETSC_TRUE; 388 PetscFunctionReturn(0); 389 } 390 391 static PetscErrorCode MatMatTransposeMultSymbolic_Elemental(Mat A,Mat B,PetscReal fill,Mat *C) 392 { 393 PetscErrorCode ierr; 394 Mat Ce; 395 MPI_Comm comm; 396 397 PetscFunctionBegin; 398 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 399 ierr = MatCreate(comm,&Ce);CHKERRQ(ierr); 400 ierr = MatSetSizes(Ce,A->rmap->n,B->rmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 401 ierr = MatSetType(Ce,MATELEMENTAL);CHKERRQ(ierr); 402 ierr = MatSetUp(Ce);CHKERRQ(ierr); 403 *C = Ce; 404 PetscFunctionReturn(0); 405 } 406 407 static PetscErrorCode MatMatTransposeMult_Elemental(Mat A,Mat B,MatReuse scall,PetscReal fill,Mat *C) 408 { 409 PetscErrorCode ierr; 410 411 PetscFunctionBegin; 412 if (scall == MAT_INITIAL_MATRIX){ 413 ierr = PetscLogEventBegin(MAT_MatTransposeMultSymbolic,A,B,0,0);CHKERRQ(ierr); 414 ierr = MatMatMultSymbolic_Elemental(A,B,1.0,C);CHKERRQ(ierr); 415 ierr = PetscLogEventEnd(MAT_MatTransposeMultSymbolic,A,B,0,0);CHKERRQ(ierr); 416 } 417 ierr = PetscLogEventBegin(MAT_MatTransposeMultNumeric,A,B,0,0);CHKERRQ(ierr); 418 ierr = MatMatTransposeMultNumeric_Elemental(A,B,*C);CHKERRQ(ierr); 419 ierr = PetscLogEventEnd(MAT_MatTransposeMultNumeric,A,B,0,0);CHKERRQ(ierr); 420 PetscFunctionReturn(0); 421 } 422 423 static PetscErrorCode MatGetDiagonal_Elemental(Mat A,Vec D) 424 { 425 PetscInt i,nrows,ncols,nD,rrank,ridx,crank,cidx; 426 Mat_Elemental *a = (Mat_Elemental*)A->data; 427 PetscErrorCode ierr; 428 PetscElemScalar v; 429 MPI_Comm comm; 430 431 PetscFunctionBegin; 432 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 433 ierr = MatGetSize(A,&nrows,&ncols);CHKERRQ(ierr); 434 nD = nrows>ncols ? ncols : nrows; 435 for (i=0; i<nD; i++) { 436 PetscInt erow,ecol; 437 P2RO(A,0,i,&rrank,&ridx); 438 RO2E(A,0,rrank,ridx,&erow); 439 if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect row translation"); 440 P2RO(A,1,i,&crank,&cidx); 441 RO2E(A,1,crank,cidx,&ecol); 442 if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect col translation"); 443 v = a->emat->Get(erow,ecol); 444 ierr = VecSetValues(D,1,&i,(PetscScalar*)&v,INSERT_VALUES);CHKERRQ(ierr); 445 } 446 ierr = VecAssemblyBegin(D);CHKERRQ(ierr); 447 ierr = VecAssemblyEnd(D);CHKERRQ(ierr); 448 PetscFunctionReturn(0); 449 } 450 451 static PetscErrorCode MatDiagonalScale_Elemental(Mat X,Vec L,Vec R) 452 { 453 Mat_Elemental *x = (Mat_Elemental*)X->data; 454 const PetscElemScalar *d; 455 PetscErrorCode ierr; 456 457 PetscFunctionBegin; 458 if (R) { 459 ierr = VecGetArrayRead(R,(const PetscScalar **)&d);CHKERRQ(ierr); 460 El::DistMatrix<PetscElemScalar,El::VC,El::STAR> de; 461 de.LockedAttach(X->cmap->N,1,*x->grid,0,0,d,X->cmap->n); 462 El::DiagonalScale(El::RIGHT,El::NORMAL,de,*x->emat); 463 ierr = VecRestoreArrayRead(R,(const PetscScalar **)&d);CHKERRQ(ierr); 464 } 465 if (L) { 466 ierr = VecGetArrayRead(L,(const PetscScalar **)&d);CHKERRQ(ierr); 467 El::DistMatrix<PetscElemScalar,El::VC,El::STAR> de; 468 de.LockedAttach(X->rmap->N,1,*x->grid,0,0,d,X->rmap->n); 469 El::DiagonalScale(El::LEFT,El::NORMAL,de,*x->emat); 470 ierr = VecRestoreArrayRead(L,(const PetscScalar **)&d);CHKERRQ(ierr); 471 } 472 PetscFunctionReturn(0); 473 } 474 475 static PetscErrorCode MatMissingDiagonal_Elemental(Mat A,PetscBool *missing,PetscInt *d) 476 { 477 PetscFunctionBegin; 478 *missing = PETSC_FALSE; 479 PetscFunctionReturn(0); 480 } 481 482 static PetscErrorCode MatScale_Elemental(Mat X,PetscScalar a) 483 { 484 Mat_Elemental *x = (Mat_Elemental*)X->data; 485 486 PetscFunctionBegin; 487 El::Scale((PetscElemScalar)a,*x->emat); 488 PetscFunctionReturn(0); 489 } 490 491 /* 492 MatAXPY - Computes Y = a*X + Y. 493 */ 494 static PetscErrorCode MatAXPY_Elemental(Mat Y,PetscScalar a,Mat X,MatStructure str) 495 { 496 Mat_Elemental *x = (Mat_Elemental*)X->data; 497 Mat_Elemental *y = (Mat_Elemental*)Y->data; 498 PetscErrorCode ierr; 499 500 PetscFunctionBegin; 501 El::Axpy((PetscElemScalar)a,*x->emat,*y->emat); 502 ierr = PetscObjectStateIncrease((PetscObject)Y);CHKERRQ(ierr); 503 PetscFunctionReturn(0); 504 } 505 506 static PetscErrorCode MatCopy_Elemental(Mat A,Mat B,MatStructure str) 507 { 508 Mat_Elemental *a=(Mat_Elemental*)A->data; 509 Mat_Elemental *b=(Mat_Elemental*)B->data; 510 PetscErrorCode ierr; 511 512 PetscFunctionBegin; 513 El::Copy(*a->emat,*b->emat); 514 ierr = PetscObjectStateIncrease((PetscObject)B);CHKERRQ(ierr); 515 PetscFunctionReturn(0); 516 } 517 518 static PetscErrorCode MatDuplicate_Elemental(Mat A,MatDuplicateOption op,Mat *B) 519 { 520 Mat Be; 521 MPI_Comm comm; 522 Mat_Elemental *a=(Mat_Elemental*)A->data; 523 PetscErrorCode ierr; 524 525 PetscFunctionBegin; 526 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 527 ierr = MatCreate(comm,&Be);CHKERRQ(ierr); 528 ierr = MatSetSizes(Be,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 529 ierr = MatSetType(Be,MATELEMENTAL);CHKERRQ(ierr); 530 ierr = MatSetUp(Be);CHKERRQ(ierr); 531 *B = Be; 532 if (op == MAT_COPY_VALUES) { 533 Mat_Elemental *b=(Mat_Elemental*)Be->data; 534 El::Copy(*a->emat,*b->emat); 535 } 536 Be->assembled = PETSC_TRUE; 537 PetscFunctionReturn(0); 538 } 539 540 static PetscErrorCode MatTranspose_Elemental(Mat A,MatReuse reuse,Mat *B) 541 { 542 Mat Be = *B; 543 PetscErrorCode ierr; 544 MPI_Comm comm; 545 Mat_Elemental *a = (Mat_Elemental*)A->data, *b; 546 547 PetscFunctionBegin; 548 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 549 /* Only out-of-place supported */ 550 if (reuse == MAT_INITIAL_MATRIX){ 551 ierr = MatCreate(comm,&Be);CHKERRQ(ierr); 552 ierr = MatSetSizes(Be,A->cmap->n,A->rmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 553 ierr = MatSetType(Be,MATELEMENTAL);CHKERRQ(ierr); 554 ierr = MatSetUp(Be);CHKERRQ(ierr); 555 *B = Be; 556 } 557 b = (Mat_Elemental*)Be->data; 558 El::Transpose(*a->emat,*b->emat); 559 Be->assembled = PETSC_TRUE; 560 PetscFunctionReturn(0); 561 } 562 563 static PetscErrorCode MatConjugate_Elemental(Mat A) 564 { 565 Mat_Elemental *a = (Mat_Elemental*)A->data; 566 567 PetscFunctionBegin; 568 El::Conjugate(*a->emat); 569 PetscFunctionReturn(0); 570 } 571 572 static PetscErrorCode MatHermitianTranspose_Elemental(Mat A,MatReuse reuse,Mat *B) 573 { 574 Mat Be = *B; 575 PetscErrorCode ierr; 576 MPI_Comm comm; 577 Mat_Elemental *a = (Mat_Elemental*)A->data, *b; 578 579 PetscFunctionBegin; 580 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 581 /* Only out-of-place supported */ 582 if (reuse == MAT_INITIAL_MATRIX){ 583 ierr = MatCreate(comm,&Be);CHKERRQ(ierr); 584 ierr = MatSetSizes(Be,A->cmap->n,A->rmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 585 ierr = MatSetType(Be,MATELEMENTAL);CHKERRQ(ierr); 586 ierr = MatSetUp(Be);CHKERRQ(ierr); 587 *B = Be; 588 } 589 b = (Mat_Elemental*)Be->data; 590 El::Adjoint(*a->emat,*b->emat); 591 Be->assembled = PETSC_TRUE; 592 PetscFunctionReturn(0); 593 } 594 595 static PetscErrorCode MatSolve_Elemental(Mat A,Vec B,Vec X) 596 { 597 Mat_Elemental *a = (Mat_Elemental*)A->data; 598 PetscErrorCode ierr; 599 PetscElemScalar *x; 600 PetscInt pivoting = a->pivoting; 601 602 PetscFunctionBegin; 603 ierr = VecCopy(B,X);CHKERRQ(ierr); 604 ierr = VecGetArray(X,(PetscScalar **)&x);CHKERRQ(ierr); 605 606 El::DistMatrix<PetscElemScalar,El::VC,El::STAR> xe; 607 xe.Attach(A->rmap->N,1,*a->grid,0,0,x,A->rmap->n); 608 El::DistMatrix<PetscElemScalar,El::MC,El::MR> xer(xe); 609 switch (A->factortype) { 610 case MAT_FACTOR_LU: 611 if (pivoting == 0) { 612 El::lu::SolveAfter(El::NORMAL,*a->emat,xer); 613 } else if (pivoting == 1) { 614 El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,xer); 615 } else { /* pivoting == 2 */ 616 El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,*a->Q,xer); 617 } 618 break; 619 case MAT_FACTOR_CHOLESKY: 620 El::cholesky::SolveAfter(El::UPPER,El::NORMAL,*a->emat,xer); 621 break; 622 default: 623 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unfactored Matrix or Unsupported MatFactorType"); 624 break; 625 } 626 El::Copy(xer,xe); 627 628 ierr = VecRestoreArray(X,(PetscScalar **)&x);CHKERRQ(ierr); 629 PetscFunctionReturn(0); 630 } 631 632 static PetscErrorCode MatSolveAdd_Elemental(Mat A,Vec B,Vec Y,Vec X) 633 { 634 PetscErrorCode ierr; 635 636 PetscFunctionBegin; 637 ierr = MatSolve_Elemental(A,B,X);CHKERRQ(ierr); 638 ierr = VecAXPY(X,1,Y);CHKERRQ(ierr); 639 PetscFunctionReturn(0); 640 } 641 642 static PetscErrorCode MatMatSolve_Elemental(Mat A,Mat B,Mat X) 643 { 644 Mat_Elemental *a=(Mat_Elemental*)A->data; 645 Mat_Elemental *b=(Mat_Elemental*)B->data; 646 Mat_Elemental *x=(Mat_Elemental*)X->data; 647 PetscInt pivoting = a->pivoting; 648 649 PetscFunctionBegin; 650 El::Copy(*b->emat,*x->emat); 651 switch (A->factortype) { 652 case MAT_FACTOR_LU: 653 if (pivoting == 0) { 654 El::lu::SolveAfter(El::NORMAL,*a->emat,*x->emat); 655 } else if (pivoting == 1) { 656 El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,*x->emat); 657 } else { 658 El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,*a->Q,*x->emat); 659 } 660 break; 661 case MAT_FACTOR_CHOLESKY: 662 El::cholesky::SolveAfter(El::UPPER,El::NORMAL,*a->emat,*x->emat); 663 break; 664 default: 665 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unfactored Matrix or Unsupported MatFactorType"); 666 break; 667 } 668 PetscFunctionReturn(0); 669 } 670 671 static PetscErrorCode MatLUFactor_Elemental(Mat A,IS row,IS col,const MatFactorInfo *info) 672 { 673 Mat_Elemental *a = (Mat_Elemental*)A->data; 674 PetscErrorCode ierr; 675 PetscInt pivoting = a->pivoting; 676 677 PetscFunctionBegin; 678 if (pivoting == 0) { 679 El::LU(*a->emat); 680 } else if (pivoting == 1) { 681 El::LU(*a->emat,*a->P); 682 } else { 683 El::LU(*a->emat,*a->P,*a->Q); 684 } 685 A->factortype = MAT_FACTOR_LU; 686 A->assembled = PETSC_TRUE; 687 688 ierr = PetscFree(A->solvertype);CHKERRQ(ierr); 689 ierr = PetscStrallocpy(MATSOLVERELEMENTAL,&A->solvertype);CHKERRQ(ierr); 690 PetscFunctionReturn(0); 691 } 692 693 static PetscErrorCode MatLUFactorNumeric_Elemental(Mat F,Mat A,const MatFactorInfo *info) 694 { 695 PetscErrorCode ierr; 696 697 PetscFunctionBegin; 698 ierr = MatCopy(A,F,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 699 ierr = MatLUFactor_Elemental(F,0,0,info);CHKERRQ(ierr); 700 PetscFunctionReturn(0); 701 } 702 703 static PetscErrorCode MatLUFactorSymbolic_Elemental(Mat F,Mat A,IS r,IS c,const MatFactorInfo *info) 704 { 705 PetscFunctionBegin; 706 /* F is create and allocated by MatGetFactor_elemental_petsc(), skip this routine. */ 707 PetscFunctionReturn(0); 708 } 709 710 static PetscErrorCode MatCholeskyFactor_Elemental(Mat A,IS perm,const MatFactorInfo *info) 711 { 712 Mat_Elemental *a = (Mat_Elemental*)A->data; 713 El::DistMatrix<PetscElemScalar,El::MC,El::STAR> d; 714 PetscErrorCode ierr; 715 716 PetscFunctionBegin; 717 El::Cholesky(El::UPPER,*a->emat); 718 A->factortype = MAT_FACTOR_CHOLESKY; 719 A->assembled = PETSC_TRUE; 720 721 ierr = PetscFree(A->solvertype);CHKERRQ(ierr); 722 ierr = PetscStrallocpy(MATSOLVERELEMENTAL,&A->solvertype);CHKERRQ(ierr); 723 PetscFunctionReturn(0); 724 } 725 726 static PetscErrorCode MatCholeskyFactorNumeric_Elemental(Mat F,Mat A,const MatFactorInfo *info) 727 { 728 PetscErrorCode ierr; 729 730 PetscFunctionBegin; 731 ierr = MatCopy(A,F,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 732 ierr = MatCholeskyFactor_Elemental(F,0,info);CHKERRQ(ierr); 733 PetscFunctionReturn(0); 734 } 735 736 static PetscErrorCode MatCholeskyFactorSymbolic_Elemental(Mat F,Mat A,IS perm,const MatFactorInfo *info) 737 { 738 PetscFunctionBegin; 739 /* F is create and allocated by MatGetFactor_elemental_petsc(), skip this routine. */ 740 PetscFunctionReturn(0); 741 } 742 743 PetscErrorCode MatFactorGetSolverType_elemental_elemental(Mat A,MatSolverType *type) 744 { 745 PetscFunctionBegin; 746 *type = MATSOLVERELEMENTAL; 747 PetscFunctionReturn(0); 748 } 749 750 static PetscErrorCode MatGetFactor_elemental_elemental(Mat A,MatFactorType ftype,Mat *F) 751 { 752 Mat B; 753 PetscErrorCode ierr; 754 755 PetscFunctionBegin; 756 /* Create the factorization matrix */ 757 ierr = MatCreate(PetscObjectComm((PetscObject)A),&B);CHKERRQ(ierr); 758 ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 759 ierr = MatSetType(B,MATELEMENTAL);CHKERRQ(ierr); 760 ierr = MatSetUp(B);CHKERRQ(ierr); 761 B->factortype = ftype; 762 ierr = PetscFree(B->solvertype);CHKERRQ(ierr); 763 ierr = PetscStrallocpy(MATSOLVERELEMENTAL,&B->solvertype);CHKERRQ(ierr); 764 765 ierr = PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_elemental_elemental);CHKERRQ(ierr); 766 *F = B; 767 PetscFunctionReturn(0); 768 } 769 770 PETSC_EXTERN PetscErrorCode MatSolverTypeRegister_Elemental(void) 771 { 772 PetscErrorCode ierr; 773 774 PetscFunctionBegin; 775 ierr = MatSolverTypeRegister(MATSOLVERELEMENTAL,MATELEMENTAL, MAT_FACTOR_LU,MatGetFactor_elemental_elemental);CHKERRQ(ierr); 776 ierr = MatSolverTypeRegister(MATSOLVERELEMENTAL,MATELEMENTAL, MAT_FACTOR_CHOLESKY,MatGetFactor_elemental_elemental);CHKERRQ(ierr); 777 PetscFunctionReturn(0); 778 } 779 780 static PetscErrorCode MatNorm_Elemental(Mat A,NormType type,PetscReal *nrm) 781 { 782 Mat_Elemental *a=(Mat_Elemental*)A->data; 783 784 PetscFunctionBegin; 785 switch (type){ 786 case NORM_1: 787 *nrm = El::OneNorm(*a->emat); 788 break; 789 case NORM_FROBENIUS: 790 *nrm = El::FrobeniusNorm(*a->emat); 791 break; 792 case NORM_INFINITY: 793 *nrm = El::InfinityNorm(*a->emat); 794 break; 795 default: 796 printf("Error: unsupported norm type!\n"); 797 } 798 PetscFunctionReturn(0); 799 } 800 801 static PetscErrorCode MatZeroEntries_Elemental(Mat A) 802 { 803 Mat_Elemental *a=(Mat_Elemental*)A->data; 804 805 PetscFunctionBegin; 806 El::Zero(*a->emat); 807 PetscFunctionReturn(0); 808 } 809 810 static PetscErrorCode MatGetOwnershipIS_Elemental(Mat A,IS *rows,IS *cols) 811 { 812 Mat_Elemental *a = (Mat_Elemental*)A->data; 813 PetscErrorCode ierr; 814 PetscInt i,m,shift,stride,*idx; 815 816 PetscFunctionBegin; 817 if (rows) { 818 m = a->emat->LocalHeight(); 819 shift = a->emat->ColShift(); 820 stride = a->emat->ColStride(); 821 ierr = PetscMalloc1(m,&idx);CHKERRQ(ierr); 822 for (i=0; i<m; i++) { 823 PetscInt rank,offset; 824 E2RO(A,0,shift+i*stride,&rank,&offset); 825 RO2P(A,0,rank,offset,&idx[i]); 826 } 827 ierr = ISCreateGeneral(PETSC_COMM_SELF,m,idx,PETSC_OWN_POINTER,rows);CHKERRQ(ierr); 828 } 829 if (cols) { 830 m = a->emat->LocalWidth(); 831 shift = a->emat->RowShift(); 832 stride = a->emat->RowStride(); 833 ierr = PetscMalloc1(m,&idx);CHKERRQ(ierr); 834 for (i=0; i<m; i++) { 835 PetscInt rank,offset; 836 E2RO(A,1,shift+i*stride,&rank,&offset); 837 RO2P(A,1,rank,offset,&idx[i]); 838 } 839 ierr = ISCreateGeneral(PETSC_COMM_SELF,m,idx,PETSC_OWN_POINTER,cols);CHKERRQ(ierr); 840 } 841 PetscFunctionReturn(0); 842 } 843 844 static PetscErrorCode MatConvert_Elemental_Dense(Mat A,MatType newtype,MatReuse reuse,Mat *B) 845 { 846 Mat Bmpi; 847 Mat_Elemental *a = (Mat_Elemental*)A->data; 848 MPI_Comm comm; 849 PetscErrorCode ierr; 850 IS isrows,iscols; 851 PetscInt rrank,ridx,crank,cidx,nrows,ncols,i,j,erow,ecol,elrow,elcol; 852 const PetscInt *rows,*cols; 853 PetscElemScalar v; 854 const El::Grid &grid = a->emat->Grid(); 855 856 PetscFunctionBegin; 857 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 858 859 if (reuse == MAT_REUSE_MATRIX) { 860 Bmpi = *B; 861 } else { 862 ierr = MatCreate(comm,&Bmpi);CHKERRQ(ierr); 863 ierr = MatSetSizes(Bmpi,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 864 ierr = MatSetType(Bmpi,MATDENSE);CHKERRQ(ierr); 865 ierr = MatSetUp(Bmpi);CHKERRQ(ierr); 866 } 867 868 /* Get local entries of A */ 869 ierr = MatGetOwnershipIS(A,&isrows,&iscols);CHKERRQ(ierr); 870 ierr = ISGetLocalSize(isrows,&nrows);CHKERRQ(ierr); 871 ierr = ISGetIndices(isrows,&rows);CHKERRQ(ierr); 872 ierr = ISGetLocalSize(iscols,&ncols);CHKERRQ(ierr); 873 ierr = ISGetIndices(iscols,&cols);CHKERRQ(ierr); 874 875 if (a->roworiented) { 876 for (i=0; i<nrows; i++) { 877 P2RO(A,0,rows[i],&rrank,&ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */ 878 RO2E(A,0,rrank,ridx,&erow); 879 if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect row translation"); 880 for (j=0; j<ncols; j++) { 881 P2RO(A,1,cols[j],&crank,&cidx); 882 RO2E(A,1,crank,cidx,&ecol); 883 if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect col translation"); 884 885 elrow = erow / grid.MCSize(); /* Elemental local row index */ 886 elcol = ecol / grid.MRSize(); /* Elemental local column index */ 887 v = a->emat->GetLocal(elrow,elcol); 888 ierr = MatSetValues(Bmpi,1,&rows[i],1,&cols[j],(PetscScalar *)&v,INSERT_VALUES);CHKERRQ(ierr); 889 } 890 } 891 } else { /* column-oriented */ 892 for (j=0; j<ncols; j++) { 893 P2RO(A,1,cols[j],&crank,&cidx); 894 RO2E(A,1,crank,cidx,&ecol); 895 if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect col translation"); 896 for (i=0; i<nrows; i++) { 897 P2RO(A,0,rows[i],&rrank,&ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */ 898 RO2E(A,0,rrank,ridx,&erow); 899 if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect row translation"); 900 901 elrow = erow / grid.MCSize(); /* Elemental local row index */ 902 elcol = ecol / grid.MRSize(); /* Elemental local column index */ 903 v = a->emat->GetLocal(elrow,elcol); 904 ierr = MatSetValues(Bmpi,1,&rows[i],1,&cols[j],(PetscScalar *)&v,INSERT_VALUES);CHKERRQ(ierr); 905 } 906 } 907 } 908 ierr = MatAssemblyBegin(Bmpi,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 909 ierr = MatAssemblyEnd(Bmpi,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 910 if (reuse == MAT_INPLACE_MATRIX) { 911 ierr = MatHeaderReplace(A,&Bmpi);CHKERRQ(ierr); 912 } else { 913 *B = Bmpi; 914 } 915 ierr = ISDestroy(&isrows);CHKERRQ(ierr); 916 ierr = ISDestroy(&iscols);CHKERRQ(ierr); 917 PetscFunctionReturn(0); 918 } 919 920 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 921 { 922 Mat mat_elemental; 923 PetscErrorCode ierr; 924 PetscInt M=A->rmap->N,N=A->cmap->N,row,ncols; 925 const PetscInt *cols; 926 const PetscScalar *vals; 927 928 PetscFunctionBegin; 929 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 930 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr); 931 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 932 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 933 for (row=0; row<M; row++) { 934 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 935 /* PETSc-Elemental interaface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 936 ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr); 937 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 938 } 939 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 940 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 941 942 if (reuse == MAT_INPLACE_MATRIX) { 943 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 944 } else { 945 *newmat = mat_elemental; 946 } 947 PetscFunctionReturn(0); 948 } 949 950 PETSC_INTERN PetscErrorCode MatConvert_MPIAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 951 { 952 Mat mat_elemental; 953 PetscErrorCode ierr; 954 PetscInt row,ncols,rstart=A->rmap->rstart,rend=A->rmap->rend,j; 955 const PetscInt *cols; 956 const PetscScalar *vals; 957 958 PetscFunctionBegin; 959 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 960 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,A->rmap->N,A->cmap->N);CHKERRQ(ierr); 961 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 962 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 963 for (row=rstart; row<rend; row++) { 964 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 965 for (j=0; j<ncols; j++) { 966 /* PETSc-Elemental interaface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 967 ierr = MatSetValues(mat_elemental,1,&row,1,&cols[j],&vals[j],ADD_VALUES);CHKERRQ(ierr); 968 } 969 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 970 } 971 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 972 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 973 974 if (reuse == MAT_INPLACE_MATRIX) { 975 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 976 } else { 977 *newmat = mat_elemental; 978 } 979 PetscFunctionReturn(0); 980 } 981 982 PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 983 { 984 Mat mat_elemental; 985 PetscErrorCode ierr; 986 PetscInt M=A->rmap->N,N=A->cmap->N,row,ncols,j; 987 const PetscInt *cols; 988 const PetscScalar *vals; 989 990 PetscFunctionBegin; 991 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 992 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr); 993 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 994 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 995 ierr = MatGetRowUpperTriangular(A);CHKERRQ(ierr); 996 for (row=0; row<M; row++) { 997 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 998 /* PETSc-Elemental interaface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 999 ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr); 1000 for (j=0; j<ncols; j++) { /* lower triangular part */ 1001 if (cols[j] == row) continue; 1002 ierr = MatSetValues(mat_elemental,1,&cols[j],1,&row,&vals[j],ADD_VALUES);CHKERRQ(ierr); 1003 } 1004 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 1005 } 1006 ierr = MatRestoreRowUpperTriangular(A);CHKERRQ(ierr); 1007 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1008 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1009 1010 if (reuse == MAT_INPLACE_MATRIX) { 1011 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 1012 } else { 1013 *newmat = mat_elemental; 1014 } 1015 PetscFunctionReturn(0); 1016 } 1017 1018 PETSC_INTERN PetscErrorCode MatConvert_MPISBAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 1019 { 1020 Mat mat_elemental; 1021 PetscErrorCode ierr; 1022 PetscInt M=A->rmap->N,N=A->cmap->N,row,ncols,j,rstart=A->rmap->rstart,rend=A->rmap->rend; 1023 const PetscInt *cols; 1024 const PetscScalar *vals; 1025 1026 PetscFunctionBegin; 1027 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 1028 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr); 1029 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 1030 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 1031 ierr = MatGetRowUpperTriangular(A);CHKERRQ(ierr); 1032 for (row=rstart; row<rend; row++) { 1033 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 1034 /* PETSc-Elemental interaface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 1035 ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr); 1036 for (j=0; j<ncols; j++) { /* lower triangular part */ 1037 if (cols[j] == row) continue; 1038 ierr = MatSetValues(mat_elemental,1,&cols[j],1,&row,&vals[j],ADD_VALUES);CHKERRQ(ierr); 1039 } 1040 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 1041 } 1042 ierr = MatRestoreRowUpperTriangular(A);CHKERRQ(ierr); 1043 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1044 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1045 1046 if (reuse == MAT_INPLACE_MATRIX) { 1047 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 1048 } else { 1049 *newmat = mat_elemental; 1050 } 1051 PetscFunctionReturn(0); 1052 } 1053 1054 static PetscErrorCode MatDestroy_Elemental(Mat A) 1055 { 1056 Mat_Elemental *a = (Mat_Elemental*)A->data; 1057 PetscErrorCode ierr; 1058 Mat_Elemental_Grid *commgrid; 1059 PetscBool flg; 1060 MPI_Comm icomm; 1061 1062 PetscFunctionBegin; 1063 delete a->emat; 1064 delete a->P; 1065 delete a->Q; 1066 1067 El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A)); 1068 ierr = PetscCommDuplicate(cxxcomm.comm,&icomm,NULL);CHKERRQ(ierr); 1069 ierr = MPI_Comm_get_attr(icomm,Petsc_Elemental_keyval,(void**)&commgrid,(int*)&flg);CHKERRQ(ierr); 1070 if (--commgrid->grid_refct == 0) { 1071 delete commgrid->grid; 1072 ierr = PetscFree(commgrid);CHKERRQ(ierr); 1073 ierr = MPI_Comm_free_keyval(&Petsc_Elemental_keyval);CHKERRQ(ierr); 1074 } 1075 ierr = PetscCommDestroy(&icomm);CHKERRQ(ierr); 1076 ierr = PetscObjectComposeFunction((PetscObject)A,"MatGetOwnershipIS_C",NULL);CHKERRQ(ierr); 1077 ierr = PetscObjectComposeFunction((PetscObject)A,"MatFactorGetSolverType_C",NULL);CHKERRQ(ierr); 1078 ierr = PetscFree(A->data);CHKERRQ(ierr); 1079 PetscFunctionReturn(0); 1080 } 1081 1082 PetscErrorCode MatSetUp_Elemental(Mat A) 1083 { 1084 Mat_Elemental *a = (Mat_Elemental*)A->data; 1085 PetscErrorCode ierr; 1086 PetscMPIInt rsize,csize; 1087 1088 PetscFunctionBegin; 1089 ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr); 1090 ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr); 1091 1092 a->emat->Resize(A->rmap->N,A->cmap->N);CHKERRQ(ierr); 1093 El::Zero(*a->emat); 1094 1095 ierr = MPI_Comm_size(A->rmap->comm,&rsize);CHKERRQ(ierr); 1096 ierr = MPI_Comm_size(A->cmap->comm,&csize);CHKERRQ(ierr); 1097 if (csize != rsize) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Cannot use row and column communicators of different sizes"); 1098 a->commsize = rsize; 1099 a->mr[0] = A->rmap->N % rsize; if (!a->mr[0]) a->mr[0] = rsize; 1100 a->mr[1] = A->cmap->N % csize; if (!a->mr[1]) a->mr[1] = csize; 1101 a->m[0] = A->rmap->N / rsize + (a->mr[0] != rsize); 1102 a->m[1] = A->cmap->N / csize + (a->mr[1] != csize); 1103 PetscFunctionReturn(0); 1104 } 1105 1106 PetscErrorCode MatAssemblyBegin_Elemental(Mat A, MatAssemblyType type) 1107 { 1108 Mat_Elemental *a = (Mat_Elemental*)A->data; 1109 1110 PetscFunctionBegin; 1111 /* printf("Calling ProcessQueues\n"); */ 1112 a->emat->ProcessQueues(); 1113 /* printf("Finished ProcessQueues\n"); */ 1114 PetscFunctionReturn(0); 1115 } 1116 1117 PetscErrorCode MatAssemblyEnd_Elemental(Mat A, MatAssemblyType type) 1118 { 1119 PetscFunctionBegin; 1120 /* Currently does nothing */ 1121 PetscFunctionReturn(0); 1122 } 1123 1124 PetscErrorCode MatLoad_Elemental(Mat newMat, PetscViewer viewer) 1125 { 1126 PetscErrorCode ierr; 1127 Mat Adense,Ae; 1128 MPI_Comm comm; 1129 1130 PetscFunctionBegin; 1131 ierr = PetscObjectGetComm((PetscObject)newMat,&comm);CHKERRQ(ierr); 1132 ierr = MatCreate(comm,&Adense);CHKERRQ(ierr); 1133 ierr = MatSetType(Adense,MATDENSE);CHKERRQ(ierr); 1134 ierr = MatLoad(Adense,viewer);CHKERRQ(ierr); 1135 ierr = MatConvert(Adense, MATELEMENTAL, MAT_INITIAL_MATRIX,&Ae);CHKERRQ(ierr); 1136 ierr = MatDestroy(&Adense);CHKERRQ(ierr); 1137 ierr = MatHeaderReplace(newMat,&Ae);CHKERRQ(ierr); 1138 PetscFunctionReturn(0); 1139 } 1140 1141 /* -------------------------------------------------------------------*/ 1142 static struct _MatOps MatOps_Values = { 1143 MatSetValues_Elemental, 1144 0, 1145 0, 1146 MatMult_Elemental, 1147 /* 4*/ MatMultAdd_Elemental, 1148 MatMultTranspose_Elemental, 1149 MatMultTransposeAdd_Elemental, 1150 MatSolve_Elemental, 1151 MatSolveAdd_Elemental, 1152 0, 1153 /*10*/ 0, 1154 MatLUFactor_Elemental, 1155 MatCholeskyFactor_Elemental, 1156 0, 1157 MatTranspose_Elemental, 1158 /*15*/ MatGetInfo_Elemental, 1159 0, 1160 MatGetDiagonal_Elemental, 1161 MatDiagonalScale_Elemental, 1162 MatNorm_Elemental, 1163 /*20*/ MatAssemblyBegin_Elemental, 1164 MatAssemblyEnd_Elemental, 1165 MatSetOption_Elemental, 1166 MatZeroEntries_Elemental, 1167 /*24*/ 0, 1168 MatLUFactorSymbolic_Elemental, 1169 MatLUFactorNumeric_Elemental, 1170 MatCholeskyFactorSymbolic_Elemental, 1171 MatCholeskyFactorNumeric_Elemental, 1172 /*29*/ MatSetUp_Elemental, 1173 0, 1174 0, 1175 0, 1176 0, 1177 /*34*/ MatDuplicate_Elemental, 1178 0, 1179 0, 1180 0, 1181 0, 1182 /*39*/ MatAXPY_Elemental, 1183 0, 1184 0, 1185 0, 1186 MatCopy_Elemental, 1187 /*44*/ 0, 1188 MatScale_Elemental, 1189 MatShift_Basic, 1190 0, 1191 0, 1192 /*49*/ 0, 1193 0, 1194 0, 1195 0, 1196 0, 1197 /*54*/ 0, 1198 0, 1199 0, 1200 0, 1201 0, 1202 /*59*/ 0, 1203 MatDestroy_Elemental, 1204 MatView_Elemental, 1205 0, 1206 0, 1207 /*64*/ 0, 1208 0, 1209 0, 1210 0, 1211 0, 1212 /*69*/ 0, 1213 0, 1214 MatConvert_Elemental_Dense, 1215 0, 1216 0, 1217 /*74*/ 0, 1218 0, 1219 0, 1220 0, 1221 0, 1222 /*79*/ 0, 1223 0, 1224 0, 1225 0, 1226 MatLoad_Elemental, 1227 /*84*/ 0, 1228 0, 1229 0, 1230 0, 1231 0, 1232 /*89*/ MatMatMult_Elemental, 1233 MatMatMultSymbolic_Elemental, 1234 MatMatMultNumeric_Elemental, 1235 0, 1236 0, 1237 /*94*/ 0, 1238 MatMatTransposeMult_Elemental, 1239 MatMatTransposeMultSymbolic_Elemental, 1240 MatMatTransposeMultNumeric_Elemental, 1241 0, 1242 /*99*/ 0, 1243 0, 1244 0, 1245 MatConjugate_Elemental, 1246 0, 1247 /*104*/0, 1248 0, 1249 0, 1250 0, 1251 0, 1252 /*109*/MatMatSolve_Elemental, 1253 0, 1254 0, 1255 0, 1256 MatMissingDiagonal_Elemental, 1257 /*114*/0, 1258 0, 1259 0, 1260 0, 1261 0, 1262 /*119*/0, 1263 MatHermitianTranspose_Elemental, 1264 0, 1265 0, 1266 0, 1267 /*124*/0, 1268 0, 1269 0, 1270 0, 1271 0, 1272 /*129*/0, 1273 0, 1274 0, 1275 0, 1276 0, 1277 /*134*/0, 1278 0, 1279 0, 1280 0, 1281 0 1282 }; 1283 1284 /*MC 1285 MATELEMENTAL = "elemental" - A matrix type for dense matrices using the Elemental package 1286 1287 Use ./configure --download-elemental to install PETSc to use Elemental 1288 1289 Use -pc_type lu -pc_factor_mat_solver_type elemental to use this direct solver 1290 1291 Options Database Keys: 1292 + -mat_type elemental - sets the matrix type to "elemental" during a call to MatSetFromOptions() 1293 - -mat_elemental_grid_height - sets Grid Height for 2D cyclic ordering of internal matrix 1294 1295 Level: beginner 1296 1297 .seealso: MATDENSE 1298 M*/ 1299 1300 PETSC_EXTERN PetscErrorCode MatCreate_Elemental(Mat A) 1301 { 1302 Mat_Elemental *a; 1303 PetscErrorCode ierr; 1304 PetscBool flg,flg1; 1305 Mat_Elemental_Grid *commgrid; 1306 MPI_Comm icomm; 1307 PetscInt optv1; 1308 1309 PetscFunctionBegin; 1310 ierr = PetscElementalInitializePackage();CHKERRQ(ierr); 1311 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 1312 A->insertmode = NOT_SET_VALUES; 1313 1314 ierr = PetscNewLog(A,&a);CHKERRQ(ierr); 1315 A->data = (void*)a; 1316 1317 /* Set up the elemental matrix */ 1318 El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A)); 1319 1320 /* Grid needs to be shared between multiple Mats on the same communicator, implement by attribute caching on the MPI_Comm */ 1321 if (Petsc_Elemental_keyval == MPI_KEYVAL_INVALID) { 1322 ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Elemental_keyval,(void*)0);CHKERRQ(ierr); 1323 } 1324 ierr = PetscCommDuplicate(cxxcomm.comm,&icomm,NULL);CHKERRQ(ierr); 1325 ierr = MPI_Comm_get_attr(icomm,Petsc_Elemental_keyval,(void**)&commgrid,(int*)&flg);CHKERRQ(ierr); 1326 if (!flg) { 1327 ierr = PetscNewLog(A,&commgrid);CHKERRQ(ierr); 1328 1329 ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)A),((PetscObject)A)->prefix,"Elemental Options","Mat");CHKERRQ(ierr); 1330 /* displayed default grid sizes (CommSize,1) are set by us arbitrarily until El::Grid() is called */ 1331 ierr = PetscOptionsInt("-mat_elemental_grid_height","Grid Height","None",El::mpi::Size(cxxcomm),&optv1,&flg1);CHKERRQ(ierr); 1332 if (flg1) { 1333 if (El::mpi::Size(cxxcomm) % optv1 != 0) { 1334 SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Grid Height %D must evenly divide CommSize %D",optv1,(PetscInt)El::mpi::Size(cxxcomm)); 1335 } 1336 commgrid->grid = new El::Grid(cxxcomm,optv1); /* use user-provided grid height */ 1337 } else { 1338 commgrid->grid = new El::Grid(cxxcomm); /* use Elemental default grid sizes */ 1339 /* printf("new commgrid->grid = %p\n",commgrid->grid); -- memory leak revealed by valgrind? */ 1340 } 1341 commgrid->grid_refct = 1; 1342 ierr = MPI_Comm_set_attr(icomm,Petsc_Elemental_keyval,(void*)commgrid);CHKERRQ(ierr); 1343 1344 a->pivoting = 1; 1345 ierr = PetscOptionsInt("-mat_elemental_pivoting","Pivoting","None",a->pivoting,&a->pivoting,NULL);CHKERRQ(ierr); 1346 1347 ierr = PetscOptionsEnd();CHKERRQ(ierr); 1348 } else { 1349 commgrid->grid_refct++; 1350 } 1351 ierr = PetscCommDestroy(&icomm);CHKERRQ(ierr); 1352 a->grid = commgrid->grid; 1353 a->emat = new El::DistMatrix<PetscElemScalar>(*a->grid); 1354 a->roworiented = PETSC_TRUE; 1355 1356 ierr = PetscObjectComposeFunction((PetscObject)A,"MatGetOwnershipIS_C",MatGetOwnershipIS_Elemental);CHKERRQ(ierr); 1357 ierr = PetscObjectChangeTypeName((PetscObject)A,MATELEMENTAL);CHKERRQ(ierr); 1358 PetscFunctionReturn(0); 1359 } 1360