Commit 28b882ce020c50db81326f56c344c2aa0f4d1b84
1 parent
800ff264
new flow header
Showing
2 changed files
with
645 additions
and
372 deletions
Show diff stats
stim/biomodels/flow.h
1 | -#pragma once | |
2 | -#include <fstream> // Required for ofstream, etc. | |
3 | -#include <iomanip> // Required for setw | |
4 | -#include <iostream> // Required for cout, cin, etc. | |
5 | -#include <tuple> // Required for returning multiple values from a function | |
6 | - | |
7 | -using namespace std; | |
8 | - | |
9 | - | |
10 | -class flow | |
11 | -{ | |
12 | -public: | |
13 | - void backupToTxt(unsigned int nL, double **D, char filename[]); | |
14 | - tuple<int, int> copySrcDesRadLen(char filename[]); | |
15 | - void copyToArray(int *src, int *dest, double *radii, double *len); | |
16 | - int getDangleNodes(int datarow, int numNodes, int *row, int *column, int *dangleNodes); | |
17 | - void inversion(double **a, int n, double **b); | |
18 | - | |
19 | -protected: | |
20 | - float determinant(double **a, int n); | |
21 | - int minor(double **src, double **dest, int row, int col, int order); | |
22 | -}; | |
23 | - | |
24 | -/* Function to find the dangle nodes in a network */ | |
25 | -// Created by Cherub P. Harder (8/10/2015), U of Houston | |
26 | -// Modified by Cherub P. Harder on 8/12/2015 | |
27 | -int flow::getDangleNodes(int datarow, int numNodes, int *column1, int *column2, int *dangleNodes) | |
28 | -{ | |
29 | - int count = datarow, diff1 = 0, diff2 = 0, numPress = 0, st = 0; | |
30 | - | |
31 | - // Find matching nodes within column2 | |
32 | - for( int i = 0; i < count; i++ ) | |
33 | - { | |
34 | - for( int y = i+1; y < datarow; y++ ) | |
35 | - { | |
36 | - if( column2[i] == column2[y] ) // Is there a match? | |
37 | - { | |
38 | - st = column2[i]; // Save the matching node | |
39 | -// cout << endl << column2[i] << " = " << column2[y] << endl; // Display the matching nodes | |
40 | - memmove(column2+i, column2+i+1, (datarow-(i+1)) * sizeof(column2[0])); // Move up the rows | |
41 | - // taking the places of the rows before them starting | |
42 | - // with where the matching node is located | |
43 | - column2[datarow-1] = st; // Place the matching node at the very end of the array-- | |
44 | - // this is for comparison purpose so that the other match- | |
45 | - // ing node will be moved as well and then omitted later. | |
46 | - diff1++; // Count the matching node | |
47 | - | |
48 | - // Display the updated array (with the matching node moved to the bottommost row) | |
49 | -/* cout << "Updated array:" << endl; | |
50 | - for( int k = 0; k < datarow; k++ ) | |
51 | - cout << column2[k] << endl; | |
52 | -*/ | |
53 | - // Decrement the counters | |
54 | - // NOTE: The counters need to be decremented because the rows had been moved up, so the same | |
55 | - // locations need to be read again because they contain different values now after the move. | |
56 | - i--; // Decrement i to read the node that took over the place | |
57 | - // of the matching node. Otherwise, it will be skipped. | |
58 | - y--; // Decrement y to read the following node for comparison | |
59 | - count--; // The maximum count need to be decremented so that the | |
60 | - // matching nodes that had been moved will not be read again. | |
61 | - // However, the maximum count (datarow) for finding a match | |
62 | - // will not be decremented because the remaining matching | |
63 | - // node that has not been moved yet needs to be moved and | |
64 | - // the only way to do that is to match it with its duplicate. | |
65 | - } | |
66 | - } | |
67 | - } | |
68 | - | |
69 | - // Store the nodes that have no duplicates | |
70 | - // NOTE: This will only save the nodes that have not been moved to the bottom. | |
71 | -// cout << "\ndangleNodes array:" << endl; | |
72 | - for( int j = 0; j < datarow-diff1; j++ ) | |
73 | - { | |
74 | - dangleNodes[numPress] = column2[j]; | |
75 | -// cout << dangleNodes[j] << endl; // DELETE!!! | |
76 | - numPress++; // Count the non-duplicated node | |
77 | - } | |
78 | - | |
79 | - // Find if the non-duplicated nodes have a match from column1 | |
80 | - count = datarow-diff1; // Reinitialize the counter | |
81 | - | |
82 | - for( int i = 0; i < count; i++ ) | |
83 | - { | |
84 | - for( int j = 0; j < datarow; j++ ) | |
85 | - { | |
86 | - if( dangleNodes[i] == column1[j] ) // Is there a match? | |
87 | - { | |
88 | - st = column1[j]; // Save the matching node | |
89 | -// cout << endl << dangleNodes[i] << " = " << column1[j] << endl; // Display the matching nodes | |
90 | - memmove(dangleNodes+i, dangleNodes+i+1, (datarow-diff1-(i+1)) * sizeof(dangleNodes[0])); | |
91 | - dangleNodes[count-1] = st; // Move the matching node to the bottom of the array | |
92 | - diff2++; // Count the matching node | |
93 | - | |
94 | - // Display the updated array | |
95 | -/* cout << "Updated dangleNodes array:" << endl; | |
96 | - for( int k = 0; k < count-1; k++ ) | |
97 | - { | |
98 | - cout << dangleNodes[k] << endl; | |
1 | +#ifndef STIM_FLOW_H | |
2 | +#define STIM_FLOW_H | |
3 | + | |
4 | +#include <vector> | |
5 | +#include <algorithm> | |
6 | + | |
7 | +//STIM include | |
8 | +#include <stim/math/vec3.h> | |
9 | +#include <stim/parser/arguments.h> | |
10 | +#include <stim/biomodels/network.h> | |
11 | + | |
12 | +#ifdef __CUDACC__ | |
13 | +#include <cublas_v2.h> | |
14 | +#include <stim/cuda/cudatools/error.h> | |
15 | +#endif | |
16 | + | |
17 | +namespace stim { | |
18 | + template <typename A, typename B, typename C> | |
19 | + struct triple { | |
20 | + A first; | |
21 | + B second; | |
22 | + C third; | |
23 | + }; | |
24 | + | |
25 | + template <typename T> | |
26 | + struct bridge { | |
27 | + std::vector<unsigned> v; // vertices' indices | |
28 | + std::vector<typename stim::vec3<T> > V; // vertices' coordinates | |
29 | + T l; // length | |
30 | + T r; // radii | |
31 | + T deltaP; // pressure drop | |
32 | + T Q; // volume flow rate | |
33 | + }; | |
34 | + | |
35 | + template <typename T> | |
36 | + class flow { | |
37 | + | |
38 | + private: | |
39 | + | |
40 | + // calculate the cofactor of elemen[row][col] | |
41 | + void get_minor(T** src, T** dest, int row, int col, int order) { | |
42 | + | |
43 | + // index of element to be copied | |
44 | + int rowCount = 0; | |
45 | + int colCount = 0; | |
46 | + | |
47 | + for (int i = 0; i < order; i++) { | |
48 | + if (i != row) { | |
49 | + colCount = 0; | |
50 | + for (int j = 0; j < order; j++) { | |
51 | + // when j is not the element | |
52 | + if (j != col) { | |
53 | + dest[rowCount][colCount] = src[i][j]; | |
54 | + colCount++; | |
55 | + } | |
56 | + } | |
57 | + rowCount++; | |
99 | 58 | } |
100 | -*/ | |
101 | - // Decrement the counters | |
102 | - i--; | |
103 | - j--; | |
104 | - count--; | |
105 | - numPress--; // Decrement to the exact number of dangle nodes | |
106 | 59 | } |
107 | 60 | } |
108 | - } | |
109 | 61 | |
110 | - return numPress; // Number of dangle nodes | |
111 | -} | |
62 | + // calculate the det() | |
63 | + T determinant(T** mat, int order) { | |
112 | 64 | |
65 | + // degenate case when n = 1 | |
66 | + if (order == 1) | |
67 | + return mat[0][0]; | |
113 | 68 | |
114 | -// Function to make a backup copy of the contents of a matrix to a .txt file | |
115 | -// Created by Cherub P. Harder (8/10/2015), U of Houston | |
116 | -void flow::backupToTxt(unsigned int nL, double **D, char filename[]) | |
117 | -{ | |
118 | - ofstream output_file(filename); | |
119 | - | |
120 | - for( unsigned int i = 0; i < nL; i++ ) | |
121 | - { | |
122 | - for( int j = 0; j < 4; j++ ) | |
123 | - { | |
124 | - if( j < 3 ) | |
125 | - output_file << D[i][j] << "\t"; | |
126 | - | |
127 | - else | |
128 | - output_file << D[i][j]; | |
129 | - } | |
69 | + T det = 0.0; // determinant value | |
130 | 70 | |
131 | - output_file << "\n"; | |
132 | - } | |
71 | + // allocate the cofactor matrix | |
72 | + T** minor = (T**)malloc((order - 1) * sizeof(T*)); | |
73 | + for (int i = 0; i < order - 1; i++) | |
74 | + minor[i] = (T*)malloc((order - 1) * sizeof(T)); | |
133 | 75 | |
134 | - output_file.close( ); | |
135 | -} | |
136 | 76 | |
77 | + for (int i = 0; i < order; i++) { | |
137 | 78 | |
138 | -// Function to make separate copies of the source nodes, destination nodes, radii, and lengths | |
139 | -// Created by Cherub P. Harder (8/10/2015), U of Houston | |
140 | -tuple<int, int> flow::copySrcDesRadLen(char filename[]) | |
141 | -{ | |
142 | - int cnt = 0, numElements = 0, numNodes = 0; | |
143 | - float number = 0.0; | |
144 | - ofstream srcData("srcCol.txt"); // A .txt file to store the source nodes | |
145 | - ofstream desData("destCol.txt"); // A .txt file to store the destination nodes | |
146 | - ofstream radiiData("radii.txt"); // A .txt file to store the radii | |
147 | - ofstream lenData("lengths.txt"); // A .txt file to store the lengths | |
148 | - FILE *fp = fopen(filename, "r"); // Create a variable of type FILE* and open the file using | |
149 | - // the fopen function and assign the file to the variable | |
150 | - // Check if the file exists | |
151 | - if(fp == NULL) // Alternative: if(!fp) | |
152 | - { | |
153 | - printf("Error! File does not exist.\n"); | |
154 | - getchar( ); // Pause | |
155 | - exit(-1); // NOTE: Must include stdlib.h. | |
156 | - } | |
157 | - | |
158 | - // Store data to their respective .txt files | |
159 | - while(fscanf(fp, "%f", &number) == 1) | |
160 | - { | |
161 | - cnt++; // Increment counter | |
162 | - | |
163 | - // Store to srcCol.txt | |
164 | - if(cnt == 1) | |
165 | - srcData << number << endl; | |
166 | - | |
167 | - // Store to destCol.txt | |
168 | - if(cnt == 2) | |
169 | - desData << number << endl; | |
170 | - | |
171 | - // Save the current number of nodes | |
172 | - if(cnt < 3) | |
173 | - { | |
174 | - if(number > numNodes) | |
175 | - numNodes = (int)number; | |
176 | - } | |
79 | + // get minor of element(0, i) | |
80 | + get_minor(mat, minor, 0, i, order); | |
177 | 81 | |
178 | - // Store to radii.txt | |
179 | - if(cnt == 3) | |
180 | - radiiData << number << endl; | |
82 | + // recursion | |
83 | + det += (i % 2 == 1 ? -1.0 : 1.0) * mat[0][i] * determinant(minor, order - 1); | |
84 | + } | |
181 | 85 | |
182 | - // Store to lengths.txt | |
183 | - if(cnt == 4) | |
184 | - { | |
185 | - lenData << number << endl; | |
86 | + // release memory | |
87 | + for (int i = 0; i < order - 1; i++) | |
88 | + free(minor[i]); | |
89 | + free(minor); | |
186 | 90 | |
187 | - numElements++; // Count the elements | |
188 | - cnt = 0; // Reset counter | |
91 | + return det; | |
189 | 92 | } |
190 | - } | |
191 | - | |
192 | - srcData.close( ); | |
193 | - desData.close( ); | |
194 | - radiiData.close( ); | |
195 | - lenData.close( ); | |
196 | - | |
197 | - return make_tuple(numNodes, numElements); // Return two values | |
198 | -} | |
199 | - | |
200 | - | |
201 | -// Function to copy data for .txt files to their respective arrays | |
202 | -// Created by Cherub P. Harder (8/11/2015), U of Houston | |
203 | -void flow::copyToArray(int *src, int *dest, double *radii, double *len) | |
204 | -{ | |
205 | - int v = 0; | |
206 | - double tmp = 0, R = 0, L = 0; | |
207 | - | |
208 | - // Store source node values to the array src | |
209 | - ifstream readSrc("srcCol.txt"); | |
210 | - | |
211 | - while( readSrc >> tmp ) | |
212 | - { | |
213 | - src[v] = (int)tmp; | |
214 | - v++; | |
215 | - } | |
216 | - | |
217 | - readSrc.close( ); | |
218 | 93 | |
219 | - // Store destination node values to the array dest | |
220 | - v = 0; // Reset counter | |
221 | - ifstream readDest("destCol.txt"); | |
94 | + public: | |
95 | + std::vector<typename stim::triple<unsigned, unsigned, T> > V; // velocity | |
96 | + std::vector<typename stim::triple<unsigned, unsigned, T> > Q; // volume flow rate | |
97 | + std::vector<typename stim::triple<unsigned, unsigned, T> > deltaP; // pressure drop | |
98 | + std::vector<T> pressure; // pressure | |
99 | + | |
100 | + flow() {} // default constructor | |
101 | + | |
102 | + // calculate the flow rate of 3D model(circle cross section) | |
103 | + void calculate_flow_rate(unsigned e, T r) { | |
104 | + stim::triple<unsigned, unsigned, T> tmp_Q; | |
105 | + tmp_Q.first = V[e].first; // copy the vertices information | |
106 | + tmp_Q.second = V[e].second; | |
107 | + tmp_Q.third = V[e].third * stim::PI * pow(r, 2); // UNITS: uL/s | |
108 | + Q.push_back(tmp_Q); // push back the volume flow rate information for every edge | |
109 | + } | |
222 | 110 | |
223 | - while( readDest >> tmp ) | |
224 | - { | |
225 | - dest[v] = (int)tmp; | |
226 | - v++; | |
227 | - } | |
111 | + // calculate the flow rate of 2D model(rectangular cross section) | |
112 | + void calculate_flow_rate(unsigned e, T r, T h) { | |
113 | + stim::triple<unsigned, unsigned, T> tmp_Q; | |
114 | + tmp_Q.first = V[e].first; // copy the vertices information | |
115 | + tmp_Q.second = V[e].second; | |
116 | + tmp_Q.third = V[e].third * h * r; // UNITS: uL/s = mm^3/s | |
117 | + Q.push_back(tmp_Q); // push back the volume flow rate information for every edge | |
118 | + } | |
228 | 119 | |
229 | - readDest.close( ); | |
120 | + // calculate the pressure drop of 3D model(circle cross section) | |
121 | + void calculate_deltaP(unsigned e, T u, T l, T r) { | |
122 | + stim::triple<unsigned, unsigned, T> tmp_deltaP; | |
123 | + tmp_deltaP.first = V[e].first; // copy the vertices information | |
124 | + tmp_deltaP.second = V[e].second; | |
125 | + tmp_deltaP.third = (8 * u * l * Q[e].third) / (stim::PI * pow(r, 4)); // UNITS: g/mm/s^2 = Pa | |
126 | + deltaP.push_back(tmp_deltaP); // push back the volume flow rate information for every edge | |
127 | + } | |
230 | 128 | |
231 | - // Store radius values to the array radii | |
232 | - v = 0; // Reset counter | |
233 | - ifstream readRad("radii.txt"); | |
129 | + // calculate the pressure drop of 2D model(rectangular cross section) | |
130 | + void calculate_deltaP(unsigned e, T u, T l, T r, T h) { | |
131 | + stim::triple<unsigned, unsigned, T> tmp_deltaP; | |
132 | + tmp_deltaP.first = V[e].first; // copy the vertices information | |
133 | + tmp_deltaP.second = V[e].second; | |
134 | + tmp_deltaP.third = (12 * u * l * Q[e].third) / (stim::PI * h * pow(r, 3)); // UNITS: g/mm/s^2 = Pa | |
135 | + deltaP.push_back(tmp_deltaP); // push back the volume flow rate information for every edge | |
136 | + } | |
234 | 137 | |
235 | - while( readRad >> tmp ) | |
236 | - { | |
237 | - radii[v] = tmp; | |
238 | - v++; | |
239 | - } | |
138 | + // better way to do this??? | |
139 | + // find the maximum and minimum pressure positions | |
140 | + void find_max_min_pressure(size_t n_e, size_t n_v, unsigned& max, unsigned& min) { | |
141 | + std::vector<T> P(n_v, FLT_MAX); | |
142 | + // set one to reference | |
143 | + P[Q[0].first] = 0.0; | |
144 | + unsigned first = 0; | |
145 | + unsigned second = 0; | |
146 | + // calculate all the relative pressure in brute force manner | |
147 | + for (unsigned e = 0; e < n_e; e++) { | |
148 | + // assuming the obj file stores in a straight order, in other words, like swc file | |
149 | + first = Q[e].first; | |
150 | + second = Q[e].second; | |
151 | + if (P[first] != FLT_MAX) // if pressure at start vertex is known | |
152 | + P[second] = P[first] - deltaP[e].third; | |
153 | + else if (P[second] != FLT_MAX) // if pressure at end vertex is known | |
154 | + P[first] = P[second] + deltaP[e].third; | |
155 | + } | |
240 | 156 | |
241 | - readRad.close( ); | |
157 | + // find the maximum and minimum pressure position | |
158 | + auto m1 = std::max_element(P.begin(), P.end()); // temporarily max number | |
159 | + auto m2 = std::min_element(P.begin(), P.end()); // temporarily min number | |
242 | 160 | |
243 | - // Store length values to the array len | |
244 | - v = 0; // Reset counter | |
245 | - ifstream readLen("lengths.txt"); | |
161 | + max = std::distance(P.begin(), m1); | |
162 | + min = std::distance(P.begin(), m2); | |
246 | 163 | |
247 | - while( readLen >> tmp ) | |
248 | - { | |
249 | - len[v] = tmp; | |
250 | - v++; | |
251 | - } | |
164 | + T tmp_m = *m2; | |
165 | + // Now set the lowest pressure port to reference pressure(0.0 Pa) | |
166 | + for (unsigned i = 0; i < n_v; i++) | |
167 | + P[i] -= tmp_m; | |
252 | 168 | |
253 | - readLen.close( ); | |
254 | -} | |
169 | + for (unsigned i = 0; i < n_v; i++) | |
170 | + pressure.push_back(P[i]); | |
171 | + } | |
255 | 172 | |
173 | + void inversion(T** A, int order, T** C) { | |
174 | + | |
175 | +#ifdef __CUDACC__ | |
176 | + | |
177 | + // convert from double pointer to single pointer, make it flat | |
178 | + T* Aflat = (T*)malloc(order * order * sizeof(T)); | |
179 | + for (unsigned i = 0; i < order; i++) | |
180 | + for (unsigned j = 0; j < order; j++) | |
181 | + Aflat[i * order + j] = A[i][j]; | |
182 | + T* Cflat = (T*)malloc(order * order * sizeof(T)); | |
183 | + | |
184 | + // create device pointer | |
185 | + T* d_Aflat; // flat original matrix | |
186 | + T* d_Cflat; // flat inverse matrix | |
187 | + T** d_A; // put the flat original matrix into another array of pointer | |
188 | + T** d_C; | |
189 | + int *d_P; | |
190 | + int *d_INFO; | |
191 | + | |
192 | + // allocate memory on device | |
193 | + HANDLE_ERROR(cudaMalloc((void**)&d_Aflat, order * order * sizeof(T))); | |
194 | + HANDLE_ERROR(cudaMalloc((void**)&d_Cflat, order * order * sizeof(T))); | |
195 | + HANDLE_ERROR(cudaMalloc((void**)&d_A, sizeof(T*))); | |
196 | + HANDLE_ERROR(cudaMalloc((void**)&d_C, sizeof(T*))); | |
197 | + HANDLE_ERROR(cudaMalloc((void**)&d_P, order * 1 * sizeof(int))); | |
198 | + HANDLE_ERROR(cudaMalloc((void**)&d_INFO, 1 * sizeof(int))); | |
199 | + | |
200 | + // copy matrix from host to device | |
201 | + HANDLE_ERROR(cudaMemcpy(d_Aflat, Aflat, order * order * sizeof(T), cudaMemcpyHostToDevice)); | |
202 | + | |
203 | + // copy matrix from device to device | |
204 | + HANDLE_ERROR(cudaMemcpy(d_A, &d_Aflat, sizeof(T*), cudaMemcpyHostToDevice)); | |
205 | + HANDLE_ERROR(cudaMemcpy(d_C, &d_Cflat, sizeof(T*), cudaMemcpyHostToDevice)); | |
256 | 206 | |
257 | -// Function to find the inverse of a square matrix | |
258 | -void flow::inversion(double **a, int n, double **b) | |
259 | -{ | |
260 | - // Get 1 over the determinant of A | |
261 | - double det = (double)(1.0/determinant(a, n)); | |
262 | -// cerr << "\n1/det(C) = " << det << endl; // DELETE!!! | |
263 | - | |
264 | - // Memory allocation | |
265 | - double *tmp = new double[(n-1) * (n-1)]; | |
266 | - double **m = new double * [n-1]; | |
267 | - for( int i = 0; i < n-1; i++ ) | |
268 | - m[i] = tmp + ( i * (n-1) ); | |
269 | - | |
270 | - for( int j = 0; j < n; j++) | |
271 | - { | |
272 | - for( int i = 0; i < n; i++ ) | |
273 | - { | |
274 | - // Get the cofactor (matrix) of a(j,i) | |
275 | - minor(a, m, j, i, n); | |
276 | - b[i][j] = det * determinant( m, n-1 ); | |
277 | - if( (i+j)%2 == 1 ) | |
278 | - b[i][j] = -b[i][j]; | |
279 | - } | |
280 | - } | |
281 | - | |
282 | - // Release memory | |
283 | - // Delete [] minor[0]; | |
284 | - delete [] tmp; | |
285 | - delete [] m; | |
286 | -} | |
207 | + // calculate the inverse of matrix based on cuBLAS | |
208 | + cublasHandle_t handle; | |
209 | + CUBLAS_HANDLE_ERROR(cublasCreate_v2(&handle)); // create cuBLAS handle object | |
287 | 210 | |
211 | + CUBLAS_HANDLE_ERROR(cublasSgetrfBatched(handle, order, d_A, order, d_P, d_INFO, 1)); | |
288 | 212 | |
289 | -// Function to find the determinant of a matrix using recursion | |
290 | -// Contribution by Edward Popko | |
291 | -// Modified by Cherub P. Harder (7/15/2015), U of Houston | |
292 | -// Arguments: a(double **) - pointer to a pointer of an arbitrary square matrix | |
293 | -// n(int) - dimension of the square matrix | |
294 | -float flow::determinant(double **a, int n) | |
295 | -{ | |
296 | - int i, j, j1, j2; // General loop and matrix subscripts | |
297 | - double det = 0; // Initialize determinant | |
298 | - double **m = NULL; // Pointer to pointer to implement 2D square array | |
299 | - | |
300 | - // Display contents of matrix C (DELETE!!!) | |
301 | -/* std::cout << "\nThe updated matrix C:\n"; | |
302 | - for( int j = 0; j < n; ++j ) | |
303 | - { | |
304 | - std::cerr << "\t"; | |
305 | - | |
306 | - for( int k = 0; k < n; ++k ) | |
307 | - std::cerr << left << setw(15) << a[j][k]; | |
308 | - | |
309 | - std::cerr << endl; | |
310 | - } | |
311 | - | |
312 | - getchar(); // DELETE!!!*/ | |
313 | - | |
314 | - if(n < 1) { } // Error condition - should never get here | |
315 | - | |
316 | - else if (n == 1) // Should never get here | |
317 | - { | |
318 | - det = a[0][0]; | |
319 | - } | |
320 | - | |
321 | - else if(n == 2) // Basic 2x2 sub-matrix determinate definition | |
322 | - { // When n == 2, this ends the recursion series | |
323 | - det = a[0][0] * a[1][1] - a[1][0] * a[0][1]; | |
324 | - } | |
325 | - // Recursion continues, solve next sub-matrix | |
326 | - else // Solve the next minor by building a sub-matrix | |
327 | - { | |
328 | - det = 0; // Initialize determinant of sub-matrix | |
329 | - | |
330 | - for (j1 = 0; j1 < n; j1++) // For each column in sub-matrix get space for the | |
331 | - { // pointer list | |
332 | - m = (double **) malloc((n-1) * sizeof(double *)); | |
333 | - | |
334 | - for (i = 0; i < n-1; i++) | |
335 | - m[i] = (double *) malloc((n-1)* sizeof(double)); | |
336 | - // i[0][1][2][3] first malloc | |
337 | - // m -> + + + + space for 4 pointers | |
338 | - // | | | | j second malloc | |
339 | - // | | | +-> _ _ _ [0] pointers to | |
340 | - // | | +----> _ _ _ [1] and memory for | |
341 | - // | +-------> _ a _ [2] 4 doubles | |
342 | - // +----------> _ _ _ [3] | |
343 | - // | |
344 | - // a[1][2] | |
345 | - // Build sub-matrix with minor elements excluded | |
346 | - | |
347 | - for (i = 1; i < n; i++) | |
213 | + int INFO = 0; | |
214 | + HANDLE_ERROR(cudaMemcpy(&INFO, d_INFO, sizeof(int), cudaMemcpyDeviceToHost)); | |
215 | + if (INFO == order) | |
348 | 216 | { |
349 | - j2 = 0 ; // Start at first sum-matrix column position | |
350 | - // Loop to copy source matrix less one column | |
351 | - for (j = 0; j < n; j++) | |
352 | - { | |
353 | - if (j == j1) continue; // Do not copy the minor column element | |
354 | - | |
355 | - m[i-1][j2] = a[i][j]; // Copy source element into new sub-matrix | |
356 | - // i-1 because new sub-matrix is one row | |
357 | - // (and column) smaller with excluded minors | |
358 | - j2++; // Move to next sub-matrix column position | |
217 | + std::cout << "Factorization Failed : Matrix is singular." << std::endl; | |
218 | + cudaDeviceReset(); | |
219 | + exit(1); | |
220 | + } | |
221 | + | |
222 | + CUBLAS_HANDLE_ERROR(cublasSgetriBatched(handle, order, (const T **)d_A, order, d_P, d_C, order, d_INFO, 1)); | |
223 | + | |
224 | + CUBLAS_HANDLE_ERROR(cublasDestroy_v2(handle)); | |
225 | + | |
226 | + // copy inverse matrix from device to device | |
227 | + HANDLE_ERROR(cudaMemcpy(&d_Cflat, d_C, sizeof(T*), cudaMemcpyDeviceToHost)); | |
228 | + | |
229 | + // copy inverse matrix from device to host | |
230 | + HANDLE_ERROR(cudaMemcpy(Cflat, d_Cflat, order * order * sizeof(T), cudaMemcpyDeviceToHost)); | |
231 | + | |
232 | + for(unsigned i = 0; i < order; i++) | |
233 | + memcpy(C[i], &Cflat[i*order], order * sizeof(T*)); | |
234 | + | |
235 | + // clear up | |
236 | + free(Aflat); | |
237 | + free(Cflat); | |
238 | + HANDLE_ERROR(cudaFree(d_Aflat)); | |
239 | + HANDLE_ERROR(cudaFree(d_Cflat)); | |
240 | + HANDLE_ERROR(cudaFree(d_A)); | |
241 | + HANDLE_ERROR(cudaFree(d_C)); | |
242 | + HANDLE_ERROR(cudaFree(d_P)); | |
243 | + HANDLE_ERROR(cudaFree(d_INFO)); | |
244 | + | |
245 | +#else | |
246 | + // get the determinant of a | |
247 | + double det = 1.0 / determinant(A, order); | |
248 | + | |
249 | + // memory allocation | |
250 | + T* tmp = (T*)malloc((order - 1)*(order - 1) * sizeof(T)); | |
251 | + T** minor = (T**)malloc((order - 1) * sizeof(T*)); | |
252 | + for (int i = 0; i < order - 1; i++) | |
253 | + minor[i] = tmp + (i * (order - 1)); | |
254 | + | |
255 | + for (int j = 0; j < order; j++) { | |
256 | + for (int i = 0; i < order; i++) { | |
257 | + // get the co-factor (matrix) of A(j,i) | |
258 | + get_minor(A, minor, j, i, order); | |
259 | + C[i][j] = det * determinant(minor, order - 1); | |
260 | + if ((i + j) % 2 == 1) | |
261 | + C[i][j] = -C[i][j]; | |
359 | 262 | } |
360 | 263 | } |
361 | - | |
362 | - det += (double)pow(-1.0, 1.0 + j1 + 1.0) * a[0][j1] * determinant(m, n-1); | |
363 | - // Sum x raised to y power | |
364 | - // recursively get determinant of next | |
365 | - // sub-matrix which is now one | |
366 | - // row & column smaller | |
367 | - | |
368 | - for (i = 0; i < n-1; i++) free(m[i]); // Free the storage allocated to | |
369 | - // this minor's set of pointers | |
370 | - free(m); // Free the storage for the original | |
371 | - // pointer to pointer | |
264 | + | |
265 | + // release memory | |
266 | + free(tmp); | |
267 | + free(minor); | |
268 | +#endif | |
372 | 269 | } |
373 | - } | |
374 | - | |
375 | - return(det); | |
270 | + }; | |
376 | 271 | } |
377 | 272 | |
378 | - | |
379 | -// Function to calculate the cofactor of element (row, col) | |
380 | -int flow::minor(double **src, double **dest, int row, int col, int order) | |
381 | -{ | |
382 | - // Indicate which col and row is being copied to dest | |
383 | - int colCount=0,rowCount=0; | |
384 | - | |
385 | - for(int i = 0; i < order; i++) | |
386 | - { | |
387 | - if(i != row) | |
388 | - { | |
389 | - colCount = 0; | |
390 | - for(int j = 0; j < order; j++) | |
391 | - { | |
392 | - // When j is not the element | |
393 | - if( j != col ) | |
394 | - { | |
395 | - dest[rowCount][colCount] = src[i][j]; | |
396 | - colCount++; | |
397 | - } | |
398 | - } | |
399 | - | |
400 | - rowCount++; | |
401 | - } | |
402 | - } | |
403 | - | |
404 | - return 1; | |
405 | -} | |
406 | 273 | \ No newline at end of file |
274 | +#endif | |
407 | 275 | \ No newline at end of file | ... | ... |
1 | +#pragma once | |
2 | +#include <fstream> // Required for ofstream, etc. | |
3 | +#include <iomanip> // Required for setw | |
4 | +#include <iostream> // Required for cout, cin, etc. | |
5 | +#include <tuple> // Required for returning multiple values from a function | |
6 | + | |
7 | +using namespace std; | |
8 | + | |
9 | + | |
10 | +class flow | |
11 | +{ | |
12 | +public: | |
13 | + void backupToTxt(unsigned int nL, double **D, char filename[]); | |
14 | + tuple<int, int> copySrcDesRadLen(char filename[]); | |
15 | + void copyToArray(int *src, int *dest, double *radii, double *len); | |
16 | + int getDangleNodes(int datarow, int numNodes, int *row, int *column, int *dangleNodes); | |
17 | + void inversion(double **a, int n, double **b); | |
18 | + | |
19 | +protected: | |
20 | + float determinant(double **a, int n); | |
21 | + int minor(double **src, double **dest, int row, int col, int order); | |
22 | +}; | |
23 | + | |
24 | +/* Function to find the dangle nodes in a network */ | |
25 | +// Created by Cherub P. Harder (8/10/2015), U of Houston | |
26 | +// Modified by Cherub P. Harder on 8/12/2015 | |
27 | +int flow::getDangleNodes(int datarow, int numNodes, int *column1, int *column2, int *dangleNodes) | |
28 | +{ | |
29 | + int count = datarow, diff1 = 0, diff2 = 0, numPress = 0, st = 0; | |
30 | + | |
31 | + // Find matching nodes within column2 | |
32 | + for( int i = 0; i < count; i++ ) | |
33 | + { | |
34 | + for( int y = i+1; y < datarow; y++ ) | |
35 | + { | |
36 | + if( column2[i] == column2[y] ) // Is there a match? | |
37 | + { | |
38 | + st = column2[i]; // Save the matching node | |
39 | +// cout << endl << column2[i] << " = " << column2[y] << endl; // Display the matching nodes | |
40 | + memmove(column2+i, column2+i+1, (datarow-(i+1)) * sizeof(column2[0])); // Move up the rows | |
41 | + // taking the places of the rows before them starting | |
42 | + // with where the matching node is located | |
43 | + column2[datarow-1] = st; // Place the matching node at the very end of the array-- | |
44 | + // this is for comparison purpose so that the other match- | |
45 | + // ing node will be moved as well and then omitted later. | |
46 | + diff1++; // Count the matching node | |
47 | + | |
48 | + // Display the updated array (with the matching node moved to the bottommost row) | |
49 | +/* cout << "Updated array:" << endl; | |
50 | + for( int k = 0; k < datarow; k++ ) | |
51 | + cout << column2[k] << endl; | |
52 | +*/ | |
53 | + // Decrement the counters | |
54 | + // NOTE: The counters need to be decremented because the rows had been moved up, so the same | |
55 | + // locations need to be read again because they contain different values now after the move. | |
56 | + i--; // Decrement i to read the node that took over the place | |
57 | + // of the matching node. Otherwise, it will be skipped. | |
58 | + y--; // Decrement y to read the following node for comparison | |
59 | + count--; // The maximum count need to be decremented so that the | |
60 | + // matching nodes that had been moved will not be read again. | |
61 | + // However, the maximum count (datarow) for finding a match | |
62 | + // will not be decremented because the remaining matching | |
63 | + // node that has not been moved yet needs to be moved and | |
64 | + // the only way to do that is to match it with its duplicate. | |
65 | + } | |
66 | + } | |
67 | + } | |
68 | + | |
69 | + // Store the nodes that have no duplicates | |
70 | + // NOTE: This will only save the nodes that have not been moved to the bottom. | |
71 | +// cout << "\ndangleNodes array:" << endl; | |
72 | + for( int j = 0; j < datarow-diff1; j++ ) | |
73 | + { | |
74 | + dangleNodes[numPress] = column2[j]; | |
75 | +// cout << dangleNodes[j] << endl; // DELETE!!! | |
76 | + numPress++; // Count the non-duplicated node | |
77 | + } | |
78 | + | |
79 | + // Find if the non-duplicated nodes have a match from column1 | |
80 | + count = datarow-diff1; // Reinitialize the counter | |
81 | + | |
82 | + for( int i = 0; i < count; i++ ) | |
83 | + { | |
84 | + for( int j = 0; j < datarow; j++ ) | |
85 | + { | |
86 | + if( dangleNodes[i] == column1[j] ) // Is there a match? | |
87 | + { | |
88 | + st = column1[j]; // Save the matching node | |
89 | +// cout << endl << dangleNodes[i] << " = " << column1[j] << endl; // Display the matching nodes | |
90 | + memmove(dangleNodes+i, dangleNodes+i+1, (datarow-diff1-(i+1)) * sizeof(dangleNodes[0])); | |
91 | + dangleNodes[count-1] = st; // Move the matching node to the bottom of the array | |
92 | + diff2++; // Count the matching node | |
93 | + | |
94 | + // Display the updated array | |
95 | +/* cout << "Updated dangleNodes array:" << endl; | |
96 | + for( int k = 0; k < count-1; k++ ) | |
97 | + { | |
98 | + cout << dangleNodes[k] << endl; | |
99 | + } | |
100 | +*/ | |
101 | + // Decrement the counters | |
102 | + i--; | |
103 | + j--; | |
104 | + count--; | |
105 | + numPress--; // Decrement to the exact number of dangle nodes | |
106 | + } | |
107 | + } | |
108 | + } | |
109 | + | |
110 | + return numPress; // Number of dangle nodes | |
111 | +} | |
112 | + | |
113 | + | |
114 | +// Function to make a backup copy of the contents of a matrix to a .txt file | |
115 | +// Created by Cherub P. Harder (8/10/2015), U of Houston | |
116 | +void flow::backupToTxt(unsigned int nL, double **D, char filename[]) | |
117 | +{ | |
118 | + ofstream output_file(filename); | |
119 | + | |
120 | + for( unsigned int i = 0; i < nL; i++ ) | |
121 | + { | |
122 | + for( int j = 0; j < 4; j++ ) | |
123 | + { | |
124 | + if( j < 3 ) | |
125 | + output_file << D[i][j] << "\t"; | |
126 | + | |
127 | + else | |
128 | + output_file << D[i][j]; | |
129 | + } | |
130 | + | |
131 | + output_file << "\n"; | |
132 | + } | |
133 | + | |
134 | + output_file.close( ); | |
135 | +} | |
136 | + | |
137 | + | |
138 | +// Function to make separate copies of the source nodes, destination nodes, radii, and lengths | |
139 | +// Created by Cherub P. Harder (8/10/2015), U of Houston | |
140 | +tuple<int, int> flow::copySrcDesRadLen(char filename[]) | |
141 | +{ | |
142 | + int cnt = 0, numElements = 0, numNodes = 0; | |
143 | + float number = 0.0; | |
144 | + ofstream srcData("srcCol.txt"); // A .txt file to store the source nodes | |
145 | + ofstream desData("destCol.txt"); // A .txt file to store the destination nodes | |
146 | + ofstream radiiData("radii.txt"); // A .txt file to store the radii | |
147 | + ofstream lenData("lengths.txt"); // A .txt file to store the lengths | |
148 | + FILE *fp = fopen(filename, "r"); // Create a variable of type FILE* and open the file using | |
149 | + // the fopen function and assign the file to the variable | |
150 | + // Check if the file exists | |
151 | + if(fp == NULL) // Alternative: if(!fp) | |
152 | + { | |
153 | + printf("Error! File does not exist.\n"); | |
154 | + getchar( ); // Pause | |
155 | + exit(-1); // NOTE: Must include stdlib.h. | |
156 | + } | |
157 | + | |
158 | + // Store data to their respective .txt files | |
159 | + while(fscanf(fp, "%f", &number) == 1) | |
160 | + { | |
161 | + cnt++; // Increment counter | |
162 | + | |
163 | + // Store to srcCol.txt | |
164 | + if(cnt == 1) | |
165 | + srcData << number << endl; | |
166 | + | |
167 | + // Store to destCol.txt | |
168 | + if(cnt == 2) | |
169 | + desData << number << endl; | |
170 | + | |
171 | + // Save the current number of nodes | |
172 | + if(cnt < 3) | |
173 | + { | |
174 | + if(number > numNodes) | |
175 | + numNodes = (int)number; | |
176 | + } | |
177 | + | |
178 | + // Store to radii.txt | |
179 | + if(cnt == 3) | |
180 | + radiiData << number << endl; | |
181 | + | |
182 | + // Store to lengths.txt | |
183 | + if(cnt == 4) | |
184 | + { | |
185 | + lenData << number << endl; | |
186 | + | |
187 | + numElements++; // Count the elements | |
188 | + cnt = 0; // Reset counter | |
189 | + } | |
190 | + } | |
191 | + | |
192 | + srcData.close( ); | |
193 | + desData.close( ); | |
194 | + radiiData.close( ); | |
195 | + lenData.close( ); | |
196 | + | |
197 | + return make_tuple(numNodes, numElements); // Return two values | |
198 | +} | |
199 | + | |
200 | + | |
201 | +// Function to copy data for .txt files to their respective arrays | |
202 | +// Created by Cherub P. Harder (8/11/2015), U of Houston | |
203 | +void flow::copyToArray(int *src, int *dest, double *radii, double *len) | |
204 | +{ | |
205 | + int v = 0; | |
206 | + double tmp = 0, R = 0, L = 0; | |
207 | + | |
208 | + // Store source node values to the array src | |
209 | + ifstream readSrc("srcCol.txt"); | |
210 | + | |
211 | + while( readSrc >> tmp ) | |
212 | + { | |
213 | + src[v] = (int)tmp; | |
214 | + v++; | |
215 | + } | |
216 | + | |
217 | + readSrc.close( ); | |
218 | + | |
219 | + // Store destination node values to the array dest | |
220 | + v = 0; // Reset counter | |
221 | + ifstream readDest("destCol.txt"); | |
222 | + | |
223 | + while( readDest >> tmp ) | |
224 | + { | |
225 | + dest[v] = (int)tmp; | |
226 | + v++; | |
227 | + } | |
228 | + | |
229 | + readDest.close( ); | |
230 | + | |
231 | + // Store radius values to the array radii | |
232 | + v = 0; // Reset counter | |
233 | + ifstream readRad("radii.txt"); | |
234 | + | |
235 | + while( readRad >> tmp ) | |
236 | + { | |
237 | + radii[v] = tmp; | |
238 | + v++; | |
239 | + } | |
240 | + | |
241 | + readRad.close( ); | |
242 | + | |
243 | + // Store length values to the array len | |
244 | + v = 0; // Reset counter | |
245 | + ifstream readLen("lengths.txt"); | |
246 | + | |
247 | + while( readLen >> tmp ) | |
248 | + { | |
249 | + len[v] = tmp; | |
250 | + v++; | |
251 | + } | |
252 | + | |
253 | + readLen.close( ); | |
254 | +} | |
255 | + | |
256 | + | |
257 | +// Function to find the inverse of a square matrix | |
258 | +void flow::inversion(double **a, int n, double **b) | |
259 | +{ | |
260 | + // Get 1 over the determinant of A | |
261 | + double det = (double)(1.0/determinant(a, n)); | |
262 | +// cerr << "\n1/det(C) = " << det << endl; // DELETE!!! | |
263 | + | |
264 | + // Memory allocation | |
265 | + double *tmp = new double[(n-1) * (n-1)]; | |
266 | + double **m = new double * [n-1]; | |
267 | + for( int i = 0; i < n-1; i++ ) | |
268 | + m[i] = tmp + ( i * (n-1) ); | |
269 | + | |
270 | + for( int j = 0; j < n; j++) | |
271 | + { | |
272 | + for( int i = 0; i < n; i++ ) | |
273 | + { | |
274 | + // Get the cofactor (matrix) of a(j,i) | |
275 | + minor(a, m, j, i, n); | |
276 | + b[i][j] = det * determinant( m, n-1 ); | |
277 | + if( (i+j)%2 == 1 ) | |
278 | + b[i][j] = -b[i][j]; | |
279 | + } | |
280 | + } | |
281 | + | |
282 | + // Release memory | |
283 | + // Delete [] minor[0]; | |
284 | + delete [] tmp; | |
285 | + delete [] m; | |
286 | +} | |
287 | + | |
288 | + | |
289 | +// Function to find the determinant of a matrix using recursion | |
290 | +// Contribution by Edward Popko | |
291 | +// Modified by Cherub P. Harder (7/15/2015), U of Houston | |
292 | +// Arguments: a(double **) - pointer to a pointer of an arbitrary square matrix | |
293 | +// n(int) - dimension of the square matrix | |
294 | +float flow::determinant(double **a, int n) | |
295 | +{ | |
296 | + int i, j, j1, j2; // General loop and matrix subscripts | |
297 | + double det = 0; // Initialize determinant | |
298 | + double **m = NULL; // Pointer to pointer to implement 2D square array | |
299 | + | |
300 | + // Display contents of matrix C (DELETE!!!) | |
301 | +/* std::cout << "\nThe updated matrix C:\n"; | |
302 | + for( int j = 0; j < n; ++j ) | |
303 | + { | |
304 | + std::cerr << "\t"; | |
305 | + | |
306 | + for( int k = 0; k < n; ++k ) | |
307 | + std::cerr << left << setw(15) << a[j][k]; | |
308 | + | |
309 | + std::cerr << endl; | |
310 | + } | |
311 | + | |
312 | + getchar(); // DELETE!!!*/ | |
313 | + | |
314 | + if(n < 1) { } // Error condition - should never get here | |
315 | + | |
316 | + else if (n == 1) // Should never get here | |
317 | + { | |
318 | + det = a[0][0]; | |
319 | + } | |
320 | + | |
321 | + else if(n == 2) // Basic 2x2 sub-matrix determinate definition | |
322 | + { // When n == 2, this ends the recursion series | |
323 | + det = a[0][0] * a[1][1] - a[1][0] * a[0][1]; | |
324 | + } | |
325 | + // Recursion continues, solve next sub-matrix | |
326 | + else // Solve the next minor by building a sub-matrix | |
327 | + { | |
328 | + det = 0; // Initialize determinant of sub-matrix | |
329 | + | |
330 | + for (j1 = 0; j1 < n; j1++) // For each column in sub-matrix get space for the | |
331 | + { // pointer list | |
332 | + m = (double **) malloc((n-1) * sizeof(double *)); | |
333 | + | |
334 | + for (i = 0; i < n-1; i++) | |
335 | + m[i] = (double *) malloc((n-1)* sizeof(double)); | |
336 | + // i[0][1][2][3] first malloc | |
337 | + // m -> + + + + space for 4 pointers | |
338 | + // | | | | j second malloc | |
339 | + // | | | +-> _ _ _ [0] pointers to | |
340 | + // | | +----> _ _ _ [1] and memory for | |
341 | + // | +-------> _ a _ [2] 4 doubles | |
342 | + // +----------> _ _ _ [3] | |
343 | + // | |
344 | + // a[1][2] | |
345 | + // Build sub-matrix with minor elements excluded | |
346 | + | |
347 | + for (i = 1; i < n; i++) | |
348 | + { | |
349 | + j2 = 0 ; // Start at first sum-matrix column position | |
350 | + // Loop to copy source matrix less one column | |
351 | + for (j = 0; j < n; j++) | |
352 | + { | |
353 | + if (j == j1) continue; // Do not copy the minor column element | |
354 | + | |
355 | + m[i-1][j2] = a[i][j]; // Copy source element into new sub-matrix | |
356 | + // i-1 because new sub-matrix is one row | |
357 | + // (and column) smaller with excluded minors | |
358 | + j2++; // Move to next sub-matrix column position | |
359 | + } | |
360 | + } | |
361 | + | |
362 | + det += (double)pow(-1.0, 1.0 + j1 + 1.0) * a[0][j1] * determinant(m, n-1); | |
363 | + // Sum x raised to y power | |
364 | + // recursively get determinant of next | |
365 | + // sub-matrix which is now one | |
366 | + // row & column smaller | |
367 | + | |
368 | + for (i = 0; i < n-1; i++) free(m[i]); // Free the storage allocated to | |
369 | + // this minor's set of pointers | |
370 | + free(m); // Free the storage for the original | |
371 | + // pointer to pointer | |
372 | + } | |
373 | + } | |
374 | + | |
375 | + return(det); | |
376 | +} | |
377 | + | |
378 | + | |
379 | +// Function to calculate the cofactor of element (row, col) | |
380 | +int flow::minor(double **src, double **dest, int row, int col, int order) | |
381 | +{ | |
382 | + // Indicate which col and row is being copied to dest | |
383 | + int colCount=0,rowCount=0; | |
384 | + | |
385 | + for(int i = 0; i < order; i++) | |
386 | + { | |
387 | + if(i != row) | |
388 | + { | |
389 | + colCount = 0; | |
390 | + for(int j = 0; j < order; j++) | |
391 | + { | |
392 | + // When j is not the element | |
393 | + if( j != col ) | |
394 | + { | |
395 | + dest[rowCount][colCount] = src[i][j]; | |
396 | + colCount++; | |
397 | + } | |
398 | + } | |
399 | + | |
400 | + rowCount++; | |
401 | + } | |
402 | + } | |
403 | + | |
404 | + return 1; | |
405 | +} | |
0 | 406 | \ No newline at end of file | ... | ... |