Commit 9b2a5d713cf6d32a0ba1072319cfa83f4d9ad79a

Authored by David Mayerich
1 parent 2ce6954b

implemented finite differences and SG filters in stim::envi

matlab/fd_coefficients.m 0 โ†’ 100644
  1 +function c = fd_coefficients(z,x,m)
  2 +% Calculates FD weights. The parameters are:
  3 +% z location where approximations are to be accurate,
  4 +% x vector with x-coordinates for grid points,
  5 +% m highest derivative that we want to find weights for
  6 +% c array size m+1,lentgh(x) containing (as output) in
  7 +% successive rows the weights for derivatives 0,1,...,m.
  8 +
  9 +n=length(x); c=zeros(m+1,n); c1=1; c4=x(1)-z; c(1,1)=1;
  10 +for i=2:n
  11 + mn=min(i,m+1); c2=1; c5=c4; c4=x(i)-z;
  12 + for j=1:i-1
  13 + c3=x(i)-x(j); c2=c2*c3;
  14 + if j==i-1
  15 + c(2:mn,i)=c1*((1:mn-1)'.*c(1:mn-1,i-1)-c5*c(2:mn,i-1))/c2;
  16 + c(1,i)=-c1*c5*c(1,i-1)/c2;
  17 + end
  18 + c(2:mn,j)=(c4*c(2:mn,j)-(1:mn-1)'.*c(1:mn-1,j))/c3;
  19 + c(1,j)=c4*c(1,j)/c3;
  20 + end
  21 + c1=c2;
  22 +end
0 23 \ No newline at end of file
... ...
matlab/sg_coefficients.m 0 โ†’ 100644
  1 +function C = sg_coefficients(n, order)
  2 +
  3 +if(mod(n, 2) == 0)
  4 + disp('The number of coefficients must be odd');
  5 + return;
  6 +end
  7 +
  8 +%assemble the column vector based on positions
  9 +r = floor(n/2); %maximum extent around zero (0)
  10 +x = -r:1:r;
  11 +
  12 +%calculate J
  13 +J = zeros(n, order + 1);
  14 +
  15 +%columns values are 1, x_i, x_i^2, ...
  16 +for i = 1:order+1
  17 + J(:, i) = (x').^(i-1);
  18 +end
  19 +C = (J' * J)^(-1) * J';
0 20 \ No newline at end of file
... ...
stim/envi/bil.h
... ... @@ -1174,7 +1174,106 @@ public:
1174 1174 }
1175 1175 }
1176 1176  
  1177 + /// Convolve the given band range with a kernel specified by a vector of coefficients.
1177 1178  
  1179 + /// @param outfile is an already open stream to the output file
  1180 + /// @param C is an array of coefficients
  1181 + /// @param start is the band to start processing (the first coefficient starts here)
  1182 + /// @param nbands is the number of bands to process
  1183 + /// @param center is the index for the center coefficient for the kernel (used to set the wavelengths in the output file)
  1184 +
  1185 + void convolve(std::string outfile, std::vector<double> C, size_t start, size_t end, bool PROGRESS = false){
  1186 + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing
  1187 + size_t B = end - start + 1;
  1188 + size_t Xb = X() * sizeof(T); //calculate the size of a band (frame) in bytes
  1189 + size_t XBb = Xb * Z();
  1190 +
  1191 + size_t N = C.size(); //get the number of bands that the kernel spans
  1192 + std::deque<T*> frame(N, NULL); //create an array to store pointers to each frame
  1193 + for(size_t f = 0; f < N; f++)
  1194 + frame[f] = (T*)malloc(Xb); //allocate space for the frame
  1195 +
  1196 + T* outline = (T*)malloc(Xb); //allocate space for the output band
  1197 +
  1198 + //Implementation: In order to minimize reads from secondary storage, each band is only loaded once into the 'frame' deque.
  1199 + // When a new band is loaded, the last band is popped, a new frame is copied to the pointer, and it is
  1200 + // re-inserted into the deque.
  1201 + for(size_t y = 0; y < Y(); y++){
  1202 + file.seekg(y * XBb + start * Xb, std::ios::beg); //move to the beginning of the 'start' band
  1203 + for(size_t f = 0; f < N; f++) //for each frame
  1204 + file.read((char*)frame[f], Xb); //load the frame
  1205 + for(size_t b = 0; b < B; b++){ //for each band
  1206 + memset(outline, 0, Xb); //set the output band to zero (0)
  1207 + for(size_t c = 0; c < N; c++){ //for each frame (corresponding to each coefficient)
  1208 + for(size_t x = 0; x < X(); x++){ //for each pixel
  1209 + outline[x] += (T)(C[c] * frame[c][x]); //calculate the contribution of the current frame (scaled by the corresponding coefficient)
  1210 + }
  1211 + }
  1212 + out.write((char*)outline, Xb); //output the band
  1213 + file.read((char*)frame[0], Xb); //read the next band
  1214 + frame.push_back(frame.front()); //put the first element in the back
  1215 + frame.pop_front(); //pop the first element
  1216 + }
  1217 + if(PROGRESS) progress = (double)(y+1) / (double)Y() * 100;
  1218 + }
  1219 + }
  1220 +
  1221 + /// Approximate the spectral derivative of the image
  1222 +
  1223 + void deriv(std::string outfile, size_t d, size_t order, const std::vector<double> w = std::vector<double>(), bool PROGRESS = false){
  1224 + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing
  1225 +
  1226 + size_t Xb = X() * sizeof(T); //calculate the size of a line (frame) in bytes
  1227 + size_t XBb = Xb * Z();
  1228 + size_t B = Z();
  1229 +
  1230 + file.seekg(0, std::ios::beg); //seek to the beginning of the file
  1231 +
  1232 + size_t N = order + d; //approximating a derivative requires order + d samples
  1233 + std::deque<T*> frame(N, NULL); //create an array to store pointers to each frame
  1234 + for(size_t f = 0; f < N; f++) //for each frame
  1235 + frame[f] = (T*)malloc(Xb); //allocate space for the frame
  1236 +
  1237 + T* outline = (T*)malloc(Xb); //allocate space for the output band
  1238 +
  1239 + //Implementation: In order to minimize reads from secondary storage, each band is only loaded once into the 'frame' deque.
  1240 + // When a new band is loaded, the last band is popped, a new frame is copied to the pointer, and it is
  1241 + // re-inserted into the deque.
  1242 + size_t mid = (size_t)(N / 2); //calculate the mid point of the kernel
  1243 + size_t iw; //index to the first wavelength used to evaluate the derivative at this band
  1244 +
  1245 + for(size_t y = 0; y < Y(); y++){
  1246 + //file.seekg(y * XBb, std::ios::beg); //seek to the beginning of the current Y plane
  1247 + for(size_t f = 0; f < N; f++) //for each frame
  1248 + file.read((char*)frame[f], Xb); //load a line
  1249 +
  1250 + for(size_t b = 0; b < B; b++){ //for each band
  1251 + if(b < mid) //calculate the first wavelength used to evaluate the derivative at this band
  1252 + iw = 0;
  1253 + else if(b > B - (N - mid + 1))
  1254 + iw = B - N;
  1255 + else{
  1256 + iw = b - mid;
  1257 + file.read((char*)frame[0], Xb); //read the next band
  1258 + frame.push_back(frame.front()); //put the first element in the back
  1259 + frame.pop_front(); //pop the first element
  1260 + }
  1261 + std::vector<double> w_pts(w.begin() + iw, w.begin() + iw + N); //get the wavelengths corresponding to each sample
  1262 + std::vector<double> C = diff_coefficients(w[b], w_pts, d); //get the optimal sample weights
  1263 +
  1264 + memset(outline, 0, Xb); //set the output band to zero (0)
  1265 + for(size_t c = 0; c < N; c++){ //for each frame (corresponding to each coefficient)
  1266 + for(size_t x = 0; x < X(); x++){ //for each pixel
  1267 + outline[x] += (T)(C[c] * frame[c][x]); //calculate the contribution of the current frame (scaled by the corresponding coefficient)
  1268 + }
  1269 + }
  1270 + out.write((char*)outline, Xb); //output the band
  1271 +
  1272 + }
  1273 + if(PROGRESS) progress = (double)(y+1) / (double)Y() * 100;
  1274 + }
  1275 +
  1276 + }
1178 1277  
1179 1278 /// Close the file.
1180 1279 bool close(){
... ...
stim/envi/bip.h
... ... @@ -1250,6 +1250,99 @@ public:
1250 1250 }
1251 1251 }
1252 1252  
  1253 + /// Convolve the given band range with a kernel specified by a vector of coefficients.
  1254 +
  1255 + /// @param outfile is an already open stream to the output file
  1256 + /// @param C is an array of coefficients
  1257 + /// @param start is the band to start processing (the first coefficient starts here)
  1258 + /// @param nbands is the number of bands to process
  1259 + /// @param center is the index for the center coefficient for the kernel (used to set the wavelengths in the output file)
  1260 +
  1261 + void convolve(std::string outfile, std::vector<double> C, size_t start, size_t end, bool PROGRESS = false){
  1262 + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing
  1263 +
  1264 + size_t N = end - start + 1; //number of bands in the output spectrum
  1265 + size_t Nb = N * sizeof(T); //size of the output spectrum in bytes
  1266 + size_t B = Z(); //calculate the number of values in a spectrum
  1267 + size_t Bb = B * sizeof(T); //calculate the size of a spectrum in bytes
  1268 +
  1269 + file.seekg(0, std::ios::beg); //move to the beginning of the input file
  1270 +
  1271 + size_t nC = C.size(); //get the number of bands that the kernel spans
  1272 + T* inspec = (T*)malloc(Bb); //allocate space for the input spectrum
  1273 + T* outspec = (T*)malloc(Nb); //allocate space for the output spectrum
  1274 +
  1275 + size_t XY = X() * Y(); //number of pixels in the image
  1276 + for(size_t xy = 0; xy < XY; xy++){ //for each pixel
  1277 + file.read((char*)inspec, Bb); //read an input spectrum
  1278 + memset(outspec, 0, Nb); //set the output spectrum to zero (0)
  1279 + for(size_t b = 0; b < N; b++){ //for each component of the spectrum
  1280 + for(size_t c = 0; c < nC; c++){ //for each coefficient in the kernel
  1281 + outspec[b] += (T)(inspec[b + start + c] * C[c]); //perform the sum/multiply part of the convolution
  1282 + }
  1283 + }
  1284 + out.write((char*)outspec, Nb); //output the band
  1285 + if(PROGRESS) progress = (double)(xy+1) / (double)XY * 100;
  1286 + }
  1287 + }
  1288 +
  1289 + void deriv(std::string outfile, size_t d, size_t order, const std::vector<double> w, bool PROGRESS = false){
  1290 + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing
  1291 +
  1292 +
  1293 + size_t B = Z(); //calculate the number of values in a spectrum
  1294 + size_t Bb = B * sizeof(T); //calculate the size of a spectrum in bytes
  1295 +
  1296 + bool UNIFORM = true;
  1297 + double ds = w[1] - w[0]; //initialize ds
  1298 + for(size_t b = 1; b < B; b++) //test to see if the spectral spacing is uniform (if it is, convolution is much faster)
  1299 + if(w[b] - w[b-1] != ds) UNIFORM = false;
  1300 +
  1301 + size_t nC = order + d; //approximating a derivative requires order + d samples
  1302 +
  1303 + file.seekg(0, std::ios::beg); //move to the beginning of the input file
  1304 +
  1305 + T* inspec = (T*)malloc(Bb); //allocate space for the input spectrum
  1306 + T* outspec = (T*)malloc(Bb); //allocate space for the output spectrum
  1307 +
  1308 + size_t XY = X() * Y(); //number of pixels in the image
  1309 + size_t mid = (size_t)(nC / 2); //calculate the mid point of the kernel
  1310 + size_t iw; //index to the first wavelength used to evaluate the derivative at this band
  1311 + for(size_t xy = 0; xy < XY; xy++){ //for each pixel
  1312 + file.read((char*)inspec, Bb); //read an input spectrum
  1313 + memset(outspec, 0, Bb); //set the output spectrum to zero (0)
  1314 +
  1315 + iw = 0;
  1316 + for(size_t b = 0; b < mid; b++){ //for each component of the spectrum
  1317 + std::vector<double> w_pts(w.begin() + iw, w.begin() + iw + nC); //get the wavelengths corresponding to each sample
  1318 + std::vector<double> C = diff_coefficients(w[b], w_pts, d); //get the optimal sample weights
  1319 + for(size_t c = 0; c < nC; c++) //for each coefficient in the kernel
  1320 + outspec[b] += (T)(inspec[iw + c] * C[c]); //perform the sum/multiply part of the convolution
  1321 + }
  1322 + std::vector<double> w_pts(w.begin(), w.begin() + nC); //get the wavelengths corresponding to each sample
  1323 + std::vector<double> C = diff_coefficients(w[0], w_pts, d); //get the optimal sample weights
  1324 + for(size_t b = mid; b <= B - (nC - mid); b++){
  1325 + iw = b - mid;
  1326 + if(!UNIFORM){ //if the spacing is non-uniform, we have to re-calculate these points every iteration
  1327 + std::vector<double> w_pts(w.begin() + iw, w.begin() + iw + nC); //get the wavelengths corresponding to each sample
  1328 + std::vector<double> C = diff_coefficients(w[b], w_pts, d); //get the optimal sample weights
  1329 + }
  1330 + for(size_t c = 0; c < nC; c++) //for each coefficient in the kernel
  1331 + outspec[b] += (T)(inspec[iw + c] * C[c]); //perform the sum/multiply part of the convolution
  1332 + }
  1333 + iw = B - nC;
  1334 + for(size_t b = B - (nC - mid) + 1; b < B; b++){
  1335 + std::vector<double> w_pts(w.begin() + iw, w.begin() + iw + nC); //get the wavelengths corresponding to each sample
  1336 + std::vector<double> C = diff_coefficients(w[b], w_pts, d); //get the optimal sample weights
  1337 + for(size_t c = 0; c < nC; c++) //for each coefficient in the kernel
  1338 + outspec[b] += (T)(inspec[iw + c] * C[c]); //perform the sum/multiply part of the convolution
  1339 + }
  1340 +
  1341 + out.write((char*)outspec, Bb); //output the band
  1342 + if(PROGRESS) progress = (double)(xy+1) / (double)XY * 100;
  1343 + }
  1344 + }
  1345 +
1253 1346  
1254 1347  
1255 1348 /// Close the file.
... ...
stim/envi/bsq.h
... ... @@ -7,6 +7,7 @@
7 7 #include <cstring>
8 8 #include <utility>
9 9 #include <vector>
  10 +#include <deque>
10 11  
11 12  
12 13  
... ... @@ -1058,6 +1059,128 @@ public:
1058 1059 out.write((char*)dst, band_dst_bytes); //write the combined image to an output file
1059 1060 if(PROGRESS) progress = (double)(b + 1) / (double) Z() * 100;
1060 1061 }
  1062 + out.close();
  1063 + }
  1064 +
  1065 + /// Convolve the given band range with a kernel specified by a vector of coefficients.
  1066 +
  1067 + /// @param outfile is an already open stream to the output file
  1068 + /// @param C is an array of coefficients
  1069 + /// @param start is the band to start processing (the first coefficient starts here)
  1070 + /// @param nbands is the number of bands to process
  1071 + /// @param center is the index for the center coefficient for the kernel (used to set the wavelengths in the output file)
  1072 +
  1073 + void convolve(std::ofstream& out, std::vector<double> C, size_t start, size_t end, bool PROGRESS = false){
  1074 + size_t nbands = end - start + 1;
  1075 + size_t XY = X() * Y(); //calculate the number of values in a band
  1076 + size_t XYb = XY * sizeof(T); //calculate the size of a band (frame) in bytes
  1077 +
  1078 + file.seekg(XYb * start, std::ios::beg); //move to the beginning of the 'start' band
  1079 +
  1080 + size_t nframes = C.size(); //get the number of bands that the kernel spans
  1081 + std::deque<T*> frame(nframes, NULL); //create an array to store pointers to each frame
  1082 + for(size_t f = 0; f < nframes; f++){ //for each frame
  1083 + frame[f] = (T*)malloc(XYb); //allocate space for the frame
  1084 + file.read((char*)frame[f], XYb); //load the frame
  1085 + }
  1086 +
  1087 + T* outband = (T*)malloc(XYb); //allocate space for the output band
  1088 +
  1089 + //Implementation: In order to minimize reads from secondary storage, each band is only loaded once into the 'frame' deque.
  1090 + // When a new band is loaded, the last band is popped, a new frame is copied to the pointer, and it is
  1091 + // re-inserted into the deque.
  1092 + for(size_t b = 0; b < nbands; b++){ //for each band
  1093 + memset(outband, 0, XYb); //set the output band to zero (0)
  1094 + for(size_t c = 0; c < nframes; c++){ //for each frame (corresponding to each coefficient)
  1095 + for(size_t xy = 0; xy < XY; xy++){ //for each pixel
  1096 + outband[xy] += (T)(C[c] * frame[c][xy]); //calculate the contribution of the current frame (scaled by the corresponding coefficient)
  1097 + }
  1098 + }
  1099 + out.write((char*)outband, XYb); //output the band
  1100 + file.read((char*)frame[0], XYb); //read the next band
  1101 + frame.push_back(frame.front()); //put the first element in the back
  1102 + frame.pop_front(); //pop the first element
  1103 + if(PROGRESS) progress = (double)(b+1) / (double)nbands * 100;
  1104 + }
  1105 + }
  1106 +
  1107 + /// Performs a single convolution and saves it to an output file
  1108 +
  1109 + /// @param outfile is the convolved file to be output
  1110 + /// @param C is an array of coefficients
  1111 + /// @param start is the band to start processing (the first coefficient starts here)
  1112 + /// @param nbands is the number of bands to process
  1113 + void convolve(std::string outfile, std::vector<double> C, size_t start, size_t end, bool PROGRESS = false){
  1114 + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing
  1115 + convolve(out, C, start, end, PROGRESS); //start the convolution
  1116 + out.close();
  1117 + }
  1118 +
  1119 + /// Performs a set of convolutions and chains the results together in a single file
  1120 +
  1121 + /// @param outfile is the convolved file to be output
  1122 + /// @param C is an array containing an array of coefficients for each kernel
  1123 + /// @param start is the list of start bands for each kernel
  1124 + /// @param end is the list of end bands for each kernel
  1125 + void convolve(std::string outfile, std::vector< std::vector<double> > C, std::vector<size_t> start, std::vector<size_t> end, bool PROGRESS = false){
  1126 + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing
  1127 +
  1128 + size_t K = C.size(); //get the number of kernels
  1129 + for(size_t k = 0; k < K; k++){
  1130 + size_t b0 = start[k]; //calculate the range of the convolution
  1131 + size_t b1 = end[k];
  1132 + convolve(out, C[k], b0, b1, PROGRESS); //perform the convolution with the current kernel in the given range
  1133 + }
  1134 + out.close();
  1135 + }
  1136 +
  1137 + /// Approximate the spectral derivative of the image
  1138 +
  1139 + void deriv(std::string outfile, size_t d, size_t order, const std::vector<double> w = std::vector<double>(), bool PROGRESS = false){
  1140 + std::ofstream out(outfile.c_str(), std::ios::binary); //open the output file for writing
  1141 +
  1142 + size_t XY = X() * Y(); //calculate the number of values in a band
  1143 + size_t XYb = XY * sizeof(T); //calculate the size of a band (frame) in bytes
  1144 + size_t B = Z();
  1145 + file.seekg(0, std::ios::beg); //move to the beginning of the file
  1146 +
  1147 + size_t N = order + d; //approximating a derivative requires order + d samples
  1148 + std::deque<T*> frame(N, NULL); //create an array to store pointers to each frame
  1149 + for(size_t f = 0; f < N; f++){ //for each frame
  1150 + frame[f] = (T*)malloc(XYb); //allocate space for the frame
  1151 + file.read((char*)frame[f], XYb); //load the frame
  1152 + }
  1153 +
  1154 + T* outband = (T*)malloc(XYb); //allocate space for the output band
  1155 +
  1156 + //Implementation: In order to minimize reads from secondary storage, each band is only loaded once into the 'frame' deque.
  1157 + // When a new band is loaded, the last band is popped, a new frame is copied to the pointer, and it is
  1158 + // re-inserted into the deque.
  1159 + size_t mid = (size_t)(N / 2); //calculate the mid point of the kernel
  1160 + size_t iw; //index to the first wavelength used to evaluate the derivative at this band
  1161 + for(size_t b = 0; b < B; b++){ //for each band
  1162 + if(b < mid) //calculate the first wavelength used to evaluate the derivative at this band
  1163 + iw = 0;
  1164 + else if(b > B - (N - mid + 1))
  1165 + iw = B - N;
  1166 + else{
  1167 + iw = b - mid;
  1168 + file.read((char*)frame[0], XYb); //read the next band
  1169 + frame.push_back(frame.front()); //put the first element in the back
  1170 + frame.pop_front(); //pop the first element
  1171 + }
  1172 + std::vector<double> w_pts(w.begin() + iw, w.begin() + iw + N); //get the wavelengths corresponding to each sample
  1173 + std::vector<double> C = diff_coefficients(w[b], w_pts, d); //get the optimal sample weights
  1174 +
  1175 + memset(outband, 0, XYb); //set the output band to zero (0)
  1176 + for(size_t c = 0; c < N; c++){ //for each frame (corresponding to each coefficient)
  1177 + for(size_t xy = 0; xy < XY; xy++){ //for each pixel
  1178 + outband[xy] += (T)(C[c] * frame[c][xy]); //calculate the contribution of the current frame (scaled by the corresponding coefficient)
  1179 + }
  1180 + }
  1181 + out.write((char*)outband, XYb); //output the band
  1182 + if(PROGRESS) progress = (double)(b+1) / (double)B * 100;
  1183 + }
1061 1184  
1062 1185 }
1063 1186  
... ...
stim/envi/envi.h
... ... @@ -5,6 +5,7 @@
5 5 #include "../envi/bsq.h"
6 6 #include "../envi/bip.h"
7 7 #include "../envi/bil.h"
  8 +#include "../math/fd_coefficients.h"
8 9 #include <iostream>
9 10 //#include "../image/image.h"
10 11  
... ... @@ -1341,6 +1342,103 @@ public:
1341 1342 }
1342 1343 }
1343 1344 }
  1345 +
  1346 + /// Convolve the given band range with a kernel specified by a vector of coefficients.
  1347 +
  1348 + /// @param outfile is the combined file to be output
  1349 + /// @param c is an array of coefficients
  1350 + /// @param start is the band to start processing (the first coefficient starts here)
  1351 + /// @param nbands is the number of bands to process
  1352 + /// @param center is the index for the center coefficient for the kernel (used to set the wavelengths in the output file)
  1353 + void convolve(std::string outfile, std::vector<double> C, size_t start, size_t end, size_t center = 0, bool PROGRESS = false){
  1354 + size_t nbands = end - start + 1;
  1355 + envi_header h = header; //copy the current header
  1356 + h.bands = nbands; //set the number of new bands
  1357 + if(header.wavelength.size() != 0){
  1358 + h.wavelength.resize(nbands); //set the number of wavelengths to the number of bands
  1359 + for(size_t b = 0; b < nbands; b++)
  1360 + h.wavelength[b] = header.wavelength[b+center];
  1361 + }
  1362 + if(header.band_names.size() != 0){
  1363 + h.band_names.resize(nbands);
  1364 + for(size_t b = 0; b < nbands; b++)
  1365 + h.band_names[b] = header.band_names[b+center];
  1366 + }
  1367 + h.save(outfile + ".hdr"); //save the new header
  1368 +
  1369 + if (header.interleave == envi_header::BSQ){
  1370 + if (header.data_type == envi_header::float32)
  1371 + ((bsq<float>*)file)->convolve(outfile, C, start, end, PROGRESS);
  1372 + else if (header.data_type == envi_header::float64)
  1373 + ((bsq<double>*)file)->convolve(outfile, C, start, end, PROGRESS);
  1374 + else{
  1375 + std::cout << "ERROR: unidentified data type" << std::endl;
  1376 + exit(1);
  1377 + }
  1378 + }
  1379 + else if (header.interleave == envi_header::BIL){
  1380 + if (header.data_type == envi_header::float32)
  1381 + ((bil<float>*)file)->convolve(outfile, C, start, end, PROGRESS);
  1382 + else if (header.data_type == envi_header::float64)
  1383 + ((bil<double>*)file)->convolve(outfile, C, start, end, PROGRESS);
  1384 + else{
  1385 + std::cout << "ERROR: unidentified data type" << std::endl;
  1386 + exit(1);
  1387 + }
  1388 + }
  1389 + else if (header.interleave == envi_header::BIP){
  1390 + if (header.data_type == envi_header::float32)
  1391 + ((bip<float>*)file)->convolve(outfile, C, start, end, PROGRESS);
  1392 + else if (header.data_type == envi_header::float64)
  1393 + ((bip<double>*)file)->convolve(outfile, C, start, end, PROGRESS);
  1394 + else{
  1395 + std::cout << "ERROR: unidentified data type" << std::endl;
  1396 + exit(1);
  1397 + }
  1398 + }
  1399 + }
  1400 +
  1401 + /// Approximates the nth derivative of the spectra to the specified order
  1402 +
  1403 + /// @param outfile is the file where the derivative approximation will be saved
  1404 + /// @n is the derivative to be calculated
  1405 + /// @order is the order of the error (must be even)
  1406 + void deriv(std::string outfile, size_t d, size_t order, bool PROGRESS = false){
  1407 + header.save(outfile + ".hdr");
  1408 + if (header.interleave == envi_header::BSQ){
  1409 + if (header.data_type == envi_header::float32)
  1410 + ((bsq<float>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS);
  1411 + else if (header.data_type == envi_header::float64)
  1412 + ((bsq<double>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS);
  1413 + else{
  1414 + std::cout << "ERROR: unidentified data type" << std::endl;
  1415 + exit(1);
  1416 + }
  1417 + }
  1418 +
  1419 + else if (header.interleave == envi_header::BIL){
  1420 + if (header.data_type == envi_header::float32)
  1421 + ((bil<float>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS);
  1422 + else if (header.data_type == envi_header::float64)
  1423 + ((bil<double>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS);
  1424 + else{
  1425 + std::cout << "ERROR: unidentified data type" << std::endl;
  1426 + exit(1);
  1427 + }
  1428 + }
  1429 +
  1430 + else if (header.interleave == envi_header::BIP){
  1431 + if (header.data_type == envi_header::float32)
  1432 + ((bip<float>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS);
  1433 + else if (header.data_type == envi_header::float64)
  1434 + ((bip<double>*)file)->deriv(outfile, d, order, header.wavelength, PROGRESS);
  1435 + else{
  1436 + std::cout << "ERROR: unidentified data type" << std::endl;
  1437 + exit(1);
  1438 + }
  1439 + }
  1440 + exit(1);
  1441 + }
1344 1442 };
1345 1443  
1346 1444 } //end namespace rts
... ...
stim/math/fd_coefficients.h 0 โ†’ 100644
  1 +#ifndef STIM_FINITE_DIFFERENCE_COEFFICIENTS
  2 +#define STIM_FINITE_DIFFERENCE_COEFFICIENTS
  3 +
  4 +#include <vector>
  5 +#include <algorithm>
  6 +
  7 +/// Calculate the coefficients used for finite differences on arbitrary grids. This code is based on:
  8 +/// Fornberg, "Generation of Finite Difference Formulas on Arbitrarily Spaced Grids", Mathematics of Computation, 51(184) 699-706, 1988
  9 +
  10 +/// @param Z is the location where the approximation is to be accurate
  11 +/// @param X is a vector of coordinates for grid points
  12 +/// @param M is the highest derivative to be computed
  13 +/// This function returns a matrix C[a][b] where a is the derivative and b is the coefficient for x = b
  14 +
  15 +template <typename T>
  16 +std::vector< std::vector<T> > diff_coefficient_matrix(T Z, std::vector<T> X, size_t M){
  17 + size_t n = X.size(); //calculate the number of data points available
  18 + std::vector< std::vector<T> > C(M+1); //create an array of m arrays
  19 + for(size_t m = 0; m < M+1; m++) //for each derivative
  20 + C[m].resize(n); //allocate space for n coefficients
  21 +
  22 + T c1, c2, c3, c4, c5;
  23 + c1 = 1; //initialize the matrix
  24 + c4 = X[0] - Z;
  25 + C[0][0] = 1;
  26 + for(size_t i = 2; i <= n; i++){
  27 + size_t mn = (std::min)(i, M+1);
  28 + c2 = 1;
  29 + c5 = c4;
  30 + c4 = X[i-1] - Z;
  31 + for(size_t j = 1; j <= i-1; j++){
  32 + c3 = X[i-1] - X[j-1];
  33 + c2 = c2 * c3;
  34 + if(j == i-1){
  35 + for(size_t k = 2; k <= mn; k++){
  36 + C[k-1][i-1] = c1 * ((k-1) * C[k-2][i-2] - c5 * C[k-1][i-2]) / c2;
  37 + }
  38 + C[0][i-1] = -c1 * c5 * C[0][i-2]/c2;
  39 + }
  40 + T c_p0 = C[0][j-1];
  41 + T c_p1 = C[1][j-1];
  42 + for(size_t k = 2; k <= mn; k++){
  43 + c_p1 = C[k-1][j-1];
  44 + C[k-1][j-1] = (c4 * c_p1 - (k-1) * c_p0) / c3;
  45 + c_p0 = c_p1;
  46 + }
  47 + C[0][j-1] = c4 * C[0][j-1] / c3;
  48 + }
  49 + c1 = c2;
  50 + }
  51 + return C;
  52 +}
  53 +
  54 +/// Returns the coefficients used to estimate the nth derivative at x0 given values at points in x
  55 +
  56 +/// @param x0 is the point where the derivative f'(x0) is to be estimated
  57 +/// @param x is the set of points where the values of f(x) are known
  58 +/// @param n specifies the derivative, ex. 2 estimates the second derivative f''(x0)
  59 +template <typename T>
  60 +std::vector<T> diff_coefficients(T x0, std::vector<T> x, size_t n){
  61 + std::vector< std::vector<T> > C = diff_coefficient_matrix(x0, x, n); //calculate all derivative coefficients
  62 + return C.back();
  63 +}
  64 +
  65 +
  66 +
  67 +#endif
0 68 \ No newline at end of file
... ...