Commit b61addd86534d3a979f98d8c777a6077a6359066
1 parent
b94dd1e0
add adjustment feature. fix utilzing aabb for testing overlapping bugs. add save function.
Showing
2 changed files
with
356 additions
and
98 deletions
Show diff stats
@@ -57,6 +57,12 @@ namespace stim { | @@ -57,6 +57,12 @@ namespace stim { | ||
57 | T h; // height | 57 | T h; // height |
58 | }; | 58 | }; |
59 | 59 | ||
60 | + template <typename T> | ||
61 | + struct circuit { | ||
62 | + std::vector<typename std::pair<unsigned, unsigned> > v; // end vertex index | ||
63 | + std::vector<T> r; // branch resistence | ||
64 | + }; | ||
65 | + | ||
60 | /// indicator function | 66 | /// indicator function |
61 | #ifdef __CUDACC__ | 67 | #ifdef __CUDACC__ |
62 | // for sphere | 68 | // for sphere |
@@ -240,6 +246,7 @@ namespace stim { | @@ -240,6 +246,7 @@ namespace stim { | ||
240 | std::vector<T> pressure; // final pressure | 246 | std::vector<T> pressure; // final pressure |
241 | std::vector<typename std::vector<typename stim::vec3<T> > > in_backup; // inlet connection back up | 247 | std::vector<typename std::vector<typename stim::vec3<T> > > in_backup; // inlet connection back up |
242 | std::vector<typename std::vector<typename stim::vec3<T> > > out_backup; | 248 | std::vector<typename std::vector<typename stim::vec3<T> > > out_backup; |
249 | + std::string units; // length units | ||
243 | 250 | ||
244 | public: | 251 | public: |
245 | 252 | ||
@@ -260,13 +267,15 @@ namespace stim { | @@ -260,13 +267,15 @@ namespace stim { | ||
260 | std::vector<bool> outlet_feasibility; | 267 | std::vector<bool> outlet_feasibility; |
261 | std::vector<typename std::pair<stim::vec3<T>, stim::vec3<T> > > inbb; // inlet connection bounding box | 268 | std::vector<typename std::pair<stim::vec3<T>, stim::vec3<T> > > inbb; // inlet connection bounding box |
262 | std::vector<typename std::pair<stim::vec3<T>, stim::vec3<T> > > outbb; // outlet connection bounding box | 269 | std::vector<typename std::pair<stim::vec3<T>, stim::vec3<T> > > outbb; // outlet connection bounding box |
270 | + T Ps; // source and end pressure | ||
271 | + T Pe; | ||
263 | 272 | ||
264 | flow() {} // default constructor | 273 | flow() {} // default constructor |
265 | ~flow() { | 274 | ~flow() { |
266 | for (unsigned i = 0; i < num_vertex; i++) | 275 | for (unsigned i = 0; i < num_vertex; i++) |
267 | delete[] C[i]; | 276 | delete[] C[i]; |
268 | delete[] C; | 277 | delete[] C; |
269 | - } | 278 | + } // default destructor |
270 | 279 | ||
271 | void init(unsigned n_e, unsigned n_v) { | 280 | void init(unsigned n_e, unsigned n_v) { |
272 | 281 | ||
@@ -307,6 +316,10 @@ namespace stim { | @@ -307,6 +316,10 @@ namespace stim { | ||
307 | } | 316 | } |
308 | } | 317 | } |
309 | 318 | ||
319 | + void set_units(std::string u) { | ||
320 | + units = u; | ||
321 | + } | ||
322 | + | ||
310 | // copy radius from cylinder to flow | 323 | // copy radius from cylinder to flow |
311 | void set_radius(unsigned i, T radius) { | 324 | void set_radius(unsigned i, T radius) { |
312 | 325 | ||
@@ -384,7 +397,7 @@ namespace stim { | @@ -384,7 +397,7 @@ namespace stim { | ||
384 | start_vertex = get_start_vertex(i); // get the start vertex index of current edge | 397 | start_vertex = get_start_vertex(i); // get the start vertex index of current edge |
385 | end_vertex = get_end_vertex(i); // get the end vertex index of current edge | 398 | end_vertex = get_end_vertex(i); // get the end vertex index of current edge |
386 | 399 | ||
387 | - C[start_vertex][end_vertex] = -((float)stim::PI * std::pow(get_average_r(i), 4)) / (8 * u * get_l(i)); | 400 | + C[start_vertex][end_vertex] = -((T)stim::PI * std::pow(get_average_r(i), 4)) / (8 * u * get_l(i)); |
388 | 401 | ||
389 | C[end_vertex][start_vertex] = C[start_vertex][end_vertex]; | 402 | C[end_vertex][start_vertex] = C[start_vertex][end_vertex]; |
390 | } | 403 | } |
@@ -427,9 +440,9 @@ namespace stim { | @@ -427,9 +440,9 @@ namespace stim { | ||
427 | } | 440 | } |
428 | 441 | ||
429 | // get the flow state from known pressure | 442 | // get the flow state from known pressure |
430 | - float start_pressure = 0.0; | ||
431 | - float end_pressure = 0.0; | ||
432 | - float deltaP = 0.0; | 443 | + T start_pressure = 0.0; |
444 | + T end_pressure = 0.0; | ||
445 | + T deltaP = 0.0; | ||
433 | for (unsigned i = 0; i < num_edge; i++) { | 446 | for (unsigned i = 0; i < num_edge; i++) { |
434 | start_vertex = get_start_vertex(i); | 447 | start_vertex = get_start_vertex(i); |
435 | end_vertex = get_end_vertex(i); | 448 | end_vertex = get_end_vertex(i); |
@@ -440,8 +453,8 @@ namespace stim { | @@ -440,8 +453,8 @@ namespace stim { | ||
440 | Q[i].first = start_vertex; | 453 | Q[i].first = start_vertex; |
441 | Q[i].second = end_vertex; | 454 | Q[i].second = end_vertex; |
442 | 455 | ||
443 | - Q[i].third = ((float)stim::PI * std::pow(get_average_r(i), 4) * deltaP) / (8 * u * get_l(i)); | ||
444 | - v[i] = Q[i].third / ((float)stim::PI * std::pow(get_average_r(i), 2)); | 456 | + Q[i].third = ((T)stim::PI * std::pow(get_average_r(i), 4) * deltaP) / (8 * u * get_l(i)); |
457 | + v[i] = Q[i].third / ((T)stim::PI * std::pow(get_average_r(i), 2)); | ||
445 | } | 458 | } |
446 | } | 459 | } |
447 | 460 | ||
@@ -474,12 +487,12 @@ namespace stim { | @@ -474,12 +487,12 @@ namespace stim { | ||
474 | void print_flow() { | 487 | void print_flow() { |
475 | 488 | ||
476 | // show the pressure information in console box | 489 | // show the pressure information in console box |
477 | - std::cout << "PRESSURE(g/um/s^2):" << std::endl; | 490 | + std::cout << "PRESSURE(g/" << units << "/s^2):" << std::endl; |
478 | for (unsigned i = 0; i < num_vertex; i++) { | 491 | for (unsigned i = 0; i < num_vertex; i++) { |
479 | std::cout << "[" << i << "] " << pressure[i] << std::endl; | 492 | std::cout << "[" << i << "] " << pressure[i] << std::endl; |
480 | } | 493 | } |
481 | // show the flow rate information in console box | 494 | // show the flow rate information in console box |
482 | - std::cout << "VOLUME FLOW RATE(um^3/s):" << std::endl; | 495 | + std::cout << "VOLUME FLOW RATE(" << units << "^3/s):" << std::endl; |
483 | for (unsigned i = 0; i < num_edge; i++) { | 496 | for (unsigned i = 0; i < num_edge; i++) { |
484 | std::cout << "(" << Q[i].first << "," << Q[i].second << ")" << Q[i].third << std::endl; | 497 | std::cout << "(" << Q[i].first << "," << Q[i].second << ")" << Q[i].third << std::endl; |
485 | } | 498 | } |
@@ -1000,14 +1013,17 @@ namespace stim { | @@ -1000,14 +1013,17 @@ namespace stim { | ||
1000 | } | 1013 | } |
1001 | 1014 | ||
1002 | // draw main feeder as solid cube | 1015 | // draw main feeder as solid cube |
1003 | - void glSolidCuboid(T length = 40.0f, T height = 10.0f) { | 1016 | + void glSolidCuboid(bool manufacture = false, T length = 40.0f, T height = 10.0f) { |
1004 | 1017 | ||
1005 | T width; | 1018 | T width; |
1006 | stim::vec3<T> L = bb.A; // get the bottom left corner | 1019 | stim::vec3<T> L = bb.A; // get the bottom left corner |
1007 | stim::vec3<T> U = bb.B; // get the top right corner | 1020 | stim::vec3<T> U = bb.B; // get the top right corner |
1008 | width = U[2] - L[2] + 10.0f; | 1021 | width = U[2] - L[2] + 10.0f; |
1009 | 1022 | ||
1010 | - glColor3f(0.0f, 0.0f, 0.0f); | 1023 | + if (manufacture) |
1024 | + glColor3f(0.0f, 0.0f, 0.0f); // black color | ||
1025 | + else | ||
1026 | + glColor3f(0.5f, 0.5f, 0.5f); // gray color | ||
1011 | for (unsigned i = 0; i < main_feeder.size(); i++) { | 1027 | for (unsigned i = 0; i < main_feeder.size(); i++) { |
1012 | // front face | 1028 | // front face |
1013 | glBegin(GL_QUADS); | 1029 | glBegin(GL_QUADS); |
@@ -1060,6 +1076,35 @@ namespace stim { | @@ -1060,6 +1076,35 @@ namespace stim { | ||
1060 | glFlush(); | 1076 | glFlush(); |
1061 | } | 1077 | } |
1062 | 1078 | ||
1079 | + // display the total volume flow rate | ||
1080 | + void display_flow_rate(T in, T out) { | ||
1081 | + | ||
1082 | + glMatrixMode(GL_PROJECTION); // set up the 2d viewport for mode text printing | ||
1083 | + glPushMatrix(); | ||
1084 | + glLoadIdentity(); | ||
1085 | + int X = glutGet(GLUT_WINDOW_WIDTH); // get the current window width | ||
1086 | + int Y = glutGet(GLUT_WINDOW_HEIGHT); // get the current window height | ||
1087 | + glViewport(0, 0, X, Y); // locate to left bottom corner | ||
1088 | + gluOrtho2D(0, X, 0, Y); // define othogonal aspect | ||
1089 | + glColor3f(0.8f, 0.0f, 0.0f); // using red to show mode | ||
1090 | + glMatrixMode(GL_MODELVIEW); | ||
1091 | + glPushMatrix(); | ||
1092 | + glLoadIdentity(); | ||
1093 | + | ||
1094 | + glRasterPos2f(X / 2, 5); // hard coded position!!!!! | ||
1095 | + std::stringstream ss_p; | ||
1096 | + ss_p << "Q = "; // Q = * um^3/s | ||
1097 | + ss_p << in; | ||
1098 | + ss_p << " "; | ||
1099 | + ss_p << units; | ||
1100 | + ss_p << "^3/s"; | ||
1101 | + glutBitmapString(GLUT_BITMAP_TIMES_ROMAN_24, (const unsigned char*)(ss_p.str().c_str())); | ||
1102 | + | ||
1103 | + glPopMatrix(); | ||
1104 | + glMatrixMode(GL_PROJECTION); | ||
1105 | + glPopMatrix(); | ||
1106 | + } | ||
1107 | + | ||
1063 | // draw the bridge as lines | 1108 | // draw the bridge as lines |
1064 | void line_bridge(bool &redisplay) { | 1109 | void line_bridge(bool &redisplay) { |
1065 | 1110 | ||
@@ -1409,7 +1454,7 @@ namespace stim { | @@ -1409,7 +1454,7 @@ namespace stim { | ||
1409 | inlet_main_feeder = stim::vec3<T>(bb.A[0] - border, bb.center()[1], bb.center()[2]); | 1454 | inlet_main_feeder = stim::vec3<T>(bb.A[0] - border, bb.center()[1], bb.center()[2]); |
1410 | outlet_main_feeder = stim::vec3<T>(bb.B[0] + border, bb.center()[1], bb.center()[2]); | 1455 | outlet_main_feeder = stim::vec3<T>(bb.B[0] + border, bb.center()[1], bb.center()[2]); |
1411 | 1456 | ||
1412 | - main_feeder.push_back(inlet_main_feeder); | 1457 | + main_feeder.push_back(inlet_main_feeder); // 0->inlet, 1->outlet |
1413 | main_feeder.push_back(outlet_main_feeder); | 1458 | main_feeder.push_back(outlet_main_feeder); |
1414 | 1459 | ||
1415 | // find both input and output vertex | 1460 | // find both input and output vertex |
@@ -1550,22 +1595,42 @@ namespace stim { | @@ -1550,22 +1595,42 @@ namespace stim { | ||
1550 | tmp_v = outlet[i].V[outlet[i].V.size() - 1]; | 1595 | tmp_v = outlet[i].V[outlet[i].V.size() - 1]; |
1551 | tmp_bb.first = tmp_v; | 1596 | tmp_bb.first = tmp_v; |
1552 | 1597 | ||
1553 | - // check whether the height of connections is acceptable | ||
1554 | - if (height > threshold) { // acceptable | ||
1555 | - // re-calculate height | ||
1556 | - if (ratio > 0.0f && ratio <= 1.0f) { // use fragment if set | ||
1557 | - cor_v = tmp_v + stim::vec3<T>(-coef_left * origin_l, 0, 0); // get the original corner vertex | ||
1558 | - desire_l = desire_l - origin_l * (1.0f - ratio / 1.0f); | ||
1559 | - origin_l = (T)origin_l * ratio / 1.0f; | 1598 | + // pre-set fragments |
1599 | + if (ratio) { | ||
1600 | + T tmp_d, tmp_l; // back ups | ||
1601 | + tmp_d = desire_l; | ||
1602 | + tmp_l = origin_l; | ||
1603 | + | ||
1604 | + cor_v = tmp_v + stim::vec3<T>(-coef_left * origin_l, 0, 0); // get the original corner vertex | ||
1605 | + desire_l = desire_l - origin_l * (1.0f - ratio / 1.0f); | ||
1606 | + origin_l = (T)origin_l * ratio / 1.0f; | ||
1607 | + n = find_number_square(origin_l, desire_l); | ||
1608 | + | ||
1609 | + width = (T)origin_l / (2 * n); // updates | ||
1610 | + height = (desire_l - origin_l) / (2 * n); | ||
1611 | + | ||
1612 | + if (width < times * radius) { // check feasibility | ||
1613 | + ratio = 0.0f; // load | ||
1614 | + desire_l = tmp_d; | ||
1615 | + origin_l = tmp_l; | ||
1616 | + | ||
1617 | + std::cout << "Warning: current ratio is not feasible, use full original line." << std::endl; | ||
1560 | n = find_number_square(origin_l, desire_l); | 1618 | n = find_number_square(origin_l, desire_l); |
1619 | + | ||
1620 | + width = (T)origin_l / (2 * n); // updates | ||
1621 | + height = (desire_l - origin_l) / (2 * n); | ||
1561 | } | 1622 | } |
1562 | - height = (desire_l - (1 + 2 * n) * origin_l) / std::pow(2 * n, 2); | ||
1563 | - // check whether the connections are good | ||
1564 | - while (height > threshold) { | 1623 | + } |
1624 | + | ||
1625 | + // check whether it needs 3D square-wave-like connections | ||
1626 | + if (height > threshold) { // enbale 3D connections | ||
1627 | + | ||
1628 | + height = (desire_l - (1 + 2 * n) * origin_l) / std::pow(2 * n, 2); // compute new height in 3D structure | ||
1629 | + while (height > threshold) { // increase order to decrease height | ||
1565 | n++; | 1630 | n++; |
1566 | width = (T)(origin_l) / (2 * n); | 1631 | width = (T)(origin_l) / (2 * n); |
1567 | height = (desire_l - (1 + 2 * n) * origin_l) / std::pow(2 * n, 2); | 1632 | height = (desire_l - (1 + 2 * n) * origin_l) / std::pow(2 * n, 2); |
1568 | - // check whether it appears overlap | 1633 | + // check whether it appears overlap, if it appears we choose last time height even if it is larger than threshold |
1569 | if (width < times * radius) { | 1634 | if (width < times * radius) { |
1570 | n--; | 1635 | n--; |
1571 | width = (T)(origin_l) / (2 * n); | 1636 | width = (T)(origin_l) / (2 * n); |
@@ -1573,12 +1638,21 @@ namespace stim { | @@ -1573,12 +1638,21 @@ namespace stim { | ||
1573 | break; | 1638 | break; |
1574 | } | 1639 | } |
1575 | } | 1640 | } |
1641 | + | ||
1642 | + // check overlap in terms of height, has potential risk when both height and width are less than times * radius. | ||
1576 | while (height < times * radius) { | 1643 | while (height < times * radius) { |
1577 | n--; | 1644 | n--; |
1578 | width = (T)(origin_l) / (2 * n); | 1645 | width = (T)(origin_l) / (2 * n); |
1579 | height = (desire_l - (1 + 2 * n) * origin_l) / std::pow(2 * n, 2); | 1646 | height = (desire_l - (1 + 2 * n) * origin_l) / std::pow(2 * n, 2); |
1580 | } | 1647 | } |
1581 | 1648 | ||
1649 | + // degenerated case | ||
1650 | + if (n == 0) { | ||
1651 | + n = 1; | ||
1652 | + width = (T)(origin_l) / (2 * n); | ||
1653 | + height = (desire_l - (1 + 2 * n) * origin_l) / std::pow(2 * n, 2); | ||
1654 | + } | ||
1655 | + | ||
1582 | // cube-like structure construction | 1656 | // cube-like structure construction |
1583 | for (int j = 0; j < n; j++) { | 1657 | for (int j = 0; j < n; j++) { |
1584 | // "up" | 1658 | // "up" |
@@ -1601,7 +1675,7 @@ namespace stim { | @@ -1601,7 +1675,7 @@ namespace stim { | ||
1601 | inlet[i].V.push_back(tmp_v); | 1675 | inlet[i].V.push_back(tmp_v); |
1602 | else if (feeder == 0) | 1676 | else if (feeder == 0) |
1603 | outlet[i].V.push_back(tmp_v); | 1677 | outlet[i].V.push_back(tmp_v); |
1604 | - // "down" | 1678 | + // "up" |
1605 | tmp_v = tmp_v + stim::vec3<T>(0, inverse * coef_up * width, 0); | 1679 | tmp_v = tmp_v + stim::vec3<T>(0, inverse * coef_up * width, 0); |
1606 | if (feeder == 1) | 1680 | if (feeder == 1) |
1607 | inlet[i].V.push_back(tmp_v); | 1681 | inlet[i].V.push_back(tmp_v); |
@@ -1623,27 +1697,28 @@ namespace stim { | @@ -1623,27 +1697,28 @@ namespace stim { | ||
1623 | 1697 | ||
1624 | // "down" | 1698 | // "down" |
1625 | for (int k = 0; k < n; k++) { | 1699 | for (int k = 0; k < n; k++) { |
1626 | - | 1700 | + // in |
1627 | tmp_v = tmp_v + stim::vec3<T>(0, 0, coef_z * height); | 1701 | tmp_v = tmp_v + stim::vec3<T>(0, 0, coef_z * height); |
1628 | if (feeder == 1) | 1702 | if (feeder == 1) |
1629 | inlet[i].V.push_back(tmp_v); | 1703 | inlet[i].V.push_back(tmp_v); |
1630 | else if (feeder == 0) | 1704 | else if (feeder == 0) |
1631 | outlet[i].V.push_back(tmp_v); | 1705 | outlet[i].V.push_back(tmp_v); |
1706 | + // get the bounding box edge | ||
1632 | if (j == n - 1 && k == 0) // first time go "in" | 1707 | if (j == n - 1 && k == 0) // first time go "in" |
1633 | tmp_bb.second = tmp_v; | 1708 | tmp_bb.second = tmp_v; |
1634 | - | 1709 | + // "down" |
1635 | tmp_v = tmp_v + stim::vec3<T>(0, inverse * coef_up * width, 0); | 1710 | tmp_v = tmp_v + stim::vec3<T>(0, inverse * coef_up * width, 0); |
1636 | if (feeder == 1) | 1711 | if (feeder == 1) |
1637 | inlet[i].V.push_back(tmp_v); | 1712 | inlet[i].V.push_back(tmp_v); |
1638 | else if (feeder == 0) | 1713 | else if (feeder == 0) |
1639 | outlet[i].V.push_back(tmp_v); | 1714 | outlet[i].V.push_back(tmp_v); |
1640 | - | 1715 | + // out |
1641 | tmp_v = tmp_v + stim::vec3<T>(0, 0, -coef_z * height); | 1716 | tmp_v = tmp_v + stim::vec3<T>(0, 0, -coef_z * height); |
1642 | if (feeder == 1) | 1717 | if (feeder == 1) |
1643 | inlet[i].V.push_back(tmp_v); | 1718 | inlet[i].V.push_back(tmp_v); |
1644 | else if (feeder == 0) | 1719 | else if (feeder == 0) |
1645 | outlet[i].V.push_back(tmp_v); | 1720 | outlet[i].V.push_back(tmp_v); |
1646 | - | 1721 | + // "down" |
1647 | tmp_v = tmp_v + stim::vec3<T>(0, inverse * coef_up * width, 0); | 1722 | tmp_v = tmp_v + stim::vec3<T>(0, inverse * coef_up * width, 0); |
1648 | if (feeder == 1) | 1723 | if (feeder == 1) |
1649 | inlet[i].V.push_back(tmp_v); | 1724 | inlet[i].V.push_back(tmp_v); |
@@ -1671,12 +1746,13 @@ namespace stim { | @@ -1671,12 +1746,13 @@ namespace stim { | ||
1671 | outlet[i].V.push_back(cor_v); | 1746 | outlet[i].V.push_back(cor_v); |
1672 | } | 1747 | } |
1673 | } | 1748 | } |
1749 | + // use 2D square-wave-like connections | ||
1674 | else { | 1750 | else { |
1675 | if (height < times * radius) { // if height is too small, decrease n and re-calculate height and width | 1751 | if (height < times * radius) { // if height is too small, decrease n and re-calculate height and width |
1676 | height = times * radius; | 1752 | height = times * radius; |
1677 | T need_l = desire_l - origin_l; | 1753 | T need_l = desire_l - origin_l; |
1678 | n = need_l / (2 * height); | 1754 | n = need_l / (2 * height); |
1679 | - if (n == 0) | 1755 | + if (n == 0) // degenerated case |
1680 | n = 1; | 1756 | n = 1; |
1681 | height = need_l / (2 * n); | 1757 | height = need_l / (2 * n); |
1682 | width = origin_l / (2 * n); | 1758 | width = origin_l / (2 * n); |
@@ -1713,6 +1789,13 @@ namespace stim { | @@ -1713,6 +1789,13 @@ namespace stim { | ||
1713 | else if (feeder == 0) | 1789 | else if (feeder == 0) |
1714 | outlet[i].V.push_back(tmp_v); | 1790 | outlet[i].V.push_back(tmp_v); |
1715 | } | 1791 | } |
1792 | + // if use fragment to do square wave connection, need to push_back the corner vertex | ||
1793 | + if (ratio > 0.0f && ratio < 1.0f) { | ||
1794 | + if (feeder == 1) | ||
1795 | + inlet[i].V.push_back(cor_v); | ||
1796 | + else if (feeder == 0) | ||
1797 | + outlet[i].V.push_back(cor_v); | ||
1798 | + } | ||
1716 | } | 1799 | } |
1717 | if (feeder == 1) | 1800 | if (feeder == 1) |
1718 | inbb[i] = tmp_bb; | 1801 | inbb[i] = tmp_bb; |
@@ -1721,7 +1804,7 @@ namespace stim { | @@ -1721,7 +1804,7 @@ namespace stim { | ||
1721 | } | 1804 | } |
1722 | 1805 | ||
1723 | // automatically modify bridge to make it feasible | 1806 | // automatically modify bridge to make it feasible |
1724 | - void modify_synthetic_connection(T viscosity, T rou, bool H, T threshold, T ratio = 0.0f, T radius = 5.0f) { | 1807 | + void modify_synthetic_connection(T viscosity, T rou, bool H, T threshold, T &in, T &out, T ratio = 0.0f, T radius = 5.0f) { |
1725 | 1808 | ||
1726 | glDeleteLists(dlist, 1); // delete display list for modify | 1809 | glDeleteLists(dlist, 1); // delete display list for modify |
1727 | glDeleteLists(dlist + 1, 1); | 1810 | glDeleteLists(dlist + 1, 1); |
@@ -1751,6 +1834,7 @@ namespace stim { | @@ -1751,6 +1834,7 @@ namespace stim { | ||
1751 | inlet_index = i; | 1834 | inlet_index = i; |
1752 | } | 1835 | } |
1753 | } | 1836 | } |
1837 | + Ps = source_pressure; | ||
1754 | 1838 | ||
1755 | // find minimum pressure outlet port | 1839 | // find minimum pressure outlet port |
1756 | T end_pressure = FLT_MAX; | 1840 | T end_pressure = FLT_MAX; |
@@ -1762,6 +1846,7 @@ namespace stim { | @@ -1762,6 +1846,7 @@ namespace stim { | ||
1762 | outlet_index = i; | 1846 | outlet_index = i; |
1763 | } | 1847 | } |
1764 | } | 1848 | } |
1849 | + Pe = end_pressure; | ||
1765 | 1850 | ||
1766 | // automatically modify inlet bridge using Hilbert curves | 1851 | // automatically modify inlet bridge using Hilbert curves |
1767 | if (H) { | 1852 | if (H) { |
@@ -1990,7 +2075,7 @@ namespace stim { | @@ -1990,7 +2075,7 @@ namespace stim { | ||
1990 | width = (T)origin_l / (2 * n); | 2075 | width = (T)origin_l / (2 * n); |
1991 | height = (desire_l - origin_l) / (2 * n); | 2076 | height = (desire_l - origin_l) / (2 * n); |
1992 | 2077 | ||
1993 | - build_square_connection(i, width, height, origin_l, desire_l, n, 1, threshold, z, true, upper, 10, ratio); | 2078 | + build_square_connection(i, width, height, origin_l, desire_l, n, 1, threshold, z, true, upper, 5, ratio); |
1994 | inlet[i].V.push_back(bus_v); | 2079 | inlet[i].V.push_back(bus_v); |
1995 | 2080 | ||
1996 | std::reverse(inlet[i].V.begin(), inlet[i].V.end()); // from bus to pendant vertex | 2081 | std::reverse(inlet[i].V.begin(), inlet[i].V.end()); // from bus to pendant vertex |
@@ -2039,7 +2124,7 @@ namespace stim { | @@ -2039,7 +2124,7 @@ namespace stim { | ||
2039 | width = (T)origin_l / (2 * n); | 2124 | width = (T)origin_l / (2 * n); |
2040 | height = (desire_l - origin_l) / (2 * n); | 2125 | height = (desire_l - origin_l) / (2 * n); |
2041 | 2126 | ||
2042 | - build_square_connection(i, width, height, origin_l, desire_l, n, 0, threshold, z, false, upper, 10, ratio); | 2127 | + build_square_connection(i, width, height, origin_l, desire_l, n, 0, threshold, z, false, upper, 5, ratio); |
2043 | outlet[i].V.push_back(bus_v); | 2128 | outlet[i].V.push_back(bus_v); |
2044 | 2129 | ||
2045 | std::reverse(outlet[i].V.begin(), outlet[i].V.end()); // from bus to pendant vertex | 2130 | std::reverse(outlet[i].V.begin(), outlet[i].V.end()); // from bus to pendant vertex |
@@ -2051,6 +2136,13 @@ namespace stim { | @@ -2051,6 +2136,13 @@ namespace stim { | ||
2051 | } | 2136 | } |
2052 | } | 2137 | } |
2053 | 2138 | ||
2139 | + // save in-/out- volume flow rate | ||
2140 | + in = out = 0.0f; | ||
2141 | + for (unsigned i = 0; i < inlet.size(); i++) | ||
2142 | + in += inlet[i].Q; | ||
2143 | + for (unsigned i = 0; i < outlet.size(); i++) | ||
2144 | + out += outlet[i].Q; | ||
2145 | + | ||
2054 | check_special_connection(); // check special connections | 2146 | check_special_connection(); // check special connections |
2055 | } | 2147 | } |
2056 | 2148 | ||
@@ -2060,23 +2152,22 @@ namespace stim { | @@ -2060,23 +2152,22 @@ namespace stim { | ||
2060 | 2152 | ||
2061 | unsigned num; | 2153 | unsigned num; |
2062 | // check inlet | 2154 | // check inlet |
2063 | - num = inlet.size(); | ||
2064 | - inlet_feasibility.resize(num, true); | 2155 | + num = inlet.size(); // get the number of inlets |
2156 | + inlet_feasibility.resize(num, true); // initialization | ||
2065 | for (unsigned i = 0; i < num; i++) { | 2157 | for (unsigned i = 0; i < num; i++) { |
2066 | for (unsigned j = 0; j < num; j++) { | 2158 | for (unsigned j = 0; j < num; j++) { |
2067 | if (i != j) { | 2159 | if (i != j) { |
2068 | - if (inlet[i].V[0][2] == inlet[j].V[0][2]) { | ||
2069 | - if ((inlet[i].V[1][0] <= inlet[j].V[1][0] && fabs(inlet[i].V[1][1]) <= fabs(inlet[j].V[1][1])) || (inlet[i].V[1][0] >= inlet[j].V[1][0] && fabs(inlet[i].V[1][1]) >= fabs(inlet[j].V[1][1]))) { | 2160 | + if (inlet[i].V[0][1] == inlet[j].V[0][1]) { |
2161 | + if ((inlet[i].V[1][0] >= inlet[j].V[1][0]) && (fabs(inlet[i].V[1][1]) >= fabs(inlet[j].V[1][1])) && (((inlet[i].V[1][1] - main_feeder[0][1]) * (inlet[j].V[1][1] - main_feeder[0][1])) > 0 ? 1 : 0)) { | ||
2070 | inlet_feasibility[i] = false; | 2162 | inlet_feasibility[i] = false; |
2071 | break; | 2163 | break; |
2072 | } | 2164 | } |
2165 | + else | ||
2166 | + inlet_feasibility[i] = true; | ||
2073 | } | 2167 | } |
2074 | - else | ||
2075 | - inlet_feasibility[i] = true; | ||
2076 | } | 2168 | } |
2077 | } | 2169 | } |
2078 | } | 2170 | } |
2079 | - | ||
2080 | // check outlet | 2171 | // check outlet |
2081 | num = outlet.size(); | 2172 | num = outlet.size(); |
2082 | outlet_feasibility.resize(num, true); | 2173 | outlet_feasibility.resize(num, true); |
@@ -2084,7 +2175,7 @@ namespace stim { | @@ -2084,7 +2175,7 @@ namespace stim { | ||
2084 | for (unsigned j = 0; j < num; j++) { | 2175 | for (unsigned j = 0; j < num; j++) { |
2085 | if (i != j) { | 2176 | if (i != j) { |
2086 | if (outlet[i].V[0][2] == outlet[j].V[0][2]) { | 2177 | if (outlet[i].V[0][2] == outlet[j].V[0][2]) { |
2087 | - if ((outlet[i].V[1][0] <= outlet[j].V[1][0] && fabs(outlet[i].V[1][1]) >= fabs(outlet[j].V[1][1])) || (outlet[i].V[1][0] >= outlet[j].V[1][0] && fabs(outlet[i].V[1][1]) <= fabs(outlet[j].V[1][1]))) { | 2178 | + if ((outlet[i].V[1][0] <= outlet[j].V[1][0]) && (fabs(outlet[i].V[1][1]) >= fabs(outlet[j].V[1][1])) && (((outlet[i].V[1][1] - main_feeder[1][1]) * (outlet[j].V[1][1] - main_feeder[1][1])) > 0 ? 1 : 0)) { |
2088 | outlet_feasibility[i] = false; | 2179 | outlet_feasibility[i] = false; |
2089 | break; | 2180 | break; |
2090 | } | 2181 | } |
@@ -2196,10 +2287,71 @@ namespace stim { | @@ -2196,10 +2287,71 @@ namespace stim { | ||
2196 | } | 2287 | } |
2197 | } | 2288 | } |
2198 | 2289 | ||
2290 | + /// adjustment in order to match microfluidics experiments | ||
2291 | + void adjust(T in, T out, T &Rt, T nQ, T viscosity, T radius = 5.0f) { | ||
2292 | + | ||
2293 | + // compute total resistance | ||
2294 | + Rt = (Ps - Pe) / in; | ||
2295 | + Pe = 0.0f; | ||
2296 | + | ||
2297 | + Ps = Rt * nQ; | ||
2199 | 2298 | ||
2200 | - /// make binary image stack | 2299 | + // adjust synthetic connections velocity flow rate. (linear scale) |
2300 | + T k = nQ / in; // linear factor | ||
2301 | + for (unsigned i = 0; i < inlet.size(); i++) { | ||
2302 | + inlet[i].Q *= k; | ||
2303 | + input[i].third *= k; | ||
2304 | + } | ||
2305 | + for (unsigned i = 0; i < outlet.size(); i++) { | ||
2306 | + outlet[i].Q *= k; | ||
2307 | + output[i].third *= k; | ||
2308 | + } | ||
2309 | + | ||
2310 | + /// simulate inner network flow | ||
2311 | + // clear up initialized pressure | ||
2312 | + P.resize(num_vertex); | ||
2313 | + for (unsigned i = 0; i < pendant_vertex.size(); i++) { | ||
2314 | + unsigned index = UINT_MAX; | ||
2315 | + for (unsigned j = 0; j < inlet.size(); j++) { | ||
2316 | + if (inlet[j].v[0] == pendant_vertex[i]) { | ||
2317 | + index = j; | ||
2318 | + break; | ||
2319 | + } | ||
2320 | + } | ||
2321 | + if (index != UINT_MAX) { | ||
2322 | + P[inlet[index].v[0]] = Ps - ((T)8 * viscosity * inlet[index].l * inlet[index].Q / (stim::PI * std::pow(radius, 4))); | ||
2323 | + } | ||
2324 | + } | ||
2325 | + | ||
2326 | + for (unsigned i = 0; i < pendant_vertex.size(); i++) { | ||
2327 | + unsigned index = UINT_MAX; | ||
2328 | + for (unsigned j = 0; j < outlet.size(); j++) { | ||
2329 | + if (outlet[j].v[0] == pendant_vertex[i]) { | ||
2330 | + index = j; | ||
2331 | + break; | ||
2332 | + } | ||
2333 | + } | ||
2334 | + if (index != UINT_MAX) { | ||
2335 | + P[outlet[index].v[0]] = Pe + ((T)8 * viscosity * outlet[index].l * outlet[index].Q / (stim::PI * std::pow(radius, 4))); | ||
2336 | + } | ||
2337 | + } | ||
2338 | + | ||
2339 | + // clear up previous simulation except synthetic connection parts | ||
2340 | + for (unsigned i = 0; i < num_vertex; i++) { | ||
2341 | + QQ[i] = 0; | ||
2342 | + pressure[i] = 0; | ||
2343 | + for (unsigned j = 0; j < num_vertex; j++) { | ||
2344 | + C[i][j] = 0; | ||
2345 | + } | ||
2346 | + } | ||
2347 | + | ||
2348 | + // re-simulation | ||
2349 | + solve_flow(viscosity); | ||
2350 | + } | ||
2351 | + | ||
2352 | + /// make full-synthetic binary image stack | ||
2201 | // prepare for image stack | 2353 | // prepare for image stack |
2202 | - void preparation(T &Xl, T &Xr, T &Yt, T &Yb, T &Z, T length = 40.0f, T height = 10.0f) { | 2354 | + void preparation(T &Xl, T &Xr, T &Yt, T &Yb, T &Z, bool prototype = false, T length = 40.0f, T height = 10.0f, T radius = 5.0f) { |
2203 | 2355 | ||
2204 | T max_radius = 0.0f; | 2356 | T max_radius = 0.0f; |
2205 | T top = FLT_MIN; | 2357 | T top = FLT_MIN; |
@@ -2225,21 +2377,23 @@ namespace stim { | @@ -2225,21 +2377,23 @@ namespace stim { | ||
2225 | CU.push_back(new_cuboid); | 2377 | CU.push_back(new_cuboid); |
2226 | 2378 | ||
2227 | // take every point as sphere, every line as cone | 2379 | // take every point as sphere, every line as cone |
2228 | - for (unsigned i = 0; i < num_edge; i++) { | ||
2229 | - for (unsigned j = 0; j < E[i].size(); j++) { | ||
2230 | - new_sphere.c = E[i][j]; | ||
2231 | - new_sphere.r = E[i].r(j); | ||
2232 | - A.push_back(new_sphere); | ||
2233 | - if (j != E[i].size() - 1) { | ||
2234 | - new_cone.c1 = E[i][j]; | ||
2235 | - new_cone.c2 = E[i][j + 1]; | ||
2236 | - new_cone.r1 = E[i].r(j); | ||
2237 | - new_cone.r2 = E[i].r(j + 1); | ||
2238 | - B.push_back(new_cone); | 2380 | + if (!prototype) { |
2381 | + for (unsigned i = 0; i < num_edge; i++) { | ||
2382 | + for (unsigned j = 0; j < E[i].size(); j++) { | ||
2383 | + new_sphere.c = E[i][j]; | ||
2384 | + new_sphere.r = E[i].r(j); | ||
2385 | + A.push_back(new_sphere); | ||
2386 | + if (j != E[i].size() - 1) { | ||
2387 | + new_cone.c1 = E[i][j]; | ||
2388 | + new_cone.c2 = E[i][j + 1]; | ||
2389 | + new_cone.r1 = E[i].r(j); | ||
2390 | + new_cone.r2 = E[i].r(j + 1); | ||
2391 | + B.push_back(new_cone); | ||
2392 | + } | ||
2239 | } | 2393 | } |
2240 | } | 2394 | } |
2241 | } | 2395 | } |
2242 | - | 2396 | + |
2243 | // secondly push back outside connection | 2397 | // secondly push back outside connection |
2244 | for (unsigned i = 0; i < inlet.size(); i++) { | 2398 | for (unsigned i = 0; i < inlet.size(); i++) { |
2245 | for (unsigned j = 1; j < inlet[i].V.size() - 1; j++) { | 2399 | for (unsigned j = 1; j < inlet[i].V.size() - 1; j++) { |
@@ -2288,34 +2442,38 @@ namespace stim { | @@ -2288,34 +2442,38 @@ namespace stim { | ||
2288 | max_radius = A[i].r; | 2442 | max_radius = A[i].r; |
2289 | } | 2443 | } |
2290 | 2444 | ||
2291 | - Yt = top; // top bound y coordinate | ||
2292 | - Yb = bottom; // bottom bound y coordinate | 2445 | + Yt = top + 2 * radius; // top bound y coordinate |
2446 | + Yb = bottom + 2 * radius; // bottom bound y coordinate | ||
2293 | Z = (bb.B[2] - bb.A[2] + 2 * max_radius); // bounding box width(along z-axis) | 2447 | Z = (bb.B[2] - bb.A[2] + 2 * max_radius); // bounding box width(along z-axis) |
2294 | } | 2448 | } |
2295 | 2449 | ||
2296 | /// making image stack main function | 2450 | /// making image stack main function |
2297 | - void make_image_stack(T dx, T dy, T dz, std::string stackdir, T radius = 5.0f) { | 2451 | + void make_image_stack(stim::image_stack<unsigned char, T> I, T dx, T dy, T dz, std::string stackdir, bool prototype = false, T radius = 5.0f) { |
2298 | 2452 | ||
2299 | /// preparation for making image stack | 2453 | /// preparation for making image stack |
2300 | T X, Xl, Xr, Y, Yt, Yb, Z; | 2454 | T X, Xl, Xr, Y, Yt, Yb, Z; |
2301 | - preparation(Xl, Xr, Yt, Yb, Z); | 2455 | + preparation(Xl, Xr, Yt, Yb, Z, prototype); |
2302 | X = Xr - Xl; // bounding box length(along x-axis) | 2456 | X = Xr - Xl; // bounding box length(along x-axis) |
2303 | Y = Yt - Yb; // bounding box height(along y-axis) | 2457 | Y = Yt - Yb; // bounding box height(along y-axis) |
2304 | - | ||
2305 | - /// make | ||
2306 | - stim::image_stack<unsigned char, T> I; | ||
2307 | - T size_x, size_y, size_z; | ||
2308 | - | ||
2309 | stim::vec3<T> center = bb.center(); // get the center of bounding box | 2458 | stim::vec3<T> center = bb.center(); // get the center of bounding box |
2459 | + T size_x, size_y, size_z; | ||
2310 | 2460 | ||
2311 | - size_x = X / dx + 1; // set the size of image | ||
2312 | - size_y = Y / dy + 1; | ||
2313 | - size_z = Z / dz + 1; | ||
2314 | - | ||
2315 | - /// initialize image stack object | ||
2316 | - I.init(1, size_x, size_y, size_z); | ||
2317 | - I.set_dim(dx, dy, dz); | ||
2318 | - | 2461 | + if (!prototype) { |
2462 | + /// make | ||
2463 | + stim::image_stack<unsigned char, T> I; | ||
2464 | + size_x = X / dx + 1; // set the size of image | ||
2465 | + size_y = Y / dy + 1; | ||
2466 | + size_z = Z / dz + 1; | ||
2467 | + /// initialize image stack object | ||
2468 | + I.init(1, size_x, size_y, size_z); | ||
2469 | + I.set_dim(dx, dy, dz); | ||
2470 | + } | ||
2471 | + else { | ||
2472 | + size_x = I.nx(); | ||
2473 | + size_y = I.ny(); | ||
2474 | + size_z = I.nz(); | ||
2475 | + } | ||
2476 | + | ||
2319 | // because of lack of memory, we have to computer one slice of stack per time | 2477 | // because of lack of memory, we have to computer one slice of stack per time |
2320 | // allocate vertex, edge and bus | 2478 | // allocate vertex, edge and bus |
2321 | stim::sphere<T> *d_V; | 2479 | stim::sphere<T> *d_V; |
@@ -2363,6 +2521,8 @@ namespace stim { | @@ -2363,6 +2521,8 @@ namespace stim { | ||
2363 | memset(ptr, 0, num * sizeof(unsigned char)); | 2521 | memset(ptr, 0, num * sizeof(unsigned char)); |
2364 | 2522 | ||
2365 | HANDLE_ERROR(cudaMalloc((void**)&d_ptr, num * sizeof(unsigned char))); | 2523 | HANDLE_ERROR(cudaMalloc((void**)&d_ptr, num * sizeof(unsigned char))); |
2524 | + if (prototype) // load prototype image stack if provided | ||
2525 | + HANDLE_ERROR(cudaMemcpy(d_ptr, &I.data()[i * num], num * sizeof(unsigned char), cudaMemcpyHostToDevice)); | ||
2366 | 2526 | ||
2367 | cudaDeviceProp prop; | 2527 | cudaDeviceProp prop; |
2368 | cudaGetDeviceProperties(&prop, 0); // get cuda device properties structure | 2528 | cudaGetDeviceProperties(&prop, 0); // get cuda device properties structure |
@@ -2403,6 +2563,28 @@ namespace stim { | @@ -2403,6 +2563,28 @@ namespace stim { | ||
2403 | I.save_images(stackdir + "/image????.bmp"); | 2563 | I.save_images(stackdir + "/image????.bmp"); |
2404 | } | 2564 | } |
2405 | 2565 | ||
2566 | + /// save network flow profile | ||
2567 | + void save_network() { | ||
2568 | + | ||
2569 | + // save the pressure information to CSV file | ||
2570 | + std::string p_filename = "profile/pressure.csv"; | ||
2571 | + std::ofstream p_file; | ||
2572 | + p_file.open(p_filename.c_str()); | ||
2573 | + p_file << "Vertex, Pressure(g/" << units << "/s^2)" << std::endl; | ||
2574 | + for (unsigned i = 0; i < num_vertex; i++) | ||
2575 | + p_file << i << "," << pressure[i] << std::endl; | ||
2576 | + p_file.close(); | ||
2577 | + | ||
2578 | + // save the flow information to CSV file | ||
2579 | + std::string f_filename = "profile/flow_rate.csv"; | ||
2580 | + std::ofstream f_file; | ||
2581 | + f_file.open(f_filename.c_str()); | ||
2582 | + f_file << "Edge, Volume flow rate(" << units << "^3/s)" << std::endl; | ||
2583 | + for (unsigned i = 0; i < num_edge; i++) | ||
2584 | + f_file << Q[i].first << "->" << Q[i].second << "," << Q[i].third << std::endl; | ||
2585 | + f_file.close(); | ||
2586 | + } | ||
2587 | + | ||
2406 | /// Calculate the inverse of A and store the result in C | 2588 | /// Calculate the inverse of A and store the result in C |
2407 | void inversion(T** A, int order, T* C) { | 2589 | void inversion(T** A, int order, T* C) { |
2408 | 2590 |
main.cu
@@ -23,10 +23,12 @@ | @@ -23,10 +23,12 @@ | ||
23 | #include <stim/visualization/camera.h> | 23 | #include <stim/visualization/camera.h> |
24 | #include <stim/visualization/colormap.h> | 24 | #include <stim/visualization/colormap.h> |
25 | #include <stim/cuda/cudatools/error.h> | 25 | #include <stim/cuda/cudatools/error.h> |
26 | +#include <stim/grids/image_stack.h> | ||
26 | 27 | ||
27 | 28 | ||
28 | //********************parameter setting******************** | 29 | //********************parameter setting******************** |
29 | // overall parameters | 30 | // overall parameters |
31 | +std::string units; // units used in this program | ||
30 | int vX, vY; | 32 | int vX, vY; |
31 | float dx, dy, dz; // x, y and z image scaling(units/pixel) | 33 | float dx, dy, dz; // x, y and z image scaling(units/pixel) |
32 | std::string stackdir = ""; // directory where image stacks will be stored | 34 | std::string stackdir = ""; // directory where image stacks will be stored |
@@ -36,7 +38,7 @@ stim::camera cam; // camera object | @@ -36,7 +38,7 @@ stim::camera cam; // camera object | ||
36 | unsigned num_edge; // number of edges in the network | 38 | unsigned num_edge; // number of edges in the network |
37 | unsigned num_vertex; // number of vertex in the network | 39 | unsigned num_vertex; // number of vertex in the network |
38 | std::vector<unsigned> pendant_vertex; // list of pendant vertex index in GT | 40 | std::vector<unsigned> pendant_vertex; // list of pendant vertex index in GT |
39 | -std::vector<std::string> menu_option = { "simulation", "build inlet/outlet", "manufacture" }; | 41 | +std::vector<std::string> menu_option = { "simulation", "build inlet/outlet", "manufacture", "adjustment" }; |
40 | stim::flow<float> flow; // flow object | 42 | stim::flow<float> flow; // flow object |
41 | float move_pace; // camera moving parameter | 43 | float move_pace; // camera moving parameter |
42 | float u; // viscosity | 44 | float u; // viscosity |
@@ -48,6 +50,13 @@ std::vector<unsigned char> color; // velocity color map | @@ -48,6 +50,13 @@ std::vector<unsigned char> color; // velocity color map | ||
48 | std::vector<int> velocity_bar; // velocity bar | 50 | std::vector<int> velocity_bar; // velocity bar |
49 | float length = 40.0f; // cuboid length | 51 | float length = 40.0f; // cuboid length |
50 | float scale = 1.0f; // render scale factor | 52 | float scale = 1.0f; // render scale factor |
53 | +bool image_stack = false; // flag indicates an image stack been loaded | ||
54 | +stim::image_stack<unsigned char, float> S; // image stack | ||
55 | +float binary_threshold = 128; // threshold for binary transformation | ||
56 | +float in = 0.0f; // total input volume flow rate | ||
57 | +float out = 0.0f; | ||
58 | +float Rt = 0.0f; // total resistance | ||
59 | +float Qn = 0.0f; // required input total volume flow rate | ||
51 | 60 | ||
52 | // hard-coded parameters | 61 | // hard-coded parameters |
53 | float camera_factor = 1.2f; // start point of the camera as a function of X and Y size | 62 | float camera_factor = 1.2f; // start point of the camera as a function of X and Y size |
@@ -134,6 +143,21 @@ inline void window_to_world(GLdouble &x, GLdouble &y, GLdouble &z) { | @@ -134,6 +143,21 @@ inline void window_to_world(GLdouble &x, GLdouble &y, GLdouble &z) { | ||
134 | gluUnProject(winX, winY, winZ, modelview, projection, viewport, &x, &y, &z); | 143 | gluUnProject(winX, winY, winZ, modelview, projection, viewport, &x, &y, &z); |
135 | } | 144 | } |
136 | 145 | ||
146 | +// convert current image stack into a binary mask | ||
147 | +#ifdef __CUDACC__ | ||
148 | +template <typename T, typename F> | ||
149 | +__global__ void binary_transform(unsigned N, T* ptr, F threshold) { | ||
150 | + | ||
151 | + unsigned ix = blockDim.x * blockIdx.x + threadIdx.x; | ||
152 | + if (ix >= N) return; // avoid seg-fault | ||
153 | + | ||
154 | + if (ptr[ix] >= threshold) // binary transformation | ||
155 | + ptr[ix] = 255; | ||
156 | + else | ||
157 | + ptr[ix] = 0; | ||
158 | +} | ||
159 | +#endif | ||
160 | + | ||
137 | 161 | ||
138 | //********************simulation function********************** | 162 | //********************simulation function********************** |
139 | // initialize flow object | 163 | // initialize flow object |
@@ -163,6 +187,16 @@ void flow_stable_state() { | @@ -163,6 +187,16 @@ void flow_stable_state() { | ||
163 | std::sort(velocity_bar.begin(), velocity_bar.end(), [&](int x, int y) {return abs(flow.v[x]) < abs(flow.v[y]); }); | 187 | std::sort(velocity_bar.begin(), velocity_bar.end(), [&](int x, int y) {return abs(flow.v[x]) < abs(flow.v[y]); }); |
164 | } | 188 | } |
165 | 189 | ||
190 | +// adjustment on input volume flow rate and corresponding flow simulation | ||
191 | +void adjustment() { | ||
192 | + | ||
193 | + system("CLS"); // clear up console box | ||
194 | + std::cout << "Please enter the input total volume flow rate: " << std::endl; | ||
195 | + std::cin >> Qn; | ||
196 | + | ||
197 | + flow.adjust(in, out, Rt, Qn, u); | ||
198 | +} | ||
199 | + | ||
166 | 200 | ||
167 | //********************glut function******************** | 201 | //********************glut function******************** |
168 | // dynamically set menu | 202 | // dynamically set menu |
@@ -226,7 +260,7 @@ void glut_render() { | @@ -226,7 +260,7 @@ void glut_render() { | ||
226 | flow.mark_vertex(scale); | 260 | flow.mark_vertex(scale); |
227 | //flow.glSolidCone(subdivision); | 261 | //flow.glSolidCone(subdivision); |
228 | flow.glSolidCylinder(direction_index, color, scale, subdivision); | 262 | flow.glSolidCylinder(direction_index, color, scale, subdivision); |
229 | - flow.glSolidCuboid(length); | 263 | + flow.glSolidCuboid(manufacture, length); |
230 | if (render_direction) | 264 | if (render_direction) |
231 | flow.glSolidCone(direction_index, scale, subdivision); | 265 | flow.glSolidCone(direction_index, scale, subdivision); |
232 | } | 266 | } |
@@ -236,7 +270,7 @@ void glut_render() { | @@ -236,7 +270,7 @@ void glut_render() { | ||
236 | } | 270 | } |
237 | 271 | ||
238 | if (manufacture) { | 272 | if (manufacture) { |
239 | - flow.glSolidCuboid(); | 273 | + flow.glSolidCuboid(manufacture, length); |
240 | flow.tube_bridge(subdivision); | 274 | flow.tube_bridge(subdivision); |
241 | } | 275 | } |
242 | 276 | ||
@@ -402,6 +436,9 @@ void glut_render() { | @@ -402,6 +436,9 @@ void glut_render() { | ||
402 | glPopMatrix(); | 436 | glPopMatrix(); |
403 | } | 437 | } |
404 | 438 | ||
439 | + if (build_inlet_outlet) | ||
440 | + flow.display_flow_rate(in, out); | ||
441 | + | ||
405 | glutSwapBuffers(); | 442 | glutSwapBuffers(); |
406 | } | 443 | } |
407 | 444 | ||
@@ -416,7 +453,7 @@ void glut_menu(int value) { | @@ -416,7 +453,7 @@ void glut_menu(int value) { | ||
416 | modified_bridge = false; | 453 | modified_bridge = false; |
417 | connection_done = false; | 454 | connection_done = false; |
418 | // first time | 455 | // first time |
419 | - if (!flow.set) { | 456 | + if (!flow.set) { // only first time simulation called "simulation", ^_^ |
420 | flow_initialize(); | 457 | flow_initialize(); |
421 | menu_option[0] = "resimulation"; | 458 | menu_option[0] = "resimulation"; |
422 | } | 459 | } |
@@ -444,7 +481,7 @@ void glut_menu(int value) { | @@ -444,7 +481,7 @@ void glut_menu(int value) { | ||
444 | flow.clear_synthetic_connection(); | 481 | flow.clear_synthetic_connection(); |
445 | } | 482 | } |
446 | 483 | ||
447 | - glut_set_menu(num, 3); | 484 | + glut_set_menu(num, 4); |
448 | } | 485 | } |
449 | 486 | ||
450 | if (value == 3) { | 487 | if (value == 3) { |
@@ -453,6 +490,16 @@ void glut_menu(int value) { | @@ -453,6 +490,16 @@ void glut_menu(int value) { | ||
453 | manufacture = true; | 490 | manufacture = true; |
454 | } | 491 | } |
455 | 492 | ||
493 | + if (value == 4) { | ||
494 | + simulation = true; | ||
495 | + build_inlet_outlet = false; | ||
496 | + manufacture = false; | ||
497 | + | ||
498 | + adjustment(); // adjust network flow accordingly | ||
499 | + | ||
500 | + glut_set_menu(num, 1); | ||
501 | + } | ||
502 | + | ||
456 | glutPostRedisplay(); | 503 | glutPostRedisplay(); |
457 | } | 504 | } |
458 | 505 | ||
@@ -580,21 +627,24 @@ void glut_mouse(int button, int state, int x, int y) { | @@ -580,21 +627,24 @@ void glut_mouse(int button, int state, int x, int y) { | ||
580 | } | 627 | } |
581 | } | 628 | } |
582 | else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && !mods && simulation && to_select_pressure) { | 629 | else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && !mods && simulation && to_select_pressure) { |
583 | - if (y > 2 * border_factor || y < vY - border_factor) { // within the pressure bar range | 630 | + if (y >= 2 * border_factor && y <= vY - border_factor) { // within the pressure bar range |
584 | to_select_pressure = false; | 631 | to_select_pressure = false; |
585 | - float tmp_pressure = (float)(vY - y - border_factor) / ((float)vY - border_factor) * max_pressure; | 632 | + float tmp_pressure = (float)(vY - y - border_factor) / ((float)vY - 3.0f * border_factor) * max_pressure; |
586 | flow.set_pressure(pressure_index, tmp_pressure); | 633 | flow.set_pressure(pressure_index, tmp_pressure); |
587 | - | ||
588 | //flow_stable_state(); // main function of solving the linear system | 634 | //flow_stable_state(); // main function of solving the linear system |
589 | //flow.print_flow(); | 635 | //flow.print_flow(); |
590 | } | 636 | } |
591 | } | 637 | } |
592 | else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && !mods && modified_bridge && change_fragment) { | 638 | else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && !mods && modified_bridge && change_fragment) { |
593 | - if (y > 2 * border_factor || y < vY - border_factor) { // within the ratio bar range | ||
594 | - fragment_ratio = (float)(vY - y - border_factor) / ((float)vY - border_factor) * 1.0f; | ||
595 | - flow.modify_synthetic_connection(u, rou, hilbert_curve, height_threshold, fragment_ratio, default_radius); | ||
596 | - change_fragment = false; | ||
597 | - } | 639 | + if (y >= 2 * border_factor && y <= vY - border_factor) // within the ratio bar range |
640 | + fragment_ratio = (float)(vY - y - border_factor) / ((float)vY - 3.0f * border_factor) * 1.0f; | ||
641 | + else if (y < 2 * border_factor) | ||
642 | + fragment_ratio = 1.0f; | ||
643 | + else if (y > vY - border_factor) | ||
644 | + fragment_ratio = 0.0f; | ||
645 | + | ||
646 | + change_fragment = false; | ||
647 | + flow.modify_synthetic_connection(u, rou, hilbert_curve, height_threshold, in, out, fragment_ratio, default_radius); | ||
598 | } | 648 | } |
599 | // move connections along y-axis | 649 | // move connections along y-axis |
600 | else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && mods == GLUT_ACTIVE_SHIFT && !modified_bridge && !picked_connection) { | 650 | else if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && mods == GLUT_ACTIVE_SHIFT && !modified_bridge && !picked_connection) { |
@@ -789,17 +839,12 @@ void glut_keyboard(unsigned char key, int x, int y) { | @@ -789,17 +839,12 @@ void glut_keyboard(unsigned char key, int x, int y) { | ||
789 | 839 | ||
790 | // register different keyboard operation | 840 | // register different keyboard operation |
791 | switch (key) { | 841 | switch (key) { |
792 | - | ||
793 | - // zooming | ||
794 | - case 'w': // if keyboard 'w' is pressed, then move closer | ||
795 | - move_pace = zoom_factor; | ||
796 | - cam.Push(move_pace); | ||
797 | - break; | ||
798 | - case 's': // if keyboard 's' is pressed, then leave farther | ||
799 | - move_pace = -zoom_factor; | ||
800 | - cam.Push(move_pace); | 842 | + |
843 | + // saving network flow profile | ||
844 | + case 's': | ||
845 | + flow.save_network(); | ||
801 | break; | 846 | break; |
802 | - | 847 | + |
803 | // open/close index marks | 848 | // open/close index marks |
804 | case 'e': | 849 | case 'e': |
805 | if (mark_index) | 850 | if (mark_index) |
@@ -812,7 +857,8 @@ void glut_keyboard(unsigned char key, int x, int y) { | @@ -812,7 +857,8 @@ void glut_keyboard(unsigned char key, int x, int y) { | ||
812 | case 'm': | 857 | case 'm': |
813 | if (manufacture) { | 858 | if (manufacture) { |
814 | #ifdef __CUDACC__ | 859 | #ifdef __CUDACC__ |
815 | - flow.make_image_stack(dx, dy, dz, stackdir); | 860 | + flow.make_image_stack(S, dx, dy, dz, stackdir, image_stack); |
861 | + | ||
816 | #else | 862 | #else |
817 | std::cout << "You need to have a gpu to make image stack, sorry." << std::endl; | 863 | std::cout << "You need to have a gpu to make image stack, sorry." << std::endl; |
818 | #endif | 864 | #endif |
@@ -821,7 +867,7 @@ void glut_keyboard(unsigned char key, int x, int y) { | @@ -821,7 +867,7 @@ void glut_keyboard(unsigned char key, int x, int y) { | ||
821 | modified_bridge = true; | 867 | modified_bridge = true; |
822 | 868 | ||
823 | if (hilbert_curve) | 869 | if (hilbert_curve) |
824 | - flow.modify_synthetic_connection(u, rou, hilbert_curve, height_threshold); | 870 | + flow.modify_synthetic_connection(u, rou, hilbert_curve, height_threshold, in, out, fragment_ratio); |
825 | else | 871 | else |
826 | change_fragment = true; | 872 | change_fragment = true; |
827 | } | 873 | } |
@@ -865,7 +911,7 @@ void glut_initialize() { | @@ -865,7 +911,7 @@ void glut_initialize() { | ||
865 | void advertise() { | 911 | void advertise() { |
866 | std::cout << std::endl << std::endl; | 912 | std::cout << std::endl << std::endl; |
867 | std::cout << " =======================================================================================" << std::endl; | 913 | std::cout << " =======================================================================================" << std::endl; |
868 | - std::cout << "|Thank you for using the synthetic microvascular model generator for microfluidics tool!|" << std::endl; | 914 | + std::cout << "|Thank you for using the AFAN tool! |" << std::endl; |
869 | std::cout << "|Scalable Tissue Imaging and Modeling (STIM) Lab, University of Houston |" << std::endl; | 915 | std::cout << "|Scalable Tissue Imaging and Modeling (STIM) Lab, University of Houston |" << std::endl; |
870 | std::cout << "|Developers: Jiaming Guo, David Mayerich |" << std::endl; | 916 | std::cout << "|Developers: Jiaming Guo, David Mayerich |" << std::endl; |
871 | std::cout << "|Source: https://git.stim.ee.uh.edu/Jack/flow3.git |" << std::endl; | 917 | std::cout << "|Source: https://git.stim.ee.uh.edu/Jack/flow3.git |" << std::endl; |
@@ -879,11 +925,12 @@ int main(int argc, char* argv[]) { | @@ -879,11 +925,12 @@ int main(int argc, char* argv[]) { | ||
879 | 925 | ||
880 | // add arguments | 926 | // add arguments |
881 | args.add("help", "prints the help"); | 927 | args.add("help", "prints the help"); |
882 | - //args.add("network", "load network from .obj or .swc file"); | 928 | + args.add("units", "string indicating units of length for output measurements (ex. velocity)", "um", "text string"); |
883 | args.add("maxpress", "maximum allowed pressure in g / units / s^2, default 2 is for blood when units = um", "2", "real value > 0"); | 929 | args.add("maxpress", "maximum allowed pressure in g / units / s^2, default 2 is for blood when units = um", "2", "real value > 0"); |
884 | args.add("viscosity", "set the viscosity of the fluid (in g / units / s), default .00001 is for blood when units = um", ".00001", "real value > 0"); | 930 | args.add("viscosity", "set the viscosity of the fluid (in g / units / s), default .00001 is for blood when units = um", ".00001", "real value > 0"); |
885 | args.add("rou", "set the desity of the fluid (in g / units^3), default 1.06*10^-12 is for blood when units = um", ".00000000000106", "real value > 0"); | 931 | args.add("rou", "set the desity of the fluid (in g / units^3), default 1.06*10^-12 is for blood when units = um", ".00000000000106", "real value > 0"); |
886 | args.add("hilbert", "activate hilbert curves connections", "0", "value 1 for enablement"); | 932 | args.add("hilbert", "activate hilbert curves connections", "0", "value 1 for enablement"); |
933 | + args.add("stack", "load the image stack"); | ||
887 | args.add("stackres", "spacing between pixel samples in each dimension(in units/pixel)", "1 1 1", "real value > 0"); | 934 | args.add("stackres", "spacing between pixel samples in each dimension(in units/pixel)", "1 1 1", "real value > 0"); |
888 | args.add("stackdir", "set the directory of the output image stack", "", "any existing directory (ex. /home/name/network)"); | 935 | args.add("stackdir", "set the directory of the output image stack", "", "any existing directory (ex. /home/name/network)"); |
889 | 936 | ||
@@ -912,6 +959,10 @@ int main(int argc, char* argv[]) { | @@ -912,6 +959,10 @@ int main(int argc, char* argv[]) { | ||
912 | } | 959 | } |
913 | get_background(); | 960 | get_background(); |
914 | 961 | ||
962 | + // get the units to work on | ||
963 | + units = args["units"].as_string(); | ||
964 | + flow.set_units(units); | ||
965 | + | ||
915 | // blood pressure in capillaries range from 15 - 35 torr | 966 | // blood pressure in capillaries range from 15 - 35 torr |
916 | // 1 torr = 133.3 Pa | 967 | // 1 torr = 133.3 Pa |
917 | max_pressure = args["maxpress"].as_float(); | 968 | max_pressure = args["maxpress"].as_float(); |
@@ -926,6 +977,31 @@ int main(int argc, char* argv[]) { | @@ -926,6 +977,31 @@ int main(int argc, char* argv[]) { | ||
926 | // check whether to enable hilbert curves or not | 977 | // check whether to enable hilbert curves or not |
927 | hilbert_curve = args["hilbert"].as_int(); | 978 | hilbert_curve = args["hilbert"].as_int(); |
928 | 979 | ||
980 | + // load image stack if provided | ||
981 | + if (args["stack"].is_set()) { | ||
982 | + image_stack = true; | ||
983 | + S.load_images(args["stack"].as_string()); | ||
984 | + // binary transformation | ||
985 | +#ifdef __CUDACC__ | ||
986 | + unsigned N = S.samples(); // number of pixels loaded | ||
987 | + unsigned char* d_S; // image stack stored in device | ||
988 | + unsigned char* h_S = (unsigned char*)malloc(N * sizeof(unsigned char)); // image stack stored in host | ||
989 | + cudaMalloc((void**)&d_S, N * sizeof(unsigned char)); | ||
990 | + cudaMemcpy(d_S, S.data(), N * sizeof(unsigned char), cudaMemcpyHostToDevice); | ||
991 | + | ||
992 | + | ||
993 | + unsigned thread = 1024; | ||
994 | + unsigned block = N / thread + 1; | ||
995 | + binary_transform <<<block, thread>>> (N, d_S, binary_threshold); | ||
996 | + | ||
997 | + cudaMemcpy(h_S, d_S, N * sizeof(unsigned char), cudaMemcpyDeviceToHost); | ||
998 | + | ||
999 | + S.copy(h_S); | ||
1000 | + | ||
1001 | + S.save_images("image????.bmp"); | ||
1002 | +#endif | ||
1003 | + } | ||
1004 | + | ||
929 | // get the vexel and image stack size | 1005 | // get the vexel and image stack size |
930 | dx = args["stackres"].as_float(0); | 1006 | dx = args["stackres"].as_float(0); |
931 | dy = args["stackres"].as_float(1); | 1007 | dy = args["stackres"].as_float(1); |