1 /*
2  * Copyright(C) 1999-2020 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  * See packages/seacas/LICENSE for details
7  */
8 
9 #include "exodusII.h"     // for ex_err, etc
10 #include "exodusII_int.h" // for EX_FATAL, ex__get_dimension, etc
11 
ex__look_up_var(int exoid,ex_entity_type var_type,int var_index,ex_entity_id obj_id,const char * VOBJID,const char * VOBJTAB,const char * DNUMOBJ,const char * DNUMOBJVAR,int * varid)12 static int ex__look_up_var(int exoid, ex_entity_type var_type, int var_index, ex_entity_id obj_id,
13                            const char *VOBJID, const char *VOBJTAB, const char *DNUMOBJ,
14                            const char *DNUMOBJVAR, int *varid)
15 {
16   int status;
17   int obj_id_ndx;
18   int dimid, time_dim, numobjdim, dims[2];
19 
20   size_t num_obj;
21   size_t num_obj_var;
22   size_t num_entity;
23 
24   int *obj_var_truth_tab;
25   char errmsg[MAX_ERR_LENGTH];
26 
27   if (var_type == EX_ASSEMBLY) {
28     status = nc_inq_varid(exoid, VAR_ENTITY_ASSEMBLY(obj_id), varid);
29     if (status != 0) {
30       snprintf(errmsg, MAX_ERR_LENGTH,
31                "ERROR: failed to locate %s id %" PRId64 " in %s array in file id %d",
32                ex_name_of_object(var_type), obj_id, VOBJID, exoid);
33       ex_err_fn(exoid, __func__, errmsg, status);
34       return (EX_FATAL);
35     }
36     obj_id_ndx = obj_id;
37   }
38   else if (var_type == EX_BLOB) {
39     status = nc_inq_varid(exoid, VAR_ENTITY_BLOB(obj_id), varid);
40     if (status != 0) {
41       snprintf(errmsg, MAX_ERR_LENGTH,
42                "ERROR: failed to locate %s id %" PRId64 " in %s array in file id %d",
43                ex_name_of_object(var_type), obj_id, VOBJID, exoid);
44       ex_err_fn(exoid, __func__, errmsg, status);
45       return (EX_FATAL);
46     }
47     obj_id_ndx = obj_id;
48   }
49   else {
50     /* Determine index of obj_id in VOBJID array */
51     obj_id_ndx = ex__id_lkup(exoid, var_type, obj_id);
52     if (obj_id_ndx <= 0) {
53       ex_get_err(NULL, NULL, &status);
54 
55       if (status != 0) {
56         if (status == EX_NULLENTITY) {
57           snprintf(errmsg, MAX_ERR_LENGTH,
58                    "Warning: no variables allowed for NULL block %" PRId64 " in file id %d", obj_id,
59                    exoid);
60           ex_err_fn(exoid, __func__, errmsg, EX_NULLENTITY);
61           return (EX_WARN);
62         }
63 
64         snprintf(errmsg, MAX_ERR_LENGTH,
65                  "ERROR: failed to locate %s id %" PRId64 " in %s array in file id %d",
66                  ex_name_of_object(var_type), obj_id, VOBJID, exoid);
67         ex_err_fn(exoid, __func__, errmsg, status);
68         return (EX_FATAL);
69       }
70     }
71   }
72 
73   if ((status = nc_inq_varid(exoid, ex__name_var_of_object(var_type, var_index, obj_id_ndx),
74                              varid)) != NC_NOERR) {
75     if (status == NC_ENOTVAR) { /* variable doesn't exist, create it! */
76       /* check for the existence of an TNAME variable truth table */
77       if (nc_inq_varid(exoid, VOBJTAB, varid) == NC_NOERR) {
78         /* find out number of TNAMEs and TNAME variables */
79         status = ex__get_dimension(exoid, DNUMOBJ, ex_name_of_object(var_type), &num_obj, &dimid,
80                                    __func__);
81         if (status != NC_NOERR) {
82           return (status);
83         }
84 
85         status = ex__get_dimension(exoid, DNUMOBJVAR, ex_name_of_object(var_type), &num_obj_var,
86                                    &dimid, __func__);
87         if (status != NC_NOERR) {
88           return (status);
89         }
90 
91         if (!(obj_var_truth_tab = malloc(num_obj * num_obj_var * sizeof(int)))) {
92           snprintf(errmsg, MAX_ERR_LENGTH,
93                    "ERROR: failed to allocate memory for %s variable "
94                    "truth table in file id %d",
95                    ex_name_of_object(var_type), exoid);
96           ex_err_fn(exoid, __func__, errmsg, EX_MEMFAIL);
97           return (EX_FATAL);
98         }
99 
100         /*   read in the TNAME variable truth table */
101         if ((status = nc_get_var_int(exoid, *varid, obj_var_truth_tab)) != NC_NOERR) {
102           snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get truth table from file id %d",
103                    exoid);
104           ex_err_fn(exoid, __func__, errmsg, status);
105           return (EX_FATAL);
106         }
107 
108         if (obj_var_truth_tab[num_obj_var * (obj_id_ndx - 1) + var_index - 1] == 0L) {
109           free(obj_var_truth_tab);
110           snprintf(
111               errmsg, MAX_ERR_LENGTH, "ERROR: Invalid %s variable %d, %s %" PRId64 " in file id %d",
112               ex_name_of_object(var_type), var_index, ex_name_of_object(var_type), obj_id, exoid);
113           ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM);
114           return (EX_FATAL);
115         }
116         free(obj_var_truth_tab);
117       }
118 
119       if ((status = nc_inq_dimid(exoid, DIM_TIME, &time_dim)) != NC_NOERR) {
120         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to locate time dimension in file id %d",
121                  exoid);
122         ex_err_fn(exoid, __func__, errmsg, status);
123         goto error_ret; /* exit define mode and return */
124       }
125 
126       ex__get_dimension(exoid, ex__dim_num_entries_in_object(var_type, obj_id_ndx),
127                         ex_name_of_object(var_type), &num_entity, &numobjdim, __func__);
128 
129       /*    variable doesn't exist so put file into define mode  */
130       if ((status = nc_redef(exoid)) != NC_NOERR) {
131         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to put file id %d into define mode", exoid);
132         ex_err_fn(exoid, __func__, errmsg, status);
133         return (EX_FATAL);
134       }
135 
136       /* define netCDF variable to store TNAME variable values */
137       dims[0] = time_dim;
138       dims[1] = numobjdim;
139       if ((status = nc_def_var(exoid, ex__name_var_of_object(var_type, var_index, obj_id_ndx),
140                                nc_flt_code(exoid), 2, dims, varid)) != NC_NOERR) {
141         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to define %s variable %d in file id %d",
142                  ex_name_of_object(var_type), var_index, exoid);
143         ex_err_fn(exoid, __func__, errmsg, status);
144         goto error_ret;
145       }
146       ex__compress_variable(exoid, *varid, 2);
147 
148       /*    leave define mode  */
149       if ((status = ex__leavedef(exoid, __func__)) != NC_NOERR) {
150         return (EX_FATAL);
151       }
152     }
153     else {
154       snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to locate %s variable %s in file id %d",
155                ex_name_of_object(var_type), ex__name_var_of_object(var_type, var_index, obj_id_ndx),
156                exoid);
157       ex_err_fn(exoid, __func__, errmsg, status);
158       return (EX_FATAL);
159     }
160   }
161   return (EX_NOERR);
162 
163 /* Fatal error: exit definition mode and return */
164 error_ret:
165   ex__leavedef(exoid, __func__);
166   return (EX_FATAL);
167 }
168 
169 /*!
170 \ingroup ResultsData
171  * writes the values of a single variable for a partial block at one time
172  * step to the database; assume the first time step and variable index
173  * are 1
174  * \param      exoid           exodus file id
175  * \param      time_step       time step number (1-based)
176  * \param      var_type        type (edge block, face block, edge set, ... )
177  * \param      var_index       entity variable index (1-based)
178  * \param      obj_id          entity id
179  * \param      start_index     index of first entity in block to write (1-based)
180  * \param      num_entities    number of entries in this block/set
181  * \param      var_vals        the values to be written
182  */
183 
ex_put_partial_var(int exoid,int time_step,ex_entity_type var_type,int var_index,ex_entity_id obj_id,int64_t start_index,int64_t num_entities,const void * var_vals)184 int ex_put_partial_var(int exoid, int time_step, ex_entity_type var_type, int var_index,
185                        ex_entity_id obj_id, int64_t start_index, int64_t num_entities,
186                        const void *var_vals)
187 {
188   int    varid;
189   size_t start[2], count[2];
190   int    status;
191   char   errmsg[MAX_ERR_LENGTH];
192 
193   EX_FUNC_ENTER();
194 
195   if (ex__check_valid_file_id(exoid, __func__) == EX_FATAL) {
196     EX_FUNC_LEAVE(EX_FATAL);
197   }
198 
199   switch (var_type) {
200   case EX_GLOBAL:
201     if (num_entities <= 0) {
202       snprintf(errmsg, MAX_ERR_LENGTH, "Warning: no global variables specified for file id %d",
203                exoid);
204       ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM);
205 
206       EX_FUNC_LEAVE(EX_WARN);
207     }
208     /* inquire previously defined variable */
209 
210     if ((status = nc_inq_varid(exoid, VAR_GLO_VAR, &varid)) != NC_NOERR) {
211       if (status == NC_ENOTVAR) {
212         snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: no global variables defined in file id %d", exoid);
213         ex_err_fn(exoid, __func__, errmsg, status);
214       }
215       else {
216         snprintf(errmsg, MAX_ERR_LENGTH,
217                  "ERROR: failed to get global variables parameters in file id %d", exoid);
218         ex_err_fn(exoid, __func__, errmsg, status);
219       }
220       EX_FUNC_LEAVE(EX_FATAL);
221     }
222     break;
223   case EX_NODAL:
224     status =
225         ex__put_partial_nodal_var(exoid, time_step, var_index, start_index, num_entities, var_vals);
226     EX_FUNC_LEAVE(status);
227     break;
228   case EX_ASSEMBLY:
229     status = ex__look_up_var(exoid, var_type, var_index, obj_id, "", VAR_ASSEMBLY_TAB,
230                              DIM_NUM_ASSEMBLY, DIM_NUM_ASSEMBLY_VAR, &varid);
231     break;
232   case EX_BLOB:
233     status = ex__look_up_var(exoid, var_type, var_index, obj_id, "", VAR_BLOB_TAB, DIM_NUM_BLOB,
234                              DIM_NUM_BLOB_VAR, &varid);
235     break;
236   case EX_EDGE_BLOCK:
237     status = ex__look_up_var(exoid, var_type, var_index, obj_id, VAR_ID_ED_BLK, VAR_EBLK_TAB,
238                              DIM_NUM_ED_BLK, DIM_NUM_EDG_VAR, &varid);
239     break;
240   case EX_FACE_BLOCK:
241     status = ex__look_up_var(exoid, var_type, var_index, obj_id, VAR_ID_FA_BLK, VAR_FBLK_TAB,
242                              DIM_NUM_FA_BLK, DIM_NUM_FAC_VAR, &varid);
243     break;
244   case EX_ELEM_BLOCK:
245     status = ex__look_up_var(exoid, var_type, var_index, obj_id, VAR_ID_EL_BLK, VAR_ELEM_TAB,
246                              DIM_NUM_EL_BLK, DIM_NUM_ELE_VAR, &varid);
247     break;
248   case EX_NODE_SET:
249     status = ex__look_up_var(exoid, var_type, var_index, obj_id, VAR_NS_IDS, VAR_NSET_TAB,
250                              DIM_NUM_NS, DIM_NUM_NSET_VAR, &varid);
251     break;
252   case EX_EDGE_SET:
253     status = ex__look_up_var(exoid, var_type, var_index, obj_id, VAR_ES_IDS, VAR_ESET_TAB,
254                              DIM_NUM_ES, DIM_NUM_ESET_VAR, &varid);
255     break;
256   case EX_FACE_SET:
257     status = ex__look_up_var(exoid, var_type, var_index, obj_id, VAR_FS_IDS, VAR_FSET_TAB,
258                              DIM_NUM_FS, DIM_NUM_FSET_VAR, &varid);
259     break;
260   case EX_SIDE_SET:
261     status = ex__look_up_var(exoid, var_type, var_index, obj_id, VAR_SS_IDS, VAR_SSET_TAB,
262                              DIM_NUM_SS, DIM_NUM_SSET_VAR, &varid);
263     break;
264   case EX_ELEM_SET:
265     status = ex__look_up_var(exoid, var_type, var_index, obj_id, VAR_ELS_IDS, VAR_ELSET_TAB,
266                              DIM_NUM_ELS, DIM_NUM_ELSET_VAR, &varid);
267     break;
268   default:
269     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: invalid variable type (%d) specified for file id %d",
270              var_type, exoid);
271     ex_err_fn(exoid, __func__, errmsg, EX_BADPARAM);
272     EX_FUNC_LEAVE(EX_FATAL);
273   }
274 
275   if (status != EX_NOERR) {
276     EX_FUNC_LEAVE(status);
277   }
278 
279   /* store element variable values */
280   start[0] = time_step - 1;
281   start[1] = start_index - 1;
282   if (var_type == EX_GLOBAL) {
283     /* global variables may be written
284      * - all at once (by setting var_index to 1 and num_entries_this_obj to
285      * num_glob, or
286      * - one at a time (by setting var_index to the desired index and
287      * num_entries_this_obj to 1.
288      */
289     count[0] = var_index;
290   }
291   else {
292     count[0] = 1;
293   }
294   count[1] = num_entities;
295   if (count[1] == 0) {
296     start[1] = 0;
297   }
298 
299   if (ex__comp_ws(exoid) == 4) {
300     status = nc_put_vara_float(exoid, varid, start, count, var_vals);
301   }
302   else {
303     status = nc_put_vara_double(exoid, varid, start, count, var_vals);
304   }
305 
306   if (status != NC_NOERR) {
307     snprintf(errmsg, MAX_ERR_LENGTH,
308              "ERROR: failed to store %s %" PRId64 " variable %d at step %d in file id %d",
309              ex_name_of_object(var_type), obj_id, var_index, time_step, exoid);
310     ex_err_fn(exoid, __func__, errmsg, status);
311     EX_FUNC_LEAVE(EX_FATAL);
312   }
313 
314   EX_FUNC_LEAVE(EX_NOERR);
315 }
316