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 ierr = PetscObjectStateIncrease((PetscObject)B);CHKERRQ(ierr); 507 PetscFunctionReturn(0); 508 } 509 510 static PetscErrorCode MatDuplicate_Elemental(Mat A,MatDuplicateOption op,Mat *B) 511 { 512 Mat Be; 513 MPI_Comm comm; 514 Mat_Elemental *a=(Mat_Elemental*)A->data; 515 PetscErrorCode ierr; 516 517 PetscFunctionBegin; 518 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 519 ierr = MatCreate(comm,&Be);CHKERRQ(ierr); 520 ierr = MatSetSizes(Be,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 521 ierr = MatSetType(Be,MATELEMENTAL);CHKERRQ(ierr); 522 ierr = MatSetUp(Be);CHKERRQ(ierr); 523 *B = Be; 524 if (op == MAT_COPY_VALUES) { 525 Mat_Elemental *b=(Mat_Elemental*)Be->data; 526 El::Copy(*a->emat,*b->emat); 527 } 528 Be->assembled = PETSC_TRUE; 529 PetscFunctionReturn(0); 530 } 531 532 static PetscErrorCode MatTranspose_Elemental(Mat A,MatReuse reuse,Mat *B) 533 { 534 Mat Be = *B; 535 PetscErrorCode ierr; 536 MPI_Comm comm; 537 Mat_Elemental *a = (Mat_Elemental*)A->data, *b; 538 539 PetscFunctionBegin; 540 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 541 /* Only out-of-place supported */ 542 if (reuse == MAT_INITIAL_MATRIX){ 543 ierr = MatCreate(comm,&Be);CHKERRQ(ierr); 544 ierr = MatSetSizes(Be,A->cmap->n,A->rmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 545 ierr = MatSetType(Be,MATELEMENTAL);CHKERRQ(ierr); 546 ierr = MatSetUp(Be);CHKERRQ(ierr); 547 *B = Be; 548 } 549 b = (Mat_Elemental*)Be->data; 550 El::Transpose(*a->emat,*b->emat); 551 Be->assembled = PETSC_TRUE; 552 PetscFunctionReturn(0); 553 } 554 555 static PetscErrorCode MatConjugate_Elemental(Mat A) 556 { 557 Mat_Elemental *a = (Mat_Elemental*)A->data; 558 559 PetscFunctionBegin; 560 El::Conjugate(*a->emat); 561 PetscFunctionReturn(0); 562 } 563 564 static PetscErrorCode MatHermitianTranspose_Elemental(Mat A,MatReuse reuse,Mat *B) 565 { 566 Mat Be = *B; 567 PetscErrorCode ierr; 568 MPI_Comm comm; 569 Mat_Elemental *a = (Mat_Elemental*)A->data, *b; 570 571 PetscFunctionBegin; 572 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 573 /* Only out-of-place supported */ 574 if (reuse == MAT_INITIAL_MATRIX){ 575 ierr = MatCreate(comm,&Be);CHKERRQ(ierr); 576 ierr = MatSetSizes(Be,A->cmap->n,A->rmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 577 ierr = MatSetType(Be,MATELEMENTAL);CHKERRQ(ierr); 578 ierr = MatSetUp(Be);CHKERRQ(ierr); 579 *B = Be; 580 } 581 b = (Mat_Elemental*)Be->data; 582 El::Adjoint(*a->emat,*b->emat); 583 Be->assembled = PETSC_TRUE; 584 PetscFunctionReturn(0); 585 } 586 587 static PetscErrorCode MatSolve_Elemental(Mat A,Vec B,Vec X) 588 { 589 Mat_Elemental *a = (Mat_Elemental*)A->data; 590 PetscErrorCode ierr; 591 PetscElemScalar *x; 592 PetscInt pivoting = a->pivoting; 593 594 PetscFunctionBegin; 595 ierr = VecCopy(B,X);CHKERRQ(ierr); 596 ierr = VecGetArray(X,(PetscScalar **)&x);CHKERRQ(ierr); 597 598 El::DistMatrix<PetscElemScalar,El::VC,El::STAR> xe; 599 xe.Attach(A->rmap->N,1,*a->grid,0,0,x,A->rmap->n); 600 El::DistMatrix<PetscElemScalar,El::MC,El::MR> xer(xe); 601 switch (A->factortype) { 602 case MAT_FACTOR_LU: 603 if (pivoting == 0) { 604 El::lu::SolveAfter(El::NORMAL,*a->emat,xer); 605 } else if (pivoting == 1) { 606 El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,xer); 607 } else { /* pivoting == 2 */ 608 El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,*a->Q,xer); 609 } 610 break; 611 case MAT_FACTOR_CHOLESKY: 612 El::cholesky::SolveAfter(El::UPPER,El::NORMAL,*a->emat,xer); 613 break; 614 default: 615 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unfactored Matrix or Unsupported MatFactorType"); 616 break; 617 } 618 El::Copy(xer,xe); 619 620 ierr = VecRestoreArray(X,(PetscScalar **)&x);CHKERRQ(ierr); 621 PetscFunctionReturn(0); 622 } 623 624 static PetscErrorCode MatSolveAdd_Elemental(Mat A,Vec B,Vec Y,Vec X) 625 { 626 PetscErrorCode ierr; 627 628 PetscFunctionBegin; 629 ierr = MatSolve_Elemental(A,B,X);CHKERRQ(ierr); 630 ierr = VecAXPY(X,1,Y);CHKERRQ(ierr); 631 PetscFunctionReturn(0); 632 } 633 634 static PetscErrorCode MatMatSolve_Elemental(Mat A,Mat B,Mat X) 635 { 636 Mat_Elemental *a=(Mat_Elemental*)A->data; 637 Mat_Elemental *b=(Mat_Elemental*)B->data; 638 Mat_Elemental *x=(Mat_Elemental*)X->data; 639 PetscInt pivoting = a->pivoting; 640 641 PetscFunctionBegin; 642 El::Copy(*b->emat,*x->emat); 643 switch (A->factortype) { 644 case MAT_FACTOR_LU: 645 if (pivoting == 0) { 646 El::lu::SolveAfter(El::NORMAL,*a->emat,*x->emat); 647 } else if (pivoting == 1) { 648 El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,*x->emat); 649 } else { 650 El::lu::SolveAfter(El::NORMAL,*a->emat,*a->P,*a->Q,*x->emat); 651 } 652 break; 653 case MAT_FACTOR_CHOLESKY: 654 El::cholesky::SolveAfter(El::UPPER,El::NORMAL,*a->emat,*x->emat); 655 break; 656 default: 657 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unfactored Matrix or Unsupported MatFactorType"); 658 break; 659 } 660 PetscFunctionReturn(0); 661 } 662 663 static PetscErrorCode MatLUFactor_Elemental(Mat A,IS row,IS col,const MatFactorInfo *info) 664 { 665 Mat_Elemental *a = (Mat_Elemental*)A->data; 666 PetscErrorCode ierr; 667 PetscInt pivoting = a->pivoting; 668 669 PetscFunctionBegin; 670 if (pivoting == 0) { 671 El::LU(*a->emat); 672 } else if (pivoting == 1) { 673 El::LU(*a->emat,*a->P); 674 } else { 675 El::LU(*a->emat,*a->P,*a->Q); 676 } 677 A->factortype = MAT_FACTOR_LU; 678 A->assembled = PETSC_TRUE; 679 680 ierr = PetscFree(A->solvertype);CHKERRQ(ierr); 681 ierr = PetscStrallocpy(MATSOLVERELEMENTAL,&A->solvertype);CHKERRQ(ierr); 682 PetscFunctionReturn(0); 683 } 684 685 static PetscErrorCode MatLUFactorNumeric_Elemental(Mat F,Mat A,const MatFactorInfo *info) 686 { 687 PetscErrorCode ierr; 688 689 PetscFunctionBegin; 690 ierr = MatCopy(A,F,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 691 ierr = MatLUFactor_Elemental(F,0,0,info);CHKERRQ(ierr); 692 PetscFunctionReturn(0); 693 } 694 695 static PetscErrorCode MatLUFactorSymbolic_Elemental(Mat F,Mat A,IS r,IS c,const MatFactorInfo *info) 696 { 697 PetscFunctionBegin; 698 /* F is create and allocated by MatGetFactor_elemental_petsc(), skip this routine. */ 699 PetscFunctionReturn(0); 700 } 701 702 static PetscErrorCode MatCholeskyFactor_Elemental(Mat A,IS perm,const MatFactorInfo *info) 703 { 704 Mat_Elemental *a = (Mat_Elemental*)A->data; 705 El::DistMatrix<PetscElemScalar,El::MC,El::STAR> d; 706 PetscErrorCode ierr; 707 708 PetscFunctionBegin; 709 El::Cholesky(El::UPPER,*a->emat); 710 A->factortype = MAT_FACTOR_CHOLESKY; 711 A->assembled = PETSC_TRUE; 712 713 ierr = PetscFree(A->solvertype);CHKERRQ(ierr); 714 ierr = PetscStrallocpy(MATSOLVERELEMENTAL,&A->solvertype);CHKERRQ(ierr); 715 PetscFunctionReturn(0); 716 } 717 718 static PetscErrorCode MatCholeskyFactorNumeric_Elemental(Mat F,Mat A,const MatFactorInfo *info) 719 { 720 PetscErrorCode ierr; 721 722 PetscFunctionBegin; 723 ierr = MatCopy(A,F,SAME_NONZERO_PATTERN);CHKERRQ(ierr); 724 ierr = MatCholeskyFactor_Elemental(F,0,info);CHKERRQ(ierr); 725 PetscFunctionReturn(0); 726 } 727 728 static PetscErrorCode MatCholeskyFactorSymbolic_Elemental(Mat F,Mat A,IS perm,const MatFactorInfo *info) 729 { 730 PetscFunctionBegin; 731 /* F is create and allocated by MatGetFactor_elemental_petsc(), skip this routine. */ 732 PetscFunctionReturn(0); 733 } 734 735 PetscErrorCode MatFactorGetSolverPackage_elemental_elemental(Mat A,const MatSolverPackage *type) 736 { 737 PetscFunctionBegin; 738 *type = MATSOLVERELEMENTAL; 739 PetscFunctionReturn(0); 740 } 741 742 static PetscErrorCode MatGetFactor_elemental_elemental(Mat A,MatFactorType ftype,Mat *F) 743 { 744 Mat B; 745 PetscErrorCode ierr; 746 747 PetscFunctionBegin; 748 /* Create the factorization matrix */ 749 ierr = MatCreate(PetscObjectComm((PetscObject)A),&B);CHKERRQ(ierr); 750 ierr = MatSetSizes(B,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 751 ierr = MatSetType(B,MATELEMENTAL);CHKERRQ(ierr); 752 ierr = MatSetUp(B);CHKERRQ(ierr); 753 B->factortype = ftype; 754 ierr = PetscFree(B->solvertype);CHKERRQ(ierr); 755 ierr = PetscStrallocpy(MATSOLVERELEMENTAL,&B->solvertype);CHKERRQ(ierr); 756 757 ierr = PetscObjectComposeFunction((PetscObject)B,"MatFactorGetSolverPackage_C",MatFactorGetSolverPackage_elemental_elemental);CHKERRQ(ierr); 758 *F = B; 759 PetscFunctionReturn(0); 760 } 761 762 PETSC_EXTERN PetscErrorCode MatSolverPackageRegister_Elemental(void) 763 { 764 PetscErrorCode ierr; 765 766 PetscFunctionBegin; 767 ierr = MatSolverPackageRegister(MATSOLVERELEMENTAL,MATELEMENTAL, MAT_FACTOR_LU,MatGetFactor_elemental_elemental);CHKERRQ(ierr); 768 ierr = MatSolverPackageRegister(MATSOLVERELEMENTAL,MATELEMENTAL, MAT_FACTOR_CHOLESKY,MatGetFactor_elemental_elemental);CHKERRQ(ierr); 769 PetscFunctionReturn(0); 770 } 771 772 static PetscErrorCode MatNorm_Elemental(Mat A,NormType type,PetscReal *nrm) 773 { 774 Mat_Elemental *a=(Mat_Elemental*)A->data; 775 776 PetscFunctionBegin; 777 switch (type){ 778 case NORM_1: 779 *nrm = El::OneNorm(*a->emat); 780 break; 781 case NORM_FROBENIUS: 782 *nrm = El::FrobeniusNorm(*a->emat); 783 break; 784 case NORM_INFINITY: 785 *nrm = El::InfinityNorm(*a->emat); 786 break; 787 default: 788 printf("Error: unsupported norm type!\n"); 789 } 790 PetscFunctionReturn(0); 791 } 792 793 static PetscErrorCode MatZeroEntries_Elemental(Mat A) 794 { 795 Mat_Elemental *a=(Mat_Elemental*)A->data; 796 797 PetscFunctionBegin; 798 El::Zero(*a->emat); 799 PetscFunctionReturn(0); 800 } 801 802 static PetscErrorCode MatGetOwnershipIS_Elemental(Mat A,IS *rows,IS *cols) 803 { 804 Mat_Elemental *a = (Mat_Elemental*)A->data; 805 PetscErrorCode ierr; 806 PetscInt i,m,shift,stride,*idx; 807 808 PetscFunctionBegin; 809 if (rows) { 810 m = a->emat->LocalHeight(); 811 shift = a->emat->ColShift(); 812 stride = a->emat->ColStride(); 813 ierr = PetscMalloc1(m,&idx);CHKERRQ(ierr); 814 for (i=0; i<m; i++) { 815 PetscInt rank,offset; 816 E2RO(A,0,shift+i*stride,&rank,&offset); 817 RO2P(A,0,rank,offset,&idx[i]); 818 } 819 ierr = ISCreateGeneral(PETSC_COMM_SELF,m,idx,PETSC_OWN_POINTER,rows);CHKERRQ(ierr); 820 } 821 if (cols) { 822 m = a->emat->LocalWidth(); 823 shift = a->emat->RowShift(); 824 stride = a->emat->RowStride(); 825 ierr = PetscMalloc1(m,&idx);CHKERRQ(ierr); 826 for (i=0; i<m; i++) { 827 PetscInt rank,offset; 828 E2RO(A,1,shift+i*stride,&rank,&offset); 829 RO2P(A,1,rank,offset,&idx[i]); 830 } 831 ierr = ISCreateGeneral(PETSC_COMM_SELF,m,idx,PETSC_OWN_POINTER,cols);CHKERRQ(ierr); 832 } 833 PetscFunctionReturn(0); 834 } 835 836 static PetscErrorCode MatConvert_Elemental_Dense(Mat A,MatType newtype,MatReuse reuse,Mat *B) 837 { 838 Mat Bmpi; 839 Mat_Elemental *a = (Mat_Elemental*)A->data; 840 MPI_Comm comm; 841 PetscErrorCode ierr; 842 IS isrows,iscols; 843 PetscInt rrank,ridx,crank,cidx,nrows,ncols,i,j,erow,ecol,elrow,elcol; 844 const PetscInt *rows,*cols; 845 PetscElemScalar v; 846 const El::Grid &grid = a->emat->Grid(); 847 848 PetscFunctionBegin; 849 ierr = PetscObjectGetComm((PetscObject)A,&comm);CHKERRQ(ierr); 850 851 if (reuse == MAT_REUSE_MATRIX) { 852 Bmpi = *B; 853 } else { 854 ierr = MatCreate(comm,&Bmpi);CHKERRQ(ierr); 855 ierr = MatSetSizes(Bmpi,A->rmap->n,A->cmap->n,PETSC_DECIDE,PETSC_DECIDE);CHKERRQ(ierr); 856 ierr = MatSetType(Bmpi,MATDENSE);CHKERRQ(ierr); 857 ierr = MatSetUp(Bmpi);CHKERRQ(ierr); 858 } 859 860 /* Get local entries of A */ 861 ierr = MatGetOwnershipIS(A,&isrows,&iscols);CHKERRQ(ierr); 862 ierr = ISGetLocalSize(isrows,&nrows);CHKERRQ(ierr); 863 ierr = ISGetIndices(isrows,&rows);CHKERRQ(ierr); 864 ierr = ISGetLocalSize(iscols,&ncols);CHKERRQ(ierr); 865 ierr = ISGetIndices(iscols,&cols);CHKERRQ(ierr); 866 867 if (a->roworiented) { 868 for (i=0; i<nrows; i++) { 869 P2RO(A,0,rows[i],&rrank,&ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */ 870 RO2E(A,0,rrank,ridx,&erow); 871 if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect row translation"); 872 for (j=0; j<ncols; j++) { 873 P2RO(A,1,cols[j],&crank,&cidx); 874 RO2E(A,1,crank,cidx,&ecol); 875 if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect col translation"); 876 877 elrow = erow / grid.MCSize(); /* Elemental local row index */ 878 elcol = ecol / grid.MRSize(); /* Elemental local column index */ 879 v = a->emat->GetLocal(elrow,elcol); 880 ierr = MatSetValues(Bmpi,1,&rows[i],1,&cols[j],(PetscScalar *)&v,INSERT_VALUES);CHKERRQ(ierr); 881 } 882 } 883 } else { /* column-oriented */ 884 for (j=0; j<ncols; j++) { 885 P2RO(A,1,cols[j],&crank,&cidx); 886 RO2E(A,1,crank,cidx,&ecol); 887 if (crank < 0 || cidx < 0 || ecol < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect col translation"); 888 for (i=0; i<nrows; i++) { 889 P2RO(A,0,rows[i],&rrank,&ridx); /* convert indices between PETSc <-> (Rank,Offset) <-> Elemental */ 890 RO2E(A,0,rrank,ridx,&erow); 891 if (rrank < 0 || ridx < 0 || erow < 0) SETERRQ(comm,PETSC_ERR_PLIB,"Incorrect row translation"); 892 893 elrow = erow / grid.MCSize(); /* Elemental local row index */ 894 elcol = ecol / grid.MRSize(); /* Elemental local column index */ 895 v = a->emat->GetLocal(elrow,elcol); 896 ierr = MatSetValues(Bmpi,1,&rows[i],1,&cols[j],(PetscScalar *)&v,INSERT_VALUES);CHKERRQ(ierr); 897 } 898 } 899 } 900 ierr = MatAssemblyBegin(Bmpi,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 901 ierr = MatAssemblyEnd(Bmpi,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 902 if (reuse == MAT_INPLACE_MATRIX) { 903 ierr = MatHeaderReplace(A,&Bmpi);CHKERRQ(ierr); 904 } else { 905 *B = Bmpi; 906 } 907 ierr = ISDestroy(&isrows);CHKERRQ(ierr); 908 ierr = ISDestroy(&iscols);CHKERRQ(ierr); 909 PetscFunctionReturn(0); 910 } 911 912 PETSC_INTERN PetscErrorCode MatConvert_SeqAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 913 { 914 Mat mat_elemental; 915 PetscErrorCode ierr; 916 PetscInt M=A->rmap->N,N=A->cmap->N,row,ncols; 917 const PetscInt *cols; 918 const PetscScalar *vals; 919 920 PetscFunctionBegin; 921 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 922 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr); 923 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 924 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 925 for (row=0; row<M; row++) { 926 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 927 /* PETSc-Elemental interaface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 928 ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr); 929 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 930 } 931 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 932 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 933 934 if (reuse == MAT_INPLACE_MATRIX) { 935 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 936 } else { 937 *newmat = mat_elemental; 938 } 939 PetscFunctionReturn(0); 940 } 941 942 PETSC_INTERN PetscErrorCode MatConvert_MPIAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 943 { 944 Mat mat_elemental; 945 PetscErrorCode ierr; 946 PetscInt row,ncols,rstart=A->rmap->rstart,rend=A->rmap->rend,j; 947 const PetscInt *cols; 948 const PetscScalar *vals; 949 950 PetscFunctionBegin; 951 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 952 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,A->rmap->N,A->cmap->N);CHKERRQ(ierr); 953 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 954 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 955 for (row=rstart; row<rend; row++) { 956 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 957 for (j=0; j<ncols; j++) { 958 /* PETSc-Elemental interaface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 959 ierr = MatSetValues(mat_elemental,1,&row,1,&cols[j],&vals[j],ADD_VALUES);CHKERRQ(ierr); 960 } 961 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 962 } 963 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 964 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 965 966 if (reuse == MAT_INPLACE_MATRIX) { 967 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 968 } else { 969 *newmat = mat_elemental; 970 } 971 PetscFunctionReturn(0); 972 } 973 974 PETSC_INTERN PetscErrorCode MatConvert_SeqSBAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 975 { 976 Mat mat_elemental; 977 PetscErrorCode ierr; 978 PetscInt M=A->rmap->N,N=A->cmap->N,row,ncols,j; 979 const PetscInt *cols; 980 const PetscScalar *vals; 981 982 PetscFunctionBegin; 983 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 984 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr); 985 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 986 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 987 ierr = MatGetRowUpperTriangular(A);CHKERRQ(ierr); 988 for (row=0; row<M; row++) { 989 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 990 /* PETSc-Elemental interaface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 991 ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr); 992 for (j=0; j<ncols; j++) { /* lower triangular part */ 993 if (cols[j] == row) continue; 994 ierr = MatSetValues(mat_elemental,1,&cols[j],1,&row,&vals[j],ADD_VALUES);CHKERRQ(ierr); 995 } 996 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 997 } 998 ierr = MatRestoreRowUpperTriangular(A);CHKERRQ(ierr); 999 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1000 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1001 1002 if (reuse == MAT_INPLACE_MATRIX) { 1003 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 1004 } else { 1005 *newmat = mat_elemental; 1006 } 1007 PetscFunctionReturn(0); 1008 } 1009 1010 PETSC_INTERN PetscErrorCode MatConvert_MPISBAIJ_Elemental(Mat A, MatType newtype,MatReuse reuse,Mat *newmat) 1011 { 1012 Mat mat_elemental; 1013 PetscErrorCode ierr; 1014 PetscInt M=A->rmap->N,N=A->cmap->N,row,ncols,j,rstart=A->rmap->rstart,rend=A->rmap->rend; 1015 const PetscInt *cols; 1016 const PetscScalar *vals; 1017 1018 PetscFunctionBegin; 1019 ierr = MatCreate(PetscObjectComm((PetscObject)A), &mat_elemental);CHKERRQ(ierr); 1020 ierr = MatSetSizes(mat_elemental,PETSC_DECIDE,PETSC_DECIDE,M,N);CHKERRQ(ierr); 1021 ierr = MatSetType(mat_elemental,MATELEMENTAL);CHKERRQ(ierr); 1022 ierr = MatSetUp(mat_elemental);CHKERRQ(ierr); 1023 ierr = MatGetRowUpperTriangular(A);CHKERRQ(ierr); 1024 for (row=rstart; row<rend; row++) { 1025 ierr = MatGetRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 1026 /* PETSc-Elemental interaface uses axpy for setting off-processor entries, only ADD_VALUES is allowed */ 1027 ierr = MatSetValues(mat_elemental,1,&row,ncols,cols,vals,ADD_VALUES);CHKERRQ(ierr); 1028 for (j=0; j<ncols; j++) { /* lower triangular part */ 1029 if (cols[j] == row) continue; 1030 ierr = MatSetValues(mat_elemental,1,&cols[j],1,&row,&vals[j],ADD_VALUES);CHKERRQ(ierr); 1031 } 1032 ierr = MatRestoreRow(A,row,&ncols,&cols,&vals);CHKERRQ(ierr); 1033 } 1034 ierr = MatRestoreRowUpperTriangular(A);CHKERRQ(ierr); 1035 ierr = MatAssemblyBegin(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1036 ierr = MatAssemblyEnd(mat_elemental, MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1037 1038 if (reuse == MAT_INPLACE_MATRIX) { 1039 ierr = MatHeaderReplace(A,&mat_elemental);CHKERRQ(ierr); 1040 } else { 1041 *newmat = mat_elemental; 1042 } 1043 PetscFunctionReturn(0); 1044 } 1045 1046 static PetscErrorCode MatDestroy_Elemental(Mat A) 1047 { 1048 Mat_Elemental *a = (Mat_Elemental*)A->data; 1049 PetscErrorCode ierr; 1050 Mat_Elemental_Grid *commgrid; 1051 PetscBool flg; 1052 MPI_Comm icomm; 1053 1054 PetscFunctionBegin; 1055 delete a->emat; 1056 delete a->P; 1057 delete a->Q; 1058 1059 El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A)); 1060 ierr = PetscCommDuplicate(cxxcomm.comm,&icomm,NULL);CHKERRQ(ierr); 1061 ierr = MPI_Attr_get(icomm,Petsc_Elemental_keyval,(void**)&commgrid,(int*)&flg);CHKERRQ(ierr); 1062 if (--commgrid->grid_refct == 0) { 1063 delete commgrid->grid; 1064 ierr = PetscFree(commgrid);CHKERRQ(ierr); 1065 ierr = MPI_Keyval_free(&Petsc_Elemental_keyval);CHKERRQ(ierr); 1066 } 1067 ierr = PetscCommDestroy(&icomm);CHKERRQ(ierr); 1068 ierr = PetscObjectComposeFunction((PetscObject)A,"MatGetOwnershipIS_C",NULL);CHKERRQ(ierr); 1069 ierr = PetscObjectComposeFunction((PetscObject)A,"MatFactorGetSolverPackage_C",NULL);CHKERRQ(ierr); 1070 ierr = PetscFree(A->data);CHKERRQ(ierr); 1071 PetscFunctionReturn(0); 1072 } 1073 1074 PetscErrorCode MatSetUp_Elemental(Mat A) 1075 { 1076 Mat_Elemental *a = (Mat_Elemental*)A->data; 1077 PetscErrorCode ierr; 1078 PetscMPIInt rsize,csize; 1079 1080 PetscFunctionBegin; 1081 ierr = PetscLayoutSetUp(A->rmap);CHKERRQ(ierr); 1082 ierr = PetscLayoutSetUp(A->cmap);CHKERRQ(ierr); 1083 1084 a->emat->Resize(A->rmap->N,A->cmap->N);CHKERRQ(ierr); 1085 El::Zero(*a->emat); 1086 1087 ierr = MPI_Comm_size(A->rmap->comm,&rsize);CHKERRQ(ierr); 1088 ierr = MPI_Comm_size(A->cmap->comm,&csize);CHKERRQ(ierr); 1089 if (csize != rsize) SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Cannot use row and column communicators of different sizes"); 1090 a->commsize = rsize; 1091 a->mr[0] = A->rmap->N % rsize; if (!a->mr[0]) a->mr[0] = rsize; 1092 a->mr[1] = A->cmap->N % csize; if (!a->mr[1]) a->mr[1] = csize; 1093 a->m[0] = A->rmap->N / rsize + (a->mr[0] != rsize); 1094 a->m[1] = A->cmap->N / csize + (a->mr[1] != csize); 1095 PetscFunctionReturn(0); 1096 } 1097 1098 PetscErrorCode MatAssemblyBegin_Elemental(Mat A, MatAssemblyType type) 1099 { 1100 Mat_Elemental *a = (Mat_Elemental*)A->data; 1101 1102 PetscFunctionBegin; 1103 /* printf("Calling ProcessQueues\n"); */ 1104 a->emat->ProcessQueues(); 1105 /* printf("Finished ProcessQueues\n"); */ 1106 PetscFunctionReturn(0); 1107 } 1108 1109 PetscErrorCode MatAssemblyEnd_Elemental(Mat A, MatAssemblyType type) 1110 { 1111 PetscFunctionBegin; 1112 /* Currently does nothing */ 1113 PetscFunctionReturn(0); 1114 } 1115 1116 PetscErrorCode MatLoad_Elemental(Mat newMat, PetscViewer viewer) 1117 { 1118 PetscErrorCode ierr; 1119 Mat Adense,Ae; 1120 MPI_Comm comm; 1121 1122 PetscFunctionBegin; 1123 ierr = PetscObjectGetComm((PetscObject)newMat,&comm);CHKERRQ(ierr); 1124 ierr = MatCreate(comm,&Adense);CHKERRQ(ierr); 1125 ierr = MatSetType(Adense,MATDENSE);CHKERRQ(ierr); 1126 ierr = MatLoad(Adense,viewer);CHKERRQ(ierr); 1127 ierr = MatConvert(Adense, MATELEMENTAL, MAT_INITIAL_MATRIX,&Ae);CHKERRQ(ierr); 1128 ierr = MatDestroy(&Adense);CHKERRQ(ierr); 1129 ierr = MatHeaderReplace(newMat,&Ae);CHKERRQ(ierr); 1130 PetscFunctionReturn(0); 1131 } 1132 1133 /* -------------------------------------------------------------------*/ 1134 static struct _MatOps MatOps_Values = { 1135 MatSetValues_Elemental, 1136 0, 1137 0, 1138 MatMult_Elemental, 1139 /* 4*/ MatMultAdd_Elemental, 1140 MatMultTranspose_Elemental, 1141 MatMultTransposeAdd_Elemental, 1142 MatSolve_Elemental, 1143 MatSolveAdd_Elemental, 1144 0, 1145 /*10*/ 0, 1146 MatLUFactor_Elemental, 1147 MatCholeskyFactor_Elemental, 1148 0, 1149 MatTranspose_Elemental, 1150 /*15*/ MatGetInfo_Elemental, 1151 0, 1152 MatGetDiagonal_Elemental, 1153 MatDiagonalScale_Elemental, 1154 MatNorm_Elemental, 1155 /*20*/ MatAssemblyBegin_Elemental, 1156 MatAssemblyEnd_Elemental, 1157 MatSetOption_Elemental, 1158 MatZeroEntries_Elemental, 1159 /*24*/ 0, 1160 MatLUFactorSymbolic_Elemental, 1161 MatLUFactorNumeric_Elemental, 1162 MatCholeskyFactorSymbolic_Elemental, 1163 MatCholeskyFactorNumeric_Elemental, 1164 /*29*/ MatSetUp_Elemental, 1165 0, 1166 0, 1167 0, 1168 0, 1169 /*34*/ MatDuplicate_Elemental, 1170 0, 1171 0, 1172 0, 1173 0, 1174 /*39*/ MatAXPY_Elemental, 1175 0, 1176 0, 1177 0, 1178 MatCopy_Elemental, 1179 /*44*/ 0, 1180 MatScale_Elemental, 1181 MatShift_Basic, 1182 0, 1183 0, 1184 /*49*/ 0, 1185 0, 1186 0, 1187 0, 1188 0, 1189 /*54*/ 0, 1190 0, 1191 0, 1192 0, 1193 0, 1194 /*59*/ 0, 1195 MatDestroy_Elemental, 1196 MatView_Elemental, 1197 0, 1198 0, 1199 /*64*/ 0, 1200 0, 1201 0, 1202 0, 1203 0, 1204 /*69*/ 0, 1205 0, 1206 MatConvert_Elemental_Dense, 1207 0, 1208 0, 1209 /*74*/ 0, 1210 0, 1211 0, 1212 0, 1213 0, 1214 /*79*/ 0, 1215 0, 1216 0, 1217 0, 1218 MatLoad_Elemental, 1219 /*84*/ 0, 1220 0, 1221 0, 1222 0, 1223 0, 1224 /*89*/ MatMatMult_Elemental, 1225 MatMatMultSymbolic_Elemental, 1226 MatMatMultNumeric_Elemental, 1227 0, 1228 0, 1229 /*94*/ 0, 1230 MatMatTransposeMult_Elemental, 1231 MatMatTransposeMultSymbolic_Elemental, 1232 MatMatTransposeMultNumeric_Elemental, 1233 0, 1234 /*99*/ 0, 1235 0, 1236 0, 1237 MatConjugate_Elemental, 1238 0, 1239 /*104*/0, 1240 0, 1241 0, 1242 0, 1243 0, 1244 /*109*/MatMatSolve_Elemental, 1245 0, 1246 0, 1247 0, 1248 0, 1249 /*114*/0, 1250 0, 1251 0, 1252 0, 1253 0, 1254 /*119*/0, 1255 MatHermitianTranspose_Elemental, 1256 0, 1257 0, 1258 0, 1259 /*124*/0, 1260 0, 1261 0, 1262 0, 1263 0, 1264 /*129*/0, 1265 0, 1266 0, 1267 0, 1268 0, 1269 /*134*/0, 1270 0, 1271 0, 1272 0, 1273 0 1274 }; 1275 1276 /*MC 1277 MATELEMENTAL = "elemental" - A matrix type for dense matrices using the Elemental package 1278 1279 Use ./configure --download-elemental to install PETSc to use Elemental 1280 1281 Use -pc_type lu -pc_factor_mat_solver_package elemental to us this direct solver 1282 1283 Options Database Keys: 1284 + -mat_type elemental - sets the matrix type to "elemental" during a call to MatSetFromOptions() 1285 - -mat_elemental_grid_height - sets Grid Height for 2D cyclic ordering of internal matrix 1286 1287 Level: beginner 1288 1289 .seealso: MATDENSE 1290 M*/ 1291 1292 PETSC_EXTERN PetscErrorCode MatCreate_Elemental(Mat A) 1293 { 1294 Mat_Elemental *a; 1295 PetscErrorCode ierr; 1296 PetscBool flg,flg1; 1297 Mat_Elemental_Grid *commgrid; 1298 MPI_Comm icomm; 1299 PetscInt optv1; 1300 1301 PetscFunctionBegin; 1302 ierr = PetscElementalInitializePackage();CHKERRQ(ierr); 1303 ierr = PetscMemcpy(A->ops,&MatOps_Values,sizeof(struct _MatOps));CHKERRQ(ierr); 1304 A->insertmode = NOT_SET_VALUES; 1305 1306 ierr = PetscNewLog(A,&a);CHKERRQ(ierr); 1307 A->data = (void*)a; 1308 1309 /* Set up the elemental matrix */ 1310 El::mpi::Comm cxxcomm(PetscObjectComm((PetscObject)A)); 1311 1312 /* Grid needs to be shared between multiple Mats on the same communicator, implement by attribute caching on the MPI_Comm */ 1313 if (Petsc_Elemental_keyval == MPI_KEYVAL_INVALID) { 1314 ierr = MPI_Keyval_create(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Elemental_keyval,(void*)0);CHKERRQ(ierr); 1315 /* ierr = MPI_Comm_create_Keyval(MPI_NULL_COPY_FN,MPI_NULL_DELETE_FN,&Petsc_Elemental_keyval,(void*)0); -- new version? */ 1316 } 1317 ierr = PetscCommDuplicate(cxxcomm.comm,&icomm,NULL);CHKERRQ(ierr); 1318 ierr = MPI_Attr_get(icomm,Petsc_Elemental_keyval,(void**)&commgrid,(int*)&flg);CHKERRQ(ierr); 1319 if (!flg) { 1320 ierr = PetscNewLog(A,&commgrid);CHKERRQ(ierr); 1321 1322 ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)A),((PetscObject)A)->prefix,"Elemental Options","Mat");CHKERRQ(ierr); 1323 /* displayed default grid sizes (CommSize,1) are set by us arbitrarily until El::Grid() is called */ 1324 ierr = PetscOptionsInt("-mat_elemental_grid_height","Grid Height","None",El::mpi::Size(cxxcomm),&optv1,&flg1);CHKERRQ(ierr); 1325 if (flg1) { 1326 if (El::mpi::Size(cxxcomm) % optv1 != 0) { 1327 SETERRQ2(PetscObjectComm((PetscObject)A),PETSC_ERR_ARG_INCOMP,"Grid Height %D must evenly divide CommSize %D",optv1,(PetscInt)El::mpi::Size(cxxcomm)); 1328 } 1329 commgrid->grid = new El::Grid(cxxcomm,optv1); /* use user-provided grid height */ 1330 } else { 1331 commgrid->grid = new El::Grid(cxxcomm); /* use Elemental default grid sizes */ 1332 /* printf("new commgrid->grid = %p\n",commgrid->grid); -- memory leak revealed by valgrind? */ 1333 } 1334 commgrid->grid_refct = 1; 1335 ierr = MPI_Attr_put(icomm,Petsc_Elemental_keyval,(void*)commgrid);CHKERRQ(ierr); 1336 1337 a->pivoting = 1; 1338 ierr = PetscOptionsInt("-mat_elemental_pivoting","Pivoting","None",a->pivoting,&a->pivoting,NULL);CHKERRQ(ierr); 1339 1340 ierr = PetscOptionsEnd();CHKERRQ(ierr); 1341 } else { 1342 commgrid->grid_refct++; 1343 } 1344 ierr = PetscCommDestroy(&icomm);CHKERRQ(ierr); 1345 a->grid = commgrid->grid; 1346 a->emat = new El::DistMatrix<PetscElemScalar>(*a->grid); 1347 a->roworiented = PETSC_TRUE; 1348 1349 ierr = PetscObjectComposeFunction((PetscObject)A,"MatGetOwnershipIS_C",MatGetOwnershipIS_Elemental);CHKERRQ(ierr); 1350 ierr = PetscObjectChangeTypeName((PetscObject)A,MATELEMENTAL);CHKERRQ(ierr); 1351 PetscFunctionReturn(0); 1352 } 1353