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