1 /*============================================================================
2 * Base functions for writing Kernel I/O files.
3 *============================================================================*/
4
5 /*
6 This file is part of Code_Saturne, a general-purpose CFD tool.
7
8 Copyright (C) 1998-2021 EDF S.A.
9
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 details.
19
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22 Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24
25 /*----------------------------------------------------------------------------*/
26
27 #include "ecs_def.h"
28
29 /*----------------------------------------------------------------------------
30 * Standard C library headers
31 *----------------------------------------------------------------------------*/
32
33 #include <assert.h>
34 #include <errno.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 /*----------------------------------------------------------------------------
40 * Local headers
41 *----------------------------------------------------------------------------*/
42
43 #include "ecs_def.h"
44 #include "ecs_file.h"
45 #include "ecs_mem.h"
46
47 /*----------------------------------------------------------------------------
48 * Headers for the current file
49 *----------------------------------------------------------------------------*/
50
51 #include "ecs_comm.h"
52
53 /*----------------------------------------------------------------------------*/
54
55 BEGIN_C_DECLS
56
57 /*=============================================================================
58 * Macro definitions
59 *============================================================================*/
60
61 /*=============================================================================
62 * Local type definitions
63 *============================================================================*/
64
65 /*----------------------------------------------------------------------------
66 * Structure defining an output writer
67 *----------------------------------------------------------------------------*/
68
69 struct _ecs_comm_t {
70
71 char *name; /* Writer name */
72
73 ecs_file_t *f; /* Associated file structure pointer */
74
75 size_t header_size; /* Header default size */
76 size_t header_align; /* Header alignment */
77 size_t body_align; /* Body alignment */
78
79 size_t cur_pos; /* Current position in file */
80
81 };
82
83 /*============================================================================
84 * Local function defintions
85 *============================================================================*/
86
87 /*----------------------------------------------------------------------------
88 * Write padding zeroes to ensure following alignement if necessary
89 *----------------------------------------------------------------------------*/
90
91 static void
_write_pad(ecs_comm_t * comm,size_t alignment)92 _write_pad(ecs_comm_t *comm,
93 size_t alignment)
94 {
95 size_t pad_size = (alignment - (comm->cur_pos % alignment)) % alignment;
96
97 if (pad_size > 0) {
98
99 char padding[128] = "";
100 size_t rem_size = pad_size;
101
102 memset(padding, 0, sizeof(padding));
103
104 while (rem_size > 0) {
105 size_t write_size = ECS_MIN(rem_size, sizeof(padding));
106 ecs_file_write(padding, 1, write_size, comm->f);
107 rem_size -= write_size;
108 }
109
110 comm->cur_pos += pad_size;
111 }
112 }
113
114 /*----------------------------------------------------------------------------
115 * Write a record to the interface file
116 *----------------------------------------------------------------------------*/
117
118 static void
_write_rec(ecs_comm_t * comm,const void * rec,size_t n_elts,ecs_type_t datatype)119 _write_rec(ecs_comm_t *comm,
120 const void *rec,
121 size_t n_elts,
122 ecs_type_t datatype)
123 {
124 size_t t_size = 0;
125
126 assert(comm != NULL);
127 assert(rec != NULL);
128
129 /* Determine size associated with type */
130
131 switch (datatype) {
132 case ECS_TYPE_ecs_int_t:
133 t_size = sizeof(ecs_int_t);
134 break;
135 case ECS_TYPE_ecs_coord_t:
136 t_size = sizeof(ecs_coord_t);
137 break;
138 case ECS_TYPE_ecs_size_t:
139 t_size = sizeof(ecs_size_t);
140 break;
141 case ECS_TYPE_char:
142 t_size = sizeof(char);
143 break;
144 case ECS_TYPE_size_t:
145 t_size = 8;
146 break;
147 default:
148 assert( datatype == ECS_TYPE_ecs_int_t
149 || datatype == ECS_TYPE_ecs_coord_t
150 || datatype == ECS_TYPE_ecs_size_t
151 || datatype == ECS_TYPE_size_t
152 || datatype == ECS_TYPE_char);
153 }
154
155 /* write record to file */
156 /*----------------------*/
157
158 if (datatype != ECS_TYPE_size_t || sizeof(size_t) == 8) {
159 ecs_file_write(rec, t_size, n_elts, comm->f);
160 comm->cur_pos += n_elts*t_size;
161 }
162
163 else { /* if (datatype == ECS_TYPE_size_t && sizeof(size_t) != 8) */
164
165 size_t i;
166
167 assert(sizeof(unsigned long long) == 8);
168
169 for (i = 0; i < n_elts; i++) {
170 const unsigned char *rp = rec;
171 unsigned long long _rec = *((const size_t *)(rp + i*sizeof(size_t)));
172 assert(sizeof(long long) == 8);
173 ecs_file_write(&_rec, 8, 1, comm->f);
174 comm->cur_pos += 8;
175 }
176
177 }
178 }
179
180 /*----------------------------------------------------------------------------
181 * Open output file and write base file description headers
182 *----------------------------------------------------------------------------*/
183
184 static void
_file_open(ecs_comm_t * comm,const char * file_name)185 _file_open(ecs_comm_t *comm,
186 const char *file_name)
187 {
188 char header[64] = "";
189 size_t sizes[3] = {comm->header_size,
190 comm->header_align,
191 comm->body_align};
192
193 memset(header, 0, 64);
194
195 /* BE stands for big-endian, allowing for future
196 native file mode generation, using BE/LE */
197
198 strncpy(header, "Code_Saturne I/O, BE, R0", 63);
199
200 /* Open file */
201
202 comm->f = ecs_file_open(file_name,
203 ECS_FILE_MODE_WRITE,
204 ECS_FILE_TYPE_BINARY);
205
206 ecs_file_set_big_endian(comm->f);
207
208 /* Write header and comment information */
209
210 _write_rec(comm, header, 64, ECS_TYPE_char);
211
212 memset(header, 0, 64);
213 strncpy(header, "Face-based mesh definition, R0", 63);
214
215 _write_rec(comm, header, 64, ECS_TYPE_char);
216
217 _write_rec(comm, sizes, 3, ECS_TYPE_size_t);
218 }
219
220 /*----------------------------------------------------------------------------
221 * Echo section output data
222 *----------------------------------------------------------------------------*/
223
224 static void
_echo_header(const char * name,size_t n_values,const char * datatype_name)225 _echo_header(const char *name,
226 size_t n_values,
227 const char *datatype_name)
228 {
229 char name_pad[33] = "";
230 char type_pad[3] = "";
231
232 if (strlen(name) < 32) {
233 memset(name_pad, ' ', sizeof(name_pad));
234 name_pad[32 - strlen(name)] = '\0';
235 }
236 if (strlen(datatype_name) < 2) {
237 type_pad[0] = ' '; type_pad[1] = ' ';
238 type_pad[2 - strlen(datatype_name)] = '\0';
239 }
240
241 if (n_values > 0)
242 printf(_(" Wrote: \"%s\"%s; Type: \"%s\"%s; Size: %lu\n"),
243 name, name_pad, datatype_name, type_pad,
244 (unsigned long)n_values);
245
246 else
247 printf(_(" Wrote: \"%s\"\n"),
248 name);
249
250 fflush(stdout);
251 }
252
253 /*============================================================================
254 * Public function definitions
255 *============================================================================*/
256
257 ecs_comm_t *
ecs_comm_initialize(const char * file_name)258 ecs_comm_initialize(const char *file_name)
259 {
260 ecs_comm_t * comm = NULL;
261
262 /* Create structure */
263
264 ECS_MALLOC(comm, 1, ecs_comm_t);
265
266 ECS_MALLOC(comm->name, strlen(file_name) + 1, char);
267
268 strcpy(comm->name, file_name);
269
270 /* Initialize other fields */
271
272 comm->header_size = 96;
273 comm->header_align = 64;
274 comm->body_align = 64;
275 comm->cur_pos = 0;
276
277 comm->f = NULL;
278
279 /* Jump a line in log file */
280
281 printf("\n");
282
283 /* Info on interface creation */
284
285 printf(_(" Opening file: %s\n"),
286 comm->name);
287
288 printf("\n");
289
290 fflush(stdout);
291
292 /* Create file descriptor */
293
294 _file_open(comm, file_name);
295
296 return comm;
297 }
298
299 /*----------------------------------------------------------------------------
300 * Close writer.
301 *
302 * arguments:
303 * comm <-- pointer to writer structure pointer
304 *----------------------------------------------------------------------------*/
305
306 void
ecs_comm_finalize(ecs_comm_t ** comm)307 ecs_comm_finalize(ecs_comm_t **comm)
308 {
309 ecs_comm_t *_comm = *comm;
310
311 printf("\n");
312
313 printf(_(" Closing file: %s\n"),
314 _comm->name);
315
316 if (_comm->f != NULL)
317 _comm->f = ecs_file_free(_comm->f);
318
319 ECS_FREE(_comm->name);
320
321 ECS_FREE(_comm);
322
323 *comm = _comm;
324 }
325
326 /*----------------------------------------------------------------------------
327 * Write a section to the Kernel I/O file.
328 *
329 * Grid locations and possibly indexes may be assigned to a section by
330 * specifying a location id; the first time a given location id appears in
331 * the file is considered a declaration. In the same manner, an index id
332 * may be specified. Values of zero indicate no location or index base
333 * is used. It is up to the calling code to ensure that total number of
334 * values, location size, and number of values per location are consistent,
335 * as this my be important for code reading the file.
336 *
337 * arguments:
338 * name <-- section name
339 * location_id <-- id of associated location
340 * index_id <-- id of associated index
341 * n_location_values <-- number of values per location
342 * embed <-- embed values in header
343 * values <-- values to write
344 * value_type <-- type of value to write
345 * comm <-- Kernel I/O file output structure
346 *----------------------------------------------------------------------------*/
347
348 void
ecs_comm_write_section(const char * name,size_t n_values,size_t location_id,size_t index_id,size_t n_location_values,bool embed,const void * values,ecs_type_t value_type,ecs_comm_t * comm)349 ecs_comm_write_section(const char *name,
350 size_t n_values,
351 size_t location_id,
352 size_t index_id,
353 size_t n_location_values,
354 bool embed,
355 const void *values,
356 ecs_type_t value_type,
357 ecs_comm_t *comm)
358 {
359 /* Section is defined by:
360
361 section size (in bytes): 8 bytes
362 n_elts, location_id, index_id, n_location_values: 4*8 bytes
363 name_size (including padding to 8 byte alignment): 8 bytes
364 datatype_name: 8 bytes (bit 6 = '\0', bit 7 = embed flag)
365 section name: strlen(name) + 1 + padding to 8 bytes
366 optional embedded data: n_values*value_type_size
367 */
368
369 size_t header_sizes[6] = {56, /* 6*8 +8 */
370 n_values,
371 location_id,
372 index_id,
373 n_location_values,
374 0};
375 size_t name_size = 0;
376 size_t name_pad_size = 0;
377 size_t data_size = 0;
378 char datatype_name[8];
379 char name_pad[8];
380
381 assert(comm != NULL);
382 assert(name != NULL);
383
384 /* Initialization */
385
386 memset(datatype_name, 0, sizeof(datatype_name));
387 memset(name_pad, 0, sizeof(name_pad));
388
389 /* Section name */
390
391 name_size = strlen(name);
392 name_pad_size = 8-(name_size%8); /* At least 1 NULL
393 character with this rule */
394
395 header_sizes[0] += (name_size + name_pad_size);
396 header_sizes[5] = (name_size + name_pad_size);
397
398 /* Value type name */
399
400 if (n_values > 0) {
401
402 switch(value_type) {
403
404 case ECS_TYPE_ecs_int_t:
405
406 switch(sizeof(ecs_int_t)) {
407 case 4:
408 strcpy(datatype_name, "i4");
409 break;
410 case 8:
411 strcpy(datatype_name, "i8");
412 break;
413 default:
414 assert(sizeof(ecs_int_t) == 4 || sizeof(ecs_int_t) == 8);
415 }
416 break;
417
418 case ECS_TYPE_ecs_coord_t:
419
420 switch(sizeof(ecs_coord_t)) {
421 case 4:
422 strcpy(datatype_name, "r4");
423 break;
424 case 8:
425 strcpy(datatype_name, "r8");
426 break;
427 default:
428 assert(sizeof(ecs_coord_t) == 4 || sizeof(ecs_coord_t) == 8);
429 }
430 break;
431
432 case ECS_TYPE_ecs_size_t:
433
434 switch(sizeof(ecs_size_t)) {
435 case 4:
436 strcpy(datatype_name, "u4");
437 break;
438 case 8:
439 strcpy(datatype_name, "u8");
440 break;
441 default:
442 assert(sizeof(ecs_size_t) == 4 || sizeof(ecs_size_t) == 8);
443 }
444 break;
445
446 case ECS_TYPE_size_t:
447
448 strcpy(datatype_name, "u8");
449 break;
450
451 case ECS_TYPE_char:
452
453 strcpy(datatype_name, "c ");
454 break;
455
456 default:
457
458 assert( value_type == ECS_TYPE_ecs_int_t
459 || value_type == ECS_TYPE_ecs_coord_t
460 || value_type == ECS_TYPE_ecs_size_t
461 || value_type == ECS_TYPE_size_t
462 || value_type == ECS_TYPE_char);
463
464
465 } /* End of switch on value_type */
466
467 }
468
469 if (embed == true) {
470
471 datatype_name[7] = 'e';
472
473 if (datatype_name[1] == '4')
474 data_size = 4*n_values;
475 else if (datatype_name[1] == '8')
476 data_size = 8*n_values;
477 else
478 data_size = n_values;
479
480 header_sizes[0] += data_size;
481
482 }
483
484 /* Only output data if file exists */
485
486 if (comm->f != NULL) {
487
488 /* Align if necessary */
489
490 _write_pad(comm, comm->header_align);
491
492 /* Write sizes */
493
494 _write_rec(comm, header_sizes, 6, ECS_TYPE_size_t);
495
496 /* Type information */
497
498 _write_rec(comm, datatype_name, 8, ECS_TYPE_char);
499
500 /* Section name */
501
502 _write_rec(comm, name, name_size, ECS_TYPE_char);
503 _write_rec(comm, name_pad, name_pad_size, ECS_TYPE_char);
504
505 /* Embedded values */
506
507 if (n_values > 0 && embed == true)
508 _write_rec(comm, values, n_values, value_type);
509
510 /* Ensure header is at least the size of the basic header block size,
511 as reads may read at least this much data */
512
513 if (header_sizes[0] < comm->header_size) {
514 char header_pad[64];
515 size_t header_pad_size = comm->header_size - header_sizes[0];
516 memset(header_pad, 0, sizeof(header_pad));
517 while (header_pad_size > 0) {
518 size_t write_size = ECS_MIN(header_pad_size, sizeof(header_pad));
519 ecs_file_write(header_pad, 1, write_size, comm->f);
520 header_pad_size -= write_size;
521 comm->cur_pos += write_size;
522 }
523 }
524
525 /* If values are not embedded, handle separate value block */
526
527 if (n_values > 0 && embed == false) {
528
529 _write_pad(comm, comm->body_align);
530 _write_rec(comm, values, n_values, value_type);
531
532 }
533
534 }
535
536 /* Print message */
537
538 _echo_header(name, n_values, datatype_name);
539 }
540
541 /*----------------------------------------------------------------------------*/
542
543 END_C_DECLS
544
545