1 /*
2  * Copyright (c) 2005 Sandia Corporation. Under the terms of Contract
3  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Governement
4  * 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 Sandia Corporation 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 * expclb - ex_put_concat_elem_block: write element block parameters
38 *
39 * entry conditions -
40 *   input parameters:
41 *       int     idexo                   exodus file id
42 *       char**  elem_type               element type string
43 *       int*    num_elem_this_blk       number of elements in the element blk
44 *       int*    num_nodes_per_elem      number of nodes per element block
45 *       int*    num_attr_this_blk       number of attributes
46 *       int     define_maps             if != 0, write maps, else don't
47 *
48 *****************************************************************************/
49 
50 #include <stdlib.h>
51 #include "exodusII.h"
52 #include "exodusII_int.h"
53 #include <string.h>
54 
55 /*!
56  * writes the parameters used to describe an element block
57  * \param    exoid                   exodus file id
58  * \param    elem_blk_id             element block id
59  * \param    elem_type               element type string
60  * \param    num_elem_this_blk       number of elements in the element blk
61  * \param    num_nodes_per_elem      number of nodes per element block
62  * \param    num_attr_this_blk       number of attributes
63  * \param    define_maps             if != 0, write maps, else don't
64  */
ex_put_concat_elem_block(int exoid,const void_int * elem_blk_id,char * elem_type[],const void_int * num_elem_this_blk,const void_int * num_nodes_per_elem,const void_int * num_attr_this_blk,int define_maps)65 int ex_put_concat_elem_block (int    exoid,
66                               const void_int*   elem_blk_id,
67                               char *elem_type[],
68                               const void_int*   num_elem_this_blk,
69                               const void_int*   num_nodes_per_elem,
70                               const void_int*   num_attr_this_blk,
71                               int    define_maps)
72 {
73   int i, varid, dimid, dims[2], strdim, *eb_array;
74   int temp;
75   int iblk;
76   int status;
77   int num_elem_blk;
78   int map_int_type, conn_int_type;
79   size_t length;
80   int cur_num_elem_blk, nelnoddim, numelbdim, numattrdim, connid, numelemdim, numnodedim;
81   char errmsg[MAX_ERR_LENGTH];
82 
83   exerrval  = 0; /* clear error code */
84 
85   /* first check if any element blocks are specified
86    * OK if zero...
87    */
88   if (nc_inq_dimid(exoid, DIM_NUM_EL_BLK, &dimid) != NC_NOERR) {
89     return (EX_NOERR);
90   }
91 
92   /* Get number of element blocks defined for this file */
93   if ((status = nc_inq_dimlen(exoid,dimid,&length)) != NC_NOERR) {
94     exerrval = status;
95     sprintf(errmsg,
96 	    "Error: failed to get number of element blocks in file id %d",
97 	    exoid);
98     ex_err("ex_put_concat_elem_block",errmsg,exerrval);
99     return (EX_FATAL);
100   }
101   num_elem_blk = length;
102 
103   /* Fill out the element block status array */
104   if (!(eb_array = malloc(num_elem_blk*sizeof(int)))) {
105     exerrval = EX_MEMFAIL;
106     sprintf(errmsg,
107 	    "Error: failed to allocate space for element block status array in file id %d",
108 	    exoid);
109     ex_err("ex_put_concat_elem_block",errmsg,exerrval);
110     return (EX_FATAL);
111   }
112 
113   if (ex_int64_status(exoid) & EX_IDS_INT64_API) {
114     for (i=0;i<num_elem_blk;i++) {
115       eb_array[i] = (((int64_t*)num_elem_this_blk)[i] == 0) ? 0 : 1;
116     }
117   } else {
118     for (i=0;i<num_elem_blk;i++) {
119       eb_array[i] = (((int*)num_elem_this_blk)[i] == 0) ? 0 : 1;
120     }
121   }
122 
123   /* Next, get variable id of status array */
124   if ((status = nc_inq_varid(exoid, VAR_STAT_EL_BLK, &varid)) != NC_NOERR) {
125     exerrval = status;
126     sprintf(errmsg,
127 	    "Error: failed to locate element block status in file id %d",
128 	    exoid);
129     ex_err("ex_put_concat_elem_block",errmsg,exerrval);
130     return (EX_FATAL);
131   }
132 
133   status = nc_put_var_int(exoid, varid, eb_array);
134 
135   if (status != NC_NOERR) {
136     exerrval = status;
137     sprintf(errmsg,
138 	    "Error: failed to store element block status array to file id %d",
139             exoid);
140     ex_err("ex_put_concat_elem_block",errmsg,exerrval);
141     return (EX_FATAL);
142   }
143 
144   /* Next, fill out ids array */
145   /* first get id of ids array variable */
146   if ((status = nc_inq_varid(exoid, VAR_ID_EL_BLK, &varid)) != NC_NOERR) {
147     exerrval = status;
148     sprintf(errmsg,
149 	    "Error: failed to locate element block ids array in file id %d",
150             exoid);
151     ex_err("ex_put_concat_elem_block",errmsg,exerrval);
152     return (EX_FATAL);
153   }
154 
155   /* then, write out id list */
156   if (ex_int64_status(exoid) & EX_IDS_INT64_API) {
157     status = nc_put_var_longlong(exoid, varid, elem_blk_id);
158   } else {
159     status = nc_put_var_int(exoid, varid, elem_blk_id);
160   }
161 
162   if (status != NC_NOERR) {
163     exerrval = status;
164     sprintf(errmsg,
165 	    "Error: failed to store element block id array in file id %d",
166             exoid);
167     ex_err("ex_put_concat_elem_block",errmsg,exerrval);
168     return (EX_FATAL);
169   }
170 
171   /* inquire previously defined dimensions  */
172   if ((status = nc_inq_dimid(exoid, DIM_STR_NAME, &strdim)) != NC_NOERR) {
173     exerrval = status;
174     sprintf(errmsg,
175 	    "Error: failed to get string length in file id %d",exoid);
176     ex_err("ex_put_concat_elem_block",errmsg,exerrval);
177     return (EX_FATAL);
178   }
179 
180   /* put netcdf file into define mode  */
181   if ((status = nc_redef (exoid)) != NC_NOERR)  {
182     exerrval = status;
183     sprintf(errmsg,"Error: failed to place file id %d into define mode",exoid);
184     ex_err("ex_put_concat_elem_block",errmsg,exerrval);
185     return (EX_FATAL);
186   }
187 
188   conn_int_type = NC_INT;
189   if (ex_int64_status(exoid) & EX_BULK_INT64_DB) {
190     conn_int_type = NC_INT64;
191   }
192 
193   map_int_type = NC_INT;
194   if (ex_int64_status(exoid) & EX_MAPS_INT64_DB) {
195     map_int_type = NC_INT64;
196   }
197 
198   /* Iterate over element blocks ... */
199   for (iblk = 0; iblk < num_elem_blk; iblk++) {
200     ex_entity_id eb_id;
201     size_t num_elem;
202     size_t num_npe;
203     size_t num_attr;
204     if (ex_int64_status(exoid) & EX_IDS_INT64_API) {
205       eb_id    = ((int64_t*)elem_blk_id)[iblk];
206       num_elem = ((int64_t*)num_elem_this_blk)[iblk];
207       num_npe  = ((int64_t*)num_nodes_per_elem)[iblk];
208       num_attr = ((int64_t*)num_attr_this_blk)[iblk];
209     } else {
210       eb_id    = ((int*)elem_blk_id)[iblk];
211       num_elem = ((int*)num_elem_this_blk)[iblk];
212       num_npe  = ((int*)num_nodes_per_elem)[iblk];
213       num_attr = ((int*)num_attr_this_blk)[iblk];
214     }
215 
216     cur_num_elem_blk=ex_get_file_item(exoid, ex_get_counter_list(EX_ELEM_BLOCK));
217     if (cur_num_elem_blk >= num_elem_blk) {
218       exerrval = EX_FATAL;
219       sprintf(errmsg,
220 	      "Error: exceeded number of element blocks (%d) defined in file id %d",
221               num_elem_blk,exoid);
222       ex_err("ex_put_concat_elem_block",errmsg,exerrval);
223       goto error_ret;
224     }
225 
226     /* NOTE: ex_inc_file_item  is used to find the number of element blocks
227        for a specific file and returns that value incremented. */
228     cur_num_elem_blk=ex_inc_file_item(exoid, ex_get_counter_list(EX_ELEM_BLOCK));
229 
230     if (eb_array[iblk] == 0) /* Is this a NULL element block? */
231       continue;
232 
233     /* define some dimensions and variables*/
234     if ((status = nc_def_dim(exoid,
235 			     DIM_NUM_EL_IN_BLK(cur_num_elem_blk+1),
236 			     num_elem, &numelbdim)) != NC_NOERR) {
237       exerrval = status;
238       if (status == NC_ENAMEINUSE) {     /* duplicate entry */
239 	sprintf(errmsg,
240 		"Error: element block %"PRId64" already defined in file id %d",
241 		eb_id,exoid);
242       } else {
243 	sprintf(errmsg,
244 		"Error: failed to define number of elements/block for block %"PRId64" file id %d",
245 		eb_id,exoid);
246       }
247       ex_err("ex_put_concat_elem_block",errmsg,exerrval);
248       goto error_ret;         /* exit define mode and return */
249     }
250 
251     if ((status = nc_def_dim(exoid,
252 			     DIM_NUM_NOD_PER_EL(cur_num_elem_blk+1),
253 			     num_npe, &nelnoddim)) != NC_NOERR) {
254       exerrval = status;
255       sprintf(errmsg,
256 	      "Error: failed to define number of nodes/element for block %"PRId64" in file id %d",
257 	      eb_id,exoid);
258       ex_err("ex_put_concat_elem_block",errmsg,exerrval);
259       goto error_ret;         /* exit define mode and return */
260     }
261 
262     /* element connectivity array */
263     dims[0] = numelbdim;
264     dims[1] = nelnoddim;
265 
266     if ((status = nc_def_var (exoid, VAR_CONN(cur_num_elem_blk+1),
267 			      conn_int_type, 2, dims, &connid)) != NC_NOERR) {
268       exerrval = status;
269       sprintf(errmsg,
270 	      "Error: failed to create connectivity array for block %"PRId64" in file id %d",
271 	      eb_id,exoid);
272       ex_err("ex_put_concat_elem_block",errmsg,exerrval);
273       goto error_ret;         /* exit define mode and return */
274     }
275     ex_compress_variable(exoid, connid, 1);
276 
277     /* store element type as attribute of connectivity variable */
278     if ((status = nc_put_att_text(exoid, connid, ATT_NAME_ELB, strlen(elem_type[iblk])+1,
279 				  (void*)elem_type[iblk])) != NC_NOERR) {
280       exerrval = status;
281       sprintf(errmsg,
282 	      "Error: failed to store element type name %s in file id %d",
283 	      elem_type[iblk],exoid);
284       ex_err("ex_put_concat_elem_block",errmsg,exerrval);
285       goto error_ret;         /* exit define mode and return */
286     }
287 
288     /* element attribute array */
289     if (num_attr > 0) {
290       if ((status = nc_def_dim (exoid,
291 				DIM_NUM_ATT_IN_BLK(cur_num_elem_blk+1),
292 				num_attr, &numattrdim)) != NC_NOERR) {
293 	exerrval = status;
294 	sprintf(errmsg,
295 		"Error: failed to define number of attributes in block %"PRId64" in file id %d",
296 		eb_id,exoid);
297 	ex_err("ex_put_concat_elem_block",errmsg,exerrval);
298 	goto error_ret;         /* exit define mode and return */
299       }
300 
301       /* Attribute names... */
302       dims[0] = numattrdim;
303       dims[1] = strdim;
304 
305       if ((status = nc_def_var(exoid, VAR_NAME_ATTRIB(cur_num_elem_blk+1),
306 			       NC_CHAR, 2, dims, &temp)) != NC_NOERR) {
307 	exerrval = status;
308 	sprintf(errmsg,
309 		"Error: failed to define element attribute name array in file id %d",exoid);
310 	ex_err("ex_put_concat_elem_block",errmsg,exerrval);
311 	goto error_ret;         /* exit define mode and return */
312       }
313       eb_array[iblk] = temp;
314 
315       dims[0] = numelbdim;
316       dims[1] = numattrdim;
317 
318       if ((status = nc_def_var(exoid, VAR_ATTRIB(cur_num_elem_blk+1),
319 			       nc_flt_code(exoid), 2, dims, &temp)) != NC_NOERR) {
320 	exerrval = status;
321 	sprintf(errmsg,
322 		"Error:  failed to define attributes for element block %"PRId64" in file id %d",
323 		eb_id,exoid);
324 	ex_err("ex_put_concat_elem_block",errmsg,exerrval);
325 	goto error_ret;         /* exit define mode and return */
326       }
327 
328     }
329 
330   }
331 
332   /* Define the element map here to avoid a later redefine call */
333   if (define_maps != 0) {
334     if (nc_inq_varid(exoid, VAR_ELEM_NUM_MAP, &temp) != NC_NOERR) {
335       /* Map does not exist */
336       /* Possible to have zero elements but >0 element blocks.
337        * Only define map if there are nonzero elements
338        */
339       if (nc_inq_dimid(exoid, DIM_NUM_ELEM, &numelemdim) == NC_NOERR) {
340 	dims[0] = numelemdim;
341 
342 	if ((status = nc_def_var(exoid, VAR_ELEM_NUM_MAP, map_int_type, 1, dims, &temp)) != NC_NOERR) {
343 	  exerrval = status;
344 	  if (status == NC_ENAMEINUSE) {
345 	    sprintf(errmsg,
346 		    "Error: element numbering map already exists in file id %d",
347 		    exoid);
348 	  } else {
349 	    sprintf(errmsg,
350 		    "Error: failed to create element numbering map in file id %d",
351 		    exoid);
352 	  }
353 	  ex_err("ex_put_concat_elem_block",errmsg,exerrval);
354 	  goto error_ret;         /* exit define mode and return */
355 	}
356 	ex_compress_variable(exoid, temp, 1);
357       }
358     }
359 
360     /* Do the same for the node numbering map */
361     if (nc_inq_varid(exoid, VAR_NODE_NUM_MAP, &temp) != NC_NOERR) {
362       /* Map does not exist */
363       if ((nc_inq_dimid(exoid, DIM_NUM_NODES, &numnodedim)) == NC_NOERR) {
364 	dims[0] = numnodedim;
365 	if ((status = nc_def_var(exoid, VAR_NODE_NUM_MAP, map_int_type, 1, dims, &temp)) != NC_NOERR) {
366 	  exerrval = status;
367 	  if (status == NC_ENAMEINUSE) {
368 	    sprintf(errmsg,
369 		    "Error: node numbering map already exists in file id %d",
370 		    exoid);
371 	  } else {
372 	    sprintf(errmsg,
373 		    "Error: failed to create node numbering map array in file id %d",
374 		    exoid);
375 	  }
376 	  ex_err("ex_put_concat_elem_block",errmsg,exerrval);
377 	  goto error_ret;         /* exit define mode and return */
378 	}
379 	ex_compress_variable(exoid, temp, 1);
380       }
381     }
382   }
383 
384   /* leave define mode  */
385   if ((status = nc_enddef(exoid)) != NC_NOERR) {
386     exerrval = status;
387     sprintf(errmsg,
388 	    "Error: failed to complete element block definition in file id %d",
389 	    exoid);
390     ex_err("ex_put_concat_elem_block",errmsg,exerrval);
391     return (EX_FATAL);
392   }
393 
394   {
395   /* Write dummy attribute name. Without this we get corruption in the
396    * attribute name.
397    */
398     size_t  start[2], count[2];
399     char *text = "";
400     count[0] = 1;
401     start[1] = 0;
402     count[1] = strlen(text)+1;
403 
404     for (iblk = 0; iblk < num_elem_blk; iblk++) {
405       size_t num_attr;
406       if (eb_array[iblk] == 0) /* Is this a NULL element block? */
407 	continue;
408       if (ex_int64_status(exoid) & EX_IDS_INT64_API) {
409 	num_attr = ((int64_t*)num_attr_this_blk)[iblk];
410       } else {
411 	num_attr = ((int*)num_attr_this_blk)[iblk];
412       }
413       for (i = 0; i < num_attr; i++) {
414 	start[0] = i;
415 	nc_put_vara_text(exoid, eb_array[iblk], start, count, text);
416       }
417     }
418   }
419   free(eb_array);
420 
421   return (EX_NOERR);
422 
423   /* Fatal error: exit definition mode and return */
424  error_ret:
425   if (nc_enddef (exoid) != NC_NOERR) {     /* exit define mode */
426     sprintf(errmsg,
427 	    "Error: failed to complete definition for file id %d",
428 	    exoid);
429     ex_err("ex_put_concat_elem_block",errmsg,exerrval);
430   }
431   return (EX_FATAL);
432 }
433 
434