xref: /petsc/src/dm/impls/moab/dmmoab.cxx (revision a4d2169cc6146dd131be8bed37042f39c361a88f)
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,&ltog);CHKERRQ(ierr);
407     ierr = VecSetLocalToGlobalMappingBlock(*vec,ltog);CHKERRQ(ierr);
408 
409       // Clean up:
410     ierr = ISLocalToGlobalMappingDestroy(&ltog);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