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
 SAF_Rel *
 saf_declare_topo_relation(SAF_ParMode pmode,            /* The parallel mode. */
                           SAF_Db *db,                   /* The dataset where the new relation will be created. */
                           SAF_Set *set,                 /* The containing set of the collection whose members are being sewn
                                                          * together by the relation. */
                           SAF_Cat *pieces,              /* The collection of members that are being sewn together. */
                           SAF_Set *range_set,
                           SAF_Cat *range_cat,           /* Together, RANGE_SET and RANGE_CAT identify the range of the relation
                                                          * (e.g., collection used to glue the pieces together). There are
                                                          * really only two valid values for RANGES_S: the set SET or the set
                                                          * MY_PIECE. */
                           SAF_Cat *storage_decomp,      /* The decomposition of SET upon which the relation is stored. */
                           SAF_Set *my_piece,            /* The piece of the decomposition being declared here. */
                           SAF_RelRep *trtype,           /* The relation types. One of SAF_STRUCTURED, SAF_UNSTRUCTURED, or
                                                          * SAF_ARBITRARY. */
                           hid_t A_type,                 /* The type of the data in A_BUF. */
                           void *A_buf,                  /* The buffer. Pass NULL if you would rather provide this in
                                                          * the write call. */
                           hid_t B_type,                 /* The type of the data in B_BUF. */
                           void *B_buf,                  /* The buffer. Pass NULL if you would rather provide this in
                                                          * the write call. */
                           SAF_Rel *rel                  /* [OUT] Optional memory that will be initialized (and returned) to
                                                          * point to the new relation. */
                           )
 {
     SAF_ENTER(saf_declare_topo_relation, NULL);
     ss_scope_t          scope;                  /* The scope where the new relation will be created. */
     int                 i, sum=0, tmp;
     ss_collection_t     pieces_coll;            /* Collection for PIECES category on SET */
     ss_collection_t     range_coll;             /* Collection for RANGE_CAT on RANGE_SET */
     ss_collection_t     storage_decomp_coll;    /* Collection for STORAGE_DECOMP on SET */

     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(set), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("SET must be a valid set handle"));
     SAF_REQUIRE(SS_CAT(pieces), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("PIECES must be a valid category"));
     SAF_REQUIRE(SS_SET(range_set), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("RANGE_SET must be a valid set"));
     SAF_REQUIRE(SS_CAT(range_cat), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("RANGE_CAT must be a valid category"));
     SAF_REQUIRE(SS_SET(my_piece), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("MY_PIECES must be a valid handle"));
     SAF_REQUIRE(SS_CAT(storage_decomp), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("STORAGE_DECOMP must be either the self decomposition or a valid cat handle"));
     SAF_REQUIRE(SS_RELREP(trtype), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("TRTYPE must be a consistent relation representation handle"));
     SAF_REQUIRE(SAF_STRUCTURED_ID==SS_RELREP(trtype)->id || SAF_UNSTRUCTURED_ID==SS_RELREP(trtype)->id ||
                 SAF_ARBITRARY_ID==SS_RELREP(trtype)->id,
                 SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("TRTYPE must be a valid topology representation"));
     SAF_REQUIRE(A_type<=0 || H5T_INTEGER==H5Tget_class(A_type) ||
                 (H5Tequal(A_type,ss_pers_tm) && _saf_is_self_decomp(storage_decomp)),
                 SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("If supplied, A_TYPE must be an integer type (or SAF_HANDLE if decomposed)"));
     SAF_REQUIRE(A_type>0 || !A_buf, SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("A_TYPE must be supplied if A_BUF is supplied"));
     SAF_REQUIRE(B_type<=0 || H5T_INTEGER==H5Tget_class(B_type) || H5Tequal(B_type, ss_pers_tm),
                 SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("B_TYPE must be an integer type or handle type"));
     SAF_REQUIRE(B_type || !B_buf, SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("B_TYPE must be supplied if B_BUF if supplied"));

     /* The my_piece parameter */
     SAF_REQUIRE(A_type<=0 || SAF_XOR(_saf_is_self_decomp(storage_decomp), H5Tequal(A_type, ss_pers_tm)),
                 SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("A_TYPE must be handle if storage decomposition is not self "
                             "but must not be handle if storage decomposition is self"));

     /* confirm pieces cat exists on set */
     if (NULL==_saf_getCollection_set(set, pieces, &pieces_coll))
         SAF_ERROR(NULL, _saf_errmsg("collection \"%s\" not found on set \"%s\"",
                                     ss_string_ptr(SS_CAT_P(pieces,name)), ss_string_ptr(SS_SET_P(set,name))));

     /* Confirm pieces is a primitive collection */
     if (SS_COLLECTION(&pieces_coll)->cell_type == SAF_CELLTYPE_SET)
         SAF_ERROR(NULL, _saf_errmsg("SAF currently only supports topology relations on primitive collections"));

     switch(SS_SET(set)->tdim) {
     case 0:
         if (SS_COLLECTION(&pieces_coll)->cell_type != SAF_CELLTYPE_POINT)
             SAF_ERROR(NULL, _saf_errmsg("domain set dimension not compatible with collection cell"));
         break;
     case 1:
         if (SS_COLLECTION(&pieces_coll)->cell_type != SAF_CELLTYPE_LINE)
             SAF_ERROR(NULL, _saf_errmsg("domain set dimension not compatible with collection cell"));
         break;
     case 2:
         if (SAF_STRUCTURED_ID==SS_RELREP(trtype)->id && SS_COLLECTION(&pieces_coll)->cell_type != SAF_CELLTYPE_QUAD)
             SAF_ERROR(NULL, _saf_errmsg("structured meshes declared on domain sets of dimension "
                                         "2 may only use SAF_CELLTYPE_QUAD collection cells"));
         break;
     case 3:
         if (SAF_STRUCTURED_ID==SS_RELREP(trtype)->id && SS_COLLECTION(&pieces_coll)->cell_type != SAF_CELLTYPE_HEX)
             SAF_ERROR(NULL, _saf_errmsg("structured meshes declared on domain sets of dimension "
                                         "3 may only use SAF_CELLTYPE_HEX collection cells"));
         break;
     default:
         SAF_ERROR(NULL, _saf_errmsg("domain sets of dimension > 3 not currently supported"));
     }

     /* Confirm range_cat exists on range_set set */
     if (NULL==_saf_getCollection_set(range_set, range_cat, &range_coll))
         SAF_ERROR(NULL, _saf_errmsg("collection \"%s\" not found on set \"%s\"",
                                     ss_string_ptr(SS_CAT_P(range_cat,name)), ss_string_ptr(SS_SET_P(range_set,name))));

     /* Build a 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 = *set;
     SS_REL(rel)->sub_cat = *pieces;
     SS_REL(rel)->sub_decomp_cat = *storage_decomp;
     SS_REL(rel)->sup = *range_set;
     SS_REL(rel)->sup_cat = *range_cat;
     SS_REL(rel)->sup_decomp_cat = *storage_decomp;
     SS_REL(rel)->kind = SAF_RELKIND_SUBSET;
     SS_REL(rel)->rep_type = *trtype;

     /* Compute the size of each buffer (if any). */
     SS_REL(rel)->m.abuf_type = A_type;
     SS_REL(rel)->m.bbuf_type = B_type;
     if (_saf_is_self_decomp(storage_decomp)) {
         /* A topological relation which is stored on self has buffers whose sizes are based on the size of the collection being
          * sewn together (given "set" and "pieces" category).
          *
          * Note that the buffer size depends on the number of size of the collection category and the nature of the relation
          * (structured, unstructured, ...). */
         switch (SS_RELREP(trtype)->id) {
         case SAF_STRUCTURED_ID:
             SS_REL(rel)->m.abuf = NULL;
             SS_REL(rel)->m.bbuf = NULL;
             SS_REL(rel)->m.abuf_size = 0;
             SS_REL(rel)->m.bbuf_size = 0;
             break;
         case SAF_UNSTRUCTURED_ID:
             /* If the user gives a value for A_buf and A_type, it is the number of range refs per member of the pieces,
              * otherwise, we assume its 1 and catch it on the write call */
             SS_REL(rel)->m.abuf = A_buf;
             SS_REL(rel)->m.bbuf = B_buf;
             SS_REL(rel)->m.abuf_size = 1;
             SS_REL(rel)->m.bbuf_size = SS_COLLECTION(&pieces_coll)->count;
             if (A_type>0 && A_buf) {
                 _saf_convert(A_type, A_buf, H5T_NATIVE_INT, &tmp);
                 SS_REL(rel)->m.bbuf_size *= tmp;
             }
             break;
         case SAF_ARBITRARY_ID:
             /* If the user gives a value for A_buf, it is an array of length equal to size of pieces from which can can
              * calculate the size of B_buf. Otherwise, we set bbuf_size to -1 and catch it on the write call */
             SS_REL(rel)->m.abuf = A_buf;
             SS_REL(rel)->m.bbuf = B_buf;
             SS_REL(rel)->m.abuf_size = SS_COLLECTION(&pieces_coll)->count;
             if (A_type>0 && A_buf) {
                 for (i=0, sum=0; i<SS_COLLECTION(&pieces_coll)->count; i++) {
                     _saf_convert(A_type, A_buf, H5T_NATIVE_INT, &tmp);
                     sum += tmp;
                 }
                 SS_REL(rel)->m.bbuf_size = sum;
             } else {
                 SS_REL(rel)->m.bbuf_size = SS_NOSIZE;
             }
             break;
         default:
             SAF_ERROR(NULL,_saf_errmsg("invalide topology relation type"));
         }
     } else {
         /* A topological relation which is stored on a decomposition has only a single buffer of type SAF_HANDLE whose size is
          * based on the size of the storage collection.  At this point the issue of structured vs. unstructured vs. arbitrary
          * is not important, the buffer is simply a vector of handles. */
         if (NULL==_saf_getCollection_set(set, storage_decomp, &storage_decomp_coll))
             SAF_ERROR(NULL, _saf_errmsg("collection \"%s\" not found on set \"%s\"",
                                         ss_string_ptr(SS_CAT_P(storage_decomp,name)), ss_string_ptr(SS_SET_P(set,name))));
     }

     SAF_LEAVE(rel);
 }