1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
 int
 saf_get_count_and_type_for_topo_relation(SAF_ParMode pmode,     /* The parallel mode. */
                                          SAF_Rel *rel,          /* The relation handle. */
                                          SAF_RelTarget *target, /* Targeting information. */
                                          SAF_RelRep *PrepType,  /* [OUT] The mapping representation type (arbitrary, structured, or
                                                                  * unstructured). The caller may pass value of NULL for this
                                                                  * parameter if this value is not desired. */
                                          size_t *abuf_sz,       /* [OUT] The number of items that would be placed in the A-buffer by
                                                                  * a call to the saf_read_topo_relation() function.  The caller
                                                                  * may pass value of NULL for this parameter if this value is not
                                                                  * desired. */
                                          hid_t *abuf_type,      /* [OUT] The type of the items that would be placed in the
                                                                  * A-buffer by a call to the saf_read_topo_relation()
                                                                  * function.  The caller may pass value of NULL for this
                                                                  * parameter if this value is not desired. */
                                          size_t *bbuf_sz,       /* [OUT] The number of items that would be placed in the B-buffer by
                                                                  * a call to the saf_read_topo_relation() function.  The caller
                                                                  * may pass value of NULL for this parameter if this value is not
                                                                  * desired. */
                                          hid_t *bbuf_type       /* [OUT] The type of the items that would be placed in the
                                                                  * B-buffer by a call to the saf_read_topo_relation()
                                                                  * function.  The caller may pass value of NULL for this
                                                                  * parameter if this value is not desired. */
                                          )
 {
     SAF_ENTER(saf_get_count_and_type_for_topo_relation, SAF_PRECONDITION_ERROR);
     static SAF_RelTarget        rt_zero;                /* Default targeting */
     ss_scope_t                  scope=SS_SCOPE_NULL;    /* Scope containing REL */
     int                         scope_size;             /* Size of the communicator for `scope' */
     size_t                      maxFactor=0;
     size_t                      minFactor=0;
     ss_set_t                    sup=SS_SET_NULL;
     ss_cat_t                    storage_decomp=SS_CAT_NULL;
     ss_relrep_t                 relrep=SS_RELREP_NULL;
     ss_blob_t                   rblob=SS_BLOB_NULL;
     ss_blob_t                   dblob=SS_BLOB_NULL;
     hsize_t                     r_size, d_size;         /* Sizes of range and domain blobs in elements */
     hid_t                       mtype=-1, ftype=-1;     /* Memory and file datatypes */
     hbool_t                     desireHandles, haveFactor;
     ss_collection_t             storage_coll=SS_COLLECTION_NULL;
     size_t                      IAcount, IBcount, d;
     hid_t                       IAtype=-1, IBtype=-1;
     void                        *IAbuf=NULL, *IBbuf=NULL;
     ss_relrep_t                 haveRelRep=SS_RELREP_NULL;
     ss_rel_t                    *theRels=NULL;
     int                         collectionSize;

     SAF_REQUIRE(_saf_valid_pmode(pmode), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("PMODE must be valid"));
     if (!_saf_is_participating_proc(pmode)) SAF_RETURN(-1);
     ss_pers_scope((ss_pers_t*)rel, &scope);
     ss_scope_comm(&scope, NULL, NULL, &scope_size);
     if (!target) target = &rt_zero;

     SAF_REQUIRE(SS_REL(rel), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("REL must be a valid relation handle"));
     SAF_REQUIRE((target->is_set && (SS_PERS_ISNULL(&target->decomp) || pmode==SAF_ALL || 1==scope_size)) || !target->is_set,
                 SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("if targeting of storage decomposition is used, the read must be a SAF_ALL mode read "
                             "or the database must be opened on only a single processor"));

     /* Check that data has actually been written to this relation and if not, return either what is known about it in the
      * relation handle itself or no information. */
     if (SS_PERS_ISNULL(SS_REL_P(rel,r_blob)) && SS_PERS_ISNULL(SS_REL_P(rel,d_blob)) &&
         0==ss_array_nelmts(SS_REL_P(rel,indirect_rels))) {
         if (abuf_sz)
             *abuf_sz = SS_NOSIZE==SS_REL(rel)->m.abuf_size ? 0 : SS_REL(rel)->m.abuf_size;
         if (bbuf_sz)
             *bbuf_sz = SS_NOSIZE==SS_REL(rel)->m.bbuf_size ? 0 : SS_REL(rel)->m.bbuf_size;
         if (abuf_type)
             *abuf_type = SS_REL(rel)->m.abuf_type>0 ? H5Tcopy(SS_REL(rel)->m.abuf_type) : H5I_INVALID_HID;
         if (bbuf_type)
             *bbuf_type = SS_REL(rel)->m.bbuf_type>0 ? H5Tcopy(SS_REL(rel)->m.bbuf_type) : H5I_INVALID_HID;
         goto theExit;
     }

     /* Cache some things for convenience */
     sup = SS_REL(rel)->sup;
     storage_decomp = SS_REL(rel)->sub_decomp_cat;
     relrep = SS_REL(rel)->rep_type;
     rblob = SS_REL(rel)->r_blob;
     dblob = SS_REL(rel)->d_blob;


     /* A topological relation that is stored on self is treated quite a bit differently that one that is stored on a
      * decomposition... */
     if (_saf_is_self_decomp(&storage_decomp)) {
         /*  Quick check for structured topology (nothing to read)... */
         if (SAF_STRUCTURED_ID==SS_RELREP(&relrep)->id) {
             if (PrepType) *PrepType = *SAF_STRUCTURED;
             if (abuf_sz) *abuf_sz = 0;
             if (abuf_type) *abuf_type = H5I_INVALID_HID;;
             if (bbuf_sz) *bbuf_sz = 0;
             if (bbuf_type) *bbuf_type = H5I_INVALID_HID;
             goto theExit;
         }

         ss_blob_bound_f1(&rblob, NULL, NULL, &r_size, &ftype);
         mtype = H5Tget_native_type(ftype, H5T_DIR_DEFAULT);
         H5Tclose(ftype); ftype=-1;

         /* The nature of the A- and B-buffers depends on the rep type. */
         switch (SS_RELREP(&relrep)->id) {
         case SAF_UNSTRUCTURED_ID:
             if (PrepType) *PrepType = *SAF_UNSTRUCTURED;
             if (abuf_sz) *abuf_sz = 1;
             if (abuf_type) *abuf_type = H5Tcopy(mtype);
             if (bbuf_sz) *bbuf_sz = r_size;
             if (bbuf_type) *bbuf_type = H5Tcopy(mtype);
             break;
         case SAF_ARBITRARY_ID:
             /* In this case, we need to get the blob record for the domain of the relation too */
             ss_blob_bound_f1(&dblob, NULL, NULL, &d_size, NULL);

             if (PrepType) *PrepType = *SAF_ARBITRARY;
             if (abuf_sz) *abuf_sz = d_size;
             if (abuf_type) *abuf_type = H5Tcopy(mtype);
             if (bbuf_sz) *bbuf_sz = r_size;
             if (bbuf_type) *bbuf_type = H5Tcopy(mtype);
             break;
         default:
             SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("unknown topology relation type %s (%d)",
                                                   ss_string_ptr(SS_RELREP_P(&relrep,name)), SS_RELREP(&relrep)->id));
         }
     } else {
         /* The relation is stored on a decomposition. There are two cases here: the caller wishes to receive info about the map
          * on self decomposition (remapping the values to "global") or the caller wishes to recieve info on the (indirect)
          * handles to the relations which actually have the data. The caller informs SAF of which of these two cases is desired
          * by using the saf_target_topo_relation function. */
         if (SS_PERS_ISNULL(&target->decomp)) {
             desireHandles = TRUE;
         } else if (_saf_is_self_decomp(&target->decomp)) {
             desireHandles = FALSE;
         } else {
             desireHandles = TRUE;
         }
         if (desireHandles) {
             if (NULL==_saf_getCollection_set(&sup, &storage_decomp, &storage_coll))
                 SAF_ERROR(SAF_CONSTRAINT_ERROR,
                           _saf_errmsg("collection \"%s\" not found on set \"%s\"",
                                       ss_string_ptr(SS_CAT_P(&storage_decomp,name)),
                                       ss_string_ptr(SS_SET_P(&sup,name))));
             if (PrepType) *PrepType = *SAF_NOT_APPLICABLE_RELREP;
             if (abuf_sz) *abuf_sz = (size_t)SS_COLLECTION(&storage_coll)->count;
             if (abuf_type) *abuf_type = H5Tcopy(ss_pers_tm);
             if (bbuf_sz) *bbuf_sz = 0;
             if (bbuf_type) *bbuf_type = H5I_INVALID_HID;
         } else {
             /* Case 2: the caller wishes to receive info about the maps as though they had been stored on self rather than on a
              * decomposition. The caller should expect the info on the number and types of items stored at A- and/or B-buffers.
              * The appropriate number of buffers data depends in the nature of the relation: structured, unstructured, or
              * arbitrary. */

             /* First we'll get the indirect handles using a recursive call. */
             IAcount = 0;
             IAtype = H5I_INVALID_HID;
             IBcount = 0;
             IBtype = H5I_INVALID_HID;
             saf_get_count_and_type_for_topo_relation(pmode, rel, NULL, NULL, &IAcount, &IAtype, &IBcount, &IBtype);
             if (IAcount < 1)
                 SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("no indirect topo handles"));
             IAbuf = NULL;
             IBbuf = NULL;
             if (saf_read_topo_relation(pmode, rel, NULL, &IAbuf, &IBbuf)!=SAF_SUCCESS || !IAbuf)
                 SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("can't retrieve indirect topo handles"));

             /* We'll read each of the topo relations on the decomposition to determine the "mapping factor". The mapping factor
              * is the number of maps for each member of the "stitched" collection (example: nodes per zone). We'll be using the
              * "mapping factor" to compute the returned (predicted) B-buffer size. */
             haveFactor = FALSE;
             haveRelRep = SS_RELREP_NULL;
             theRels = IAbuf;
             for (d=0; d<IAcount; d++) {
                 void *Abuf, *Bbuf;
                 size_t Acount=0, Bcount=0;
                 hid_t Atype=H5I_INVALID_HID, Btype=H5I_INVALID_HID;
                 SAF_RelRep thisRelRep;

                 saf_get_count_and_type_for_topo_relation(pmode, theRels+d, NULL, &thisRelRep, &Acount, &Atype, &Bcount, &Btype);
                 if (SS_PERS_ISNULL(&haveRelRep)) {
                     haveRelRep = thisRelRep;
                 } else if (!SAF_EQUIV(&haveRelRep, SAF_ERROR_RELREP) && !SAF_EQUIV(&haveRelRep,&thisRelRep)) {
                     SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("multiple relation representations found"));
                 }
                 Abuf = Bbuf = NULL;
                 if (saf_read_topo_relation(pmode, theRels+d, NULL, &Abuf, &Bbuf)!=SAF_SUCCESS || !Abuf)
                     SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("can't retrieve indirect topo handles"));

                 /* Look at the size of the A-buffer and the contents if the size is exactly 1. This is the "mapping factor"
                  * indicating how many of the "stitching" category for each of the "stitched" category.  Update both the max an
                  * min encountered... */
                 if (Acount==1 && Bcount>0) {
                     size_t tmp;
                     _saf_convert(Atype, Abuf, H5T_NATIVE_SIZE, &tmp);
                     if (haveFactor) {
                         if (tmp<minFactor) minFactor = tmp;
 #ifdef SSLIB_SUPPORT_PENDING
                         /* This is the old code. It looks wrong. [rpm 2004-05-26] */
                         if (minFactor<tmp) maxFactor = tmp;
 #else
                         if (tmp>maxFactor) maxFactor = tmp;
 #endif /*SSLIB_SUPPORT_PENDING*/
                     } else {
                         minFactor = maxFactor = tmp;
                         haveFactor = TRUE;
                     }
                 }
                 Abuf = SS_FREE(Abuf);
                 Bbuf = SS_FREE(Bbuf);
             }

             if (SAF_EQUIV(&haveRelRep, SAF_ARBITRARY)) {
                 if (PrepType) *PrepType = *SAF_ARBITRARY;
                 SAF_ERROR(SAF_NOTIMPL_ERROR, _saf_errmsg("\"arbitrary\" topo remapping not implemented yet"));
             } else if (SAF_EQUIV(&haveRelRep, SAF_STRUCTURED)) {
                 if (PrepType) *PrepType = *SAF_STRUCTURED;
                 if (abuf_sz) *abuf_sz = 0;
                 if (abuf_type) *abuf_type = H5I_INVALID_HID;
                 if (bbuf_sz) *bbuf_sz = 0;
                 if (bbuf_type) *bbuf_type = H5I_INVALID_HID;
             } else if (SAF_EQUIV(&haveRelRep, SAF_UNSTRUCTURED)) {
                 if (haveFactor && minFactor==maxFactor) {
                     saf_describe_collection(pmode, SS_REL_P(rel,sub), SS_REL_P(rel,sub_cat), NULL, &collectionSize, NULL, NULL,
                                             NULL);
                     if (PrepType) *PrepType = *SAF_UNSTRUCTURED;
                     if (abuf_sz) *abuf_sz = 1;
                     if (abuf_type) *abuf_type = H5Tcopy(H5T_NATIVE_SIZE);
                     if (bbuf_sz) *bbuf_sz = collectionSize * minFactor;
                     if (bbuf_type) *bbuf_type = H5Tcopy(H5T_NATIVE_SIZE);
                 } else {
                     SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("mixed factors not supported in topo remapping"));
                 }
             }

             IAbuf = SS_FREE(IAbuf);
             IBbuf = SS_FREE(IBbuf);
         }
     }

 theExit:

     SAF_LEAVE(SAF_SUCCESS);
 }