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_set, ex_err, etc
37 #include "exodusII_int.h" // for EX_FATAL, etc
38 #include "vtk_netcdf.h" // for NC_NOERR, nc_def_var, etc
39 #include <inttypes.h> // for PRId64
40 #include <stddef.h> // for size_t
41 #include <stdio.h>
42 #include <stdlib.h> // for NULL, free, malloc
43 #include <sys/types.h> // for int64_t
44
45 /*!
46 * writes the set parameters and optionally set data for 1 or more sets
47 * \param exoid exodus file id
48 * \param set_count number of sets to write
49 * \param *sets array of ex_set structures
50 */
51
ex_put_sets(int exoid,size_t set_count,const struct ex_set * sets)52 int ex_put_sets(int exoid, size_t set_count, const struct ex_set *sets)
53 {
54 size_t i;
55 int needs_define = 0;
56 int set_stat;
57 int dimid, varid, status, dims[1];
58 int set_id_ndx;
59 size_t start[1];
60 int cur_num_sets;
61 char errmsg[MAX_ERR_LENGTH];
62 int * sets_to_define = NULL;
63 char * numentryptr = NULL;
64 char * entryptr = NULL;
65 char * extraptr = NULL;
66 char * idsptr = NULL;
67 char * statptr = NULL;
68 char * numdfptr = NULL;
69 char * factptr = NULL;
70
71 int int_type;
72
73 EX_FUNC_ENTER();
74
75 ex_check_valid_file_id(exoid, __func__);
76
77 sets_to_define = malloc(set_count * sizeof(int));
78
79 /* Note that this routine can be called:
80 1) just define the sets
81 2) just output the set data (after a previous call to define)
82 3) define and output the set data in one call.
83 */
84 for (i = 0; i < set_count; i++) {
85 /* first check if any sets are specified */
86 if ((status = nc_inq_dimid(exoid, ex_dim_num_objects(sets[i].type), &dimid)) != NC_NOERR) {
87 if (status == NC_EBADDIM) {
88 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: no %ss defined for file id %d",
89 ex_name_of_object(sets[i].type), exoid);
90 ex_err(__func__, errmsg, status);
91 }
92 else {
93 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to locate %ss defined in file id %d",
94 ex_name_of_object(sets[i].type), exoid);
95 ex_err(__func__, errmsg, status);
96 }
97 free(sets_to_define);
98 EX_FUNC_LEAVE(EX_FATAL);
99 }
100
101 if (sets[i].id < 0) {
102 /* We are adding a set with id = -sets[i].id. We want to define
103 * everything, but we don't
104 * want to increment the number of sets... Major kluge / proof of concept
105 */
106 needs_define++;
107 sets_to_define[i] = -1;
108 }
109 else {
110 status = ex_id_lkup(exoid, sets[i].type, sets[i].id);
111 if (status != -EX_LOOKUPFAIL) { /* found the side set id, so set is already defined... */
112 sets_to_define[i] = 0;
113 }
114 else {
115 needs_define++;
116 sets_to_define[i] = 1;
117 }
118 }
119 }
120
121 if (needs_define > 0) {
122 /* put netcdf file into define mode */
123 if ((status = nc_redef(exoid)) != NC_NOERR) {
124 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to put file id %d into define mode", exoid);
125 ex_err(__func__, errmsg, status);
126 free(sets_to_define);
127 EX_FUNC_LEAVE(EX_FATAL);
128 }
129
130 for (i = 0; i < set_count; i++) {
131 if (sets_to_define[i] == 0) {
132 continue;
133 }
134
135 if (sets_to_define[i] > 0) {
136 /* NOTE: ex_inc_file_item finds the current number of sets defined
137 for a specific file and returns that value incremented. */
138 cur_num_sets = ex_inc_file_item(exoid, ex_get_counter_list(sets[i].type));
139 set_id_ndx = cur_num_sets + 1;
140 sets_to_define[i] = set_id_ndx;
141 }
142 else {
143 cur_num_sets = ex_get_file_item(exoid, ex_get_counter_list(sets[i].type));
144 set_id_ndx = cur_num_sets - set_count + i + 1;
145 sets_to_define[i] = set_id_ndx;
146 }
147
148 if (sets[i].num_entry == 0) {
149 continue;
150 }
151
152 /* setup pointers based on set_type */
153 if (sets[i].type == EX_NODE_SET) {
154 numentryptr = DIM_NUM_NOD_NS(set_id_ndx);
155 entryptr = VAR_NODE_NS(set_id_ndx);
156 extraptr = NULL;
157 /* note we are using DIM_NUM_NODE_NS instead of DIM_NUM_DF_NS */
158 numdfptr = DIM_NUM_NOD_NS(set_id_ndx);
159 factptr = VAR_FACT_NS(set_id_ndx);
160 }
161 else if (sets[i].type == EX_EDGE_SET) {
162 numentryptr = DIM_NUM_EDGE_ES(set_id_ndx);
163 entryptr = VAR_EDGE_ES(set_id_ndx);
164 extraptr = VAR_ORNT_ES(set_id_ndx);
165 numdfptr = DIM_NUM_DF_ES(set_id_ndx);
166 factptr = VAR_FACT_ES(set_id_ndx);
167 }
168 else if (sets[i].type == EX_FACE_SET) {
169 numentryptr = DIM_NUM_FACE_FS(set_id_ndx);
170 entryptr = VAR_FACE_FS(set_id_ndx);
171 extraptr = VAR_ORNT_FS(set_id_ndx);
172 numdfptr = DIM_NUM_DF_FS(set_id_ndx);
173 factptr = VAR_FACT_FS(set_id_ndx);
174 }
175 else if (sets[i].type == EX_SIDE_SET) {
176 numentryptr = DIM_NUM_SIDE_SS(set_id_ndx);
177 entryptr = VAR_ELEM_SS(set_id_ndx);
178 extraptr = VAR_SIDE_SS(set_id_ndx);
179 numdfptr = DIM_NUM_DF_SS(set_id_ndx);
180 factptr = VAR_FACT_SS(set_id_ndx);
181 }
182 else if (sets[i].type == EX_ELEM_SET) {
183 numentryptr = DIM_NUM_ELE_ELS(set_id_ndx);
184 entryptr = VAR_ELEM_ELS(set_id_ndx);
185 extraptr = NULL;
186 numdfptr = DIM_NUM_DF_ELS(set_id_ndx);
187 factptr = VAR_FACT_ELS(set_id_ndx);
188 }
189
190 /* define dimensions and variables */
191 if ((status = nc_def_dim(exoid, numentryptr, sets[i].num_entry, &dimid)) != NC_NOERR) {
192 if (status == NC_ENAMEINUSE) {
193 snprintf(errmsg, MAX_ERR_LENGTH,
194 "ERROR: %s %" PRId64 " -- size already defined in file id %d",
195 ex_name_of_object(sets[i].type), sets[i].id, exoid);
196 ex_err(__func__, errmsg, status);
197 }
198 else {
199 snprintf(errmsg, MAX_ERR_LENGTH,
200 "ERROR: failed to define number of entries in %s %" PRId64 " in file id %d",
201 ex_name_of_object(sets[i].type), sets[i].id, exoid);
202 ex_err(__func__, errmsg, status);
203 }
204 goto error_ret;
205 }
206
207 int_type = NC_INT;
208 if (ex_int64_status(exoid) & EX_BULK_INT64_DB) {
209 int_type = NC_INT64;
210 }
211
212 /* create variable array in which to store the entry lists */
213 dims[0] = dimid;
214 if ((status = nc_def_var(exoid, entryptr, int_type, 1, dims, &varid)) != NC_NOERR) {
215 if (status == NC_ENAMEINUSE) {
216 snprintf(errmsg, MAX_ERR_LENGTH,
217 "ERROR: entry list already exists for %s %" PRId64 " in file id %d",
218 ex_name_of_object(sets[i].type), sets[i].id, exoid);
219 ex_err(__func__, errmsg, status);
220 }
221 else {
222 snprintf(errmsg, MAX_ERR_LENGTH,
223 "ERROR: failed to create entry list for %s %" PRId64 " in file id %d",
224 ex_name_of_object(sets[i].type), sets[i].id, exoid);
225 ex_err(__func__, errmsg, status);
226 }
227 goto error_ret; /* exit define mode and return */
228 }
229 ex_compress_variable(exoid, varid, 1);
230
231 if (extraptr) {
232 if ((status = nc_def_var(exoid, extraptr, int_type, 1, dims, &varid)) != NC_NOERR) {
233 if (status == NC_ENAMEINUSE) {
234 snprintf(errmsg, MAX_ERR_LENGTH,
235 "ERROR: extra list already exists for %s %" PRId64 " in file id %d",
236 ex_name_of_object(sets[i].type), sets[i].id, exoid);
237 ex_err(__func__, errmsg, status);
238 }
239 else {
240 snprintf(errmsg, MAX_ERR_LENGTH,
241 "ERROR: failed to create extra list for %s %" PRId64 " in file id %d",
242 ex_name_of_object(sets[i].type), sets[i].id, exoid);
243 ex_err(__func__, errmsg, status);
244 }
245 goto error_ret; /* exit define mode and return */
246 }
247 ex_compress_variable(exoid, varid, 1);
248 }
249
250 /* Create distribution factors variable if required */
251 if (sets[i].num_distribution_factor > 0) {
252 if (sets[i].type != EX_SIDE_SET) {
253 /* but sets[i].num_distribution_factor must equal number of nodes */
254 if (sets[i].num_distribution_factor != sets[i].num_entry) {
255 snprintf(errmsg, MAX_ERR_LENGTH,
256 "ERROR: # dist fact (%" PRId64 ") not equal to # nodes (%" PRId64
257 ") in node set %" PRId64 " file id %d",
258 sets[i].num_distribution_factor, sets[i].num_entry, sets[i].id, exoid);
259 ex_err(__func__, errmsg, EX_BADPARAM);
260 goto error_ret; /* exit define mode and return */
261 }
262 }
263 else {
264 /* resuse dimid from entry lists */
265 if ((status = nc_def_dim(exoid, numdfptr, sets[i].num_distribution_factor, &dimid)) !=
266 NC_NOERR) {
267 snprintf(errmsg, MAX_ERR_LENGTH,
268 "ERROR: failed to define number of dist factors in %s %" PRId64
269 " in file id %d",
270 ex_name_of_object(sets[i].type), sets[i].id, exoid);
271 ex_err(__func__, errmsg, status);
272 goto error_ret; /* exit define mode and return */
273 }
274 }
275
276 /* create variable array in which to store the set distribution factors
277 */
278 dims[0] = dimid;
279 if ((status = nc_def_var(exoid, factptr, nc_flt_code(exoid), 1, dims, &varid)) !=
280 NC_NOERR) {
281 if (status == NC_ENAMEINUSE) {
282 snprintf(errmsg, MAX_ERR_LENGTH,
283 "ERROR: dist factors list already exists for %s %" PRId64 " in file id %d",
284 ex_name_of_object(sets[i].type), sets[i].id, exoid);
285 ex_err(__func__, errmsg, status);
286 }
287 else {
288 snprintf(errmsg, MAX_ERR_LENGTH,
289 "ERROR: failed to create dist factors list for %s %" PRId64 " in file id %d",
290 ex_name_of_object(sets[i].type), sets[i].id, exoid);
291 ex_err(__func__, errmsg, status);
292 }
293 goto error_ret; /* exit define mode and return */
294 }
295 ex_compress_variable(exoid, varid, 2);
296 }
297 }
298
299 /* leave define mode */
300 if ((status = nc_enddef(exoid)) != NC_NOERR) {
301 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to complete definition in file id %d", exoid);
302 ex_err(__func__, errmsg, status);
303 free(sets_to_define);
304 EX_FUNC_LEAVE(EX_FATAL);
305 }
306
307 /* Output the set ids and status... */
308 for (i = 0; i < set_count; i++) {
309 /* setup pointers based on sets[i].type */
310 if (sets[i].type == EX_NODE_SET) {
311 idsptr = VAR_NS_IDS;
312 statptr = VAR_NS_STAT;
313 }
314 else if (sets[i].type == EX_EDGE_SET) {
315 idsptr = VAR_ES_IDS;
316 statptr = VAR_ES_STAT;
317 }
318 else if (sets[i].type == EX_FACE_SET) {
319 idsptr = VAR_FS_IDS;
320 statptr = VAR_FS_STAT;
321 }
322 else if (sets[i].type == EX_SIDE_SET) {
323 idsptr = VAR_SS_IDS;
324 statptr = VAR_SS_STAT;
325 }
326 else if (sets[i].type == EX_ELEM_SET) {
327 idsptr = VAR_ELS_IDS;
328 statptr = VAR_ELS_STAT;
329 }
330
331 /* first: get id of set id variable */
332 if ((status = nc_inq_varid(exoid, idsptr, &varid)) != NC_NOERR) {
333 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to locate %s %" PRId64 " in file id %d",
334 ex_name_of_object(sets[i].type), sets[i].id, exoid);
335 ex_err(__func__, errmsg, status);
336 free(sets_to_define);
337 EX_FUNC_LEAVE(EX_FATAL);
338 }
339
340 /* write out set id */
341 start[0] = sets_to_define[i] - 1;
342 long long id = sets[i].id;
343 if (id < 0) {
344 id = -id;
345 }
346 status = nc_put_var1_longlong(exoid, varid, start, &id);
347
348 if (status != NC_NOERR) {
349 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to store %s id %" PRId64 " in file id %d",
350 ex_name_of_object(sets[i].type), sets[i].id, exoid);
351 ex_err(__func__, errmsg, status);
352 free(sets_to_define);
353 EX_FUNC_LEAVE(EX_FATAL);
354 }
355
356 set_stat = (sets[i].num_entry == 0) ? 0 : 1;
357
358 if ((status = nc_inq_varid(exoid, statptr, &varid)) != NC_NOERR) {
359 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to locate %s status in file id %d",
360 ex_name_of_object(sets[i].type), exoid);
361 ex_err(__func__, errmsg, status);
362 free(sets_to_define);
363 EX_FUNC_LEAVE(EX_FATAL);
364 }
365
366 if ((status = nc_put_var1_int(exoid, varid, start, &set_stat)) != NC_NOERR) {
367 snprintf(errmsg, MAX_ERR_LENGTH,
368 "ERROR: failed to store %s %" PRId64 " status to file id %d",
369 ex_name_of_object(sets[i].type), sets[i].id, exoid);
370 ex_err(__func__, errmsg, status);
371 free(sets_to_define);
372 EX_FUNC_LEAVE(EX_FATAL);
373 }
374 }
375 }
376
377 free(sets_to_define);
378
379 /* Sets are now all defined; see if any set data needs to be output... */
380 status = EX_NOERR;
381 for (i = 0; i < set_count; i++) {
382 int stat;
383 long long id = sets[i].id;
384 if (id < 0) {
385 id = -id;
386 }
387 if (sets[i].entry_list != NULL || sets[i].extra_list != NULL) {
388 /* NOTE: ex_put_set will write the warning/error message... */
389 stat = ex_put_set(exoid, sets[i].type, id, sets[i].entry_list, sets[i].extra_list);
390 if (stat != EX_NOERR) {
391 status = EX_FATAL;
392 }
393 }
394 if (sets[i].num_distribution_factor > 0 && sets[i].distribution_factor_list != NULL) {
395 /* NOTE: ex_put_set_dist_fact will write the warning/error message... */
396 stat = ex_put_set_dist_fact(exoid, sets[i].type, id, sets[i].distribution_factor_list);
397 if (stat != EX_NOERR) {
398 status = EX_FATAL;
399 }
400 }
401 }
402 EX_FUNC_LEAVE(status);
403
404 /* Fatal error: exit definition mode and return */
405 error_ret:
406 free(sets_to_define);
407
408 if ((status = nc_enddef(exoid)) != NC_NOERR) { /* exit define mode */
409 snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to complete definition for file id %d", exoid);
410 ex_err(__func__, errmsg, status);
411 }
412 EX_FUNC_LEAVE(EX_FATAL);
413 }
414