diff --git a/CMakeLists.txt b/CMakeLists.txt index 170a698417dbd755dee6305615011516f5060eb2..ec32c249e5046947220cd51a011d427a2ec7aa3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,23 +12,23 @@ find_package(Eigen3 REQUIRED) # Library add_subdirectory(source/numsimulation) -add_subdirectory(source/potential) add_subdirectory(source/potential_rectangular) add_subdirectory(source/potential_warped) +add_subdirectory(source/potential) add_subdirectory(source/scalar) add_subdirectory(source/scalar_v2) +add_subdirectory(source/simple_partial) #add_subdirectory(source/simple) -#add_subdirectory(source/simple_partial) # Demo -add_subdirectory(demo/potential) add_subdirectory(demo/potential_rectangular) add_subdirectory(demo/potential_warped) +add_subdirectory(demo/potential) add_subdirectory(demo/scalar) add_subdirectory(demo/scalar_v2) +add_subdirectory(demo/simple_partial) #add_subdirectory(demo/simple) -#add_subdirectory(demo/simple_partial) -add_custom_target(demo DEPENDS potential_rectangular_demo_all potential_warped_demo_all potential_demo_all scalar_demo_all scalar_v2_demo_all) +add_custom_target(demo DEPENDS potential_rectangular_demo_all potential_warped_demo_all potential_demo_all scalar_demo_all scalar_v2_demo_all simple_partial_demo_all) #add_custom_target(demo DEPENDS potential_rectangular_demo_all potential_warped_demo_all potential_demo_all scalar_demo_all scalar_v2_demo_all simple_partial_demo_all simple_demo_all) # Automation diff --git a/demo/simple_partial/main.cpp b/demo/simple_partial/main.cpp index a6f95902ba2e29defaf7b5efef69839dae08849a..d33653854087c25d4bf90e15edfe04e339cae711 100644 --- a/demo/simple_partial/main.cpp +++ b/demo/simple_partial/main.cpp @@ -45,10 +45,10 @@ int _main(int argc, char **argv) b = ((u[1] - u[0]) - c * (sqr(max[1]) - sqr(min[1]))) / (max[1] - min[1]); a = u[0] - b * min[1] - c * sqr(min[1]); boundaries.resize(4); - boundaries[0] = new Line(Eigen::Vector2d(max[0], max[1]), Eigen::Vector2d(max[0], min[1]), false); //Right - boundaries[1] = new Line(Eigen::Vector2d(max[0], min[1]), Eigen::Vector2d(min[0], min[1]), false); //Bottom - boundaries[2] = new Line(Eigen::Vector2d(min[0], min[1]), Eigen::Vector2d(min[0], max[1]), false); //Left - boundaries[3] = new Line(Eigen::Vector2d(min[0], max[1]), Eigen::Vector2d(max[0], max[1]), false); //Top + boundaries[0].figure = new Line(Eigen::Vector2d(max[0], max[1]), Eigen::Vector2d(max[0], min[1]), false); //Right + boundaries[1].figure = new Line(Eigen::Vector2d(max[0], min[1]), Eigen::Vector2d(min[0], min[1]), false); //Bottom + boundaries[2].figure = new Line(Eigen::Vector2d(min[0], min[1]), Eigen::Vector2d(min[0], max[1]), false); //Left + boundaries[3].figure = new Line(Eigen::Vector2d(min[0], max[1]), Eigen::Vector2d(max[0], max[1]), false); //Top grid_origin = Eigen::Vector2d((min[0] + max[0]) / 2, (min[1] + max[1]) / 2); exact = true; } @@ -68,7 +68,7 @@ int _main(int argc, char **argv) w(reader.get_real("W")) { boundaries.resize(1); - boundaries[0] = new Circle(Eigen::Vector2d::Zero(), reader.get_real("R"), true); + boundaries[0].figure = new Circle(Eigen::Vector2d::Zero(), reader.get_real("R"), true); grid_origin = Eigen::Vector2d::Zero(); exact = true; } diff --git a/include/simple_partial/simple_partial.h b/include/simple_partial/simple_partial.h index 8c83777c5048f35900a5e7d40f76e07a1a575a9e..43c2dfc36072609e3d2c0b4cf9b3412d2d5a4563 100644 --- a/include/simple_partial/simple_partial.h +++ b/include/simple_partial/simple_partial.h @@ -3,11 +3,12 @@ Developed as part of Numerical Flow Simulation course Author: Kyrylo Sovailo */ #pragma once -#include <vector> -#include <unordered_set> -#include <Eigen/Dense> + #include <numsimulation/common.h> +#include <Eigen/Dense> #include <fstream> +#include <vector> +#include <set> using namespace numsimulation; @@ -16,19 +17,22 @@ namespace simple_partial struct Point; struct Face; struct Cell; + struct TemporaryCell; /// Point. Cells and faces consist of points struct Point { //Constants Eigen::Vector2d coord; ///< Point coordinate + + Point(Eigen::Vector2d coord); ///< Creates point }; /// Face. Face is a line between two points struct Face { /// Precalculated geometry data for each neighboring face - struct Precalculated + struct FaceConstants { int neighbor_velocity_sign; ///< Sign of velocity in neighboring cell (1 or -1) int neighbor_velocity_inwards_sign; ///< Sign of inwards velocity relative to velocity (1 or -1 or 0) @@ -48,7 +52,7 @@ namespace simple_partial double cell_cell_distance; ///< Precalculated distance between cells (corrected by normal) double area; ///< Precalculated area int pressure_sign; ///< Precalculated sign of pressure (1 or -1) - std::vector<Precalculated> precalculated; ///< Precalculated geometry data + std::vector<FaceConstants> face_constants; ///< Precalculated geometry data //Variables double velocity; ///< Velocity @@ -69,6 +73,8 @@ namespace simple_partial //Variables double pressure; ///< Pressure + + Cell(double area, Eigen::Vector2d center); ///< Creates cell }; /// Numerical method @@ -81,11 +87,17 @@ namespace simple_partial exponential }; + ///Boundary + struct Boundary + { + Figure *figure; ///< Boundary geometry + }; + /// Parameters (parameter functions unimplemented) struct AbstractParameters { // Geometry parameters - std::vector<Boundary*> boundaries; ///< List of boundaries + std::vector<Boundary> boundaries; ///< List of boundaries // Grid parameters Eigen::Vector2d grid_origin;///< Grid origin, where the field probing begins @@ -112,11 +124,24 @@ namespace simple_partial const AbstractParameters *_parameters; const std::string _filename; std::ofstream _file; - std::unordered_set<Point*> _points; - std::unordered_set<Face*> _faces; - std::unordered_set<Cell*> _cells; + std::set<Point*> _points; + std::set<Face*> _faces; + std::set<Cell*> _cells; double _time = 0.0; + + void _add_first_cell(std::map<Position, TemporaryCell> &active); ///< Adds first cell to active set + void _add_all_cells(std::map<Position, TemporaryCell> &active, std::map<Position, TemporaryCell> &passive); ///< Searches and adds cells to passive set + void _calculate_area(std::map<Position, TemporaryCell> &cells); ///< Calculate area of the cells + void _create_cells(std::map<Position, TemporaryCell> &cells); ///< Create cells + void _create_points(std::map<Position, TemporaryCell> &cells); ///< Create points + void _create_faces(std::map<Position, TemporaryCell> &cells); ///< Create faces + void _precalculate_faces(); ///< Precalculate face constants + void _interconnect_faces(std::map<Position, TemporaryCell> &cells); ///< Setup face->face pointers + void _precalculate_faces_cells(); ///< Precalculate face->cells constants + void _setup_velocity(); ///< Setup velocity on all faces + void _setup_fixed_velocity(); ///< Setup velocity on all fixed faces + void _setup_pressure(); ///< Setup pressure on all cells double _a(double pe) const; public: diff --git a/source/scalar_v2/scalar_v2.cpp b/source/scalar_v2/scalar_v2.cpp index d8d73f231b0000657e6c07efb1d1beede77ff063..f031f76144aca3cac4970508d17628e6b866eb39 100644 --- a/source/scalar_v2/scalar_v2.cpp +++ b/source/scalar_v2/scalar_v2.cpp @@ -6,7 +6,10 @@ Author: Kyrylo Sovailo */ #include <unordered_map> /* - Beginning with scalar_v2 all constructors are copypasted from scalar. Unique parts are marked with UNIQUE mark. Decent template/OOP refactoring is not the priority + Beginning with scalar_v2 all constructors are copypasted from scalar. Unique parts will be descried here and marked with UNIQUE mark + + Unique: + 1. face_cell_distance is not calculated */ namespace scalar_v2 diff --git a/source/simple_partial/output.cpp b/source/simple_partial/output.cpp index b8f43451c7b653ddd2b78b3632a6af98c4376a44..d8a67d53ffdc903167248c9eceee149d03b37f6a 100644 --- a/source/simple_partial/output.cpp +++ b/source/simple_partial/output.cpp @@ -9,29 +9,29 @@ void simple_partial::Solver::output() _file << "T " << _time << "\n"; //Write pressure data - for (std::unordered_set<Cell*>::iterator i = _cells.begin(); i != _cells.end(); i++) + for (std::set<Cell*>::iterator icell = _cells.begin(); icell != _cells.end(); icell++) { - Cell *p = *i; - _file << "X " << p->center(0) << " Y " << p->center(1) << " EP " << _parameters->pressure(p->center, _time) << "\n"; + Cell *cell = *icell; + _file << "X " << cell->center(0) << " Y " << cell->center(1) << " EP " << _parameters->pressure(cell->center, _time) << "\n"; } //Write velocity data - for (std::unordered_set<Face*>::iterator i = _faces.begin(); i != _faces.end(); i++) + for (std::set<Face*>::iterator iface = _faces.begin(); iface != _faces.end(); iface++) { - Face *f = *i; - _file << "X " << f->center(0) << " Y " << f->center(1); - if (abs(f->normal(0)) > abs(f->normal(1))) + Face *face = *iface; + _file << "X " << face->center(0) << " Y " << face->center(1); + if (abs(face->normal(0)) > abs(face->normal(1))) { //Horizontal normal, vertical face - _file << " VX " << (f->normal * f->velocity).x(); - if (_parameters->exact) _file << " EVX " << _parameters->velocity(f->center, _time).x(); + _file << " VX " << (face->normal * face->velocity).x(); + if (_parameters->exact) _file << " EVX " << _parameters->velocity(face->center, _time).x(); _file << "\n"; } else { //Vertical normal, horizontal face - _file << " VY " << (f->normal * f->velocity).y(); - if (_parameters->exact) _file << " EVY " << _parameters->velocity(f->center, _time).y(); + _file << " VY " << (face->normal * face->velocity).y(); + if (_parameters->exact) _file << " EVY " << _parameters->velocity(face->center, _time).y(); _file << "\n"; } } diff --git a/source/simple_partial/simple_partial.cpp b/source/simple_partial/simple_partial.cpp index d8c6620c7076a21d35ad84eab32ecdd02a582a98..695310a9f9919d0fbf7638c571744d222844505a 100644 --- a/source/simple_partial/simple_partial.cpp +++ b/source/simple_partial/simple_partial.cpp @@ -5,6 +5,16 @@ Author: Kyrylo Sovailo */ #include <simple_partial/simple_partial.h> #include <unordered_map> +/* + Beginning with scalar_v2 all constructors are copypasted from simple_partial. Unique parts will be descried here and marked with UNIQUE mark + + Unique: + 1. Faces have neighbors + 2. Faces have precalculated constants, cells do not + 3. There are no boundary conditions + 4. Only square grid +*/ + namespace simple_partial { enum class PointStatus @@ -37,8 +47,9 @@ namespace simple_partial { std::vector<TemporaryPoint> points; std::vector<TemporaryFace> faces; - double area = 0; - Eigen::Vector2d center = Eigen::Vector2d::Zero(); + double area; + Eigen::Vector2d center; + bool fixed_scalar = false; Cell *cell = nullptr; TemporaryCell(GridType grid_type); @@ -52,138 +63,138 @@ simple_partial::TemporaryCell::TemporaryCell(GridType grid_type) else { points.resize(4); faces.resize(4); } } -simple_partial::Solver::Solver(const AbstractParameters *parameters, std::string filename) : _parameters(parameters), _filename(filename) -{ - //Works like the scalar algorithm wit two differences: - //1. Interconnects faces - //2. Extended boundary conditions +simple_partial::Point::Point(Eigen::Vector2d coord) : coord(coord) {} - //Define sets, add first active point - std::unordered_map<Position, TemporaryCell> passive, active; +simple_partial::Cell::Cell(double area, Eigen::Vector2d center) : area(area), center(center) {} + +void simple_partial::Solver::_add_first_cell(std::map<Position, TemporaryCell> &active) +{ + TemporaryCell new_cell(GridType::square); + new_cell.points[0].status = PointStatus::active; + active.insert({Position(), new_cell}); + const std::vector<PointNeighbor> neighbors = get_point_neighbors(Position(), GridType::square, 0); + for (unsigned int n = 0; n < neighbors.size(); n++) { - TemporaryCell new_cell(GridType::square); - new_cell.points[0].status = PointStatus::active; - active.insert({Position(), new_cell}); - std::vector<std::pair<Position, unsigned int>> neighbors = get_point_neighbors(Position(), GridType::square, 0); - for (unsigned int n = 0; n < neighbors.size(); n++) - { - new_cell = TemporaryCell(GridType::square); - new_cell.points[neighbors[n].second].status = PointStatus::active; - active.insert({neighbors[n].first, new_cell}); - } + new_cell = TemporaryCell(GridType::square); + new_cell.points[neighbors[n].point].status = PointStatus::active; + active.insert({neighbors[n].position, new_cell}); } +} - //Search all other elements +void simple_partial::Solver::_add_all_cells(std::map<Position, TemporaryCell> &active, std::map<Position, TemporaryCell> &passive) +{ while (!active.empty()) { //Iterate through active, probe unprobed faces, add new cells to to_be_active - std::unordered_map<Position, TemporaryCell> to_be_active; - for (std::unordered_map<Position, TemporaryCell>::iterator i = active.begin(); i != active.end(); i++) + std::map<Position, TemporaryCell> to_be_active; + for (std::map<Position, TemporaryCell>::iterator cell = active.begin(); cell != active.end(); cell++) { //For each point - std::vector<Eigen::Vector2d> points = get_points(i->first, GridType::square, parameters->grid_origin, parameters->grid_size); + std::vector<Eigen::Vector2d> points = get_points(cell->first, GridType::square, _parameters->grid_origin, _parameters->grid_size); for (unsigned int p = 0; p < get_shape(GridType::square); p++) { - if (i->second.points[p].status != PointStatus::active) continue; + if (cell->second.points[p].status != PointStatus::active) continue; - //Trying to probe counterclockwise - unsigned int next_ccw = ((p == (i->second.points.size() - 1)) ? 0 : (p + 1)); - if (!i->second.faces[p].probed) + //Trying to probe counterclockwise + const unsigned int next_ccw = ((p == (cell->second.points.size() - 1)) ? 0 : (p + 1)); + if (!cell->second.faces[p].probed) { Intersection intersection; - for (unsigned int b = 0; b < parameters->boundaries.size(); b++) + //UNIQUE: no fixed_scalar + for (std::vector<Boundary>::const_iterator boundary = _parameters->boundaries.begin(); boundary != _parameters->boundaries.end(); boundary++) { - Intersection new_intersection = parameters->boundaries[b]->intersection(points[p], points[next_ccw]); + Intersection new_intersection = boundary->figure->intersection(points[p], points[next_ccw]); if (new_intersection.valid && (!intersection.valid || ((new_intersection.coord-points[p]).squaredNorm() < (intersection.coord-points[p]).squaredNorm()))) { intersection = new_intersection; } } - i->second.faces[p].probed = true; - i->second.faces[p].valid = intersection.valid; - i->second.faces[p].intersection = intersection.coord; - std::pair<Position, unsigned int> neighbor = get_face_neighbor(i->first, GridType::square, p); - std::unordered_map<Position, TemporaryCell>::iterator f = active.find(neighbor.first); - f->second.faces[neighbor.second].probed = true; - f->second.faces[neighbor.second].valid = intersection.valid; - f->second.faces[neighbor.second].intersection = intersection.coord; + cell->second.faces[p].probed = true; + cell->second.faces[p].valid = intersection.valid; + cell->second.faces[p].intersection = intersection.coord; + const FaceNeighbor neighbor = get_face_neighbor(cell->first, GridType::square, p); + std::map<Position, TemporaryCell>::iterator find = active.find(neighbor.position); + find->second.faces[neighbor.face].probed = true; + find->second.faces[neighbor.face].valid = intersection.valid; + find->second.faces[neighbor.face].intersection = intersection.coord; } - if (!i->second.faces[p].valid && i->second.points[next_ccw].status == PointStatus::unreached) + if (!cell->second.faces[p].valid && cell->second.points[next_ccw].status == PointStatus::unreached) { - i->second.points[next_ccw].status = PointStatus::to_be_active; - std::vector<std::pair<Position, unsigned int>> neighbors = get_point_neighbors(i->first, GridType::square, next_ccw); - for (std::vector<std::pair<Position, unsigned int>>::iterator neighbor = neighbors.begin(); neighbor != neighbors.end(); neighbor++) + cell->second.points[next_ccw].status = PointStatus::to_be_active; + const std::vector<PointNeighbor> neighbors = get_point_neighbors(cell->first, GridType::square, next_ccw); + for (std::vector<PointNeighbor>::const_iterator neighbor = neighbors.begin(); neighbor != neighbors.end(); neighbor++) { - if (to_be_active.find(neighbor->first) != to_be_active.end()) //to_be_active points remain to_be_active + if (to_be_active.find(neighbor->position) != to_be_active.end()) //to_be_active points remain to_be_active { - to_be_active.find(neighbor->first)->second.points[neighbor->second].status = PointStatus::to_be_active; + to_be_active.find(neighbor->position)->second.points[neighbor->point].status = PointStatus::to_be_active; } - else if (active.find(neighbor->first) != active.end()) //Active points remain active + else if (active.find(neighbor->position) != active.end()) //Active points remain active { - active.find(neighbor->first)->second.points[neighbor->second].status = PointStatus::to_be_active; + active.find(neighbor->position)->second.points[neighbor->point].status = PointStatus::to_be_active; } - else if (passive.find(neighbor->first) != passive.end()) //Passive points become to_be_active + else if (passive.find(neighbor->position) != passive.end()) //Passive points become to_be_active { - passive.find(neighbor->first)->second.points[neighbor->second].status = PointStatus::to_be_active; - to_be_active.insert(*passive.find(neighbor->first)); - passive.erase(neighbor->first); + passive.find(neighbor->position)->second.points[neighbor->point].status = PointStatus::to_be_active; + to_be_active.insert(*passive.find(neighbor->position)); + passive.erase(neighbor->position); } else //Create to_be_active point { TemporaryCell new_cell(GridType::square); - new_cell.points[neighbor->second].status = PointStatus::to_be_active; - to_be_active.insert({neighbor->first, new_cell}); + new_cell.points[neighbor->point].status = PointStatus::to_be_active; + to_be_active.insert({neighbor->position, new_cell}); } } } //Trying to probe clockwise - unsigned int next_cw = ((p == 0) ? (i->second.points.size() - 1) : (p - 1)); - if (!i->second.faces[next_cw].probed) + unsigned int next_cw = ((p == 0) ? (cell->second.points.size() - 1) : (p - 1)); + if (!cell->second.faces[next_cw].probed) { Intersection intersection; - for (unsigned int b = 0; b < parameters->boundaries.size(); b++) + //UNIQUE: no fixed_scalar + for (std::vector<Boundary>::const_iterator boundary = _parameters->boundaries.begin(); boundary != _parameters->boundaries.end(); boundary++) { - Intersection new_intersection = parameters->boundaries[b]->intersection(points[p], points[next_cw]); + Intersection new_intersection = boundary->figure->intersection(points[p], points[next_cw]); if (new_intersection.valid && (!intersection.valid || ((new_intersection.coord-points[p]).squaredNorm() < (intersection.coord-points[p]).squaredNorm()))) { intersection = new_intersection; } } - i->second.faces[next_cw].probed = true; - i->second.faces[next_cw].valid = intersection.valid; - i->second.faces[next_cw].intersection = intersection.coord; - std::pair<Position, unsigned int> neighbor = get_face_neighbor(i->first, GridType::square, next_cw); - std::unordered_map<Position, TemporaryCell>::iterator f = active.find(neighbor.first); - f->second.faces[neighbor.second].probed = true; - f->second.faces[neighbor.second].valid = intersection.valid; - f->second.faces[neighbor.second].intersection = intersection.coord; + cell->second.faces[next_cw].probed = true; + cell->second.faces[next_cw].valid = intersection.valid; + cell->second.faces[next_cw].intersection = intersection.coord; + const FaceNeighbor neighbor = get_face_neighbor(cell->first, GridType::square, next_cw); + std::map<Position, TemporaryCell>::iterator find = active.find(neighbor.position); + find->second.faces[neighbor.face].probed = true; + find->second.faces[neighbor.face].valid = intersection.valid; + find->second.faces[neighbor.face].intersection = intersection.coord; } - if (!i->second.faces[next_cw].valid && i->second.points[next_cw].status == PointStatus::unreached) + if (!cell->second.faces[next_cw].valid && cell->second.points[next_cw].status == PointStatus::unreached) { - i->second.points[next_cw].status = PointStatus::to_be_active; - std::vector<std::pair<Position, unsigned int>> neighbors = get_point_neighbors(i->first, GridType::square, next_cw); - for (std::vector<std::pair<Position, unsigned int>>::iterator neighbor = neighbors.begin(); neighbor != neighbors.end(); neighbor++) + cell->second.points[next_cw].status = PointStatus::to_be_active; + const std::vector<PointNeighbor> neighbors = get_point_neighbors(cell->first, GridType::square, next_cw); + for (std::vector<PointNeighbor>::const_iterator neighbor = neighbors.begin(); neighbor != neighbors.end(); neighbor++) { - if (to_be_active.find(neighbor->first) != to_be_active.end()) //to_be_active points remain to_be_active + if (to_be_active.find(neighbor->position) != to_be_active.end()) //to_be_active points remain to_be_active { - to_be_active.find(neighbor->first)->second.points[neighbor->second].status = PointStatus::to_be_active; + to_be_active.find(neighbor->position)->second.points[neighbor->point].status = PointStatus::to_be_active; } - else if (active.find(neighbor->first) != active.end()) //Active points remain active + else if (active.find(neighbor->position) != active.end()) //Active points remain active { - active.find(neighbor->first)->second.points[neighbor->second].status = PointStatus::to_be_active; + active.find(neighbor->position)->second.points[neighbor->point].status = PointStatus::to_be_active; } - else if (passive.find(neighbor->first) != passive.end()) //Passive points become to_be_active + else if (passive.find(neighbor->position) != passive.end()) //Passive points become to_be_active { - passive.find(neighbor->first)->second.points[neighbor->second].status = PointStatus::to_be_active; - to_be_active.insert(*passive.find(neighbor->first)); - passive.erase(neighbor->first); + passive.find(neighbor->position)->second.points[neighbor->point].status = PointStatus::to_be_active; + to_be_active.insert(*passive.find(neighbor->position)); + passive.erase(neighbor->position); } else //Create to_be_active point { TemporaryCell new_cell(GridType::square); - new_cell.points[neighbor->second].status = PointStatus::to_be_active; - to_be_active.insert({neighbor->first, new_cell}); + new_cell.points[neighbor->point].status = PointStatus::to_be_active; + to_be_active.insert({neighbor->position, new_cell}); } } } @@ -194,33 +205,35 @@ simple_partial::Solver::Solver(const AbstractParameters *parameters, std::string active.insert(to_be_active.begin(), to_be_active.end()); //Make to_be_active points active, make active points passive, divide active into new_active and passive - std::unordered_map<Position, TemporaryCell> new_active; - for (std::unordered_map<Position, TemporaryCell>::iterator i = active.begin(); i != active.end(); i++) + std::map<Position, TemporaryCell> new_active; + for (std::map<Position, TemporaryCell>::iterator cell = active.begin(); cell != active.end(); cell++) { bool active = false; - for (unsigned int p = 0; p < i->second.points.size(); p++) + for (unsigned int p = 0; p < cell->second.points.size(); p++) { - if (i->second.points[p].status == PointStatus::to_be_active) + if (cell->second.points[p].status == PointStatus::to_be_active) { - i->second.points[p].status = PointStatus::active; + cell->second.points[p].status = PointStatus::active; active = true; } - else if (i->second.points[p].status == PointStatus::active) + else if (cell->second.points[p].status == PointStatus::active) { - i->second.points[p].status = PointStatus::passive; + cell->second.points[p].status = PointStatus::passive; } } - if (active) new_active.insert(*i); - else passive.insert(*i); + if (active) new_active.insert(*cell); + else passive.insert(*cell); } active = new_active; } +} - //Calculating cells' area - for (std::unordered_map<Position, TemporaryCell>::iterator i = passive.begin(); i != passive.end(); i++) +void simple_partial::Solver::_calculate_area(std::map<Position, TemporaryCell> &cells) +{ + for (std::map<Position, TemporaryCell>::iterator i = cells.begin(); i != cells.end(); i++) { //Create list of points - std::vector<Eigen::Vector2d> points = get_points(i->first, GridType::square, parameters->grid_origin, parameters->grid_size); + std::vector<Eigen::Vector2d> points = get_points(i->first, GridType::square, _parameters->grid_origin, _parameters->grid_size); std::vector<Eigen::Vector2d> point_list; for (unsigned int p = 0; p < get_shape(GridType::square); p++) { @@ -230,6 +243,8 @@ simple_partial::Solver::Solver(const AbstractParameters *parameters, std::string } //Calculate area + i->second.area = 0; + i->second.center = Eigen::Vector2d::Zero(); for (unsigned int p = 1; p < (point_list.size() - 1); p++) { double a = (point_list[p] - point_list[0]).norm(); @@ -243,96 +258,106 @@ simple_partial::Solver::Solver(const AbstractParameters *parameters, std::string } i->second.center = i->second.center / i->second.area; } +} +void simple_partial::Solver::_create_cells(std::map<Position, TemporaryCell> &cells) +{ //Creating cells - for (std::unordered_map<Position, TemporaryCell>::iterator i = passive.begin(); i != passive.end(); i++) + for (std::map<Position, TemporaryCell>::iterator cell = cells.begin(); cell != cells.end(); cell++) { - if (i->second.area >= parameters->area_threshold) + if (cell->second.area >= _parameters->area_threshold) { - _cells.insert(i->second.cell = new Cell); - i->second.cell->pressure = parameters->pressure(i->second.center, 0); - i->second.cell->center = i->second.center; - i->second.cell->area = i->second.area; + _cells.insert(cell->second.cell = new Cell(cell->second.area, cell->second.center)); } } +} +void simple_partial::Solver::_create_points(std::map<Position, TemporaryCell> &cells) +{ //Creating points, faces and adding neighbors - for (std::unordered_map<Position, TemporaryCell>::iterator i = passive.begin(); i != passive.end(); i++) + for (std::map<Position, TemporaryCell>::iterator cell = cells.begin(); cell != cells.end(); cell++) { - if (i->second.cell == nullptr) continue; + if (cell->second.cell == nullptr) continue; //Creating points - std::vector<Eigen::Vector2d> points = get_points(i->first, GridType::square, parameters->grid_origin, parameters->grid_size); - for (unsigned int p = 0; p < i->second.points.size(); p++) + std::vector<Eigen::Vector2d> points = get_points(cell->first, GridType::square, _parameters->grid_origin, _parameters->grid_size); + for (unsigned int p = 0; p < cell->second.points.size(); p++) { //Regular points - if (i->second.points[p].status == PointStatus::passive) + if (cell->second.points[p].status == PointStatus::passive) { - if (i->second.points[p].point == nullptr) + if (cell->second.points[p].point == nullptr) { - _points.insert(i->second.points[p].point = new Point()); - i->second.points[p].point->coord = points[p]; - std::vector<std::pair<Position, unsigned int>> neighbors = get_point_neighbors(i->first, GridType::square, p); - for (std::vector<std::pair<Position, unsigned int>>::iterator neighbor = neighbors.begin(); neighbor != neighbors.end(); neighbor++) - passive.find(neighbor->first)->second.points[neighbor->second].point = i->second.points[p].point; + _points.insert(cell->second.points[p].point = new Point(points[p])); + const std::vector<PointNeighbor> neighbors = get_point_neighbors(cell->first, GridType::square, p); + for (std::vector<PointNeighbor>::const_iterator neighbor = neighbors.begin(); neighbor != neighbors.end(); neighbor++) + cells.find(neighbor->position)->second.points[neighbor->point].point = cell->second.points[p].point; } - i->second.cell->points.push_back(i->second.points[p].point); + cell->second.cell->points.push_back(cell->second.points[p].point); } //Points on faces - unsigned int next_ccw = ((p == (i->second.points.size() - 1)) ? 0 : (p + 1)); - if (i->second.points[p].status != i->second.points[next_ccw].status) + unsigned int next_ccw = ((p == (cell->second.points.size() - 1)) ? 0 : (p + 1)); + if (cell->second.points[p].status != cell->second.points[next_ccw].status) { - if (i->second.faces[p].point == nullptr) + if (cell->second.faces[p].point == nullptr) { - _points.insert(i->second.faces[p].point = new Point()); - i->second.faces[p].point->coord = i->second.faces[p].intersection; - std::pair<Position, unsigned int> neighbor = get_face_neighbor(i->first, GridType::square, p); - passive.find(neighbor.first)->second.faces[neighbor.second].point = i->second.faces[p].point; + _points.insert(cell->second.faces[p].point = new Point(cell->second.faces[p].intersection)); + const FaceNeighbor neighbor = get_face_neighbor(cell->first, GridType::square, p); + cells.find(neighbor.position)->second.faces[neighbor.face].point = cell->second.faces[p].point; } - i->second.cell->points.push_back(i->second.faces[p].point); + cell->second.cell->points.push_back(cell->second.faces[p].point); } } + } +} + +void simple_partial::Solver::_create_faces(std::map<Position, TemporaryCell> &cells) +{ + //Creating points, faces and adding neighbors + for (std::map<Position, TemporaryCell>::iterator cell = cells.begin(); cell != cells.end(); cell++) + { + if (cell->second.cell == nullptr) continue; //Creating faces Face *irregular = nullptr; - for (unsigned int p = 0; p < i->second.faces.size(); p++) + for (unsigned int p = 0; p < cell->second.faces.size(); p++) { - unsigned int next_ccw = ((p == (i->second.points.size() - 1)) ? 0 : (p + 1)); - if (i->second.points[p].status == PointStatus::passive || i->second.points[next_ccw].status == PointStatus::passive) + unsigned int next_ccw = ((p == (cell->second.points.size() - 1)) ? 0 : (p + 1)); + if (cell->second.points[p].status == PointStatus::passive || cell->second.points[next_ccw].status == PointStatus::passive) { - std::pair<Position, unsigned int> neighbor = get_face_neighbor(i->first, GridType::square, p); - if (i->second.faces[p].face == nullptr) + const FaceNeighbor neighbor = get_face_neighbor(cell->first, GridType::square, p); + if (cell->second.faces[p].face == nullptr) { - _faces.insert(i->second.faces[p].face = new Face()); - passive.find(neighbor.first)->second.faces[neighbor.second].face = i->second.faces[p].face; + _faces.insert(cell->second.faces[p].face = new Face()); + cells.find(neighbor.position)->second.faces[neighbor.face].face = cell->second.faces[p].face; } - i->second.cell->faces.push_back(i->second.faces[p].face); - i->second.cell->neighbors.push_back(passive.find(neighbor.first)->second.cell); + cell->second.cell->faces.push_back(cell->second.faces[p].face); + cell->second.cell->neighbors.push_back(cells.find(neighbor.position)->second.cell); } - if (i->second.points[p].status == PointStatus::passive && i->second.points[next_ccw].status == PointStatus::passive) + if (cell->second.points[p].status == PointStatus::passive && cell->second.points[next_ccw].status == PointStatus::passive) { - i->second.faces[p].face->point[0] = i->second.points[p].point; - i->second.faces[p].face->point[1] = i->second.points[next_ccw].point; + cell->second.faces[p].face->point[0] = cell->second.points[p].point; + cell->second.faces[p].face->point[1] = cell->second.points[next_ccw].point; } - if (i->second.points[p].status == PointStatus::passive && i->second.points[next_ccw].status != PointStatus::passive) + if (cell->second.points[p].status == PointStatus::passive && cell->second.points[next_ccw].status != PointStatus::passive) { - i->second.faces[p].face->point[0] = i->second.points[p].point; - i->second.faces[p].face->point[1] = i->second.faces[p].point; + cell->second.faces[p].face->point[0] = cell->second.points[p].point; + cell->second.faces[p].face->point[1] = cell->second.faces[p].point; //Opening irregular face _faces.insert(irregular = new Face); - i->second.cell->faces.push_back(irregular); - i->second.cell->neighbors.push_back(nullptr); - irregular->point[0] = i->second.faces[p].point; + cell->second.cell->faces.push_back(irregular); + cell->second.cell->neighbors.push_back(nullptr); + irregular->point[0] = cell->second.faces[p].point; } - if (i->second.points[p].status != PointStatus::passive && i->second.points[next_ccw].status == PointStatus::passive) + if (cell->second.points[p].status != PointStatus::passive && cell->second.points[next_ccw].status == PointStatus::passive) { - i->second.faces[p].face->point[0] = i->second.faces[p].point; - i->second.faces[p].face->point[1] = i->second.points[next_ccw].point; + cell->second.faces[p].face->point[0] = cell->second.faces[p].point; + cell->second.faces[p].face->point[1] = cell->second.points[next_ccw].point; //Closing irregular face if (irregular != nullptr) { - irregular->point[1] = i->second.faces[p].point; + irregular->point[1] = cell->second.faces[p].point; irregular = nullptr; } } @@ -340,64 +365,68 @@ simple_partial::Solver::Solver(const AbstractParameters *parameters, std::string if (irregular != nullptr) { //Closing irregular face - for (unsigned int p = 0; p < i->second.faces.size(); p++) + for (unsigned int p = 0; p < cell->second.faces.size(); p++) { - if (i->second.faces[p].point != nullptr) { irregular->point[1] = i->second.faces[p].point; break; } + if (cell->second.faces[p].point != nullptr) { irregular->point[1] = cell->second.faces[p].point; break; } } } } +} - //Precalculating face-specific and setting velocity - for (std::unordered_set<Face*>::iterator i = _faces.begin(); i != _faces.end(); i++) +void simple_partial::Solver::_precalculate_faces() +{ + for (std::set<Face*>::iterator iface = _faces.begin(); iface != _faces.end(); iface++) { - Face *face = *i; - face->center = (face->point[0]->coord + face->point[1]->coord) / 2; - Eigen::Vector2d face_vector = face->point[0]->coord - face->point[1]->coord; //should point same as normal - face->length = face_vector.norm(); + Face *face = *iface; + Eigen::Vector2d face_vector = face->point[0]->coord - face->point[1]->coord; face->normal = rotate_cw(face_vector) / face_vector.norm(); - - face->velocity = _parameters->velocity(face->center, 0).dot(face->normal); + face->length = face_vector.norm(); + face->center = (face->point[0]->coord + face->point[1]->coord) / 2; } +} - //Making reverse links - for (std::unordered_map<Position, TemporaryCell>::iterator i = passive.begin(); i != passive.end(); i++) +void simple_partial::Solver::_interconnect_faces(std::map<Position, TemporaryCell> &cells) +{ + for (std::map<Position, TemporaryCell>::iterator cell = cells.begin(); cell != cells.end(); cell++) { - if (i->second.cell == nullptr) continue; + if (cell->second.cell == nullptr) continue; //Face to cell reverse pointer - for (unsigned int f = 0; f < i->second.cell->faces.size(); f++) i->second.cell->faces[f]->cells.push_back(i->second.cell); + for (unsigned int f = 0; f < cell->second.cell->faces.size(); f++) cell->second.cell->faces[f]->cells.push_back(cell->second.cell); //Face to face reverse pointer - for (unsigned int f = 0; f < i->second.faces.size(); f++) + for (unsigned int f = 0; f < cell->second.faces.size(); f++) { - if (i->second.faces[f].face == nullptr) continue; + if (cell->second.faces[f].face == nullptr) continue; - if (i->second.faces[(f+2)%4].face != nullptr) i->second.faces[f].face->neighbors.push_back(i->second.faces[(f+2)%4].face); + if (cell->second.faces[(f+2)%4].face != nullptr) cell->second.faces[f].face->neighbors.push_back(cell->second.faces[(f+2)%4].face); - Position position[2] = { i->first, i->first }; + Position position[2] = { cell->first, cell->first }; if (f == 0 || f == 2) { position[0].xi--; position[1].xi++; } else { position[0].yi--; position[1].yi++; } for (unsigned int j = 0; j < 2; j++) { - std::unordered_map<Position, TemporaryCell>::iterator found = passive.find(position[j]); - if (found != passive.end() && found->second.faces[f].face != nullptr) + std::map<Position, TemporaryCell>::iterator find = cells.find(position[j]); + if (find != cells.end() && find->second.faces[f].face != nullptr) { bool match = false; - for (unsigned int k = 0; k < i->second.faces[f].face->neighbors.size(); k++) + for (unsigned int k = 0; k < cell->second.faces[f].face->neighbors.size(); k++) { - if (i->second.faces[f].face->neighbors[k] == found->second.faces[f].face) match = true; + if (cell->second.faces[f].face->neighbors[k] == find->second.faces[f].face) match = true; } - if (!match) i->second.faces[f].face->neighbors.push_back(found->second.faces[f].face); + if (!match) cell->second.faces[f].face->neighbors.push_back(find->second.faces[f].face); } } } } +} - //Precalculating face- and neighbor-specific - for (std::unordered_set<Face*>::iterator i = _faces.begin(); i != _faces.end(); i++) +void simple_partial::Solver::_precalculate_faces_cells() +{ + for (std::set<Face*>::iterator iface = _faces.begin(); iface != _faces.end(); iface++) { - Face *face = *i; - if (face->cells.size() < 2) continue; + Face *face = *iface; + if (face->cells.size() < 2) continue; //Skip fixed Eigen::Vector2d cell_cell_vector = face->cells[1]->center - face->cells[0]->center; face->cell_cell_distance = cell_cell_vector.dot(face->normal); @@ -405,59 +434,85 @@ simple_partial::Solver::Solver(const AbstractParameters *parameters, std::string if (face->cell_cell_distance < 0) { cell_cell_vector *= -1; face->cell_cell_distance *= -1; face->pressure_sign *= -1; } face->area = face->length * face->cell_cell_distance; - face->precalculated.resize(face->neighbors.size()); + face->face_constants.resize(face->neighbors.size()); for (unsigned int n = 0; n < face->neighbors.size(); n++) { - face->precalculated[n].neighbor_velocity_sign = (face->neighbors[n]->normal.dot(face->normal) < 0) ? (-1) : (1); + face->face_constants[n].neighbor_velocity_sign = (face->neighbors[n]->normal.dot(face->normal) < 0) ? (-1) : (1); Eigen::Vector2d face_face_vector = face->center - face->neighbors[n]->center; //points inwards double face_face_vector_y = face_face_vector.dot(face->normal); double face_face_vector_x = face_face_vector.dot(rotate_cw(face->normal)); if (std::abs(face_face_vector_y) > std::abs(face_face_vector_x)) //upper or lower { - face->precalculated[n].neighbor_velocity_inwards_sign = ((face_face_vector_y < 0) ? (-1) : (1)) * face->precalculated[n].neighbor_velocity_sign; //negative if upper - face->precalculated[n].face_face_distance = std::abs(face_face_vector_y); - face->precalculated[n].border_length = face->length; + face->face_constants[n].neighbor_velocity_inwards_sign = ((face_face_vector_y < 0) ? (-1) : (1)) * face->face_constants[n].neighbor_velocity_sign; //negative if upper + face->face_constants[n].face_face_distance = std::abs(face_face_vector_y); + face->face_constants[n].border_length = face->length; } else //right or left { - face->precalculated[n].neighbor_velocity_inwards_sign = 0; - face->precalculated[n].face_face_distance = std::abs(face_face_vector_x); - face->precalculated[n].border_length = face->cell_cell_distance; + face->face_constants[n].neighbor_velocity_inwards_sign = 0; + face->face_constants[n].face_face_distance = std::abs(face_face_vector_x); + face->face_constants[n].border_length = face->cell_cell_distance; } } } +} + +void simple_partial::Solver::_setup_velocity() +{ + for (std::set<Face*>::iterator iface = _faces.begin(); iface != _faces.end(); iface++) + { + Face *face = *iface; + face->velocity = _parameters->velocity(face->center, 0).dot(face->normal); + } +} + +simple_partial::Solver::Solver(const AbstractParameters *parameters, std::string filename) : _parameters(parameters), _filename(filename) +{ + //Define sets, add first active point + std::map<Position, TemporaryCell> passive, active; + _add_first_cell(active); + _add_all_cells(active, passive); + _calculate_area(passive); + _create_cells(passive); + _create_points(passive); + _create_faces(passive); + _precalculate_faces(); + _interconnect_faces(passive); + _precalculate_faces_cells(); + _setup_velocity(); //Opening file _file = std::ofstream(_filename, std::ios::binary); - if (!_file.good()) throw std::runtime_error("scalar_v2::Solver::_output(): Cannot open file"); + if (!_file.good()) throw std::runtime_error("simple_partial::Solver::_output(): Cannot open file"); //Write header double min[2] = { std::numeric_limits<double>::infinity(), std::numeric_limits<double>::infinity() }; double max[2] = { -std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity() }; - for (std::unordered_set<Cell*>::iterator i = _cells.begin(); i != _cells.end(); i++) + for (std::set<Cell*>::iterator icell = _cells.begin(); icell != _cells.end(); icell++) { - if ((*i)->center(0) < min[0]) min[0] = (*i)->center(0); - if ((*i)->center(1) < min[1]) min[1] = (*i)->center(1); - if ((*i)->center(0) > max[0]) max[0] = (*i)->center(0); - if ((*i)->center(1) > max[1]) max[1] = (*i)->center(1); + Cell *cell = *icell; + if (cell->center(0) < min[0]) min[0] = cell->center(0); + if (cell->center(1) < min[1]) min[1] = cell->center(1); + if (cell->center(0) > max[0]) max[0] = cell->center(0); + if (cell->center(1) > max[1]) max[1] = cell->center(1); } _file << "NX " << (unsigned int)((max[0] - min[0]) / _parameters->grid_size[0]) << " NY " << (unsigned int)((max[1] - min[1]) / _parameters->grid_size[1]) << '\n'; } simple_partial::Solver::~Solver() { - for (std::unordered_set<Point*>::iterator i = _points.begin(); i != _points.end(); i++) + for (std::set<Point*>::iterator i = _points.begin(); i != _points.end(); i++) { delete (*i); } - for (std::unordered_set<Face*>::iterator i = _faces.begin(); i != _faces.end(); i++) + for (std::set<Face*>::iterator i = _faces.begin(); i != _faces.end(); i++) { delete (*i); } - for (std::unordered_set<Cell*>::iterator i = _cells.begin(); i != _cells.end(); i++) + for (std::set<Cell*>::iterator i = _cells.begin(); i != _cells.end(); i++) { delete (*i); } diff --git a/source/simple_partial/solve.cpp b/source/simple_partial/solve.cpp index a5484150e9e7db03914627eee80e9ec2fc472c0e..452376753b43c458f318f5cc913bbc905e7f6d2a 100644 --- a/source/simple_partial/solve.cpp +++ b/source/simple_partial/solve.cpp @@ -20,53 +20,51 @@ double simple_partial::Solver::_a(double pe) const void simple_partial::Solver::step() { //Settting up pressure - for (std::unordered_set<Cell*>::iterator i = _cells.begin(); i != _cells.end(); i++) + for (std::set<Cell*>::iterator icell = _cells.begin(); icell != _cells.end(); icell++) { - Cell *cell = *i; + Cell *cell = *icell; cell->pressure = _parameters->pressure(cell->center, _time); } //Setting up fixed faces - for (std::unordered_set<Face*>::iterator i = _faces.begin(); i != _faces.end(); i++) + for (std::set<Face*>::iterator iface = _faces.begin(); iface != _faces.end(); iface++) { - Face *face = *i; + Face *face = *iface; if (face->cells.size() < 2) face->velocity = _parameters->velocity(face->center, _time).dot(face->normal); } //Processing - for (std::unordered_set<Face*>::iterator i = _faces.begin(); i != _faces.end(); i++) + for (std::set<Face*>::iterator iface = _faces.begin(); iface != _faces.end(); iface++) { - Face *face = *i; + Face *face = *iface; if (face->cells.size() < 2) continue; //Skip fixed cells - double ap = _parameters->density * face->area / _parameters->step; //ap becomes ap_tilde till the end of the iteration - double b = ap * face->velocity; //b becomes ap_tilde*next_velocity till the end of the iteration + double a0 = _parameters->density * face->area / _parameters->step; //a0 becomes a0_tilde till the end of the iteration + double b = a0 * face->velocity; //b becomes a0_tilde*next_velocity till the end of the iteration b -= face->pressure_sign * (face->cells[1]->pressure - face->cells[0]->pressure) * face->area / face->cell_cell_distance; for (unsigned int n = 0; n < face->neighbors.size(); n++) { //Precalculating - //face velocity in the right direction, used as scalar - double neighbor_velocity = face->precalculated[n].neighbor_velocity_sign * face->neighbors[n]->velocity; - //face velocity in inwards direction, used as velocity - double neighbor_velocity_inwards = face->precalculated[n].neighbor_velocity_inwards_sign * neighbor_velocity; - double face_face_distance = face->precalculated[n].face_face_distance; - double border_length = face->precalculated[n].border_length; + const double neighbor_velocity = face->face_constants[n].neighbor_velocity_sign * face->neighbors[n]->velocity; + const double neighbor_velocity_inwards = face->face_constants[n].neighbor_velocity_inwards_sign * neighbor_velocity; + const double face_face_distance = face->face_constants[n].face_face_distance; + const double border_length = face->face_constants[n].border_length; //Kernel - double d = _parameters->viscosity / face_face_distance; - double pe = _parameters->density * neighbor_velocity_inwards * face_face_distance / _parameters->viscosity; - double f = neighbor_velocity_inwards * _parameters->density; - double a = d * border_length * _a(pe) + std::max(0.0, f * border_length); - ap += a; + const double d = _parameters->viscosity / face_face_distance; + const double pe = _parameters->density * neighbor_velocity_inwards * face_face_distance / _parameters->viscosity; + const double f = neighbor_velocity_inwards * _parameters->density; + const double a = d * border_length * _a(pe) + std::max(0.0, f * border_length); + a0 += a; b += a * neighbor_velocity; } - face->new_velocity = b / ap; + face->new_velocity = b / a0; } //Postprocessing - for (std::unordered_set<Face*>::iterator i = _faces.begin(); i != _faces.end(); i++) + for (std::set<Face*>::iterator iface = _faces.begin(); iface != _faces.end(); iface++) { - Face *face = *i; + Face *face = *iface; if (face->cells.size() < 2) continue; face->velocity = face->new_velocity; }