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