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