Commit 28b882ce020c50db81326f56c344c2aa0f4d1b84

Authored by Jiaming Guo
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 \ No newline at end of file 273 \ No newline at end of file
  274 +#endif
407 \ No newline at end of file 275 \ No newline at end of file
stim/biomodels/flow_dep.h 0 โ†’ 100644
  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 \ No newline at end of file 406 \ No newline at end of file