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