Blame view

tensorfield.h 3.24 KB
e4667cee   David Mayerich   first commit
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