diff --git a/CMakePresets.json b/CMakePresets.json deleted file mode 100644 index 97aa089298..0000000000 --- a/CMakePresets.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": 8, - "configurePresets": [ - { - "name": "default", - "displayName": "SPHinXsys Debug", - "description": "Sets Ninja generator, build and install directory", - "generator": "Ninja", - "binaryDir": "${sourceDir}/build", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_TOOLCHAIN_FILE": "'$/home/xyhu/vcpkg/scripts/buildsystems/vcpkg.cmake'" - } - }, - { - "name": "release", - "displayName": "SPHinXsys Release", - "description": "Sets Ninja generator, build and install directory", - "generator": "Ninja", - "binaryDir": "${sourceDir}/build", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Release", - "CMAKE_TOOLCHAIN_FILE": "'$/home/xyhu/vcpkg/scripts/buildsystems/vcpkg.cmake'" - } - } - ] -} \ No newline at end of file diff --git a/src/shared/common/sphinxsys_containers.h b/src/shared/common/sphinxsys_containers.h index abca65ff04..483001344d 100644 --- a/src/shared/common/sphinxsys_containers.h +++ b/src/shared/common/sphinxsys_containers.h @@ -77,8 +77,6 @@ using ListData = std::pair; using ListDataVector = StdLargeVec; using DataListsInCells = StdLargeVec; using ConcurrentCellLists = ConcurrentVec; -/** Cell list for splitting algorithms. */ -using SplitCellLists = StdVec; /** Cell list for periodic boundary condition algorithms. */ using CellLists = std::pair; diff --git a/src/shared/meshes/cell_linked_list.cpp b/src/shared/meshes/cell_linked_list.cpp index faccfc03c3..6d10e43950 100644 --- a/src/shared/meshes/cell_linked_list.cpp +++ b/src/shared/meshes/cell_linked_list.cpp @@ -13,40 +13,18 @@ BaseCellLinkedList:: BaseCellLinkedList(BaseParticles &base_particles, SPHAdaptation &sph_adaptation) : BaseMeshField("CellLinkedList"), kernel_(*sph_adaptation.getKernel()) {} //=================================================================================================// -SplitCellLists *BaseCellLinkedList::getSplitCellLists() -{ - std::cout << "\n Error: SplitCellList not defined!" << std::endl; - std::cout << __FILE__ << ':' << __LINE__ << std::endl; - exit(1); - return nullptr; -} -//=================================================================================================// -void BaseCellLinkedList::setUseSplitCellLists() -{ - std::cout << "\n Error: SplitCellList not defined!" << std::endl; - std::cout << __FILE__ << ':' << __LINE__ << std::endl; - exit(1); -}; -//=================================================================================================// -void BaseCellLinkedList::clearSplitCellLists(SplitCellLists &split_cell_lists) -{ - for (size_t i = 0; i < split_cell_lists.size(); i++) - split_cell_lists[i].clear(); -} -//=================================================================================================// CellLinkedList::CellLinkedList(BoundingBox tentative_bounds, Real grid_spacing, BaseParticles &base_particles, SPHAdaptation &sph_adaptation) : BaseCellLinkedList(base_particles, sph_adaptation), Mesh(tentative_bounds, grid_spacing, 2), - use_split_cell_lists_(false), cell_offset_list_size_(NumberOfCells() + 1), + cell_offset_list_size_(NumberOfCells() + 1), index_list_size_(SMAX(base_particles.ParticlesBound(), cell_offset_list_size_)), dv_particle_index_(base_particles.registerDiscreteVariableOnly("ParticleIndex", index_list_size_)), dv_cell_offset_(base_particles.registerDiscreteVariableOnly("CellOffset", cell_offset_list_size_)), - cell_index_lists_(nullptr), cell_data_lists_(nullptr) + cell_index_lists_(nullptr), cell_data_lists_(nullptr), + number_of_split_cell_lists_(static_cast(pow(3, Dimensions))) { allocateMeshDataMatrix(); single_cell_linked_list_level_.push_back(this); - size_t number_of_split_cell_lists = pow(3, Dimensions); - split_cell_lists_.resize(number_of_split_cell_lists); } //=================================================================================================// void CellLinkedList ::allocateMeshDataMatrix() @@ -89,23 +67,6 @@ void CellLinkedList::UpdateCellListData(BaseParticles &base_particles) }); } //=================================================================================================// -void CellLinkedList::updateSplitCellLists(SplitCellLists &split_cell_lists) -{ - clearSplitCellLists(split_cell_lists); - mesh_parallel_for( - MeshRange(Arrayi::Zero(), all_cells_), - [&](const Arrayi &cell_index) - { - ConcurrentIndexVector &cell_list = getCellDataList(cell_index_lists_, cell_index); - size_t real_particles_in_cell = cell_list.size(); - if (real_particles_in_cell != 0) - { - split_cell_lists[transferMeshIndexTo1D(3 * Arrayi::Ones(), mod(cell_index, 3))] - .push_back(&cell_list); - } - }); -} -//=================================================================================================// void CellLinkedList::UpdateCellLists(BaseParticles &base_particles) { clearCellLists(); @@ -123,11 +84,6 @@ void CellLinkedList::UpdateCellLists(BaseParticles &base_particles) ap); UpdateCellListData(base_particles); - - if (use_split_cell_lists_) - { - updateSplitCellLists(split_cell_lists_); - } } //=================================================================================================// void CellLinkedList ::insertParticleIndex(size_t particle_index, const Vecd &particle_position) diff --git a/src/shared/meshes/cell_linked_list.h b/src/shared/meshes/cell_linked_list.h index baae6d2cf5..1dd15e95a0 100644 --- a/src/shared/meshes/cell_linked_list.h +++ b/src/shared/meshes/cell_linked_list.h @@ -33,6 +33,7 @@ #define MESH_CELL_LINKED_LIST_H #include "base_mesh.h" +#include "execution_policy.h" #include "neighborhood.h" namespace SPH @@ -51,20 +52,14 @@ class BaseCellLinkedList : public BaseMeshField { protected: Kernel &kernel_; - /** clear split cell lists in this mesh*/ - virtual void clearSplitCellLists(SplitCellLists &split_cell_lists); - /** update split particle list in this mesh */ - virtual void updateSplitCellLists(SplitCellLists &split_cell_lists) = 0; public: BaseCellLinkedList(BaseParticles &base_particles, SPHAdaptation &sph_adaptation); - virtual ~BaseCellLinkedList() {}; + virtual ~BaseCellLinkedList(){}; /** access concrete cell linked list levels*/ virtual StdVec CellLinkedListLevels() = 0; virtual void UpdateCellLists(BaseParticles &base_particles) = 0; - virtual SplitCellLists *getSplitCellLists(); - virtual void setUseSplitCellLists(); /** Insert a cell-linked_list entry to the concurrent index list. */ virtual void insertParticleIndex(size_t particle_index, const Vecd &particle_position) = 0; /** Insert a cell-linked_list entry of the index and particle position pair. */ @@ -105,14 +100,6 @@ class NeighborSearch : public Mesh class CellLinkedList : public BaseCellLinkedList, public Mesh { StdVec single_cell_linked_list_level_; - /** - * @brief particle by cells lists is for parallel splitting algorithm. - * All particles in each cell are collected together. - * If two particles each belongs two different cell entries, - * they have no interaction because they are too far. - */ - SplitCellLists split_cell_lists_; - bool use_split_cell_lists_; UnsignedInt cell_offset_list_size_; UnsignedInt index_list_size_; // at least number_of_cells_pluse_one_ @@ -124,10 +111,11 @@ class CellLinkedList : public BaseCellLinkedList, public Mesh ConcurrentIndexVector *cell_index_lists_; /** non-concurrent list data rewritten for building neighbor list */ ListDataVector *cell_data_lists_; + /**< number of split cell lists */ + size_t number_of_split_cell_lists_; void allocateMeshDataMatrix(); /**< allocate memories for addresses of data packages. */ void deleteMeshDataMatrix(); /**< delete memories for addresses of data packages. */ - virtual void updateSplitCellLists(SplitCellLists &split_cell_lists) override; template DataListsType &getCellDataList(DataListsType *data_lists, const Arrayi &cell_index) { @@ -140,8 +128,6 @@ class CellLinkedList : public BaseCellLinkedList, public Mesh ~CellLinkedList() { deleteMeshDataMatrix(); }; void clearCellLists(); - virtual SplitCellLists *getSplitCellLists() override { return &split_cell_lists_; }; - virtual void setUseSplitCellLists() override { use_split_cell_lists_ = true; }; void UpdateCellListData(BaseParticles &base_particles); virtual void UpdateCellLists(BaseParticles &base_particles) override; void insertParticleIndex(size_t particle_index, const Vecd &particle_position) override; @@ -163,6 +149,12 @@ class CellLinkedList : public BaseCellLinkedList, public Mesh UnsignedInt getCellOffsetListSize() { return cell_offset_list_size_; }; DiscreteVariable *getParticleIndex() { return dv_particle_index_; }; DiscreteVariable *getCellOffset() { return dv_cell_offset_; }; + + /** split algorithm */; + template + void particle_for_split(const execution::SequencedPolicy &, const LocalDynamicsFunction &local_dynamics_function); + template + void particle_for_split(const execution::ParallelPolicy &, const LocalDynamicsFunction &local_dynamics_function); }; template <> @@ -172,7 +164,7 @@ class RefinedMesh : public CellLinkedList RefinedMesh(BoundingBox tentative_bounds, CellLinkedList &coarse_mesh, BaseParticles &base_particles, SPHAdaptation &sph_adaptation) : CellLinkedList(tentative_bounds, 0.5 * coarse_mesh.GridSpacing(), - base_particles, sph_adaptation) {}; + base_particles, sph_adaptation){}; }; /** @@ -184,8 +176,6 @@ class MultilevelCellLinkedList : public MultilevelMesh +void CellLinkedList::particle_for_split(const execution::SequencedPolicy &, const LocalDynamicsFunction &local_dynamics_function) +{ + // foward sweeping + for (size_t k = 0; k < number_of_split_cell_lists_; k++) + { + // get the corresponding 2D/3D split cell index (m, n) + // e.g., for k = 0, split_cell_index = (0,0), for k = 3, split_cell_index = (1,0), etc. + const Arrayi split_cell_index = transfer1DtoMeshIndex(3 * Arrayi::Ones(), k); + // get the number of cells belonging to the split cell k + // i_max = (M - m - 1) / 3 + 1, j_max = (N - n - 1) / 3 + 1 + // e.g. all_cells = (M,N) = (6, 9), (m, n) = (1, 1), then i_max = 2, j_max = 3 + const Arrayi all_cells_k = (all_cells_ - split_cell_index - Arrayi::Ones()) / 3 + Arrayi::Ones(); + const size_t number_of_cells = all_cells_k.prod(); // i_max * j_max + + // looping over all cells in the split cell k + for (size_t l = 0; l < number_of_cells; l++) + { + // get the 2D/3D cell index of the l-th cell in the split cell k + // (i , j) = (m + 3 * (l / j_max), n + 3 * l % i_max) + // e.g. all_cells = (M,N) = (6, 9), (m, n) = (1, 1), l = 0, then (i, j) = (1, 1) + // l = 1, then (i, j) = (1, 4), l = 3, then (i, j) = (4, 1), etc. + const Arrayi cell_index = split_cell_index + 3 * transfer1DtoMeshIndex(all_cells_k, l); + // get the list of particles in the cell (i, j) + const ConcurrentIndexVector &cell_list = getCellDataList(cell_index_lists_, cell_index); + // looping over all particles in the cell (i, j) + for (const size_t index_i : cell_list) + { + local_dynamics_function(index_i); + } + } + } + + // backward sweeping + for (size_t k = number_of_split_cell_lists_; k != 0; --k) + { + const Arrayi split_cell_index = transfer1DtoMeshIndex(3 * Arrayi::Ones(), k - 1); + const Arrayi all_cells_k = (all_cells_ - split_cell_index - Arrayi::Ones()) / 3 + Arrayi::Ones(); + const size_t number_of_cells = all_cells_k.prod(); + + for (size_t l = 0; l < number_of_cells; l++) + { + const Arrayi cell_index = split_cell_index + 3 * transfer1DtoMeshIndex(all_cells_k, l); + const ConcurrentIndexVector &cell_list = getCellDataList(cell_index_lists_, cell_index); + for (size_t i = cell_list.size(); i != 0; --i) + { + local_dynamics_function(cell_list[i - 1]); + } + } + } +} +//=================================================================================================// +template +void CellLinkedList::particle_for_split(const execution::ParallelPolicy &, const LocalDynamicsFunction &local_dynamics_function) +{ + // foward sweeping + for (size_t k = 0; k < number_of_split_cell_lists_; k++) + { + const Arrayi split_cell_index = transfer1DtoMeshIndex(3 * Arrayi::Ones(), k); + const Arrayi all_cells_k = (all_cells_ - split_cell_index - Arrayi::Ones()) / 3 + Arrayi::Ones(); + const size_t number_of_cells = all_cells_k.prod(); + + parallel_for( + IndexRange(0, number_of_cells), + [&](const IndexRange &r) + { + for (size_t l = r.begin(); l < r.end(); ++l) + { + const Arrayi cell_index = split_cell_index + 3 * transfer1DtoMeshIndex(all_cells_k, l); + const ConcurrentIndexVector &cell_list = getCellDataList(cell_index_lists_, cell_index); + for (const size_t index_i : cell_list) + { + local_dynamics_function(index_i); + } + } + }, + ap); + } + + // backward sweeping + for (size_t k = number_of_split_cell_lists_; k != 0; --k) + { + const Arrayi split_cell_index = transfer1DtoMeshIndex(3 * Arrayi::Ones(), k - 1); + const Arrayi all_cells_k = (all_cells_ - split_cell_index - Arrayi::Ones()) / 3 + Arrayi::Ones(); + const size_t number_of_cells = all_cells_k.prod(); + + parallel_for( + IndexRange(0, number_of_cells), + [&](const IndexRange &r) + { + for (size_t l = r.begin(); l < r.end(); ++l) + { + const Arrayi cell_index = split_cell_index + 3 * transfer1DtoMeshIndex(all_cells_k, l); + const ConcurrentIndexVector &cell_list = getCellDataList(cell_index_lists_, cell_index); + for (size_t i = cell_list.size(); i != 0; --i) + { + local_dynamics_function(cell_list[i - 1]); + } + } + }, + ap); + } +} +//=================================================================================================// } // namespace SPH diff --git a/src/shared/particle_dynamics/dynamics_algorithms.h b/src/shared/particle_dynamics/dynamics_algorithms.h index 9f3ae94645..b925ea4165 100644 --- a/src/shared/particle_dynamics/dynamics_algorithms.h +++ b/src/shared/particle_dynamics/dynamics_algorithms.h @@ -52,6 +52,7 @@ #include "base_local_dynamics.h" #include "base_particle_dynamics.h" +#include "cell_linked_list.hpp" #include "particle_iterators.h" #include @@ -198,28 +199,25 @@ class InteractionSplit : public BaseInteractionDynamics - InteractionSplit(Args &&... args) + explicit InteractionSplit(Args &&...args) : BaseInteractionDynamics(std::forward(args)...), real_body_(DynamicCast(this, this->getSPHBody())), - split_cell_lists_(*real_body_.getCellLinkedList().getSplitCellLists()) + cell_linked_list_(DynamicCast(this, real_body_.getCellLinkedList())) { - real_body_.getCellLinkedList().setUseSplitCellLists(); static_assert(!has_initialize::value && !has_update::value, "LocalDynamicsType does not fulfill InteractionSplit requirements"); }; - virtual ~InteractionSplit(){}; /** run the main interaction step between particles. */ - virtual void runMainStep(Real dt) override + void runMainStep(Real dt) override { - particle_for(ExecutionPolicy(), - split_cell_lists_, - [&](size_t i) { this->interaction(i, dt * 0.5); }); + cell_linked_list_.particle_for_split(ExecutionPolicy(), [&](size_t i) + { this->interaction(i, dt * 0.5); }); } }; diff --git a/src/shared/particle_dynamics/particle_iterators.h b/src/shared/particle_dynamics/particle_iterators.h index 982a3df6fe..013e8c790e 100644 --- a/src/shared/particle_dynamics/particle_iterators.h +++ b/src/shared/particle_dynamics/particle_iterators.h @@ -164,86 +164,6 @@ inline void particle_for(const ParallelPolicy &par, const DataListsInCells &body }, ap); }; -/** - * Splitting algorithm (for sequential and parallel computing). - */ -template -inline void particle_for(const SequencedPolicy &seq, const SplitCellLists &split_cell_lists, - const LocalDynamicsFunction &local_dynamics_function) -{ - // forward sweeping - for (size_t k = 0; k != split_cell_lists.size(); ++k) - { - const ConcurrentCellLists &cell_lists = split_cell_lists[k]; - for (size_t l = 0; l != cell_lists.size(); ++l) - { - const ConcurrentIndexVector &particle_indexes = *cell_lists[l]; - for (size_t i = 0; i != particle_indexes.size(); ++i) - { - local_dynamics_function(particle_indexes[i]); - } - } - } - - // backward sweeping - for (size_t k = split_cell_lists.size(); k != 0; --k) - { - const ConcurrentCellLists &cell_lists = split_cell_lists[k - 1]; - for (size_t l = 0; l != cell_lists.size(); ++l) - { - const ConcurrentIndexVector &particle_indexes = *cell_lists[l]; - for (size_t i = particle_indexes.size(); i != 0; --i) - { - local_dynamics_function(particle_indexes[i - 1]); - } - } - } -} - -template -inline void particle_for(const ParallelPolicy &par, const SplitCellLists &split_cell_lists, - const LocalDynamicsFunction &local_dynamics_function) -{ - // forward sweeping - for (size_t k = 0; k != split_cell_lists.size(); ++k) - { - const ConcurrentCellLists &cell_lists = split_cell_lists[k]; - parallel_for( - IndexRange(0, cell_lists.size()), - [&](const IndexRange &r) - { - for (size_t l = r.begin(); l < r.end(); ++l) - { - const ConcurrentIndexVector &particle_indexes = *cell_lists[l]; - for (size_t i = 0; i < particle_indexes.size(); ++i) - { - local_dynamics_function(particle_indexes[i]); - } - } - }, - ap); - } - - // backward sweeping - for (size_t k = split_cell_lists.size(); k != 0; --k) - { - const ConcurrentCellLists &cell_lists = split_cell_lists[k - 1]; - parallel_for( - IndexRange(0, cell_lists.size()), - [&](const IndexRange &r) - { - for (size_t l = r.begin(); l < r.end(); ++l) - { - const ConcurrentIndexVector &particle_indexes = *cell_lists[l]; - for (size_t i = particle_indexes.size(); i != 0; --i) - { - local_dynamics_function(particle_indexes[i - 1]); - } - } - }, - ap); - } -} template diff --git a/tests/2d_examples/test_2d_three_ring_impact/test_2d_three_ring_impact.cpp b/tests/2d_examples/test_2d_three_ring_impact/test_2d_three_ring_impact.cpp index a029c4ca01..506444c249 100644 --- a/tests/2d_examples/test_2d_three_ring_impact/test_2d_three_ring_impact.cpp +++ b/tests/2d_examples/test_2d_three_ring_impact/test_2d_three_ring_impact.cpp @@ -299,7 +299,7 @@ void three_ring_impact(int resolution_factor_l, int resolution_factor_m, int res { Vecd *pos = particles->getVariableDataByName("Position"); for (size_t index_i = 0; index_i < particles->TotalRealParticles(); ++index_i) - if (std::isnan(pos[index_i][0]) || std::isnan(pos[index_i][1]) || std::isnan(pos[index_i][2])) + if (std::isnan(pos[index_i][0]) || std::isnan(pos[index_i][1])) throw std::runtime_error("position has become nan"); }; diff --git a/tests/unit_tests_src/for_2D_build/meshes/CMakeLists.txt b/tests/unit_tests_src/for_2D_build/meshes/CMakeLists.txt new file mode 100644 index 0000000000..8eb174fa72 --- /dev/null +++ b/tests/unit_tests_src/for_2D_build/meshes/CMakeLists.txt @@ -0,0 +1,7 @@ +SUBDIRLIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR}) + +foreach(subdir ${SUBDIRS}) + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}/CMakeLists.txt) + add_subdirectory(${subdir}) + endif() +endforeach() \ No newline at end of file diff --git a/tests/unit_tests_src/for_2D_build/meshes/test_2d_particle_for_split/CMakeLists.txt b/tests/unit_tests_src/for_2D_build/meshes/test_2d_particle_for_split/CMakeLists.txt new file mode 100644 index 0000000000..c5b091dac7 --- /dev/null +++ b/tests/unit_tests_src/for_2D_build/meshes/test_2d_particle_for_split/CMakeLists.txt @@ -0,0 +1,15 @@ +STRING( REGEX REPLACE ".*/(.*)" "\\1" CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} ) +PROJECT("${CURRENT_FOLDER}") + +SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) +SET(EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}/bin/") +SET(BUILD_INPUT_PATH "${EXECUTABLE_OUTPUT_PATH}/input") +SET(BUILD_RELOAD_PATH "${EXECUTABLE_OUTPUT_PATH}/reload") + +aux_source_directory(. DIR_SRCS) +ADD_EXECUTABLE(${PROJECT_NAME} ${EXECUTABLE_OUTPUT_PATH} ${DIR_SRCS}) +target_link_libraries(${PROJECT_NAME} sphinxsys_2d GTest::gtest GTest::gtest_main) +set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}") + +add_test(NAME ${PROJECT_NAME} COMMAND ${PROJECT_NAME} + WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) diff --git a/tests/unit_tests_src/for_2D_build/meshes/test_2d_particle_for_split/test_particle_for_split.cpp b/tests/unit_tests_src/for_2D_build/meshes/test_2d_particle_for_split/test_particle_for_split.cpp new file mode 100644 index 0000000000..e0eb37daa0 --- /dev/null +++ b/tests/unit_tests_src/for_2D_build/meshes/test_2d_particle_for_split/test_particle_for_split.cpp @@ -0,0 +1,64 @@ +#include "sphinxsys.h" +#include + +using namespace SPH; + +TEST(test_meshes, split_for) +{ + Real length = 10; + Real dp = 1; + + MultiPolygon shape; + shape.addABox(Transform(0.5 * length * Vec2d::Ones()), 0.5 * length * Vec2d::Ones(), ShapeBooleanOps::add); + auto polygon_shape = makeShared(shape, "PolygonShape"); + + BoundingBox bb_system = polygon_shape->getBounds(); + + SPHSystem system(bb_system, dp); + + SolidBody body(system, polygon_shape); + body.defineMaterial(); + body.generateParticles(); + auto &particles = body.getBaseParticles(); + const auto pos = particles.registerStateVariable("Position"); + auto quantity = particles.registerStateVariable("Quantity", [&](size_t i) -> Real + { return pos[i].norm(); }); + + InnerRelation inner(body); + + body.updateCellLinkedList(); + inner.updateConfiguration(); + + auto interaction = [&](size_t index_i) + { + const auto &configuration = inner.inner_configuration_; + const auto &neighborhood = configuration[index_i]; + for (size_t n = 0; n < neighborhood.current_size_; n++) + { + size_t q_ij = quantity[index_i] - quantity[neighborhood.j_[n]]; + quantity[index_i] += 0.5 * q_ij; + quantity[neighborhood.j_[n]] -= 0.5 * q_ij; + } + }; + + auto &cell_linked_list = *dynamic_cast(&body.getCellLinkedList()); + + // run the interaction in sequenced policy + cell_linked_list.particle_for_split(execution::SequencedPolicy(), interaction); + // record the result + auto q_seq = quantity; + + // reset the value + for (size_t i = 0; i < particles.TotalRealParticles(); i++) + { + quantity[i] = pos[i].norm(); + } + // run the interaction in parallel policy + cell_linked_list.particle_for_split(execution::ParallelPolicy(), interaction); + + // check the result + for (size_t i = 0; i < particles.TotalRealParticles(); i++) + { + ASSERT_EQ(q_seq[i], quantity[i]); + } +} \ No newline at end of file diff --git a/tests/unit_tests_src/for_3D_build/meshes/CMakeLists.txt b/tests/unit_tests_src/for_3D_build/meshes/CMakeLists.txt new file mode 100644 index 0000000000..8eb174fa72 --- /dev/null +++ b/tests/unit_tests_src/for_3D_build/meshes/CMakeLists.txt @@ -0,0 +1,7 @@ +SUBDIRLIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR}) + +foreach(subdir ${SUBDIRS}) + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}/CMakeLists.txt) + add_subdirectory(${subdir}) + endif() +endforeach() \ No newline at end of file diff --git a/tests/unit_tests_src/for_3D_build/meshes/test_3d_particle_for_split/CMakeLists.txt b/tests/unit_tests_src/for_3D_build/meshes/test_3d_particle_for_split/CMakeLists.txt new file mode 100644 index 0000000000..d9a298a2e7 --- /dev/null +++ b/tests/unit_tests_src/for_3D_build/meshes/test_3d_particle_for_split/CMakeLists.txt @@ -0,0 +1,16 @@ +STRING( REGEX REPLACE ".*/(.*)" "\\1" CURRENT_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} ) +PROJECT("${CURRENT_FOLDER}") + +SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) +SET(EXECUTABLE_OUTPUT_PATH "${PROJECT_BINARY_DIR}/bin/") +SET(BUILD_INPUT_PATH "${EXECUTABLE_OUTPUT_PATH}/input") +SET(BUILD_RELOAD_PATH "${EXECUTABLE_OUTPUT_PATH}/reload") + +aux_source_directory(. DIR_SRCS) +ADD_EXECUTABLE(${PROJECT_NAME} ${EXECUTABLE_OUTPUT_PATH} ${DIR_SRCS}) +target_link_libraries(${PROJECT_NAME} sphinxsys_3d GTest::gtest GTest::gtest_main) +set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${EXECUTABLE_OUTPUT_PATH}") + +add_test(NAME ${PROJECT_NAME}_particle_relaxation + COMMAND ${PROJECT_NAME} --relax=true + WORKING_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}) diff --git a/tests/unit_tests_src/for_3D_build/meshes/test_3d_particle_for_split/test_particle_for_split.cpp b/tests/unit_tests_src/for_3D_build/meshes/test_3d_particle_for_split/test_particle_for_split.cpp new file mode 100644 index 0000000000..ef4c9264e4 --- /dev/null +++ b/tests/unit_tests_src/for_3D_build/meshes/test_3d_particle_for_split/test_particle_for_split.cpp @@ -0,0 +1,62 @@ +#include "sphinxsys.h" +#include + +using namespace SPH; + +TEST(test_meshes, split_for) +{ + Real length = 10; + Real dp = 1; + + auto shape = makeShared(0.5 * length * Vec3d::Ones(), "Shape"); + + BoundingBox bb_system = shape->getBounds(); + + SPHSystem system(bb_system, dp); + + SolidBody body(system, shape); + body.defineMaterial(); + body.generateParticles(); + auto &particles = body.getBaseParticles(); + const auto pos = particles.registerStateVariable("Position"); + auto quantity = particles.registerStateVariable("Quantity", [&](size_t i) -> Real + { return pos[i].norm(); }); + + InnerRelation inner(body); + + body.updateCellLinkedList(); + inner.updateConfiguration(); + + auto interaction = [&](size_t index_i) + { + const auto &configuration = inner.inner_configuration_; + const auto &neighborhood = configuration[index_i]; + for (size_t n = 0; n < neighborhood.current_size_; n++) + { + size_t q_ij = quantity[index_i] - quantity[neighborhood.j_[n]]; + quantity[index_i] += 0.5 * q_ij; + quantity[neighborhood.j_[n]] -= 0.5 * q_ij; + } + }; + + auto &cell_linked_list = *dynamic_cast(&body.getCellLinkedList()); + + // run the interaction in sequenced policy + cell_linked_list.particle_for_split(execution::SequencedPolicy(), interaction); + // record the result + auto q_seq = quantity; + + // reset the value + for (size_t i = 0; i < particles.TotalRealParticles(); i++) + { + quantity[i] = pos[i].norm(); + } + // run the interaction in parallel policy + cell_linked_list.particle_for_split(execution::ParallelPolicy(), interaction); + + // check the result + for (size_t i = 0; i < particles.TotalRealParticles(); i++) + { + ASSERT_EQ(q_seq[i], quantity[i]); + } +} \ No newline at end of file