• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nasa / trick / 14091947617

26 Mar 2025 07:33PM UTC coverage: 55.952% (+0.07%) from 55.886%
14091947617

Pull #1844

github

web-flow
Merge c012bcb8f into 957682f68
Pull Request #1844: Integrated MultiDtInteg classes into Trick build.

0 of 5 new or added lines in 2 files covered. (0.0%)

14 existing lines in 3 files now uncovered.

12328 of 22033 relevant lines covered (55.95%)

79740.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/trick_source/sim_services/DataRecord/DRHDF5.cpp
1
/*
2
PURPOSE:
3
    (Data record to disk in HDF5 format.)
4
PROGRAMMERS:
5
     ((Warwick Woodard) (NASA) (February 2010) (--) (Initial version))
6
*/
7

8
#include <cstring>
9
#include <iostream>
10
#include <stdlib.h>
11

12
#include "trick/DRHDF5.hh"
13
#include "trick/parameter_types.h"
14
#include "trick/command_line_protos.h"
15
#include "trick/memorymanager_c_intf.h"
16
#include "trick/message_proto.h"
17
#include "trick/bitfield_proto.h"
18

19
Trick::DRHDF5::DRHDF5( std::string in_name, Trick::DR_Type dr_type ) : Trick::DataRecordGroup(in_name, dr_type) {
×
UNCOV
20
    register_group_with_mm(this, "Trick::DRHDF5") ;
×
21
}
×
22

23
int Trick::DRHDF5::format_specific_header( std::fstream & out_stream ) {
×
UNCOV
24
    out_stream << " byte_order is HDF5" << std::endl ;
×
UNCOV
25
    return(0) ;
×
26
}
27

28
/**
29
@details
30
-# Set the file extension to ".h5"
31
-# Open the log file
32
-# Create the root directory in the HDF5 file
33
-# For each variable to be recorded
34
   -# Create a fixed length packet table
35
   -# Associate the packet table with the temporary memory buffer storing the simulation data
36
-# Declare the recording group to the memory manager so that the group can be checkpointed
37
   and restored.
38
*/
UNCOV
39
int Trick::DRHDF5::format_specific_init() {
×
40

41
#ifdef HDF5
42
    unsigned int ii ;
43
    hsize_t chunk_size = 1024;
44
    hid_t byte_id ;
45
    hid_t file_names_id, param_types_id, param_units_id, param_names_id ;
46
    hid_t datatype ;
47
    hid_t s256 ;
48
    std::string buf;
49

50
    file_name.append(".h5") ;
51

52
    s256 = H5Tcopy(H5T_C_S1);
53
    H5Tset_size(s256, 256);
54

55
    // Create a new HDF5 file with the specified name; overwrite if it exists.
56
    if ((file = H5Fcreate(file_name.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT)) < 0) {
57
        message_publish(MSG_ERROR, "Can't open Data Record file %s.\n", file_name.c_str()) ;
58
        record = false ;
59
        return -1 ;
60
    }
61

62
    // Check file validity first
63
    if (H5Iis_valid(file) <= 0) {
64
        message_publish(MSG_ERROR, "File handle invalid, id=%lld\n", (long long)file);
65
        return -1;
66
    }
67
    // All HDF5 objects live in the top-level "/" (root) group.
68
    root_group = H5Gopen(file, "/", H5P_DEFAULT);
69

70
    // Create a new group named "header" at the root ("/") level.
71
    header_group = H5Gcreate(file, "/header", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
72
    // Validate header group
73
    if (H5Iis_valid(header_group) <= 0) {
74
        message_publish(MSG_ERROR, "Header group invalid, id=%lld\n", (long long)header_group);
75
        return -1;
76
    }
77
    // Create a packet table (PT) that stores byte order.
78
    byte_id = H5PTcreate_fl(header_group, "byte_order", s256, chunk_size, 1) ;
79
    // Add the byte order value to the byte packet table.
80
    H5PTappend( byte_id, 1, byte_order.c_str() );
81
    // Create a packet table (PT) that stores each parameter's file location.
82
    file_names_id = H5PTcreate_fl(header_group, "file_names", s256, chunk_size, 1) ;
83
    // Create a packet table (PT) that stores each parameter's type.
84
    param_types_id = H5PTcreate_fl(header_group, "param_types", s256, chunk_size, 1) ;
85
    // Create a packet table (PT) that stores each parameter's unit.
86
    param_units_id = H5PTcreate_fl(header_group, "param_units", s256, chunk_size, 1) ;
87
    // Create a packet table (PT) that stores each parameter's name.
88
    param_names_id =  H5PTcreate_fl(header_group, "param_names", s256, chunk_size, 1) ;
89

90
    // Allocate memory for the parameter names
91
    param_names = new char*[rec_buffer.size()];
92
    // Allocate memory for the dataset ids
93
    param_dataset_ids = new hid_t[rec_buffer.size()];
94

95
    // Create a table for each requested parameter.
96
    for (ii = 0; ii < rec_buffer.size(); ii++) {
97

98
        /* Case statements taken from "parameter_types.h."
99
         *  HDF5 Native types found in "H5Tpublic.h." */
100
        switch (rec_buffer[ii]->ref->attr->type) {
101
            case TRICK_CHARACTER:
102
                datatype = H5T_NATIVE_CHAR;
103
                break;
104
            case TRICK_UNSIGNED_CHARACTER:
105
                datatype = H5T_NATIVE_UCHAR;
106
                break;
107
            case TRICK_STRING:
108
                datatype = s256;
109
                break;
110
            case TRICK_SHORT:
111
                datatype = H5T_NATIVE_SHORT;
112
                break;
113
            case TRICK_UNSIGNED_SHORT:
114
                datatype = H5T_NATIVE_USHORT;
115
                break;
116
            case TRICK_ENUMERATED:
117
            case TRICK_INTEGER:
118
                datatype = H5T_NATIVE_INT;
119
                break;
120
            case TRICK_UNSIGNED_INTEGER:
121
                datatype = H5T_NATIVE_UINT;
122
                break;
123
            case TRICK_LONG:
124
                datatype = H5T_NATIVE_LONG;
125
                break;
126
            case TRICK_UNSIGNED_LONG:
127
                datatype = H5T_NATIVE_ULONG;
128
                break;
129
            case TRICK_FLOAT:
130
                datatype = H5T_NATIVE_FLOAT;
131
                break;
132
            case TRICK_DOUBLE:
133
                datatype = H5T_NATIVE_DOUBLE;
134
                break;
135
            case TRICK_BITFIELD:
136
                if (rec_buffer[ii]->ref->attr->size == sizeof(int)) {
137
                    datatype = H5T_NATIVE_INT;
138
                } else if (rec_buffer[ii]->ref->attr->size == sizeof(short)) {
139
                    datatype = H5T_NATIVE_SHORT;
140
                } else {
141
                    datatype = H5T_NATIVE_CHAR;
142
                }
143
                break;
144
            case TRICK_UNSIGNED_BITFIELD:
145
                if (rec_buffer[ii]->ref->attr->size == sizeof(unsigned int)) {
146
                    datatype = H5T_NATIVE_UINT;
147
                } else if (rec_buffer[ii]->ref->attr->size == sizeof(unsigned short)) {
148
                    datatype = H5T_NATIVE_USHORT;
149
                } else {
150
                    datatype = H5T_NATIVE_UCHAR;
151
                }
152
                break;
153
            case TRICK_LONG_LONG:
154
                datatype = H5T_NATIVE_LLONG;
155
                break;
156
            case TRICK_UNSIGNED_LONG_LONG:
157
                datatype = H5T_NATIVE_ULLONG;
158
                break;
159
            case TRICK_BOOLEAN:
160
#if ( __sun | __APPLE__ )
161
                datatype = H5T_NATIVE_INT;
162
#else
163
                datatype = H5T_NATIVE_UCHAR;
164
#endif
165
                break;
166
            default:
167
                continue;
168
        }
169

170
        /* Create packet table(s) to store "fixed-length" packets.
171
         *  A separate packet table (PT) is created for each variable.
172
         * PARAMETERS:
173
         *     IN: Identifier of the file or group to create the table within.
174
         *     IN: The name of the dataset (i.e. variable).
175
         *     IN: The datatype of a packet.
176
         *     IN: The packet table uses HDF5 chunked storage to allow it to
177
         *         grow. This value allows the user to set the size of a chunk.
178
         *         The chunk size affects performance.
179
         *     IN: Compression level, a value of 0 through 9. Level 0 is faster
180
         *         but offers the least compression; level 9 is slower but
181
         *         offers maximum compression. A setting of -1 indicates that
182
         *         no compression is desired.
183
         * RETURN:
184
         *     Returns an identifier for the new packet table, or H5I_BADID on error.
185
         */
186
        // Allocate memory for the parameter names
187
        param_names[ii] = (char *)malloc(strlen(rec_buffer[ii]->ref->reference) + 1);
188
        // Copy the parameter name to the list
189
        strcpy(param_names[ii], rec_buffer[ii]->ref->reference);
190
        // Create a packet table for each parameter
191
        param_dataset_ids[ii] = H5PTcreate_fl(root_group, param_names[ii], datatype, chunk_size, 1) ;
192
        // Validate the dataset
193
        if ( param_dataset_ids[ii] == H5I_BADID ) {
194
            message_publish(MSG_ERROR, "An error occured in data record group \"%s\" when adding \"%s\".\n",
195
             group_name.c_str() , param_names[ii]) ;
196
            continue;
197
        }
198

199
        // As a bonus, add a header entry for each parameter.
200
        /* File Name */
201
        buf = "log_" + group_name ;
202
        H5PTappend( file_names_id, 1, buf.c_str() );
203
        /* Param Type */
204
        buf = type_string(rec_buffer[ii]->ref->attr->type, rec_buffer[ii]->ref->attr->size );
205
        H5PTappend( param_types_id, 1, buf.c_str() );
206
        /* Param Units */
207
        if ( rec_buffer[ii]->ref->attr->mods & TRICK_MODS_UNITSDASHDASH ) {
208
            H5PTappend( param_units_id, 1, "--" );
209
        } else {
210
            H5PTappend( param_units_id, 1, rec_buffer[ii]->ref->attr->units );
211
        }
212
        /* Param Name */
213
        H5PTappend( param_names_id, 1, rec_buffer[ii]->ref->reference );
214

215
    }
216
    H5PTclose( byte_id );
217
    H5PTclose( file_names_id );
218
    H5PTclose( param_types_id );
219
    H5PTclose( param_units_id );
220
    H5PTclose( param_names_id );
221
    H5Gclose( header_group );
222
#endif
223

UNCOV
224
    return(0);
×
225
}
226

227
#ifdef HDF5
228
/**
229
 * Helper function to append specified data records for one variable to its dataset(packet table).
230
 */
231
void append_var_packet_table(Trick::DataRecordBuffer *drb, char* buf, size_t records, hid_t param_ds) {
232
    // Data records to be appended to the packet table
233
    void* data = 0;
234
    int bf;
235

236
    switch (drb->ref->attr->type) {
237
        case TRICK_CHARACTER:
238
        case TRICK_UNSIGNED_CHARACTER:
239
        case TRICK_STRING:
240
        case TRICK_SHORT:
241
        case TRICK_UNSIGNED_SHORT:
242
        case TRICK_ENUMERATED:
243
        case TRICK_INTEGER:
244
        case TRICK_UNSIGNED_INTEGER:
245
        case TRICK_LONG:
246
        case TRICK_UNSIGNED_LONG:
247
        case TRICK_FLOAT:
248
        case TRICK_DOUBLE:
249
            H5PTappend(param_ds, records , buf);
250
            break;
251
        case TRICK_BITFIELD:
252
            bf = GET_BITFIELD(buf, drb->ref->attr->size, drb->ref->attr->index[0].start, drb->ref->attr->index[0].size);
253
            data = malloc(records * sizeof(bf));
254
            
255
            // Extract bitfield for each record from different segments of buf
256
            for (size_t j = 0; j < records; j++) {               
257
                // Calculate the correct offset in buf for each record
258
                // Each record in buf has size of rec_buffer[ii]->ref->attr->size
259
                size_t offset = j * drb->ref->attr->size;
260

261
                if (drb->ref->attr->size == sizeof(int)) {
262
                    ((int *)data)[j] = extract_bitfield_any(
263
                                                    *(int *)(buf+offset), drb->ref->attr->size,
264
                                                    drb->ref->attr->index[0].start, drb->ref->attr->index[0].size);
265
                } else if (drb->ref->attr->size == sizeof(short)) {
266
                    ((short *)data)[j] = extract_bitfield_any(
267
                                                    *(short *)(buf+offset), drb->ref->attr->size,
268
                                                    drb->ref->attr->index[0].start, drb->ref->attr->index[0].size);
269
                } else if (drb->ref->attr->size == sizeof(char)) {
270
                    ((char *)data)[j] = extract_bitfield_any(
271
                                                    *(char *)(buf+offset), drb->ref->attr->size,
272
                                                    drb->ref->attr->index[0].start, drb->ref->attr->index[0].size);
273
                } else {
274
                    ((int*)data)[j] = extract_bitfield_any(
275
                                                    *(int *)(buf+offset), drb->ref->attr->size,
276
                                                    drb->ref->attr->index[0].start, drb->ref->attr->index[0].size);
277
                }
278
            }
279
            H5PTappend(param_ds, records, data);
280
            break;
281
        case TRICK_UNSIGNED_BITFIELD:
282
            bf = GET_UNSIGNED_BITFIELD(buf, drb->ref->attr->size, drb->ref->attr->index[0].start, drb->ref->attr->index[0].size);
283
            data = malloc(records * sizeof(bf));
284

285
            // Extract bitfield for each record from different segments of buf
286
            for (size_t j = 0; j < records; j++) {               
287
                // Calculate the correct offset in buf for each record
288
                // Each record in buf has size of rec_buffer[ii]->ref->attr->size
289
                size_t offset = j * drb->ref->attr->size;  // record_size would be the size of one record in buf
290

291
                if (drb->ref->attr->size == sizeof(int)) {
292
                    ((unsigned int *)data)[j] = extract_unsigned_bitfield_any(
293
                                                    *(unsigned int *)(buf+offset), drb->ref->attr->size,
294
                                                    drb->ref->attr->index[0].start, drb->ref->attr->index[0].size);
295
                } else if (drb->ref->attr->size == sizeof(short)) {
296
                    ((unsigned short *)data)[j] = extract_unsigned_bitfield_any(
297
                                                    *(unsigned short *)(buf+offset), drb->ref->attr->size,
298
                                                    drb->ref->attr->index[0].start, drb->ref->attr->index[0].size);
299
                } else if (drb->ref->attr->size == sizeof(char)) {
300
                    ((unsigned char *)data)[j] = extract_unsigned_bitfield_any(
301
                                                    *(unsigned char *)(buf+offset), drb->ref->attr->size,
302
                                                    drb->ref->attr->index[0].start, drb->ref->attr->index[0].size);
303
                } else {
304
                    ((int *)data)[j] = extract_unsigned_bitfield_any(
305
                                                    *(int *)(buf+offset), drb->ref->attr->size,
306
                                                    drb->ref->attr->index[0].start, drb->ref->attr->index[0].size);
307
                }
308
            }
309
            H5PTappend(param_ds, records, data);
310
            break;
311
        case TRICK_LONG_LONG:
312
        case TRICK_UNSIGNED_LONG_LONG:
313
        case TRICK_BOOLEAN:
314
        default:
315
            H5PTappend(param_ds, records , buf);
316
            break;
317

318
        if (data != 0) {
319
            free(data);
320
            data = 0;
321
        }
322
    }
323
}
324
#endif
325

326
/*
327
   HDF5 logging is done on a per variable basis instead of per time step like the
328
   other recording methods.  This write_data routine overrides the default in
329
   DataRecordGroup.  This routine writes out all of the buffered data of a variable
330
   in one or two HDF5 calls.
331
*/
332
int Trick::DRHDF5::write_data(bool must_write) {
×
333

334
#ifdef HDF5
335
    unsigned int local_buffer_num ;
336
    unsigned int num_to_write ;
337
    unsigned int ii;
338
    char *buf = 0;
339
    size_t ds_records1;
340
    size_t ds_records2;
341

342
    if ( record and inited and (buffer_type == DR_No_Buffer or must_write)) {
343

344
        // buffer_mutex is used in this one place to prevent forced calls of write_data
345
        // to not overwrite data being written by the asynchronous thread.
346
        pthread_mutex_lock(&buffer_mutex) ;
347
        local_buffer_num = buffer_num ;
348
        if ( (local_buffer_num - writer_num) > max_num ) {
349
            num_to_write = max_num ;
350
        } else {
351
            num_to_write = (local_buffer_num - writer_num) ;
352
        }
353
        writer_num = local_buffer_num - num_to_write ;
354

355
        if ( writer_num != local_buffer_num ) {
356
            unsigned int writer_offset = writer_num % max_num ;
357
            // Test if the writer pointer to the right of the buffer pointer in the ring
358
            if ( (writer_num % max_num) > (local_buffer_num % max_num) ) {
359
                ds_records1 = max_num - writer_offset;
360
                ds_records2 = local_buffer_num % max_num;
361

362
                // we have 2 segments to write per variable
363
                for (ii = 0; ii < rec_buffer.size(); ii++) {
364
                    //unsigned int writer_offset = writer_num % max_num ;
365
                    buf = rec_buffer[ii]->buffer + (writer_offset * rec_buffer[ii]->ref->attr->size) ;
366
                    append_var_packet_table(rec_buffer[ii], buf, ds_records1, param_dataset_ids[ii]);
367

368
                    buf = rec_buffer[ii]->buffer ;
369
                    append_var_packet_table(rec_buffer[ii], buf, ds_records2, param_dataset_ids[ii]);
370
                }
371
            }  else {
372
                ds_records1 = local_buffer_num - writer_num;
373
                // we have 1 continous segment to write per variable
374
                for (ii = 0; ii < rec_buffer.size(); ii++) {
375
                    //unsigned int writer_offset = writer_num % max_num ;
376
                    buf = rec_buffer[ii]->buffer + (writer_offset * rec_buffer[ii]->ref->attr->size) ;
377
                    append_var_packet_table(rec_buffer[ii], buf, ds_records1, param_dataset_ids[ii]);
378
               }
379
            }
380
            writer_num = local_buffer_num ;
381
        }
382
        pthread_mutex_unlock(&buffer_mutex) ;
383

384
    }
385
#else
386
    (void)must_write;
387
#endif
UNCOV
388
    return 0 ;
×
389
}
390

391
/**
392
@details
393
-# Snapshot the index of the most recent temporary memory buffer to write to disk to curr_buffer_num
394
-# For each parameter to be recorded
395
   -# Point a pointer to the beginning of the data in the memory buffer to be written to disk
396
   -# Append one packet to the packet table.
397
*/
UNCOV
398
int Trick::DRHDF5::format_specific_write_data(unsigned int writer_offset __attribute__((unused))) {
×
399

400
#ifdef HDF5
401
    unsigned int ii;
402
    char *buf = 0;
403

404
    /* Loop through each parameter. */
405
    for (ii = 0; ii < rec_buffer.size(); ii++) {
406

407
        /* Each parameters[] element contains a DataRecordBuffer class.
408
         * So there is a seperate DataRecordBuffer per variable.
409
         * Point to the value to be recorded. */
410
        buf = rec_buffer[ii]->buffer + (writer_offset * rec_buffer[ii]->ref->attr->size) ;
411
        append_var_packet_table(rec_buffer[ii], buf, 1, param_dataset_ids[ii]);
412

413
    }
414
#endif
415

UNCOV
416
    return(0);
×
417
}
418

419
/**
420
@details
421
-# For each parameter being recorded
422
   -# Close the HDF5 packet table
423
-# Close the HDF5 root
424
-# Close the HDF5 file
425
*/
UNCOV
426
int Trick::DRHDF5::format_specific_shutdown() {
×
427

428
#ifdef HDF5
429
    unsigned int ii ;
430

431
    if ( inited ) {
432
        for (ii = 0; ii < rec_buffer.size(); ii++) {
433
            // Free parameter names memory
434
            free(param_names[ii]);
435
            // Close the parameter dataset
436
            if (param_dataset_ids[ii] != H5I_BADID) {
437
                H5PTclose(param_dataset_ids[ii]);
438
            }
439
        }
440
        // Free the parameter names array
441
        delete[] param_names;
442
        // Set the pointer to NULL
443
        param_names = nullptr;
444
        // Free the dataset ids array
445
        delete[] param_dataset_ids;
446
        // Set the pointer to NULL
447
        param_dataset_ids = nullptr;
448

449
        // Close root group
450
        H5Gclose(root_group);
451
        // Close file handle
452
        H5Fclose(file);
453

454
    }
455
#endif
UNCOV
456
    return(0);
×
457
}
458

STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc