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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
 SAF_Field *
 saf_declare_field(SAF_ParMode pmode,            /* The parallel mode. */
                   SAF_Db *db,                   /* The database where the new field will be created. */
                   SAF_FieldTmpl *ftmpl,         /* The field template handle for this field. Recall that the field template
                                                  * describes the abstract features of the field, including the quantity the
                                                  * field represents, and the algebraic type. The field being created in this
                                                  * saf_declare_field() call is simply an instance of the abstract field
                                                  * characterized by the field template passed as this argument. */
                   const char *name,             /* The name of this field. If a writer client declares different fields with
                                                  * the same name, a reader client that searches for fields by name will find
                                                  * multiple matches. However, it is ok to declare different fields with the
                                                  * same name. */
                   SAF_Set *base_space,          /* The base_space of this field */
                   SAF_Unit *unit,               /* The specific units of measure. If in the field template, the quantity was
                                                  * not specified, then the only valid value that can be passed for units is
                                                  * SAF_NOT_APPLICABLE_UNIT. Otherwise, pass SAF_NOT_SET_UNIT if you do not want
                                                  * to specify units for the field or pass one of the valid units of
                                                  * measure. */
                   SAF_Cat *homog_decomp,        /* If the field is homogeneous, enter SAF_SELF() here. Otherwise, the field is
                                                  * inhomogenous and this argument must indicate a decomposing collection of the
                                                  * field's base-space upon which it is /presumably/ homogeneous. We say
                                                  * /presumably/ because it is not a *requirement* that the field be
                                                  * homogeneous on each of the members of the collection indentified here. The
                                                  * field pieces defined on any one or all of those members can, in turn, also
                                                  * be inhomogeneous. The only requirement is that the collection identified
                                                  * here be a decomposition of the associated set and that, ultimately, the
                                                  * recursion of defining inhomogeneous fields in terms of other inhomogeneous
                                                  * fields terminates on a bunch of homogeneous pieces. A common use of this
                                                  * argument is to indicate that the field is broken into independent chunks of
                                                  * storage (either within a single processor or distributed across other
                                                  * processors). In fact, prior to SAF-1.2.1, that was all this argument was
                                                  * used for and documented as supporting. Any collections contained in the
                                                  * base space set for which the IS_DECOMP argument in the
                                                  * saf_declare_collection() call was SAF_DECOMP_TRUE, can be passed
                                                  * here. See the chapter introduction for fields for further information (see
                                                  * Fields). */
                   SAF_Cat *coeff_assoc,         /* This argument identifies the category of a collection in the base space set
                                                  * which the field's coefficients are n:1 associated with.  For example, for a
                                                  * field whose coefficients are 1:1 with a collection of a category
                                                  * representing the nodes, you would identify that collection category with
                                                  * this argument. Likewise, for a field whose coefficients are 4:1 with a
                                                  * collection of a category representing the elements in the problem, you
                                                  * would identify that collection with this argument. Note, if the
                                                  * coefficients are associated with the base space itself, and not the members
                                                  * of a collection in the base-space set, you would pass SAF_SELF() for
                                                  * this argument. */
                   int assoc_ratio,              /* This argument specifies the /n/ in the n:1 association described above. For
                                                  * example, if for every member of the collection representing the elements,
                                                  * you have 1 coefficient, then this value would be 1. This value is always
                                                  * non-negative. */
                   SAF_Cat *eval_cat,            /* This argument specifies the collection whose members represent the pieces in
                                                  * the piecewise evaluation of the field.  If there is only a single piece
                                                  * (e.g. the whole base space), then pass SAF_SELF().  For example, a
                                                  * collection category identifying the nodes for the COEFF_ASSOC argument and
                                                  * an ASSOC_RATIO of 1 indicates only that we have 1 coefficient for each
                                                  * member of the collection of nodes. It does not indicate which collection
                                                  * in the base space (for example the elements), the field is actually
                                                  * piecewise evaluated on. */
                   SAF_Eval *eval_func,          /* This argument identifies one of several evaluation functions currently known
                                                  * to SAF. Again, SAF does not yet actually evaluate a field. It only stores
                                                  * the descriptive information to support its evaluation. See definition of
                                                  * SAF_EvalFunc enum for the possible values. Also, we have provided some
                                                  * convenience macros for this and COEFF_ASSOC, ASSOC_RATIO, and EVAL_CAT
                                                  * arguments for common cases; /node/ /centered/ and /zone/ /centered/
                                                  * fields. Pass SAF_NODAL() for a node centered field, SAF_ZONAL() for a zone
                                                  * centered field, SAF_DECOMP for a field that is piecewise constant over
                                                  * some /decomposing/ collection (e.g. domains) or SAF_CONSTANT() for a
                                                  * constant field. */
                   hid_t data_type,              /* The type of data in BUFS if BUFS are provided. */
                   SAF_Field *comp_flds,         /* Array of component field handles.  Pass null only if there are no
                                                  * components to this field (the field is a scalar field). */
                   SAF_Interleave comp_intlv,    /* The particular fashion in which components are interleaved.  Currently there
                                                  * are really only two: SAF_INTERLEAVE_VECTOR and SAF_INTERLEAVE_COMPONENT.
                                                  * These represent the XYZXYZ...XYZ and the XXX...XYYY...YZZZ...Z cases.  Note
                                                  * that interleave really only deals within a single blob of storage.  In the
                                                  * case of a composite field whose coefficients are stored independently on
                                                  * the component fields, interleave really has no meaning (use
                                                  * SAF_INTERLEAVE_INDEPENDENT).  Interleave only has meaning on fields with
                                                  * storage.  In the case of a scalar field interleave is also meaningless,
                                                  * both cases degenerate to the same layout: XXX...X (use
                                                  * SAF_INTERLEAVE_NONE). */
                   int *comp_order,              /* Only relevant for fields with component fields.  This value indicates the
                                                  * order of the fields in the COMP_FLDS relative to the registered
                                                  * order. Pass NULL if the permutation is the identity. */
                   void **bufs,                  /* The field data buffers. Pass NULL if you would rather provide this on the
                                                  * write call.  Note that the number and size of buffers (if any) is specified
                                                  * by the interleave and number of components.  If the field has vector
                                                  * interleave then there may only be 1 buffer, if the field has component
                                                  * interleave then there must be num_components buffers.  The number of
                                                  * components is defined in the field template specified by FTMPL. */
                   SAF_Field *fld                /* [OUT] The optional returned field handle. If NULL is passed here then this
                                                  * function allocates the field handle before returning it. */
                   )
 {
     SAF_ENTER(saf_declare_field, NULL);
     ss_scope_t          scope=SS_SCOPE_NULL;
     SAF_Algebraic       algebraic=SS_ALGEBRAIC_NULL;
     int                 i, count, nbufs, buf_size=0;

     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);

     SAF_REQUIRE(SS_SET(base_space), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("BASE_SPACE must be a valid set handle"));
     SAF_REQUIRE(name, SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("NAME must be non-null"));
     SAF_REQUIRE(SS_FIELDTMPL(ftmpl), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("FTMPL must be a valid field template"));
     SAF_REQUIRE(_saf_is_self_decomp(homog_decomp) || SS_CAT(homog_decomp), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("STORAGE_DECOMP must be either SELF_DECOMP or a valid cat handle"));
     SAF_REQUIRE(_saf_is_self_decomp(coeff_assoc) || SS_CAT(coeff_assoc), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("COEFF_ASSOC must be a valid cat handle"));
     SAF_REQUIRE(_saf_is_self_decomp(eval_cat) || SS_CAT(eval_cat), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("EVAL_CAT must be a valid cat handle"));
     SAF_REQUIRE(!unit || SS_UNIT(unit), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("UNIT must be a valid unit handle if supplied"));
     SAF_REQUIRE(_saf_is_valid_units(unit, ftmpl), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("UNIT must agree with quantity defined on field template"));
     SAF_REQUIRE(assoc_ratio >= 0, SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("ASSOC_RATIO must be non-negative"));
     SAF_REQUIRE(!eval_func || SS_EVALUATION(eval_func), SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("EVAL_FUNC must be a valid evaluation type handle if supplied"));
     SAF_REQUIRE(true, SAF_LOW_CHK_COST, NULL,
                 _saf_errmsg("units of component fields must match units of composite field"));

     /* Get the algebraic type for the SAF_ASSERT() below */
     algebraic = SS_FIELDTMPL(ftmpl)->algebraic;

     /* Error checking */
     SAF_ASSERT(data_type<=0 ||
                (SS_ALGEBRAIC(&algebraic)->indirect && H5Tequal(data_type,SAF_HANDLE)) ||
                SAF_XOR(_saf_is_self_decomp(homog_decomp), H5Tequal(data_type,SAF_HANDLE)),
                SAF_LOW_CHK_COST, NULL,
                _saf_errmsg("STORAGE_DECOMP=(SAF_SELF,!SAF_SELF) ==> DATA_TYPE=(!SAF_HANDLE,SAF_HANDLE) or "
                            "ALG_TYPE is SAF_ALGTYPE_FIELD"));
     SAF_ASSERT(_saf_is_self_decomp(homog_decomp) || SS_ALGEBRAIC(&algebraic)->indirect,
                SAF_LOW_CHK_COST, NULL,
                _saf_errmsg("algebraic type must be SAF_ALGTYPE_FIELD if field is inhomogeneous"));
     SAF_ASSERT((!(SS_ALGEBRAIC(&algebraic)->indirect) || !comp_flds), SAF_LOW_CHK_COST, NULL,
                _saf_errmsg("component fields cannot be supplied if algebraic type is SAF_ALGTYPE_FIELD"));
     SAF_ASSERT((SS_FIELDTMPL(ftmpl)->num_comps == 1 && comp_intlv == SAF_INTERLEAVE_NONE) ||
                (1 < SS_FIELDTMPL(ftmpl)->num_comps && (comp_intlv == SAF_INTERLEAVE_VECTOR ||
                                                         comp_intlv == SAF_INTERLEAVE_COMPONENT ||
                                                         comp_intlv == SAF_INTERLEAVE_INDEPENDENT)) ||
                SS_FIELDTMPL(ftmpl)->num_comps == SAF_NOT_APPLICABLE_INT,
                SAF_LOW_CHK_COST, NULL,
                _saf_errmsg("component interleave must be appropriate for number of component fields"));
     SAF_ASSERT(SS_ALGEBRAIC(&algebraic)->indirect ||
                (SS_FIELDTMPL(ftmpl)->num_comps==1 && !comp_flds) ||
                (SS_FIELDTMPL(ftmpl)->num_comps>1  &&  comp_flds),
                SAF_LOW_CHK_COST, NULL,
                _saf_errmsg("must supply component fields when there are 2 or more component expected"));
     SAF_ASSERT(comp_order==NULL || SS_FIELDTMPL(ftmpl)->num_comps>1,
                SAF_LOW_CHK_COST, NULL,
                _saf_errmsg("COMP_ORDER is relevent only when there is more than 1 component"));
     SAF_ASSERT(comp_order==SAF_IDENTITY || _saf_is_permutation(SS_FIELDTMPL(ftmpl)->num_comps,comp_order),
                SAF_LOW_CHK_COST, NULL,
                _saf_errmsg("if specified, COMP_ORDER must a valid permutation vector"));

     /* check buffer pointers */
     SAF_ASSERT_BEGIN(SAF_LOW_CHK_COST) {
         ok = TRUE;
         if (bufs && comp_intlv == SAF_INTERLEAVE_INDEPENDENT) {
             for (i=0; i<SS_FIELDTMPL(ftmpl)->num_comps && ok; i++) {
                 if (!bufs[i]) ok = FALSE;
             }
         }
     } SAF_ASSERT_END(NULL, _saf_errmsg("BUFS must point to NCOMPS valid (i.e., non-null) pointers"));

     /* Verify that comp_intlv==SAF_INTERLEAVE_VECTOR if the field is not a state field with more than one component on an
      * extendible base space. */
     SAF_ASSERT(!SS_SET(base_space)->is_extendible || SS_ALGEBRAIC(&algebraic)->indirect ||
                SS_FIELDTMPL(ftmpl)->num_comps==1 || comp_intlv==SAF_INTERLEAVE_VECTOR,
                SAF_LOW_CHK_COST, NULL,
                _saf_errmsg("only VECTOR interleaving is allowed for fields (not state fields) "
                            "with more than one component defined on extendible base spaces"));

     /* Create the new field object */
     ss_file_topscope(db, &scope);
     fld = (ss_field_t*)ss_pers_new(&scope, SS_MAGIC(ss_field_t), NULL, SAF_ALL==pmode?SS_ALLSAME:0U, (ss_pers_t*)fld, NULL);
     if (SAF_EACH==pmode) SS_PERS_UNIQUE(fld);

     /* if the eval collection category (eval_cat) is not SAF_SELF and non-primitive, then make sure eval_func is PWCONSTANT */
     /* This looks like a library limitation to me, so I'm coding it to look for an evaluation function whose name is
      * "piecewise constant". If this is some fundamental limitation of the model then we should really add some property to
      * the Evaluation table to describe this. --rpm 2001-04-26 */
     /* If we allow SAF_SPACE_PWCONST then we must certainly allow SAF_SPACE_CONSTANT.  I think we should remove
      * this restriction alltogether.  mjo 2002-04-03 */
     if (!_saf_is_self_decomp(eval_cat)) {
         ss_collection_t eval_coll;
         SAF_Eval *pwconst = SAF_SPACE_PWCONST;
         SAF_Eval *constant = SAF_SPACE_CONSTANT;

         if (NULL==_saf_getCollection_set(base_space, eval_cat, &eval_coll))
             SAF_ERROR(NULL, _saf_errmsg("unable to obtain collection for category\n"));
         SAF_ASSERT(SS_COLLECTION(&eval_coll)->cell_type!=SAF_CELLTYPE_SET ||
                    (SS_COLLECTION(&eval_coll)->cell_type==SAF_CELLTYPE_SET &&
                     (SAF_EQUIV(eval_func, pwconst) ||  SAF_EQUIV(eval_func, constant))),
                    SAF_LOW_CHK_COST, NULL,
                    _saf_errmsg("only SAF_SPACE_PWCONST is valid on non-primitive collections for a participating process"));
     }

     /*  If this is a multi-component (non-scalar) field, but NOT a field of fields (i.e., ALG_TYPE!=SAF_ALGTYPE_FIELD),
      *  then we must set-up the association from this field to the components and then deal with any ordering... */
     if (SS_FIELDTMPL(ftmpl)->num_comps>1 && !SS_ALGEBRAIC(&algebraic)->indirect) {
         /* Save the supplied field links */
         ss_array_resize(SS_FIELD_P(fld,comp_fields), (size_t)SS_FIELDTMPL_M(ftmpl,num_comps));
         ss_array_put(SS_FIELD_P(fld,comp_fields), ss_pers_tm, 0, SS_NOSIZE, comp_flds);

         /* Now if the caller supplied an ordering permutation vector the we'll save it. */
         if (comp_order) {
             ss_array_target(SS_FIELD_P(fld,comp_order), H5T_NATIVE_INT);
             ss_array_resize(SS_FIELD_P(fld,comp_order), (size_t)SS_FIELDTMPL_M(ftmpl,num_comps));
             ss_array_put(SS_FIELD_P(fld,comp_order), H5T_NATIVE_INT, 0, SS_NOSIZE, comp_order);
         }
     }

     /* Additional initialization of the new field object */
     ss_string_set(SS_FIELD_P(fld,name), name);
     SS_FIELD(fld)->base_space = *base_space;
     SS_FIELD(fld)->ftmpl = *ftmpl;
     if (unit) SS_FIELD(fld)->units = *unit;
     SS_FIELD(fld)->storage_decomp_cat = *homog_decomp;
     SS_FIELD(fld)->comp_intlv = comp_intlv;
     SS_FIELD(fld)->dof_assoc_cat = *coeff_assoc;
     SS_FIELD(fld)->assoc_ratio = assoc_ratio;
     SS_FIELD(fld)->eval_decomp_cat = *eval_cat;
     if (eval_func) SS_FIELD(fld)->evaluation = *eval_func;
     SS_FIELD(fld)->is_homogeneous = _saf_is_self_decomp(homog_decomp);

     /* Compute the number of and size of each buffer (if any).
      *
      * Note that the buffer size depends on the number of size of the collection category and the association ratio which gives
      * the number of coefficients.  Multiplying this by the number of components gives the number of "numbers" of the given
      * datatype (float, double, ... ) Fields with interleave NONE have no components (are scalar) and fields with interleave
      * INDEPENDENT often have components but often have no buffers since the storage is on the components, we'll treat this as
      * vector. */
     if (_saf_is_self_decomp(homog_decomp)) {
         /* if coeff_assoc is SAF_SELF, then we have only 1 member of the collection. That is the set itself.
             Otherwise, we need to get the collection to get its count */
         if (!_saf_is_self_decomp(coeff_assoc)) {
             ss_collection_t assoc_coll;
             _saf_getCollection_set(base_space, coeff_assoc, &assoc_coll);
             count = SS_COLLECTION(&assoc_coll)->count;
         } else {
             count = 1;
         }
         switch (comp_intlv) {
         case SAF_INTERLEAVE_NONE:
             nbufs    = 1;
             buf_size = count * assoc_ratio;
             break;
         case SAF_INTERLEAVE_VECTOR:
             nbufs    = 1;
             assert(SS_FIELDTMPL(ftmpl)->num_comps>=0);
             buf_size = count * assoc_ratio * SS_FIELDTMPL(ftmpl)->num_comps;
             break;
         case SAF_INTERLEAVE_COMPONENT:
             assert(SS_FIELDTMPL(ftmpl)->num_comps>=0);
             nbufs    = SS_FIELDTMPL(ftmpl)->num_comps;
             buf_size = count * assoc_ratio;
             break;
         case SAF_INTERLEAVE_INDEPENDENT:
             nbufs    = 1;
             buf_size = count * assoc_ratio;
             break;
         default:
             /* VBT_INTERLEAVE_ANY, VBT_INTERLEAVE_INVALID, VBT_INTERLEAVE_NA, VBT_INTERLEAVE_UNKNOWN are handled here: by doing
              * nothing. */
             nbufs = 1;
             buf_size = count * assoc_ratio;
             break;
         }
     } else {
         ss_collection_t storage_coll;
         _saf_getCollection_set(base_space, homog_decomp, &storage_coll);
         nbufs = 1;
         buf_size = SS_COLLECTION(&storage_coll)->count;
     }

     /* stick buf, buf size and type onto field handle */
     SS_FIELD(fld)->m.nbufs     = nbufs;
     SS_FIELD(fld)->m.bufs      = bufs;
     SS_FIELD(fld)->m.buf_size  = buf_size;
     SS_FIELD(fld)->m.data_type = data_type;

     SAF_LEAVE(fld);
 }