1 /*
2  * Copyright (c) 2005 Sandia Corporation. Under the terms of Contract
3  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Governement
4  * 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 Sandia Corporation 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"
37 #include "exodusII_int.h"
38 #include <string.h>
39 
40 /*!
41 
42 The function ex_put_prop() stores an integer object property value to
43 a single element block, node set, or side set. Although it is not
44 necessary to invoke ex_put_prop_names(), since ex_put_prop() will
45 allocate space within the data file if it hasn't been previously
46 allocated, it is more efficient to use ex_put_prop_names() if there is
47 more than one property to store. \see Efficiency for a discussion of
48 efficiency issues.
49 
50 It should be noted that the interpretation of the values of the
51 integers stored as properties is left to the application code. In
52 general, a zero (0) means the object does not have the specified
53 property (or is not in the specified group); a nonzero value means the
54 object does have the specified property. When space is allocated for
55 the properties using ex_put_prop_names() or ex_put_prop(), the
56 properties are initialized to zero (0).
57 
58 Because the ID of an element block, node set, or side set is just
59 another property (named \b ID), this routine can be used to change
60 the value of an ID. This feature must be used with caution, though,
61 because changing the ID of an object to the ID of another object of
62 the same type (element block, node set, or side set) would cause two
63 objects to have the same ID, and thus only the first would be
64 accessible. Therefore, ex_put_prop() issues a warning if a user
65 attempts to give two objects the same ID.
66 
67 \return In case of an error, ex_put_prop() returns a negative number;
68 a warning will return a positive number.  Possible causes of errors
69 include:
70   -  data file not properly opened with call to ex_create() or ex_open()
71   -  data file opened for read only.
72   -  data file not initialized properly with call to ex_put_init().
73   -  invalid object type specified.
74   -  a warning is issued if a user attempts to change the ID of an
75      object to the ID of an existing object of the same type.
76 
77 \param[in] exoid      exodus file ID returned from a previous call to ex_create() or ex_open().
78 \param[in] obj_type   Type of object; use one of the options in the table below.
79 \param[in] obj_id     The element block, node set, or side set ID.
80 \param[in]  prop_name The name of the property for which the value will be stored.
81                       Maximum length of this string is \p MAX_STR_LENGTH .
82 \param[in] value      The value of the property.
83 
84 <table>
85 <tr><td> \c EX_NODE_SET   </td><td>  Node Set entity type     </td></tr>
86 <tr><td> \c EX_EDGE_BLOCK </td><td>  Edge Block entity type   </td></tr>
87 <tr><td> \c EX_EDGE_SET   </td><td>  Edge Set entity type     </td></tr>
88 <tr><td> \c EX_FACE_BLOCK </td><td>  Face Block entity type   </td></tr>
89 <tr><td> \c EX_FACE_SET   </td><td>  Face Set entity type     </td></tr>
90 <tr><td> \c EX_ELEM_BLOCK </td><td>  Element Block entity type</td></tr>
91 <tr><td> \c EX_ELEM_SET   </td><td>  Element Set entity type  </td></tr>
92 <tr><td> \c EX_SIDE_SET   </td><td>  Side Set entity type     </td></tr>
93 <tr><td> \c EX_ELEM_MAP   </td><td>  Element Map entity type  </td></tr>
94 <tr><td> \c EX_NODE_MAP   </td><td>  Node Map entity type     </td></tr>
95 <tr><td> \c EX_EDGE_MAP   </td><td>  Edge Map entity type     </td></tr>
96 <tr><td> \c EX_FACE_MAP   </td><td>  Face Map entity type     </td></tr>
97 </table>
98 
99 For an example of code to write out an object property, refer to the
100 description for ex_put_prop_names().
101 */
102 
ex_put_prop(int exoid,ex_entity_type obj_type,int obj_id,const char * prop_name,int value)103 int ex_put_prop (int   exoid,
104                  ex_entity_type obj_type,
105                  int   obj_id,
106                  const char *prop_name,
107                  int   value)
108 {
109   int status;
110   int oldfill, temp;
111   int found = FALSE;
112   int num_props, i, dimid, propid, dims[1];
113   size_t start[1];
114   size_t prop_name_len, name_length;
115   int ldum;
116   char name[MAX_VAR_NAME_LENGTH+1];
117   char tmpstr[MAX_STR_LENGTH+1];
118   char dim_name[MAX_VAR_NAME_LENGTH+1];
119   int vals[1];
120 
121   char errmsg[MAX_ERR_LENGTH];
122 
123   exerrval  = 0; /* clear error code */
124 
125   /* check if property has already been created */
126 
127   num_props = ex_get_num_props(exoid, obj_type);
128 
129   if (num_props > 1) {  /* any properties other than the default 1? */
130 
131     for (i=1; i<=num_props; i++) {
132       switch (obj_type) {
133       case EX_ELEM_BLOCK:
134   strcpy (name, VAR_EB_PROP(i));
135   break;
136       case EX_EDGE_BLOCK:
137   strcpy (name, VAR_ED_PROP(i));
138   break;
139       case EX_FACE_BLOCK:
140   strcpy (name, VAR_FA_PROP(i));
141   break;
142       case EX_NODE_SET:
143   strcpy (name, VAR_NS_PROP(i));
144   break;
145       case EX_EDGE_SET:
146   strcpy (name, VAR_ES_PROP(i));
147   break;
148       case EX_FACE_SET:
149   strcpy (name, VAR_FS_PROP(i));
150   break;
151       case EX_ELEM_SET:
152   strcpy (name, VAR_ELS_PROP(i));
153   break;
154       case EX_SIDE_SET:
155   strcpy (name, VAR_SS_PROP(i));
156   break;
157       case EX_ELEM_MAP:
158   strcpy (name, VAR_EM_PROP(i));
159   break;
160       case EX_FACE_MAP:
161   strcpy (name, VAR_FAM_PROP(i));
162   break;
163       case EX_EDGE_MAP:
164   strcpy (name, VAR_EDM_PROP(i));
165   break;
166       case EX_NODE_MAP:
167   strcpy (name, VAR_NM_PROP(i));
168   break;
169       default:
170   exerrval = EX_BADPARAM;
171   sprintf(errmsg, "Error: object type %d not supported; file id %d",
172     obj_type, exoid);
173   ex_err("ex_put_prop",errmsg,exerrval);
174   return(EX_FATAL);
175       }
176 
177       if ((status = nc_inq_varid(exoid, name, &propid)) != NC_NOERR) {
178   exerrval = status;
179   sprintf(errmsg,
180     "Error: failed to get property array id in file id %d",
181     exoid);
182   ex_err("ex_put_prop",errmsg,exerrval);
183   return (EX_FATAL);
184       }
185 
186       /*   compare stored attribute name with passed property name   */
187       memset(tmpstr, 0, MAX_STR_LENGTH+1);
188       if ((status = nc_get_att_text(exoid, propid, ATT_PROP_NAME, tmpstr)) != NC_NOERR) {
189   exerrval = status;
190   sprintf(errmsg,
191     "Error: failed to get property name in file id %d", exoid);
192   ex_err("ex_put_prop",errmsg,exerrval);
193   return (EX_FATAL);
194       }
195 
196       if (strcmp(tmpstr, prop_name) == 0) {
197   found = TRUE;
198   break;
199       }
200     }
201   }
202 
203   /* if property array has not been created, create it */
204   if (!found) {
205 
206     name_length = ex_inquire_int(exoid, EX_INQ_DB_MAX_ALLOWED_NAME_LENGTH)+1;
207 
208     /* put netcdf file into define mode  */
209     if ((status = nc_redef (exoid)) != NC_NOERR) {
210       exerrval = status;
211       sprintf(errmsg,"Error: failed to place file id %d into define mode",exoid);
212       ex_err("ex_put_prop",errmsg,exerrval);
213       return (EX_FATAL);
214     }
215 
216     /*   create a variable with a name xx_prop#, where # is the new number   */
217     /*   of the property                                                     */
218 
219     switch (obj_type){
220     case EX_ELEM_BLOCK:
221       strcpy (name, VAR_EB_PROP(num_props+1));
222       strcpy (dim_name, DIM_NUM_EL_BLK);
223       break;
224     case EX_FACE_BLOCK:
225       strcpy (name, VAR_FA_PROP(num_props+1));
226       strcpy (dim_name, DIM_NUM_FA_BLK);
227       break;
228     case EX_EDGE_BLOCK:
229       strcpy (name, VAR_ED_PROP(num_props+1));
230       strcpy (dim_name, DIM_NUM_ED_BLK);
231       break;
232     case EX_NODE_SET:
233       strcpy (name, VAR_NS_PROP(num_props+1));
234       strcpy (dim_name, DIM_NUM_NS);
235       break;
236     case EX_EDGE_SET:
237       strcpy (name, VAR_ES_PROP(num_props+1));
238       strcpy (dim_name, DIM_NUM_ES);
239       break;
240     case EX_FACE_SET:
241       strcpy (name, VAR_FS_PROP(num_props+1));
242       strcpy (dim_name, DIM_NUM_FS);
243       break;
244     case EX_ELEM_SET:
245       strcpy (name, VAR_ELS_PROP(num_props+1));
246       strcpy (dim_name, DIM_NUM_ELS);
247       break;
248     case EX_SIDE_SET:
249       strcpy (name, VAR_SS_PROP(num_props+1));
250       strcpy (dim_name, DIM_NUM_SS);
251       break;
252     case EX_ELEM_MAP:
253       strcpy (name, VAR_EM_PROP(num_props+1));
254       strcpy (dim_name, DIM_NUM_EM);
255       break;
256     case EX_FACE_MAP:
257       strcpy (name, VAR_FAM_PROP(num_props+1));
258       strcpy (dim_name, DIM_NUM_FAM);
259       break;
260     case EX_EDGE_MAP:
261       strcpy (name, VAR_EDM_PROP(num_props+1));
262       strcpy (dim_name, DIM_NUM_EDM);
263       break;
264     case EX_NODE_MAP:
265       strcpy (name, VAR_NM_PROP(num_props+1));
266       strcpy (dim_name, DIM_NUM_NM);
267       break;
268     default:
269       exerrval = EX_BADPARAM;
270       sprintf(errmsg, "Error: object type %d not supported; file id %d",
271         obj_type, exoid);
272       ex_err("ex_put_prop",errmsg,exerrval);
273       goto error_ret;        /* Exit define mode and return */
274     }
275 
276     /*   inquire id of previously defined dimension (number of objects) */
277     if ((status = nc_inq_dimid(exoid, dim_name, &dimid)) != NC_NOERR) {
278       exerrval = status;
279       sprintf(errmsg,
280         "Error: failed to locate number of objects in file id %d",
281         exoid);
282       ex_err("ex_put_prop",errmsg, exerrval);
283       goto error_ret;  /* Exit define mode and return */
284     }
285 
286     dims[0] = dimid;
287     nc_set_fill(exoid, NC_FILL, &oldfill); /* fill with zeros per routine spec */
288 
289     if ((status = nc_def_var(exoid, name, NC_INT, 1, dims, &propid)) != NC_NOERR) {
290       exerrval = status;
291       sprintf(errmsg,
292         "Error: failed to create property array variable in file id %d",
293         exoid);
294       ex_err("ex_put_prop",errmsg,exerrval);
295       goto error_ret;  /* Exit define mode and return */
296     }
297 
298     vals[0] = 0; /* fill value */
299     /*   create attribute to cause variable to fill with zeros per routine spec */
300     if ((status = nc_put_att_int(exoid, propid, _FillValue, NC_INT, 1, vals)) != NC_NOERR) {
301       exerrval = status;
302       sprintf(errmsg,
303         "Error: failed to create property name fill attribute in file id %d",
304         exoid);
305       ex_err("ex_put_prop",errmsg,exerrval);
306       goto error_ret;  /* Exit define mode and return */
307     }
308 
309     /*   Check that the property name length is less than MAX_NAME_LENGTH */
310     prop_name_len = strlen(prop_name)+1;
311     if (prop_name_len > name_length) {
312       fprintf(stderr,
313         "Warning: The property name '%s' is too long.\n\tIt will be truncated from %d to %d characters\n",
314         prop_name, (int)prop_name_len-1, (int)name_length-1);
315       prop_name_len = name_length;
316     }
317 
318     /*   store property name as attribute of property array variable */
319     if ((status = nc_put_att_text(exoid, propid, ATT_PROP_NAME,
320           prop_name_len, (void*)prop_name)) != NC_NOERR) {
321       exerrval = status;
322       sprintf(errmsg,
323         "Error: failed to store property name %s in file id %d",
324         prop_name,exoid);
325       ex_err("ex_put_prop",errmsg,exerrval);
326       goto error_ret;  /* Exit define mode and return */
327     }
328 
329     ex_update_max_name_length(exoid, prop_name_len-1);
330 
331     /* leave define mode  */
332     if ((status = nc_enddef (exoid)) != NC_NOERR) {
333       exerrval = status;
334       sprintf(errmsg,
335         "Error: failed to leave define mode in file id %d",
336         exoid);
337       ex_err("ex_put_prop",errmsg,exerrval);
338       return (EX_FATAL);
339     }
340 
341     nc_set_fill(exoid, oldfill, &temp); /* default: nofill */
342   }
343 
344   /* find index into property array using obj_id; put value in property */
345   /* array at proper index; ex_id_lkup returns an index that is 1-based,*/
346   /* but netcdf expects 0-based arrays so subtract 1                    */
347 
348   /* special case: property name ID - check for duplicate ID assignment */
349   if (strcmp("ID",prop_name) == 0) {
350     start[0] = ex_id_lkup (exoid, obj_type, value);
351     if (exerrval != EX_LOOKUPFAIL)   /* found the id */
352       {
353   exerrval = EX_BADPARAM;
354   sprintf(errmsg,
355     "Warning: attempt to assign duplicate %s ID %d in file id %d",
356     ex_name_of_object(obj_type), value, exoid);
357   ex_err("ex_put_prop",errmsg,exerrval);
358   return (EX_WARN);
359       }
360   }
361 
362   start[0] = ex_id_lkup (exoid, obj_type, obj_id);
363   if (exerrval != 0) {
364     if (exerrval == EX_NULLENTITY) {
365       sprintf(errmsg,
366         "Warning: no properties allowed for NULL %s id %d in file id %d",
367         ex_name_of_object(obj_type), obj_id,exoid);
368       ex_err("ex_put_prop",errmsg,EX_MSG);
369       return (EX_WARN);
370     } else {
371       sprintf(errmsg,
372         "Error: failed to find value %d in %s property array in file id %d",
373         obj_id, ex_name_of_object(obj_type), exoid);
374       ex_err("ex_put_prop",errmsg,exerrval);
375       return (EX_FATAL);
376     }
377   }
378 
379   start[0] = start[0] - 1;
380 
381   ldum = (int)value;
382   if ((status = nc_put_var1_int(exoid, propid, start, &ldum)) != NC_NOERR) {
383     exerrval = status;
384     sprintf(errmsg,
385       "Error: failed to store property value in file id %d",
386       exoid);
387     ex_err("ex_put_prop",errmsg,exerrval);
388     return (EX_FATAL);
389   }
390 
391   return (EX_NOERR);
392 
393   /* Fatal error: exit definition mode and return */
394  error_ret:
395   nc_set_fill(exoid, oldfill, &temp); /* default: nofill */
396 
397   if (nc_enddef (exoid) != NC_NOERR) {    /* exit define mode */
398     sprintf(errmsg,
399       "Error: failed to complete definition for file id %d",
400       exoid);
401     ex_err("ex_put_prop",errmsg,exerrval);
402   }
403   return (EX_FATAL);
404 }
405