xref: /petsc/src/dm/impls/moab/dmmbvec.cxx (revision db66d124cedba962fb8ceb469cd36885b3f01337)
1 #include <petsc-private/dmmbimpl.h> /*I  "petscdm.h"   I*/
2 #include <petsc-private/vecimpl.h> /*I  "petscdm.h"   I*/
3 
4 #include <petscdmmoab.h>
5 #include <MBTagConventions.hpp>
6 
7 // declare for use later but before they're defined
8 static PetscErrorCode DMMoab_VecUserDestroy(void *user);
9 static PetscErrorCode DMMoab_VecDuplicate(Vec x,Vec *y);
10 static PetscErrorCode DMMoab_VecCreateTagName_Private(moab::ParallelComm *pcomm,char** tag_name);
11 
12 #undef __FUNCT__
13 #define __FUNCT__ "DMMoab_CreateVector_Private"
14 PetscErrorCode DMMoab_CreateVector_Private(DM dm,moab::Tag tag,PetscInt tag_size,moab::Range* userrange,PetscBool is_global_vec,PetscBool destroy_tag,Vec *vec)
15 {
16   PetscErrorCode         ierr;
17   moab::ErrorCode        merr;
18   PetscBool              is_newtag;
19   moab::Range           *range;
20   PetscInt               *gindices,*gsindices;
21   PetscInt               i,count,icount,dof;
22   PetscInt               size,rank;
23   PetscScalar *data_ptr;
24 
25   Vec_MOAB *vmoab;
26   DM_Moab *dmmoab = (DM_Moab*)dm->data;
27   moab::ParallelComm *pcomm = dmmoab->pcomm;
28   moab::Interface *mbiface = dmmoab->mbiface;
29   moab::Tag ltog_tag = dmmoab->ltog_tag;
30 
31   PetscFunctionBegin;
32   if(!userrange) range = dmmoab->vowned;
33   else range = userrange;
34   if(!range) SETERRQ(PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Input range cannot be empty or call DMSetUp first.");
35 
36   if (!tag) {
37     /* get the new name for the anonymous MOABVec -> the tag_name will be destroyed along with Tag */
38     char *tag_name = PETSC_NULL;
39     ierr = DMMoab_VecCreateTagName_Private(pcomm,&tag_name);CHKERRQ(ierr);
40     is_newtag = PETSC_TRUE;
41 
42     /* Create the default value for the tag (all zeros) */
43     std::vector<PetscScalar> default_value(tag_size, 0.0);
44 
45     /* Create the tag */
46     merr = mbiface->tag_get_handle(tag_name,tag_size,moab::MB_TYPE_DOUBLE,tag,
47                                    moab::MB_TAG_DENSE|moab::MB_TAG_CREAT,default_value.data());MBERRNM(merr);
48     ierr = PetscFree(tag_name);CHKERRQ(ierr);
49   }
50   else {
51     /* Make sure the tag data is of type "double" */
52     moab::DataType tag_type;
53     merr = mbiface->tag_get_data_type(tag, tag_type);MBERRNM(merr);
54     if(tag_type != moab::MB_TYPE_DOUBLE) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Tag data type must be MB_TYPE_DOUBLE");
55     is_newtag = destroy_tag;
56   }
57 
58   /* Create the MOAB internal data object */
59   ierr = PetscNew(Vec_MOAB,&vmoab);CHKERRQ(ierr);
60   vmoab->tag = tag;
61   vmoab->mbiface = mbiface;
62   vmoab->pcomm = pcomm;
63   vmoab->new_tag = is_newtag;
64   vmoab->is_global_vec = is_global_vec;
65   merr = mbiface->tag_get_length(tag,vmoab->tag_size);MBERR("tag_get_size", merr);
66 
67   /* set the reference for vector range */
68   vmoab->tag_range = new moab::Range(*range);
69 
70   /* Call tag_iterate. This will cause MOAB to allocate memory for the
71      tag data if it hasn't already happened */
72   merr = mbiface->tag_iterate(tag,range->begin(),range->end(),count,(void*&)data_ptr);MBERRNM(merr);
73 
74   /* Check to make sure the tag data is in a single sequence */
75   if ((unsigned)count != range->size()) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Can only create MOAB Vector for single sequence");
76 
77   ierr = MPI_Comm_size(((PetscObject)dm)->comm, &size);CHKERRQ(ierr);
78   ierr = MPI_Comm_rank(((PetscObject)dm)->comm, &rank);CHKERRQ(ierr);
79 
80   /* Create the PETSc Vector
81      Query MOAB mesh to check if there are any ghosted entities
82        -> if we do, create a ghosted vector to map correctly to the same layout
83        -> else, create a non-ghosted parallel vector */
84   if (!is_global_vec && (size>1) && dmmoab->nghost) {
85     moab::Range::iterator  iter;
86     ierr = PetscMalloc(dmmoab->nghost*sizeof(PetscInt), &gsindices);CHKERRQ(ierr);
87 
88     for(iter = dmmoab->vghost->begin(),icount=0; iter != dmmoab->vghost->end(); iter++) {
89       merr = mbiface->tag_get_data(ltog_tag,&(*iter),1,&dof);MBERRNM(merr);
90       gsindices[icount++] = dof;
91     }
92 
93     /* This is an MPI Vector with ghosted padding */
94     ierr = VecCreateGhostBlockWithArray(vmoab->pcomm->comm(),vmoab->tag_size,vmoab->tag_size*dmmoab->nloc,
95                               vmoab->tag_size*dmmoab->n,dmmoab->nghost,gsindices,data_ptr,vec);CHKERRQ(ierr);
96 
97     ierr = PetscFree(gsindices);CHKERRQ(ierr);
98   }
99   else if (size>1) {
100     /* This is an MPI Vector without ghosted padding */
101     ierr = VecCreateMPIWithArray(vmoab->pcomm->comm(),vmoab->tag_size,vmoab->tag_size*range->size(),
102                               PETSC_DECIDE,data_ptr,vec);CHKERRQ(ierr);
103   }
104   else {
105     /* This is a sequential vector - valid only for the single processor case since MOAB tags are always partitioned
106        and we cannot define a Vec using the Tag array with size>1 will be of full length */
107     ierr = VecCreateSeqWithArray(PETSC_COMM_SELF,vmoab->tag_size,vmoab->tag_size*dmmoab->n,data_ptr,vec);CHKERRQ(ierr);
108   }
109 
110   PetscContainer moabdata;
111   ierr = PetscContainerCreate(PETSC_COMM_SELF,&moabdata);CHKERRQ(ierr);
112   ierr = PetscContainerSetPointer(moabdata,vmoab);CHKERRQ(ierr);
113   ierr = PetscContainerSetUserDestroy(moabdata,DMMoab_VecUserDestroy);CHKERRQ(ierr);
114   ierr = PetscObjectCompose((PetscObject)*vec,"MOABData",(PetscObject)moabdata);CHKERRQ(ierr);
115   (*vec)->ops->duplicate = DMMoab_VecDuplicate;
116   ierr = PetscContainerDestroy(&moabdata);CHKERRQ(ierr);
117 
118   if (!dmmoab->ltog_map) {
119     /* Vector created, manually set local to global mapping */
120     ierr = PetscMalloc(range->size()*sizeof(PetscInt)*vmoab->tag_size, &gindices);CHKERRQ(ierr);
121     moab::Range::iterator  iter;
122     for(iter = range->begin(),count=0; iter != range->end(); iter++,count+=vmoab->tag_size) {
123       merr = mbiface->tag_get_data(ltog_tag,&(*iter),1,&dof);MBERRNM(merr);
124       for(i=0; i<vmoab->tag_size; ++i)
125         gindices[count+i] = (dof)*vmoab->tag_size+i;
126     }
127 
128     ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_SELF,range->size(),gindices,
129                                         PETSC_COPY_VALUES,&dmmoab->ltog_map);CHKERRQ(ierr);
130 
131     ierr = VecSetLocalToGlobalMappingBlock(*vec,dmmoab->ltog_map);CHKERRQ(ierr);
132 
133     /* Clean up */
134     ierr = PetscFree(gindices);CHKERRQ(ierr);
135   }
136   else {
137     ierr = VecSetLocalToGlobalMappingBlock(*vec,dmmoab->ltog_map);CHKERRQ(ierr);
138   }
139 
140   /* set the DM reference to the vector */
141   ierr = VecSetDM(*vec, dm);CHKERRQ(ierr);
142   PetscFunctionReturn(0);
143 }
144 
145 
146 #undef __FUNCT__
147 #define __FUNCT__ "DMMoabCreateVector"
148 /*@
149   DMMoabCreateVector - Create a Vec from either an existing tag, or a specified tag size, and a range of entities
150 
151   Collective on MPI_Comm
152 
153   Input Parameter:
154 . dm              - The DMMoab object being set
155 . tag             - If non-zero, block size will be taken from the tag size
156 . tag_size        - If tag was zero, this parameter specifies the block size; unique tag name will be generated automatically
157 . range           - If non-empty, Vec corresponds to these entities, otherwise to the entities set on the DMMoab
158 . is_global_vec   - If true, this is a local representation of the Vec (including ghosts in parallel), otherwise a truly parallel one
159 . destroy_tag     - If true, MOAB tag is destroyed with Vec, otherwise it is left on MOAB
160 
161   Output Parameter:
162 . vec             - The created vector
163 
164   Level: beginner
165 
166 .keywords: DMMoab, create
167 @*/
168 PetscErrorCode DMMoabCreateVector(DM dm,moab::Tag tag,PetscInt tag_size,moab::Range* range,PetscBool is_global_vec,PetscBool destroy_tag,Vec *vec)
169 {
170   PetscErrorCode     ierr;
171 
172   PetscFunctionBegin;
173   if(!tag && !tag_size) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Both tag_size and tag cannot be null.");
174 
175   ierr = DMMoab_CreateVector_Private(dm,tag,tag_size,range,is_global_vec,destroy_tag,vec);CHKERRQ(ierr);
176   PetscFunctionReturn(0);
177 }
178 
179 
180 #undef __FUNCT__
181 #define __FUNCT__ "DMCreateGlobalVector_Moab"
182 PetscErrorCode DMCreateGlobalVector_Moab(DM dm,Vec *gvec)
183 {
184   PetscErrorCode  ierr;
185   DM_Moab         *dmmoab = (DM_Moab*)dm->data;
186 
187   PetscFunctionBegin;
188   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
189   PetscValidPointer(gvec,2);
190   ierr = DMMoab_CreateVector_Private(dm,PETSC_NULL,dmmoab->bs,dmmoab->vowned,PETSC_TRUE,PETSC_TRUE,gvec);CHKERRQ(ierr);
191   PetscFunctionReturn(0);
192 }
193 
194 
195 #undef __FUNCT__
196 #define __FUNCT__ "DMCreateLocalVector_Moab"
197 PetscErrorCode DMCreateLocalVector_Moab(DM dm,Vec *lvec)
198 {
199   PetscErrorCode  ierr;
200   moab::Range     vlocal;
201   DM_Moab         *dmmoab = (DM_Moab*)dm->data;
202 
203   PetscFunctionBegin;
204   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
205   PetscValidPointer(lvec,2);
206   vlocal = *dmmoab->vowned;
207   vlocal.merge(*dmmoab->vghost);
208   ierr = DMMoab_CreateVector_Private(dm,PETSC_NULL,dmmoab->bs,dmmoab->vowned,PETSC_FALSE,PETSC_TRUE,lvec);CHKERRQ(ierr);
209   PetscFunctionReturn(0);
210 }
211 
212 
213 #undef __FUNCT__
214 #define __FUNCT__ "DMMoabGetVecTag"
215 /*@
216   DMMoabGetVecTag - Get the MOAB tag associated with this Vec
217 
218   Collective on MPI_Comm
219 
220   Input Parameter:
221 . vec - Vec being queried
222 
223   Output Parameter:
224 . tag - Tag associated with this Vec
225 
226   Level: beginner
227 
228 .keywords: DMMoab, create
229 @*/
230 PetscErrorCode DMMoabGetVecTag(Vec vec,moab::Tag *tag)
231 {
232   PetscContainer  moabdata;
233   Vec_MOAB        *vmoab;
234   PetscErrorCode  ierr;
235 
236   PetscFunctionBegin;
237   PetscValidPointer(tag,2);
238 
239   // Get the MOAB private data:
240   ierr = PetscObjectQuery((PetscObject)vec,"MOABData", (PetscObject*) &moabdata);CHKERRQ(ierr);
241   ierr = PetscContainerGetPointer(moabdata, (void**) &vmoab);CHKERRQ(ierr);
242 
243   *tag = vmoab->tag;
244   PetscFunctionReturn(0);
245 }
246 
247 
248 #undef __FUNCT__
249 #define __FUNCT__ "DMMoabGetVecRange"
250 /*@
251   DMMoabGetVecRange - Get the MOAB entities associated with this Vec
252 
253   Collective on MPI_Comm
254 
255   Input Parameter:
256 . vec   - Vec being queried
257 
258   Output Parameter:
259 . range - Entities associated with this Vec
260 
261   Level: beginner
262 
263 .keywords: DMMoab, create
264 @*/
265 PetscErrorCode DMMoabGetVecRange(Vec vec,moab::Range *range)
266 {
267   PetscContainer  moabdata;
268   Vec_MOAB        *vmoab;
269   PetscErrorCode  ierr;
270 
271   PetscFunctionBegin;
272   PetscValidPointer(range,2);
273 
274   // Get the MOAB private data handle
275   ierr = PetscObjectQuery((PetscObject)vec,"MOABData", (PetscObject*) &moabdata);CHKERRQ(ierr);
276   ierr = PetscContainerGetPointer(moabdata, (void**) &vmoab);CHKERRQ(ierr);
277 
278   *range = *vmoab->tag_range;
279   PetscFunctionReturn(0);
280 }
281 
282 
283 #undef __FUNCT__
284 #define __FUNCT__ "DMMoab_VecDuplicate"
285 PetscErrorCode DMMoab_VecDuplicate(Vec x,Vec *y)
286 {
287   PetscErrorCode ierr;
288   DM             dm;
289   PetscContainer  moabdata;
290   Vec_MOAB        *vmoab;
291 
292   PetscFunctionBegin;
293   PetscValidHeaderSpecific(x,VEC_CLASSID,1);
294   PetscValidPointer(y,2);
295 
296   // Get the Vec_MOAB struct for the original vector
297   ierr = PetscObjectQuery((PetscObject)x,"MOABData", (PetscObject*) &moabdata);CHKERRQ(ierr);
298   ierr = PetscContainerGetPointer(moabdata, (void**)&vmoab);CHKERRQ(ierr);
299 
300   ierr = VecGetDM(x, &dm);CHKERRQ(ierr);
301   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
302 
303   ierr = DMMoab_CreateVector_Private(dm,PETSC_NULL,vmoab->tag_size,vmoab->tag_range,vmoab->is_global_vec,PETSC_TRUE,y);CHKERRQ(ierr);
304   ierr = VecSetDM(*y, dm);CHKERRQ(ierr);
305   PetscFunctionReturn(0);
306 }
307 
308 
309 #undef __FUNCT__
310 #define __FUNCT__ "DMMoab_VecCreateTagName_Private"
311 /*  DMMoab_VecCreateTagName_Private
312  *
313  *  Creates a unique tag name that will be shared across processes. If
314  *  pcomm is NULL, then this is a serial vector. A unique tag name
315  *  will be returned in tag_name in either case.
316  *
317  *  The tag names have the format _PETSC_VEC_N where N is some integer.
318  *
319  *  NOTE: The tag_name is allocated in this routine; The user needs to free
320  *        the character array.
321  */
322 PetscErrorCode DMMoab_VecCreateTagName_Private(moab::ParallelComm *pcomm,char** tag_name)
323 {
324   moab::ErrorCode mberr;
325   PetscErrorCode  ierr;
326   PetscInt        n,global_n;
327   moab::Tag indexTag;
328 
329   PetscFunctionBegin;
330   const char*       PVEC_PREFIX      = "__PETSC_VEC_";
331   ierr = PetscMalloc(PETSC_MAX_PATH_LEN, tag_name);CHKERRQ(ierr);
332 
333   // Check to see if there are any PETSc vectors defined:
334   moab::Interface  *mbiface = pcomm->get_moab();
335   moab::EntityHandle rootset = mbiface->get_root_set();
336 
337     // Create a tag in MOAB mesh to index and keep track of number of Petsc vec tags
338   mberr = mbiface->tag_get_handle("__PETSC_VECS__",1,moab::MB_TYPE_INTEGER,indexTag,
339                                   moab::MB_TAG_SPARSE | moab::MB_TAG_CREAT,0);MBERRNM(mberr);
340   mberr = mbiface->tag_get_data(indexTag, &rootset, 1, &n);
341   if (mberr == moab::MB_TAG_NOT_FOUND) n=0;  /* this is the first temporary vector */
342   else MBERRNM(mberr);
343 
344   /* increment the new value of n */
345   ++n;
346 
347   // Make sure that n is consistent across all processes:
348   ierr = MPI_Allreduce(&n,&global_n,1,MPI_INT,MPI_MAX,pcomm->comm());CHKERRQ(ierr);
349 
350   // Set the new name accordingly and return:
351   ierr = PetscSNPrintf(*tag_name, PETSC_MAX_PATH_LEN-1, "%s_%D", PVEC_PREFIX, global_n);CHKERRQ(ierr);
352   mberr = mbiface->tag_set_data(indexTag, &rootset, 1, (const void*)&global_n);MBERRNM(mberr);
353   PetscFunctionReturn(0);
354 }
355 
356 
357 #undef __FUNCT__
358 #define __FUNCT__ "DMMoab_VecUserDestroy"
359 PetscErrorCode DMMoab_VecUserDestroy(void *user)
360 {
361   Vec_MOAB        *vmoab;
362   PetscErrorCode  ierr;
363   moab::ErrorCode merr;
364 
365   PetscFunctionBegin;
366   vmoab = (Vec_MOAB*)user;
367 
368   if(vmoab->new_tag && vmoab->tag) {
369     // Tag created via a call to VecDuplicate, delete the underlying tag in MOAB...
370     merr = vmoab->mbiface->tag_delete(vmoab->tag);MBERRNM(merr);
371   }
372   delete vmoab->tag_range;
373   vmoab->tag = PETSC_NULL;
374   vmoab->mbiface = PETSC_NULL;
375   vmoab->pcomm = PETSC_NULL;
376   ierr = PetscFree(vmoab);CHKERRQ(ierr);
377   PetscFunctionReturn(0);
378 }
379 
380 #undef __FUNCT__
381 #define __FUNCT__ "DMGlobalToLocalBegin_Moab"
382 PetscErrorCode  DMGlobalToLocalBegin_Moab(DM dm,Vec g,InsertMode mode,Vec l)
383 {
384   PetscErrorCode    ierr;
385   DM_Moab         *dmmoab = (DM_Moab*)dm->data;
386 
387   PetscFunctionBegin;
388   ierr = VecScatterBegin(dmmoab->ltog_sendrecv,g,l,mode,SCATTER_FORWARD);CHKERRQ(ierr);
389   PetscFunctionReturn(0);
390 }
391 
392 
393 #undef __FUNCT__
394 #define __FUNCT__ "DMGlobalToLocalEnd_Moab"
395 PetscErrorCode  DMGlobalToLocalEnd_Moab(DM dm,Vec g,InsertMode mode,Vec l)
396 {
397   PetscErrorCode    ierr;
398   DM_Moab         *dmmoab = (DM_Moab*)dm->data;
399 
400   PetscFunctionBegin;
401   ierr = VecScatterEnd(dmmoab->ltog_sendrecv,g,l,mode,SCATTER_FORWARD);CHKERRQ(ierr);
402   PetscFunctionReturn(0);
403 }
404 
405 
406 #undef __FUNCT__
407 #define __FUNCT__ "DMLocalToGlobalBegin_Moab"
408 PetscErrorCode  DMLocalToGlobalBegin_Moab(DM dm,Vec l,InsertMode mode,Vec g)
409 {
410   PetscErrorCode    ierr;
411   DM_Moab         *dmmoab = (DM_Moab*)dm->data;
412 
413   PetscFunctionBegin;
414   ierr = VecScatterBegin(dmmoab->ltog_sendrecv,l,g,mode,SCATTER_REVERSE);CHKERRQ(ierr);
415   PetscFunctionReturn(0);
416 }
417 
418 
419 #undef __FUNCT__
420 #define __FUNCT__ "DMLocalToGlobalEnd_Moab"
421 PetscErrorCode  DMLocalToGlobalEnd_Moab(DM dm,Vec l,InsertMode mode,Vec g)
422 {
423   PetscErrorCode    ierr;
424   DM_Moab         *dmmoab = (DM_Moab*)dm->data;
425 
426   PetscFunctionBegin;
427   ierr = VecScatterEnd(dmmoab->ltog_sendrecv,l,g,mode,SCATTER_REVERSE);CHKERRQ(ierr);
428   PetscFunctionReturn(0);
429 }
430 
431 
432