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