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