1 #include <petsc-private/dmimpl.h> /*I "petscdm.h" I*/ 2 3 #include <petscdmmoab.h> 4 #include "MBTagConventions.hpp" 5 6 typedef struct { 7 PetscInt bs; /* Number of degrees of freedom on each entity, aka tag size in moab */ 8 PetscBool icreatedinstance; /* true if DM created moab instance internally, will destroy instance in DMDestroy */ 9 moab::ParallelComm *pcomm; 10 moab::Interface *mbiface; 11 moab::Tag ltog_tag; /* moab supports "global id" tags, which are usually local to global numbering */ 12 moab::Range range; 13 } DM_Moab; 14 15 typedef struct { 16 moab::Interface *mbiface; 17 moab::ParallelComm *pcomm; 18 moab::Range tag_range; /* entities to which this tag applies */ 19 moab::Tag tag; 20 moab::Tag ltog_tag; 21 PetscInt tag_size; 22 PetscBool new_tag; 23 PetscBool serial; 24 25 } Vec_MOAB; 26 27 #undef __FUNCT__ 28 #define __FUNCT__ "DMCreateGlobalVector_Moab" 29 PetscErrorCode DMCreateGlobalVector_Moab(DM dm,Vec *gvec) 30 { 31 PetscErrorCode ierr; 32 DM_Moab *dmmoab = (DM_Moab*)dm->data; 33 34 PetscFunctionBegin; 35 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 36 PetscValidPointer(gvec,2); 37 PetscInt block_size = ((DM_Moab*)dm->data)->bs; 38 moab::Tag tag = 0; 39 ierr = DMMoabCreateVector(dm,tag,block_size,dmmoab->range,PETSC_FALSE,PETSC_TRUE,gvec);CHKERRQ(ierr); 40 PetscFunctionReturn(0); 41 } 42 43 44 #undef __FUNCT__ 45 #define __FUNCT__ "DMCreateLocalVector_Moab" 46 PetscErrorCode DMCreateLocalVector_Moab(DM dm,Vec *gvec) 47 { 48 PetscErrorCode ierr; 49 DM_Moab *dmmoab = (DM_Moab*)dm->data; 50 51 PetscFunctionBegin; 52 PetscInt bs = 1; 53 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 54 PetscValidPointer(gvec,2); 55 moab::Tag tag = 0; 56 ierr = DMMoabCreateVector(dm,tag,bs,dmmoab->range,PETSC_TRUE,PETSC_TRUE,gvec);CHKERRQ(ierr); 57 PetscFunctionReturn(0); 58 } 59 60 #undef __FUNCT__ 61 #define __FUNCT__ "DMDestroy_Moab" 62 PetscErrorCode DMDestroy_Moab(DM dm) 63 { 64 PetscFunctionBegin; 65 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 66 67 // Delete the DM_Moab: 68 if(dm->data) { 69 if (((DM_Moab*)dm->data)->icreatedinstance) { 70 delete ((DM_Moab*)dm->data)->mbiface; 71 ((DM_Moab*)dm->data)->mbiface = NULL; 72 ((DM_Moab*)dm->data)->pcomm = NULL; 73 } 74 delete (DM_Moab*)dm->data; 75 dm->data = NULL; 76 } 77 PetscFunctionReturn(0); 78 } 79 80 81 #undef __FUNCT__ 82 #define __FUNCT__ "DMMoabCreate" 83 /*@ 84 DMMoabCreate - Creates a DMMoab object, which encapsulates a moab instance 85 86 Collective on MPI_Comm 87 88 Input Parameter: 89 . comm - The communicator for the DMMoab object 90 91 Output Parameter: 92 . moab - The DMMoab object 93 94 Level: beginner 95 96 .keywords: DMMoab, create 97 @*/ 98 PetscErrorCode DMMoabCreate(MPI_Comm comm, DM *moab) 99 { 100 PetscErrorCode ierr; 101 102 PetscFunctionBegin; 103 PetscValidPointer(moab,2); 104 ierr = DMCreate(comm, moab);CHKERRQ(ierr); 105 ierr = DMSetType(*moab, DMMOAB);CHKERRQ(ierr); 106 PetscFunctionReturn(0); 107 } 108 109 EXTERN_C_BEGIN 110 #undef __FUNCT__ 111 #define __FUNCT__ "DMCreate_Moab" 112 PetscErrorCode DMCreate_Moab(DM dm) 113 { 114 DM_Moab *moab; 115 PetscErrorCode ierr; 116 117 PetscFunctionBegin; 118 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 119 ierr = PetscNewLog(dm, DM_Moab, &moab);CHKERRQ(ierr); 120 dm->data = moab; 121 122 PetscFunctionReturn(0); 123 } 124 EXTERN_C_END 125 126 /*@ 127 DMMoabCreate - Creates a DMMoab object, optionally from an instance and other data 128 129 Collective on MPI_Comm 130 131 Input Parameter: 132 . comm - The communicator for the DMMoab object 133 . moab - (ptr to) the MOAB Instance; if passed in NULL, MOAB instance is created inside PETSc, and destroyed 134 along with the DMMoab 135 . pcomm - (ptr to) a ParallelComm; if NULL, creates one internally for the whole communicator 136 . ltog_tag - A tag to use to retrieve global id for an entity; if 0, will use GLOBAL_ID_TAG_NAME/tag 137 . range - If non-NULL, contains range of entities to which DOFs will be assigned 138 139 Output Parameter: 140 . moab - The DMMoab object 141 142 Level: beginner 143 144 .keywords: DMMoab, create 145 @*/ 146 #undef __FUNCT__ 147 #define __FUNCT__ "DMMoabCreateMoab" 148 PetscErrorCode DMMoabCreateMoab(MPI_Comm comm, moab::Interface *mbiface, moab::ParallelComm *pcomm, moab::Tag ltog_tag, moab::Range *range, DM *moab) 149 { 150 PetscErrorCode ierr; 151 152 PetscFunctionBegin; 153 PetscValidPointer(moab,2); 154 ierr = DMCreate(comm, moab);CHKERRQ(ierr); 155 ierr = DMSetType(*moab, DMMOAB);CHKERRQ(ierr); 156 157 if (!mbiface) { 158 mbiface = new moab::Core(); 159 ((DM_Moab*)(*moab)->data)->icreatedinstance = PETSC_TRUE; 160 } 161 if (!pcomm) { 162 PetscInt rank, nprocs; 163 MPI_Comm_rank(comm, &rank); 164 MPI_Comm_size(comm, &nprocs); 165 pcomm = new moab::ParallelComm(mbiface, comm); 166 } 167 168 // do the initialization of the DM 169 DM_Moab *dmmoab = new DM_Moab; 170 (*moab)->data = dmmoab; 171 dmmoab->bs = 0; 172 dmmoab->pcomm = pcomm; 173 dmmoab->mbiface = mbiface; 174 dmmoab->ltog_tag = ltog_tag; 175 176 // initialize various functions 177 (*moab)->ops->createglobalvector = DMCreateGlobalVector_Moab; 178 (*moab)->ops->createlocalvector = DMCreateLocalVector_Moab; 179 (*moab)->ops->destroy = DMDestroy_Moab; 180 181 ierr = DMMoabSetInterface(*moab, mbiface);CHKERRQ(ierr); 182 if (!pcomm) pcomm = new moab::ParallelComm(mbiface, comm); 183 ierr = DMMoabSetParallelComm(*moab, pcomm);CHKERRQ(ierr); 184 if (!ltog_tag) { 185 moab::ErrorCode merr = mbiface->tag_get_handle(GLOBAL_ID_TAG_NAME, ltog_tag);MBERRNM(merr); 186 } 187 if (ltog_tag) { 188 ierr = DMMoabSetLocalToGlobalTag(*moab, ltog_tag);CHKERRQ(ierr); 189 } 190 if (range) { 191 ierr = DMMoabSetRange(*moab, *range);CHKERRQ(ierr); 192 } 193 PetscFunctionReturn(0); 194 } 195 196 #undef __FUNCT__ 197 #define __FUNCT__ "DMMoabSetParallelComm" 198 PetscErrorCode DMMoabSetParallelComm(DM dm,moab::ParallelComm *pcomm) 199 { 200 PetscFunctionBegin; 201 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 202 ((DM_Moab*)dm->data)->pcomm = pcomm; 203 ((DM_Moab*)dm->data)->mbiface = pcomm->get_moab(); 204 PetscFunctionReturn(0); 205 } 206 207 208 #undef __FUNCT__ 209 #define __FUNCT__ "DMMoabGetParallelComm" 210 PetscErrorCode DMMoabGetParallelComm(DM dm,moab::ParallelComm **pcomm) 211 { 212 PetscFunctionBegin; 213 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 214 *pcomm = ((DM_Moab*)dm->data)->pcomm; 215 PetscFunctionReturn(0); 216 } 217 218 219 #undef __FUNCT__ 220 #define __FUNCT__ "DMMoabSetInterface" 221 PetscErrorCode DMMoabSetInterface(DM dm,moab::Interface *mbiface) 222 { 223 PetscFunctionBegin; 224 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 225 ((DM_Moab*)dm->data)->pcomm = NULL; 226 ((DM_Moab*)dm->data)->mbiface = mbiface; 227 PetscFunctionReturn(0); 228 } 229 230 231 #undef __FUNCT__ 232 #define __FUNCT__ "DMMoabGetInterface" 233 PetscErrorCode DMMoabGetInterface(DM dm,moab::Interface **mbiface) 234 { 235 PetscFunctionBegin; 236 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 237 *mbiface = ((DM_Moab*)dm->data)->mbiface; 238 PetscFunctionReturn(0); 239 } 240 241 242 #undef __FUNCT__ 243 #define __FUNCT__ "DMMoabSetRange" 244 PetscErrorCode DMMoabSetRange(DM dm,moab::Range range) 245 { 246 PetscFunctionBegin; 247 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 248 ((DM_Moab*)dm->data)->range = range; 249 PetscFunctionReturn(0); 250 } 251 252 253 #undef __FUNCT__ 254 #define __FUNCT__ "DMMoabGetRange" 255 PetscErrorCode DMMoabGetRange(DM dm,moab::Range *range) 256 { 257 PetscFunctionBegin; 258 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 259 *range = ((DM_Moab*)dm->data)->range; 260 PetscFunctionReturn(0); 261 } 262 263 #undef __FUNCT__ 264 #define __FUNCT__ "DMMoabSetLocalToGlobalTag" 265 PetscErrorCode DMMoabSetLocalToGlobalTag(DM dm,moab::Tag ltogtag) 266 { 267 PetscFunctionBegin; 268 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 269 ((DM_Moab*)dm->data)->ltog_tag = ltogtag; 270 PetscFunctionReturn(0); 271 } 272 273 274 #undef __FUNCT__ 275 #define __FUNCT__ "DMMoabGetLocalToGlobalTag" 276 PetscErrorCode DMMoabGetLocalToGlobalTag(DM dm,moab::Tag *ltog_tag) 277 { 278 PetscFunctionBegin; 279 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 280 *ltog_tag = ((DM_Moab*)dm->data)->ltog_tag; 281 PetscFunctionReturn(0); 282 } 283 284 285 #undef __FUNCT__ 286 #define __FUNCT__ "DMMoabSetBlockSize" 287 PetscErrorCode DMMoabSetBlockSize(DM dm,PetscInt bs) 288 { 289 PetscFunctionBegin; 290 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 291 ((DM_Moab*)dm->data)->bs = bs; 292 PetscFunctionReturn(0); 293 } 294 295 296 #undef __FUNCT__ 297 #define __FUNCT__ "DMMoabGetBlockSize" 298 PetscErrorCode DMMoabGetBlockSize(DM dm,PetscInt *bs) 299 { 300 PetscFunctionBegin; 301 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 302 *bs = ((DM_Moab*)dm->data)->bs; 303 PetscFunctionReturn(0); 304 } 305 306 307 // declare for use later but before they're defined 308 PetscErrorCode DMMoab_VecUserDestroy(void *user); 309 PetscErrorCode DMMoab_VecDuplicate(Vec x,Vec *y); 310 PetscErrorCode DMMoab_CreateTagName(const moab::ParallelComm *pcomm,std::string& tag_name); 311 PetscErrorCode DMMoab_CreateVector(moab::Interface *iface,moab::ParallelComm *pcomm,moab::Tag tag,PetscInt tag_size,moab::Tag ltog_tag,moab::Range range,PetscBool serial, PetscBool destroy_tag,Vec *vec); 312 313 #undef __FUNCT__ 314 #define __FUNCT__ "DMMoabCreateVector" 315 PetscErrorCode DMMoabCreateVector(DM dm,moab::Tag tag,PetscInt tag_size,moab::Range range,PetscBool serial, PetscBool destroy_tag,Vec *vec) 316 { 317 PetscErrorCode ierr; 318 319 PetscFunctionBegin; 320 321 DM_Moab *dmmoab = (DM_Moab*)dm->data; 322 moab::ParallelComm *pcomm = dmmoab->pcomm; 323 moab::Interface *mbiface = dmmoab->mbiface; 324 moab::Tag ltog_tag = dmmoab->ltog_tag; 325 326 if (!tag && !tag_size) { 327 PetscFunctionReturn(PETSC_ERR_ARG_WRONG); 328 } 329 else if (!tag && tag_size) { 330 ierr = DMMoab_CreateVector(mbiface,pcomm,tag,tag_size,ltog_tag,range,serial,destroy_tag,vec);CHKERRQ(ierr); 331 } 332 PetscFunctionReturn(0); 333 } 334 335 336 #undef __FUNCT__ 337 #define __FUNCT__ "DMMoab_CreateVector" 338 PetscErrorCode DMMoab_CreateVector(moab::Interface *mbiface,moab::ParallelComm *pcomm,moab::Tag tag,PetscInt tag_size,moab::Tag ltog_tag,moab::Range range,PetscBool serial, PetscBool destroy_tag,Vec *vec) 339 { 340 PetscErrorCode ierr; 341 moab::ErrorCode merr; 342 343 PetscFunctionBegin; 344 345 if (!tag) { 346 std::string tag_name; 347 ierr = DMMoab_CreateTagName(pcomm,tag_name);CHKERRQ(ierr); 348 349 // Create the default value for the tag (all zeros): 350 std::vector<PetscScalar> default_value(tag_size, 0.0); 351 352 // Create the tag: 353 merr = mbiface->tag_get_handle(tag_name.c_str(),tag_size,moab::MB_TYPE_DOUBLE,tag, 354 moab::MB_TAG_DENSE | moab::MB_TAG_CREAT,default_value.data());MBERRNM(merr); 355 } 356 else { 357 358 // Make sure the tag data is of type "double": 359 moab::DataType tag_type; 360 merr = mbiface->tag_get_data_type(tag, tag_type);MBERRNM(merr); 361 if(tag_type != moab::MB_TYPE_DOUBLE) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Tag data type must be MB_TYPE_DOUBLE"); 362 } 363 364 // Create the MOAB internal data object 365 Vec_MOAB *vmoab; 366 ierr = PetscMalloc(sizeof(Vec_MOAB),&vmoab);CHKERRQ(ierr); 367 new (vmoab) Vec_MOAB(); 368 vmoab->tag = tag; 369 vmoab->ltog_tag = ltog_tag; 370 vmoab->mbiface = mbiface; 371 vmoab->pcomm = pcomm; 372 vmoab->tag_range = range; 373 vmoab->new_tag = destroy_tag; 374 vmoab->serial = serial; 375 merr = mbiface->tag_get_length(tag,vmoab->tag_size);MBERR("tag_get_size", merr); 376 377 // Call tag_iterate. This will cause MOAB to allocate memory for the 378 // tag data if it hasn't already happened: 379 int count; 380 void *void_ptr; 381 merr = mbiface->tag_iterate(tag,range.begin(),range.end(),count,void_ptr);MBERRNM(merr); 382 383 // Check to make sure the tag data is in a single sequence: 384 if ((unsigned)count != range.size()) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only create MOAB Vector for single sequence"); 385 PetscScalar *data_ptr = (PetscScalar*)void_ptr; 386 387 // Create the PETSc Vector: 388 if(!serial) { 389 // This is an MPI Vector: 390 ierr = VecCreateMPIWithArray(vmoab->pcomm->comm(),vmoab->tag_size,vmoab->tag_size*range.size(), 391 PETSC_DECIDE,data_ptr,vec);CHKERRXX(ierr); 392 393 // Vector created, manually set local to global mapping: 394 ISLocalToGlobalMapping ltog; 395 PetscInt *gindices = new PetscInt[range.size()]; 396 PetscInt count = 0; 397 moab::Range::iterator iter; 398 for(iter = range.begin(); iter != range.end(); iter++) { 399 int dof; 400 merr = mbiface->tag_get_data(ltog_tag,&(*iter),1,&dof);MBERRNM(merr); 401 gindices[count] = dof; 402 count++; 403 } 404 405 ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_SELF,range.size(),gindices, 406 PETSC_COPY_VALUES,<og);CHKERRQ(ierr); 407 ierr = VecSetLocalToGlobalMappingBlock(*vec,ltog);CHKERRQ(ierr); 408 409 // Clean up: 410 ierr = ISLocalToGlobalMappingDestroy(<og);CHKERRQ(ierr); 411 delete [] gindices; 412 } else { 413 // This is a serial vector: 414 ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,vmoab->tag_size,vmoab->tag_size*range.size(),data_ptr,vec);CHKERRXX(ierr); 415 } 416 417 418 PetscContainer moabdata; 419 ierr = PetscContainerCreate(PETSC_COMM_SELF,&moabdata);CHKERRQ(ierr); 420 ierr = PetscContainerSetPointer(moabdata,vmoab);CHKERRQ(ierr); 421 ierr = PetscContainerSetUserDestroy(moabdata,DMMoab_VecUserDestroy);CHKERRQ(ierr); 422 ierr = PetscObjectCompose((PetscObject)*vec,"MOABData",(PetscObject)moabdata);CHKERRQ(ierr); 423 (*vec)->ops->duplicate = DMMoab_VecDuplicate; 424 425 ierr = PetscContainerDestroy(&moabdata);CHKERRQ(ierr); 426 PetscFunctionReturn(0); 427 } 428 429 #undef __FUNCT__ 430 #define __FUNCT__ "DMMoabGetVecTag" 431 PetscErrorCode DMMoabGetVecTag(Vec vec,moab::Tag *tag) 432 { 433 PetscContainer moabdata; 434 Vec_MOAB *vmoab; 435 PetscErrorCode ierr; 436 437 PetscFunctionBegin; 438 439 // Get the MOAB private data: 440 ierr = PetscObjectQuery((PetscObject)vec,"MOABData", (PetscObject*) &moabdata);CHKERRQ(ierr); 441 ierr = PetscContainerGetPointer(moabdata, (void**) &vmoab);CHKERRQ(ierr); 442 443 *tag = vmoab->tag; 444 445 PetscFunctionReturn(0); 446 } 447 448 449 #undef __FUNCT__ 450 #define __FUNCT__ "DMMoabGetVecRange" 451 PetscErrorCode DMMoabGetVecRange(Vec vec,moab::Range *range) 452 { 453 PetscContainer moabdata; 454 Vec_MOAB *vmoab; 455 PetscErrorCode ierr; 456 457 PetscFunctionBegin; 458 459 // Get the MOAB private data: 460 ierr = PetscObjectQuery((PetscObject)vec,"MOABData", (PetscObject*) &moabdata);CHKERRQ(ierr); 461 ierr = PetscContainerGetPointer(moabdata, (void**) &vmoab);CHKERRQ(ierr); 462 463 *range = vmoab->tag_range; 464 465 PetscFunctionReturn(0); 466 } 467 468 469 #undef __FUNCT__ 470 #define __FUNCT__ "DMMoab_VecDuplicate" 471 PetscErrorCode DMMoab_VecDuplicate(Vec x,Vec *y) 472 { 473 PetscErrorCode ierr; 474 PetscFunctionBegin; 475 PetscValidHeaderSpecific(x,VEC_CLASSID,1); 476 PetscValidPointer(y,2); 477 478 // Get the Vec_MOAB struct for the original vector: 479 PetscContainer moabdata; 480 Vec_MOAB *vmoab; 481 ierr = PetscObjectQuery((PetscObject)x,"MOABData", (PetscObject*) &moabdata);CHKERRQ(ierr); 482 ierr = PetscContainerGetPointer(moabdata, (void**)&vmoab);CHKERRQ(ierr); 483 484 ierr = DMMoab_CreateVector(vmoab->mbiface,vmoab->pcomm,vmoab->tag, vmoab->tag_size,vmoab->ltog_tag,vmoab->tag_range,vmoab->serial,PETSC_TRUE,y);CHKERRQ(ierr); 485 PetscFunctionReturn(0); 486 } 487 488 489 #undef __FUNCT__ 490 #define __FUNCT__ "DMMoab_CreateTagName" 491 /* DMMoab_CreateTagName 492 * 493 * Creates a unique tag name that will be shared across processes. If 494 * pcomm is NULL, then this is a serial vector. A unique tag name 495 * will be returned in tag_name in either case. 496 * 497 * The tag names have the format _PETSC_VEC_N where N is some integer. 498 */ 499 PetscErrorCode DMMoab_CreateTagName(const moab::ParallelComm *pcomm,std::string& tag_name) 500 { 501 moab::ErrorCode mberr; 502 PetscErrorCode ierr; 503 504 PetscFunctionBegin; 505 const std::string PVEC_PREFIX = "_PETSC_VEC_"; 506 const PetscInt PVEC_PREFIX_SIZE = PVEC_PREFIX.size(); 507 508 // Check to see if there are any PETSc vectors defined: 509 const moab::Interface *mbiface = pcomm->get_moab(); 510 std::vector<moab::Tag> tags; 511 PetscInt n = 0; 512 mberr = mbiface->tag_get_tags(tags);MBERRNM(mberr); 513 for(unsigned i = 0; i < tags.size(); i++) { 514 std::string s; 515 mberr = mbiface->tag_get_name(tags[i],s);MBERRNM(mberr); 516 if(s.find(PVEC_PREFIX) != std::string::npos){ 517 // This tag represents a PETSc vector. Find the vector number: 518 PetscInt m; 519 std::istringstream(s.substr(PVEC_PREFIX_SIZE)) >> m; 520 if(m >= n) n = m+1; 521 } 522 } 523 524 // Make sure that n is consistent across all processes: 525 PetscInt global_n; 526 MPI_Comm comm = PETSC_COMM_SELF; 527 if(pcomm) comm = pcomm->comm(); 528 ierr = MPI_Allreduce(&n,&global_n,1,MPI_INT,MPI_MAX,comm);CHKERRQ(ierr); 529 530 // Set the answer and return: 531 std::stringstream ss; 532 ss << PVEC_PREFIX << global_n; 533 tag_name = ss.str(); 534 PetscFunctionReturn(0); 535 } 536 537 538 #undef __FUNCT__ 539 #define __FUNCT__ "DMMoab_VecUserDestroy" 540 PetscErrorCode DMMoab_VecUserDestroy(void *user) 541 { 542 Vec_MOAB *vmoab; 543 PetscErrorCode ierr; 544 moab::ErrorCode merr; 545 546 PetscFunctionBegin; 547 vmoab = (Vec_MOAB*)user; 548 if(vmoab->new_tag == PETSC_TRUE) { 549 // Tag created via a call to VecDuplicate, delete the underlying tag in MOAB... 550 merr = vmoab->mbiface->tag_delete(vmoab->tag);MBERRNM(merr); 551 } 552 553 ierr = PetscFree(vmoab);CHKERRQ(ierr); 554 PetscFunctionReturn(0); 555 } 556 557