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