tensorfield.h
3.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#ifndef TIRA_TENSORFIELD
#define TIRA_TENSORFIELD
#include <valarray>
#include <string>
#include <fstream>
#include <initializer_list>
enum tira_floattype {unused0, unused1, float16, unused3, float32, unused4, unused5, unused6, unused7, float64};
enum tira_error {TIRA_SUCCESS, TIRA_UNDEFINED, TIRA_FILE_OPEN_ERROR, TIRA_UNKNOWN_FILE_TYPE};
enum tira_filetype {unused, spectrum, tensor2};
struct tira_header {
std::valarray<size_t> shape; //stores the resolution of the tensor field along each dimension
tira_filetype filetype; //stores the file type
tira_floattype datatype; //stores the data type of the tensor field
float version; //file version
};
tira_error tira_load_header(std::ifstream &infile, tira_header &header) {
//see if the file represents a TIRA structure
unsigned char TIRA[5];
TIRA[4] = 0;
infile.read((char*)TIRA, 4);
if (strcmp((char*)TIRA, "TIRA") != 0)
return TIRA_UNKNOWN_FILE_TYPE;
//get the file type
infile.read((char*)&(header.filetype), sizeof(tira_filetype));
//get the version
infile.read((char*)&(header.version), sizeof(float));
//get the number of dimensions in the field
size_t ndim;
infile.read((char*)&ndim, sizeof(size_t));
header.shape.resize(ndim);
//read each dimension
for (int d = 0; d < ndim; d++)
infile.read((char*)&(header.shape[d]), sizeof(size_t));
//read the data type
infile.read((char*)&(header.datatype), sizeof(tira_floattype));
return TIRA_SUCCESS;
}
template <typename T>
class tensorfield {
public:
std::valarray<size_t> shape; //number of samples in each dimension
std::valarray<size_t> cum_offsets; //cumulative factors for fast array accesses
tira_filetype filetype; //stores the file type
tira_floattype datatype; //stores the data type of the tensor field
T* ptr; //pointer to the raw tensor data
void init() {
size_t ndims = shape.size(); //get the number of dimensions
cum_offsets.resize(ndims); //allocate space for the cumulative offsets
size_t cum = 1;
for (int i = 0; i < ndims; i++) {
cum_offsets[ndims - 1 - i] = cum;
cum *= shape[ndims - 1 - i];
}
}
size_t bytes() {
size_t product = 1;
for (size_t i = 0; i < shape.size(); i++)
product *= shape[i];
return product * (size_t)datatype;
}
// Function turns a series of array indices into a 1D index to the corresponding element
inline size_t idx(std::initializer_list<size_t> coords) {
size_t index = 0;
size_t i = 0;
for (auto c : coords) {
index += c * cum_offsets[i];
i++;
}
return index;
}
tira_error load_tira(std::string filename) {
//open the file for binary reading
std::ifstream infile(filename, std::ios::binary);
if (!infile) return TIRA_FILE_OPEN_ERROR;
tira_header header;
tira_load_header(infile, header);
shape = header.shape;
filetype = header.filetype;
datatype = header.datatype;
//allocate space in memory for the tensor field
size_t size_bytes = bytes();
ptr = (T*)malloc(size_bytes);
//copy data from the file to memory
infile.read((char*)ptr, bytes());
//close the file
infile.close();
//initialize all internal variables
init();
return TIRA_SUCCESS;
}
T& operator()(size_t x, size_t y, size_t z, size_t r, size_t c) {
size_t i = idx({ z, y, x, r, c });
return ptr[i];
}
};
#endif