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
 int

 saf_get_count_and_type_for_field(SAF_ParMode pmode,     /* The parallel mode. */
                                  SAF_Field *field,      /* The field handle. */
                                  SAF_FieldTarget *target, /* Optional field targeting information. */
                                  size_t *Pcount,        /* [OUT] The number of items that would be placed in the buffer by a
                                                          * call to the saf_read_field() function.  The caller may pass a value
                                                          * of NULL for this parameter if this value is not desired. */
                                  hid_t *Ptype           /* [OUT] The type of the items that would be placed in the buffer by a
                                                          * call to the saf_read_field() function.  The caller may pass a value
                                                          * of NULL for this parameter if this value is not desired. The
                                                          * returned HDF5 datatype can be closed by the caller when no longer
                                                          * needed. */
                                  )
 {
     SAF_ENTER(saf_get_count_and_type_for_field, SAF_PRECONDITION_ERROR);
     ss_scope_t          scope=SS_SCOPE_NULL;            /* Scope containing FIELD */
     ss_fieldtmpl_t      ftmpl=SS_FIELDTMPL_NULL;        /* Field template for FIELD */
     ss_set_t            basespace=SS_SET_NULL;          /* Base space of FIELD */
     ss_cat_t            dof_assoc_cat=SS_CAT_NULL;      /* Cached from FIELD */
     int                 scope_size;                     /* Size of the communicator for `scope' */
     hsize_t             count;                          /* Needed because PCOUNT is not the right type */
     hid_t               ftype;                          /* File datatype */
     hbool_t             desireHandles;                  /* Should we read field links or the pointed-to-field's dofs? */
     ss_field_t          *ifields=NULL;                  /* Indirect fields */
     size_t              icount=0;                       /* Number of indirect fields */
     ss_field_t          *comps=NULL;                    /* Component fields */
     int                 num_comps;                      /* Number of component fields */
     static SAF_FieldTarget ft_zero;                     /* Default field targeting */
     int                 numberOfComponents;
     int                 collSize;

     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*)field, &scope);
     ss_scope_comm(&scope, NULL, NULL, &scope_size);
     if (!target) target = &ft_zero;

     SAF_REQUIRE(SS_FIELD(field), SAF_LOW_CHK_COST, SAF_PRECONDITION_ERROR,
                 _saf_errmsg("FIELD must be a valid field handle"));
     SAF_REQUIRE(SS_PERS_ISNULL(&target->decomp) || pmode==SAF_ALL || 1==scope_size, 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"));

     if (Pcount)
         *Pcount = 1234567;

     /* Cache some stuff for convenience */
     ftmpl = SS_FIELD(field)->ftmpl;
     dof_assoc_cat = SS_FIELD(field)->dof_assoc_cat;
     basespace = SS_FIELD(field)->base_space;

     /* When a field is stored on "self" then we store actual field coefficient values.  When a field is not stored on "self"
      * then DOFs are stored on the subsets specified by the decomposition.  In this case the field values of this "parent"
      * field are the handles to the "actual" fields found on each of the subsets. Dofs are stored in the dof_blob while field
      * handles are stored in a variable length array. */
     if (!SS_PERS_ISNULL(SS_FIELD_P(field,dof_blob))) {
         /*  In this case the field appears to be stored on self so the stored values are real field DOF values. */
         SAF_ASSERT(_saf_is_self_decomp(SS_FIELD_P(field,storage_decomp_cat)), SAF_LOW_CHK_COST, SAF_ASSERTION_ERROR,
                    _saf_errmsg("if a dof_blob exists then the field must not be storing pointers to other fields"));
         ss_blob_bound_f1(SS_FIELD_P(field,dof_blob), NULL, NULL, &count, &ftype);
         if (Ptype) *Ptype = H5Tget_native_type(target->data_type>0?target->data_type:ftype, H5T_DIR_DEFAULT);
         H5Tclose(ftype); ftype=-1;
         if (Pcount) *Pcount = count;
     } else if (ss_array_nelmts(SS_FIELD_P(field,indirect_fields))>0) {
         /* In this case the field is stored on a decomposition.  The stored values are handles to the fields on the parts *
          * forming the decomposition.  The datatype is known to be handles (to fields) and the VL-array tells how
          * many. However the caller may have used the saf_target_field() function to request the field to be remapped. */
         if (SS_PERS_ISNULL(&target->decomp)) {
             desireHandles = TRUE;
         } else if (_saf_is_self_decomp(&target->decomp)) {
             desireHandles = FALSE;
         } else {
             desireHandles = TRUE;
         }
         if (desireHandles) {
             /* The caller has not requested the field to be remapped, thus we can assume that the caller desires handles... */
             if (Pcount) *Pcount = ss_array_nelmts(SS_FIELD_P(field,indirect_fields));
             if (Ptype) *Ptype = H5Tcopy(ss_pers_tm); /*target datatype is ignored in this case*/
         } else {
             /* The caller has requested the field to be remapped, we must track down the proper count by examining the
              * collection that the field is defined on (rather than the one that it is decomposed on) and the proper type
              * by following the indirection. */
             if (Pcount) {
                 /* First we'll figure out how many DOFs the remapped field has. We'll use the category that field is defined on
                  * and the basespace to identify the collection that the field DOFS are associated with. Note that the
                  * basespace is actually kept with the field template. If the number of components is negative then the
                  * component count must be gotten by recursing on the indirect fields until a valid component count is
                  * encountered. */
                 numberOfComponents = SS_FIELDTMPL(&ftmpl)->num_comps;
                 if (numberOfComponents <= 0)
                     _saf_numberOfComponentsOf_field(pmode, field, &numberOfComponents);
                 saf_describe_collection(pmode, &basespace, &dof_assoc_cat, NULL, &collSize, NULL, NULL, NULL);
                 *Pcount = collSize * SS_FIELD(field)->assoc_ratio * numberOfComponents;
             }
             if (Ptype) {
                 if (target->data_type<=0) {
                     /*  Then we'll get the indirect handles using a recursive call with no field targeting. */
                     saf_get_count_and_type_for_field(pmode, field, NULL, &icount, NULL);
                     if (!icount)
                         SAF_ERROR(SAF_FILE_ERROR, _saf_errmsg("no indirect field handles"));
                     if (NULL==(ifields=malloc(icount*sizeof(*ifields))))
                         SAF_ERROR(SAF_MEMORY_ERROR, _saf_errmsg("unable to allocate buffer to recieve indirect fields"));
                     saf_read_field(pmode, field, NULL, SAF_WHOLE_FIELD, (void**)&ifields);

                     /* We'll now get the type of the first field on the decomposition to determine the type to return.  Note
                      * that we are not requiring the data types of the fields to match since saf_read_field will do the
                      * appropriate data type conversions. Use the same targeting as for FIELD. */
                     saf_get_count_and_type_for_field(pmode, ifields, target, NULL, Ptype);
                     ifields = SS_FREE(ifields);
                 } else {
                     *Ptype  = H5Tget_native_type(target->data_type, H5T_DIR_DEFAULT);
                 }
             }
         }
     } else {
         /* In this case the field is a component of another field or is made up of components.  The datatype and count are
          * unknown.  However the caller may have used the saf_target_field() function to request the field to be remapped. */
         if (SS_PERS_ISNULL(&target->decomp)) {
             desireHandles = TRUE;
         } else if (_saf_is_self_decomp(&target->decomp)) {
             desireHandles = FALSE;
         } else {
             desireHandles = TRUE;
         }
         if (desireHandles) {
             if (Pcount) *Pcount = 0;
             if (Ptype) *Ptype = H5I_INVALID_HID;
         } else {
             /* Lets find out if the field is made up of components.  If it is then get the size and count of the first
              * component, otherwise punt since it is a component of another field. */
             saf_describe_field(pmode, field, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &num_comps,
                                &comps, NULL, NULL);
             if (0 < num_comps) {
                 /* In this case the field is made up of components.  We can use the count and type of the first component. */
                 saf_get_count_and_type_for_field(pmode, comps+0, NULL, Pcount, Ptype);
                 if (Pcount) *Pcount *= num_comps;
                 comps = SS_FREE(comps);
             } else {
                 /* In this case the field is a component of another field and has no storage of its own.  It really should have
                  * a blob record which provides the offset/skip info for traversing the blob of the parent field but that is
                  * not currently the case... */
                 if (Pcount) *Pcount = 0;
                 if (Ptype) *Ptype  = H5I_INVALID_HID;
             }
         }
     }

     assert(!Pcount || *Pcount!=1234567);
     SAF_LEAVE(SAF_SUCCESS);
 }