1 /*
2 * Copyright (c) 2005-2017 National Technology & Engineering Solutions
3 * of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with
4 * NTESS, the U.S. Government retains certain rights in this software.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * * Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * * Neither the name of NTESS nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
35
36 #include "exodusII.h" // for ex_err, etc
37 #include "exodusII_int.h" // for EX_FATAL, ex_id_lkup, etc
38 #include "vtk_netcdf.h" // for NC_NOERR, nc_set_fill, etc
39 #include <inttypes.h> // for PRId64
40 #include <stddef.h> // for size_t
41 #include <stdio.h>
42 #include <string.h> // for memset, strcmp, etc
43
44 /*!
45
46 The function ex_put_prop() stores an integer object property value to
47 a single element block, node set, or side set. Although it is not
48 necessary to invoke ex_put_prop_names(), since ex_put_prop() will
49 allocate space within the data file if it hasn't been previously
50 allocated, it is more efficient to use ex_put_prop_names() if there is
51 more than one property to store. \see Efficiency for a discussion of
52 efficiency issues.
53
54 It should be noted that the interpretation of the values of the
55 integers stored as properties is left to the application code. In
56 general, a zero (0) means the object does not have the specified
57 property (or is not in the specified group); a nonzero value means the
58 object does have the specified property. When space is allocated for
59 the properties using ex_put_prop_names() or ex_put_prop(), the
60 properties are initialized to zero (0).
61
62 Because the ID of an element block, node set, or side set is just
63 another property (named \b ID), this routine can be used to change
64 the value of an ID. This feature must be used with caution, though,
65 because changing the ID of an object to the ID of another object of
66 the same type (element block, node set, or side set) would cause two
67 objects to have the same ID, and thus only the first would be
68 accessible. Therefore, ex_put_prop() issues a warning if a user
69 attempts to give two objects the same ID.
70
71 \return In case of an error, ex_put_prop() returns a negative number;
72 a warning will return a positive number. Possible causes of errors
73 include:
74 - data file not properly opened with call to ex_create() or ex_open()
75 - data file opened for read only.
76 - data file not initialized properly with call to ex_put_init().
77 - invalid object type specified.
78 - a warning is issued if a user attempts to change the ID of an
79 object to the ID of an existing object of the same type.
80
81 \param[in] exoid exodus file ID returned from a previous call to
82 ex_create() or ex_open().
83 \param[in] obj_type Type of object; use one of the options in the table below.
84 \param[in] obj_id The element block, node set, or side set ID.
85 \param[in] prop_name The name of the property for which the value will be
86 stored.
87 Maximum length of this string is \p MAX_STR_LENGTH .
88 \param[in] value The value of the property.
89
90 | ex_entity_type | description |
91 | -------------- | ------------------------- |
92 | EX_NODE_SET | Node Set entity type |
93 | EX_EDGE_BLOCK | Edge Block entity type |
94 | EX_EDGE_SET | Edge Set entity type |
95 | EX_FACE_BLOCK | Face Block entity type |
96 | EX_FACE_SET | Face Set entity type |
97 | EX_ELEM_BLOCK | Element Block entity type|
98 | EX_ELEM_SET | Element Set entity type |
99 | EX_SIDE_SET | Side Set entity type |
100 | EX_ELEM_MAP | Element Map entity type |
101 | EX_NODE_MAP | Node Map entity type |
102 | EX_EDGE_MAP | Edge Map entity type |
103 | EX_FACE_MAP | Face Map entity type |
104
105 For an example of code to write out an object property, refer to the
106 description for ex_put_prop_names().
107 */
108
ex_put_prop(int exoid,ex_entity_type obj_type,ex_entity_id obj_id,const char * prop_name,ex_entity_id value)109 int ex_put_prop(int exoid, ex_entity_type obj_type, ex_entity_id obj_id, const char *prop_name,
110 ex_entity_id value)
111 {
112 int status;
113 int oldfill = 0;
114 int temp;
115 int found = EX_FALSE;
116 int num_props, i, dimid, propid, dims[1];
117 int int_type;
118 size_t start[1];
119 size_t prop_name_len, name_length;
120 char * name;
121 char tmpstr[MAX_STR_LENGTH + 1];
122 char * dim_name;
123 long long vals[1];
124
125 char errmsg[MAX_ERR_LENGTH];
126
127 EX_FUNC_ENTER();
128 ex_check_valid_file_id(exoid, __func__);
129
130 /* check if property has already been created */
131
132 num_props = ex_get_num_props(exoid, obj_type);
133
134 if (num_props > 1) { /* any properties other than the default 1? */
135
136 for (i = 1; i <= num_props; i++) {
137 switch (obj_type) {
138 case EX_ELEM_BLOCK: name = VAR_EB_PROP(i); break;
139 case EX_EDGE_BLOCK: name = VAR_ED_PROP(i); break;
140 case EX_FACE_BLOCK: name = VAR_FA_PROP(i); break;
141 case EX_NODE_SET: name = VAR_NS_PROP(i); break;
142 case EX_EDGE_SET: name = VAR_ES_PROP(i); break;
143 case EX_FACE_SET: name = VAR_FS_PROP(i); break;
144 case EX_ELEM_SET: name = VAR_ELS_PROP(i); break;
145 case EX_SIDE_SET: name = VAR_SS_PROP(i); break;
146 case EX_ELEM_MAP: name = VAR_EM_PROP(i); break;
147 case EX_FACE_MAP: name = VAR_FAM_PROP(i); break;
148 case EX_EDGE_MAP: name = VAR_EDM_PROP(i); break;
149 case EX_NODE_MAP: name = VAR_NM_PROP(i); break;
150 default:
151 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: object type %d not supported; file id %d",
152 obj_type, exoid);
153 ex_err(__func__, errmsg, EX_BADPARAM);
154 EX_FUNC_LEAVE(EX_FATAL);
155 }
156
157 if ((status = nc_inq_varid(exoid, name, &propid)) != NC_NOERR) {
158 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get property array id in file id %d",
159 exoid);
160 ex_err(__func__, errmsg, status);
161 EX_FUNC_LEAVE(EX_FATAL);
162 }
163
164 /* compare stored attribute name with passed property name */
165 memset(tmpstr, 0, MAX_STR_LENGTH + 1);
166 if ((status = nc_get_att_text(exoid, propid, ATT_PROP_NAME, tmpstr)) != NC_NOERR) {
167 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get property name in file id %d", exoid);
168 ex_err(__func__, errmsg, status);
169 EX_FUNC_LEAVE(EX_FATAL);
170 }
171
172 if (strcmp(tmpstr, prop_name) == 0) {
173 found = EX_TRUE;
174 break;
175 }
176 }
177 }
178
179 /* if property array has not been created, create it */
180 if (!found) {
181
182 name_length = ex_inquire_int(exoid, EX_INQ_DB_MAX_ALLOWED_NAME_LENGTH) + 1;
183
184 /* put netcdf file into define mode */
185 if ((status = nc_redef(exoid)) != NC_NOERR) {
186 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to place file id %d into define mode", exoid);
187 ex_err(__func__, errmsg, status);
188 EX_FUNC_LEAVE(EX_FATAL);
189 }
190
191 /* create a variable with a name xx_prop#, where # is the new number */
192 /* of the property */
193
194 switch (obj_type) {
195 case EX_ELEM_BLOCK:
196 name = VAR_EB_PROP(num_props + 1);
197 dim_name = DIM_NUM_EL_BLK;
198 break;
199 case EX_FACE_BLOCK:
200 name = VAR_FA_PROP(num_props + 1);
201 dim_name = DIM_NUM_FA_BLK;
202 break;
203 case EX_EDGE_BLOCK:
204 name = VAR_ED_PROP(num_props + 1);
205 dim_name = DIM_NUM_ED_BLK;
206 break;
207 case EX_NODE_SET:
208 name = VAR_NS_PROP(num_props + 1);
209 dim_name = DIM_NUM_NS;
210 break;
211 case EX_EDGE_SET:
212 name = VAR_ES_PROP(num_props + 1);
213 dim_name = DIM_NUM_ES;
214 break;
215 case EX_FACE_SET:
216 name = VAR_FS_PROP(num_props + 1);
217 dim_name = DIM_NUM_FS;
218 break;
219 case EX_ELEM_SET:
220 name = VAR_ELS_PROP(num_props + 1);
221 dim_name = DIM_NUM_ELS;
222 break;
223 case EX_SIDE_SET:
224 name = VAR_SS_PROP(num_props + 1);
225 dim_name = DIM_NUM_SS;
226 break;
227 case EX_ELEM_MAP:
228 name = VAR_EM_PROP(num_props + 1);
229 dim_name = DIM_NUM_EM;
230 break;
231 case EX_FACE_MAP:
232 name = VAR_FAM_PROP(num_props + 1);
233 dim_name = DIM_NUM_FAM;
234 break;
235 case EX_EDGE_MAP:
236 name = VAR_EDM_PROP(num_props + 1);
237 dim_name = DIM_NUM_EDM;
238 break;
239 case EX_NODE_MAP:
240 name = VAR_NM_PROP(num_props + 1);
241 dim_name = DIM_NUM_NM;
242 break;
243 default:
244 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: object type %d not supported; file id %d", obj_type,
245 exoid);
246 ex_err(__func__, errmsg, EX_BADPARAM);
247 goto error_ret; /* Exit define mode and return */
248 }
249
250 /* inquire id of previously defined dimension (number of objects) */
251 if ((status = nc_inq_dimid(exoid, dim_name, &dimid)) != NC_NOERR) {
252 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to locate number of objects in file id %d",
253 exoid);
254 ex_err(__func__, errmsg, status);
255 goto error_ret; /* Exit define mode and return */
256 }
257
258 dims[0] = dimid;
259 nc_set_fill(exoid, NC_FILL, &oldfill); /* fill with zeros per routine spec */
260
261 int_type = NC_INT;
262 if (ex_int64_status(exoid) & EX_IDS_INT64_DB) {
263 int_type = NC_INT64;
264 }
265
266 if ((status = nc_def_var(exoid, name, int_type, 1, dims, &propid)) != NC_NOERR) {
267 snprintf(errmsg, MAX_ERR_LENGTH,
268 "ERROR: failed to create property array variable in file id %d", exoid);
269 ex_err(__func__, errmsg, status);
270 goto error_ret; /* Exit define mode and return */
271 }
272
273 vals[0] = 0; /* fill value */
274 /* create attribute to cause variable to fill with zeros per routine spec
275 */
276 if ((status = nc_put_att_longlong(exoid, propid, _FillValue, int_type, 1, vals)) != NC_NOERR) {
277 snprintf(errmsg, MAX_ERR_LENGTH,
278 "ERROR: failed to create property name fill attribute in file id %d", exoid);
279 ex_err(__func__, errmsg, status);
280 goto error_ret; /* Exit define mode and return */
281 }
282
283 /* Check that the property name length is less than MAX_NAME_LENGTH */
284 prop_name_len = strlen(prop_name) + 1;
285 if (prop_name_len > name_length) {
286 fprintf(stderr,
287 "Warning: The property name '%s' is too long.\n\tIt will "
288 "be truncated from %d to %d characters\n",
289 prop_name, (int)prop_name_len - 1, (int)name_length - 1);
290 prop_name_len = name_length;
291 }
292
293 /* store property name as attribute of property array variable */
294 if ((status = nc_put_att_text(exoid, propid, ATT_PROP_NAME, prop_name_len,
295 (void *)prop_name)) != NC_NOERR) {
296 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to store property name %s in file id %d",
297 prop_name, exoid);
298 ex_err(__func__, errmsg, status);
299 goto error_ret; /* Exit define mode and return */
300 }
301
302 ex_update_max_name_length(exoid, prop_name_len - 1);
303
304 /* leave define mode */
305 if ((status = nc_enddef(exoid)) != NC_NOERR) {
306 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to leave define mode in file id %d", exoid);
307 ex_err(__func__, errmsg, status);
308 EX_FUNC_LEAVE(EX_FATAL);
309 }
310
311 nc_set_fill(exoid, oldfill, &temp); /* default: nofill */
312 }
313
314 /* find index into property array using obj_id; put value in property */
315 /* array at proper index; ex_id_lkup returns an index that is 1-based,*/
316 /* but netcdf expects 0-based arrays so subtract 1 */
317
318 /* special case: property name ID - check for duplicate ID assignment */
319 if (strcmp("ID", prop_name) == 0) {
320 int indx = ex_id_lkup(exoid, obj_type, value);
321 if (indx != -EX_LOOKUPFAIL) { /* found the id */
322 snprintf(errmsg, MAX_ERR_LENGTH,
323 "Warning: attempt to assign duplicate %s ID %" PRId64 " in file id %d",
324 ex_name_of_object(obj_type), value, exoid);
325 ex_err(__func__, errmsg, EX_DUPLICATEID);
326 EX_FUNC_LEAVE(EX_WARN);
327 }
328 }
329
330 status = ex_id_lkup(exoid, obj_type, obj_id);
331 if (status > 0) {
332 start[0] = status - 1;
333 }
334 else {
335 ex_get_err(NULL, NULL, &status);
336
337 if (status != 0) {
338 if (status == EX_NULLENTITY) {
339 snprintf(errmsg, MAX_ERR_LENGTH,
340 "Warning: no properties allowed for NULL %s id %" PRId64 " in file id %d",
341 ex_name_of_object(obj_type), obj_id, exoid);
342 ex_err(__func__, errmsg, EX_NULLENTITY);
343 EX_FUNC_LEAVE(EX_WARN);
344 }
345 snprintf(errmsg, MAX_ERR_LENGTH,
346 "ERROR: failed to find value %" PRId64 " in %s property array in file id %d", obj_id,
347 ex_name_of_object(obj_type), exoid);
348 ex_err(__func__, errmsg, status);
349 EX_FUNC_LEAVE(EX_FATAL);
350 }
351 }
352
353 /* value is of type 'ex_entity_id' which is a typedef to int64_t or long long
354 */
355 status = nc_put_var1_longlong(exoid, propid, start, (long long *)&value);
356
357 if (status != NC_NOERR) {
358 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to store property value in file id %d", exoid);
359 ex_err(__func__, errmsg, status);
360 EX_FUNC_LEAVE(EX_FATAL);
361 }
362
363 EX_FUNC_LEAVE(EX_NOERR);
364
365 /* Fatal error: exit definition mode and return */
366 error_ret:
367 nc_set_fill(exoid, oldfill, &temp); /* default: nofill */
368
369 if ((status = nc_enddef(exoid)) != NC_NOERR) { /* exit define mode */
370 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to complete definition for file id %d", exoid);
371 ex_err(__func__, errmsg, status);
372 }
373 EX_FUNC_LEAVE(EX_FATAL);
374 }
375