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 ierr = PetscFree(B->solvertype);CHKERRQ(ierr); 795 ierr = PetscStrallocpy(MATSOLVERELEMENTAL,&B->solvertype);CHKERRQ(ierr); 796 797 ierr = PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverType_C",MatFactorGetSolverType_elemental_elemental);CHKERRQ(ierr); 798 *F = B; 799 PetscFunctionReturn(0); 800 } 801 802 PETSC_EXTERN PetscErrorCode MatSolverTypeRegister_Elemental(void) 803 { 804 PetscErrorCode ierr; 805 806 PetscFunctionBegin; 807 ierr = MatSolverTypeRegister(MATSOLVERELEMENTAL,MATELEMENTAL, MAT_FACTOR_LU,MatGetFactor_elemental_elemental);CHKERRQ(ierr); 808 ierr = MatSolverTypeRegister(MATSOLVERELEMENTAL,MATELEMENTAL, MAT_FACTOR_CHOLESKY,MatGetFactor_elemental_elemental);CHKERRQ(ierr); 809 PetscFunctionReturn(0); 810 } 811 812 static PetscErrorCode MatNorm_Elemental(Mat A,NormType type,PetscReal *nrm) 813 { 814 Mat_Elemental *a=(Mat_Elemental*)A->data; 815 816 PetscFunctionBegin; 817 switch (type){ 818 case NORM_1: 819 *nrm = El::OneNorm(*a->emat); 820 break; 821 case NORM_FROBENIUS: 822 *nrm = El::FrobeniusNorm(*a->emat); 823 break; 824 case NORM_INFINITY: 825 *nrm = El::InfinityNorm(*a->emat); 826 break; 827 default: 828 SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_SUP,"Unsupported norm type"); 829 } 830 PetscFunctionReturn(0); 831 } 832 833 static PetscErrorCode MatZeroEntries_Elemental(Mat A) 834 { 835 Mat_Elemental *a=(Mat_Elemental*)A->data; 836 837 PetscFunctionBegin; 838 El::Zero(*a->emat); 839 PetscFunctionReturn(0); 840 } 841 842 static PetscErrorCode MatGetOwnershipIS_Elemental(Mat A,IS *rows,IS *cols) 843 { 844 Mat_Elemental *a = (Mat_Elemental*)A->data; 845 PetscErrorCode ierr; 846 PetscInt i,m,shift,stride,*idx; 847 848 PetscFunctionBegin; 849 if (rows) { 850 m = a->emat->LocalHeight(); 851 shift = a->emat->ColShift(); 852 stride = a->emat->ColStride(); 853 ierr = PetscMalloc1(m,&idx);CHKERRQ(ierr); 854 for (i=0; i<m; i++) { 855 PetscInt rank,offset; 856 E2RO(A,0,shift+i*stride,&rank,&offset); 857 RO2P(A,0,rank,offset,&idx[i]); 858 } 859 ierr = ISCreateGeneral(PETSC_COMM_SELF,m,idx,PETSC_OWN_POINTER,rows);CHKERRQ(ierr); 860 } 861 if (cols) { 862 m = a->emat->LocalWidth(); 863 shift = a->emat->RowShift(); 864 stride = a->emat->RowStride(); 865 ierr = PetscMalloc1(m,&idx);CHKERRQ(ierr); 866 for (i=0; i<m; i++) { 867 PetscInt rank,offset; 868 E2RO(A,1,shift+i*stride,&rank,&offset); 869 RO2P(A,1,rank,offset,&idx[i]); 870 } 871 ierr = ISCreateGeneral(PETSC_COMM_SELF,m,idx,PETSC_OWN_POINTER,cols);CHKERRQ(ierr); 872 } 873 PetscFunctionReturn(0); 874 } 875 876 static PetscErrorCode MatConvert_Elemental_Dense(Mat A,MatType newtype,MatReuse reuse,Mat *B) 877 { 878 Mat Bmpi; 879 Mat_Elemental *a = (Mat_Elemental*)A->data; 880 MPI_Comm comm; 881 PetscErrorCode ierr; 882 IS isrows,iscols; 883 PetscInt rrank,ridx,crank,cidx,nrows,ncols,i,j,erow,ecol,elrow,elcol; 884 const PetscInt *rows,*cols; 885 PetscElemScalar v; 886 const El::Grid &grid = a->emat->Grid(); 887 888 PetscFunctionBegin; 889 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 890 891 if (reuse == MAT_REUSE_MATRIX) { 892 Bmpi = *B; 893 } else { 894 ierr = MatCreate(comm,&Bmpi);CHKERRQ(ierr); 895 ierr = MatSetSizes(Bmpi,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 896 ierr = MatSetType(Bmpi,MATDENSE);CHKERRQ(ierr); 897 ierr = MatSetUp(Bmpi);CHKERRQ(ierr); 898 } 899 900 /* Get local entries of A */ 901 ierr = MatGetOwnershipIS(A,&isrows,&iscols);CHKERRQ(ierr); 902 ierr = ISGetLocalSize(isrows,&nrows);CHKERRQ(ierr); 903 ierr = ISGetIndices(isrows,&rows);CHKERRQ(ierr); 904 ierr = ISGetLocalSize(iscols,&ncols);CHKERRQ(ierr); 905 ierr = ISGetIndices(iscols,&cols);CHKERRQ(ierr); 906 907 if (a->roworiented) { 908 for (i=0; i<nrows; i++) { 909 P2RO(A,0,rows[i],&rrank,&ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */ 910 RO2E(A,0,rrank,ridx,&erow); 911 if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect row translation"); 912 for (j=0; j<ncols; j++) { 913 P2RO(A,1,cols[j],&crank,&cidx); 914 RO2E(A,1,crank,cidx,&ecol); 915 if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect col translation"); 916 917 elrow = erow / grid.MCSize(); /* Elemental local row index */ 918 elcol = ecol / grid.MRSize(); /* Elemental local column index */ 919 v = a->emat->GetLocal(elrow,elcol); 920 ierr = MatSetValues(Bmpi,1,&rows[i],1,&cols[j],(PetscScalar *)&v,INSERT_VALUES);CHKERRQ(ierr); 921 } 922 } 923 } else { /* column-oriented */ 924 for (j=0; j<ncols; j++) { 925 P2RO(A,1,cols[j],&crank,&cidx); 926 RO2E(A,1,crank,cidx,&ecol); 927 if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect col translation"); 928 for (i=0; i<nrows; i++) { 929 P2RO(A,0,rows[i],&rrank,&ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */ 930 RO2E(A,0,rrank,ridx,&erow); 931 if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect row translation"); 932 933 elrow = erow / grid.MCSize(); /* Elemental local row index */ 934 elcol = ecol / grid.MRSize(); /* Elemental local column index */ 935 v = a->emat->GetLocal(elrow,elcol); 936 ierr = MatSetValues(Bmpi,1,&rows[i],1,&cols[j],(PetscScalar *)&v,INSERT_VALUES);CHKERRQ(ierr); 937 } 938 } 939 } 940 ierr = MatAssemblyBegin(Bmpi,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 941 ierr = MatAssemblyEnd(Bmpi,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 942 if (reuse == MAT_INPLACE_MATRIX) { 943 ierr = MatHeaderReplace(A,&Bmpi);CHKERRQ(ierr); 944 } else { 945 *B = Bmpi; 946 } 947 ierr = ISDestroy(&isrows);CHKERRQ(ierr); 948 ierr = ISDestroy(&iscols);CHKERRQ(ierr); 949 PetscFunctionReturn(0); 950 } 951 952 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 953 { 954 Mat mat_elemental; 955 PetscErrorCode ierr; 956 PetscInt M=A->rmap->N,N=A->cmap->N,row,ncols; 957 const PetscInt *cols; 958 const PetscScalar *vals; 959 960 PetscFunctionBegin; 961 if (reuse == MAT_REUSE_MATRIX) { 962 mat_elemental = *newmat; 963 ierr = MatZeroEntries(mat_elemental);CHKERRQ(ierr); 964 } else { 965 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 966 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr); 967 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 968 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 969 } 970 for (row=0; row<M; row++) { 971 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 972 /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 973 ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr); 974 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 975 } 976 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 977 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 978 979 if (reuse == MAT_INPLACE_MATRIX) { 980 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 981 } else { 982 *newmat = mat_elemental; 983 } 984 PetscFunctionReturn(0); 985 } 986 987 PETSC_INTERN PetscErrorCode MatConvert_MPIAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 988 { 989 Mat mat_elemental; 990 PetscErrorCode ierr; 991 PetscInt row,ncols,rstart=A->rmap->rstart,rend=A->rmap->rend,j; 992 const PetscInt *cols; 993 const PetscScalar *vals; 994 995 PetscFunctionBegin; 996 if (reuse == MAT_REUSE_MATRIX) { 997 mat_elemental = *newmat; 998 ierr = MatZeroEntries(mat_elemental);CHKERRQ(ierr); 999 } else { 1000 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 1001 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,A->rmap->N,A->cmap->N);CHKERRQ(ierr); 1002 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 1003 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 1004 } 1005 for (row=rstart; row<rend; row++) { 1006 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 1007 for (j=0; j<ncols; j++) { 1008 /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 1009 ierr = MatSetValues(mat_elemental,1,&row,1,&cols[j],&vals[j],ADD_VALUES);CHKERRQ(ierr); 1010 } 1011 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 1012 } 1013 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1014 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1015 1016 if (reuse == MAT_INPLACE_MATRIX) { 1017 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 1018 } else { 1019 *newmat = mat_elemental; 1020 } 1021 PetscFunctionReturn(0); 1022 } 1023 1024 PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 1025 { 1026 Mat mat_elemental; 1027 PetscErrorCode ierr; 1028 PetscInt M=A->rmap->N,N=A->cmap->N,row,ncols,j; 1029 const PetscInt *cols; 1030 const PetscScalar *vals; 1031 1032 PetscFunctionBegin; 1033 if (reuse == MAT_REUSE_MATRIX) { 1034 mat_elemental = *newmat; 1035 ierr = MatZeroEntries(mat_elemental);CHKERRQ(ierr); 1036 } else { 1037 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 1038 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr); 1039 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 1040 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 1041 } 1042 ierr = MatGetRowUpperTriangular(A);CHKERRQ(ierr); 1043 for (row=0; row<M; row++) { 1044 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 1045 /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 1046 ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr); 1047 for (j=0; j<ncols; j++) { /* lower triangular part */ 1048 PetscScalar v; 1049 if (cols[j] == row) continue; 1050 v = A->hermitian ? PetscConj(vals[j]) : vals[j]; 1051 ierr = MatSetValues(mat_elemental,1,&cols[j],1,&row,&v,ADD_VALUES);CHKERRQ(ierr); 1052 } 1053 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 1054 } 1055 ierr = MatRestoreRowUpperTriangular(A);CHKERRQ(ierr); 1056 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1057 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1058 1059 if (reuse == MAT_INPLACE_MATRIX) { 1060 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 1061 } else { 1062 *newmat = mat_elemental; 1063 } 1064 PetscFunctionReturn(0); 1065 } 1066 1067 PETSC_INTERN PetscErrorCode MatConvert_MPISBAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 1068 { 1069 Mat mat_elemental; 1070 PetscErrorCode ierr; 1071 PetscInt M=A->rmap->N,N=A->cmap->N,row,ncols,j,rstart=A->rmap->rstart,rend=A->rmap->rend; 1072 const PetscInt *cols; 1073 const PetscScalar *vals; 1074 1075 PetscFunctionBegin; 1076 if (reuse == MAT_REUSE_MATRIX) { 1077 mat_elemental = *newmat; 1078 ierr = MatZeroEntries(mat_elemental);CHKERRQ(ierr); 1079 } else { 1080 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 1081 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr); 1082 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 1083 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 1084 } 1085 ierr = MatGetRowUpperTriangular(A);CHKERRQ(ierr); 1086 for (row=rstart; row<rend; row++) { 1087 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 1088 /* PETSc-Elemental interface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 1089 ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr); 1090 for (j=0; j<ncols; j++) { /* lower triangular part */ 1091 PetscScalar v; 1092 if (cols[j] == row) continue; 1093 v = A->hermitian ? PetscConj(vals[j]) : vals[j]; 1094 ierr = MatSetValues(mat_elemental,1,&cols[j],1,&row,&v,ADD_VALUES);CHKERRQ(ierr); 1095 } 1096 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 1097 } 1098 ierr = MatRestoreRowUpperTriangular(A);CHKERRQ(ierr); 1099 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1100 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1101 1102 if (reuse == MAT_INPLACE_MATRIX) { 1103 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 1104 } else { 1105 *newmat = mat_elemental; 1106 } 1107 PetscFunctionReturn(0); 1108 } 1109 1110 static PetscErrorCode MatDestroy_Elemental(Mat A) 1111 { 1112 Mat_Elemental *a = (Mat_Elemental*)A->data; 1113 PetscErrorCode ierr; 1114 Mat_Elemental_Grid *commgrid; 1115 PetscBool flg; 1116 MPI_Comm icomm; 1117 1118 PetscFunctionBegin; 1119 delete a->emat; 1120 delete a->P; 1121 delete a->Q; 1122 1123 El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A)); 1124 ierr = PetscCommDuplicate(cxxcomm.comm,&icomm,NULL);CHKERRQ(ierr); 1125 ierr = MPI_Comm_get_attr(icomm,Petsc_Elemental_keyval,(void**)&commgrid,(int*)&flg);CHKERRMPI(ierr); 1126 if (--commgrid->grid_refct == 0) { 1127 delete commgrid->grid; 1128 ierr = PetscFree(commgrid);CHKERRQ(ierr); 1129 ierr = MPI_Comm_free_keyval(&Petsc_Elemental_keyval);CHKERRMPI(ierr); 1130 } 1131 ierr = PetscCommDestroy(&icomm);CHKERRQ(ierr); 1132 ierr = PetscObjectComposeFunction((PetscObject)A,"MatGetOwnershipIS_C",NULL);CHKERRQ(ierr); 1133 ierr = PetscObjectComposeFunction((PetscObject)A,"MatFactorGetSolverType_C",NULL);CHKERRQ(ierr); 1134 ierr = PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_elemental_mpidense_C",NULL);CHKERRQ(ierr); 1135 ierr = PetscFree(A->data);CHKERRQ(ierr); 1136 PetscFunctionReturn(0); 1137 } 1138 1139 PetscErrorCode MatSetUp_Elemental(Mat A) 1140 { 1141 Mat_Elemental *a = (Mat_Elemental*)A->data; 1142 PetscErrorCode ierr; 1143 MPI_Comm comm; 1144 PetscMPIInt rsize,csize; 1145 PetscInt n; 1146 1147 PetscFunctionBegin; 1148 ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr); 1149 ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr); 1150 1151 /* Check if local row and column sizes are equally distributed. 1152 Jed: Elemental uses "element" cyclic ordering so the sizes need to match that 1153 exactly. The strategy in MatElemental is for PETSc to implicitly permute to block ordering (like would be returned by 1154 PetscSplitOwnership(comm,&n,&N), at which point Elemental matrices can act on PETSc vectors without redistributing the vectors. */ 1155 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 1156 n = PETSC_DECIDE; 1157 ierr = PetscSplitOwnership(comm,&n,&A->rmap->N);CHKERRQ(ierr); 1158 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); 1159 1160 n = PETSC_DECIDE; 1161 ierr = PetscSplitOwnership(comm,&n,&A->cmap->N);CHKERRQ(ierr); 1162 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); 1163 1164 a->emat->Resize(A->rmap->N,A->cmap->N);CHKERRQ(ierr); 1165 El::Zero(*a->emat); 1166 1167 ierr = MPI_Comm_size(A->rmap->comm,&rsize);CHKERRMPI(ierr); 1168 ierr = MPI_Comm_size(A->cmap->comm,&csize);CHKERRMPI(ierr); 1169 if (csize != rsize) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Cannot use row and column communicators of different sizes"); 1170 a->commsize = rsize; 1171 a->mr[0] = A->rmap->N % rsize; if (!a->mr[0]) a->mr[0] = rsize; 1172 a->mr[1] = A->cmap->N % csize; if (!a->mr[1]) a->mr[1] = csize; 1173 a->m[0] = A->rmap->N / rsize + (a->mr[0] != rsize); 1174 a->m[1] = A->cmap->N / csize + (a->mr[1] != csize); 1175 PetscFunctionReturn(0); 1176 } 1177 1178 PetscErrorCode MatAssemblyBegin_Elemental(Mat A, MatAssemblyType type) 1179 { 1180 Mat_Elemental *a = (Mat_Elemental*)A->data; 1181 1182 PetscFunctionBegin; 1183 /* printf("Calling ProcessQueues\n"); */ 1184 a->emat->ProcessQueues(); 1185 /* printf("Finished ProcessQueues\n"); */ 1186 PetscFunctionReturn(0); 1187 } 1188 1189 PetscErrorCode MatAssemblyEnd_Elemental(Mat A, MatAssemblyType type) 1190 { 1191 PetscFunctionBegin; 1192 /* Currently does nothing */ 1193 PetscFunctionReturn(0); 1194 } 1195 1196 PetscErrorCode MatLoad_Elemental(Mat newMat, PetscViewer viewer) 1197 { 1198 PetscErrorCode ierr; 1199 Mat Adense,Ae; 1200 MPI_Comm comm; 1201 1202 PetscFunctionBegin; 1203 ierr = PetscObjectGetComm((PetscObject)newMat,&comm);CHKERRQ(ierr); 1204 ierr = MatCreate(comm,&Adense);CHKERRQ(ierr); 1205 ierr = MatSetType(Adense,MATDENSE);CHKERRQ(ierr); 1206 ierr = MatLoad(Adense,viewer);CHKERRQ(ierr); 1207 ierr = MatConvert(Adense, MATELEMENTAL, MAT_INITIAL_MATRIX,&Ae);CHKERRQ(ierr); 1208 ierr = MatDestroy(&Adense);CHKERRQ(ierr); 1209 ierr = MatHeaderReplace(newMat,&Ae);CHKERRQ(ierr); 1210 PetscFunctionReturn(0); 1211 } 1212 1213 /* -------------------------------------------------------------------*/ 1214 static struct _MatOps MatOps_Values = { 1215 MatSetValues_Elemental, 1216 0, 1217 0, 1218 MatMult_Elemental, 1219 /* 4*/ MatMultAdd_Elemental, 1220 MatMultTranspose_Elemental, 1221 MatMultTransposeAdd_Elemental, 1222 MatSolve_Elemental, 1223 MatSolveAdd_Elemental, 1224 0, 1225 /*10*/ 0, 1226 MatLUFactor_Elemental, 1227 MatCholeskyFactor_Elemental, 1228 0, 1229 MatTranspose_Elemental, 1230 /*15*/ MatGetInfo_Elemental, 1231 0, 1232 MatGetDiagonal_Elemental, 1233 MatDiagonalScale_Elemental, 1234 MatNorm_Elemental, 1235 /*20*/ MatAssemblyBegin_Elemental, 1236 MatAssemblyEnd_Elemental, 1237 MatSetOption_Elemental, 1238 MatZeroEntries_Elemental, 1239 /*24*/ 0, 1240 MatLUFactorSymbolic_Elemental, 1241 MatLUFactorNumeric_Elemental, 1242 MatCholeskyFactorSymbolic_Elemental, 1243 MatCholeskyFactorNumeric_Elemental, 1244 /*29*/ MatSetUp_Elemental, 1245 0, 1246 0, 1247 0, 1248 0, 1249 /*34*/ MatDuplicate_Elemental, 1250 0, 1251 0, 1252 0, 1253 0, 1254 /*39*/ MatAXPY_Elemental, 1255 0, 1256 0, 1257 0, 1258 MatCopy_Elemental, 1259 /*44*/ 0, 1260 MatScale_Elemental, 1261 MatShift_Basic, 1262 0, 1263 0, 1264 /*49*/ 0, 1265 0, 1266 0, 1267 0, 1268 0, 1269 /*54*/ 0, 1270 0, 1271 0, 1272 0, 1273 0, 1274 /*59*/ 0, 1275 MatDestroy_Elemental, 1276 MatView_Elemental, 1277 0, 1278 0, 1279 /*64*/ 0, 1280 0, 1281 0, 1282 0, 1283 0, 1284 /*69*/ 0, 1285 0, 1286 MatConvert_Elemental_Dense, 1287 0, 1288 0, 1289 /*74*/ 0, 1290 0, 1291 0, 1292 0, 1293 0, 1294 /*79*/ 0, 1295 0, 1296 0, 1297 0, 1298 MatLoad_Elemental, 1299 /*84*/ 0, 1300 0, 1301 0, 1302 0, 1303 0, 1304 /*89*/ 0, 1305 0, 1306 MatMatMultNumeric_Elemental, 1307 0, 1308 0, 1309 /*94*/ 0, 1310 0, 1311 0, 1312 MatMatTransposeMultNumeric_Elemental, 1313 0, 1314 /*99*/ MatProductSetFromOptions_Elemental, 1315 0, 1316 0, 1317 MatConjugate_Elemental, 1318 0, 1319 /*104*/0, 1320 0, 1321 0, 1322 0, 1323 0, 1324 /*109*/MatMatSolve_Elemental, 1325 0, 1326 0, 1327 0, 1328 MatMissingDiagonal_Elemental, 1329 /*114*/0, 1330 0, 1331 0, 1332 0, 1333 0, 1334 /*119*/0, 1335 MatHermitianTranspose_Elemental, 1336 0, 1337 0, 1338 0, 1339 /*124*/0, 1340 0, 1341 0, 1342 0, 1343 0, 1344 /*129*/0, 1345 0, 1346 0, 1347 0, 1348 0, 1349 /*134*/0, 1350 0, 1351 0, 1352 0, 1353 0, 1354 0, 1355 /*140*/0, 1356 0, 1357 0, 1358 0, 1359 0, 1360 /*145*/0, 1361 0, 1362 0 1363 }; 1364 1365 /*MC 1366 MATELEMENTAL = "elemental" - A matrix type for dense matrices using the Elemental package 1367 1368 Use ./configure --download-elemental to install PETSc to use Elemental 1369 1370 Use -pc_type lu -pc_factor_mat_solver_type elemental to use this direct solver 1371 1372 Options Database Keys: 1373 + -mat_type elemental - sets the matrix type to "elemental" during a call to MatSetFromOptions() 1374 - -mat_elemental_grid_height - sets Grid Height for 2D cyclic ordering of internal matrix 1375 1376 Level: beginner 1377 1378 .seealso: MATDENSE 1379 M*/ 1380 1381 PETSC_EXTERN PetscErrorCode MatCreate_Elemental(Mat A) 1382 { 1383 Mat_Elemental *a; 1384 PetscErrorCode ierr; 1385 PetscBool flg,flg1; 1386 Mat_Elemental_Grid *commgrid; 1387 MPI_Comm icomm; 1388 PetscInt optv1; 1389 1390 PetscFunctionBegin; 1391 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 1392 A->insertmode = NOT_SET_VALUES; 1393 1394 ierr = PetscNewLog(A,&a);CHKERRQ(ierr); 1395 A->data = (void*)a; 1396 1397 /* Set up the elemental matrix */ 1398 El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A)); 1399 1400 /* Grid needs to be shared between multiple Mats on the same communicator, implement by attribute caching on the MPI_Comm */ 1401 if (Petsc_Elemental_keyval == MPI_KEYVAL_INVALID) { 1402 ierr = MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN,MPI_COMM_NULL_DELETE_FN,&Petsc_Elemental_keyval,(void*)0);CHKERRMPI(ierr); 1403 ierr = PetscCitationsRegister(ElementalCitation,&ElementalCite);CHKERRQ(ierr); 1404 } 1405 ierr = PetscCommDuplicate(cxxcomm.comm,&icomm,NULL);CHKERRQ(ierr); 1406 ierr = MPI_Comm_get_attr(icomm,Petsc_Elemental_keyval,(void**)&commgrid,(int*)&flg);CHKERRMPI(ierr); 1407 if (!flg) { 1408 ierr = PetscNewLog(A,&commgrid);CHKERRQ(ierr); 1409 1410 ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)A),((PetscObject)A)->prefix,"Elemental Options","Mat");CHKERRQ(ierr); 1411 /* displayed default grid sizes (CommSize,1) are set by us arbitrarily until El::Grid() is called */ 1412 ierr = PetscOptionsInt("-mat_elemental_grid_height","Grid Height","None",El::mpi::Size(cxxcomm),&optv1,&flg1);CHKERRQ(ierr); 1413 if (flg1) { 1414 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)); 1415 commgrid->grid = new El::Grid(cxxcomm,optv1); /* use user-provided grid height */ 1416 } else { 1417 commgrid->grid = new El::Grid(cxxcomm); /* use Elemental default grid sizes */ 1418 /* printf("new commgrid->grid = %p\n",commgrid->grid); -- memory leak revealed by valgrind? */ 1419 } 1420 commgrid->grid_refct = 1; 1421 ierr = MPI_Comm_set_attr(icomm,Petsc_Elemental_keyval,(void*)commgrid);CHKERRMPI(ierr); 1422 1423 a->pivoting = 1; 1424 ierr = PetscOptionsInt("-mat_elemental_pivoting","Pivoting","None",a->pivoting,&a->pivoting,NULL);CHKERRQ(ierr); 1425 1426 ierr = PetscOptionsEnd();CHKERRQ(ierr); 1427 } else { 1428 commgrid->grid_refct++; 1429 } 1430 ierr = PetscCommDestroy(&icomm);CHKERRQ(ierr); 1431 a->grid = commgrid->grid; 1432 a->emat = new El::DistMatrix<PetscElemScalar>(*a->grid); 1433 a->roworiented = PETSC_TRUE; 1434 1435 ierr = PetscObjectComposeFunction((PetscObject)A,"MatGetOwnershipIS_C",MatGetOwnershipIS_Elemental);CHKERRQ(ierr); 1436 ierr = PetscObjectComposeFunction((PetscObject)A,"MatProductSetFromOptions_elemental_mpidense_C",MatProductSetFromOptions_Elemental_MPIDense);CHKERRQ(ierr); 1437 ierr = PetscObjectChangeTypeName((PetscObject)A,MATELEMENTAL);CHKERRQ(ierr); 1438 PetscFunctionReturn(0); 1439 } 1440