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