double hyperbolic_step(MESH& m, FLUX& f, double t, double dt, Point ball_loc, int water_tris) { for (auto tri_it = m.triangle_begin(); (*tri_it).index() != water_tris; ++tri_it) { QVar sum = QVar(0,0,0); /* Defines the force of the floating objects by checking its submerged * cross section of the ball intersects with the centers of adjacent triangles */ floatObj obj = floatObj(); if (norm((*tri_it).center()-Point(ball_loc.x, ball_loc.y, 0)) < ball_loc.z) obj = floatObj(total_mass*grav, M_PI*ball_loc.z*ball_loc.z, density); Point norm_vec = (*tri_it).normal((*tri_it).node1(), (*tri_it).node2()); // Calcuate flux using adjacent triangle's Q if ((*tri_it).adj_triangle((*tri_it).node1(), (*tri_it).node2()).is_valid()) sum += f(norm_vec.x, norm_vec.y, dt, (*tri_it).value().q_bar, (*tri_it).adj_triangle((*tri_it).node1(), (*tri_it).node2()).value().q_bar, obj); // Boundary conditions else sum += f(norm_vec.x, norm_vec.y, dt, (*tri_it).value().q_bar, QVar((*tri_it).value().q_bar.h, 0, 0), obj); norm_vec = (*tri_it).normal((*tri_it).node2(), (*tri_it).node3()); // Calcuate flux using adjacent triangle's Q if ((*tri_it).adj_triangle((*tri_it).node2(), (*tri_it).node3()).is_valid()) sum += f(norm_vec.x, norm_vec.y, dt, (*tri_it).value().q_bar, (*tri_it).adj_triangle((*tri_it).node2(), (*tri_it).node3()).value().q_bar, obj); // Boundary conditions else sum += f(norm_vec.x, norm_vec.y, dt, (*tri_it).value().q_bar, QVar((*tri_it).value().q_bar.h, 0, 0), obj); norm_vec = (*tri_it).normal((*tri_it).node3(), (*tri_it).node1()); // Calcuate flux using adjacent triangle's Q if ((*tri_it).adj_triangle((*tri_it).node3(), (*tri_it).node1()).is_valid()) sum += f(norm_vec.x, norm_vec.y, dt, (*tri_it).value().q_bar, (*tri_it).adj_triangle((*tri_it).node3(), (*tri_it).node1()).value().q_bar, obj); // Boundary conditions else sum += f(norm_vec.x, norm_vec.y, dt, (*tri_it).value().q_bar, QVar((*tri_it).value().q_bar.h, 0, 0), obj); (*tri_it).value().q_bar2 = ((*tri_it).value().S * dt/(*tri_it).area()) + (*tri_it).value().q_bar - (sum * dt/(*tri_it).area()); } /* In order to use original (as opposed to update) q_bar values in the equation above, we have to update * q_bar values for all triangles after the q_bar values have been calculated. * Updates the Source term */ for (auto tri_it = m.triangle_begin(); (*tri_it).index() != water_tris; ++tri_it){ (*tri_it).value().S = (*tri_it).value().S/(*tri_it).value().q_bar.h*(*tri_it).value().q_bar2.h; (*tri_it).value().q_bar = (*tri_it).value().q_bar2; } return t + dt; }
double initialize_node_values(MeshType& mesh) const { double max_height = 0; for (auto nit = mesh.node_begin(); nit != mesh.node_end(); ++nit) { if ((*nit).position().x < 0) { (*nit).value() = QVar(1.75, 0, 0); } else { (*nit).value() = QVar(1, 0, 0); } max_height = std::max(max_height, (*nit).value().h); } return max_height; }
/* * implementation of euler approximation of the shallow water PDE * @pre: a valid Mesh class instance @mesh * @post: all triangle in the mesh class have new value() = old value - dt/area() * total flux, where total flux is calculated by all three edges of the triangle @return: return total time t+dt */ double hyperbolic_step(MESH& mesh, FLUX& f, double t, double dt) { // Step the finite volume model in time by dt. // Implement Equation 7 from your pseudocode here. for (auto it = mesh.tri_begin(); it!=mesh.tri_end() ; ++it) { // value function will return the flux QVar total_flux=QVar(0,0,0); QVar qm = QVar(0,0,0); // iterate through 3 edges of a triangle auto edgetemp = (*it).edge1(); for (int num = 0; num < 3; num++) { if (num ==0) edgetemp= (*it).edge1(); else if (num==1) edgetemp = (*it).edge2(); else edgetemp = (*it).edge3(); if ( mesh.has_neighbor(edgetemp.index()) ) // it has a common triangle { auto nx = ((*it).norm_vector(edgetemp)).x; auto ny = ((*it).norm_vector(edgetemp)).y; // find the neighbour of a common edge for (auto i = mesh.tri_edge_begin(edgetemp.index()); i != mesh.tri_edge_end(edgetemp.index()); ++i){ if (!(*i==*it)) qm = (*i).value(); } // calculat the total flux total_flux += f(nx, ny, dt, (*it).value(), qm); } else{ // when it doesnt have a neighbour shared with this edge auto nx = ((*it).norm_vector(edgetemp)).x; auto ny = ((*it).norm_vector(edgetemp)).y; qm = QVar((*it).value().h, 0, 0 ); // approximation total_flux += f(nx, ny, dt, (*it).value(), qm); } } (*it).value() += total_flux * (- dt / (*it).area()); } return t + dt; }
QVar operator+(const QVar& q){ double hnew = h+q.h; double hunew = hu+q.hu; double hvnew = hv+q.hv; //return QVar(h+q.h, hu + q.hu, hv + q.hv); return QVar(hnew, hunew, hvnew); }
QVar operator()(double nx, double ny, double dt, const QVar& qk, const QVar& qm) { // Normalize the (nx,ny) vector double n_length = std::sqrt(nx*nx + ny*ny); nx /= n_length; ny /= n_length; // The velocities normal to the edge double wm = (qm.hx*nx + qm.hy*ny) / qm.h; double wk = (qk.hx*nx + qk.hy*ny) / qk.h; // Lax-Wendroff local dissipation coefficient double vm = sqrt(grav*qm.h) + sqrt(qm.hx*qm.hx + qm.hy*qm.hy) / qm.h; double vk = sqrt(grav*qk.h) + sqrt(qk.hx*qk.hx + qk.hy*qk.hy) / qk.h; double a = dt * std::max(vm*vm, vk*vk); // Helper values double scale = 0.5 * n_length; double gh2 = 0.5 * grav * (qm.h*qm.h + qk.h*qk.h); // Simple flux with dissipation for stability return QVar(scale * (wm*qm.h + wk*qk.h) - a * (qm.h - qk.h), scale * (wm*qm.hx + wk*qk.hx + gh2*nx) - a * (qm.hx - qk.hx), scale * (wm*qm.hy + wk*qk.hy + gh2*ny) - a * (qm.hy - qk.hy)); }
double hyperbolic_step(MESH& m, FLUX& f, double t, double dt) { // HW4B: YOUR CODE HERE // Step the finite volume model in time by dt. // Pseudocode: // Compute all fluxes. (before updating any triangle Q_bars) // For each triangle, update Q_bar using the fluxes as in Equation 8. // NOTE: Much like symp_euler_step, this may require TWO for-loops /* 1. Initialize a vector temp_Q of size @a m.num_triangles() for storing all temp Q_bar values * 2. Use a TriangleIterator to iterate through all the triangles, for each tri_it: * a. Compute the sum of fluxes sum_fluxes * b. temp_Q[(*it).index()] = sum_fluxes * 3. Use indices of triangles to do another for loop, for each triangle(i): * a. triangle_i.value().Q_bar = temp_Q[i] */ std::vector<QVar> temp_fluxes(m.num_triangles(), QVar()); for (auto tri_it = m.triangle_begin(); tri_it != m.triangle_end(); ++tri_it) { auto qk = (*tri_it).value(); QVar F_k(0, 0, 0); for (size_type i = 0; i < 3; ++i) { auto edge = (*tri_it).edge(i); QVar qm(0, 0, 0); if (m.adj_triangle1_index(edge) == -1 || m.adj_triangle2_index(edge) == -1) { //set_boundary_conditions qm = QVar(qk.h, 0, 0); } else { size_type adj_tri_idx = m.adj_triangle1_index(edge) == (*tri_it).index() ? m.adj_triangle2_index(edge) : m.adj_triangle1_index(edge); auto adj_triangle = m.triangle(adj_tri_idx); qm = adj_triangle.value(); } auto norm_ke = m.out_norm((*tri_it), edge); F_k = F_k + f(norm_ke.x, norm_ke.y, dt, qk, qm); } // print_triangle(m, (*tri_it), f, t, dt); temp_fluxes[(*tri_it).index()] = qk - F_k * (dt / (*tri_it).area()); } for (auto tri_it = m.triangle_begin(); tri_it != m.triangle_end(); ++tri_it) { (*tri_it).value() = temp_fluxes[(*tri_it).index()]; } return t + dt; }
double initialize_node_values(MeshType& mesh) const { double max_height = 0; for (auto nit = mesh.node_begin(); nit != mesh.node_end(); ++nit) { unsigned H = 0; if ((*nit).position().x < 0) H = 1; (*nit).value() = QVar(1 + 0.75 * H * (pow(((*nit).position().x - 0.75), 2) + pow((*nit).position().y, 2) - 0.15 * 0.15), 0, 0); max_height = std::max(max_height, (*nit).value().h); } return max_height; }
double hyperbolic_step(MESH& m, FLUX& f, double t, double dt) { // HW4B: YOUR CODE HERE // Step the finite volume model in time by dt. // Pseudocode: // Compute all fluxes. (before updating any triangle Q_bars) // For each triangle, update Q_bar using the fluxes as in Equation 8. // NOTE: Much like symp_euler_step, this may require TWO for-loops // Implement Equation 7 from your pseudocode here. for(auto i = m.edge_begin(); i != m.edge_end(); ++i){ if ((*i).triangle1().index() != (unsigned) -1 && (*i).triangle2().index() != (unsigned) -1 ){ MeshType::Triangle trik = (*i).triangle1(); MeshType::Triangle trim = (*i).triangle2(); unsigned int edge_k = 0; unsigned int edge_m = 0; //which edge (*i) is in trik and trim while(trik.node(edge_k).index()== (*i).node1().index() || trik.node(edge_k).index()== (*i).node2().index() ) ++edge_k; while(trim.node(edge_m).index()== (*i).node1().index() || trim.node(edge_m).index()== (*i).node2().index() ) ++edge_m; QVar flux = f(trik.normal(edge_k).x, trik.normal(edge_k).y, dt, trik.value().Q, trim.value().Q); trik.value().F[edge_k] = flux; trim.value().F[edge_m] = -flux; } else{ MeshType::Triangle trik; if ((*i).triangle1().index() != (unsigned) -1) trik = (*i).triangle1(); else trik = (*i).triangle2(); unsigned int edge_k = 0; while(trik.node(edge_k).index()== (*i).node1().index() || trik.node(edge_k).index()== (*i).node2().index() ) ++edge_k; QVar flux = f(trik.normal(edge_k).x, trik.normal(edge_k).y, dt, trik.value().Q, QVar(trik.value().Q.h, 0, 0)); trik.value().F[edge_k] = flux; } } for(auto i = m.triangle_begin(); i != m.triangle_end(); ++i){ QVar sum = QVar(0, 0, 0); for (int j = 0; j < 3; ++j){ sum += (*i).value().F[j]; } (*i).value().Q = (*i).value().Q-dt/(*i).area()*sum; } return t + dt; };
double initialize_node_values(MeshType& mesh) const { double max_height = 0; for (auto nit = mesh.node_begin(); nit != mesh.node_end(); ++nit) { (*nit).value() = QVar(1 - 0.75 * exp( -80*(pow((*nit).position().x - 0.75, 2) + pow((*nit).position().y, 2)) ), 0, 0); max_height = std::max(max_height, (*nit).value().h); } return max_height; }
void post_process(MESH& m) { // HW4B: Post-processing step // Translate the triangle-averaged values to node-averaged values // Implement Equation 9 from your pseudocode here for (auto it = m.node_begin(); it != m.node_end(); ++it){ double sumarea=0; QVar sumQ = QVar(0, 0, 0); for(auto j = m.triangle_begin(*it); j != m.triangle_end(*it); ++j){ sumarea += (*j).area(); sumQ += (*j).value().Q * (*j).area(); } (*it).value().Q = sumQ/sumarea; } }
Point post_process(MESH& m, FORCE force, CONSTRAINT& c, double t, double dt, uint water_nodes) { static double ball_bottom = std::numeric_limits<double>::max(); double water_dis = std::numeric_limits<double>::max(); double dh = 0; static double submerged_height = 0; Point bottom_loc; Point water_loc; for (auto n_it = m.node_begin(); n_it != m.node_end(); ++n_it) { // handles the shallow water if ((*n_it).index() < water_nodes) { double sum_area = 0; QVar value = QVar(0,0,0); for (auto tri_it = m.adj_triangle_begin((*n_it).uid()); tri_it != m.adj_triangle_end((*n_it).uid()); ++tri_it) { value += (*tri_it).value().q_bar * (*tri_it).area(); sum_area += (*tri_it).area(); } (*n_it).value().q = value * 1.0/(sum_area); } // handles the ball else { (*n_it).set_position((*n_it).position() + (*n_it).value().velocity*dt); dh = (*n_it).value().q.h - (*n_it).position().z; (*n_it).value().q.h = (*n_it).position().z; (*n_it).value().velocity += force(m,(*n_it),t)*dt/(*n_it).value().mass; if ((*n_it).value().q.h < ball_bottom) { ball_bottom = (*n_it).position().z; bottom_loc = (*n_it).position(); } } } // find the water node closest to the bottom of the ball for (auto n_it = m.node_begin(); (*n_it).index() != water_nodes; ++n_it) { if (norm(Point((*n_it).position().x,(*n_it).position().y,0)-Point(bottom_loc.x,bottom_loc.y,0)) < water_dis){ water_dis = norm(Point((*n_it).position().x,(*n_it).position().y,0)-Point(bottom_loc.x,bottom_loc.y,0)); water_loc = Point((*n_it).position().x,(*n_it).position().y,(*n_it).value().q.h); } } // apply contraints of neccessary c(m,ball_bottom); // determines if the ball fell below shallow water and updates height submerged if (bottom_loc.z < water_loc.z) submerged_height += dh; return Point(bottom_loc.x, bottom_loc.y, submerged_height); }
/* * post process of a mesh instance to update the values of all the nodes values * @pre: a valid mesh instance * @post: update the nodes values based on approximation of the average of neighbours values refer to equation 9 on the notes */ void post_process(MESH& m) { // Translate the triangle-averaged values to node-averaged values // Implement Equation 8 from your pseudocode here // iterate through all the nodes for ( auto it = m.node_begin(); it!= m.node_end(); ++it) { QVar sum = QVar(0,0,0); double sumTriArea = 0; // for each node, iterate through its adjacent triangles for (auto adji = m.vertex_begin((*it).index()); adji != m.vertex_end((*it).index()); ++ adji) { auto tri = (*adji); sum += tri.area() * tri.value(); sumTriArea += tri.area(); } (*it).value() = sum/sumTriArea; // update nodes value } }
QVar operator()(double nx, double ny, double dt, const QVar& qk, const QVar& qm) { double e_length = sqrt(nx*nx + ny*ny); nx /= e_length; ny /= e_length; // The velocities normal to the edge double wm = (qm.hu*nx + qm.hv*ny) / qm.h; double wk = (qk.hu*nx + qk.hv*ny) / qk.h; // Lax-Wendroff local dissipation coefficient double vm = sqrt(grav*qm.h) + sqrt(qm.hu*qm.hu + qm.hv*qm.hv) / qm.h; double vk = sqrt(grav*qk.h) + sqrt(qk.hu*qk.hu + qk.hv*qk.hv) / qk.h; double a = dt * std::max(vm*vm, vk*vk); // Helper values double scale = 0.5 * e_length; double gh2 = 0.5 * grav * (qm.h*qm.h + qk.h*qk.h); // Simple flux with dissipation for stability return QVar(scale * (wm*qm.h + wk*qk.h) - a * (qm.h - qk.h), scale * (wm*qm.hu + wk*qk.hu + gh2*nx) - a * (qm.hu - qk.hu), scale * (wm*qm.hv + wk*qk.hv + gh2*ny) - a * (qm.hv - qk.hv)); }
QVar operator()(double nx, double ny, double dt, const QVar& qk, const QVar& qm, floatObj obj = floatObj()) { double e_length = sqrt(nx*nx + ny*ny); nx /= e_length; ny /= e_length; // The velocities normal to the edge double wm = (qm.hu*nx + qm.hv*ny) / qm.h; double wk = (qk.hu*nx + qk.hv*ny) / qk.h; // Lax-Wendroff local dissipation coefficient double vm = sqrt(grav*qm.h) + sqrt(qm.hu*qm.hu + qm.hv*qm.hv) / qm.h; double vk = sqrt(grav*qk.h) + sqrt(qk.hu*qk.hu + qk.hv*qk.hv) / qk.h; double a = dt * std::max(vm*vm, vk*vk); // Helper values which accounts for floating objects (MODIFIED EQN HERE) double scale = 0.5 * e_length; double gh2 = (0.5 * grav) * (qm.h*qm.h + qk.h*qk.h) + (obj.F/(obj.A * obj.ro)*(qm.h+qk.h)); // Simple flux with dissipation for stability return QVar(scale * (wm*qm.h + wk*qk.h) - a * (qm.h - qk.h), scale * (wm*qm.hu + wk*qk.hu + gh2*nx) - a * (qm.hu - qk.hu), scale * (wm*qm.hv + wk*qk.hv + gh2*ny) - a * (qm.hv - qk.hv)); }
TriData():Q(QVar()), F(3, QVar()){}
int main(int argc, char* argv[]) { // Check arguments if (argc < 3) { std::cerr << "Usage: shallow_water NODES_FILE TRIS_FILE\n"; exit(1); } MeshType mesh; // HW4B: Need node_type before this can be used! #if 1 std::vector<typename MeshType::node_type> mesh_node; #endif // Read all Points and add them to the Mesh std::ifstream nodes_file(argv[1]); Point p; while (CS207::getline_parsed(nodes_file, p)) { // HW4B: Need to implement add_node before this can be used! #if 1 mesh_node.push_back(mesh.add_node(p)); #endif } // Read all mesh triangles and add them to the Mesh std::ifstream tris_file(argv[2]); std::array<int,3> t; while (CS207::getline_parsed(tris_file, t)) { // HW4B: Need to implement add_triangle before this can be used! #if 1 mesh.add_triangle(mesh_node[t[0]], mesh_node[t[1]], mesh_node[t[2]]); #endif } // Print out the stats std::cout << mesh.num_nodes() << " " << mesh.num_edges() << " " << mesh.num_triangles() << std::endl; // HW4B Initialization // Set the initial conditions according the type of input pattern if(argv[2][5]=='d'){ Dam<MeshType> init; for(auto it= mesh.node_begin(); it != mesh.node_end(); ++it) init(*it); } else if((argv[2][5]=='p')){ Pebble<MeshType> init; for(auto it= mesh.node_begin(); it != mesh.node_end(); ++it) init(*it); } else{ Wave<MeshType> init; for(auto it= mesh.node_begin(); it != mesh.node_end(); ++it) init(*it); } // Set triangle values for (auto it=mesh.triangle_begin(); it!=mesh.triangle_end(); ++it) { (*it).value().Q = QVar(0.0,0.0,0.0); (*it).value().Q += (*it).node(0).value().Q; (*it).value().Q += (*it).node(1).value().Q; (*it).value().Q += (*it).node(2).value().Q; (*it).value().Q /= 3.0; } // Launch the SDLViewer CS207::SDLViewer viewer; viewer.launch(); // HW4B: Need to define Mesh::node_type and node/edge iterator // before these can be used! #if 1 auto node_map = viewer.empty_node_map(mesh); viewer.add_nodes(mesh.node_begin(), mesh.node_end(), CS207::DefaultColor(), NodePosition(), node_map); viewer.add_edges(mesh.edge_begin(), mesh.edge_end(), node_map); #endif viewer.center_view(); // HW4B: Timestep // CFL stability condition requires dt <= dx / max|velocity| // For the shallow water equations with u = v = 0 initial conditions // we can compute the minimum edge length and maximum original water height // to set the time-step // Compute the minimum edge length and maximum water height for computing dt double min_edge_length =( *mesh.edge_begin()).length(); for (auto it=mesh.edge_begin(); it!=mesh.edge_end(); ++it) { if ((*it).length() < min_edge_length) { min_edge_length = (*it).length(); } } double max_height = 0.0; for (auto it=mesh.node_begin(); it!=mesh.node_end(); ++it) { if ((*it).value().Q.h > max_height) { max_height = (*it).value().Q.h; } } #if 1 double dt = 0.25 * min_edge_length / (sqrt(grav * max_height)); #else // Placeholder!! Delete me when min_edge_length and max_height can be computed! double dt = 0.1; #endif double t_start = 0; double t_end = 10; // Preconstruct a Flux functor EdgeFluxCalculator f; // Begin the time stepping for (double t = t_start; t < t_end; t += dt) { //print(mesh, t); // Step forward in time with forward Euler hyperbolic_step(mesh, f, t, dt); // Update node values with triangle-averaged values post_process(mesh); // Update the viewer with new node positions // HW4B: Need to define node_iterators before these can be used! #if 1 viewer.add_nodes(mesh.node_begin(), mesh.node_end(), CS207::DefaultColor(), NodePosition(), node_map); #endif viewer.set_label(t); // These lines slow down the animation for small meshes. // Feel free to remove them or tweak the constants. if (mesh.num_nodes() < 100) CS207::sleep(0.05); } return 0; }
int main(int argc, char* argv[]) { // Check arguments if (argc < 5) { std::cerr << "Usage: final_project NODES_FILE TRIS_FILE ball.nodes ball.tris \n"; exit(1); } MeshType mesh; std::vector<typename MeshType::node_type> mesh_node; // Read all water Points and add them to the Mesh std::ifstream nodes_file(argv[1]); Point p; uint water_nodes = 0; while (CS207::getline_parsed(nodes_file, p)) { mesh_node.push_back(mesh.add_node(p)); water_nodes++; } // Read all water mesh triangles and add them to the Mesh std::ifstream tris_file(argv[2]); std::array<int,3> t; int water_tris = 0; while (CS207::getline_parsed(tris_file, t)) { mesh.add_triangle(mesh_node[t[0]], mesh_node[t[1]], mesh_node[t[2]]); water_tris++; } uint water_edges = mesh.num_edges(); std::ifstream nodes_file2(argv[3]); double radius = 1 * scale; while (CS207::getline_parsed(nodes_file2, p)) { p *= scale; p.z += + start_height; mesh_node.push_back(mesh.add_node(p)); } // Read all ball mesh triangles and add them to the mesh std::ifstream tris_file2(argv[4]); while (CS207::getline_parsed(tris_file2, t)) { mesh.add_triangle(mesh_node[t[0]+water_nodes], mesh_node[t[1]+water_nodes], mesh_node[t[2]+water_nodes]); } // Print out the stats std::cout << mesh.num_nodes() << " " << mesh.num_edges() << " " << mesh.num_triangles() << std::endl; /* Set the initial conditions */ // Set the initial values of the nodes and get the maximum height double double max_h = 0; double dx = 0; double dy = 0; auto init_cond = Still(); auto b_init_cond = Cone(); // Find the maximum height and apply initial conditions to nodes for (auto it = mesh.node_begin(); it != mesh.node_end(); ++it) { auto n = *it; if (n.index() < water_nodes){ n.value().q = init_cond(n.position()); n.value().b = b_init_cond(n.position()); max_h = std::max(max_h, n.value().q.h); } else { n.value().q = QVar(n.position().z, 0, 0); n.value().mass = total_mass/(mesh.num_nodes() - water_nodes); n.value().velocity = Point(0.0,0.0,0.0); } } // Set the initial values of the triangles to the average of their nodes and finds S // Set the triangle direction values so that we can determine which // way to point normal vectors. This part assumes a convex shape Point center = get_center(mesh); for (auto it = mesh.triangle_begin(); it != mesh.triangle_end(); ++it) { auto t = *it; if (t.index() < water_tris){ t.value().q_bar = (t.node1().value().q + t.node2().value().q + t.node3().value().q) / 3.0; t.value().q_bar2 = t.value().q_bar; double b_avg = (t.node1().value().b + t.node2().value().b + t.node3().value().b) / 3.0; // finds the max dx and dy to calculate Source dx = std::max(dx, fabs(t.node1().position().x - t.node2().position().x)); dx = std::max(dx, fabs(t.node2().position().x - t.node3().position().x)); dx = std::max(dx, fabs(t.node3().position().x - t.node1().position().x)); dy = std::max(dy, fabs(t.node1().position().y - t.node2().position().y)); dy = std::max(dy, fabs(t.node2().position().y - t.node3().position().y)); dy = std::max(dy, fabs(t.node3().position().y - t.node1().position().y)); t.value().S = QVar(0, -grav * t.value().q_bar.h * b_avg / dx, -grav * t.value().q_bar.h * b_avg / dy); } else set_normal_direction((*it),center); } // Calculate the minimum edge length and set edge inital condititons double min_edge_length = std::numeric_limits<double>::max(); uint count = 0; for (auto it = mesh.edge_begin(); it != mesh.edge_end(); ++it, count++){ if (count < water_edges) min_edge_length = std::min(min_edge_length, (*it).length()); else { (*it).value().spring_constant = spring_const; (*it).value().initial_length = (*it).length(); } } // Launch the SDLViewer CS207::SDLViewer viewer; viewer.launch(); auto node_map = viewer.empty_node_map(mesh); viewer.add_nodes(mesh.node_begin(), mesh.node_end(), Color(water_nodes), NodePosition(), node_map); viewer.add_edges(mesh.edge_begin(), mesh.edge_end(), node_map); // adds solid color-slows down program significantly //viewer.add_triangles(mesh.triangle_begin(), mesh.triangle_end(), node_map); viewer.center_view(); // CFL stability condition requires dt <= dx / max|velocity| // For the shallow water equations with u = v = 0 initial conditions // we can compute the minimum edge length and maximum original water height // to set the time-step // Compute the minimum edge length and maximum water height for computing dt double dt = 0.25 * min_edge_length / (sqrt(grav * max_h)); double t_start = 0; double t_end = 10; Point ball_loc = Point(0,0,0); double dh = 0; // double pressure = gas_const/(4/3*M_PI*radius*radius*radius); // add listener my_listener* l = new my_listener(viewer,mesh,dt); viewer.add_listener(l); // Preconstruct a Flux functor EdgeFluxCalculator f; // defines the constraint PlaneConstraint c = PlaneConstraint(plane_const); // Begin the time stepping for (double t = t_start; t < t_end; t += dt) { // define forces on ball GravityForce g_force; BuoyantForce b_force = BuoyantForce(dh, ball_loc.z); WindForce w_force; MassSpringForce ms_force; // PressureForce p_force = PressureForce(pressure); // DampingForce d_force = DampingForce(mesh.num_nodes()); auto combined_forces = make_combined_force(g_force, b_force, w_force, ms_force); // Step forward in time with forward Euler hyperbolic_step(mesh, f, t, dt, ball_loc, water_tris); // Update node values with triangle-averaged values ball_loc = post_process(mesh, combined_forces, c, t, dt, water_nodes); // Update the viewer with new node positions viewer.add_nodes(mesh.node_begin(), mesh.node_end(), Color(water_nodes), NodePosition(), node_map); // viewer.add_triangles(mesh.triangle_begin(), mesh.triangle_end(), node_map); viewer.set_label(t); // find radius of cross sectional radius of ball submerged dh = ball_loc.z; if (dh > 2*radius) dh = 2 * radius; ball_loc.z = cross_radius(radius, dh); // These lines slow down the animation for small meshes. if (mesh.num_nodes() < 100) CS207::sleep(0.05); } return 0; }
QVar operator/ (double n){ return QVar(h/n, hu/n, hv/n); }
QVar operator()(Point p) { if (pow(p.x-0.75,2) + pow(p.y,2) - pow(0.15,2) < 0) return QVar(1.75,0,0); else return QVar(1.0,0,0); }
QVar operator()(Point p) { return QVar(1.0 - 0.75*exp(-80*(pow((p.x-0.75),2) + pow(p.y,2))), 0, 0); }
int main(int argc, char* argv[]) { // Check arguments if (argc < 3) { std::cerr << "Usage: shallow_water NODES_FILE TRIS_FILE\n"; exit(1); } auto start = std::chrono::high_resolution_clock::now(); MeshType mesh; // HW4B: Need node_type before this can be used! std::vector<typename MeshType::node_type> mesh_node; // Read all Points and add them to the Mesh std::ifstream nodes_file(argv[1]); Point p; while (CS207::getline_parsed(nodes_file, p)) { mesh_node.push_back(mesh.add_node(p)); } // Read all mesh triangles and add them to the Mesh std::ifstream tris_file(argv[2]); std::array<int,3> t; while (CS207::getline_parsed(tris_file, t)) { // HW4B: Need to implement add_triangle before this can be used! mesh.add_triangle(mesh_node[t[0]], mesh_node[t[1]], mesh_node[t[2]]); } // Print out the stats std::cout << mesh.num_nodes() << " " << mesh.num_edges() << " " << mesh.num_triangles() << std::endl; //Start of nearest neighor. Put all positions that you want inspected in a vector of type double std::vector<double> pos; for (auto it = mesh.node_begin(); it != mesh.node_end(); ++it ) pos.push_back((*it).position().z); unsigned num_neighbors = 10; //num of neighors to return unsigned object_idx = 5; // do this if you want to examine the neighbors of a specific idx MeshType::NearestNeighbor a = mesh.calculateNearestNeighbors(num_neighbors ,pos); auto idx = mesh.getNeighbors(a,object_idx); auto dist = mesh.getNeighborDistances(a,object_idx); /*auto all_n = mesh.getAllNeighbors(a); auto all_d = mesh.getAllNeighborDistances(a);*/ for (unsigned i = 0; i < idx.size(); ++i) std::cout << "Node " << object_idx << "'s " << i << " neighbor is: node " << idx[i] << " with distance of " << dist[i] << endl; /*//Uncomment to view results for all nodes for (unsigned j = 0; j < pos.size(); ++j){ std::cout << endl; for (unsigned i = 0; i < num_neighbors; ++i) std::cout << "For node " << j << " neighbor " << i << " is index " << all_n[i+j*num_neighbors] << " and distance is " << all_d[i+j*num_neighbors] << endl; }*/ // HW4B Initialization // Set the initial conditions int wave = 0, peddle=0, dam=1; if (wave){ for ( auto it = mesh.node_begin(); it!= mesh.node_end(); ++it){ auto x = (*it).position().x; auto y = (*it).position().y; double h = 1-0.75 * exp(-80 * ( (x-0.75)*(x-0.75) + y*y )); mesh.value((*it),QVar( h,0,0)); } } else if (peddle){ for ( auto it = mesh.node_begin(); it!= mesh.node_end(); ++it){ auto x = (*it).position().x; auto y = (*it).position().y; double h = (x-0.75)*(x-0.75) + y*y -0.15*0.15 ; int H =0; if (h < 0) H = 1; mesh.value((*it), QVar(1+0.75*H,0,0)); } } else if (dam){ for ( auto it = mesh.node_begin(); it!= mesh.node_end(); ++it){ auto x = (*it).position().x; int H =0; if (x < 0) H = 1; mesh.value((*it), QVar(1+0.75*H,0,0)); } } // Perform any needed precomputation // initialize triangle for (auto it = mesh.tri_begin(); it != mesh.tri_end(); ++it ) { (*it).value() = ((*it).node1().value() + (*it).node2().value() + (*it).node3().value())/3.0; } // Launch the SDLViewer CS207::SDLViewer viewer; viewer.launch(); // HW4B: Need to define Mesh::node_type and node/edge iterator // before these can be used! auto node_map = viewer.empty_node_map(mesh); viewer.add_nodes(mesh.node_begin(), mesh.node_end(), CS207::DefaultColor(), NodePosition(), node_map); viewer.add_edges(mesh.edge_begin(), mesh.edge_end(), node_map); viewer.center_view(); // HW4B: Timestep // CFL stability condition requires dt <= dx / max|velocity| // For the shallow water equations with u = v = 0 initial conditions // we can compute the minimum edge length and maximum original water height // to set the time-step // Compute the minimum edge length and maximum water height for computing dt auto min_length = *std::min_element(mesh.edge_begin(), mesh.edge_end(), EdgeComparator); auto max_h = *std::max_element(mesh.node_begin(), mesh.node_end(), HeightComparator); double dt = 0.25 * min_length.length() / (sqrt(grav * max_h.value().h)); double t_start = 0; double t_end = 0.1; // Preconstruct a Flux functor EdgeFluxCalculator f; // Begin the time stepping for (double t = t_start; t < t_end; t += dt) { // Step forward in time with forward Euler hyperbolic_step(mesh, f, t, dt); // Update node values with triangle-averaged values post_process(mesh); // Update the viewer with new node positions // HW4B: Need to define node_iterators before these can be used! viewer.add_nodes(mesh.node_begin(), mesh.node_end(), CS207::DefaultColor(), NodePosition(), node_map); viewer.set_label(t); // These lines slow down the animation for small meshes. // Feel free to remove them or tweak the constants. if (mesh.num_nodes() < 100) CS207::sleep(0.05); } auto elapsed = std::chrono::high_resolution_clock::now() - start; long long microseconds = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count(); cout << microseconds << endl; return 0; }
QVar operator-(const QVar& q){ return QVar(h-q.h, hu - q.hu, hv - q.hv); }
QVar operator*(double n, QVar& q){ return QVar(n*q.h,n*q.hu,n*q.hv); }
QVar operator()(Point p) { if (p.x < 0) return QVar(1.75,0,0); else return QVar(1.0,0,0); }
QVar operator* (double n){ return QVar(h*n, hu*n, hv*n); }
QVar operator()(Point p) { (void) p; return QVar(1.0,0,0); }
QVar operator/(double n,QVar& q) { return QVar(n/q.h, n/q.hu, n/q.hv); }