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  *
37  * expvtt - ex_put_truth_table
38  *
39  * entry conditions -
40  *   input parameters:
41  *       int     exoid              exodus file id
42  *       int     obj_type           object type
43  *       int     num_blk            number of blocks
44  *       int     num_var            number of variables
45  *       int*    variable_table            variable truth table array
46  *
47  * exit conditions -
48  *
49  * revision history -
50  *
51  *
52  *****************************************************************************/
53 
54 #include "exodusII.h"     // for ex_err, etc
55 #include "exodusII_int.h" // for ex_get_dimension, EX_FATAL, etc
56 #include "vtk_netcdf.h"       // for nc_inq_varid, NC_NOERR, etc
57 #include <stddef.h>       // for size_t
58 #include <stdio.h>
59 #include <stdlib.h> // for free, NULL, malloc
60 
61 /*!
62 \ingroup ResultsData
63 
64  * writes the EXODUS variable truth table to the database; also,
65  * creates netCDF variables in which to store EXODUS variable
66  * values; although this table isn't required (because the netCDF
67  * variables can also be created in ex_put_var()), this call will save
68  * tremendous time because all of the variables are defined at once
69  * while the file is in define mode, rather than going in and out of
70  * define mode (causing the entire file to be copied over and over)
71  * which is what occurs when the variables are defined in ex_put_var()
72  * \param       exoid              exodus file id
73  * \param       obj_type           object type
74  * \param       num_blk            number of blocks or sets
75  * \param       num_var            number of variables
76  * \param      *var_tab            variable truth table array
77  *
78 The following coding will create, populate, and write an element
79 variable truth table to an opened exodus file (NOTE: all element
80 variables are valid for all element blocks in this example.):
81 
82 ~~~{.c}
83 int *truth_tab, num_elem_blk, num_ele_vars, error, exoid;
84 
85 \comment{write element variable truth table}
86 truth_tab = (int *)calloc((num_elem_blk*num_ele_vars), sizeof(int));
87 
88 for (i=0, k=0; i < num_elem_blk; i++) {
89    for (j=0; j < num_ele_vars; j++) {
90       truth_tab[k++] = 1;
91    }
92 }
93 error = ex_put_truth_table(exoid, EX_ELEM_BLOCK, num_elem_blk, num_ele_vars,
94                             truth_tab);
95 ~~~
96  */
97 
ex_put_truth_table(int exoid,ex_entity_type obj_type,int num_blk,int num_var,int * var_tab)98 int ex_put_truth_table(int exoid, ex_entity_type obj_type, int num_blk, int num_var, int *var_tab)
99 {
100   int    numelblkdim, numelvardim, timedim, dims[2], varid;
101   char * sta_type, *tab_type;
102   size_t num_entity = 0;
103   size_t num_var_db = 0;
104   int *  stat_vals;
105   int    i, j, k;
106   int    status;
107   char   errmsg[MAX_ERR_LENGTH];
108 
109   /*
110    * The ent_type and the var_name are used to build the netcdf
111    * variables name.  Normally this is done via a macro defined in
112    * exodusII_int.h
113    */
114   const char *ent_type = NULL;
115   const char *var_name = NULL;
116   const char *ent_size = NULL;
117 
118   EX_FUNC_ENTER();
119 
120   ex_check_valid_file_id(exoid, __func__);
121 
122   ex_get_dimension(exoid, ex_dim_num_objects(obj_type), ex_name_of_object(obj_type), &num_entity,
123                    &numelblkdim, __func__);
124 
125   if (obj_type == EX_ELEM_BLOCK) {
126     ex_get_dimension(exoid, DIM_NUM_ELE_VAR, "element variables", &num_var_db, &numelvardim,
127                      __func__);
128     var_name = "vals_elem_var";
129     ent_type = "eb";
130     ent_size = "num_el_in_blk";
131     sta_type = VAR_STAT_EL_BLK;
132     tab_type = VAR_ELEM_TAB;
133   }
134   else if (obj_type == EX_EDGE_BLOCK) {
135     ex_get_dimension(exoid, DIM_NUM_EDG_VAR, "edge block variables", &num_var_db, &numelvardim,
136                      __func__);
137     var_name = "vals_edge_var";
138     ent_type = "eb";
139     ent_size = "num_ed_in_blk";
140     sta_type = VAR_STAT_ED_BLK;
141     tab_type = VAR_EBLK_TAB;
142   }
143   else if (obj_type == EX_FACE_BLOCK) {
144     ex_get_dimension(exoid, DIM_NUM_FAC_VAR, "face block variables", &num_var_db, &numelvardim,
145                      __func__);
146     var_name = "vals_face_var";
147     ent_type = "fb";
148     ent_size = "num_fa_in_blk";
149     sta_type = VAR_STAT_FA_BLK;
150     tab_type = VAR_FBLK_TAB;
151   }
152   else if (obj_type == EX_SIDE_SET) {
153     ex_get_dimension(exoid, DIM_NUM_SSET_VAR, "sideset variables", &num_var_db, &numelvardim,
154                      __func__);
155     var_name = "vals_sset_var";
156     ent_type = "ss";
157     ent_size = "num_side_ss";
158     sta_type = VAR_SS_STAT;
159     tab_type = VAR_SSET_TAB;
160   }
161   else if (obj_type == EX_NODE_SET) {
162     ex_get_dimension(exoid, DIM_NUM_NSET_VAR, "nodeset variables", &num_var_db, &numelvardim,
163                      __func__);
164     var_name = "vals_nset_var";
165     ent_type = "ns";
166     ent_size = "num_nod_ns";
167     sta_type = VAR_NS_STAT;
168     tab_type = VAR_NSET_TAB;
169   }
170   else if (obj_type == EX_EDGE_SET) {
171     ex_get_dimension(exoid, DIM_NUM_ESET_VAR, "edge set variables", &num_var_db, &numelvardim,
172                      __func__);
173     var_name = "vals_eset_var";
174     ent_type = "es";
175     ent_size = "num_edge_es";
176     sta_type = VAR_ES_STAT;
177     tab_type = VAR_ESET_TAB;
178   }
179   else if (obj_type == EX_FACE_SET) {
180     ex_get_dimension(exoid, DIM_NUM_FSET_VAR, "face set variables", &num_var_db, &numelvardim,
181                      __func__);
182     var_name = "vals_fset_var";
183     ent_type = "fs";
184     ent_size = "num_face_fs";
185     sta_type = VAR_FS_STAT;
186     tab_type = VAR_FSET_TAB;
187   }
188   else if (obj_type == EX_ELEM_SET) {
189     ex_get_dimension(exoid, DIM_NUM_ELSET_VAR, "element set variables", &num_var_db, &numelvardim,
190                      __func__);
191     var_name = "vals_elset_var";
192     ent_type = "es";
193     ent_size = "num_ele_els";
194     sta_type = VAR_ELS_STAT;
195     tab_type = VAR_ELSET_TAB;
196   }
197 
198   else { /* invalid variable type */
199     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: Invalid variable type %d specified in file id %d",
200              obj_type, exoid);
201     ex_err(__func__, errmsg, EX_BADPARAM);
202     EX_FUNC_LEAVE(EX_WARN);
203   }
204 
205   if ((int)num_entity != num_blk) {
206     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: # of %s doesn't match those defined in file id %d",
207              ex_name_of_object(obj_type), exoid);
208     ex_err(__func__, errmsg, EX_BADPARAM);
209     EX_FUNC_LEAVE(EX_FATAL);
210   }
211 
212   if ((int)num_var_db != num_var) {
213     snprintf(errmsg, MAX_ERR_LENGTH,
214              "ERROR: # of %s variables doesn't match those defined in file id %d",
215              ex_name_of_object(obj_type), exoid);
216     ex_err(__func__, errmsg, EX_BADPARAM);
217     EX_FUNC_LEAVE(EX_FATAL);
218   }
219 
220   /* Get status array for later use */
221   if (!(stat_vals = malloc(num_blk * sizeof(int)))) {
222     snprintf(errmsg, MAX_ERR_LENGTH,
223              "ERROR: failed to allocate memory for %s status array for file id %d",
224              ex_name_of_object(obj_type), exoid);
225     ex_err(__func__, errmsg, EX_MEMFAIL);
226     EX_FUNC_LEAVE(EX_FATAL);
227   }
228 
229   status = nc_inq_varid(exoid, sta_type, &varid);
230 
231   /* get variable id of status array */
232   if (status == NC_NOERR) {
233     /* if status array exists (V 2.01+), use it, otherwise assume
234        object exists to be backward compatible */
235 
236     if ((status = nc_get_var_int(exoid, varid, stat_vals)) != NC_NOERR) {
237       free(stat_vals);
238       snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get %s status array from file id %d",
239                ex_name_of_object(obj_type), exoid);
240       ex_err(__func__, errmsg, status);
241       EX_FUNC_LEAVE(EX_FATAL);
242     }
243   }
244   else {
245     /* status array doesn't exist (V2.00), dummy one up for later checking */
246     for (i = 0; i < num_blk; i++) {
247       stat_vals[i] = 1;
248     }
249   }
250 
251   /* put netcdf file into define mode  */
252   if ((status = nc_redef(exoid)) != NC_NOERR) {
253     free(stat_vals);
254     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to put file id %d into define mode", exoid);
255     ex_err(__func__, errmsg, status);
256     EX_FUNC_LEAVE(EX_FATAL);
257   }
258 
259   /* inquire previously defined dimensions */
260   if ((status = nc_inq_dimid(exoid, DIM_TIME, &timedim)) != NC_NOERR) {
261     free(stat_vals);
262     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to locate time variable in file id %d", exoid);
263     ex_err(__func__, errmsg, status);
264     goto error_ret; /* exit define mode and return */
265   }
266 
267   /* define netCDF variables in which to store EXODUS element
268    * variable values
269    */
270 
271   k = 0;
272   for (i = 0; i < num_blk; i++) {
273     for (j = 1; j <= num_var; j++) {
274 
275       /* check if variables are to be put out for this entity */
276       if (var_tab[k] != 0) {
277         if (stat_vals[i] != 0) { /* check for NULL entity */
278           /* NOTE: This code used to zero out the var_tab entry
279              if the stat_vals[i] value was zero. However, in some
280              cases it is good to know that a variable was assigned to
281              an entity even if that entity is empty. The code was
282              changed to not modify the truth table.
283           */
284           dims[0] = timedim;
285 
286           /* Determine number of entities in block */
287           if ((status = nc_inq_dimid(exoid, ex_catstr(ent_size, (i + 1)), &dims[1])) != NC_NOERR) {
288             free(stat_vals);
289             snprintf(errmsg, MAX_ERR_LENGTH,
290                      "ERROR: failed to locate number of entities in "
291                      "%d'th %s in file id %d",
292                      i + 1, ex_name_of_object(obj_type), exoid);
293             ex_err(__func__, errmsg, status);
294             goto error_ret; /* exit define mode and return */
295           }
296 
297           /* define netCDF variable to store variable values; the j
298            * index cycles from 1 through the number of variables so
299            * that the index of the EXODUS variable (which is part
300            * of the name of the netCDF variable) will begin at 1
301            * instead of 0
302            */
303 
304           if ((status = nc_def_var(exoid, ex_catstr2(var_name, j, ent_type, i + 1),
305                                    nc_flt_code(exoid), 2, dims, &varid)) != NC_NOERR) {
306             if (status != NC_ENAMEINUSE) {
307               free(stat_vals);
308               snprintf(errmsg, MAX_ERR_LENGTH,
309                        "ERROR: failed to define variable for %d'th %s in file id %d", i + 1,
310                        ex_name_of_object(obj_type), exoid);
311               ex_err(__func__, errmsg, status);
312               goto error_ret; /* exit define mode and return */
313             }
314             ex_compress_variable(exoid, varid, 2);
315           }
316         }
317       }    /* if */
318       k++; /* increment element truth table pointer */
319     }      /* for j */
320   }        /* for i */
321 
322   free(stat_vals);
323 
324   /* create a variable array in which to store the truth table
325    */
326 
327   dims[0] = numelblkdim;
328   dims[1] = numelvardim;
329   status  = nc_def_var(exoid, tab_type, NC_INT, 2, dims, &varid);
330 
331   if (status != NC_NOERR) {
332     snprintf(errmsg, MAX_ERR_LENGTH,
333              "ERROR: failed to define %s variable truth table in file id %d",
334              ex_name_of_object(obj_type), exoid);
335     ex_err(__func__, errmsg, status);
336     goto error_ret; /* exit define mode and return */
337   }
338 
339   /* leave define mode  */
340   if ((status = nc_enddef(exoid)) != NC_NOERR) {
341     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to complete definitions in file id %d", exoid);
342     ex_err(__func__, errmsg, status);
343     EX_FUNC_LEAVE(EX_FATAL);
344   }
345 
346   /* write out the element variable truth table */
347   status = nc_put_var_int(exoid, varid, var_tab);
348 
349   if (status != NC_NOERR) {
350     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to store variable truth table in file id %d",
351              exoid);
352     ex_err(__func__, errmsg, status);
353     EX_FUNC_LEAVE(EX_FATAL);
354   }
355 
356   EX_FUNC_LEAVE(EX_NOERR);
357 
358 /* Fatal error: exit definition mode and return */
359 error_ret:
360   if ((status = nc_enddef(exoid)) != NC_NOERR) /* exit define mode */
361   {
362     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to complete definition for file id %d", exoid);
363     ex_err(__func__, errmsg, status);
364   }
365   EX_FUNC_LEAVE(EX_FATAL);
366 }
367