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

nasa / trick / 22683480808

04 Mar 2026 06:31PM UTC coverage: 55.595%. First build
22683480808

Pull #2062

github

web-flow
Merge 7680e3ecb into 43b8fa7c8
Pull Request #2062: Integration loop DR recording

30 of 75 new or added lines in 3 files covered. (40.0%)

12565 of 22601 relevant lines covered (55.59%)

307682.0 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

NEW
19
Trick::DRHDF5::DRHDF5( std::string in_name, bool register_group, Trick::DR_Type dr_type ) : Trick::DataRecordGroup(in_name, dr_type) {
×
NEW
20
    if ( register_group ) {
×
NEW
21
        register_group_with_mm(this, "Trick::DRHDF5") ;
×
22
    }
23
}
×
24

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

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

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

52
    file_name.append(".h5") ;
53

54
    s256 = H5Tcopy(H5T_C_S1);
55
    H5Tset_size(s256, 256);
56

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

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

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

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

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

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

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

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

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

226
    return(0);
×
227
}
228

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

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

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

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

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

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

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

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

344
    if ( record and inited and (buffer_type == DR_No_Buffer or must_write)) {
345

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

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

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

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

386
    }
387
#else
388
    (void)must_write;
389
#endif
390
    return 0 ;
×
391
}
392

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

402
#ifdef HDF5
403
    unsigned int ii;
404
    char *buf = 0;
405

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

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

415
    }
416
#endif
417

418
    return(0);
×
419
}
420

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

430
#ifdef HDF5
431
    unsigned int ii ;
432

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

451
        // Close root group
452
        H5Gclose(root_group);
453
        // Close file handle
454
        H5Fclose(file);
455

456
    }
457
#endif
458
    return(0);
×
459
}
460

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