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
 SAF_Rel *
 saf_declare_subset_relation(SAF_ParMode pmode,          /* The parallel mode. */
                             SAF_Db *db,                 /* The database in which to place the new relation. */
                             SAF_Set *sup,               /* The superset. In SAF_ONE parallel mode, all processors except the
                                                          * one identified by the SAF_ONE argument should pass the null set of
                                                          * the database by using the SAF_NULL macro. */
                             SAF_Set *sub,               /* The subset. In SAF_ONE parallel mode, all processors except the one
                                                          * identified by the SAF_ONE argument should pass the null set of the
                                                          * database by using the SAF_NULL macro. */
                             SAF_Cat *sup_cat,           /* The collection category on the SUP set upon which
                                                          * the subset relation is being defined. Note that collections of this
                                                          * category must have already been defined on SUP. Otherwise, an
                                                          * error is generated. Note, the four args, SUP_CAT, SUB_CAT, SBMODE,
                                                          * CBMODE, are typically passed using one of the macros described above,
                                                          * SAF_COMMON(C), SAF_BOUNDARY(P,B), SAF_EMBEDBND(P,B) or
                                                          * SAF_GENERAL(BND) */
                             SAF_Cat *sub_cat,           /* The collection category on the SUB set upon which the subset relation
                                                          * is being defined. Note that collections of this category must have
                                                          * already been defined on SUB. Otherwise an error is generated. */
                             SAF_BoundMode sbmode,       /* Indicates whether SUB is the boundary of SUP. Pass either
                                                          * SAF_BOUNDARY_TRUE or SAF_BOUNDARY_FALSE */
                             SAF_BoundMode cbmode,       /* Indicates whether *members* of collection on SUB are *on* the
                                                          * boundary of members of the collection on SUP. Pass either
                                                          * SAF_BOUNDARY_TRUE or SAF_BOUNDARY_FALSE */
                             SAF_RelRep *srtype,         /* Subset relation types. This argument describes how the data in ABUF
                                                          * represents the subset. Valid values are SAF_HSLAB meaning that ABUF
                                                          * points to a hyperslab specification and SAF_TUPLES meaning that ABUF
                                                          * points to a list of N-tuples. */
                             hid_t A_type,               /* The type of the data in A_BUF */
                             void *A_buf,                /* This buffer contains references, one for each member of the domain
                                                          * collection (on SUB), to members of the range collection (on SUP).
                                                          * The client may pass NULL here meaning that the raw data will be bound
                                                          * to the object during write, rather than declaration. */
                             hid_t B_type,               /* The type of the data in B_BUF */
                             void *B_buf,                /* This buffer is valid *only* when the members of the domain collection
                                                          * (on SUB) are on the boundaries of the members of the range collection
                                                          * (on SUP). In this case, the data contained in this buffer identifies
                                                          * "which piece" of the boundary each member of the domain collection is.
                                                          * Otherwise, the client should pass NULL here.
                                                          * As with ABUF, the client may pass also NULL here meaning the raw data
                                                          * will be bound to the object during write, rather than declaration. */
                             SAF_Rel *rel                /* [OUT] Optional returned relation handle. */
                             )
 {
     SAF_ENTER(saf_declare_subset_relation, NULL);
     ss_scope_t          scope;                          /* The scope where the new relation will be created. */
     ss_collection_t     sub_coll=SS_COLLECTION_NULL, sup_coll=SS_COLLECTION_NULL;
     int                 sub_count, sup_ndims;
     ss_indexspec_t      idx;

     SAF_REQUIRE(_saf_valid_pmode(pmode), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("PMODE must be valid"));
     if (!_saf_is_participating_proc(pmode)) SAF_RETURN(NULL);
     ss_file_topscope(db, &scope);

     SAF_REQUIRE(SS_SET(sup), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("SUP must be a valid set handle"));
     SAF_REQUIRE(SS_SET(sub), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("SUB must be a valid set handle"));
     SAF_REQUIRE(sbmode==SAF_BOUNDARY_TRUE || sbmode==SAF_BOUNDARY_FALSE, SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("SBMODE must be either SAF_BOUNDARY_TRUE or SAF_BOUNDARY_FALSE"));
     SAF_REQUIRE(cbmode==SAF_BOUNDARY_TRUE || cbmode==SAF_BOUNDARY_FALSE, SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("CBMODE must be either SAF_BOUNDARY_TRUE or SAF_BOUNDARY_FALSE"));
     SAF_REQUIRE((sbmode==SAF_BOUNDARY_TRUE && cbmode==SAF_BOUNDARY_TRUE) || sbmode==SAF_BOUNDARY_FALSE,
                 SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("CBMODE must be SAF_BOUNDARY_TRUE if SBMODE is SAF_BOUNDARY_TRUE for all participating processes"));
     SAF_REQUIRE((!SS_CAT(sup_cat) && !SS_CAT(sub_cat) && !A_buf) || (SS_CAT(sup_cat) && SS_CAT(sub_cat)),
                 SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("Either A_BUF is null and both SUP_CAT and SUB_CAT are not valid cat handles or"
                             "SUP_CAT and SUB_CAT are both valid cat handles"));
     SAF_REQUIRE((B_buf && cbmode==SAF_BOUNDARY_TRUE) || !B_buf, SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("B_BUF can be non-NULL only when CBMODE is SAF_BOUNDARY_TRUE"));
     SAF_REQUIRE((_saf_is_self_decomp(sup_cat) && _saf_is_self_decomp(sub_cat) &&
                  cbmode!=SAF_BOUNDARY_TRUE && sbmode!=SAF_BOUNDARY_TRUE) ||
                 (!_saf_is_self_decomp(sup_cat) && !_saf_is_self_decomp(sub_cat)),
                 SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("on the reserved, \"self\" collection, CBMODE and SBMODE must be SAF_BOUNDARY_FALSE"));
     SAF_REQUIRE(SS_RELREP(srtype), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("SRTYPE must be a valid relation representation handle"));
     SAF_REQUIRE(SAF_HSLAB_ID==SS_RELREP(srtype)->id || SAF_TUPLES_ID==SS_RELREP(srtype)->id,
                 SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("SRTYPE must be either SAF_HSLAB or SAF_TUPLES"));
     SAF_REQUIRE(rel, SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("REL must be non-NULL"));
     SAF_REQUIRE(A_type<=0 || H5T_INTEGER==H5Tget_class(A_type), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("A_TYPE must be an integer type if supplied"));
     SAF_REQUIRE(B_type<=0 || H5T_INTEGER==H5Tget_class(B_type), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("B_TYPE must be an integer type if supplied"));

     if (SS_CAT(sup_cat) && SS_CAT(sub_cat)) {
         _saf_getCollection_set(sub, sub_cat, &sub_coll);
         _saf_getCollection_set(sup, sup_cat, &sup_coll);

         /* confirm sup collecton has its respective category defined on it */
         if (SS_PERS_ISNULL(&sup_coll)) {
             /* instantiate the self collection on the sup set, if necessary */
             if (_saf_is_self_decomp(sup_cat)) {
                 if (saf_declare_collection(pmode, sup, sup_cat, SAF_CELLTYPE_SET, 1, SAF_1DC(1), SAF_DECOMP_TRUE) != SAF_SUCCESS) {
                     SAF_ERROR(NULL, _saf_errmsg("unable to instantiate self collection on set \"%s\"",
                                                 ss_string_ptr(SS_CAT_P(sup_cat,name))));
                 }
             } else {
                 SAF_ERROR(NULL,_saf_errmsg("set \"%s\" does not have a collection of category \"%s\"",
                                            ss_string_ptr(SS_SET_P(sup,name)), ss_string_ptr(SS_CAT_P(sup_cat,name))));
             }
         }

         /* confirm sub collecton has its respective category defined on it */
         if (SS_PERS_ISNULL(&sub_coll)) {
             /* instantiate the self collection on the sub set, if necessary */
             if (_saf_is_self_decomp(sub_cat)) {
                 if (saf_declare_collection(pmode, sub, sub_cat, SAF_CELLTYPE_SET, 1, SAF_1DC(1), SAF_DECOMP_TRUE)!=SAF_SUCCESS) {
                     SAF_ERROR(NULL, _saf_errmsg("unable to instantiate self collection on set \"%s\"",
                                                 ss_string_ptr(SS_CAT_P(sub_cat,name))));
                 }
                 sub_count = 1;
                 sup_ndims = 1;
             } else {
                 SAF_ERROR(NULL, _saf_errmsg("set \"%s\" does not have a collection of category \"%s\"",
                                             ss_string_ptr(SS_SET_P(sub,name)), ss_string_ptr(SS_CAT_P(sub_cat,name))));
             }
         } else {
             /* obtain the count of the domain */
             sub_count = SS_COLLECTION(&sub_coll)->count;

             /* obtain the default indexing scheme of the range */
             ss_array_get(SS_COLLECTION_P(&sup_coll,indexing), ss_pers_tm, (size_t)0, (size_t)1, &idx);
             sup_ndims = SS_INDEXSPEC(&idx)->ndims;
         }
     } else {
         /* if both sup_cat and sub_cat are NULL, it is the general case */
         sub_count = 0;
         sup_ndims = 0;
     }

     /* Initialize the relation record */
     rel = (ss_rel_t*)ss_pers_new(&scope, SS_MAGIC(ss_rel_t), NULL, SAF_ALL==pmode?SS_ALLSAME:0U, (ss_pers_t*)rel, NULL);
     if (!rel) SAF_ERROR(NULL, _saf_errmsg("unable to create or initialize the new relation object and/or handle"));
     if (SAF_EACH==pmode) SS_PERS_UNIQUE(rel);
     SS_REL(rel)->sub = *sub;
     if (sub_cat) SS_REL(rel)->sub_cat = *sub_cat;
     SS_REL(rel)->sup = *sup;
     if (sup_cat) SS_REL(rel)->sup_cat = *sup_cat;
     SS_REL(rel)->kind = cbmode==SAF_BOUNDARY_TRUE ? SAF_RELKIND_BOUND : SAF_RELKIND_EQUAL;
     SS_REL(rel)->rep_type = *srtype;

     /* If the subset is the boundary of the superset, then set the bnd_set_id member of superset */
     if (sbmode == SAF_BOUNDARY_TRUE) {
         SAF_DIRTY(sup, pmode);
         SS_SET(sup)->bnd_set = *sub;
     }

     /* Issue: If we could guarantee all processors' is_top member were identical, we could wrap this call so that we don't try
      *        to put the set record if its already NOT a top set. */

     /* Set the "is_top" member of the subset to false */

     /* The test whether parent and child sroles are the same has been added as a result of the new 'cross-product base space'.
      * The 'mesh space' topset now becomes a subset of the new Suite set, but we want the conceptual topset of the mesh space
      * to still be flagged as a topset.  The srole of the suite is SAF_SUITE and the srole of the mesh space topset is
      * SAF_SPACE.  By checking to make sure the sroles are equal before changing is_top to false, we can ensure that the mesh
      * space stays flagged with is_top true.
      *
      * The is_top in should probably be changed from hbool_t to another type that allows for us to have multiple topsets for
      * different sroles.  SPACE topsets, SUITE topsets, TIME topsets, etc. */
     if (SS_SET(sup)->srole == SS_SET(sub)->srole) {
         SAF_DIRTY(sub, pmode);
         SS_SET(sub)->is_top = FALSE;
     }

     /* Fill in the handle and return it. */
     SS_REL(rel)->m.abuf = A_buf;
     SS_REL(rel)->m.abuf_type = A_type;
     SS_REL(rel)->m.bbuf = B_buf;
     SS_REL(rel)->m.bbuf_type = B_type;

     /* Calculate size stuff. In general case, the bufs are zero-sized. */
     if (!SS_CAT(sup_cat) && !SS_CAT(sub_cat)) {
         SS_REL(rel)->m.abuf_size = 0;
         SS_REL(rel)->m.bbuf_size = 0;
     } else {
         if (SAF_HSLAB_ID==SS_RELREP(srtype)->id)
             SS_REL(rel)->m.abuf_size = 3 * sup_ndims;           /* start, length and stride for each dim of sup */
         if (SAF_TUPLES_ID==SS_RELREP(srtype)->id)
             SS_REL(rel)->m.abuf_size = sub_count * sup_ndims;   /* one ndim-tuple for each member of sub */
         SS_REL(rel)->m.bbuf_size = sub_count;
     }

     SAF_LEAVE(rel);
 }