Advertisement
Guest User

Untitled

a guest
Apr 20th, 2019
99
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 10.13 KB | None | 0 0
  1. #include <iostream>
  2. #include <iomanip>
  3. #include <string>
  4. #include <sstream>
  5. #include <fstream>
  6. #include <functional>
  7. #include <vector>
  8. #include <limits>
  9. #include <utility>
  10. #include "eigen/Dense"
  11. #include "eigen/Eigen"
  12.  
  13. //Class Representing Shallow-Water Problem
  14. class Shallow_Water_Solver {
  15. public:
  16.  
  17.     //Default Constructors and Assignment
  18.     Shallow_Water_Solver() = default;
  19.     Shallow_Water_Solver(const Shallow_Water_Solver&) = default;
  20.     Shallow_Water_Solver(Shallow_Water_Solver&&) = default;
  21.     Shallow_Water_Solver& operator=(const Shallow_Water_Solver&) = default;
  22.     Shallow_Water_Solver& operator=(Shallow_Water_Solver&&) = default;
  23.  
  24.     //Constructors with Real Information
  25.     Shallow_Water_Solver(double x_min_in, double x_max_in, int nx_in,
  26.                          double y_min_in, double y_max_in, int ny_in,
  27.                          const std::function<Eigen::Vector3d(double,double)>& initial_condition) :
  28.             SolutionVector(3*nx_in*ny_in),
  29.             ResidualVector(3*nx_in*ny_in),
  30.             x_min(x_min_in),
  31.             x_max(x_max_in),
  32.             nx(nx_in),
  33.             delta_x((x_max-x_min)/static_cast<double>(nx+1)),
  34.             y_min(y_min_in),
  35.             y_max(y_max_in),
  36.             ny(ny_in),
  37.             delta_y((y_max-y_min)/static_cast<double>(ny+1)),
  38.             current_time(0.0)
  39.     {
  40.         if(x_min > x_max || nx <= 0 || y_min > y_max || ny <= 0) {
  41.             throw std::runtime_error("Invalid inputs to solver.");
  42.         }
  43.         set_initial_conditions(initial_condition);
  44.     }
  45.  
  46.     auto num_x() const {return nx;} //Number of Nodes in the X Direction
  47.     auto num_y() const {return ny;} //Number of Nodes in the Y Direction
  48.     auto dx() const {return delta_x;} //Delta X
  49.     auto dy() const {return delta_y;} //Delta Y
  50.  
  51.     //Position of i-j Node
  52.     Eigen::Vector2d node(int i, int j) const {
  53.         while(i<0) i += nx;
  54.         auto index_i = i%nx;
  55.         while(j<0) j += ny;
  56.         auto index_j = j%ny;
  57.         return {x_min + static_cast<double>(index_i)*delta_x + (i/nx)*(x_max-x_min),
  58.                 y_min + static_cast<double>(index_j)*delta_y + (j/ny)*(y_max-y_min)};
  59.     }
  60.  
  61.     auto& U() {return SolutionVector;} //Full Solution Vector
  62.     const auto& U() const {return SolutionVector;} //Full Solution Vector
  63.  
  64.     //Solution at i-j Node. Returns Eigen Segment. Desired SubVector Reference
  65.     auto U(int i, int j) {
  66.         auto index = global_solution_index(i,j);
  67.         return SolutionVector.segment<3>(index);
  68.     }
  69.  
  70.     //Solution at i-j Node. Returns Eigen Segment. Desired SubVector Reference
  71.     auto U(int i, int j) const {
  72.         auto index = global_solution_index(i,j);
  73.         return SolutionVector.segment<3>(index);
  74.     }
  75.  
  76.     auto& dUdt() {return ResidualVector;} //Full Residual Vector
  77.     const auto& dUdt() const {return ResidualVector;} //Full Residual Vector
  78.  
  79.     //Solution at i-j Node. Returns Eigen Segment. Desired SubVector Reference
  80.     auto dUdt(int i, int j) {
  81.         auto index = global_solution_index(i,j);
  82.         return ResidualVector.segment<3>(index);
  83.     }
  84.  
  85.     //Solution at i-j Node. Returns Eigen Segment. Desired SubVector Reference
  86.     auto dUdt(int i, int j) const {
  87.         auto index = global_solution_index(i,j);
  88.         return ResidualVector.segment<3>(index);
  89.     }
  90.  
  91.     auto time() const {return current_time;} //Current Time
  92.  
  93.     //Force X
  94.     Eigen::Vector3d Fx(const Eigen::Vector3d& U) {
  95.         return {U[1], U[1]*U[1]/U[0] + 0.5*g*U[0]*U[0], U[1]*U[2]/U[0]};
  96.     }
  97.  
  98.     //Force Y
  99.     Eigen::Vector3d Fy(const Eigen::Vector3d& U) {
  100.         return {U[2], U[2]*U[1]/U[0], U[2]*U[2]/U[0] + 0.5*g*U[0]*U[0]};
  101.     }
  102.  
  103.     //Max Wave Speeds in X and Y Directions.
  104.     Eigen::Vector2d max_wavespeeds(const Eigen::Vector3d& U) {
  105.         double a  = sqrt(U[0]*g);
  106.         double ux = U[1]/U[0];
  107.         double uy = U[2]/U[0];
  108.         return {fabs(ux)+a, fabs(uy)+a};
  109.     }
  110.  
  111.     void time_march(double final_time, double CFL); //Time March to Time
  112.  
  113. private:
  114.  
  115.     // Index in Solution Vector. Storing Location for Node i-j Entries
  116.     int global_solution_index(int i, int j) const {
  117.         while(i<0) i += nx;
  118.         auto index_i = i%nx;
  119.         while(j<0) j += ny;
  120.         auto index_j = j%ny;
  121.         return 3 * (index_i + nx*index_j);
  122.     }
  123.  
  124.     //Set Initial Conditions
  125.     void set_initial_conditions(const std::function<Eigen::Vector3d(double, double)>& initial_condition) {
  126.  
  127.         for(int i = 0; i < nx; ++i) {
  128.             for(int j = 0; j < ny; ++j) {
  129.                 auto n = node(i,j);
  130.                 U(i,j) = initial_condition(n.x(), n.y());
  131.             }
  132.         }
  133.  
  134.     }
  135.  
  136.     Eigen::VectorXd SolutionVector; //Solution vector (U)
  137.     Eigen::VectorXd ResidualVector; // Residual Vector (dUdt)
  138.     const double x_min; //Minimum Value of X
  139.     const double x_max; //Maximum value of X
  140.     const int nx; //Number of Nodes in the X Direction
  141.     const double delta_x; //Spacing of Nodes in the X Direction
  142.     const double y_min; //Minimum Value of Y
  143.     const double y_max; //Maximum Value of Y
  144.     const int ny; //Number of Nodes in the Y Direction
  145.     const double delta_y; //Spacing of Nodes in the Y Direction
  146.     double current_time; //Solution Time
  147.     constexpr static double g = 9.81; //Gravity
  148.  
  149. };
  150.  
  151. //Time March to Time. Local Lax-Friedrichs
  152. void Shallow_Water_Solver::time_march(double final_time, double CFL) {
  153.     std::cout << "Time marching from t = " << current_time
  154.               << " to t = " << final_time
  155.               << ".  Total difference = " << final_time-current_time << ".\n";
  156.     const double time_tolerance = 1.0e-12;
  157.     const double min_length = std::min(dx(), dy());
  158.     while(current_time < final_time - time_tolerance) {
  159.         auto dt = std::numeric_limits<double>::max();
  160.         dUdt().fill(0.0);
  161.         for(int i = 0; i < num_x(); ++i) {
  162.             for(int j = 0; j < num_y(); ++j) {
  163.                 Eigen::Vector3d Um = U(i  , j  );
  164.                 Eigen::Vector3d Ul = U(i-1, j  );
  165.                 Eigen::Vector3d Ur = U(i+1, j  );
  166.                 Eigen::Vector3d Ub = U(i  , j-1);
  167.                 Eigen::Vector3d Ut = U(i  , j+1);
  168.                 Eigen::Vector2d lambda = max_wavespeeds(Um);
  169.                 auto max_lambda = std::max(lambda[0], lambda[1]);
  170.                 dt = std::min(dt, CFL*min_length/max_lambda);
  171.                 dUdt(i,j) = (Fx(Ul) - Fx(Ur) + lambda[0]*(Ul - 2.0*Um + Ur)) / (2.0*delta_x)
  172.                             +(Fy(Ub) - Fy(Ut) + lambda[1]*(Ub - 2.0*Um + Ut)) / (2.0*delta_y);
  173.             }
  174.         }
  175.  
  176.         if(current_time + dt > final_time) {
  177.             dt = final_time - current_time;
  178.         }
  179.  
  180.         U()  += dt*dUdt();
  181.         current_time += dt;
  182.         std::cout << "Time = " << std::setw(10) << current_time << '\n';
  183.     }
  184.  
  185.     std::cout << "Time marching done.\n";
  186. }
  187.  
  188. //Write to VTK
  189. void write_to_VTK(const Shallow_Water_Solver& solver,
  190.                   const std::string& filename) {
  191.     std::ofstream fout(filename);
  192.     if(!fout) {
  193.         throw std::runtime_error("Could not open file: " + filename);
  194.     }
  195.  
  196.     std::cout << "Writing output to file: " << filename << '\n';
  197.     const auto num_nodes = (solver.num_x()+1)*(solver.num_y()+1);
  198.     fout << "# vtk DataFile Version 2.0\n"
  199.          << "Shallow-Water equations solution\n"
  200.          << "ASCII\n"
  201.          << "DATASET STRUCTURED_GRID\n"
  202.          << "DIMENSIONS " << solver.num_x()+1 << " " << solver.num_y()+1 << " 1\n"
  203.          << "POINTS " << num_nodes << " double\n";
  204.     for(int j = 0; j <= solver.num_y(); ++j) {
  205.         for(int i = 0; i <= solver.num_x(); ++i) {
  206.             auto n = solver.node(i,j);
  207.             auto U = solver.U(i,j);
  208.             fout << n.x() << " " << n.y() << " " << U[0] << '\n';
  209.         }
  210.     }
  211.  
  212.     fout << "\nPOINT_DATA " << num_nodes
  213.          << "\nSCALARS h double 1\nLOOkUP_TABLE default\n";
  214.     for(int j = 0; j <= solver.num_y(); ++j) {
  215.         for(int i = 0; i <= solver.num_x(); ++i) {
  216.             fout << solver.U(i,j)[0] << '\n';
  217.         }
  218.     }
  219.  
  220.     fout << "\nVECTORS u double\n";
  221.     for(int j = 0; j <= solver.num_y(); ++j) {
  222.         for(int i = 0; i <= solver.num_x(); ++i) {
  223.             auto ux = solver.U(i,j)[1]/solver.U(i,j)[0];
  224.             auto uy = solver.U(i,j)[2]/solver.U(i,j)[0];
  225.             fout << ux << " " << uy << " 0.0\n";
  226.         }
  227.     }
  228. }
  229.  
  230. //Make Movie
  231. void make_movie(Shallow_Water_Solver& solver,
  232.                 const double final_time,
  233.                 const double CFL,
  234.                 const int number_of_frames,
  235.                 const std::string& filename_base) {
  236.     if(number_of_frames < 2) {
  237.         throw std::runtime_error("make_movie requires at least two frames.");
  238.     }
  239.  
  240.     const auto frame_time = (final_time-solver.time())/static_cast<double>(number_of_frames-1);
  241.     const auto build_filename = [](const std::string& filename_base, int index) {
  242.         std::stringstream filename_ss;
  243.         filename_ss <<  filename_base << "_" << std::setfill('0') << std::setw(5) << index << ".vtk";
  244.         return filename_ss.str();
  245.     };
  246.  
  247.     write_to_VTK(solver, build_filename(filename_base, 0));
  248.     for(int i = 1; i<number_of_frames; ++i) {
  249.         double target_time = static_cast<double>(i)*frame_time;
  250.         solver.time_march(target_time, CFL);
  251.         write_to_VTK(solver, build_filename(filename_base, i));
  252.     }
  253. }
  254.  
  255. //Main
  256. int main() {
  257.     std::cout << "---------------------------------------\n"
  258.               << " |              Lab 6                |\n"
  259.               << " |           Shallow-water           |\n"
  260.               << "---------------------------------------\n";
  261.     double x_min = -1.0;
  262.     double x_max =  1.0;
  263.     int       nx =  500;
  264.     double y_min = -1.0;
  265.     double y_max =  1.0;
  266.     int       ny =  500;
  267.     auto initial_condition = [] (double x, double y) {
  268.         Eigen::Vector3d U;
  269.         U[0] = 1.0;
  270.         U[1] = 0.0;
  271.         U[2] = 0.0;
  272.         if(fabs(x)<0.2 && fabs(y)<0.2) {
  273.             U *= 1.2;
  274.         }
  275.         return U;
  276.     };
  277.  
  278.     auto solver = Shallow_Water_Solver(x_min, x_max, nx, y_min, y_max, ny, initial_condition);
  279.     make_movie(solver, 2.5, 0.5, 750, "movie");
  280.     return 0;
  281. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement