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  *
37  * exgssc - ex_get_side_set_node_count
38  *
39  * entry conditions -
40  *   input parameters:
41  *       int     exoid                   exodus file id
42  *       int     side_set_id             side set id
43  *
44  * exit conditions -
45  *       int     *side_set_node_cnt_list returned array of number of nodes for
46  *                                       side or face
47  * revision history -
48  *
49  *****************************************************************************/
50 
51 #include "exodusII.h"     // for ex_err, ex_block, etc
52 #include "exodusII_int.h" // for elem_blk_parm, EX_FATAL, etc
53 #include <assert.h>       // for assert
54 #include <ctype.h>        // for toupper
55 #include <inttypes.h>     // for PRId64
56 #include <stddef.h>       // for size_t
57 #include <stdio.h>
58 #include <stdlib.h>    // for free, malloc
59 #include <string.h>    // for strncmp, strlen
60 #include <sys/types.h> // for int64_t
61 
ex_get_side_set_node_count(int exoid,ex_entity_id side_set_id,int * side_set_node_cnt_list)62 int ex_get_side_set_node_count(int exoid, ex_entity_id side_set_id, int *side_set_node_cnt_list)
63 {
64   int       status;
65   size_t    ii, i, j;
66   int       num_side_sets, num_elem_blks, ndim;
67   size_t    tot_num_ss_elem = 0;
68   int64_t   side, elem;
69   void_int *elem_blk_ids       = NULL;
70   void_int *ss_elem_ndx        = NULL;
71   void_int *side_set_elem_list = NULL;
72   void_int *side_set_side_list = NULL;
73   size_t    elem_ctr;
74 
75   struct elem_blk_parm *elem_blk_parms = NULL;
76 
77   char errmsg[MAX_ERR_LENGTH];
78   int  err_stat = EX_NOERR;
79 
80   EX_FUNC_ENTER();
81   ex_check_valid_file_id(exoid, __func__);
82 
83   /* first check if any side sets are specified */
84   /* inquire how many side sets have been stored */
85   num_side_sets = ex_inquire_int(exoid, EX_INQ_SIDE_SETS);
86   if (num_side_sets < 0) {
87     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get number of side sets in file id %d",
88              exoid);
89     ex_err(__func__, errmsg, EX_LASTERR);
90     EX_FUNC_LEAVE(EX_FATAL);
91   }
92 
93   if (num_side_sets == 0) {
94     snprintf(errmsg, MAX_ERR_LENGTH, "Warning: no side sets defined in file id %d", exoid);
95     ex_err(__func__, errmsg, EX_WARN);
96     EX_FUNC_LEAVE(EX_WARN);
97   }
98 
99   /* Lookup index of side set id in VAR_SS_IDS array */
100   if (ex_id_lkup(exoid, EX_SIDE_SET, side_set_id) <= 0) {
101     ;
102   }
103   ex_get_err(NULL, NULL, &status);
104 
105   if (status != 0) {
106     if (status == EX_NULLENTITY) {
107       snprintf(errmsg, MAX_ERR_LENGTH, "Warning: side set %" PRId64 " is NULL in file id %d",
108                side_set_id, exoid);
109       ex_err(__func__, errmsg, EX_NULLENTITY);
110       EX_FUNC_LEAVE(EX_WARN);
111     }
112 
113     snprintf(errmsg, MAX_ERR_LENGTH,
114              "ERROR: failed to locate side set %" PRId64 " in VAR_SS_IDS array in file id %d",
115              side_set_id, exoid);
116     ex_err(__func__, errmsg, status);
117     EX_FUNC_LEAVE(EX_FATAL);
118   }
119 
120   num_elem_blks = ex_inquire_int(exoid, EX_INQ_ELEM_BLK);
121   if (num_elem_blks < 0) {
122     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get number of element blocks in file id %d",
123              exoid);
124     ex_err(__func__, errmsg, EX_LASTERR);
125     EX_FUNC_LEAVE(EX_FATAL);
126   }
127 
128   /* get the dimensionality of the coordinates;  this is necessary to
129      distinguish between 2d TRIs and 3d TRIs */
130   ndim = ex_inquire_int(exoid, EX_INQ_DIM);
131   if (ndim < 0) {
132     snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get dimensionality in file id %d", exoid);
133     ex_err(__func__, errmsg, EX_LASTERR);
134     EX_FUNC_LEAVE(EX_FATAL);
135   }
136 
137   int int_size = sizeof(int);
138   if (ex_int64_status(exoid) & EX_BULK_INT64_API) {
139     int_size = sizeof(int64_t);
140   }
141 
142   /* First determine the  # of elements in the side set*/
143   int err;
144   if (int_size == sizeof(int64_t)) {
145     int64_t ss_elem = 0;
146     int64_t ss_df   = 0;
147     err             = ex_get_set_param(exoid, EX_SIDE_SET, side_set_id, &ss_elem, &ss_df);
148     tot_num_ss_elem = ss_elem;
149   }
150   else {
151     int ss_elem     = 0;
152     int ss_df       = 0;
153     err             = ex_get_set_param(exoid, EX_SIDE_SET, side_set_id, &ss_elem, &ss_df);
154     tot_num_ss_elem = ss_elem;
155   }
156 
157   if (err == -1) {
158     snprintf(errmsg, MAX_ERR_LENGTH,
159              "ERROR: failed to get number of elements in side set %" PRId64 " in file id %d",
160              side_set_id, exoid);
161     ex_err(__func__, errmsg, EX_LASTERR);
162     EX_FUNC_LEAVE(EX_FATAL);
163   }
164 
165   /* Allocate space for the side set element list */
166   {
167     if (!(side_set_elem_list = malloc(tot_num_ss_elem * int_size))) {
168       snprintf(errmsg, MAX_ERR_LENGTH,
169                "ERROR: failed to allocate space for side set element "
170                "list for file id %d",
171                exoid);
172       ex_err(__func__, errmsg, EX_MEMFAIL);
173       EX_FUNC_LEAVE(EX_FATAL);
174     }
175 
176     /* Allocate space for the side set side list */
177     if (!(side_set_side_list = malloc(tot_num_ss_elem * int_size))) {
178       snprintf(errmsg, MAX_ERR_LENGTH,
179                "ERROR: failed to allocate space for side set side list "
180                "for file id %d",
181                exoid);
182       ex_err(__func__, errmsg, EX_MEMFAIL);
183       err_stat = EX_FATAL;
184       goto cleanup;
185     }
186 
187     if (ex_get_set(exoid, EX_SIDE_SET, side_set_id, side_set_elem_list, side_set_side_list) == -1) {
188       snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get side set %" PRId64 " in file id %d",
189                side_set_id, exoid);
190       ex_err(__func__, errmsg, EX_LASTERR);
191       err_stat = EX_FATAL;
192       goto cleanup;
193     }
194 
195     /* Allocate space for the ss element index array */
196     if (!(ss_elem_ndx = malloc(tot_num_ss_elem * int_size))) {
197       snprintf(errmsg, MAX_ERR_LENGTH,
198                "ERROR: failed to allocate space for side set elem sort "
199                "array for file id %d",
200                exoid);
201       ex_err(__func__, errmsg, EX_MEMFAIL);
202       err_stat = EX_FATAL;
203       goto cleanup;
204     }
205 
206     if (int_size == sizeof(int64_t)) {
207       /* Sort side set element list into index array  - non-destructive */
208       int64_t *elems = (int64_t *)ss_elem_ndx;
209       for (i = 0; i < tot_num_ss_elem; i++) {
210         elems[i] = i; /* init index array to current position */
211       }
212       ex_iqsort64(side_set_elem_list, elems, tot_num_ss_elem);
213     }
214     else {
215       /* Sort side set element list into index array  - non-destructive */
216       int *elems = (int *)ss_elem_ndx;
217       for (i = 0; i < tot_num_ss_elem; i++) {
218         elems[i] = i; /* init index array to current position */
219       }
220       ex_iqsort(side_set_elem_list, elems, tot_num_ss_elem);
221     }
222   }
223 
224   /* Allocate space for the element block ids */
225   {
226     int_size = sizeof(int);
227     if (ex_int64_status(exoid) & EX_IDS_INT64_API) {
228       int_size = sizeof(int64_t);
229     }
230 
231     if (!(elem_blk_ids = malloc(num_elem_blks * int_size))) {
232       snprintf(errmsg, MAX_ERR_LENGTH,
233                "ERROR: failed to allocate space for element block ids "
234                "for file id %d",
235                exoid);
236       ex_err(__func__, errmsg, EX_MEMFAIL);
237       err_stat = EX_FATAL;
238       goto cleanup;
239     }
240 
241     if (ex_get_ids(exoid, EX_ELEM_BLOCK, elem_blk_ids) == -1) {
242       snprintf(errmsg, MAX_ERR_LENGTH, "ERROR: failed to get element block ids in file id %d",
243                exoid);
244       ex_err(__func__, errmsg, EX_MSG);
245       err_stat = EX_FATAL;
246       goto cleanup;
247     }
248   }
249 
250   /* Allocate space for the element block params */
251   if (!(elem_blk_parms = malloc(num_elem_blks * sizeof(struct elem_blk_parm)))) {
252     snprintf(errmsg, MAX_ERR_LENGTH,
253              "ERROR: failed to allocate space for element block params "
254              "for file id %d",
255              exoid);
256     ex_err(__func__, errmsg, EX_MEMFAIL);
257     err_stat = EX_FATAL;
258     goto cleanup;
259   }
260 
261   elem_ctr = 0;
262   for (i = 0; i < num_elem_blks; i++) {
263     ex_entity_id id;
264     if (ex_int64_status(exoid) & EX_IDS_INT64_API) {
265       id = ((int64_t *)elem_blk_ids)[i];
266     }
267     else {
268       id = ((int *)elem_blk_ids)[i];
269     }
270 
271     err_stat = ex_int_get_block_param(exoid, id, ndim, &elem_blk_parms[i]);
272     if (err_stat != EX_NOERR) {
273       goto cleanup;
274     }
275 
276     elem_ctr += elem_blk_parms[i].num_elem_in_blk;
277     elem_blk_parms[i].elem_ctr = elem_ctr; /* save elem number max */
278   }
279 
280   /* Finally... Create the list of node counts for each face in the
281    * side set.
282    */
283 
284   j = 0; /* The current element block... */
285   for (ii = 0; ii < tot_num_ss_elem; ii++) {
286 
287     if (ex_int64_status(exoid) & EX_BULK_INT64_API) {
288       i    = ((int64_t *)ss_elem_ndx)[ii];
289       elem = ((int64_t *)side_set_elem_list)[i];
290       side = ((int64_t *)side_set_side_list)[i] - 1; /* Convert to 0-based sides */
291     }
292     else {
293       i    = ((int *)ss_elem_ndx)[ii];
294       elem = ((int *)side_set_elem_list)[i];
295       side = ((int *)side_set_side_list)[i] - 1; /* Convert to 0-based sides */
296     }
297 
298     /*
299      * Since the elements are being accessed in sorted, order, the
300      * block that contains the elements must progress sequentially
301      * from block 0 to block[num_elem_blks-1]. Once we find an element
302      * not in this block, find a following block that contains it...
303      */
304     for (; j < num_elem_blks; j++) {
305       if (elem <= elem_blk_parms[j].elem_ctr) {
306         break;
307       }
308     }
309 
310     if (j < num_elem_blks) {
311       assert(side < elem_blk_parms[j].num_sides);
312       side_set_node_cnt_list[i] = elem_blk_parms[j].num_nodes_per_side[side];
313     }
314     else {
315       snprintf(errmsg, MAX_ERR_LENGTH,
316                "ERROR: Invalid element number %" PRId64 " found in side set %" PRId64 " in file %d",
317                elem, side_set_id, exoid);
318       ex_err(__func__, errmsg, EX_BADPARAM);
319       err_stat = EX_FATAL;
320       goto cleanup;
321     }
322   }
323 
324 /* All done: release connectivity array space, element block ids
325  * array, element block parameters array, and side set element index
326  * array
327  */
328 cleanup:
329   free(elem_blk_ids);
330   free(elem_blk_parms);
331   free(ss_elem_ndx);
332   free(side_set_side_list);
333   free(side_set_elem_list);
334 
335   EX_FUNC_LEAVE(err_stat);
336 }
337