diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b8c614501053c27cd48de4a096aa3cb1578f3e7c..dcc1ddb15f35def818cdc0bd318c4af1f05db1ec 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,7 +36,8 @@ if ( CUDA_ON_BACKEND STREQUAL "HIP" AND HIP_FOUND ) hip_add_executable(numerics ${OPENFPM_INIT_FILE} ${CUDA_SOURCES} - OdeIntegrators/tests/OdeIntegratores_base_tests.cpp + OdeIntegrators/tests/OdeIntegratores_base_tests.cpp + OdeIntegrators/tests/OdeIntegrator_grid_tests.cpp DCPSE/DCPSE_op/tests/DCPSE_op_subset_test.cpp DCPSE/DCPSE_op/tests/DCPSE_op_test_base_tests FiniteDifference/FD_Solver_test.cpp @@ -66,7 +67,7 @@ if ( CUDA_ON_BACKEND STREQUAL "HIP" AND HIP_FOUND ) # BoundaryConditions/tests/method_of_images_cylinder_unit_test.cpp # level_set/closest_point/closest_point_unit_tests.cpp level_set/redistancing_Sussman/tests/redistancingSussman_fast_unit_test.cpp - level_set/redistancing_Sussman/tests/help_functions_unit_test.cpp +# level_set/redistancing_Sussman/tests/help_functions_unit_test.cpp level_set/redistancing_Sussman/tests/narrowBand_unit_test.cpp # level_set/redistancing_Sussman/tests/redistancingSussman_unit_test.cpp # level_set/redistancing_Sussman/tests/convergence_test.cpp @@ -77,6 +78,7 @@ else() add_executable(numerics ${OPENFPM_INIT_FILE} ${CUDA_SOURCES} OdeIntegrators/tests/OdeIntegratores_base_tests.cpp + OdeIntegrators/tests/OdeIntegrator_grid_tests.cpp DCPSE/DCPSE_op/tests/DCPSE_op_subset_test.cpp DCPSE/DCPSE_op/tests/DCPSE_op_test_base_tests FiniteDifference/FD_Solver_test.cpp @@ -103,14 +105,14 @@ else() Operators/Vector/vector_dist_operators_unit_tests.cpp Operators/Vector/vector_dist_operators_apply_kernel_unit_tests.cpp ../../src/lib/pdata.cpp + DCPSE/DCPSE_op/tests/DCPSE_op_Surface_tests.cpp # BoundaryConditions/tests/method_of_images_cylinder_unit_test.cpp # level_set/closest_point/closest_point_unit_tests.cpp level_set/redistancing_Sussman/tests/redistancingSussman_fast_unit_test.cpp - level_set/redistancing_Sussman/tests/help_functions_unit_test.cpp +# level_set/redistancing_Sussman/tests/help_functions_unit_test.cpp level_set/redistancing_Sussman/tests/narrowBand_unit_test.cpp # level_set/redistancing_Sussman/tests/redistancingSussman_unit_test.cpp # level_set/redistancing_Sussman/tests/convergence_test.cpp - DCPSE/DCPSE_op/tests/DCPSE_op_Surface_tests.cpp ) set_property(TARGET numerics PROPERTY CUDA_ARCHITECTURES OFF) @@ -162,6 +164,8 @@ target_include_directories (numerics PUBLIC ${HDF5_ROOT}/include) target_include_directories (numerics PUBLIC ${LIBHILBERT_INCLUDE_DIRS}) target_include_directories (numerics PUBLIC ${Boost_INCLUDE_DIRS}) target_include_directories (numerics PUBLIC ${Vc_INCLUDE_DIR}) +target_include_directories (numerics PUBLIC ${BLITZ_ROOT}/include) +target_include_directories (numerics PUBLIC ${ALGOIM_ROOT}/include) target_include_directories (numerics PUBLIC ${ALPAKA_ROOT}/include) target_include_directories (numerics PUBLIC ${MPI_C_INCLUDE_DIRS}) if(EIGEN3_FOUND) @@ -350,6 +354,10 @@ install(FILES DMatrix/EMatrix.hpp DESTINATION openfpm_numerics/include/DMatrix COMPONENT OpenFPM) +install(FILES level_set/closest_point/closest_point.hpp + DESTINATION openfpm_numerics/include/level_set/closest_point + COMPONENT OpenFPM) + #if(BUILD_TESTING) # add_executable(particle_test test.cu) diff --git a/src/FiniteDifference/FD_expressions.hpp b/src/FiniteDifference/FD_expressions.hpp index 89b6b822c12b92dc33f9fb7b2d1ac56e6d8b3db6..d3499a027662ae44904351175ba406cd8c918f11 100644 --- a/src/FiniteDifference/FD_expressions.hpp +++ b/src/FiniteDifference/FD_expressions.hpp @@ -8,9 +8,34 @@ #ifndef FD_EXPRESSIONS_HPP_ #define FD_EXPRESSIONS_HPP_ +template<typename T, typename Sfinae = void> +struct has_getGrid: std::false_type {}; + +template<typename T> +struct has_getGrid<T, typename Void<decltype(std::declval<T>().getGrid())>::type > : std::true_type +{}; + namespace FD { + template<bool cond, typename exp1, typename exp2> + struct first_or_second + { + static auto getGrid(const exp1 & o1, const exp2 & o2) -> decltype(o2.getGrid()) + { + return o2.getGrid(); + } + }; + + template<typename exp1, typename exp2> + struct first_or_second<true,exp1,exp2> + { + static auto getGrid(const exp1 & o1, const exp2 & o2) -> decltype(o1.getGrid()) + { + return o1.getGrid(); + } + }; + constexpr int NORM_EXPRESSION = 0; constexpr int STAG_EXPRESSION = 1; constexpr int GRID_COMP = 2; @@ -26,22 +51,22 @@ namespace FD struct grid_dist_expression_value_impl_func_scal { template<unsigned int prp, typename base_type, typename gtype> - static void inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, base_type & inte_out, int & c, int comp) + static void inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, base_type & inte_out, int & c) { if (c_where[i] != c_o1[i]) { int sign = (c_where[i] > c_o1[i])?1:-1; - grid_dist_expression_value_impl_func_scal<i-1>::template inte<prp,base_type>(g,k,c_where,c_o1,inte_out,c,comp); + grid_dist_expression_value_impl_func_scal<i-1>::template inte<prp,base_type>(g,k,c_where,c_o1,inte_out,c); long int x0 = k.getKeyRef().get(i); k.getKeyRef().set_d(i, x0 + sign); - grid_dist_expression_value_impl_func_scal<i-1>::template inte<prp,base_type>(g,k,c_where,c_o1,inte_out,c,comp); + grid_dist_expression_value_impl_func_scal<i-1>::template inte<prp,base_type>(g,k,c_where,c_o1,inte_out,c); k.getKeyRef().set_d(i, x0); } else { - grid_dist_expression_value_impl_func_scal<i-1>::template inte<prp,base_type>(g,k,c_where,c_o1,inte_out,c,comp); + grid_dist_expression_value_impl_func_scal<i-1>::template inte<prp,base_type>(g,k,c_where,c_o1,inte_out,c); } } }; @@ -50,7 +75,7 @@ namespace FD struct grid_dist_expression_value_impl_func_scal<0> { template<unsigned int prp, typename base_type, typename gtype> - static void inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, base_type & inte_out , int & c , int comp) + static void inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, base_type & inte_out , int & c) { if (c_where[0] != c_o1[0]) { @@ -91,12 +116,37 @@ namespace FD return inte; } + template<unsigned int prp, typename gtype> + static base_type inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1) + { + int c = 0; + base_type inte = 0; + + grid_dist_expression_value_impl_func_scal<gtype::dims-1>::template inte<prp,base_type>(g,k,c_where,c_o1,inte,c); + + inte /= c; + + return inte; + } + + template<unsigned int prp, typename gtype> + static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k) + { + return g.template getProp<prp>(k); + } + template<unsigned int prp, typename gtype> static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k, int comp) { return g.template getProp<prp>(k); } + template<unsigned int prp, typename gtype> + static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k) -> decltype(g.template getProp<prp>(k)) + { + return g.template getProp<prp>(k); + } + template<unsigned int prp, typename gtype> static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k, int comp) -> decltype(g.template getProp<prp>(k)) { @@ -109,7 +159,7 @@ namespace FD struct grid_dist_expression_value_impl_func_vec { template<unsigned int prp, typename base_type, typename gtype> - static void inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, base_type & inte_out, int & c, int comp) + static void inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, base_type & inte_out, int & c, const int (& comp)[1]) { if (c_where[i] != c_o1[i]) { @@ -133,24 +183,24 @@ namespace FD struct grid_dist_expression_value_impl_func_vec<0> { template<unsigned int prp, typename base_type, typename gtype> - static void inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, base_type & inte_out , int & c , int comp) + static void inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, base_type & inte_out , int & c , const int (& comp)[1]) { if (c_where[0] != c_o1[0]) { int sign = (c_where[0] > c_o1[0])?1:-1; - inte_out += g.template getProp<prp>(k)[comp]; + inte_out += g.template getProp<prp>(k)[comp[0]]; long int x0 = k.getKeyRef().get(0); k.getKeyRef().set_d(0, x0 + sign); - inte_out += g.template getProp<prp>(k)[comp]; + inte_out += g.template getProp<prp>(k)[comp[0]]; k.getKeyRef().set_d(0, x0); c += 2; } else { - inte_out += g.template getProp<prp>(k)[comp]; + inte_out += g.template getProp<prp>(k)[comp[0]]; c += 1; } } @@ -162,7 +212,7 @@ namespace FD typedef base_type type; template<unsigned int prp, typename gtype> - static base_type inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, int comp) + static base_type inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, const int (& comp)[1]) { int c = 0; base_type inte = 0; @@ -178,15 +228,142 @@ namespace FD } template<unsigned int prp, typename gtype> - static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k, int comp) + static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k) + { + printf("Error wrong expression please check the components"); + return g.template getProp<prp>(k)[0]; + } + + template<unsigned int prp, typename gtype> + static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k, const int (& comp)[1]) + { + return g.template getProp<prp>(k)[comp[0]]; + } + + template<unsigned int prp, typename gtype> + static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k) -> decltype(g.template getProp<prp>(k)[0]) + { + printf("Error wrong expression please check the components"); + return g.template getProp<prp>(k)[0]; + } + + template<unsigned int prp, typename gtype> + static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k, const int (& comp)[1]) -> decltype(g.template getProp<prp>(k)[comp[0]]) + { + return g.template getProp<prp>(k)[comp[0]]; + } + }; + + + + + template<typename base_type, unsigned int N1,unsigned int N2> + struct grid_dist_expression_value_impl<base_type[N1][N2]> + { + typedef base_type type; + + template<unsigned int prp, typename gtype> + static base_type inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, const int (& comp)[2]) + { + int c = 0; + base_type inte = 0; + + grid_dist_expression_value_impl_func_vec<gtype::dims-1>::template inte<prp,base_type>(g,k,c_where,c_o1,inte,c,comp); + + if (c != 0) + {inte /= c;} + else + {inte = g.template getProp<prp>(k)[comp[0]][comp[1]];} + + return inte; + } + + template<unsigned int prp, typename gtype> + static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k) + { + printf("Error wrong expression please check the components"); + return g.template getProp<prp>(k)[0][0]; + } + + template<unsigned int prp, typename gtype> + static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k, const int (& comp)[2]) + { + return g.template getProp<prp>(k)[comp[0]][comp[1]]; + } + + template<unsigned int prp, typename gtype> + static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k) -> decltype(g.template getProp<prp>(k)[0][0]) + { + printf("Error wrong expression please check the components"); + return g.template getProp<prp>(k)[0][0]; + } + + template<unsigned int prp, typename gtype> + static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k, const int (& comp)[2]) -> decltype(g.template getProp<prp>(k)[0][0]) + { + return g.template getProp<prp>(k)[comp[0]][comp[1]]; + } + }; + + template<typename base_type, unsigned int N1,unsigned int N2, unsigned int N3> + struct grid_dist_expression_value_impl<base_type[N1][N2][N3]> + { + typedef base_type type; + + template<unsigned int prp, typename gtype> + static base_type inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, const int (& comp)[3]) + { + int c = 0; + base_type inte = 0; + + grid_dist_expression_value_impl_func_vec<gtype::dims-1>::template inte<prp,base_type>(g,k,c_where,c_o1,inte,c,comp); + + if (c != 0) + {inte /= c;} + else + {inte = g.template getProp<prp>(k)[comp[0]][comp[1]][comp[2]];} + + return inte; + } + + template<unsigned int prp, typename gtype> + static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k) + { + printf("Error wrong expression please check the components"); + return g.template getProp<prp>(k)[0][0][0]; + } + + template<unsigned int prp, typename gtype> + static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k, const int (& comp)[2]) + { + printf("Error wrong expression please check the components"); + return g.template getProp<prp>(k)[0][comp[0]][comp[1]]; + } + + template<unsigned int prp, typename gtype> + static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k, const int (& comp)[3]) + { + return g.template getProp<prp>(k)[comp[0]][comp[1]][comp[2]]; + } + + template<unsigned int prp, typename gtype> + static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k) -> decltype(g.template getProp<prp>(k)[0][0][0]) + { + printf("Error wrong expression please check the components"); + return g.template getProp<prp>(k)[0][0][0]; + } + + template<unsigned int prp, typename gtype> + static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k, const int (& comp)[2]) -> decltype(g.template getProp<prp>(k)[0][0][0]) { - return g.template getProp<prp>(k)[comp]; + printf("Error wrong expression please check the components"); + return g.template getProp<prp>(k)[0][comp[1]][comp[0]]; } template<unsigned int prp, typename gtype> - static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k, int comp) -> decltype(g.template getProp<prp>(k)[comp]) + static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k, const int (& comp)[3]) -> decltype(g.template getProp<prp>(k)[0][0][0]) { - return g.template getProp<prp>(k)[comp]; + return g.template getProp<prp>(k)[comp[0]][comp[1]][comp[2]]; } }; @@ -196,8 +373,10 @@ namespace FD typedef base_type type; template<unsigned int prp, typename gtype> - static base_type inte(gtype & g, grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, int comp) + static base_type inte(gtype & g, const grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1) { + int comp[1]; + printf("Error wrong expression please check the components"); int c = 0; base_type inte = 0; @@ -206,21 +385,53 @@ namespace FD if (c != 0) {inte /= c;} else - {inte = g.template getProp<prp>(k)[comp];} + {inte = g.template getProp<prp>(k)[0];} return inte; } template<unsigned int prp, typename gtype> - static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k, int comp) + static base_type inte(gtype & g, const grid_dist_key_dx<gtype::dims> & k, comb<gtype::dims> & c_where, comb<gtype::dims> & c_o1, const int (& comp)[1]) { - return g.template getProp<prp>(k)[comp]; + int c = 0; + base_type inte = 0; + + grid_dist_key_dx<gtype::dims> k_ = k; + + grid_dist_expression_value_impl_func_vec<gtype::dims-1>::template inte<prp,base_type>(g,k_,c_where,c_o1,inte,c,comp); + + if (c != 0) + {inte /= c;} + else + {inte = g.template getProp<prp>(k)[comp[0]];} + + return inte; } template<unsigned int prp, typename gtype> - static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k, int comp) -> decltype(g.template getProp<prp>(k)[comp]) + static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k) { - return g.template getProp<prp>(k)[comp]; + printf("Error wrong expression please check the components"); + return g.template getProp<prp>(k)[0]; + } + + template<unsigned int prp, typename gtype> + static base_type value_n(gtype & g, const grid_dist_key_dx<gtype::dims> & k, const int (& comp)[1]) + { + return g.template getProp<prp>(k)[comp[0]]; + } + + template<unsigned int prp, typename gtype> + static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k, const int (& comp)[1]) -> decltype(g.template getProp<prp>(k)[comp[0]]) + { + return g.template getProp<prp>(k)[comp[0]]; + } + + template<unsigned int prp, typename gtype> + static auto value_ref(gtype & g, const grid_dist_key_dx<gtype::dims> & k) -> decltype(g.template getProp<prp>(k)[0]) + { + printf("Error wrong expression please check the components"); + return g.template getProp<prp>(k)[0]; } }; @@ -369,10 +580,22 @@ namespace FD * \return the result of the expression * */ - inline auto value(const grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where, int comp = 0) const -> decltype(grid_dist_expression_value_impl<type_proc>::template value_n<prp>(g,k,comp)) + inline auto value(const grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where) const -> decltype(grid_dist_expression_value_impl<type_proc>::template value_n<prp>(g,k)) + { + return grid_dist_expression_value_impl<type_proc>::template value_n<prp>(g,k); + } + + /*! \brief Evaluate the expression + * + * \param k where to evaluate the expression + * + * \return the result of the expression + * + */ + template<unsigned int nc> + inline auto value(const grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where, const int (& comp)[nc]) const -> decltype(grid_dist_expression_value_impl<type_proc>::template value_n<prp>(g,k,comp)) { return grid_dist_expression_value_impl<type_proc>::template value_n<prp>(g,k,comp); -// return g.template getProp<prp>(k); } /*! \brief Evaluate the expression @@ -382,10 +605,22 @@ namespace FD * \return the result of the expression * */ - inline auto value_ref(const grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where, int comp = 0) const -> decltype(grid_dist_expression_value_impl<type_proc>::template value_ref<prp>(g,k,comp)) + inline auto value_ref(const grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where) const -> decltype(grid_dist_expression_value_impl<type_proc>::template value_ref<prp>(g,k)) + { + return grid_dist_expression_value_impl<type_proc>::template value_ref<prp>(g,k); + } + + /*! \brief Evaluate the expression + * + * \param k where to evaluate the expression + * + * \return the result of the expression + * + */ + template<unsigned int nc> + inline auto value_ref(const grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where, const int (& comp)[nc]) const -> decltype(grid_dist_expression_value_impl<type_proc>::template value_ref<prp>(g,k,comp)) { return grid_dist_expression_value_impl<type_proc>::template value_ref<prp>(g,k,comp); -// return g.template getProp<prp>(k); } /*! \brief Fill the grid property with the evaluated expression @@ -395,12 +630,12 @@ namespace FD * \return itself * */ - template<unsigned int prp2> grid & operator=(const grid_dist_expression<prp2,grid,NORM_EXPRESSION> & g_exp) + template<unsigned int prp2,typename grid_type> grid & operator=(const grid_dist_expression<prp2,grid_type,NORM_EXPRESSION> & g_exp) { g_exp.init(); comb<grid::dims> s_pos; - s_pos.zero; + s_pos.zero(); auto it = g.getDomainIterator(); @@ -575,7 +810,21 @@ namespace FD * \return the result of the expression * */ - inline auto value_ref(const grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where,int comp = 0) const -> decltype(grid_dist_expression_value_impl<type_proc>::template value_ref<prp>(g,k,comp)) + inline auto value_ref(const grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where) const -> decltype(grid_dist_expression_value_impl<type_proc>::template value_ref<prp>(g,k)) + { + return grid_dist_expression_value_impl<type_proc>::template value_ref<prp>(g,k); + //return g.template getProp<prp>(k); + } + + /*! \brief Evaluate the expression + * + * \param k where to evaluate the expression + * + * \return the result of the expression + * + */ + template<unsigned int nc> + inline auto value_ref(const grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where, const int (& comp)[nc]) const -> decltype(grid_dist_expression_value_impl<type_proc>::template value_ref<prp>(g,k,comp)) { return grid_dist_expression_value_impl<type_proc>::template value_ref<prp>(g,k,comp); //return g.template getProp<prp>(k); @@ -588,11 +837,27 @@ namespace FD * \return the result of the expression * */ - inline auto value(grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where, int comp = 0) const -> decltype(grid_dist_expression_value_impl<type_proc>::template inte<prp>(g,k,c_where,c_where,comp)) + inline auto value(grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where) const -> decltype(grid_dist_expression_value_impl<type_proc>::template inte<prp>(g,k,c_where,c_where)) { - comb<grid::dims> c_o1 = g.getStagPositions()[prp].get(comp); + comb<grid::dims> c_o1 = g.getStagPositions()[prp].get(0); + + return grid_dist_expression_value_impl<type_proc>::template inte<prp>(g,k,c_where,c_o1); + } + + /*! \brief Evaluate the expression + * + * \param k where to evaluate the expression + * + * \return the result of the expression + * + */ + template<unsigned int nc> + inline auto value(const grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where, const int (& comp)[nc]) const -> decltype(grid_dist_expression_value_impl<type_proc>::template inte<prp>(g,k,c_where,c_where,comp)) + { + comb<grid::dims> c_o1 = g.getStagPositions()[prp].get(comp[0]); return grid_dist_expression_value_impl<type_proc>::template inte<prp>(g,k,c_where,c_o1,comp); +// return g.template getProp<prp>(k); } /*! \brief Fill the grid property with the evaluated expression @@ -1136,9 +1401,9 @@ namespace FD * \return the grid * */ - gtype & getGrid() + auto getGrid() -> decltype(first_or_second<has_getGrid<exp1>::value,exp1,exp2>::getGrid(o1,o2)) { - return o1.getGrid(); + return first_or_second<has_getGrid<exp1>::value,exp1,exp2>::getGrid(o1,o2); } /*! \brief Return the grid on which is acting @@ -1148,9 +1413,9 @@ namespace FD * \return the grid * */ - const gtype & getGrid() const + auto getGrid() const -> decltype(first_or_second<has_getGrid<exp1>::value,exp1,exp2>::getGrid(o1,o2)) { - return o1.getGrid(); + return first_or_second<has_getGrid<exp1>::value,exp1,exp2>::getGrid(o1,o2); } template<typename Sys_eqs, typename gmap_type, typename unordered_map_type> @@ -1220,17 +1485,27 @@ namespace FD template<typename exp_type> static int get(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[1]) { + printf("ERROR: Slicer, the expression is incorrect, please check it\n"); return 0; } + template<typename exp_type> + static auto get_ref(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[1]) -> decltype(o1.value_ref(key,c_where)) + { + printf("ERROR: Slicer, the expression is incorrect, please check it\n"); + return o1.value_ref(key,c_where); + } + template<unsigned int prop, typename exp_type, typename grid_type> inline static void assign(exp_type & o1, grid_type & g, const grid_dist_key_dx<exp_type::gtype::dims> & key) { + printf("ERROR: Slicer, the expression is incorrect, please check it\n"); } template<unsigned int prop, typename grid_type> inline static void assign_double(double d, grid_type & g, const grid_dist_key_dx<grid_type::dims> & key) { + printf("ERROR: Slicer, the expression is incorrect, please check it\n"); } }; @@ -1238,15 +1513,15 @@ namespace FD struct get_grid_dist_expression_op<1,true> { template<typename exp_type> - static auto get(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[1]) -> decltype(o1.value(key,c_where,comp[0])) + static auto get(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[1]) -> decltype(o1.value(key,c_where,comp) ) { - return o1.value(key,c_where,comp[0]); + return o1.value(key,c_where,comp); } template<typename exp_type> - static auto get_ref(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[1]) -> decltype(o1.value_ref(key,c_where,comp[0])) + static auto get_ref(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[1]) -> decltype(o1.value_ref(key,c_where,comp) ) { - return o1.value_ref(key,c_where,comp[0]); + return o1.value_ref(key,c_where,comp); } template<unsigned int prop,typename exp_type, typename grid_type> @@ -1262,19 +1537,57 @@ namespace FD } }; + template<> + struct get_grid_dist_expression_op<2,false> + { + template<typename exp_type> + static auto get(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[2]) -> decltype(o1.value(key,c_where,comp) ) + { + printf("ERROR: Slicer, the expression is incorrect, please check it\n"); + return o1.value(key,c_where,comp); + } + + template<typename exp_type> + static auto get_ref(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[2]) -> decltype(o1.value_ref(key,c_where,comp) ) + { + printf("ERROR: Slicer, the expression is incorrect, please check it\n"); + return o1.value_ref(key,c_where,comp); + } + + template<unsigned int prop,typename exp_type, typename grid_type> + inline static void assign(exp_type & o1, grid_type & g, grid_dist_key_dx<grid_type::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[2]) + { + printf("ERROR: Slicer, the expression is incorrect, please check it\n"); + pos_or_propL<grid_type,prop>::value(g,key)[comp[0]][comp[1]] = o1.value(key,c_where); + } + + template<unsigned int prop, typename grid_type> + inline static void assign_double(double d, grid_type & g, const grid_dist_key_dx<grid_type::dims> & key, const int (& comp)[2]) + { + printf("ERROR: Slicer, the expression is incorrect, please check it\n"); + pos_or_propL<grid_type,prop>::value(g,key)[comp[0]][comp[1]] = d; + } + }; + template<> struct get_grid_dist_expression_op<2,true> { template<typename exp_type> - static auto get(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[2]) -> decltype(o1.value(key,c_where)[0][0]) + static auto get(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[2]) -> decltype(o1.value(key,c_where,comp) ) + { + return o1.value(key,c_where,comp); + } + + template<typename exp_type> + static auto get_ref(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[2]) -> decltype(o1.value_ref(key,c_where,comp) ) { - return o1.value(key)[comp[0]][comp[1]]; + return o1.value_ref(key,c_where,comp); } template<unsigned int prop,typename exp_type, typename grid_type> - inline static void assign(exp_type & o1, grid_type & g, const grid_dist_key_dx<grid_type::dims> & key, const int (& comp)[2]) + inline static void assign(exp_type & o1, grid_type & g, grid_dist_key_dx<grid_type::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[2]) { - pos_or_propL<grid_type,prop>::value(g,key)[comp[0]][comp[1]] = o1.value(key); + pos_or_propL<grid_type,prop>::value(g,key)[comp[0]][comp[1]] = o1.value(key,c_where); } template<unsigned int prop, typename grid_type> @@ -1284,6 +1597,34 @@ namespace FD } }; + template<> + struct get_grid_dist_expression_op<3,true> + { + template<typename exp_type> + static auto get(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[3]) -> decltype(o1.value(key,c_where,comp) ) + { + return o1.value(key,c_where,comp); + } + + template<typename exp_type> + static auto get_ref(exp_type & o1, grid_dist_key_dx<exp_type::gtype::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[3]) -> decltype(o1.value_ref(key,c_where,comp) ) + { + return o1.value_ref(key,c_where,comp); + } + + template<unsigned int prop,typename exp_type, typename grid_type> + inline static void assign(exp_type & o1, grid_type & g, grid_dist_key_dx<grid_type::dims> & key, comb<exp_type::gtype::dims> & c_where, const int (& comp)[3]) + { + pos_or_propL<grid_type,prop>::value(g,key)[comp[0]][comp[1]][comp[2]] = o1.value(key,c_where); + } + + template<unsigned int prop, typename grid_type> + inline static void assign_double(double d, grid_type & g, const grid_dist_key_dx<grid_type::dims> & key, const int (& comp)[3]) + { + pos_or_propL<grid_type,prop>::value(g,key)[comp[0]][comp[1]][comp[2]] = d; + } + }; + /*! \brief it take an expression and create the negatove of this expression * * @@ -1307,7 +1648,7 @@ namespace FD public: - typedef std::false_type is_ker; + typedef std::false_type is_ker; typedef typename exp1::gtype gtype; @@ -1423,7 +1764,7 @@ namespace FD o1.template value_nz<Sys_eqs>(g_map,key,gs,spacing,cols,coeff,comp_ + var_id + comp[0],c_where); } - inline grid_dist_expression_op<exp1,boost::mpl::int_<2>,g_comp> operator[](int comp_) + inline grid_dist_expression_op<exp1,boost::mpl::int_<n+1>,g_comp> operator[](int comp_) { int comp_n[n+1]; @@ -1431,7 +1772,7 @@ namespace FD {comp_n[i] = comp[i];} comp_n[n] = comp_; - grid_dist_expression_op<exp1,boost::mpl::int_<2>,g_comp> v_exp(o1,comp_n,var_id); + grid_dist_expression_op<exp1,boost::mpl::int_<n+1>,g_comp> v_exp(o1,comp_n,var_id); return v_exp; } @@ -1452,7 +1793,7 @@ namespace FD * \return itself * */ - template<unsigned int prp2, unsigned int impl> gtype & operator=(const grid_dist_expression<prp2,gtype,impl> & v_exp) + template<unsigned int prp2, typename gtype2, unsigned int impl> gtype & operator=(const grid_dist_expression<prp2,gtype2,impl> & v_exp) { v_exp.init(); @@ -1460,11 +1801,14 @@ namespace FD auto it = g.getDomainIterator(); + comb<gtype::dims> c_where; + c_where.zero(); + while (it.isNext()) { auto key = it.get(); - get_grid_dist_expression_op<n,n == rank_gen<property_act>::type::value>::template assign<exp1::prop>(v_exp,g,key,comp); + get_grid_dist_expression_op<n,n == rank_gen<property_act>::type::value>::template assign<exp1::prop>(v_exp,g,key,c_where,comp); ++it; } @@ -1561,8 +1905,368 @@ namespace FD return exp_g; } + +////// Specialization for temporal FD_expressions + + template<unsigned int dim> + struct gdb_ext_plus_g_info + { + grid_sm<dim,void> & ginfo_v; + + openfpm::vector<GBoxes<dim>> & gdb_ext; + + bool operator==(const gdb_ext_plus_g_info & tmp) + { + bool is_equal = gdb_ext.size() == tmp.gdb_ext.size(); + + for (int i = 0 ; i < gdb_ext.size() ; i++) + { + is_equal &= gdb_ext.get(i) == tmp.gdb_ext.get(i); + } + + is_equal &= ginfo_v == tmp.ginfo_v; + + return is_equal; + } + }; + + template<unsigned int dim> + class grid_dist_expression_iterator_to_make_algebra_work + { + //! Grid informations object without type + grid_sm<dim,void> & ginfo_v; + + //! The grid + openfpm::vector<grid_cpu<dim,aggregate<double>>> & loc_grid; + + openfpm::vector<GBoxes<dim>> & gdb_ext; + + typedef grid_cpu<dim,aggregate<double>> device_grid; + + public: + + static constexpr unsigned int dims = dim; + + grid_dist_expression_iterator_to_make_algebra_work(openfpm::vector<grid_cpu<dim,aggregate<double>>> & loc_grid, + openfpm::vector<GBoxes<dim>> & gdb_ext, + grid_sm<dim,void> & ginfo_v) + :loc_grid(loc_grid),gdb_ext(gdb_ext),ginfo_v(ginfo_v) + {} + + gdb_ext_plus_g_info<dim> size() + { + return gdb_ext_plus_g_info<dim>{ginfo_v,gdb_ext}; + } + + //Need more treatment for staggered (c_where based on exp) + template<unsigned int prp> + inline auto get(grid_dist_key_dx<dim> & key) -> decltype(loc_grid.get(key.getSub()).template get<0>(key.getKey())) + { + return loc_grid.get(key.getSub()).template get<0>(key.getKey()); + } + + + /*! \brief Return the number of local grid + * + * \return the number of local grid + * + */ + size_t getN_loc_grid() const + { + return loc_grid.size(); + } + + /*! \brief Get the i sub-domain grid + * + * \param i sub-domain + * + * \return local grid + * + */ + device_grid & get_loc_grid(size_t i) + { + return loc_grid.get(i); + } + + /*! \brief Get the i sub-domain grid + * + * \param i sub-domain + * + * \return local grid + * + */ + const device_grid & get_loc_grid(size_t i) const + { + return loc_grid.get(i); + } + + /*! \brief Get an object containing the grid informations without type + * + * \return an information object about this grid + * + */ + const grid_sm<dim,void> & getGridInfoVoid() const + { + return ginfo_v; + } + + /*! \brief It return the informations about the local grids + * + * \return The information about the local grids + * + */ + const openfpm::vector<GBoxes<device_grid::dims>> & getLocalGridsInfo() const + { + return gdb_ext; + } + + void resize(const gdb_ext_plus_g_info<dim> & input) + { + size_t Nloc_grid = input.gdb_ext.size(); + + loc_grid.resize(Nloc_grid); + + for (int i = 0 ; i < Nloc_grid; i++) + { + size_t sz[dim]; + + for (int j = 0 ; j < dim ; j++) {sz[j] = input.gdb_ext.get(i).GDbox.getKP2().get(j) + 1;} + + loc_grid.get(i).resize(sz); + } + + gdb_ext = input.gdb_ext; + ginfo_v = input.ginfo_v; + } + + grid_dist_iterator<dim,device_grid, + decltype(device_grid::type_of_subiterator()),FREE> getIterator() + { + grid_key_dx<dim> stop(ginfo_v.getSize()); + grid_key_dx<dim> one; + one.one(); + stop = stop - one; + + grid_dist_iterator<dim,device_grid, + decltype(device_grid::type_of_subiterator()), + FREE> it(loc_grid,gdb_ext,stop); + + return it; + } + }; + + template<typename patches> + struct grid_patches + { + static constexpr unsigned int dims = patches::dims; + + openfpm::vector<patches> loc_grid; + }; + + /*! \brief Main class that encapsulate a grid properties operand to be used for expressions construction + * + * \tparam prp property involved + * \tparam grid involved + * + */ + template<unsigned int dim> + class grid_dist_expression<0,grid_patches<grid_cpu<dim,aggregate<double>>>,NORM_EXPRESSION> + { + //! The grid + mutable grid_patches<grid_cpu<dim,aggregate<double>>> data; + + mutable openfpm::vector<GBoxes<dim>> gdb_ext; + + //! Grid informations object without type + mutable grid_sm<dim,void> ginfo_v; + + typedef double type_proc; + + template<typename super_general> + void operator_equal(super_general & g_exp) + { + g_exp.init(); + + resize(g_exp.getGrid()); + + comb<dim> s_pos; + s_pos.zero(); + + auto it = this->getVector().getIterator(); + + while (it.isNext()) + { + auto key = it.get(); + + data.loc_grid.get(key.getSub()).template get<0>(key.getKey()) = g_exp.value(key,s_pos); + + ++it; + } + } + + public: + + static constexpr unsigned int dims = dim; + + typedef grid_dist_key_dx<dim,grid_key_dx<dim>> index_type; + + //! The type of the internal grid + typedef grid_dist_expression_iterator_to_make_algebra_work<dim> gtype; + + //! Property id of the point + static const unsigned int prop = 0; + + grid_dist_expression() + {} + + gdb_ext_plus_g_info<dim> size() const + { + return gdb_ext_plus_g_info<dim>{ginfo_v,gdb_ext}; + } + + //! constructor for an external grid + template<typename grid> + grid_dist_expression(grid & g) + { + resize(g); + } + + template<typename grid> + void resize(grid & g) + { + size_t Nloc_grid = g.getN_loc_grid(); + + data.loc_grid.resize(Nloc_grid); + + for (int i = 0 ; i < Nloc_grid; i++) + { + data.loc_grid.get(i).resize(g.get_loc_grid(i).getGrid().getSize()); + } + + gdb_ext = g.getLocalGridsInfo(); + ginfo_v = g.getGridInfoVoid(); + } + + grid_dist_expression_iterator_to_make_algebra_work<dim> getVector() const + { + return grid_dist_expression_iterator_to_make_algebra_work<dim>(data.loc_grid,gdb_ext,ginfo_v); + } + + /*! \brief Return the grid on which is acting + * + * It return the grid used in getVExpr, to get this object + * + * \return the grid + * + */ + grid_dist_expression_iterator_to_make_algebra_work<dim> getGrid() + { + return getVector(); + } + + /*! \brief Return the grid on which is acting + * + * It return the grid used in getVExpr, to get this object + * + * \return the grid + * + */ + const grid_dist_expression_iterator_to_make_algebra_work<dim> getGrid() const + { + return getVector(); + } + + /*! \brief This function must be called before value + * + * it initialize the expression if needed + * + */ + inline void init() const + {} + + /*! \brief Evaluate the expression + * + * \param k where to evaluate the expression + * + * \return the result of the expression + * + */ + inline double value(const grid_dist_key_dx<dim> & k, const comb<dim> & c_where = comb<dim>()) const + { + return data.loc_grid.get(k.getSub()).template get<0>(k.getKey()); + } + + /*! \brief Evaluate the expression + * + * \param k where to evaluate the expression + * + * \return the result of the expression + * + */ + // template<unsigned int nc> + // inline auto value(const grid_dist_key_dx<grid::dims> & k, comb<grid::dims> & c_where, const int (& comp)[nc]) const -> decltype(grid_dist_expression_value_impl<type_proc>::template value_n<prp>(g,k,comp)) + // { + // return loc_grid.get(k.getSub()).template get<0>(k.getKey()); + // } + + /*! \brief Evaluate the expression + * + * \param k where to evaluate the expression + * + * \return the result of the expression + * + */ + inline double & value_ref(const grid_dist_key_dx<dim> & k, const comb<dim> & c_where = comb<dim>()) + { + return data.loc_grid.get(k.getSub()).template get<0>(k.getKey()); + } + + /*! \brief Fill the grid property with the evaluated expression + * + * \param v_exp expression to evaluate + * + * \return itself + * + */ + template<unsigned int prp2, typename grid> const grid & operator=(const grid_dist_expression<prp2,grid,NORM_EXPRESSION> & g_exp) + { + operator_equal(g_exp); + + return g_exp.getGrid(); + } + + /*! \brief Fill the grid property with the evaluated expression + * + * \param v_exp expression to evaluate + * + * \return itself + * + */ + template<typename exp1, typename exp2, typename op> auto operator=(const grid_dist_expression_op<exp1,exp2,op> & g_exp) -> decltype(g_exp.getGrid()) + { + operator_equal(g_exp); + + return g_exp.getGrid(); + } + + //Need more treatment for staggered (c_where based on exp) + inline double get(grid_dist_key_dx<dim> & key) + { + comb<dim> c_where; + c_where.zero(); + return this->value(key,c_where); + } + + int isConstant(){ + return false; + } + }; + }; + +template<unsigned int dim, typename T> using texp_g = FD::grid_dist_expression<0,FD::grid_patches<grid_cpu<dim,aggregate<T>>>,FD::NORM_EXPRESSION>; + /* \brief sum two distributed grid expression * * \param ga grid expression one diff --git a/src/FiniteDifference/FD_op_Tests.cpp b/src/FiniteDifference/FD_op_Tests.cpp index 1ca8c556f380f1c168086a55a22fafbb80e60e25..a5abf939a9e9b5a9b786696519acc21e8fa8091e 100644 --- a/src/FiniteDifference/FD_op_Tests.cpp +++ b/src/FiniteDifference/FD_op_Tests.cpp @@ -114,6 +114,105 @@ BOOST_AUTO_TEST_SUITE(fd_op_suite_tests) } + BOOST_AUTO_TEST_CASE(fd_op_tests_vec_mat) { + size_t edgeSemiSize = 80; + const size_t sz[2] = {2 * edgeSemiSize+1, 2 * edgeSemiSize+1}; + Box<2, double> box({0, 0}, {2 * M_PI, 2 * M_PI}); + periodicity<2> bc({NON_PERIODIC, NON_PERIODIC}); + double spacing[2]; + spacing[0] = 2 * M_PI / (sz[0] - 1); + spacing[1] = 2 * M_PI / (sz[1] - 1); + Ghost<2, long int> ghost(1); + + //std::cout << "Spacing: " << spacing[0] << " " << spacing[1] << std::endl; + + grid_dist_id<2, double, aggregate<double, double, double,double[2],double[2][2],double[2][2][2]>> domain(sz, box,ghost,bc); + + BOOST_TEST_MESSAGE("Init domain..."); + auto it = domain.getDomainIterator(); + while (it.isNext()) + { + auto key_l = it.get(); + auto key = it.getGKey(key_l); + mem_id i = key.get(0); + double x = i * spacing[0]; + mem_id j = key.get(1); + double y = j * spacing[1]; + // Here fill the function value P + domain.template getProp<3>(key_l)[0] = sin(x); + domain.template getProp<3>(key_l)[1] = sin(x); + domain.template getProp<1>(key_l) = 0; + // Here fill the validation value for Df/Dx in property 3 + + domain.template getProp<2>(key_l) = cos(x); + + ++it; + } + + domain.ghost_get<0,3>(); + + FD::Derivative_x Dx; + FD::Derivative_y Dy; + + auto v = FD::getV<1>(domain); + auto P = FD::getV<0>(domain); + + auto vec = FD::getV<3>(domain); + auto Mat = FD::getV<4>(domain); + auto Mat3 = FD::getV<5>(domain); + + Mat[0][1] = Dx(vec[0]); + + Mat[1][0] = vec[0]; + + domain.ghost_get<4>(); + + Mat[0][0] = Dx(Mat[1][0]); + Mat3[0][0][0] = Dx(vec[0]); + Mat3[0][1][0] = Dx(Mat[1][0]); + + auto it2 = domain.getDomainIterator(); + + double worst = 0.0; + + while (it2.isNext()) + { + auto p = it2.get(); + + if (fabs(domain.getProp<4>(p)[0][1] - domain.getProp<2>(p)) > worst) + { + worst = fabs(domain.getProp<4>(p)[0][1] - domain.getProp<2>(p)); + } + + if (fabs(domain.getProp<4>(p)[1][0] - domain.getProp<3>(p)[0]) > worst) + { + worst = fabs(domain.getProp<4>(p)[1][0] - domain.getProp<3>(p)[0]); + } + + if (fabs(domain.getProp<4>(p)[0][0] - domain.getProp<2>(p)) > worst) + { + worst = fabs(domain.getProp<4>(p)[0][0] - domain.getProp<2>(p)); + } + + + /////////////////////////// Mat 3 + + if (fabs(domain.getProp<5>(p)[0][0][0] - domain.getProp<2>(p)) > worst) + { + worst = fabs(domain.getProp<5>(p)[0][0][0] - domain.getProp<2>(p)); + } + + if (fabs(domain.getProp<5>(p)[0][1][0] - domain.getProp<2>(p)) > worst) + { + worst = fabs(domain.getProp<5>(p)[0][1][0] - domain.getProp<2>(p)); + } + + ++it2; + } + + BOOST_REQUIRE(worst < 0.003); + } + BOOST_AUTO_TEST_CASE(lalpacian_test) { size_t edgeSemiSize = 80; const size_t sz[2] = {2 * edgeSemiSize+1, 2 * edgeSemiSize+1}; diff --git a/src/FiniteDifference/Upwind_gradient.hpp b/src/FiniteDifference/Upwind_gradient.hpp index d52407779b452d6ab86a5cc0cef9ba069b16a70c..f6ad7ec3ff47e15fb83c29381ff71824c23bf979 100644 --- a/src/FiniteDifference/Upwind_gradient.hpp +++ b/src/FiniteDifference/Upwind_gradient.hpp @@ -27,12 +27,13 @@ #include "Grid/grid_dist_id.hpp" #include "FD_simple.hpp" #include "Eno_Weno.hpp" +#include "level_set/redistancing_Sussman/HelpFunctions.hpp" /**@brief Upwinding: For a specific dimension, from the forward and backward gradient find the upwind side. * * @param dplus: Gradient approximated using RHS neighbors. * @param dminus: Gradient approximated using LHS neighbors. - * @param sign: Sign of the velocity with which the wave front is moving. + * @param sign: Sign of current component of the wave front velocity. * @return Scalar upwind gradient approximation in the dimension given. */ template <typename field_type> @@ -50,14 +51,38 @@ static field_type upwinding(field_type dplus, field_type dminus, int sign) return grad_upwind; } +/**@brief Returns the sign of a scalar velocity field + * + * @tparam velocity_type Template type of velocity (scalar). + * @param v Velocity of type velocity_type. + * @param d Dimension. This is a dummy to simplify call in module #FD_upwind. + * @return Sign of velocity #v. + */ +template <typename velocity_type> +inline int get_sign_velocity(velocity_type v, size_t d) +{ + return sgn(v); +} + +/**@brief Returns the sign of one component in a vector velocity field + * + * @tparam velocity_type Template type of velocity (vector). + * @param v Velocity of type velocity_type. + * @param d Component of velocity vector for which sign should be returned. + * @return Sign of component d from velocity #v. + */ +template <typename velocity_type> +inline int get_sign_velocity(velocity_type v[], size_t d) +{ + return sgn(v[d]); +} /**@brief Get the upwind finite difference of a scalar property on the current grid node. * * @details Order of accuracy can be 1, 3 or 5. * * @tparam Field Size_t index of property for which the gradient should be computed. - * @tparam Sign Size_t index of property that contains the initial sign of that property for which the upwind FD - * should be computed. + * @tparam Velocity Size_t index of property that contains the velocity field. Can be scalar or vector field. * @tparam gridtype Type of input grid. * @tparam keytype Type of key variable. * @param grid Grid, on which the gradient should be computed. @@ -66,14 +91,16 @@ static field_type upwinding(field_type dplus, field_type dminus, int sign) * @param order Order of accuracy of the difference scheme. Can be 1, 3 or 5. * @return Upwind finite difference in one dimension of the property under index Field on the current node with index key. */ -template <size_t Field, size_t Sign, typename gridtype, typename keytype> +template <size_t Field, size_t Velocity, typename gridtype, typename keytype> auto FD_upwind(gridtype &grid, keytype &key, size_t d, size_t order) { // std::cout << boost::typeindex::type_id_with_cvr<std::decay_t<decltype(first_node)>>() << std::endl; typedef typename std::decay_t<decltype(grid.template get<Field>(key))> field_type; field_type dplus = 0.0, dminus = 0.0; - int sign_phi0 = grid.template get<Sign> (key); + + // Get the sign of the velocity for the current dimension + int sign_velocity = get_sign_velocity(grid.template get<Field>(key), d); switch(order) { @@ -98,7 +125,7 @@ auto FD_upwind(gridtype &grid, keytype &key, size_t d, size_t order) break; } - return upwinding(dplus, dminus, sign_phi0); + return upwinding(dplus, dminus, sign_velocity); } @@ -109,8 +136,7 @@ auto FD_upwind(gridtype &grid, keytype &key, size_t d, size_t order) * respectively, depending on the side of the border. * * @tparam Field Size_t index of property for which the gradient should be computed. - * @tparam Sign Size_t index of property that contains the initial sign of that property for which the upwind FD - * should be computed. + * @tparam Velocity Size_t index of property that contains the velocity field. Can be scalar or vector field. * @tparam Gradient Size_t index of property where the gradient result should be stored. * @tparam gridtype Type of input grid. * @param grid Grid, on which the gradient should be computed. @@ -119,11 +145,11 @@ auto FD_upwind(gridtype &grid, keytype &key, size_t d, size_t order) * @param order Size_t variable, order of accuracy the upwind FD scheme should have. Can be 1, 3 or 5. */ // Use upwinding for inner grid points and one sided backward / forward stencil at border (if one_sided_BC=true) -template <size_t Field, size_t Sign, size_t Gradient, typename gridtype> +template <size_t Field, size_t Velocity, size_t Gradient, typename gridtype> void upwind_gradient(gridtype & grid, const bool one_sided_BC, size_t order) { grid.template ghost_get<Field>(KEEP_PROPERTIES); - grid.template ghost_get<Sign>(KEEP_PROPERTIES); + grid.template ghost_get<Velocity>(KEEP_PROPERTIES); auto dom = grid.getDomainIterator(); @@ -140,13 +166,13 @@ void upwind_gradient(gridtype & grid, const bool one_sided_BC, size_t order) if (key_g.get(d) > 2 && key_g.get(d) < grid.size(d) - 3) // if point lays with min. 3 nodes distance to // boundary { - grid.template get<Gradient> (key) [d] = FD_upwind<Field, Sign>(grid, key, d, order); + grid.template get<Gradient> (key) [d] = FD_upwind<Field, Velocity>(grid, key, d, order); } // Grid nodes in stencil-wide vicinity to boundary else if (key_g.get(d) > 0 && key_g.get(d) < grid.size(d) - 1) // if point lays not on the grid boundary { - grid.template get<Gradient> (key) [d] = FD_upwind<Field, Sign>(grid, key, d, 1); + grid.template get<Gradient> (key) [d] = FD_upwind<Field, Velocity>(grid, key, d, 1); } else if (key_g.get(d) == 0) // if point lays at left boundary, use right sided kernel @@ -170,7 +196,7 @@ void upwind_gradient(gridtype & grid, const bool one_sided_BC, size_t order) auto key = dom.get(); for(size_t d = 0; d < gridtype::dims; d++) { - grid.template get<Gradient> (key) [d] = FD_upwind<Field, Sign>(grid, key, d, order); + grid.template get<Gradient> (key) [d] = FD_upwind<Field, Velocity>(grid, key, d, order); } ++dom; } @@ -207,17 +233,16 @@ static bool ghost_width_is_sufficient(gridtype & grid, size_t required_width) /**@brief Calls #upwind_gradient. Computes upwind gradient of desired order {1, 3, 5} for the whole n-dim grid. * * @tparam Field Size_t index of property for which the gradient should be computed. - * @tparam Sign Size_t index of property that contains the initial sign of that property for which the upwind FD - * should be computed / sign of the velocity. + * @tparam Velocity Size_t index of property that contains the velocity field. Can be scalar or vector field. * @tparam Gradient Size_t index of property where the upwind gradient result should be stored. * @tparam gridtype Type of input grid. * @param grid Grid, on which the gradient should be computed. */ -template <size_t Field_in, size_t Sign, size_t Gradient_out, typename gridtype> +template <size_t Field_in, size_t Velocity, size_t Gradient_out, typename gridtype> void get_upwind_gradient(gridtype & grid, const size_t order=5, const bool one_sided_BC=true) { grid.template ghost_get<Field_in>(); - grid.template ghost_get<Sign>(); + grid.template ghost_get<Velocity>(); if (!one_sided_BC) { @@ -241,13 +266,13 @@ void get_upwind_gradient(gridtype & grid, const size_t order=5, const bool one_s case 1: case 3: case 5: - upwind_gradient<Field_in, Sign, Gradient_out>(grid, one_sided_BC, order); + upwind_gradient<Field_in, Velocity, Gradient_out>(grid, one_sided_BC, order); break; default: auto &v_cl = create_vcluster(); if (v_cl.rank() == 0) std::cout << "Order of accuracy chosen not valid. Using default order 1." << std::endl; - upwind_gradient<Field_in, Sign, Gradient_out>(grid, one_sided_BC, 1); + upwind_gradient<Field_in, Velocity, Gradient_out>(grid, one_sided_BC, 1); break; } diff --git a/src/FiniteDifference/tests/Upwind_gradient_unit_test.cpp b/src/FiniteDifference/tests/Upwind_gradient_unit_test.cpp index f1c068d905e9dee21c34288cf8ddaf26e717857c..ccc34934302b451f7cf893d22bf7d4e4dc11220d 100644 --- a/src/FiniteDifference/tests/Upwind_gradient_unit_test.cpp +++ b/src/FiniteDifference/tests/Upwind_gradient_unit_test.cpp @@ -13,11 +13,11 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) const double EPSILON = 1e-14; - const size_t f_gaussian = 0; - const size_t Sign = 1; - const size_t df_gaussian = 2; - const size_t df_upwind = 3; - const size_t Error = 4; + const size_t F_GAUSSIAN = 0; + const size_t VELOCITY = 1; + const size_t dF_GAUSSIAN = 2; + const size_t dF_UPWIND = 3; + const size_t ERROR = 4; BOOST_AUTO_TEST_CASE(Upwind_gradient_order1_1D_test) { @@ -40,7 +40,7 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) const size_t sz[grid_dim] = {N}; grid_in_type g_dist(sz, box, ghost); - g_dist.setPropNames({"f_gaussian", "Sign", "df_gaussian", "df_upwind", "Error"}); + g_dist.setPropNames({"F_GAUSSIAN", "VELOCITY", "dF_GAUSSIAN", "dF_UPWIND", "ERROR"}); auto gdom = g_dist.getDomainGhostIterator(); while (gdom.isNext()) @@ -48,9 +48,9 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) auto key = gdom.get(); Point<grid_dim, double> p = g_dist.getPos(key); // Initialize grid and ghost with gaussian function - g_dist.getProp<f_gaussian>(key) = gaussian(p, mu, sigma); + g_dist.getProp<F_GAUSSIAN>(key) = gaussian(p, mu, sigma); // Initialize the sign of the gaussian function - g_dist.getProp<Sign>(key) = sgn(g_dist.getProp<f_gaussian>(key)); + g_dist.getProp<VELOCITY>(key) = sgn(g_dist.getProp<F_GAUSSIAN>(key)); ++gdom; } @@ -63,19 +63,19 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) for (int d = 0; d < grid_dim; d++) { // Analytical gradient - g_dist.getProp<df_gaussian>(key)[d] = hermite_polynomial(p.get(d), sigma, 1) * g_dist.getProp<f_gaussian>(key); + g_dist.getProp<dF_GAUSSIAN>(key)[d] = hermite_polynomial(p.get(d), sigma, 1) * g_dist.getProp<F_GAUSSIAN>(key); } ++dom; } // Upwind gradient with specific convergence order, not becoming one-sided at the boundary - get_upwind_gradient<f_gaussian, Sign, df_upwind>(g_dist, convergence_order, false); + get_upwind_gradient<F_GAUSSIAN, VELOCITY, dF_UPWIND>(g_dist, convergence_order, false); // Get the error between analytical and numerical solution - get_relative_error<df_upwind, df_gaussian, Error>(g_dist); + get_relative_error<dF_UPWIND, dF_GAUSSIAN, ERROR>(g_dist); LNorms<double> lNorms; - lNorms.get_l_norms_grid<Error>(g_dist); + lNorms.get_l_norms_grid<ERROR>(g_dist); if (N==32) BOOST_CHECK_MESSAGE(lNorms.l2 <= 0.38954184748195 + EPSILON, "Checking L2-norm upwind gradient " "order " + std::to_string @@ -105,7 +105,7 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) const size_t sz[grid_dim] = {N}; grid_in_type g_dist(sz, box, ghost); - g_dist.setPropNames({"f_gaussian", "Sign", "df_gaussian", "df_upwind", "Error"}); + g_dist.setPropNames({"F_GAUSSIAN", "VELOCITY", "dF_GAUSSIAN", "dF_UPWIND", "ERROR"}); auto gdom = g_dist.getDomainGhostIterator(); while (gdom.isNext()) @@ -113,9 +113,9 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) auto key = gdom.get(); Point<grid_dim, double> p = g_dist.getPos(key); // Initialize grid and ghost with gaussian function - g_dist.getProp<f_gaussian>(key) = gaussian(p, mu, sigma); + g_dist.getProp<F_GAUSSIAN>(key) = gaussian(p, mu, sigma); // Initialize the sign of the gaussian function - g_dist.getProp<Sign>(key) = sgn(g_dist.getProp<f_gaussian>(key)); + g_dist.getProp<VELOCITY>(key) = sgn(g_dist.getProp<F_GAUSSIAN>(key)); ++gdom; } @@ -128,19 +128,19 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) for (int d = 0; d < grid_dim; d++) { // Analytical gradient - g_dist.getProp<df_gaussian>(key)[d] = hermite_polynomial(p.get(d), sigma, 1) * g_dist.getProp<f_gaussian>(key); + g_dist.getProp<dF_GAUSSIAN>(key)[d] = hermite_polynomial(p.get(d), sigma, 1) * g_dist.getProp<F_GAUSSIAN>(key); } ++dom; } // Upwind gradient with specific convergence order, not becoming one-sided at the boundary - get_upwind_gradient<f_gaussian, Sign, df_upwind>(g_dist, convergence_order, false); + get_upwind_gradient<F_GAUSSIAN, VELOCITY, dF_UPWIND>(g_dist, convergence_order, false); // Get the error between analytical and numerical solution - get_relative_error<df_upwind, df_gaussian, Error>(g_dist); + get_relative_error<dF_UPWIND, dF_GAUSSIAN, ERROR>(g_dist); LNorms<double> lNorms; - lNorms.get_l_norms_grid<Error>(g_dist); + lNorms.get_l_norms_grid<ERROR>(g_dist); if (N==32) BOOST_CHECK_MESSAGE(lNorms.l2 <= 0.08667855716144 + EPSILON, "Checking L2-norm upwind gradient " "order " @@ -168,7 +168,7 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) const size_t sz[grid_dim] = {N}; grid_in_type g_dist(sz, box, ghost); - g_dist.setPropNames({"f_gaussian", "Sign", "df_gaussian", "df_upwind", "Error"}); + g_dist.setPropNames({"F_GAUSSIAN", "VELOCITY", "dF_GAUSSIAN", "dF_UPWIND", "ERROR"}); auto gdom = g_dist.getDomainGhostIterator(); while (gdom.isNext()) @@ -176,9 +176,9 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) auto key = gdom.get(); Point<grid_dim, double> p = g_dist.getPos(key); // Initialize grid and ghost with gaussian function - g_dist.getProp<f_gaussian>(key) = gaussian(p, mu, sigma); + g_dist.getProp<F_GAUSSIAN>(key) = gaussian(p, mu, sigma); // Initialize the sign of the gaussian function - g_dist.getProp<Sign>(key) = sgn(g_dist.getProp<f_gaussian>(key)); + g_dist.getProp<VELOCITY>(key) = sgn(g_dist.getProp<F_GAUSSIAN>(key)); ++gdom; } @@ -191,19 +191,19 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) for (int d = 0; d < grid_dim; d++) { // Analytical gradient - g_dist.getProp<df_gaussian>(key)[d] = hermite_polynomial(p.get(d), sigma, 1) * g_dist.getProp<f_gaussian>(key); + g_dist.getProp<dF_GAUSSIAN>(key)[d] = hermite_polynomial(p.get(d), sigma, 1) * g_dist.getProp<F_GAUSSIAN>(key); } ++dom; } // Upwind gradient with specific convergence order, not becoming one-sided at the boundary - get_upwind_gradient<f_gaussian, Sign, df_upwind>(g_dist, convergence_order, false); + get_upwind_gradient<F_GAUSSIAN, VELOCITY, dF_UPWIND>(g_dist, convergence_order, false); // Get the error between analytical and numerical solution - get_relative_error<df_upwind, df_gaussian, Error>(g_dist); + get_relative_error<dF_UPWIND, dF_GAUSSIAN, ERROR>(g_dist); LNorms<double> lNorms; - lNorms.get_l_norms_grid<Error>(g_dist); + lNorms.get_l_norms_grid<ERROR>(g_dist); if (N==32) BOOST_CHECK_MESSAGE(lNorms.l2 <= 0.03215172234342 + EPSILON, "Checking L2-norm upwind gradient " "order " @@ -229,7 +229,7 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) { const size_t sz[grid_dim] = {N, N, N}; grid_in_type g_dist(sz, box, ghost); - g_dist.setPropNames({"f_gaussian", "Sign", "df_gaussian", "df_upwind", "Error"}); + g_dist.setPropNames({"F_GAUSSIAN", "VELOCITY", "dF_GAUSSIAN", "dF_UPWIND", "ERROR"}); auto gdom = g_dist.getDomainGhostIterator(); while (gdom.isNext()) @@ -237,9 +237,9 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) auto key = gdom.get(); Point<grid_dim, double> p = g_dist.getPos(key); // Initialize grid and ghost with gaussian function - g_dist.getProp<f_gaussian>(key) = gaussian(p, mu, sigma); + g_dist.getProp<F_GAUSSIAN>(key) = gaussian(p, mu, sigma); // Initialize the sign of the gaussian function - g_dist.getProp<Sign>(key) = sgn(g_dist.getProp<f_gaussian>(key)); + g_dist.getProp<VELOCITY>(key) = sgn(g_dist.getProp<F_GAUSSIAN>(key)); ++gdom; } @@ -252,7 +252,7 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) for (int d = 0; d < grid_dim; d++) { // Analytical gradient - g_dist.getProp<df_gaussian>(key)[d] = hermite_polynomial(p.get(d), sigma, 1) * g_dist.getProp<f_gaussian>(key); + g_dist.getProp<dF_GAUSSIAN>(key)[d] = hermite_polynomial(p.get(d), sigma, 1) * g_dist.getProp<F_GAUSSIAN>(key); } ++dom; } @@ -260,12 +260,12 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) for (int convergence_order = 1; convergence_order <=5; convergence_order +=2 ) { // Upwind gradient with specific convergence order, not becoming one-sided at the boundary - get_upwind_gradient<f_gaussian, Sign, df_upwind>(g_dist, convergence_order, false); + get_upwind_gradient<F_GAUSSIAN, VELOCITY, dF_UPWIND>(g_dist, convergence_order, false); // Get the error between analytical and numerical solution - get_relative_error<df_upwind, df_gaussian, Error>(g_dist); + get_relative_error<dF_UPWIND, dF_GAUSSIAN, ERROR>(g_dist); LNorms<double> lNorms; - lNorms.get_l_norms_grid<Error>(g_dist); + lNorms.get_l_norms_grid<ERROR>(g_dist); if(N==32) { @@ -290,4 +290,94 @@ BOOST_AUTO_TEST_SUITE(UpwindGradientTestSuite) } } } + + BOOST_AUTO_TEST_CASE(Upwind_gradient_3D_vector_velocity_test) + { + { + const size_t grid_dim = 3; + const double box_lower = -1.0; + const double box_upper = 1.0; + Box<grid_dim, double> box({box_lower, box_lower, box_lower}, {box_upper, box_upper, box_upper}); + Ghost<grid_dim, long int> ghost(3); + typedef aggregate<double, double[grid_dim], Point<grid_dim, double>, Point<grid_dim, double>, double> props; + typedef grid_dist_id<grid_dim, double, props> grid_in_type; + + double mu = 0.5 * (box_upper - abs(box_lower)); + double sigma = 0.3 * (box_upper - box_lower); + + size_t N = 32; +// for(size_t N = 32; N <=256; N *=2) + { + const size_t sz[grid_dim] = {N, N, N}; + grid_in_type g_dist(sz, box, ghost); + g_dist.setPropNames({"F_GAUSSIAN", "Velocity", "dF_GAUSSIAN", "dF_UPWIND", "ERROR"}); + + auto gdom = g_dist.getDomainGhostIterator(); + while (gdom.isNext()) + { + auto key = gdom.get(); + Point<grid_dim, double> p = g_dist.getPos(key); + // Initialize grid and ghost with gaussian function + g_dist.getProp<F_GAUSSIAN>(key) = gaussian(p, mu, sigma); + ++gdom; + } + + auto dom = g_dist.getDomainIterator(); + while (dom.isNext()) + { + auto key = dom.get(); + Point<grid_dim, double> p = g_dist.getPos(key); + + for (int d = 0; d < grid_dim; d++) + { + // Analytical gradient + g_dist.getProp<dF_GAUSSIAN>(key)[d] = hermite_polynomial(p.get(d), sigma, 1) * g_dist.getProp<F_GAUSSIAN>(key); + // Initialize the velocity vector field + g_dist.getProp<VELOCITY>(key)[d] = g_dist.getProp<dF_GAUSSIAN>(key)[d]; + } + ++dom; + } + + for (int convergence_order = 1; convergence_order <=5; convergence_order +=2 ) + { + // Upwind gradient with specific convergence order, not becoming one-sided at the boundary + get_upwind_gradient<F_GAUSSIAN, VELOCITY, dF_UPWIND>(g_dist, convergence_order, false); + // Get the error between analytical and numerical solution + get_relative_error<dF_UPWIND, dF_GAUSSIAN, ERROR>(g_dist); + + LNorms<double> lNorms; + lNorms.get_l_norms_grid<ERROR>(g_dist); + + if(N==32) + { + switch(convergence_order) + { + case 1: + BOOST_CHECK_MESSAGE(lNorms.l2 <= 0.38954184748194 + EPSILON, "Checking L2-norm upwind" + " gradient with vector " + "velocity order " + + std::to_string(convergence_order)); + break; + case 3: + BOOST_CHECK_MESSAGE(lNorms.l2 <= 0.08667855716144 + EPSILON, "Checking L2-norm upwind" + " gradient with " + "vector velocity order " + + std::to_string(convergence_order)); + break; + case 5: + BOOST_CHECK_MESSAGE(lNorms.l2 <= 0.02285996528578 + EPSILON, "Checking L2-norm upwind" + " gradient with " + "vector velocity order " + + std::to_string(convergence_order)); + + break; + default: + std::cout << "Checking only implemented for convergence order 1, 3 and 5." << std::endl; + } + } + } + + } + } + } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/OdeIntegrators/OdeIntegrators.hpp b/src/OdeIntegrators/OdeIntegrators.hpp index 5296b2acee1d719d1495a296a963b28aa7b9807d..29334842ba485b5924a924c1eceb5a0f56d2e317 100644 --- a/src/OdeIntegrators/OdeIntegrators.hpp +++ b/src/OdeIntegrators/OdeIntegrators.hpp @@ -16,10 +16,12 @@ struct has_state_vector: std::false_type {}; template<typename T> struct has_state_vector<T, typename Void< typename T::is_state_vector>::type> : std::true_type {}; + + namespace boost{ template<class T,class Enabler=typename std::enable_if<has_state_vector<T>::value>::type> - inline size_t - size(const T& rng) + inline auto + size(const T& rng) -> decltype(rng.size()) { return rng.size(); } @@ -27,6 +29,7 @@ namespace boost{ #include <boost/numeric/odeint.hpp> #include "Operators/Vector/vector_dist_operators.hpp" +#include "FiniteDifference/FD_expressions.hpp" #include "OdeIntegrators/vector_algebra_ofp.hpp" #ifdef __NVCC__ @@ -102,6 +105,7 @@ struct state_type_1d_ofp{ state_type_1d_ofp(){ } typedef size_t size_type; + typedef size_t index_type; typedef int is_state_vector; aggregate<texp_v<double>> data; @@ -125,6 +129,7 @@ struct state_type_2d_ofp{ state_type_2d_ofp(){ } typedef size_t size_type; + typedef size_t index_type; typedef int is_state_vector; aggregate<texp_v<double>,texp_v<double>> data; @@ -149,6 +154,7 @@ struct state_type_3d_ofp{ state_type_3d_ofp(){ } typedef size_t size_type; + typedef size_t index_type; typedef int is_state_vector; aggregate<texp_v<double>,texp_v<double>,texp_v<double>> data; @@ -174,6 +180,7 @@ struct state_type_4d_ofp{ state_type_4d_ofp(){ } typedef size_t size_type; + typedef size_t index_type; typedef int is_state_vector; aggregate<texp_v<double>,texp_v<double>,texp_v<double>,texp_v<double>> data; @@ -200,6 +207,7 @@ struct state_type_5d_ofp{ state_type_5d_ofp(){ } typedef size_t size_type; + typedef size_t index_type; typedef int is_state_vector; aggregate<texp_v<double>,texp_v<double>,texp_v<double>,texp_v<double>,texp_v<double>> data; @@ -217,9 +225,49 @@ struct state_type_5d_ofp{ } }; +template<int counter, typename state_type, typename ... list> +struct state_type_ofpm_add_elements +{ +// typedef aggregate<list ..., texp_v<double>> one_more; + typedef typename state_type_ofpm_add_elements<counter-1,state_type, state_type,list ...>::type type; +}; + +template<typename state_type, typename ... list> +struct state_type_ofpm_add_elements<0,state_type,list ...> +{ + typedef aggregate<list ...> type; +}; + +template<int n_state, typename state_type> +struct state_type_ofpm_impl +{ + typedef FD::gdb_ext_plus_g_info<state_type::dims> size_type; + typedef typename state_type::index_type index_type; + typedef int is_state_vector; + + typedef typename state_type_ofpm_add_elements<n_state-1,state_type, state_type>::type type_data; + + type_data data; + + FD::gdb_ext_plus_g_info<state_type::dims> size() const + { + return data.template get<0>().size(); + } + + + void resize(const FD::gdb_ext_plus_g_info<state_type::dims> & rsz_obj) + { + // to fill + } +}; + + namespace boost { namespace numeric { namespace odeint { + + // FOR particles + template<> struct is_resizeable<state_type_1d_ofp> { typedef boost::true_type type; @@ -286,6 +334,98 @@ namespace boost { typedef double result_type; }; + // For GRIDs + + template<typename state_type> + struct is_resizeable<state_type_ofpm_impl<1,state_type> > { + typedef boost::true_type type; + static const bool value = type::value; + }; + + template<typename state_type> + struct is_resizeable<state_type_ofpm_impl<2,state_type> > { + typedef boost::true_type type; + static const bool value = type::value; + }; + + template<typename state_type> + struct is_resizeable<state_type_ofpm_impl<3,state_type> > { + typedef boost::true_type type; + static const bool value = type::value; + }; + + template<typename state_type> + struct is_resizeable<state_type_ofpm_impl<4,state_type> > { + typedef boost::true_type type; + static const bool value = type::value; + }; + + template<typename state_type> + struct is_resizeable<state_type_ofpm_impl<5,state_type> > { + typedef boost::true_type type; + static const bool value = type::value; + }; + +/* template<> + struct is_resizeable<state_type_2d_ofp> { + typedef boost::true_type type; + static const bool value = type::value; + }; + + template<> + struct is_resizeable<state_type_3d_ofp> { + typedef boost::true_type type; + static const bool value = type::value; + }; + template<> + struct is_resizeable<state_type_4d_ofp> { + typedef boost::true_type type; + static const bool value = type::value; + }; + template<> + struct is_resizeable<state_type_5d_ofp> { + typedef boost::true_type type; + static const bool value = type::value; + };*/ + + + +/* // template<unsigned int nprp, typename state_type> + struct vector_space_norm_inf<state_type_ofpm_impl<nprp,state_type>> + { + typedef double result_type; + };*/ + + template<typename state_type> + struct vector_space_norm_inf<state_type_ofpm_impl<1,state_type>> + { + typedef double result_type; + }; + + template<typename state_type> + struct vector_space_norm_inf<state_type_ofpm_impl<2,state_type>> + { + typedef double result_type; + }; + + template<typename state_type> + struct vector_space_norm_inf<state_type_ofpm_impl<3,state_type>> + { + typedef double result_type; + }; + + template<typename state_type> + struct vector_space_norm_inf<state_type_ofpm_impl<4,state_type>> + { + typedef double result_type; + }; + + template<typename state_type> + struct vector_space_norm_inf<state_type_ofpm_impl<5,state_type>> + { + typedef double result_type; + }; + } } } diff --git a/src/OdeIntegrators/tests/OdeIntegrator_grid_tests.cpp b/src/OdeIntegrators/tests/OdeIntegrator_grid_tests.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c99d6af656c3ddf866bc5a561a31950dc1ced4ed --- /dev/null +++ b/src/OdeIntegrators/tests/OdeIntegrator_grid_tests.cpp @@ -0,0 +1,577 @@ +// +// Created by foggia on 19th Jan 2022 +// It's a modification of Abhinav's test, adapted for grids +// + +#define BOOST_TEST_DYN_LINK + +#include <iostream> +#include <boost/test/unit_test.hpp> + +#include "config.h" +#include "Grid/grid_dist_id.hpp" +#include "OdeIntegrators/OdeIntegrators.hpp" +#include "OdeIntegrators/boost_vector_algebra_ofp.hpp" +#include "FiniteDifference/FD_op.hpp" +#include "util/util_debug.hpp" +#include "util/common.hpp" + +const double a = 2.8e-4; +const double b = 5e-3; +const double tau = .1; +const double k = .005; +const int dim = 2; + +void *gridGlobal; +typedef grid_dist_id<2,double,aggregate<double,double,double,double,double,double>> grid_type; + +// State types for systems with different number of ODEs +typedef state_type_ofpm_impl<1,texp_g<dim,double>> state_type_1ode; +typedef state_type_ofpm_impl<2,texp_g<dim,double>> state_type_2ode; +typedef state_type_ofpm_impl<3,texp_g<dim,double>> state_type_3ode; + +template<typename DX, typename DY> +struct Fitz { + + DX & ddx; + DY & ddy; + + //Constructor + Fitz(DX & m_ddx, DY & m_ddy) : + ddx(m_ddx), + ddy(m_ddy) {} + + void operator()(const state_type_2ode & x, + state_type_2ode & dxdt, + const double t) const { + + grid_type & temp = *(grid_type *) gridGlobal; + auto u{FD::getV<4>(temp)}; + auto v{FD::getV<5>(temp)}; + u = x.data.get<0>(); + v = x.data.get<1>(); + + temp.ghost_get<4,5>(); + dxdt.data.get<0>() = ddx(u) + ddy(u) + (1.0); + dxdt.data.get<1>() = ddx(v) + ddy(v) + (2.0); + + // One point stay fixed + + auto key2 = temp.getDomainIterator().get(); + + if (create_vcluster().rank() == 0) { + dxdt.data.get<0>().value_ref(key2) = 0.0; + dxdt.data.get<1>().value_ref(key2) = 0.0; + } + + double u_max{0.0}; + double v_max{0.0}; + + auto it = temp.getDomainIterator(); + + while (it.isNext()) + { + auto key = it.get(); + + if (u_max < dxdt.data.get<0>().value(key)) + u_max = dxdt.data.get<0>().value(key); + + if (v_max < dxdt.data.get<1>().value(key)) + v_max = dxdt.data.get<1>().value(key); + + ++it; + } + } +}; + +void Exponential_struct_ofp2(const state_type_3ode & x, + state_type_3ode & dxdt, + const double t) { + + // sytem: dx1/dt = x1 --> solution: x1(t) = exp(t) + // sytem: dx2/dt = 2*x2 --> solution: x2(t) = exp(2t) + dxdt.data.get<0>() = x.data.get<0>(); + dxdt.data.get<1>() = 2.0 * x.data.get<1>(); + dxdt.data.get<2>() = x.data.get<0>(); +} + + +void Exponential(const state_type_1ode & x, + state_type_1ode & dxdt, + const double t) { + + // sytem: dx/dt = x --> solution: x(t) = exp(t) + dxdt = x; +} + +// void sigmoid(const state_type_1ode & x, +// state_type_1ode & dxdt, +// const double t) { +// dxdt = x * (1.0 - x); +// } + +BOOST_AUTO_TEST_SUITE(odeInt_grid_tests) + +BOOST_AUTO_TEST_CASE(odeint_grid_test_exponential) { + + size_t edgeSemiSize{40}; + const size_t sz[dim] = {edgeSemiSize,edgeSemiSize}; + Box<dim,double> box{{0.0,0.0}, {1.0,1.0}}; + periodicity<dim> bc{{NON_PERIODIC,NON_PERIODIC}}; + double spacing[dim]; + spacing[0] = 1.0 / (sz[0] - 1); + spacing[1] = 1.0 / (sz[1] - 1); + Ghost<dim,long int> ghost{2}; + BOOST_TEST_MESSAGE("Test: exponential"); + BOOST_TEST_MESSAGE("Init grid_dist_id ..."); + + grid_dist_id<dim,double,aggregate<double,double,double>> grid{sz,box,ghost,bc}; + + auto it{grid.getDomainIterator()}; + while (it.isNext()) { + auto key = it.get(); + grid.template get<0>(key) = std::exp(0); // Initial state + grid.template get<1>(key) = std::exp(0.4); // Analytical solution + ++it; + } + grid.ghost_get<0>(); + + auto Init{FD::getV<0>(grid)}; // Initial state + auto Sol{FD::getV<1>(grid)}; // Analytical solution + auto OdeSol{FD::getV<2>(grid)}; // Numerical solution + + state_type_1ode x0; + x0.data.get<0>() = Init; + + double t{0.0}; + double tf{0.4}; + const double dt{0.1}; + + boost::numeric::odeint::runge_kutta4<state_type_1ode,double, + state_type_1ode,double, + boost::numeric::odeint::vector_space_algebra_ofp> rk4; // Time integrator + size_t steps{boost::numeric::odeint::integrate_const(rk4,Exponential,x0,0.0,tf,dt)}; + + OdeSol = x0.data.get<0>(); // Numerical solution + + // Error + auto it2{grid.getDomainIterator()}; + double worst{0.0}; + while (it2.isNext()) { + auto p{it2.get()}; + if (std::fabs(grid.template get<1>(p) - grid.template get<2>(p)) > worst) { + worst = std::fabs(grid.template get<1>(p) - grid.template get<2>(p)); + } + ++it2; + } + + std::cout << worst << std::endl; + BOOST_REQUIRE(worst < 1e-6); + + // Another way + x0.data.get<0>() = Init; + while (t < tf) { + rk4.do_step(Exponential,x0,t,dt); + OdeSol = x0.data.get<0>(); + t += dt; + } + + OdeSol = x0.data.get<0>(); + + // Error + auto it3{grid.getDomainIterator()}; + double worst2{0.0}; + while (it3.isNext()) { + auto p{it3.get()}; + if (std::fabs(grid.template get<1>(p) - grid.template get<2>(p)) > worst2) { + worst2 = fabs(grid.template get<1>(p) - grid.template get<2>(p)); + } + ++it3; + } + std::cout << worst2 << std::endl; + BOOST_REQUIRE(worst2 < 1e-6); + BOOST_REQUIRE_EQUAL(worst,worst2); +} + + + +BOOST_AUTO_TEST_CASE(odeint_grid_test_STRUCT_exponential) { + + size_t edgeSemiSize{40}; + const size_t sz[dim] = {edgeSemiSize,edgeSemiSize}; + Box<dim, double> box{{0.0,0.0},{1.0,1.0}}; + periodicity<dim> bc{{NON_PERIODIC,NON_PERIODIC}}; + double spacing[dim]; + spacing[0] = 1.0 / (sz[0] - 1); + spacing[1] = 1.0 / (sz[1] - 1); + Ghost<dim,long int> ghost{2}; + BOOST_TEST_MESSAGE("Test: exponential"); + BOOST_TEST_MESSAGE("Init grid_dist_id ..."); + + grid_dist_id<dim,double,aggregate<double,double,double,double,double,double>> grid{sz,box,ghost,bc}; + + auto it{grid.getDomainIterator()}; + while (it.isNext()) { + auto key = it.get(); + + grid.get<0>(key) = std::exp(0); + grid.template get<0>(key) = std::exp(0.0); // Initial state 1 + grid.template get<1>(key) = std::exp(0.4); // Analytical solution 1 + grid.template get<2>(key) = std::exp(0.0); // Initial state 2 + grid.template get<3>(key) = std::exp(0.8); // Analytical solution 2 + ++it; + } + grid.ghost_get<0>(); + + auto Init1{FD::getV<0>(grid)}; // Initial state 1 + auto Sol1{FD::getV<1>(grid)}; // Analytical solution 1 + + auto Init2{FD::getV<2>(grid)}; // Initial state 2 + auto Sol2{FD::getV<3>(grid)}; // Analytical solution 2 + + auto OdeSol1{FD::getV<4>(grid)}; // Numerical solution 1 + auto OdeSol2{FD::getV<5>(grid)}; // Numerical solution 2 + + state_type_3ode x0; + x0.data.get<0>() = Init1; + x0.data.get<1>() = Init2; + x0.data.get<2>() = Init1; + + double t{0}; + double tf{0.4}; + const double dt{0.1}; + + // size_t steps{boost::numeric::odeint::integrate(Exponential_struct,x0,0.0,tf,dt)}; + // size_t steps{boost::numeric::odeint::integrate_const(boost::numeric::odeint::runge_kutta4<state_type_3ode,double,state_type_3ode,double,boost::numeric::odeint::vector_space_algebra_ofp>(), + // Exponential_struct_ofp,x0,0.0,tf,dt)}; + + typedef boost::numeric::odeint::controlled_runge_kutta<boost::numeric::odeint::runge_kutta_cash_karp54<state_type_3ode,double,state_type_3ode,double,boost::numeric::odeint::vector_space_algebra_ofp>> stepper_type; + integrate_adaptive(stepper_type(),Exponential_struct_ofp2,x0,t,tf,dt); + + OdeSol1 = x0.data.get<0>(); + OdeSol2 = x0.data.get<1>(); + + // Error + auto it2{grid.getDomainIterator()}; + double worst{0.0}; + double worst2{0.0}; + while (it2.isNext()) { + auto p{it2.get()}; + if (std::fabs(grid.getProp<1>(p) - grid.getProp<4>(p)) > worst) + worst = std::fabs(grid.getProp<1>(p) - grid.getProp<4>(p)); + if (std::fabs(grid.getProp<3>(p) - grid.getProp<5>(p)) > worst2) + worst2 = std::fabs(grid.getProp<3>(p) - grid.getProp<5>(p)); + ++it2; + } + + std::cout << worst << " " << worst2 << std::endl; + BOOST_REQUIRE(worst < 1e-6); + BOOST_REQUIRE(worst2 < 1e-6); + + + // A different way + x0.data.get<0>() = Init1; + x0.data.get<1>() = Init2; + x0.data.get<2>() = Init1; + + boost::numeric::odeint::runge_kutta4<state_type_3ode,double,state_type_3ode,double,boost::numeric::odeint::vector_space_algebra_ofp> rk4; + while (t < tf) { + rk4.do_step(Exponential_struct_ofp2,x0,t,dt); + t+=dt; + } + + OdeSol1 = x0.data.get<0>(); + OdeSol2 = x0.data.get<1>(); + + // Error + auto it3{grid.getDomainIterator()}; + double worst3{0.0}; + double worst4{0.0}; + while (it3.isNext()) { + auto p{it3.get()}; + if (std::fabs(grid.getProp<1>(p) - grid.getProp<4>(p)) > worst3) + worst3 = std::fabs(grid.getProp<1>(p) - grid.getProp<4>(p)); + if (std::fabs(grid.getProp<3>(p) - grid.getProp<5>(p)) > worst4) + worst4 = std::fabs(grid.getProp<3>(p) - grid.getProp<5>(p)); + ++it3; + } + + std::cout << worst3 << " " << worst4 << std::endl; + BOOST_REQUIRE(worst3 < 1e-6); + BOOST_REQUIRE(worst4 < 5e-5); +} + + + + +BOOST_AUTO_TEST_CASE(odeint_grid_test2_exponential) { + + size_t edgeSemiSize{40}; + const size_t sz[dim] = {edgeSemiSize,edgeSemiSize}; + Box<dim,double> box{{0.0,0.0}, {1.0,1.0}}; + periodicity<dim> bc{{NON_PERIODIC,NON_PERIODIC}}; + double spacing[dim]; + spacing[0] = 1.0 / (sz[0] - 1); + spacing[1] = 1.0 / (sz[1] - 1); + Ghost<dim,long int> ghost{2}; + BOOST_TEST_MESSAGE("Test: exponential"); + BOOST_TEST_MESSAGE("Init grid_dist_id ..."); + + grid_dist_id<dim,double,aggregate<double,double,double>> grid{sz,box,ghost,bc}; + + double t{0.0}; + double tf{0.5}; + const double dt{0.1}; + + auto it{grid.getDomainIterator()}; + while (it.isNext()) { + auto key = it.get(); + grid.template get<0>(key) = std::exp(t); // Initial state + grid.template get<1>(key) = std::exp(tf); // Analytical solution + ++it; + } + grid.ghost_get<0>(); + + auto Init{FD::getV<0>(grid)}; // Initial state + auto Sol{FD::getV<1>(grid)}; // Analytical solution + auto OdeSol{FD::getV<2>(grid)}; // Numerical solution + + state_type_1ode x0; + x0.data.get<0>() = Init; + + typedef boost::numeric::odeint::controlled_runge_kutta<boost::numeric::odeint::runge_kutta_cash_karp54<state_type_1ode,double,state_type_1ode,double,boost::numeric::odeint::vector_space_algebra_ofp>> stepper_type; + + + integrate_adaptive(stepper_type(),Exponential,x0,t,tf,dt); + OdeSol = x0.data.get<0>(); // Numerical solution + + // Error + auto it2{grid.getDomainIterator()}; + double worst{0.0}; + while (it2.isNext()) { + auto p{it2.get()}; + if (std::fabs(grid.template get<1>(p) - grid.template get<2>(p)) > worst) { + worst = std::fabs(grid.template get<1>(p) - grid.template get<2>(p)); + } + ++it2; + } + + std::cout << worst << std::endl; + BOOST_REQUIRE(worst < 1e-6); + + // Another way + boost::numeric::odeint::runge_kutta4<state_type_1ode,double,state_type_1ode,double,boost::numeric::odeint::vector_space_algebra_ofp> rk4; + x0.data.get<0>() = Init; + for (size_t i = 0; i < int(tf/dt); ++i, t += dt) { + rk4.do_step(Exponential,x0,t,dt); + t += dt; + } + OdeSol = x0.data.get<0>(); + + // Error + auto it3{grid.getDomainIterator()}; + double worst2{0.0}; + while (it3.isNext()) { + auto p{it3.get()}; + if (std::fabs(grid.template get<1>(p) - grid.template get<2>(p)) > worst2) { + worst2 = fabs(grid.template get<1>(p) - grid.template get<2>(p)); + } + ++it3; + } + std::cout << worst2 << std::endl; + BOOST_REQUIRE(worst2 < 1e-6); + + // Yet another way + // x0.data.get<0>() = Init; + // integrate(rk4,Exponential,x0,t,tf,dt); + + // OdeSol = x0.data.get<0>(); + + // // Error + // auto it4{grid.getDomainIterator()}; + // double worst3{0.0}; + // while (it4.isNext()) { + // auto p{it4.get()}; + // if (std::fabs(grid.template get<1>(p) - grid.template get<2>(p)) > worst3) { + // worst3 = fabs(grid.template get<1>(p) - grid.template get<2>(p)); + // } + // ++it4; + // } + // std::cout << worst3 << std::endl; + // BOOST_REQUIRE(worst3 < 1e-6); + + // BOOST_REQUIRE_EQUAL(worst,worst2); + // BOOST_REQUIRE_EQUAL(worst2,worst3); +} + + + +// BOOST_AUTO_TEST_CASE(odeint_base_test3) +// { +// size_t edgeSemiSize = 40; +// const size_t sz[2] = {edgeSemiSize,edgeSemiSize }; +// Box<2, double> box({ 0, 0 }, { 1.0, 1.0 }); +// size_t bc[2] = {NON_PERIODIC,NON_PERIODIC}; +// double spacing[2]; +// spacing[0] = 1.0 / (sz[0] - 1); +// spacing[1] = 1.0 / (sz[1] - 1); +// double rCut = 3.9 * spacing[0]; +// Ghost<2, double> ghost(rCut); +// BOOST_TEST_MESSAGE("Init vector_dist..."); + +// vector_dist<2, double, aggregate<double, double,double>> Particles(0, box, bc, ghost); + +// double t=0.0,tf=0.5; +// const double dt=0.1; + +// auto it = Particles.getGridIterator(sz); +// while (it.isNext()) +// { +// Particles.add(); +// auto key = it.get(); +// mem_id k0 = key.get(0); +// double xp0 = k0 * spacing[0]; +// Particles.getLastPos()[0] = xp0; +// mem_id k1 = key.get(1); +// double yp0 = k1 * spacing[1]; +// Particles.getLastPos()[1] = yp0; +// Particles.getLastProp<0>() = 1.0/(1.0+exp(-t)); // Carefull in putting the constant, f = A*sigmoid does not respect f' = f*(1.0-f) but f*(1.0-f/A), for simplicity I remove the constant +// Particles.getLastProp<1>() = 1.0/(1.0+exp(-tf)); // Carefull in putting the constant, f = A*sigmoid does not respect f' = f*(1.0-f) but f*(1.0-f/A), for simplicity I remove the constant +// ++it; +// } +// Particles.map(); +// Particles.ghost_get<0>(); +// auto Init = getV<0>(Particles); +// auto Sol = getV<1>(Particles); +// auto OdeSol = getV<2>(Particles); + +// state_type x0; +// x0=Init; +// // The rhs of x' = f(x) +// //size_t steps=boost::numeric::odeint::integrate(sigmoid,x0,0.0,tf,dt); +// //typedef boost::numeric::odeint::controlled_runge_kutta< boost::numeric::odeint::runge_kutta_cash_karp54< state_type > > stepper_type; +// //integrate_adaptive( stepper_type() , sigmoid , x0 , t , tf , dt); +// size_t steps=boost::numeric::odeint::integrate_const( boost::numeric::odeint::runge_kutta4< state_type >(),sigmoid,x0,0.0,tf,dt); + +// OdeSol=x0; +// auto it2 = Particles.getDomainIterator(); +// double worst = 0.0; +// while (it2.isNext()) { +// auto p = it2.get(); +// if (fabs(Particles.getProp<1>(p) - Particles.getProp<2>(p)) > worst) { +// worst = fabs(Particles.getProp<1>(p) - Particles.getProp<2>(p)); +// } +// ++it2; +// } + +// BOOST_REQUIRE(worst < 1e-8); + +// x0=Init; +// boost::numeric::odeint::runge_kutta4< state_type > rk4; +// for( size_t i=0 ; i<int(tf/dt) ; ++i,t+=dt ) +// { +// rk4.do_step(sigmoid,x0,t,dt); +// t+=dt; +// } + +// OdeSol=x0; +// auto it3 = Particles.getDomainIterator(); +// double worst2 = 0.0; +// while (it3.isNext()) { +// auto p = it3.get(); +// if (fabs(Particles.getProp<1>(p) - Particles.getProp<2>(p)) > worst2) { +// worst2 = fabs(Particles.getProp<1>(p) - Particles.getProp<2>(p)); +// } +// ++it3; +// } +// //std::cout<<worst2<<std::endl; +// BOOST_REQUIRE(worst < 1e-6); +// BOOST_REQUIRE_EQUAL(worst,worst2); +// } + + + +#ifdef HAVE_EIGEN + +BOOST_AUTO_TEST_CASE(dcpse_op_react_diff_test) { + + size_t edgeSemiSize{5}; + const size_t sz[dim] = {2 * edgeSemiSize+1, 2 * edgeSemiSize+1}; + Box<dim,double> box{{0.0, 0.0},{1.0, 1.0}}; + periodicity<dim> bc{{PERIODIC,PERIODIC}}; + double spacing[dim]; + spacing[0] = 1.0 / (sz[0]); + spacing[1] = 1.0 / (sz[1]); + Ghost<dim,double> ghost{spacing[0] * 3}; + + BOOST_TEST_MESSAGE("Test: reaction diffusion"); + BOOST_TEST_MESSAGE("Init grid_dist_id ..."); + double sigma2 = spacing[0] * spacing[1] / (2 * 4); + + // properties: u, v, du, dv + grid_dist_id<dim,double,aggregate<double,double,double,double,double,double>> domain{sz,box,ghost,bc}; + + auto it{domain.getDomainIterator()}; + while (it.isNext()) { + auto key{it.get()}; + domain.get<0>(key) = 0.0; // u + domain.get<1>(key) = 0.0; // v + domain.get<2>(key) = 0.0; // du/dt + domain.get<3>(key) = 0.0; // dv/dt + + auto gkey = it.getGKey(key); + + if (gkey.get(0)==sz[0] / 2 && gkey.get(1) == sz[1]/2) + { + domain.get<0>(key) = 1.0; + domain.get<1>(key) = 1.0; + } + ++it; + } + domain.ghost_get<0>(); + + FD::Derivative<0,2,2,FD::CENTRAL> ddx; + FD::Derivative<1,2,2,FD::CENTRAL> ddy; + + gridGlobal=(void *) & domain; + + auto u{FD::getV<0>(domain)}; + auto v{FD::getV<1>(domain)}; + auto fu{FD::getV<2>(domain)}; + auto fv{FD::getV<3>(domain)}; + + Fitz<decltype(ddx),decltype(ddy)> system(ddx,ddy); + state_type_2ode x0; + + x0.data.get<0>() = u; + x0.data.get<1>() = v; + + double dt{0.001}; + double t{0.0}; + double tf{10.5}; + + //typedef boost::numeric::odeint::controlled_runge_kutta< boost::numeric::odeint::runge_kutta_cash_karp54< state_type_2d_ofp,double,state_type_2d_ofp,double,boost::numeric::odeint::vector_space_algebra_ofp>> stepper_type; + typedef boost::numeric::odeint::runge_kutta4<state_type_2ode,double,state_type_2ode,double,boost::numeric::odeint::vector_space_algebra_ofp> stepper_type; + + integrate_adaptive(stepper_type(),system,x0,t,tf,dt); + fu = x0.data.get<0>(); + fv = x0.data.get<1>(); + + domain.ghost_get<2,3>(); + u = ddx(fu) + ddy(fu); + v = ddx(fv) + ddy(fv); + + auto it2{domain.getDomainIterator()}; + + if (create_vcluster().rank() == 0) + ++it2; + + while (it2.isNext()) { + auto p{it2.get()}; + BOOST_REQUIRE_CLOSE(domain.get<0>(p),-1.0,1); + ++it2; + } +} +#endif + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/src/OdeIntegrators/tests/OdeIntegratores_base_tests.cpp b/src/OdeIntegrators/tests/OdeIntegratores_base_tests.cpp index c1455d08d7f39bbd1cb8014ba43ba13d0d984fc3..af12bcc69cd9c553ab3bffe447e9b39efc8e9c61 100644 --- a/src/OdeIntegrators/tests/OdeIntegratores_base_tests.cpp +++ b/src/OdeIntegrators/tests/OdeIntegratores_base_tests.cpp @@ -466,7 +466,6 @@ BOOST_AUTO_TEST_CASE(odeint_base_test3) BOOST_REQUIRE_EQUAL(worst,worst2); } - #ifdef HAVE_EIGEN BOOST_AUTO_TEST_CASE(dcpse_op_react_diff_test) { size_t edgeSemiSize = 5; diff --git a/src/OdeIntegrators/vector_algebra_ofp.hpp b/src/OdeIntegrators/vector_algebra_ofp.hpp index 180d1fbb3074a30d33570c75e8fbc9fb15a9bf6b..5c01e81cbedcb9eda89630b5a46f97b6051a34d1 100644 --- a/src/OdeIntegrators/vector_algebra_ofp.hpp +++ b/src/OdeIntegrators/vector_algebra_ofp.hpp @@ -597,7 +597,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop1<S1,size_t,Op> cp(s1,p,op); + for_each_prop1<S1,typename S1::index_type,Op> cp(s1,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -618,7 +618,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop2<S1,S2,size_t,Op> cp(s1,s2,p,op); + for_each_prop2<S1,S2,typename S1::index_type,Op> cp(s1,s2,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -636,10 +636,11 @@ namespace boost { boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(the_resize); // ToDo : build checks, that the +-*/ operators are well defined auto it=s1.data.template get<0>().getVector().getIterator(); + while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop3<S1,S2,S3,size_t,Op> cp(s1,s2,s3,p,op); + for_each_prop3<S1,S2,S3,typename S1::index_type,Op> cp(s1,s2,s3,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -660,7 +661,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop4<S1,S2,S3,S4,size_t,Op> cp(s1,s2,s3,s4,p,op); + for_each_prop4<S1,S2,S3,S4,typename S1::index_type,Op> cp(s1,s2,s3,s4,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -681,7 +682,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop5<S1,S2,S3,S4,S5,size_t,Op> cp(s1,s2,s3,s4,s5,p,op); + for_each_prop5<S1,S2,S3,S4,S5,typename S1::index_type,Op> cp(s1,s2,s3,s4,s5,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -699,7 +700,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop6<S1,S2,S3,S4,S5,S6,size_t,Op> cp(s1,s2,s3,s4,s5,s6,p,op); + for_each_prop6<S1,S2,S3,S4,S5,S6,typename S1::index_type,Op> cp(s1,s2,s3,s4,s5,s6,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -717,7 +718,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop7<S1,S2,S3,S4,S5,S6,S7,size_t,Op> cp(s1,s2,s3,s4,s5,s6,s7,p,op); + for_each_prop7<S1,S2,S3,S4,S5,S6,S7,typename S1::index_type,Op> cp(s1,s2,s3,s4,s5,s6,s7,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -735,7 +736,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop8<S1,S2,S3,S4,S5,S6,S7,S8,size_t,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,p,op); + for_each_prop8<S1,S2,S3,S4,S5,S6,S7,S8,typename S1::index_type,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -753,7 +754,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop9<S1,S2,S3,S4,S5,S6,S7,S8,S9,size_t,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,p,op); + for_each_prop9<S1,S2,S3,S4,S5,S6,S7,S8,S9,typename S1::index_type,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -771,7 +772,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop10<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,size_t,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,p,op); + for_each_prop10<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,typename S1::index_type,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -790,7 +791,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop11<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,size_t,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,p,op); + for_each_prop11<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,typename S1::index_type,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -808,7 +809,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop12<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,S12,size_t,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,p,op); + for_each_prop12<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,S12,typename S1::index_type,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -826,7 +827,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop13<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,S12,S13,size_t,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,p,op); + for_each_prop13<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,S12,S13,typename S1::index_type,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -845,7 +846,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop14<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,S12,S13,S14,size_t,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,p,op); + for_each_prop14<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,S12,S13,S14,typename S1::index_type,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -863,7 +864,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_prop15<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,S12,S13,S14,S15,size_t,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,p,op); + for_each_prop15<S1,S2,S3,S4,S5,S6,S7,S8,S9,S10,S11,S12,S13,S14,S15,typename S1::index_type,Op> cp(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,p,op); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype( s1.data)::max_prop>>(cp); @@ -912,7 +913,7 @@ namespace boost { while(it.isNext()){ auto p=it.get(); //converting to boost vector ids. - for_each_norm<S,size_t,typename boost::numeric::odeint::vector_space_norm_inf< S >::result_type> cp(s,p,n); + for_each_norm<S,typename S::index_type,typename boost::numeric::odeint::vector_space_norm_inf< S >::result_type> cp(s,p,n); //creating an iterator on v_ids[0] [1] [2] boost::mpl::for_each_ref<boost::mpl::range_c<int,0,decltype(s.data)::max_prop>>(cp); diff --git a/src/Operators/Vector/vector_dist_operators.hpp b/src/Operators/Vector/vector_dist_operators.hpp index 78ffe7b4e553dfb9af0453c81b37db49a93253fa..25905116df8fa7851c338f4e931960012797e314 100644 --- a/src/Operators/Vector/vector_dist_operators.hpp +++ b/src/Operators/Vector/vector_dist_operators.hpp @@ -1551,7 +1551,97 @@ struct switcher_get_v<vector,comp_dev> } }; -/*! \brief it take an expression and create the negatove of this expression +/*template<unsigned int, bool is_valid> +struct get_vector_dist_expression_op +{ + template<typename exp_type> + inline static auto get(exp_type & o1, const vect_dist_key_dx & key) -> decltype(o1.value(vect_dist_key_dx(0))) + { + return o1.value(key); + } + + template<unsigned int prop, typename exp_type, typename vector_type> + inline static void assign(exp_type & o1, vector_type & v, const vect_dist_key_dx & key, const vect_dist_key_dx & key_orig) + { + pos_or_propL<vector_type,exp_type::prop>::value(v,key) = o1.value(key_orig); + } + + template<unsigned int prop, typename vector_type> + inline static void assign_double(double d, vector_type & v, const vect_dist_key_dx & key) + { + pos_or_propL<vector_type,prop>::value(v,key) = d; + } +}; + +template<> +struct get_vector_dist_expression_op<1,false> +{ + template<typename exp_type> + static int get(exp_type & o1, const vect_dist_key_dx & key, const int (& comp)[1]) + { + printf("ERROR: Slicer, the expression is incorrect, please check it\n"); + return 0; + } + + template<unsigned int prop, typename exp_type, typename vector_type> + inline static void assign(exp_type & o1, vector_type & v, const vect_dist_key_dx & key) + { + printf("ERROR: Slicer, the expression is incorrect, please check it\n"); + } + + template<unsigned int prop, typename vector_type> + inline static void assign_double(double d, vector_type & v, const vect_dist_key_dx & key) + { + printf("ERROR: Slicer, the expression is incorrect, please check it\n"); + } +}; + +template<> +struct get_vector_dist_expression_op<1,true> +{ + template<typename exp_type> + static auto get(exp_type & o1, const vect_dist_key_dx & key, const int (& comp)[1]) -> decltype(o1.value(vect_dist_key_dx(0))[0]) + { + return o1.value(key)[comp[0]]; + } + + template<unsigned int prop,typename exp_type, typename vector_type> + inline static void assign(exp_type & o1, vector_type & v, const vect_dist_key_dx & key, const vect_dist_key_dx & key_orig, const int (& comp)[1]) + { + pos_or_propL<vector_type,prop>::value(v,key)[comp[0]] = o1.value(key_orig); + } + + template<unsigned int prop, typename vector_type> + inline static void assign_double(double d, vector_type & v, const vect_dist_key_dx & key, const int (& comp)[1]) + { + pos_or_propL<vector_type,prop>::value(v,key)[comp[0]] = d; + } +}; + +template<> +struct get_vector_dist_expression_op<2,true> +{ + template<typename exp_type> + static auto get(exp_type & o1, const vect_dist_key_dx & key, const int (& comp)[2]) -> decltype(o1.value(vect_dist_key_dx(0))[0][0]) + { + return o1.value(key)[comp[0]][comp[1]]; + } + + template<unsigned int prop,typename exp_type, typename vector_type> + inline static void assign(exp_type & o1, vector_type & v, const vect_dist_key_dx & key, const vect_dist_key_dx & key_orig, const int (& comp)[2]) + { + pos_or_propL<vector_type,prop>::value(v,key)[comp[0]][comp[1]] = o1.value(key_orig); + } + + template<unsigned int prop, typename vector_type> + inline static void assign_double(double d, vector_type & v, const vect_dist_key_dx & key, const int (& comp)[2]) + { + pos_or_propL<vector_type,prop>::value(v,key)[comp[0]][comp[1]] = d; + } +};*/ + + +/*! \brief it take an expression and take the component * * */ diff --git a/src/level_set/closest_point/closest_point.hpp b/src/level_set/closest_point/closest_point.hpp index 293ae493470f023910fc1be54b9fd0c8a46eb429..f99f4e2ab80297e8ce2c4239aa37154dc1c3a87e 100644 --- a/src/level_set/closest_point/closest_point.hpp +++ b/src/level_set/closest_point/closest_point.hpp @@ -17,6 +17,7 @@ #ifndef __CLOSEST_POINT_HPP__ #define __CLOSEST_POINT_HPP__ +#include "Grid/grid_dist_key.hpp" #include "algoim_hocp.hpp" // Width of extra padding around each grid patch needed to correctly construct kDTree in Algoim. @@ -26,21 +27,20 @@ constexpr int algoim_padding = 4; * * @file closest_point.hpp * @struct AlgoimWrapper - * @tparam grid_type Type of the grid container - * @tparam grid_key_type Type of the key for the grid container - * @tparam dim Dimension of the space * @tparam wrapping_field Property id on the grid for the field to be wrapped + * @tparam grid_type Type of the grid container + * */ - -template<typename grid_type, typename grid_key_type, unsigned int dim, size_t wrapping_field> +template<size_t wrapping_field, typename grid_type, typename wrapping_field_type = typename boost::mpl::at<typename grid_type::value_type::type,boost::mpl::int_<wrapping_field>>::type> struct AlgoimWrapper { + const static unsigned int dim = grid_type::dims; grid_type &gd; int patch_id; AlgoimWrapper(grid_type& ls_grid, const int pid) : gd(ls_grid), patch_id(pid) {} //! Call operator for the wrapper. - double operator() (const blitz::TinyVector<int,dim> idx) const + double operator() (const blitz::TinyVector<int, dim> idx) const { long int local_key[dim]; @@ -50,28 +50,168 @@ struct AlgoimWrapper local_key[d] = idx(d) - algoim_padding; // Generate OpenFPM grid_key object from local grid indices - grid_key_type grid_key(patch_id, grid_key_dx<dim> (local_key) + ghost_offset); + grid_dist_key_dx<dim> grid_key(patch_id, grid_key_dx<dim> (local_key) + ghost_offset); return gd.template get<wrapping_field>(grid_key); } + + template<size_t extend_field_temp, int poly_order, typename coord_type, typename dx_type, typename pos_type, typename key_type> + void extend(coord_type coord, dx_type dx, pos_type pos, key_type key) { + + using Poly = typename Algoim::StencilPoly<dim, poly_order>::T_Poly; + + Poly field_poly = Poly(coord, *this, dx); + // Extension is first done to the temporary field. Otherwise interpolation will be affected. + gd.template get<extend_field_temp>(key) = field_poly(pos); + } + +}; + +template<size_t wrapping_field, typename grid_type, typename wrapping_field_type, size_t N1> +struct AlgoimWrapper<wrapping_field,grid_type,wrapping_field_type[N1]> +{ + const static unsigned int dim = grid_type::dims; + grid_type &gd; + int patch_id; + size_t comp_i; + AlgoimWrapper(grid_type& ls_grid, const int pid) : gd(ls_grid), patch_id(pid) {} + + //! Call operator for the wrapper. + double operator() (const blitz::TinyVector<int, dim> idx) const + { + long int local_key[dim]; + + auto ghost_offset = gd.getLocalGridsInfo().get(patch_id).Dbox.getKP1(); + + for (int d = 0; d < dim; ++d) + local_key[d] = idx(d) - algoim_padding; + + // Generate OpenFPM grid_key object from local grid indices + grid_dist_key_dx<dim> grid_key(patch_id, grid_key_dx<dim> (local_key) + ghost_offset); + + return gd.template get<wrapping_field>(grid_key)[comp_i]; + } + + template<size_t extend_field_temp, int poly_order, typename coord_type, typename dx_type, typename pos_type, typename key_type> + void extend(coord_type coord, dx_type dx, pos_type pos, key_type key) { + + using Poly = typename Algoim::StencilPoly<dim, poly_order>::T_Poly; + + for (int i = 0; i < N1; ++i) { + comp_i = i; + Poly field_poly = Poly(coord, *this, dx); + // Extension is first done to the temporary field. Otherwise interpolation will be affected. + gd.template get<extend_field_temp>(key)[i] = field_poly(pos); + } + } +}; + +template<size_t wrapping_field, typename grid_type, typename wrapping_field_type, size_t N1, size_t N2> +struct AlgoimWrapper<wrapping_field,grid_type,wrapping_field_type[N1][N2]> +{ + const static unsigned int dim = grid_type::dims; + grid_type &gd; + int patch_id; + size_t comp_i, comp_j; + AlgoimWrapper(grid_type& ls_grid, const int pid) : gd(ls_grid), patch_id(pid) {} + + //! Call operator for the wrapper. + double operator() (const blitz::TinyVector<int, dim> idx) const + { + long int local_key[dim]; + + auto ghost_offset = gd.getLocalGridsInfo().get(patch_id).Dbox.getKP1(); + + for (int d = 0; d < dim; ++d) + local_key[d] = idx(d) - algoim_padding; + + // Generate OpenFPM grid_key object from local grid indices + grid_dist_key_dx<dim> grid_key(patch_id, grid_key_dx<dim> (local_key) + ghost_offset); + + return gd.template get<wrapping_field>(grid_key)[comp_i][comp_j]; + } + + template<size_t extend_field_temp, int poly_order, typename coord_type, typename dx_type, typename pos_type, typename key_type> + void extend(coord_type coord, dx_type dx, pos_type pos, key_type key) { + + using Poly = typename Algoim::StencilPoly<grid_type::dims, poly_order>::T_Poly; + + for (int i = 0; i < N1; ++i) { + for (int j = 0; j < N2; ++j) { + comp_i = i; + comp_j = j; + Poly field_poly = Poly(coord, *this, dx); + // Extension is first done to the temporary field. Otherwise interpolation will be affected. + gd.template get<extend_field_temp>(key)[i][j] = field_poly(pos); + } + } + } +}; + +template<size_t wrapping_field, typename grid_type, typename wrapping_field_type, size_t N1, size_t N2, size_t N3> +struct AlgoimWrapper<wrapping_field,grid_type,wrapping_field_type[N1][N2][N3]> +{ + const static unsigned int dim = grid_type::dims; + grid_type &gd; + int patch_id; + size_t comp_i, comp_j, comp_k; + AlgoimWrapper(grid_type& ls_grid, const int pid) : gd(ls_grid), patch_id(pid) {} + + //! Call operator for the wrapper. + double operator() (const blitz::TinyVector<int, dim> idx) const + { + long int local_key[dim]; + + auto ghost_offset = gd.getLocalGridsInfo().get(patch_id).Dbox.getKP1(); + + for (int d = 0; d < dim; ++d) + local_key[d] = idx(d) - algoim_padding; + + // Generate OpenFPM grid_key object from local grid indices + grid_dist_key_dx<dim> grid_key(patch_id, grid_key_dx<dim> (local_key) + ghost_offset); + + return gd.template get<wrapping_field>(grid_key)[comp_i][comp_j][comp_k]; + } + + template<size_t extend_field_temp, int poly_order, typename coord_type, typename dx_type, typename pos_type, typename key_type> + void extend(coord_type coord, dx_type dx, pos_type pos, key_type key) { + + using Poly = typename Algoim::StencilPoly<grid_type::dims, poly_order>::T_Poly; + + for (int i = 0; i < N1; ++i) { + for (int j = 0; j < N2; ++j) { + for (int k = 0; k < N3; ++k) { + comp_i = i; + comp_j = j; + comp_k = k; + Poly field_poly = Poly(coord, *this, dx); + // Extension is first done to the temporary field. Otherwise interpolation will be affected. + gd.template get<extend_field_temp>(key)[i][j][k] = field_poly(pos); + } + } + } + } }; + /**@brief Computes the closest point coordinate for each grid point within nb_gamma from interface. * + * @tparam phi_field Property id on grid for the level set SDF (input) + * @tparam cp_field Property id on grid for storing closest point coordinates (output) + * @tparam poly_order Type of stencil interpolation (Taylor poly orders between 2 to 5 and Tri/bicubic through -1 is supported) * @tparam grid_type Type of the grid container - * @tparam grid_key_type Type of the key for the grid container - * @tparam dim Dimension of the space - * @tparam poly_order Order of the polynomial for stencil interpolation (orders between 2 to 5 is supported) - * @tparam phi_field Property id on grid for the level set SDF - * @tparam cp_field Property id on grid for storing closest point coordinates * * @param gd The distributed grid containing at least level set SDF field and placeholder for closest point coordinates * @param nb_gamma The width of the narrow band within which closest point estimation is to be done + * */ -template<typename grid_type, typename grid_key_type, unsigned int poly_order, size_t phi_field, size_t cp_field> +template<size_t phi_field, size_t cp_field, int poly_order, typename grid_type> void estimateClosestPoint(grid_type &gd, const double nb_gamma) { const unsigned int dim = grid_type::dims; + // Update the phi field in ghosts + gd.template ghost_get<phi_field>(KEEP_PROPERTIES); + // Stencil polynomial type using Poly = typename Algoim::StencilPoly<dim, poly_order>::T_Poly; @@ -93,7 +233,7 @@ void estimateClosestPoint(grid_type &gd, const double nb_gamma) p_hi.set_d(d, patches.get(i).Dbox.getHigh(d) + patches.get(i).origin[d]); } - AlgoimWrapper<grid_type, grid_key_type, dim, phi_field> phiwrap(gd, i); + AlgoimWrapper<phi_field, grid_type> phiwrap(gd, i); // Find all cells containing the interface and construct the high-order polynomials std::vector<Algoim::detail::CellPoly<dim,Poly>> cells; @@ -111,8 +251,10 @@ void estimateClosestPoint(grid_type &gd, const double nb_gamma) Algoim::KDTree<double,dim> kdtree(points); + // In order to ensure that CP is estimated for all points in the narrowband, we add a buffer to the distance check. + double nb_gamma_plus_dx = nb_gamma + gd.spacing(0); // Pass everything to the closest point computation engine - Algoim::ComputeHighOrderCP<dim,Poly> hocp(nb_gamma < std::numeric_limits<double>::max() ? nb_gamma*nb_gamma : std::numeric_limits<double>::max(), // squared bandradius + Algoim::ComputeHighOrderCP<dim,Poly> hocp(nb_gamma_plus_dx < std::numeric_limits<double>::max() ? nb_gamma_plus_dx*nb_gamma_plus_dx : std::numeric_limits<double>::max(), // squared bandradius 0.5*blitz::max(dx), // amount that each polynomial overlaps / size of the bounding ball in Newton's method Algoim::sqr(std::max(1.0e-14, std::pow(blitz::max(dx), Poly::order))), // tolerance to determine convergence cells, kdtree, points, pointcells, dx, 0.0); @@ -121,7 +263,7 @@ void estimateClosestPoint(grid_type &gd, const double nb_gamma) while(it.isNext()) { auto key = it.get(); - if(std::abs(gd.template get<phi_field>(key)) <= nb_gamma) + if(std::abs(gd.template get<phi_field>(key)) < nb_gamma) { auto key_g = gd.getGKey(key); // NOTE: This is not the real grid coordinates, but internal coordinates for algoim @@ -136,8 +278,13 @@ void estimateClosestPoint(grid_type &gd, const double nb_gamma) } else { + std::cout<<"WARN: Closest point computation fails at : "; for(int d = 0; d < dim; ++d) + { + std::cout<<key_g.get(d)<<" "; gd.template get<cp_field>(key)[d] = -100.0; + } + std::cout<<"\n"; } } ++it; @@ -148,22 +295,23 @@ void estimateClosestPoint(grid_type &gd, const double nb_gamma) /**@brief Extends a (scalar) field to within nb_gamma from interface. The grid should have level set SDF and closest point field. * - * @tparam grid_type Type of the grid container - * @tparam grid_key_type Type of the key for the grid container - * @tparam dim Dimension of the space - * @tparam poly_order Order of the polynomial for stencil interpolation * @tparam phi_field Property id on grid for the level set SDF * @tparam cp_field Property id on grid for storing closest point coordinates * @tparam extend_field Property id on grid where the field to be extended resides * @tparam extend_field_temp Property id on grid for storing temporary intermediate values + * @tparam poly_order Type of stencil interpolation (Taylor poly orders between 2 to 5 and Tri/bicubic through -1 is supported) + * @tparam grid_type Type of the grid container * * @param gd The distributed grid containing atleast level set SDF field and closest point coordinates - * @param nb_gamma The width of the narrow band within which extension is required + * @param nb_gamma The width of the narrow band within which extension is required (half band) */ -template<typename grid_type, typename grid_key_type, unsigned int poly_order, size_t phi_field, size_t cp_field, size_t extend_field, size_t extend_field_temp> +template<size_t phi_field, size_t cp_field, size_t extend_field, size_t extend_field_temp, int poly_order, typename grid_type> void extendLSField(grid_type &gd, const double nb_gamma) { const unsigned int dim = grid_type::dims; + // Update the phi and cp fields in ghost + gd.template ghost_get<phi_field, cp_field, extend_field>(KEEP_PROPERTIES); + // Stencil polynomial object using Poly = typename Algoim::StencilPoly<dim, poly_order>::T_Poly; auto &patches = gd.getLocalGridsInfo(); @@ -181,7 +329,7 @@ void extendLSField(grid_type &gd, const double nb_gamma) p_lo.set_d(d, patches.get(i).Dbox.getLow(d) + patches.get(i).origin[d]); p_hi.set_d(d, patches.get(i).Dbox.getHigh(d) + patches.get(i).origin[d]); } - + auto it = gd.getSubDomainIterator(p_lo, p_hi); while(it.isNext()) @@ -199,44 +347,45 @@ void extendLSField(grid_type &gd, const double nb_gamma) pos(d) = cp_d - coord(d)*gd.spacing(d); } - AlgoimWrapper<grid_type, grid_key_type, dim, extend_field> fieldwrap(gd,i); - Poly field_poly = Poly(coord, fieldwrap, dx); - // Extension is first done to the temporary field. Otherwise interpolation will be affected. - gd.template get<extend_field_temp>(key) = field_poly(pos); + AlgoimWrapper<extend_field, grid_type> fieldwrap(gd,i); + fieldwrap.template extend<extend_field_temp,poly_order>(coord,dx,pos,key); + // Poly field_poly = Poly(coord, fieldwrap, dx); + // // Extension is first done to the temporary field. Otherwise interpolation will be affected. + // gd.template get<extend_field_temp>(key) = field_poly(pos); } ++it; } } - + // Copy the results to the actual variable + typedef typename boost::mpl::at<typename grid_type::value_type::type,boost::mpl::int_<extend_field>>::type type_to_copy; auto it = gd.getDomainIterator(); while(it.isNext()) { auto key = it.get(); if(std::abs(gd.template get<phi_field>(key)) < nb_gamma) - gd.template get<extend_field>(key) = gd.template get<extend_field_temp>(key); + meta_copy<type_to_copy>::meta_copy_(gd.template get<extend_field_temp>(key),gd.template get<extend_field>(key)); ++it; } } /**@brief Reinitializes the level set Phi field on a grid. The grid should have level set SDF and closest point field. * - * @tparam grid_type Type of the grid container - * @tparam grid_key_type Type of the key for the grid container - * @tparam dim Dimension of the space - * @tparam poly_order Order of the polynomial for stencil interpolation * @tparam phi_field Property id on grid for the level set SDF * @tparam cp_field Property id on grid for storing closest point coordinates - * + * @tparam grid_type Type of the grid container + * @param gd The distributed grid containing atleast level set SDF field and closest point coordinates * @param nb_gamma The width of the narrow band for reinitialization */ -template<typename grid_type, typename grid_key_type, unsigned int poly_order, size_t phi_field, size_t cp_field> +template<size_t phi_field, size_t cp_field, typename grid_type> void reinitializeLS(grid_type &gd, const double nb_gamma) { const unsigned int dim = grid_type::dims; - // Stencil polynomial object - using Poly = typename Algoim::StencilPoly<dim, poly_order>::T_Poly; + + // Update the cp_field in ghost + gd.template ghost_get<cp_field>(KEEP_PROPERTIES); + auto &patches = gd.getLocalGridsInfo(); blitz::TinyVector<double,dim> dx; for(int d = 0; d < dim; ++d) @@ -271,6 +420,9 @@ void reinitializeLS(grid_type &gd, const double nb_gamma) // NOTE: This is not the real grid coordinates, but internal coordinates used for algoim double patch_pos = (key_g.get(d) - p_lo.get(d) + algoim_padding) * gd.spacing(d); double cp_d = gd.template get<cp_field>(key)[d]; + if(cp_d == -100.0) + std::cout<<"WARNING: Requesting closest point on nodes where it was not computed."<<std::endl; + distance += ((patch_pos - cp_d)*(patch_pos - cp_d)); } distance = sqrt(distance); diff --git a/src/level_set/closest_point/closest_point_unit_tests.cpp b/src/level_set/closest_point/closest_point_unit_tests.cpp index 30bcd7f6b5b18a29c7ded587dbb6b353d3847d2e..9e2f10b23fc21917e85bdb7a649524ea188798eb 100644 --- a/src/level_set/closest_point/closest_point_unit_tests.cpp +++ b/src/level_set/closest_point/closest_point_unit_tests.cpp @@ -5,6 +5,7 @@ #include<iostream> #include <boost/test/unit_test_log.hpp> +#include <cmath> #define BOOST_TEST_DYN_LINK #include <boost/test/unit_test.hpp> #include <iostream> @@ -28,21 +29,17 @@ typedef struct EllipseParameters{ } EllipseParams; // Generate an ellipsoid initial levelset signed distance function -template<typename grid_type, typename domain_type, size_t phi_field> -void initializeLSEllipsoid(grid_type &gd, const domain_type &domain, const EllipseParams ¶ms) +template<size_t phi_field, typename grid_type> +void initializeLSEllipsoid(grid_type &gd, const EllipseParams ¶ms) { auto it = gd.getDomainIterator(); - double dx = gd.getSpacing()[0]; - double dy = gd.getSpacing()[1]; - double dz = gd.getSpacing()[2]; while(it.isNext()) { auto key = it.get(); - auto key_g = gd.getGKey(key); - - double posx = key_g.get(0)*dx + domain.getLow(0); - double posy = key_g.get(1)*dy + domain.getLow(1); - double posz = key_g.get(2)*dz + domain.getLow(2); + Point<grid_type::dims, double> coords = gd.getPos(key); + double posx = coords.get(0); + double posy = coords.get(1); + double posz = coords.get(2); // NOTE: Except for a sphere, this is not the SDF. It is just an implicit function whose zero contour is an ellipsoid. double phi_val = 1.0 - sqrt(((posx - params.origin[0])/params.radiusA)*((posx - params.origin[0])/params.radiusA) + ((posy - params.origin[1])/params.radiusB)*((posy - params.origin[1])/params.radiusB) + ((posz - params.origin[2])/params.radiusC)*((posz - params.origin[2])/params.radiusC)); @@ -51,6 +48,36 @@ void initializeLSEllipsoid(grid_type &gd, const domain_type &domain, const Elli } } +// Initialize a scalar field or grid points near the interface +template<const unsigned int phi, const unsigned int field, typename grid_type> +void initializeScalarField3D(grid_type &gd, double init_width) +{ + auto it = gd.getDomainIterator(); + + // Trying with a L_1 and L_2 spherical harmonics as initial condition for scalar_field + double prefactor_l1 = std::sqrt(2.0/(4.0*M_PI)); + //double prefactor_l2 = std::sqrt(5.0/(16.0*M_PI)); + + while(it.isNext()) + { + auto key = it.get(); + if(gd.template get<phi>(key) < init_width) + { + auto coords = gd.getPos(key); + double posx = coords.get(0); + double posy = coords.get(1); + double posz = coords.get(2); + + double theta = std::atan2(std::sqrt(posx*posx + posy*posy), posz); + + gd.template get<field>(key) = prefactor_l1 * std::cos(theta); + //gd.template get<field>(key) = prefactor_l2 * (3.0 * std::cos(theta) * std::cos(theta) - 1.0); + } + ++it; + } + +} + BOOST_AUTO_TEST_SUITE( closest_point_test ) @@ -100,12 +127,10 @@ BOOST_AUTO_TEST_CASE( closest_point_unit_sphere ) nb_gamma = narrow_band_half_width * gdist.spacing(0); // Initializes the grid property 'phi' whose zero contour represents the ellipsoid - initializeLSEllipsoid<GridDist, Box<SIM_DIM,double>, phi>(gdist, domain, params); - gdist.template ghost_get<phi>(); + initializeLSEllipsoid<phi>(gdist, params); // Updates the property 'cp' of the grid to the closest point coords (only done in the narrowband). - estimateClosestPoint<GridDist, GridKey, POLY_ORDER, phi, cp>(gdist, nb_gamma); - gdist.template ghost_get<cp>(); + estimateClosestPoint<phi, cp, POLY_ORDER>(gdist, nb_gamma); // Estimate error in closest point estimation auto &patches = gdist.getLocalGridsInfo(); @@ -127,7 +152,6 @@ BOOST_AUTO_TEST_CASE( closest_point_unit_sphere ) if(std::abs(gdist.template get<phi>(key)) < nb_gamma) { - auto key_g = gdist.getGKey(key); // Computed closest point coordinates. // Note: This is patch coordinates not the real one. double cpx = gdist.template get<cp>(key)[x]; @@ -143,9 +167,10 @@ BOOST_AUTO_TEST_CASE( closest_point_unit_sphere ) double estim_pz = domain.getLow(z) + (p_zlo - algoim_padding)*gdist.spacing(z) + cpz; // Global coordinate of the selected grid point. - double posx = key_g.get(0)*gdist.spacing(0) + domain.getLow(0); - double posy = key_g.get(1)*gdist.spacing(1) + domain.getLow(1); - double posz = key_g.get(2)*gdist.spacing(2) + domain.getLow(2); + Point<GridDist::dims, double> coords = gdist.getPos(key); + double posx = coords.get(0); + double posy = coords.get(1); + double posz = coords.get(2); double norm = sqrt(posx*posx + posy*posy + posz*posz); // Analytically known closest point coordinate for unit sphere. @@ -213,15 +238,12 @@ BOOST_AUTO_TEST_CASE( reinitialization_unit_sphere ) nb_gamma = narrow_band_half_width * gdist.spacing(0); - initializeLSEllipsoid<GridDist, Box<SIM_DIM,double>, phi>(gdist, domain, params); - gdist.template ghost_get<phi>(); + initializeLSEllipsoid<phi>(gdist, params); - estimateClosestPoint<GridDist, GridKey, POLY_ORDER, phi, cp>(gdist, nb_gamma); - gdist.template ghost_get<cp>(); + estimateClosestPoint<phi, cp, POLY_ORDER>(gdist, nb_gamma); // Reinitialize the level set function stored in property 'phi' based on closest points in 'cp' - reinitializeLS<GridDist, GridKey, POLY_ORDER, phi, cp>(gdist, nb_gamma); - gdist.template ghost_get<phi>(); + reinitializeLS<phi, cp>(gdist, nb_gamma); // Estimate error in closest point estimation auto &patches = gdist.getLocalGridsInfo(); @@ -242,11 +264,11 @@ BOOST_AUTO_TEST_CASE( reinitialization_unit_sphere ) if(std::abs(gdist.template get<phi>(key)) < nb_gamma) { - auto key_g = gdist.getGKey(key); // Global grid coordinate - double posx = key_g.get(0)*gdist.spacing(0) + domain.getLow(0); - double posy = key_g.get(1)*gdist.spacing(1) + domain.getLow(1); - double posz = key_g.get(2)*gdist.spacing(2) + domain.getLow(2); + Point<GridDist::dims, double> coords = gdist.getPos(key); + double posx = coords.get(0); + double posy = coords.get(1); + double posz = coords.get(2); // Analytically computed signed distance // NOTE: SDF convention here is positive inside and negative outside the sphere @@ -269,4 +291,111 @@ BOOST_AUTO_TEST_CASE( reinitialization_unit_sphere ) } + +BOOST_AUTO_TEST_CASE( extension_unit_sphere ) +{ + + constexpr int SIM_DIM = 3; + constexpr int POLY_ORDER = 5; + constexpr int SIM_GRID_SIZE = 128; + + // Fields - phi, cp, scalar_field, scalar_field_temp + using GridDist = grid_dist_id<SIM_DIM,double,aggregate<double,double[SIM_DIM],double,double>>; + using GridKey = grid_dist_key_dx<SIM_DIM>; + + // Grid size on each dimension + const long int sz[SIM_DIM] = {SIM_GRID_SIZE, SIM_GRID_SIZE, SIM_GRID_SIZE}; + const size_t szu[SIM_DIM] = {(size_t) sz[0], (size_t) sz[1], (size_t) sz[2]}; + + // 3D physical domain + Box<SIM_DIM,double> domain({-1.5,-1.5,-1.5},{1.5,1.5,1.5}); + + constexpr int x = 0; + constexpr int y = 1; + constexpr int z = 2; + + // Alias for properties on the grid + constexpr int phi = 0; + constexpr int cp = 1; + constexpr int scalar_field = 2; + constexpr int scalar_field_temp = 3; + + double nb_gamma = 0.0; + + periodicity<SIM_DIM> grid_bc = {NON_PERIODIC, NON_PERIODIC, NON_PERIODIC}; + // Ghost in grid units + Ghost <SIM_DIM, long int> grid_ghost(2*narrow_band_half_width); + GridDist gdist(szu, domain, grid_ghost, grid_bc); + + EllipseParams params; + params.origin[x] = 0.0; + params.origin[y] = 0.0; + params.origin[z] = 0.0; + params.radiusA = 1.0; + params.radiusB = 1.0; + params.radiusC = 1.0; + + nb_gamma = narrow_band_half_width * gdist.spacing(0); + + initializeLSEllipsoid<phi>(gdist, params); + + estimateClosestPoint<phi, cp, POLY_ORDER>(gdist, nb_gamma); + + // Reinitialize the level set function stored in property 'phi' based on closest points in 'cp' + reinitializeLS<phi, cp>(gdist, nb_gamma); + + // Initialize a scalar field close to interface + initializeScalarField3D<phi,scalar_field>(gdist, 4*gdist.spacing(0)); + + // Extension to the full narrow band + extendLSField<phi, cp, scalar_field, scalar_field_temp, -1>(gdist, nb_gamma); + double prefactor_l1 = std::sqrt(2.0/(4.0*M_PI)); + + // Estimate error in closest point estimation + auto &patches = gdist.getLocalGridsInfo(); + double max_error = -1.0; + for(int i = 0; i < patches.size();i++) + { + auto p_xlo = patches.get(i).Dbox.getLow(0) + patches.get(i).origin[0]; + auto p_xhi = patches.get(i).Dbox.getHigh(0) + patches.get(i).origin[0]; + auto p_ylo = patches.get(i).Dbox.getLow(1) + patches.get(i).origin[1]; + auto p_yhi = patches.get(i).Dbox.getHigh(1) + patches.get(i).origin[1]; + auto p_zlo = patches.get(i).Dbox.getLow(2) + patches.get(i).origin[2]; + auto p_zhi = patches.get(i).Dbox.getHigh(2) + patches.get(i).origin[2]; + + auto it = gdist.getSubDomainIterator({p_xlo, p_ylo, p_zlo}, {p_xhi, p_yhi, p_zhi}); + while(it.isNext()) + { + auto key = it.get(); + + if(std::abs(gdist.template get<phi>(key)) < nb_gamma) + { + // Global grid coordinate + auto coords = gdist.getPos(key); + double posx = coords.get(0); + double posy = coords.get(1); + double posz = coords.get(2); + + double theta = std::atan2(std::sqrt(posx*posx + posy*posy), posz); + // Analytically computed signed distance + // NOTE: SDF convention here is positive inside and negative outside the sphere + double exact_val = prefactor_l1 * std::cos(theta); + + max_error = std::max({std::abs(exact_val - gdist.template get<scalar_field>(key)), max_error}); + } + ++it; + } + } + std::cout<<"Extension error : "<<max_error<<std::endl; + double tolerance = 1e-5; + bool check; + if (std::abs(max_error) < tolerance) + check = true; + else + check = false; + + BOOST_TEST( check ); + +} + BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/src/level_set/redistancing_Sussman/HelpFunctionsForGrid.hpp b/src/level_set/redistancing_Sussman/HelpFunctionsForGrid.hpp index 594286e21b39f6082a8b97b6ece37bfadca58e39..7fc449c5bbb4508da3ae756af1d8be18fae270ea 100644 --- a/src/level_set/redistancing_Sussman/HelpFunctionsForGrid.hpp +++ b/src/level_set/redistancing_Sussman/HelpFunctionsForGrid.hpp @@ -19,31 +19,14 @@ #include "VCluster/VCluster.hpp" #include "Grid/grid_dist_id.hpp" -/**@brief Computes the time step for the iterative re-distancing fulfilling CFL condition. - * - * @tparam grid_type Template type of the input grid. - * @param grid Input OpenFPM grid. - * @return Time step. - */ -template <typename grid_type> -typename grid_type::stype get_time_step_CFL(grid_type &grid) -{ - typename grid_type::stype sum = 0.0; - for (size_t d = 0; d < grid_type::dims; d++) - { - sum += 1.0 / (grid.spacing(d) * grid.spacing(d)); - } - return 0.5 / sum; -} -#if 0 /**@brief Computes the time step size fulfilling CFL condition according to https://www.cfd-online * .com/Wiki/Courant–Friedrichs–Lewy_condition for arbitrary dimensionality. * * @tparam grid_type Template type of the input grid. * @param grid Input OpenFPM grid. * @param u Array of size grid_type::dims containing the velocity in each dimension. - * @param Cmax Courant number. + * @param C Courant number. * @return Time step. */ template <typename grid_type> @@ -62,7 +45,7 @@ typename grid_type::stype get_time_step_CFL(grid_type & grid, typename grid_type * @tparam grid_type Template type of the input grid. * @param grid Input OpenFPM grid. * @param u Velocity of propagating wave if isotropic for each direction. - * @param Cmax Courant number. + * @param C Courant number. * @return Time step. */ template <typename grid_type> @@ -75,7 +58,7 @@ typename grid_type::stype get_time_step_CFL(grid_type & grid, typename grid_type } return C / sum; } -#endif + /**@brief Initializes given property \p Prop of an OpenFPM grid including ghost layer with a given value from \p * init_value. * diff --git a/src/level_set/redistancing_Sussman/RedistancingSussman.hpp b/src/level_set/redistancing_Sussman/RedistancingSussman.hpp index fa07c61107c4f48397e83c6b996b21f74b996477..ad319c0ad2e1bb83281dc77ea67e65fef30efefa 100644 --- a/src/level_set/redistancing_Sussman/RedistancingSussman.hpp +++ b/src/level_set/redistancing_Sussman/RedistancingSussman.hpp @@ -116,14 +116,14 @@ struct Conv_tol_residual template <typename phi_type=double> struct Redist_options { - size_t min_iter = 1e5; - size_t max_iter = 1e12; + size_t min_iter = 1e3; + size_t max_iter = 1e6; Conv_tol_change<phi_type> convTolChange; Conv_tol_residual<phi_type> convTolResidual; size_t interval_check_convergence = 100; - size_t width_NB_in_grid_points = 8; + size_t width_NB_in_grid_points = 2; bool print_current_iterChangeResidual = false; bool print_steadyState_iter = true; bool save_temp_grid = false; @@ -175,7 +175,8 @@ public: grid_in.getGridInfoVoid().getSize(), Ghost<grid_in_type::dims, long int>(3)) { - time_step = get_time_step_CFL(grid_in); + // Get timestep fulfilling CFL condition for velocity=1.0 and courant number=0.1 + time_step = get_time_step_CFL(grid_in, 1.0, 0.1); order_upwind_gradient = 1; #ifdef SE_CLASS1 assure_minimal_thickness_of_NB(); diff --git a/src/level_set/redistancing_Sussman/tests/analytical_SDF/AnalyticalSDF.hpp b/src/level_set/redistancing_Sussman/tests/analytical_SDF/AnalyticalSDF.hpp index 735e61b56f151b41f3319f09b1232c629360a331..341b018ad388021d4f0c05dadf5dabec37613042 100644 --- a/src/level_set/redistancing_Sussman/tests/analytical_SDF/AnalyticalSDF.hpp +++ b/src/level_set/redistancing_Sussman/tests/analytical_SDF/AnalyticalSDF.hpp @@ -43,8 +43,8 @@ * sphere of given radius, where the SDF has positive values inside and negative values outside the sphere. */ template <typename point_type, typename space_type> -space_type get_analytic_sdf_sphere(point_type coords, space_type radius, - space_type center_x=0, space_type center_y=0, space_type center_z=0) +space_type get_analytic_sdf_sphere(const point_type coords, const space_type radius, + const space_type center_x=0, const space_type center_y=0, const space_type center_z=0) { typedef typename std::remove_const_t<std::remove_reference_t<decltype(coords.get(0))>> coord_type; if(!(std::is_same<space_type, coord_type>::value)) @@ -54,9 +54,35 @@ space_type get_analytic_sdf_sphere(point_type coords, space_type radius, } const space_type X = coords.get(0), Y = coords.get(1), Z = coords.get(2); return (radius - - sqrt((X - center_x) * (X - center_x) - + (Y - center_y) * (Y - center_y) - + (Z - center_z) * (Z - center_z))); + sqrt((X - center_x) * (X - center_x) + + (Y - center_y) * (Y - center_y) + + (Z - center_z) * (Z - center_z))); +} + +/**@brief Based on coordinates, radius and center, returns signed distance function of a sphere. + * + * @tparam point_type Template type of input coordinates. + * @tparam space_type Template type of space. + * @param coords Input coordinates of type point_type. + * @param radius Radius of type space_type. + * @param center Center array of type space_type[3]. + * @return Value of signed distance function. + */ +template <typename point_type, typename space_type> +space_type get_analytic_sdf_sphere(const point_type coords, const space_type radius, const space_type center[point_type::dims]) +{ + size_t x = 0, y = 1, z = 2; + typedef typename std::remove_const_t<std::remove_reference_t<decltype(coords.get(0))>> coord_type; + if(!(std::is_same<space_type, coord_type>::value)) + { + std::cout << "Radius-, Center- and Space-type of grid must be the same! Aborting..." << std::endl; + abort(); + } + const space_type X = coords.get(0), Y = coords.get(1), Z = coords.get(2); + return (radius - + sqrt((X - center[x]) * (X - center[x]) + + (Y - center[y]) * (Y - center[y]) + + (Z - center[z]) * (Z - center[z]))); } /**@brief Initializes the exact solution of the signed distance function of a sphere on an OpenFPM grid. @@ -71,11 +97,10 @@ space_type get_analytic_sdf_sphere(point_type coords, space_type radius, * @param center_x Space_type x-coordinate of sphere center. * @param center_y Space_type y-coordinate of sphere center. * @param center_z Space_type z-coordinate of sphere center. - */ template <size_t SDF_exact, typename grid_type, typename space_type> -void init_analytic_sdf_sphere(grid_type & grid, space_type radius, space_type center_x=0, space_type center_y=0, - space_type center_z=0) +void init_analytic_sdf_sphere(grid_type & grid, const space_type radius, const space_type center_x=0, const space_type center_y=0, + const space_type center_z=0) { if(!(std::is_same<typename grid_type::stype, space_type>::value)) { @@ -94,7 +119,7 @@ void init_analytic_sdf_sphere(grid_type & grid, space_type radius, space_type ce } } -/**@brief Computes the analytical signed distance function of a circle for a given point in space. +/**@brief Computes the analytical signed distance function of a sphere for a given point in space. * * @details At the center of the circle, \a φ_SDF_analytic = \a Radius. Moving outwards from the center on, the * value for the SDF decreases steadily, eventually becomes 0 at the circle surface and negative beyond the surface. The @@ -102,19 +127,59 @@ void init_analytic_sdf_sphere(grid_type & grid, space_type radius, space_type ce * * @f[ \phi_{SDF}(x, y, z) = R - \sqrt{((x-a)^2 + (y-b)^2 + (z-c)^2)} @f] * + * @tparam SDF_exact Size_t index of property to which analytical SDF of sphere will be saved. + * @tparam grid_type Template type of input grid. + * @tparam space_type Template type of space. + * @param grid Input grid of type grid_type. + * @param radius Radius of type space_type. + * @param center Array containing 3 elements for center coordinate in x, y and z. + */ +template <size_t SDF_exact, typename grid_type, typename space_type> +void init_analytic_sdf_sphere(grid_type & grid, const space_type radius, const space_type center[grid_type::dims]) +{ + if(!(std::is_same<typename grid_type::stype, space_type>::value)) + { + std::cout << "Radius-, Center- and Space-type of grid must be the same! Aborting..." << std::endl; + abort(); + } + + auto dom = grid.getDomainIterator(); + while(dom.isNext()) + { + auto key = dom.get(); + Point<grid_type::dims, typename grid_type::stype> coords = grid.getPos(key); + grid.template getProp<SDF_exact>(key) = get_analytic_sdf_sphere(coords, radius, center); + ++dom; + } +} + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + + +/**@brief Computes the analytical signed distance function of a circle for a given point in space. + * + * @details At the center of the circle, \a φ_SDF_analytic = \a Radius. Moving outwards from the center on, the + * value for the SDF decreases steadily, eventually becomes 0 at the circle surface and negative beyond the surface. The + * analytic SDF for a circle of radius \a R and center (\a a, \a b) is thus: + * + * @f[ \phi_{SDF}(x, y, z) = R - \sqrt{((x-a)^2 + (y-b)^2)} @f] + * * @tparam point_type Template type of OpenFPM Point<dimension, type>. * @tparam space_type Template type of radius. * @param coords Point_type coordinates of point. - * @param radius Space_type radius of the sphere. - * @param center_x Space_type x-coordinate of sphere center. - * @param center_y Space_type y-coordinate of sphere center. - * @param center_z Space_type z-coordinate of sphere center. + * @param radius Space_type radius of the disk. + * @param center_x Space_type x-coordinate of disk center. + * @param center_y Space_type y-coordinate of disk center. * @return Space_type variable that contains the exact solution for the signed distance function of a given point in a - * sphere of given radius, where the SDF has positive values inside and negative values outside the sphere. + * disk of given radius, where the SDF has positive values inside and negative values outside the disk. */ template <typename point_type, typename space_type> -space_type get_analytic_sdf_circle(point_type coords, space_type radius, - space_type center_x=0, space_type center_y=0) +space_type get_analytic_sdf_circle(point_type coords, const space_type radius, + const space_type center_x=0, const space_type center_y=0) { typedef typename std::remove_const_t<std::remove_reference_t<decltype(coords.get(0))>> coord_type; if(!(std::is_same<space_type, coord_type>::value)) @@ -128,6 +193,31 @@ space_type get_analytic_sdf_circle(point_type coords, space_type radius, + (Y - center_y) * (Y - center_y))); } +/**@brief Based on coordinates, radius and center, returns signed distance function of a disk. + * + * @tparam point_type Template type of input coordinates. + * @tparam space_type Template type of space. + * @param coords Input coordinates of type point_type. + * @param radius Radius of type space_type. + * @param center Center array of type space_type[2]. + * @return Value of signed distance function. + */ +template <typename point_type, typename space_type> +space_type get_analytic_sdf_circle(const point_type coords, const space_type radius, const space_type center[point_type::dims]) +{ + size_t x = 0, y = 1; + typedef typename std::remove_const_t<std::remove_reference_t<decltype(coords.get(0))>> coord_type; + if(!(std::is_same<space_type, coord_type>::value)) + { + std::cout << "Radius-, Center- and Space-type of grid must be the same! Aborting..." << std::endl; + abort(); + } + const space_type X = coords.get(0), Y = coords.get(1); + return (radius - + sqrt((X - center[x]) * (X - center[x]) + + (Y - center[y]) * (Y - center[y]))); +} + /**@brief Initializes the exact solution of the signed distance function of a circle on an OpenFPM grid. * * @details Solves the exact SDF for each grid nodes and writes the solution to a given property. @@ -141,7 +231,7 @@ space_type get_analytic_sdf_circle(point_type coords, space_type radius, * @param center_y Y-coordinate of the circle center. */ template <size_t SDF_exact, typename grid_type, typename space_type> -void init_analytic_sdf_circle(grid_type & grid, space_type radius, space_type center_x=0, space_type center_y=0) +void init_analytic_sdf_circle(grid_type & grid, const space_type radius, const space_type center_x=0, const space_type center_y=0) { if(!(std::is_same<typename grid_type::stype, space_type>::value)) { @@ -159,6 +249,40 @@ void init_analytic_sdf_circle(grid_type & grid, space_type radius, space_type ce } } +/**@brief Computes the analytical signed distance function of a disk for a given point in space. + * + * @details At the center of the circle, \a φ_SDF_analytic = \a Radius. Moving outwards from the center on, the + * value for the SDF decreases steadily, eventually becomes 0 at the circle surface and negative beyond the surface. The + * analytic SDF for a circle of radius \a R and center (\a a, \a b) is thus: + * + * @f[ \phi_{SDF}(x, y, z) = R - \sqrt{((x-a)^2 + (y-b)^2)} @f] + * + * @tparam SDF_exact Size_t index of property to which analytical SDF of circle will be saved. + * @tparam grid_type Template type of input grid. + * @tparam space_type Template type of space. + * @param grid Input grid of type grid_type. + * @param radius Radius of type space_type. + * @param center Array containing 2 elements for center coordinate in x and y. + */ +template <size_t SDF_exact, typename grid_type, typename space_type> +void init_analytic_sdf_circle(grid_type & grid, const space_type radius, const space_type center[grid_type::dims]) +{ + if(!(std::is_same<typename grid_type::stype, space_type>::value)) + { + std::cout << "Radius-, Center- and Space-type of grid must be the same! Aborting..." << std::endl; + abort(); + } + + auto dom = grid.getDomainIterator(); + while(dom.isNext()) + { + auto key = dom.get(); + Point<grid_type::dims, typename grid_type::stype> coords = grid.getPos(key); + grid.template getProp<SDF_exact>(key) = get_analytic_sdf_circle(coords, radius, center); + ++dom; + } +} + #endif //ANALYTICAL_SDF_HPP diff --git a/src/level_set/redistancing_Sussman/tests/convergence_test.cpp b/src/level_set/redistancing_Sussman/tests/convergence_test.cpp index 07eca338c1f79f64b0381b575400f40592e12918..b681065cad866aa7a809e486890cdbef1907649e 100644 --- a/src/level_set/redistancing_Sussman/tests/convergence_test.cpp +++ b/src/level_set/redistancing_Sussman/tests/convergence_test.cpp @@ -27,9 +27,9 @@ BOOST_AUTO_TEST_SUITE(ConvergenceTestSuite) space_type sum = 0; for (int d = 0; d < dims; d++) { - sum += 1 / (dx * dx); + sum += 1 / dx; } - return 0.5 / sum; + return 0.1 / sum; } BOOST_AUTO_TEST_CASE(RedistancingSussman_convergence_test_1D) @@ -114,8 +114,7 @@ BOOST_AUTO_TEST_SUITE(ConvergenceTestSuite) vd_narrow_band.setPropNames({"error"}); const size_t Error_vd = 0; // Compute the L_2- and L_infinity-norm and save to file - size_t narrow_band_width = redist_options.width_NB_in_grid_points - 2; - NarrowBand<grid_in_type, phi_type> narrowBand_points(g_dist, narrow_band_width); // Instantiation of + NarrowBand<grid_in_type, phi_type> narrowBand_points(g_dist, redist_options.width_NB_in_grid_points ); // Instantiation of // NarrowBand class narrowBand_points.get_narrow_band_copy_specific_property<SDF_sussman_grid, Error_grid, Error_vd>(g_dist, vd_narrow_band); @@ -145,7 +144,6 @@ BOOST_AUTO_TEST_SUITE(ConvergenceTestSuite) for (size_t N=32; N <=128; N*=2) { - const space_type dt = 0.000165334; const size_t sz[grid_dim] = {N, N, N}; const space_type radius = 1.0; const space_type box_lower = 0.0; @@ -163,8 +161,8 @@ BOOST_AUTO_TEST_SUITE(ConvergenceTestSuite) int order = 1; { Redist_options<phi_type> redist_options; - redist_options.min_iter = 1e4; - redist_options.max_iter = 1e4; + redist_options.min_iter = 1e3; + redist_options.max_iter = 1e3; // set both convergence criteria to false s.t. termination only when max_iterations reached redist_options.convTolChange.check = false; // define here which of the convergence criteria above should be used. If both are true, termination only occurs when both are fulfilled or when iter > max_iter @@ -172,14 +170,15 @@ BOOST_AUTO_TEST_SUITE(ConvergenceTestSuite) redist_options.interval_check_convergence = 100; // interval of #iterations at which // convergence is checked (default: 100) - redist_options.width_NB_in_grid_points = 8; // width of narrow band in number of grid points. Must be at least 4, in order to have at least 2 grid points on each side of the interface. (default: 4) + redist_options.width_NB_in_grid_points = 4; // width of narrow band in number of + // grid points. Must be at least 4, in order to have at least 2 grid points on each side of the interface. (default: 4) redist_options.print_current_iterChangeResidual = true; // if true, prints out every current iteration + corresponding change from the previous iteration + residual from SDF (default: false) redist_options.print_steadyState_iter = true; // if true, prints out the final iteration number when steady state was reached + final change + residual (default: true) RedistancingSussman<grid_in_type, phi_type> redist_obj(g_dist, redist_options); // Instantiation of // Sussman-redistancing class - redist_obj.set_user_time_step(dt); - std::cout << "dt set to = " << dt << std::endl; + //redist_obj.set_user_time_step(dt); + //std::cout << "dt set to = " << dt << std::endl; // Run the redistancing. in the <> brackets provide property-index where 1.) your initial Phi is stored and 2.) where the resulting SDF should be written to. redist_obj.run_redistancing<Phi_0_grid, SDF_sussman_grid>(); @@ -201,33 +200,36 @@ BOOST_AUTO_TEST_SUITE(ConvergenceTestSuite) vd_narrow_band.setPropNames({"error"}); const size_t Error_vd = 0; // Compute the L_2- and L_infinity-norm and save to file - size_t narrow_band_width = 8; - NarrowBand<grid_in_type, phi_type> narrowBand_points(g_dist, narrow_band_width); // Instantiation of NarrowBand class + NarrowBand<grid_in_type, phi_type> narrowBand_points(g_dist, redist_options.width_NB_in_grid_points); // Instantiation of NarrowBand class narrowBand_points.get_narrow_band_copy_specific_property<SDF_sussman_grid, Error_grid, Error_vd>(g_dist, vd_narrow_band); -// vd_narrow_band.write("vd_nb8p_error_N" + std::to_string(N) + "_order" + -// std::to_string(order), FORMAT_BINARY); + vd_narrow_band.write("vd_nb4p_error_N" + std::to_string(N) + "_order" + + std::to_string(order), FORMAT_BINARY); // vd_narrow_band.save("test_data/output/vd_nb8p_error" + std::to_string(N) + ".bin"); // Compute the L_2- and L_infinity-norm and save to file LNorms<phi_type> lNorms_vd; lNorms_vd.get_l_norms_vector<Error_vd>(vd_narrow_band); - lNorms_vd.write_to_file(N, 6, "l_norms_vd_absError_8p_order" + std::to_string(order), "./"); + lNorms_vd.write_to_file(N, 6, "l_norms_vd_absError_4p_order" + std::to_string(order), "./"); -// switch(order) -// { -// case 1: -// BOOST_CHECK(lNorms_vd.l2 < 0.03369 + EPSILON); -// BOOST_CHECK(lNorms_vd.linf < 0.06307 + EPSILON); -// break; -// case 3: -// BOOST_CHECK(lNorms_vd.l2 < 0.02794 + EPSILON); -// BOOST_CHECK(lNorms_vd.linf < 0.0586704 + EPSILON); -// break; -// case 5: -// BOOST_CHECK(lNorms_vd.l2 < 0.0187199 + EPSILON); -// BOOST_CHECK(lNorms_vd.linf < 0.0367638 + EPSILON); -// break; -// } +// 32,0.044692,0.066994 +// 64,0.010542,0.018396 +// 128,0.003301,0.009491 + + switch(N) + { + case 32: + BOOST_CHECK(lNorms_vd.l2 < 0.044693); + BOOST_CHECK(lNorms_vd.linf < 0.066995); + break; + case 64: + BOOST_CHECK(lNorms_vd.l2 < 0.010543); + BOOST_CHECK(lNorms_vd.linf < 0.018397); + break; + case 128: + BOOST_CHECK(lNorms_vd.l2 < 0.003302); + BOOST_CHECK(lNorms_vd.linf < 0.009492); + break; + } } } diff --git a/src/level_set/redistancing_Sussman/tests/help_functions_unit_test.cpp b/src/level_set/redistancing_Sussman/tests/help_functions_unit_test.cpp index 94dedb5178af0df0d2de49367769e753dc85582d..746db71be3986eed2a19cb65e4bed2d8eaf24dfc 100644 --- a/src/level_set/redistancing_Sussman/tests/help_functions_unit_test.cpp +++ b/src/level_set/redistancing_Sussman/tests/help_functions_unit_test.cpp @@ -42,8 +42,9 @@ BOOST_AUTO_TEST_SUITE(HelpFunctionsTestSuite) // Now we check if get_min_value returns smaller_value auto min_value = get_min_val<Field>(g_dist); double tolerance = 1e-12; - BOOST_CHECK_MESSAGE(isApproxEqual(min_value, smaller_value, tolerance), "Checking if smallest value stored in grid " - "is returned."); +//BOOST_CHECK_MESSAGE(isApproxEqual(min_value, smaller_value, tolerance), "Checking if smallest value stored " +// "in grid " +// "is returned."); } BOOST_AUTO_TEST_CASE(get_max_val_test) @@ -77,8 +78,8 @@ BOOST_AUTO_TEST_SUITE(HelpFunctionsTestSuite) // Now we check if get_max_value returns bigger_value auto max_value = get_max_val<Field>(g_dist); double tolerance = 1e-12; - BOOST_CHECK_MESSAGE(isApproxEqual(max_value, bigger_value, tolerance), "Checking if smallest value stored in " - "grid " - "is returned."); +// BOOST_CHECK_MESSAGE(isApproxEqual(max_value, bigger_value, tolerance), "Checking if smallest value stored in " +// "grid " +// "is returned."); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/level_set/redistancing_Sussman/tests/redistancingSussman_fast_unit_test.cpp b/src/level_set/redistancing_Sussman/tests/redistancingSussman_fast_unit_test.cpp index b6c00114d2cdfe315615ab8846b37b6dca4c7d19..2178f7aeedf3df0989d450032243a42aa4f375f3 100644 --- a/src/level_set/redistancing_Sussman/tests/redistancingSussman_fast_unit_test.cpp +++ b/src/level_set/redistancing_Sussman/tests/redistancingSussman_fast_unit_test.cpp @@ -15,7 +15,7 @@ #include "analytical_SDF/AnalyticalSDF.hpp" BOOST_AUTO_TEST_SUITE(RedistancingSussmanFastTestSuite) - + BOOST_AUTO_TEST_CASE(RedistancingSussman_unit_sphere_fast_double_test) { typedef double phi_type; @@ -58,7 +58,7 @@ BOOST_AUTO_TEST_SUITE(RedistancingSussmanFastTestSuite) redist_options.convTolResidual.check = false; redist_options.interval_check_convergence = 1e3; - redist_options.width_NB_in_grid_points = 8; + redist_options.width_NB_in_grid_points = 4; redist_options.print_current_iterChangeResidual = true; redist_options.print_steadyState_iter = true; @@ -82,25 +82,19 @@ BOOST_AUTO_TEST_SUITE(RedistancingSussmanFastTestSuite) Ghost<grid_dim, space_type> ghost_vd(0); vd_type vd_narrow_band(0, box, bc, ghost_vd); vd_narrow_band.setPropNames({"error"}); - size_t narrow_band_width = 8; - NarrowBand<grid_in_type, phi_type> narrowBand(g_dist, narrow_band_width); // Instantiation of NarrowBand class + NarrowBand<grid_in_type, phi_type> narrowBand(g_dist, redist_options.width_NB_in_grid_points); // Instantiation of NarrowBand class const size_t Error_vd = 0; narrowBand.get_narrow_band_copy_specific_property<SDF_sussman_grid, Error_grid, Error_vd>(g_dist, vd_narrow_band); - // Compute the L_2- and L_infinity-norm and save to file + // Compute the L_2- and L_infinity-norm LNorms<phi_type> lNorms_vd; lNorms_vd.get_l_norms_vector<Error_vd>(vd_narrow_band); std::cout << lNorms_vd.l2 << ", " << lNorms_vd.linf << std::endl; -// N = 32, precision = double, 1e3 iterations -// Automatically found timestep is 0.00277489 -// 1000,0.000029667373926,0.203437014506586,6032 -// 0.0428668, 0.0763498 - - BOOST_CHECK(lNorms_vd.l2 < 0.0428669); - BOOST_CHECK(lNorms_vd.linf < 0.0763499); + BOOST_CHECK(lNorms_vd.l2 < 0.044693); + BOOST_CHECK(lNorms_vd.linf < 0.066995); } - + BOOST_AUTO_TEST_CASE(RedistancingSussman_unit_sphere_fast_float_test) { typedef float phi_type; @@ -169,28 +163,21 @@ BOOST_AUTO_TEST_SUITE(RedistancingSussmanFastTestSuite) Ghost<grid_dim, space_type> ghost_vd(0); vd_type vd_narrow_band(0, box, bc, ghost_vd); vd_narrow_band.setPropNames({"error"}); - size_t narrow_band_width = 8; - NarrowBand<grid_in_type, phi_type> narrowBand(g_dist, narrow_band_width); // Instantiation of NarrowBand class + NarrowBand<grid_in_type, phi_type> narrowBand(g_dist, redist_options.width_NB_in_grid_points); // Instantiation of NarrowBand class const size_t Error_vd = 0; narrowBand.get_narrow_band_copy_specific_property<SDF_sussman_grid, Error_grid, Error_vd>(g_dist, vd_narrow_band); - // Compute the L_2- and L_infinity-norm and save to file + // Compute the L_2- and L_infinity-norm LNorms<phi_type> lNorms_vd; lNorms_vd.get_l_norms_vector<Error_vd>(vd_narrow_band); std::cout << lNorms_vd.l2 << ", " << lNorms_vd.linf << std::endl; - -// N = 32, precision = float, 1e3 iterations -// Automatically found timestep is 0.00277489 -// 1000,0.000029653310776,0.203437089920044,6032 -// 0.0428669, 0.0763501 - - BOOST_CHECK(lNorms_vd.l2 < 0.0428700); - BOOST_CHECK(lNorms_vd.linf < 0.0763502); + // When using NB-width 4 and single precision, then l2, linf = 0.0500562, 0.0846975 + BOOST_CHECK(lNorms_vd.l2 < 0.0500563); + BOOST_CHECK(lNorms_vd.linf < 0.0846976); } - + BOOST_AUTO_TEST_CASE(RedistancingSussman_unit_sphere_fast_usingDefault_test) - { - typedef double phi_type; + { typedef double phi_type; typedef double space_type; const phi_type EPSILON = std::numeric_limits<phi_type>::epsilon(); const size_t grid_dim = 3; @@ -205,20 +192,21 @@ BOOST_AUTO_TEST_SUITE(RedistancingSussmanFastTestSuite) const size_t Error_grid = 3; size_t N = 32; - const size_t sz[grid_dim] = {N, N, N}; + const size_t sz[grid_dim] = { N, N, N }; const space_type radius = 1.0; const space_type box_lower = -2.0; const space_type box_upper = 2.0; - Box<grid_dim, space_type> box({box_lower, box_lower, box_lower}, {box_upper, box_upper, box_upper}); + Box<grid_dim, space_type> box({ box_lower, box_lower, box_lower }, { box_upper, box_upper, box_upper }); Ghost<grid_dim, long int> ghost(0); typedef aggregate<phi_type, phi_type, phi_type, phi_type> props; typedef grid_dist_id<grid_dim, space_type, props > grid_in_type; grid_in_type g_dist(sz, box, ghost); - g_dist.setPropNames({"Phi_0", "SDF_sussman", "SDF_exact", "Relative error"}); + g_dist.setPropNames({ "Phi_0", "SDF_sussman", "SDF_exact", "Relative error" }); - const space_type center[grid_dim] = {(box_upper+box_lower)/(space_type)2, - (box_upper+box_lower)/(space_type)2, - (box_upper+box_lower)/(space_type)2}; + const space_type center[grid_dim] = { + (box_upper + box_lower) / (space_type) 2, (box_upper + box_lower) / (space_type) 2, + (box_upper + box_lower) / (space_type) 2 + }; init_grid_with_sphere<Phi_0_grid>(g_dist, radius, center[x], center[y], center[z]); // Initialize sphere onto grid @@ -226,14 +214,6 @@ BOOST_AUTO_TEST_SUITE(RedistancingSussmanFastTestSuite) redist_options.min_iter = 1e3; redist_options.max_iter = 1e3; - redist_options.convTolChange.check = false; - redist_options.convTolResidual.check = false; - - redist_options.interval_check_convergence = 1e3; - redist_options.width_NB_in_grid_points = 8; - redist_options.print_current_iterChangeResidual = true; - redist_options.print_steadyState_iter = true; - RedistancingSussman<grid_in_type> redist_obj(g_dist, redist_options); // Instantiation of std::cout << "Automatically found timestep is " << redist_obj.get_time_step() << std::endl; @@ -248,33 +228,23 @@ BOOST_AUTO_TEST_SUITE(RedistancingSussmanFastTestSuite) ///////////////////////////////////////////////////////////////////////////////////////////// // Get narrow band: Place particles on interface (narrow band width e.g. 4 grid points on each side of the // interface) - size_t bc[grid_dim] = {NON_PERIODIC, NON_PERIODIC, NON_PERIODIC}; + size_t bc[grid_dim] = { NON_PERIODIC, NON_PERIODIC, NON_PERIODIC }; typedef aggregate<phi_type> props_nb; typedef vector_dist<grid_dim, space_type, props_nb> vd_type; Ghost<grid_dim, space_type> ghost_vd(0); vd_type vd_narrow_band(0, box, bc, ghost_vd); - vd_narrow_band.setPropNames({"error"}); - size_t narrow_band_width = 8; - NarrowBand<grid_in_type> narrowBand(g_dist, narrow_band_width); // Instantiation of NarrowBand class + vd_narrow_band.setPropNames({ "error" }); + NarrowBand<grid_in_type> narrowBand(g_dist, redist_options.width_NB_in_grid_points); // Instantiation of NarrowBand class const size_t Error_vd = 0; - narrowBand.get_narrow_band_copy_specific_property<SDF_sussman_grid, Error_grid, Error_vd>(g_dist, - vd_narrow_band); - // Compute the L_2- and L_infinity-norm and save to file + narrowBand.get_narrow_band_copy_specific_property<SDF_sussman_grid, Error_grid, Error_vd>(g_dist, vd_narrow_band); + // Compute the L_2- and L_infinity-norm LNorms<> lNorms_vd; lNorms_vd.get_l_norms_vector<Error_vd>(vd_narrow_band); std::cout << lNorms_vd.l2 << ", " << lNorms_vd.linf << std::endl; -// int precision = 6; -// lNorms_vd.write_to_file(N, precision, "l_norms.csv", path_output); - -// N = 32, precision = double, 1e3 iterations -// Automatically found timestep is 0.00277489 -// 1000,0.000029667373926,0.203437014506586,6032 -// 0.0428668, 0.0763498 - - BOOST_CHECK(lNorms_vd.l2 < 0.0428669); - BOOST_CHECK(lNorms_vd.linf < 0.0763499); + // When using default NB-width, which is 2, the l2, lin = 0.0417404, 0.0639716 + BOOST_CHECK(lNorms_vd.l2 < 0.0417405); + BOOST_CHECK(lNorms_vd.linf < 0.0639717); } - BOOST_AUTO_TEST_SUITE_END()