diff --git a/src/particles/containers/linkedcells/LinkedCellsContainer.cpp b/src/particles/containers/linkedcells/LinkedCellsContainer.cpp index b4276e12d..980e79d7b 100644 --- a/src/particles/containers/linkedcells/LinkedCellsContainer.cpp +++ b/src/particles/containers/linkedcells/LinkedCellsContainer.cpp @@ -4,6 +4,9 @@ #include "cells/Cell.h" #include "io/logger/Logger.h" +#include "particles/containers/linkedcells/boundaries/OutflowBoundaryType.h" +#include "particles/containers/linkedcells/boundaries/PeriodicBoundaryType.h" +#include "particles/containers/linkedcells/boundaries/ReflectiveBoundaryType.h" #include "physics/pairwiseforces/LennardJonesForce.h" #include "utils/ArrayUtils.h" @@ -87,17 +90,12 @@ void LinkedCellsContainer::prepareForceCalculation() { // update the particle references in the cells in case the particles have moved updateCellsParticleReferences(); - // move particles in the halo cells of periodic boundaries over to the other side of the domain - moveOverPeriodicBoundaries(); + ReflectiveBoundaryType::pre(*this); + OutflowBoundaryType::pre(*this); + PeriodicBoundaryType::pre(*this); // update the particle references in the cells in case the particles have moved updateCellsParticleReferences(); - - // remove all particles left in halo cells (they are in outflow boundaries) - deleteHaloParticles(); - - // update the particle references in the cells in case some particles have been removed - updateCellsParticleReferences(); } void LinkedCellsContainer::applySimpleForces(const std::vector>& simple_force_sources) { @@ -110,10 +108,9 @@ void LinkedCellsContainer::applySimpleForces(const std::vector>& force_sources) { // apply the boundary conditions - applyReflectiveBoundaryConditions(); - - // add the periodic halo particles - addPeriodicHaloParticles(); + ReflectiveBoundaryType::applyBoundaryConditions(*this); + OutflowBoundaryType::applyBoundaryConditions(*this); + PeriodicBoundaryType::applyBoundaryConditions(*this); // clear the already influenced by vector in the cells // this is needed to prevent the two cells from affecting each other twice @@ -359,299 +356,3 @@ void LinkedCellsContainer::deleteHaloParticles() { } } } - -void LinkedCellsContainer::applyReflectiveBoundaryConditions() { - if (boundary_types[0] == BoundaryCondition::REFLECTIVE) { - for (Cell* cell : left_boundary_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - double distance = p->getX()[0]; - p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, BoundarySide::LEFT)); - } - } - } - - if (boundary_types[1] == BoundaryCondition::REFLECTIVE) { - for (Cell* cell : right_boundary_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - double distance = domain_size[0] - p->getX()[0]; - p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, BoundarySide::RIGHT)); - } - } - } - - if (boundary_types[2] == BoundaryCondition::REFLECTIVE) { - for (Cell* cell : bottom_boundary_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - double distance = p->getX()[1]; - p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, BoundarySide::BOTTOM)); - } - } - } - - if (boundary_types[3] == BoundaryCondition::REFLECTIVE) { - for (Cell* cell : top_boundary_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - double distance = domain_size[1] - p->getX()[1]; - p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, BoundarySide::TOP)); - } - } - } - - if (boundary_types[4] == BoundaryCondition::REFLECTIVE) { - for (Cell* cell : back_boundary_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - double distance = p->getX()[2]; - p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, BoundarySide::BACK)); - } - } - } - - if (boundary_types[5] == BoundaryCondition::REFLECTIVE) { - for (Cell* cell : front_boundary_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - double distance = domain_size[2] - p->getX()[2]; - p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, BoundarySide::FRONT)); - } - } - } -} - -std::array LinkedCellsContainer::calculateReflectiveBoundaryForce(Particle& p, double distance, BoundarySide side) { - LennardJonesForce force = LennardJonesForce(); - - if (2 * distance >= std::pow(2, 1.0 / 6) * p.getSigma()) { - return {0, 0, 0}; - } - - Particle ghost_particle = Particle(p); - ghost_particle.setX(p.getX() - std::array{2 * distance, 0, 0}); - - auto force_vector_left_side = force.calculateForce(p, ghost_particle); - - switch (side) { - case BoundarySide::LEFT: - return force_vector_left_side; - case BoundarySide::RIGHT: - return {-force_vector_left_side[0], 0, 0}; - case BoundarySide::BOTTOM: - return {0, force_vector_left_side[0], 0}; - case BoundarySide::TOP: - return {0, -force_vector_left_side[0], 0}; - case BoundarySide::BACK: - return {0, 0, force_vector_left_side[0]}; - case BoundarySide::FRONT: - return {0, 0, -force_vector_left_side[0]}; - } - - Logger::logger->error("Faulty reflective boundary condition"); - return {0, 0, 0}; -} - -void LinkedCellsContainer::addPeriodicHaloParticles() { - // Add Halo Particles for each side of the domain - if (boundary_types[0] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForSide(left_boundary_cell_references, {domain_size[0], 0, 0}); - } - - if (boundary_types[1] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForSide(right_boundary_cell_references, {-domain_size[0], 0, 0}); - } - - if (boundary_types[2] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForSide(bottom_boundary_cell_references, {0, domain_size[1], 0}); - } - - if (boundary_types[3] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForSide(top_boundary_cell_references, {0, -domain_size[1], 0}); - } - - if (boundary_types[4] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForSide(back_boundary_cell_references, {0, 0, domain_size[2]}); - } - - if (boundary_types[5] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForSide(front_boundary_cell_references, {0, 0, -domain_size[2]}); - } - - // Add Halo Particles for each edge of the domain - if (boundary_types[0] == BoundaryCondition::PERIODIC && boundary_types[2] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(2, {domain_size[0], domain_size[1], 0}); - } - - if (boundary_types[0] == BoundaryCondition::PERIODIC && boundary_types[3] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(2, {domain_size[0], -domain_size[1], 0}); - } - - if (boundary_types[1] == BoundaryCondition::PERIODIC && boundary_types[2] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(2, {-domain_size[0], domain_size[1], 0}); - } - - if (boundary_types[1] == BoundaryCondition::PERIODIC && boundary_types[3] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(2, {-domain_size[0], -domain_size[1], 0}); - } - - if (boundary_types[0] == BoundaryCondition::PERIODIC && boundary_types[4] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(1, {domain_size[0], 0, domain_size[2]}); - } - - if (boundary_types[0] == BoundaryCondition::PERIODIC && boundary_types[5] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(1, {domain_size[0], 0, -domain_size[2]}); - } - - if (boundary_types[1] == BoundaryCondition::PERIODIC && boundary_types[4] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(1, {-domain_size[0], 0, domain_size[2]}); - } - - if (boundary_types[1] == BoundaryCondition::PERIODIC && boundary_types[5] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(1, {-domain_size[0], 0, -domain_size[2]}); - } - - if (boundary_types[2] == BoundaryCondition::PERIODIC && boundary_types[4] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(0, {0, domain_size[1], domain_size[2]}); - } - - if (boundary_types[2] == BoundaryCondition::PERIODIC && boundary_types[5] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(0, {0, domain_size[1], -domain_size[2]}); - } - - if (boundary_types[3] == BoundaryCondition::PERIODIC && boundary_types[4] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(0, {0, -domain_size[1], domain_size[2]}); - } - - if (boundary_types[3] == BoundaryCondition::PERIODIC && boundary_types[5] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForEdge(0, {0, -domain_size[1], -domain_size[2]}); - } - - // Add Halo Particles for each corner of the domain - if (boundary_types[0] == BoundaryCondition::PERIODIC && boundary_types[2] == BoundaryCondition::PERIODIC && - boundary_types[4] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForCorner({domain_size[0], domain_size[1], domain_size[2]}); - } - - if (boundary_types[0] == BoundaryCondition::PERIODIC && boundary_types[2] == BoundaryCondition::PERIODIC && - boundary_types[5] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForCorner({domain_size[0], domain_size[1], -domain_size[2]}); - } - - if (boundary_types[0] == BoundaryCondition::PERIODIC && boundary_types[3] == BoundaryCondition::PERIODIC && - boundary_types[4] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForCorner({domain_size[0], -domain_size[1], domain_size[2]}); - } - - if (boundary_types[0] == BoundaryCondition::PERIODIC && boundary_types[3] == BoundaryCondition::PERIODIC && - boundary_types[5] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForCorner({domain_size[0], -domain_size[1], -domain_size[2]}); - } - - if (boundary_types[1] == BoundaryCondition::PERIODIC && boundary_types[2] == BoundaryCondition::PERIODIC && - boundary_types[4] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForCorner({-domain_size[0], domain_size[1], domain_size[2]}); - } - - if (boundary_types[1] == BoundaryCondition::PERIODIC && boundary_types[2] == BoundaryCondition::PERIODIC && - boundary_types[5] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForCorner({-domain_size[0], domain_size[1], -domain_size[2]}); - } - - if (boundary_types[1] == BoundaryCondition::PERIODIC && boundary_types[3] == BoundaryCondition::PERIODIC && - boundary_types[4] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForCorner({-domain_size[0], -domain_size[1], domain_size[2]}); - } - - if (boundary_types[1] == BoundaryCondition::PERIODIC && boundary_types[3] == BoundaryCondition::PERIODIC && - boundary_types[5] == BoundaryCondition::PERIODIC) { - addPeriodicHaloParticlesForCorner({-domain_size[0], -domain_size[1], -domain_size[2]}); - } -} - -void LinkedCellsContainer::addPeriodicHaloParticlesForSide(const std::vector& side_cell_references, - const std::array& offset) { - for (Cell* cell : side_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - Particle ghost_particle = Particle(*p); - ghost_particle.setX(p->getX() + offset); - addParticle(ghost_particle); - } - } -} - -void LinkedCellsContainer::addPeriodicHaloParticlesForEdge(int free_dimension, const std::array& offset) { - std::array running_array{0, 0, 0}; - running_array[0] = (offset[0] < 0) ? domain_num_cells[0] - 1 : 0; - running_array[1] = (offset[1] < 0) ? domain_num_cells[1] - 1 : 0; - running_array[2] = (offset[2] < 0) ? domain_num_cells[2] - 1 : 0; - - for (int c = 0; c < domain_num_cells[2]; ++c) { - Cell* cell = &cells.at(cellCoordToCellIndex(running_array[0], running_array[1], running_array[2])); - for (Particle* p : cell->getParticleReferences()) { - Particle ghost_particle = Particle(*p); - ghost_particle.setX(p->getX() + offset); - addParticle(ghost_particle); - } - running_array[free_dimension] += 1; - } -} - -void LinkedCellsContainer::addPeriodicHaloParticlesForCorner(const std::array& offset) { - std::array cell_coords{0, 0, 0}; - cell_coords[0] = (offset[0] < 0) ? domain_num_cells[0] - 1 : 0; - cell_coords[1] = (offset[1] < 0) ? domain_num_cells[1] - 1 : 0; - cell_coords[2] = (offset[2] < 0) ? domain_num_cells[2] - 1 : 0; - - Cell* cell = &cells.at(cellCoordToCellIndex(cell_coords[0], cell_coords[1], cell_coords[2])); - for (Particle* p : cell->getParticleReferences()) { - Particle ghost_particle = Particle(*p); - ghost_particle.setX(p->getX() + offset); - addParticle(ghost_particle); - } -} - -void LinkedCellsContainer::moveOverPeriodicBoundaries() { - if (boundary_types[0] == BoundaryCondition::PERIODIC) { - for (Cell* cell : left_halo_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - p->setX(p->getX() + std::array{domain_size[0], 0, 0}); - } - } - } - - if (boundary_types[1] == BoundaryCondition::PERIODIC) { - for (Cell* cell : right_halo_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - p->setX(p->getX() + std::array{-domain_size[0], 0, 0}); - } - } - } - - if (boundary_types[2] == BoundaryCondition::PERIODIC) { - for (Cell* cell : bottom_halo_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - p->setX(p->getX() + std::array{0, domain_size[1], 0}); - } - } - } - - if (boundary_types[3] == BoundaryCondition::PERIODIC) { - for (Cell* cell : top_halo_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - p->setX(p->getX() + std::array{0, -domain_size[1], 0}); - } - } - } - - if (boundary_types[4] == BoundaryCondition::PERIODIC) { - for (Cell* cell : back_halo_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - p->setX(p->getX() + std::array{0, 0, domain_size[2]}); - } - } - } - - if (boundary_types[5] == BoundaryCondition::PERIODIC) { - for (Cell* cell : front_halo_cell_references) { - for (Particle* p : cell->getParticleReferences()) { - p->setX(p->getX() + std::array{0, 0, -domain_size[2]}); - } - } - } -} diff --git a/src/particles/containers/linkedcells/LinkedCellsContainer.h b/src/particles/containers/linkedcells/LinkedCellsContainer.h index 2f874ce54..f60c48208 100644 --- a/src/particles/containers/linkedcells/LinkedCellsContainer.h +++ b/src/particles/containers/linkedcells/LinkedCellsContainer.h @@ -24,127 +24,6 @@ class LinkedCellsContainer : public ParticleContainer { */ enum class BoundarySide { LEFT, RIGHT, BOTTOM, TOP, BACK, FRONT }; - private: - /** - * @brief Internal data structure for the particles - */ - std::vector particles; - - /** - * @brief Domain size in each dimension - */ - std::array domain_size; - - /** - * @brief Cutoff radius for the force calculation - */ - double cutoff_radius; - - /** - * @brief The boundary types for each side of the domain (order in array: left, right, bottom, top, back, front) - */ - std::array boundary_types; - - /** - * @brief Cell size in each dimension - */ - std::array cell_size; - - /** - * @brief Number of cells in each dimension - */ - std::array domain_num_cells; - - /** - * @brief Internal data structure for the cells - */ - std::vector cells; - - /** - * @brief References to the domain cells - */ - std::vector domain_cell_references; - - /** - * @brief References to the boundary cells - */ - std::vector boundary_cell_references; - - /** - * @brief References to the halo cells - */ - std::vector halo_cell_references; - - /** - * @brief Temporary storage for references of cells that contain at least one particle to avoid iteration over empty cells. Uses - * unordered_set to avoid duplicate inserts. - */ - std::unordered_set occupied_cells_references; - - // Boundary cell references with respect to x-axis pointing to the right, y-axis pointing up and z axis pointing out of the screen - - /** - * @brief References to the boundary cells on the left (x = 0) - */ - std::vector left_boundary_cell_references; - - /** - * @brief References to the boundary cells on the right (x = domain_num_cells[0]-1) - */ - std::vector right_boundary_cell_references; - - /** - * @brief References to the boundary cells on the bottom (y = 0) - */ - std::vector bottom_boundary_cell_references; - - /** - * @brief References to the boundary cells on the top (y = domain_num_cells[1]-1) - */ - std::vector top_boundary_cell_references; - - /** - * @brief References to the boundary cells on the back (z = 0) - */ - std::vector back_boundary_cell_references; - - /** - * @brief References to the boundary cells on the front (z = domain_num_cells[2]-1) - */ - std::vector front_boundary_cell_references; - - // Halo cell references with respect to x-axis pointing to the right, y-axis pointing up and z axis pointing out of the screen - - /** - * @brief References to the halo cells on the left (x = -1) - */ - std::vector left_halo_cell_references; - - /** - * @brief References to the halo cells on the right (x = domain_num_cells[0]) - */ - std::vector right_halo_cell_references; - - /** - * @brief References to the halo cells on the bottom (y = -1) - */ - std::vector bottom_halo_cell_references; - - /** - * @brief References to the halo cells on the top (y = domain_num_cells[1]) - */ - std::vector top_halo_cell_references; - - /** - * @brief References to the halo cells on the back (z = -1) - */ - std::vector back_halo_cell_references; - - /** - * @brief References to the halo cells on the front (z = domain_num_cells[2]) - */ - std::vector front_halo_cell_references; - public: /** * @brief Construct a new Linked Cells Particle Container object @@ -381,54 +260,138 @@ class LinkedCellsContainer : public ParticleContainer { void deleteHaloParticles(); /** - * @brief Applies the reflective boundary conditions to the particles in the cells at a reflective boundary + * @brief Friend class to allow access to the internal data structures */ - void applyReflectiveBoundaryConditions(); + friend class ReflectiveBoundaryType; /** - * @brief Calculates the force exerted by a reflective boundary on a particle in a boundary cell - * - * @param p Particle - * @param distance Distance of the particle to the boundary - * @param side Side of the boundary (left, right, bottom, top, back, front) - * @return Reflective boundary force exerted by the boundary on the particle + * @brief Friend class to allow access to the internal data structures */ - std::array calculateReflectiveBoundaryForce(Particle& p, double distance, BoundarySide side); + friend class OutflowBoundaryType; /** - * @brief Inserts the halo particles necessary for periodic boundary conditions into the particle vector and cells. + * @brief Friend class to allow access to the internal data structures */ - void addPeriodicHaloParticles(); + friend class PeriodicBoundaryType; + private: /** - * @brief Helper method for addPeriodicHaloParticles() that adds the halo particles for a specific single side of the domain - * ATTENTION: This method does not perform any checks on the correctness of its parameters!!! - * - * @param side_cell_references References to the cells on specified side of the domain - * @param offset Offset vector for the periodic boundary + * @brief Internal data structure for the particles */ - void addPeriodicHaloParticlesForSide(const std::vector& side_cell_references, const std::array& offset); + std::vector particles; /** - * @brief Helper method for addPeriodicHaloParticles() that adds the halo particles for a specific edge of the domain (deduced via - * offset and free dimension) ATTENTION: This method does not perform any checks on the correctness of its parameters!!! - * - * @param free_dimension The free dimension of the edge (dimension over witch to iterate) (0 -> x, 1 -> y, 2 -> z) - * @param offset Offset vector for the halo particles boundary + * @brief Domain size in each dimension */ - void addPeriodicHaloParticlesForEdge(int free_dimension, const std::array& offset); + std::array domain_size; /** - * @brief Helper method for addPeriodicHaloParticles() that adds the halo particles for a specific corner of the domain (deduced via - * offset) ATTENTION: This method does not perform any checks on the correctness of its parameters!!! - * - * @param offset Offset vector for the halo particles boundary + * @brief Cutoff radius for the force calculation + */ + double cutoff_radius; + + /** + * @brief The boundary types for each side of the domain (order in array: left, right, bottom, top, back, front) */ - void addPeriodicHaloParticlesForCorner(const std::array& offset); + std::array boundary_types; + + /** + * @brief Cell size in each dimension + */ + std::array cell_size; + + /** + * @brief Number of cells in each dimension + */ + std::array domain_num_cells; /** - * @brief Moves the particles in the halo cells to the corresponding periodic boundary cells. - * ATTENTION: A particle reference update must be triggered after wards + * @brief Internal data structure for the cells + */ + std::vector cells; + + /** + * @brief References to the domain cells + */ + std::vector domain_cell_references; + + /** + * @brief References to the boundary cells + */ + std::vector boundary_cell_references; + + /** + * @brief References to the halo cells + */ + std::vector halo_cell_references; + + /** + * @brief Temporary storage for references of cells that contain at least one particle to avoid iteration over empty cells. Uses + * unordered_set to avoid duplicate inserts. + */ + std::unordered_set occupied_cells_references; + + // Boundary cell references with respect to x-axis pointing to the right, y-axis pointing up and z axis pointing out of the screen + + /** + * @brief References to the boundary cells on the left (x = 0) */ - void moveOverPeriodicBoundaries(); + std::vector left_boundary_cell_references; + + /** + * @brief References to the boundary cells on the right (x = domain_num_cells[0]-1) + */ + std::vector right_boundary_cell_references; + + /** + * @brief References to the boundary cells on the bottom (y = 0) + */ + std::vector bottom_boundary_cell_references; + + /** + * @brief References to the boundary cells on the top (y = domain_num_cells[1]-1) + */ + std::vector top_boundary_cell_references; + + /** + * @brief References to the boundary cells on the back (z = 0) + */ + std::vector back_boundary_cell_references; + + /** + * @brief References to the boundary cells on the front (z = domain_num_cells[2]-1) + */ + std::vector front_boundary_cell_references; + + // Halo cell references with respect to x-axis pointing to the right, y-axis pointing up and z axis pointing out of the screen + + /** + * @brief References to the halo cells on the left (x = -1) + */ + std::vector left_halo_cell_references; + + /** + * @brief References to the halo cells on the right (x = domain_num_cells[0]) + */ + std::vector right_halo_cell_references; + + /** + * @brief References to the halo cells on the bottom (y = -1) + */ + std::vector bottom_halo_cell_references; + + /** + * @brief References to the halo cells on the top (y = domain_num_cells[1]) + */ + std::vector top_halo_cell_references; + + /** + * @brief References to the halo cells on the back (z = -1) + */ + std::vector back_halo_cell_references; + + /** + * @brief References to the halo cells on the front (z = domain_num_cells[2]) + */ + std::vector front_halo_cell_references; }; diff --git a/src/particles/containers/linkedcells/boundaries/OutflowBoundaryType.cpp b/src/particles/containers/linkedcells/boundaries/OutflowBoundaryType.cpp new file mode 100644 index 000000000..8152bf37d --- /dev/null +++ b/src/particles/containers/linkedcells/boundaries/OutflowBoundaryType.cpp @@ -0,0 +1,57 @@ +#include "OutflowBoundaryType.h" + +#include "io/logger/Logger.h" +#include "physics/pairwiseforces/LennardJonesForce.h" +#include "utils/ArrayUtils.h" + +void OutflowBoundaryType::pre(LinkedCellsContainer& container) { + if (container.boundary_types[0] == LinkedCellsContainer::BoundaryCondition::OUTFLOW) { + for (Cell* cell : container.left_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + container.particles.erase(std::find(container.particles.begin(), container.particles.end(), *p)); + } + } + } + + if (container.boundary_types[1] == LinkedCellsContainer::BoundaryCondition::OUTFLOW) { + for (Cell* cell : container.right_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + container.particles.erase(std::find(container.particles.begin(), container.particles.end(), *p)); + } + } + } + + if (container.boundary_types[2] == LinkedCellsContainer::BoundaryCondition::OUTFLOW) { + for (Cell* cell : container.bottom_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + container.particles.erase(std::find(container.particles.begin(), container.particles.end(), *p)); + } + } + } + + if (container.boundary_types[3] == LinkedCellsContainer::BoundaryCondition::OUTFLOW) { + for (Cell* cell : container.top_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + container.particles.erase(std::find(container.particles.begin(), container.particles.end(), *p)); + } + } + } + + if (container.boundary_types[4] == LinkedCellsContainer::BoundaryCondition::OUTFLOW) { + for (Cell* cell : container.back_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + container.particles.erase(std::find(container.particles.begin(), container.particles.end(), *p)); + } + } + } + + if (container.boundary_types[5] == LinkedCellsContainer::BoundaryCondition::OUTFLOW) { + for (Cell* cell : container.front_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + container.particles.erase(std::find(container.particles.begin(), container.particles.end(), *p)); + } + } + } +} + +void OutflowBoundaryType::applyBoundaryConditions(LinkedCellsContainer& container) {} diff --git a/src/particles/containers/linkedcells/boundaries/OutflowBoundaryType.h b/src/particles/containers/linkedcells/boundaries/OutflowBoundaryType.h new file mode 100644 index 000000000..ec319e056 --- /dev/null +++ b/src/particles/containers/linkedcells/boundaries/OutflowBoundaryType.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +#include "particles/containers/linkedcells/LinkedCellsContainer.h" + +class OutflowBoundaryType { + public: + /** + * @brief Applies the preconditioning step for the outflow boundary condition. + * + * @param container The container to apply the boundary conditions to. + * + * This method removes all particles from the container that are in halo cells with the outflow boundary condition. + */ + static void pre(LinkedCellsContainer& container); + + /** + * @brief Applies the boundary conditions for the outflow boundary condition. + * + * @param container The container to apply the boundary conditions to. + * + * This method is empty, as the outflow boundary condition does not require any special treatment. + */ + static void applyBoundaryConditions(LinkedCellsContainer& container); + + private: + static std::array calculateReflectiveBoundaryForce(Particle& p, double distance, LinkedCellsContainer::BoundarySide side); +}; \ No newline at end of file diff --git a/src/particles/containers/linkedcells/boundaries/PeriodicBoundaryType.cpp b/src/particles/containers/linkedcells/boundaries/PeriodicBoundaryType.cpp new file mode 100644 index 000000000..0932b0322 --- /dev/null +++ b/src/particles/containers/linkedcells/boundaries/PeriodicBoundaryType.cpp @@ -0,0 +1,235 @@ +#include "PeriodicBoundaryType.h" + +#include "io/logger/Logger.h" +#include "physics/pairwiseforces/LennardJonesForce.h" +#include "utils/ArrayUtils.h" + +void PeriodicBoundaryType::pre(LinkedCellsContainer& container) { + if (container.boundary_types[0] == LinkedCellsContainer::LinkedCellsContainer::BoundaryCondition::PERIODIC) { + for (Cell* cell : container.left_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + p->setX(p->getX() + std::array{container.domain_size[0], 0, 0}); + } + } + } + + if (container.boundary_types[1] == LinkedCellsContainer::LinkedCellsContainer::BoundaryCondition::PERIODIC) { + for (Cell* cell : container.right_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + p->setX(p->getX() + std::array{-container.domain_size[0], 0, 0}); + } + } + } + + if (container.boundary_types[2] == LinkedCellsContainer::LinkedCellsContainer::BoundaryCondition::PERIODIC) { + for (Cell* cell : container.bottom_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + p->setX(p->getX() + std::array{0, container.domain_size[1], 0}); + } + } + } + + if (container.boundary_types[3] == LinkedCellsContainer::LinkedCellsContainer::BoundaryCondition::PERIODIC) { + for (Cell* cell : container.top_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + p->setX(p->getX() + std::array{0, -container.domain_size[1], 0}); + } + } + } + + if (container.boundary_types[4] == LinkedCellsContainer::LinkedCellsContainer::BoundaryCondition::PERIODIC) { + for (Cell* cell : container.back_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + p->setX(p->getX() + std::array{0, 0, container.domain_size[2]}); + } + } + } + + if (container.boundary_types[5] == LinkedCellsContainer::LinkedCellsContainer::BoundaryCondition::PERIODIC) { + for (Cell* cell : container.front_halo_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + p->setX(p->getX() + std::array{0, 0, -container.domain_size[2]}); + } + } + } +} + +void PeriodicBoundaryType::applyBoundaryConditions(LinkedCellsContainer& container) { + // Add Halo Particles for each side of the domain + if (container.boundary_types[0] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForSide(container, container.left_boundary_cell_references, {container.domain_size[0], 0, 0}); + } + + if (container.boundary_types[1] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForSide(container, container.right_boundary_cell_references, {-container.domain_size[0], 0, 0}); + } + + if (container.boundary_types[2] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForSide(container, container.bottom_boundary_cell_references, {0, container.domain_size[1], 0}); + } + + if (container.boundary_types[3] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForSide(container, container.top_boundary_cell_references, {0, -container.domain_size[1], 0}); + } + + if (container.boundary_types[4] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForSide(container, container.back_boundary_cell_references, {0, 0, container.domain_size[2]}); + } + + if (container.boundary_types[5] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForSide(container, container.front_boundary_cell_references, {0, 0, -container.domain_size[2]}); + } + + // Add Halo Particles for each edge of the domain + if (container.boundary_types[0] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[2] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 2, {container.domain_size[0], container.domain_size[1], 0}); + } + + if (container.boundary_types[0] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[3] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 2, {container.domain_size[0], -container.domain_size[1], 0}); + } + + if (container.boundary_types[1] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[2] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 2, {-container.domain_size[0], container.domain_size[1], 0}); + } + + if (container.boundary_types[1] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[3] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 2, {-container.domain_size[0], -container.domain_size[1], 0}); + } + + if (container.boundary_types[0] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[4] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 1, {container.domain_size[0], 0, container.domain_size[2]}); + } + + if (container.boundary_types[0] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[5] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 1, {container.domain_size[0], 0, -container.domain_size[2]}); + } + + if (container.boundary_types[1] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[4] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 1, {-container.domain_size[0], 0, container.domain_size[2]}); + } + + if (container.boundary_types[1] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[5] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 1, {-container.domain_size[0], 0, -container.domain_size[2]}); + } + + if (container.boundary_types[2] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[4] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 0, {0, container.domain_size[1], container.domain_size[2]}); + } + + if (container.boundary_types[2] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[5] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 0, {0, container.domain_size[1], -container.domain_size[2]}); + } + + if (container.boundary_types[3] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[4] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 0, {0, -container.domain_size[1], container.domain_size[2]}); + } + + if (container.boundary_types[3] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[5] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForEdge(container, 0, {0, -container.domain_size[1], -container.domain_size[2]}); + } + + // Add Halo Particles for each corner of the domain + if (container.boundary_types[0] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[2] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[4] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForCorner(container, {container.domain_size[0], container.domain_size[1], container.domain_size[2]}); + } + + if (container.boundary_types[0] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[2] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[5] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForCorner(container, {container.domain_size[0], container.domain_size[1], -container.domain_size[2]}); + } + + if (container.boundary_types[0] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[3] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[4] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForCorner(container, {container.domain_size[0], -container.domain_size[1], container.domain_size[2]}); + } + + if (container.boundary_types[0] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[3] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[5] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForCorner(container, {container.domain_size[0], -container.domain_size[1], -container.domain_size[2]}); + } + + if (container.boundary_types[1] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[2] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[4] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForCorner(container, {-container.domain_size[0], container.domain_size[1], container.domain_size[2]}); + } + + if (container.boundary_types[1] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[2] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[5] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForCorner(container, {-container.domain_size[0], container.domain_size[1], -container.domain_size[2]}); + } + + if (container.boundary_types[1] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[3] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[4] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForCorner(container, {-container.domain_size[0], -container.domain_size[1], container.domain_size[2]}); + } + + if (container.boundary_types[1] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[3] == LinkedCellsContainer::BoundaryCondition::PERIODIC && + container.boundary_types[5] == LinkedCellsContainer::BoundaryCondition::PERIODIC) { + addPeriodicHaloParticlesForCorner(container, {-container.domain_size[0], -container.domain_size[1], -container.domain_size[2]}); + } +} + +void PeriodicBoundaryType::addPeriodicHaloParticlesForSide(LinkedCellsContainer& container, const std::vector& side_cell_references, + const std::array& offset) { + for (Cell* cell : side_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + Particle ghost_particle = Particle(*p); + ghost_particle.setX(p->getX() + offset); + container.addParticle(ghost_particle); + } + } +} + +void PeriodicBoundaryType::addPeriodicHaloParticlesForEdge(LinkedCellsContainer& container, int free_dimension, + const std::array& offset) { + std::array running_array{0, 0, 0}; + running_array[0] = (offset[0] < 0) ? container.domain_num_cells[0] - 1 : 0; + running_array[1] = (offset[1] < 0) ? container.domain_num_cells[1] - 1 : 0; + running_array[2] = (offset[2] < 0) ? container.domain_num_cells[2] - 1 : 0; + + for (int c = 0; c < container.domain_num_cells[2]; ++c) { + Cell* cell = &container.cells.at(container.cellCoordToCellIndex(running_array[0], running_array[1], running_array[2])); + for (Particle* p : cell->getParticleReferences()) { + Particle ghost_particle = Particle(*p); + ghost_particle.setX(p->getX() + offset); + container.addParticle(ghost_particle); + } + running_array[free_dimension] += 1; + } +} + +void PeriodicBoundaryType::addPeriodicHaloParticlesForCorner(LinkedCellsContainer& container, const std::array& offset) { + std::array cell_coords{0, 0, 0}; + cell_coords[0] = (offset[0] < 0) ? container.domain_num_cells[0] - 1 : 0; + cell_coords[1] = (offset[1] < 0) ? container.domain_num_cells[1] - 1 : 0; + cell_coords[2] = (offset[2] < 0) ? container.domain_num_cells[2] - 1 : 0; + + Cell* cell = &container.cells.at(container.cellCoordToCellIndex(cell_coords[0], cell_coords[1], cell_coords[2])); + for (Particle* p : cell->getParticleReferences()) { + Particle ghost_particle = Particle(*p); + ghost_particle.setX(p->getX() + offset); + container.addParticle(ghost_particle); + } +} diff --git a/src/particles/containers/linkedcells/boundaries/PeriodicBoundaryType.h b/src/particles/containers/linkedcells/boundaries/PeriodicBoundaryType.h new file mode 100644 index 000000000..4b22a05a0 --- /dev/null +++ b/src/particles/containers/linkedcells/boundaries/PeriodicBoundaryType.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +#include "particles/containers/linkedcells/LinkedCellsContainer.h" + +class PeriodicBoundaryType { + public: + /** + * @brief Applies the preconditioning step for the periodic boundary condition. + * + * @param container The container to apply the boundary conditions to. + * + * This method teleports all particles that are in halo cells with the periodic boundary condition to the opposite side of the + * container. + */ + static void pre(LinkedCellsContainer& container); + + /** + * @brief Applies the boundary conditions for the periodic boundary condition. + * + * @param container The container to apply the boundary conditions to. + * + * This method adds all the Halo particles for the periodic boundary to the respective side of the container. + */ + static void applyBoundaryConditions(LinkedCellsContainer& container); + + private: + /** + * @brief Adds the periodic halo particles for the given side of the container to the other side of the container. + * + * @param container The container to add the particles to. + * @param side_cell_references The cell references of the halo cells for the given side. + * @param offset The offset to the opposite side of the container. + */ + static void addPeriodicHaloParticlesForSide(LinkedCellsContainer& container, const std::vector& side_cell_references, + const std::array& offset); + + /** + * @brief Adds the periodic halo particles for the given edge of the container to the diagonally opposite edge of the container. + * @param container The container to add the particles to. + * @param free_dimension The free dimension of the edge. + * @param offset The offset to the opposite edge of the container. + */ + static void addPeriodicHaloParticlesForEdge(LinkedCellsContainer& container, int free_dimension, const std::array& offset); + + /** + * @brief Adds the periodic halo particles for the given corner of the container to the diagonally opposite corner of the container. + * @param container The container to add the particles to. + * @param offset The offset to the opposite corner of the container. + */ + static void addPeriodicHaloParticlesForCorner(LinkedCellsContainer& container, const std::array& offset); +}; diff --git a/src/particles/containers/linkedcells/boundaries/ReflectiveBoundaryType.cpp b/src/particles/containers/linkedcells/boundaries/ReflectiveBoundaryType.cpp new file mode 100644 index 000000000..af6307d88 --- /dev/null +++ b/src/particles/containers/linkedcells/boundaries/ReflectiveBoundaryType.cpp @@ -0,0 +1,97 @@ +#include "ReflectiveBoundaryType.h" + +#include "io/logger/Logger.h" +#include "physics/pairwiseforces/LennardJonesForce.h" +#include "utils/ArrayUtils.h" + +void ReflectiveBoundaryType::pre(LinkedCellsContainer& container){ + +}; + +void ReflectiveBoundaryType::applyBoundaryConditions(LinkedCellsContainer& container) { + if (container.boundary_types[0] == LinkedCellsContainer::BoundaryCondition::REFLECTIVE) { + for (Cell* cell : container.left_boundary_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + double distance = p->getX()[0]; + p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, LinkedCellsContainer::BoundarySide::LEFT)); + } + } + } + + if (container.boundary_types[1] == LinkedCellsContainer::BoundaryCondition::REFLECTIVE) { + for (Cell* cell : container.right_boundary_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + double distance = container.domain_size[0] - p->getX()[0]; + p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, LinkedCellsContainer::BoundarySide::RIGHT)); + } + } + } + + if (container.boundary_types[2] == LinkedCellsContainer::BoundaryCondition::REFLECTIVE) { + for (Cell* cell : container.bottom_boundary_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + double distance = p->getX()[1]; + p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, LinkedCellsContainer::BoundarySide::BOTTOM)); + } + } + } + + if (container.boundary_types[3] == LinkedCellsContainer::BoundaryCondition::REFLECTIVE) { + for (Cell* cell : container.top_boundary_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + double distance = container.domain_size[1] - p->getX()[1]; + p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, LinkedCellsContainer::BoundarySide::TOP)); + } + } + } + + if (container.boundary_types[4] == LinkedCellsContainer::BoundaryCondition::REFLECTIVE) { + for (Cell* cell : container.back_boundary_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + double distance = p->getX()[2]; + p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, LinkedCellsContainer::BoundarySide::BACK)); + } + } + } + + if (container.boundary_types[5] == LinkedCellsContainer::BoundaryCondition::REFLECTIVE) { + for (Cell* cell : container.front_boundary_cell_references) { + for (Particle* p : cell->getParticleReferences()) { + double distance = container.domain_size[2] - p->getX()[2]; + p->setF(p->getF() + calculateReflectiveBoundaryForce(*p, distance, LinkedCellsContainer::BoundarySide::FRONT)); + } + } + } +} + +std::array ReflectiveBoundaryType::calculateReflectiveBoundaryForce(Particle& p, double distance, + LinkedCellsContainer::BoundarySide side) { + LennardJonesForce force = LennardJonesForce(); + + if (2 * distance >= std::pow(2, 1.0 / 6) * p.getSigma()) { + return {0, 0, 0}; + } + + Particle ghost_particle = Particle(p); + ghost_particle.setX(p.getX() - std::array{2 * distance, 0, 0}); + + auto force_vector_left_side = force.calculateForce(p, ghost_particle); + + switch (side) { + case LinkedCellsContainer::BoundarySide::LEFT: + return force_vector_left_side; + case LinkedCellsContainer::BoundarySide::RIGHT: + return {-force_vector_left_side[0], 0, 0}; + case LinkedCellsContainer::BoundarySide::BOTTOM: + return {0, force_vector_left_side[0], 0}; + case LinkedCellsContainer::BoundarySide::TOP: + return {0, -force_vector_left_side[0], 0}; + case LinkedCellsContainer::BoundarySide::BACK: + return {0, 0, force_vector_left_side[0]}; + case LinkedCellsContainer::BoundarySide::FRONT: + return {0, 0, -force_vector_left_side[0]}; + } + + Logger::logger->error("Faulty reflective boundary condition"); + return {0, 0, 0}; +} \ No newline at end of file diff --git a/src/particles/containers/linkedcells/boundaries/ReflectiveBoundaryType.h b/src/particles/containers/linkedcells/boundaries/ReflectiveBoundaryType.h new file mode 100644 index 000000000..6810f7d69 --- /dev/null +++ b/src/particles/containers/linkedcells/boundaries/ReflectiveBoundaryType.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +#include "particles/containers/linkedcells/LinkedCellsContainer.h" + +class ReflectiveBoundaryType { + public: + /** + * @brief Applies the preconditioning step for the reflective boundary condition. + * + * @param container The container to apply the boundary conditions to. + * + * This method is empty, as the reflective boundary condition does not require any special treatment. + */ + static void pre(LinkedCellsContainer& container); + + /** + * @brief Applies the boundary conditions for the reflective boundary condition. + * + * @param container The container to apply the boundary conditions to. + * + * This method adds the force of the reflective boundary to all particles that are in halo cells with the reflective boundary condition. + */ + static void applyBoundaryConditions(LinkedCellsContainer& container); + + private: + /** + * @brief Calculates the force of the reflective boundary for the given particle. + * + * @param p The particle to calculate the force for. + * @param distance The distance of the particle to the boundary. + * @param side The side of the boundary. + * + * @return The force of the reflective boundary for the given particle. + */ + static std::array calculateReflectiveBoundaryForce(Particle& p, double distance, LinkedCellsContainer::BoundarySide side); +}; \ No newline at end of file