mirror of
https://github.com/NGSolve/netgen.git
synced 2024-12-24 21:10:33 +05:00
Merge remote-tracking branch 'origin/master' into rules_files_not_matching_cpp
This commit is contained in:
commit
4592123f68
@ -15,8 +15,8 @@ push_github_sourceforge:
|
|||||||
- git remote update
|
- git remote update
|
||||||
- git checkout master
|
- git checkout master
|
||||||
- git pull origin master
|
- git pull origin master
|
||||||
- git push sourceforge master
|
- git push sourceforge master --tags
|
||||||
- git push github master
|
- git push github master --tags
|
||||||
only:
|
only:
|
||||||
- master
|
- master
|
||||||
|
|
||||||
@ -55,6 +55,8 @@ build_win:
|
|||||||
cmake %SRC_DIR%
|
cmake %SRC_DIR%
|
||||||
-G Ninja
|
-G Ninja
|
||||||
-DCMAKE_INSTALL_PREFIX=%INSTALL_DIR%
|
-DCMAKE_INSTALL_PREFIX=%INSTALL_DIR%
|
||||||
|
-DCHECK_RANGE=ON
|
||||||
|
-DUSE_CGNS=ON
|
||||||
-DUSE_OCC=ON
|
-DUSE_OCC=ON
|
||||||
-DOCC_LIBRARY=C:/install_opencascade_7.4.0_static/win64/vc14/lib/TKernel.lib
|
-DOCC_LIBRARY=C:/install_opencascade_7.4.0_static/win64/vc14/lib/TKernel.lib
|
||||||
-DOCC_INCLUDE_DIR=C:/install_opencascade_7.4.0_static/inc
|
-DOCC_INCLUDE_DIR=C:/install_opencascade_7.4.0_static/inc
|
||||||
@ -68,6 +70,7 @@ test_win:
|
|||||||
<<: *win
|
<<: *win
|
||||||
stage: test
|
stage: test
|
||||||
script:
|
script:
|
||||||
|
- pip install pytest-check
|
||||||
- cd tests\pytest
|
- cd tests\pytest
|
||||||
- cd %NETGEN_BUILD_DIR%\netgen
|
- cd %NETGEN_BUILD_DIR%\netgen
|
||||||
- ctest -C Release -V --output-on-failure
|
- ctest -C Release -V --output-on-failure
|
||||||
@ -237,11 +240,13 @@ build_mac:
|
|||||||
cmake $SRC_DIR
|
cmake $SRC_DIR
|
||||||
-DCMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX
|
-DCMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX
|
||||||
-DCMAKE_BUILD_TYPE=Release
|
-DCMAKE_BUILD_TYPE=Release
|
||||||
|
-DCHECK_RANGE=ON
|
||||||
-DUSE_NATIVE_ARCH=OFF
|
-DUSE_NATIVE_ARCH=OFF
|
||||||
-DUSE_CCACHE=ON
|
-DUSE_CCACHE=ON
|
||||||
-DENABLE_UNIT_TESTS=ON
|
-DENABLE_UNIT_TESTS=ON
|
||||||
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.12
|
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.12
|
||||||
-DCMAKE_OSX_SYSROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
|
-DCMAKE_OSX_SYSROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
|
||||||
|
-DUSE_CGNS=ON
|
||||||
-DUSE_OCC=ON
|
-DUSE_OCC=ON
|
||||||
-DOCC_LIBRARY=/usr/local/opt/opencascade-7.4.0/lib/libTKernel.a
|
-DOCC_LIBRARY=/usr/local/opt/opencascade-7.4.0/lib/libTKernel.a
|
||||||
-DOCC_INCLUDE_DIR=/usr/local/opt/opencascade-7.4.0/include/opencascade
|
-DOCC_INCLUDE_DIR=/usr/local/opt/opencascade-7.4.0/include/opencascade
|
||||||
|
@ -14,9 +14,12 @@ option( USE_NATIVE_ARCH "build for native cpu architecture" ON)
|
|||||||
option( USE_GUI "don't build netgen with GUI" ON )
|
option( USE_GUI "don't build netgen with GUI" ON )
|
||||||
option( USE_PYTHON "build with python interface" ON )
|
option( USE_PYTHON "build with python interface" ON )
|
||||||
option( USE_MPI "enable mpi parallelization" OFF )
|
option( USE_MPI "enable mpi parallelization" OFF )
|
||||||
|
option( USE_MPI4PY "enable mpi4py interface" ON )
|
||||||
option( USE_OCC "(not supported) compile with OpenCascade geometry kernel" OFF)
|
option( USE_OCC "(not supported) compile with OpenCascade geometry kernel" OFF)
|
||||||
option( USE_JPEG "enable snapshots using library libjpeg" OFF )
|
option( USE_JPEG "enable snapshots using library libjpeg" OFF )
|
||||||
option( USE_MPEG "enable video recording with FFmpeg, uses libavcodec" OFF )
|
option( USE_MPEG "enable video recording with FFmpeg, uses libavcodec" OFF )
|
||||||
|
option( USE_CGNS "enable CGNS file read/write support" OFF )
|
||||||
|
option( USE_NUMA "compile with NUMA-aware code")
|
||||||
option( INTEL_MIC "cross compile for intel xeon phi")
|
option( INTEL_MIC "cross compile for intel xeon phi")
|
||||||
option( INSTALL_PROFILES "install environment variable settings to /etc/profile.d" OFF )
|
option( INSTALL_PROFILES "install environment variable settings to /etc/profile.d" OFF )
|
||||||
option( USE_CCACHE "use ccache")
|
option( USE_CCACHE "use ccache")
|
||||||
@ -30,11 +33,12 @@ option( BUILD_STUB_FILES "Build stub files for better autocompletion" ON)
|
|||||||
option( BUILD_FOR_CONDA "Link python libraries only to executables" OFF)
|
option( BUILD_FOR_CONDA "Link python libraries only to executables" OFF)
|
||||||
|
|
||||||
option( USE_SUPERBUILD "use ccache" ON)
|
option( USE_SUPERBUILD "use ccache" ON)
|
||||||
|
option( TRACE_MEMORY "Enable memory tracing" OFF)
|
||||||
|
|
||||||
|
set(NG_COMPILE_FLAGS "" CACHE STRING "Additional compile flags")
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_modules")
|
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_modules")
|
||||||
|
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set(INSTALL_DIR_DEFAULT /Applications/Netgen.app)
|
set(INSTALL_DIR_DEFAULT /Applications/Netgen.app)
|
||||||
else(APPLE)
|
else(APPLE)
|
||||||
@ -50,14 +54,14 @@ if(INSTALL_DIR)
|
|||||||
set(INSTALL_DIR_DEFAULT ${INSTALL_DIR})
|
set(INSTALL_DIR_DEFAULT ${INSTALL_DIR})
|
||||||
endif(INSTALL_DIR)
|
endif(INSTALL_DIR)
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX AND USE_SUPERBUILD)
|
||||||
message("Checking for write permissions in install directory...")
|
message("Checking for write permissions in install directory...")
|
||||||
execute_process(COMMAND mkdir -p ${CMAKE_INSTALL_PREFIX})
|
execute_process(COMMAND mkdir -p ${CMAKE_INSTALL_PREFIX})
|
||||||
execute_process(COMMAND test -w ${CMAKE_INSTALL_PREFIX} RESULT_VARIABLE res)
|
execute_process(COMMAND test -w ${CMAKE_INSTALL_PREFIX} RESULT_VARIABLE res)
|
||||||
if(res)
|
if(res)
|
||||||
message(WARNING "No write access at install directory, please set correct permissions")
|
message(WARNING "No write access at install directory, please set correct permissions")
|
||||||
endif()
|
endif()
|
||||||
endif(UNIX)
|
endif(UNIX AND USE_SUPERBUILD)
|
||||||
|
|
||||||
if (USE_SUPERBUILD)
|
if (USE_SUPERBUILD)
|
||||||
project (SUPERBUILD)
|
project (SUPERBUILD)
|
||||||
@ -76,12 +80,10 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(NETGEN_VERSION_MAJOR 6)
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||||
set(NETGEN_VERSION_MINOR 2)
|
|
||||||
string(TIMESTAMP NETGEN_VERSION_PATCH "%y%U%w" )
|
include (${CMAKE_CURRENT_LIST_DIR}/cmake/generate_version_file.cmake)
|
||||||
set(NETGEN_VERSION "${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}-dev")
|
set(CPACK_PACKAGE_VERSION "${NETGEN_VERSION}")
|
||||||
set(PACKAGE_VERSION "${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}-${NETGEN_VERSION_PATCH}")
|
|
||||||
set(CPACK_PACKAGE_VERSION "${PACKAGE_VERSION}")
|
|
||||||
|
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
@ -193,7 +195,6 @@ check_include_files (dlfcn.h HAVE_DLFCN_H)
|
|||||||
if(HAVE_DLFCN_H)
|
if(HAVE_DLFCN_H)
|
||||||
add_definitions(-DHAVE_DLFCN_H)
|
add_definitions(-DHAVE_DLFCN_H)
|
||||||
endif()
|
endif()
|
||||||
add_definitions(-DNETGEN_VERSION="${NETGEN_VERSION}")
|
|
||||||
|
|
||||||
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
|
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
@ -300,6 +301,14 @@ if (USE_MPI)
|
|||||||
target_include_directories(netgen_metis INTERFACE ${METIS_INCLUDE_DIR})
|
target_include_directories(netgen_metis INTERFACE ${METIS_INCLUDE_DIR})
|
||||||
target_link_libraries(netgen_metis INTERFACE ${METIS_LIBRARY} )
|
target_link_libraries(netgen_metis INTERFACE ${METIS_LIBRARY} )
|
||||||
target_compile_definitions(netgen_metis INTERFACE METIS )
|
target_compile_definitions(netgen_metis INTERFACE METIS )
|
||||||
|
|
||||||
|
if(USE_MPI4PY AND USE_PYTHON)
|
||||||
|
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import mpi4py;print(mpi4py.get_include())" OUTPUT_VARIABLE mpi4py_path OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||||
|
find_path(MPI4PY_INCLUDE_DIR mpi4py.h HINTS ${mpi4py_path}/mpi4py NO_DEFAULT_PATH REQUIRED)
|
||||||
|
target_include_directories(netgen_metis INTERFACE ${MPI4PY_INCLUDE_DIR})
|
||||||
|
target_compile_definitions(netgen_metis INTERFACE NG_MPI4PY )
|
||||||
|
message(STATUS "Found mpi4py: ${MPI4PY_INCLUDE_DIR}")
|
||||||
|
endif(USE_MPI4PY AND USE_PYTHON)
|
||||||
endif (USE_MPI)
|
endif (USE_MPI)
|
||||||
install(TARGETS netgen_mpi netgen_metis ${NG_INSTALL_DIR})
|
install(TARGETS netgen_mpi netgen_metis ${NG_INSTALL_DIR})
|
||||||
|
|
||||||
@ -324,6 +333,12 @@ if (USE_MPEG)
|
|||||||
include_directories(${FFMPEG_INCLUDE_DIR})
|
include_directories(${FFMPEG_INCLUDE_DIR})
|
||||||
endif (USE_MPEG)
|
endif (USE_MPEG)
|
||||||
|
|
||||||
|
#######################################################################
|
||||||
|
add_custom_target(ng_generate_version_file
|
||||||
|
${CMAKE_COMMAND}
|
||||||
|
-DBDIR=${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
-P ${CMAKE_CURRENT_LIST_DIR}/cmake/generate_version_file.cmake
|
||||||
|
)
|
||||||
#######################################################################
|
#######################################################################
|
||||||
if(INSTALL_PROFILES)
|
if(INSTALL_PROFILES)
|
||||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/netgen.sh "#!/bin/sh\n")
|
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/netgen.sh "#!/bin/sh\n")
|
||||||
@ -388,12 +403,27 @@ if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
|||||||
endif()
|
endif()
|
||||||
endif(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
endif(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
||||||
|
|
||||||
|
add_library(netgen_cgns INTERFACE)
|
||||||
|
if(USE_CGNS)
|
||||||
|
find_library( CGNS_LIBRARY NAMES cgns cgnsdll )
|
||||||
|
find_path( CGNS_INCLUDE_DIR cgnslib.h )
|
||||||
|
target_compile_definitions(netgen_cgns INTERFACE NG_CGNS)
|
||||||
|
target_include_directories(netgen_cgns INTERFACE ${CGNS_INCLUDE_DIR})
|
||||||
|
target_link_libraries(netgen_cgns INTERFACE ${CGNS_LIBRARY})
|
||||||
|
if(NOT WIN32 AND NOT APPLE) # hdf5 is statically linked into cgns in Windows amd MacOS binaries
|
||||||
|
find_library(HDF5_LIBRARY NAMES hdf5 hdf5_serial)
|
||||||
|
target_link_libraries(netgen_cgns INTERFACE ${HDF5_LIBRARY})
|
||||||
|
endif(NOT WIN32 AND NOT APPLE)
|
||||||
|
endif(USE_CGNS)
|
||||||
|
|
||||||
|
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/netgen_version.hpp ${CMAKE_CURRENT_BINARY_DIR}/netgen_config.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/include COMPONENT netgen_devel)
|
||||||
|
|
||||||
|
add_subdirectory(windows)
|
||||||
add_subdirectory(libsrc)
|
add_subdirectory(libsrc)
|
||||||
add_subdirectory(ng)
|
add_subdirectory(ng)
|
||||||
add_subdirectory(tutorials)
|
add_subdirectory(tutorials)
|
||||||
add_subdirectory(py_tutorials)
|
add_subdirectory(py_tutorials)
|
||||||
add_subdirectory(doc)
|
add_subdirectory(doc)
|
||||||
add_subdirectory(windows)
|
|
||||||
add_subdirectory(nglib)
|
add_subdirectory(nglib)
|
||||||
if (USE_PYTHON)
|
if (USE_PYTHON)
|
||||||
add_subdirectory(python)
|
add_subdirectory(python)
|
||||||
@ -444,6 +474,8 @@ if(USE_NATIVE_ARCH)
|
|||||||
else()
|
else()
|
||||||
message(STATUS "Build for generic CPU")
|
message(STATUS "Build for generic CPU")
|
||||||
endif()
|
endif()
|
||||||
|
elseif(APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||||
|
# no flag necessary/available on Apple M1
|
||||||
else()
|
else()
|
||||||
target_compile_options(ngcore PUBLIC "-march=native")
|
target_compile_options(ngcore PUBLIC "-march=native")
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
18
CONTRIBUTING.md
Normal file
18
CONTRIBUTING.md
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
# How to Contribute
|
||||||
|
|
||||||
|
## Reporting issues
|
||||||
|
|
||||||
|
If you have a problem using Netgen/NGSolve consider asking a question in our [forum](https://ngsolve.org/forum).
|
||||||
|
|
||||||
|
If you found a bug create an issue in the [Github Issue Tracker](https://github.com/NGSolve/netgen/issues). Please be as specific as possible, issues with a reproducible minimal failing example will get more attention than unspecific one liners :)
|
||||||
|
|
||||||
|
## Contributing patches
|
||||||
|
|
||||||
|
We love and want to encourage community engagement and will review and accept patches and contributions to this project. There are just a few steps to follow:
|
||||||
|
|
||||||
|
On your first contribution, to clear any legal questions, we ask you to sign our [Contributor License Agreement](CLA.pdf). Generally you have to sign this only once for Netgen or NGSolve. Please send the signed agreement to <joachim.schoeberl@tuwien.ac.at>.
|
||||||
|
|
||||||
|
Place a pull request on GitHub. From there we will pull it into our internal testing environment and, if approved, merge it into the main codebase.
|
||||||
|
|
||||||
|
If you have any questions feel free to ask on the [forum](https://ngsolve.org/forum).
|
@ -1,4 +1,8 @@
|
|||||||
set(NETGEN_VERSION "@NETGEN_VERSION@")
|
set(NETGEN_VERSION "@NETGEN_VERSION@")
|
||||||
|
set(NETGEN_VERSION_MAJOR "@NETGEN_VERSION_MAJOR@")
|
||||||
|
set(NETGEN_VERSION_MINOR "@NETGEN_VERSION_MINOR@")
|
||||||
|
set(NETGEN_VERSION_PATCH "@NETGEN_VERSION_PATCH@")
|
||||||
|
set(NETGEN_VERSION_TWEAK "@NETGEN_VERSION_TWEAK@")
|
||||||
|
|
||||||
get_filename_component(NETGEN_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
get_filename_component(NETGEN_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
|
||||||
|
|
||||||
@ -27,6 +31,7 @@ set(NETGEN_METIS_LIBRARY "@METIS_LIBRARY@")
|
|||||||
set(NETGEN_MKL_LIBRARIES "@MKL_LIBRARIES@")
|
set(NETGEN_MKL_LIBRARIES "@MKL_LIBRARIES@")
|
||||||
set(NETGEN_MPI_CXX_INCLUDE_PATH "@MPI_CXX_INCLUDE_PATH@")
|
set(NETGEN_MPI_CXX_INCLUDE_PATH "@MPI_CXX_INCLUDE_PATH@")
|
||||||
set(NETGEN_MPI_CXX_LIBRARIES "@MPI_CXX_LIBRARIES@")
|
set(NETGEN_MPI_CXX_LIBRARIES "@MPI_CXX_LIBRARIES@")
|
||||||
|
set(NETGEN_NUMA_LIBRARY "@NUMA_LIBRARY@")
|
||||||
set(NETGEN_OCC_INCLUDE_DIR "@OCC_INCLUDE_DIR@")
|
set(NETGEN_OCC_INCLUDE_DIR "@OCC_INCLUDE_DIR@")
|
||||||
set(NETGEN_OCC_LIBRARIES_BIN "@OCC_LIBRARIES_BIN@")
|
set(NETGEN_OCC_LIBRARIES_BIN "@OCC_LIBRARIES_BIN@")
|
||||||
set(NETGEN_OCC_LIBRARIES "@OCC_LIBRARIES@")
|
set(NETGEN_OCC_LIBRARIES "@OCC_LIBRARIES@")
|
||||||
@ -51,10 +56,12 @@ set(NETGEN_USE_MPI @USE_MPI@)
|
|||||||
set(NETGEN_USE_OCC @USE_OCC@)
|
set(NETGEN_USE_OCC @USE_OCC@)
|
||||||
set(NETGEN_USE_JPEG @USE_JPEG@)
|
set(NETGEN_USE_JPEG @USE_JPEG@)
|
||||||
set(NETGEN_USE_MPEG @USE_MPEG@)
|
set(NETGEN_USE_MPEG @USE_MPEG@)
|
||||||
|
set(NETGEN_USE_CGNS @USE_CGNS@)
|
||||||
set(NETGEN_INTEL_MIC @INTEL_MIC@)
|
set(NETGEN_INTEL_MIC @INTEL_MIC@)
|
||||||
set(NETGEN_INSTALL_PROFILES @INSTALL_PROFILES@)
|
set(NETGEN_INSTALL_PROFILES @INSTALL_PROFILES@)
|
||||||
set(NETGEN_USE_CCACHE @USE_CCACHE@)
|
set(NETGEN_USE_CCACHE @USE_CCACHE@)
|
||||||
set(NETGEN_USE_NATIVE_ARCH @USE_NATIVE_ARCH@)
|
set(NETGEN_USE_NATIVE_ARCH @USE_NATIVE_ARCH@)
|
||||||
|
set(NETGEN_USE_NUMA @USE_NUMA@)
|
||||||
|
|
||||||
set(NETGEN_PYTHON_RPATH "@NETGEN_PYTHON_RPATH@")
|
set(NETGEN_PYTHON_RPATH "@NETGEN_PYTHON_RPATH@")
|
||||||
set(NETGEN_RPATH_TOKEN "@NG_RPATH_TOKEN@")
|
set(NETGEN_RPATH_TOKEN "@NG_RPATH_TOKEN@")
|
||||||
|
@ -15,12 +15,12 @@ macro(set_vars VAR_OUT)
|
|||||||
endforeach()
|
endforeach()
|
||||||
endmacro()
|
endmacro()
|
||||||
#######################################################################
|
#######################################################################
|
||||||
if(WIN32)
|
set (DEPS_DOWNLOAD_URL "https://github.com/NGSolve/ngsolve_dependencies/releases/download/v1.0.0" CACHE STRING INTERNAL)
|
||||||
set (DEPS_DOWNLOAD_URL "https://github.com/NGSolve/ngsolve_dependencies/releases/download/v1.0.0" CACHE STRING INTERNAL)
|
set (OCC_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/occ_win64.zip" CACHE STRING INTERNAL)
|
||||||
set (OCC_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/occ_win64.zip" CACHE STRING INTERNAL)
|
set (TCLTK_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/tcltk_win64.zip" CACHE STRING INTERNAL)
|
||||||
set (TCLTK_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/tcltk_win64.zip" CACHE STRING INTERNAL)
|
set (ZLIB_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/zlib_win64.zip" CACHE STRING INTERNAL)
|
||||||
set (ZLIB_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/zlib_win64.zip" CACHE STRING INTERNAL)
|
set (CGNS_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/cgns_win64.zip" CACHE STRING INTERNAL)
|
||||||
endif(WIN32)
|
set (CGNS_DOWNLOAD_URL_MAC "${DEPS_DOWNLOAD_URL}/cgns_mac.zip" CACHE STRING INTERNAL)
|
||||||
|
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
message("Checking for write permissions in install directory...")
|
message("Checking for write permissions in install directory...")
|
||||||
@ -86,6 +86,10 @@ if(USE_GUI)
|
|||||||
include(cmake/external_projects/tcltk.cmake)
|
include(cmake/external_projects/tcltk.cmake)
|
||||||
endif(USE_GUI)
|
endif(USE_GUI)
|
||||||
|
|
||||||
|
if(USE_CGNS)
|
||||||
|
include(cmake/external_projects/cgns.cmake)
|
||||||
|
endif(USE_CGNS)
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
if(USE_MPI)
|
if(USE_MPI)
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
@ -128,6 +132,7 @@ set_vars( NETGEN_CMAKE_ARGS
|
|||||||
USE_OCC
|
USE_OCC
|
||||||
USE_MPEG
|
USE_MPEG
|
||||||
USE_JPEG
|
USE_JPEG
|
||||||
|
USE_CGNS
|
||||||
USE_INTERNAL_TCL
|
USE_INTERNAL_TCL
|
||||||
INSTALL_PROFILES
|
INSTALL_PROFILES
|
||||||
INTEL_MIC
|
INTEL_MIC
|
||||||
@ -138,8 +143,10 @@ set_vars( NETGEN_CMAKE_ARGS
|
|||||||
USE_SPDLOG
|
USE_SPDLOG
|
||||||
DEBUG_LOG
|
DEBUG_LOG
|
||||||
CHECK_RANGE
|
CHECK_RANGE
|
||||||
|
TRACE_MEMORY
|
||||||
BUILD_STUB_FILES
|
BUILD_STUB_FILES
|
||||||
BUILD_FOR_CONDA
|
BUILD_FOR_CONDA
|
||||||
|
NG_COMPILE_FLAGS
|
||||||
)
|
)
|
||||||
|
|
||||||
# propagate all variables set on the command line using cmake -DFOO=BAR
|
# propagate all variables set on the command line using cmake -DFOO=BAR
|
||||||
|
@ -25,9 +25,9 @@ else(WIN32)
|
|||||||
)
|
)
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
||||||
if(OCC_LIBRARY)
|
if(OCC_LIBRARY AND NOT OCC_LIBRARY_DIR)
|
||||||
get_filename_component(OCC_LIBRARY_DIR ${OCC_LIBRARY} PATH)
|
get_filename_component(OCC_LIBRARY_DIR ${OCC_LIBRARY} PATH)
|
||||||
endif(OCC_LIBRARY)
|
endif(OCC_LIBRARY AND NOT OCC_LIBRARY_DIR)
|
||||||
|
|
||||||
if(OCC_INCLUDE_DIR)
|
if(OCC_INCLUDE_DIR)
|
||||||
file(STRINGS ${OCC_INCLUDE_DIR}/Standard_Version.hxx OCC_MAJOR
|
file(STRINGS ${OCC_INCLUDE_DIR}/Standard_Version.hxx OCC_MAJOR
|
||||||
@ -89,7 +89,7 @@ if(OCC_VERSION_STRING VERSION_GREATER_EQUAL "7.3.0")
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
foreach( libname ${OCC_LIBRARY_NAMES} )
|
foreach( libname ${OCC_LIBRARY_NAMES} )
|
||||||
find_library( ${libname} ${libname} ${OCC_LIBRARY_DIR} )
|
find_library( ${libname} ${libname} ${OCC_LIBRARY_DIR} NO_DEFAULT_PATH)
|
||||||
set(OCC_LIBRARIES ${OCC_LIBRARIES} ${${libname}})
|
set(OCC_LIBRARIES ${OCC_LIBRARIES} ${${libname}})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
30
cmake/external_projects/cgns.cmake
Normal file
30
cmake/external_projects/cgns.cmake
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
if(WIN32)
|
||||||
|
|
||||||
|
ExternalProject_Add(project_win_cgns
|
||||||
|
URL ${CGNS_DOWNLOAD_URL_WIN}
|
||||||
|
UPDATE_COMMAND "" # Disable update
|
||||||
|
BUILD_IN_SOURCE 1
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX}
|
||||||
|
LOG_DOWNLOAD 1
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND NETGEN_DEPENDENCIES project_win_cgns)
|
||||||
|
endif(WIN32)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
ExternalProject_Add(project_mac_cgns
|
||||||
|
URL ${CGNS_DOWNLOAD_URL_MAC}
|
||||||
|
UPDATE_COMMAND "" # Disable update
|
||||||
|
BUILD_IN_SOURCE 1
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX}
|
||||||
|
LOG_DOWNLOAD 1
|
||||||
|
)
|
||||||
|
|
||||||
|
list(APPEND NETGEN_DEPENDENCIES project_mac_cgns)
|
||||||
|
list(APPEND NETGEN_CMAKE_ARGS "-DCGNS_INCLUDE_DIR=${CMAKE_INSTALL_PREFIX}/Contents/Resources/include")
|
||||||
|
list(APPEND NETGEN_CMAKE_ARGS "-DCGNS_LIBRARY=${CMAKE_INSTALL_PREFIX}/Contents/MacOS/libcgns.dylib")
|
||||||
|
endif(APPLE)
|
92
cmake/generate_version_file.cmake
Normal file
92
cmake/generate_version_file.cmake
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
if(NOT BDIR)
|
||||||
|
set(BDIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(Git REQUIRED)
|
||||||
|
execute_process(COMMAND git describe --tags --match "v[0-9]*" --long --dirty WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} OUTPUT_VARIABLE git_version_string RESULT_VARIABLE status ERROR_QUIET)
|
||||||
|
|
||||||
|
if(status AND NOT status EQUAL 0)
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../version.txt)
|
||||||
|
# for source package files (generated for ubuntu builds on launchpad) read the version from version.txt
|
||||||
|
if(EXISTS ${CMAKE_CURRENT_LIST_DIR}/../version.txt)
|
||||||
|
file(READ ${CMAKE_CURRENT_LIST_DIR}/../version.txt git_version_string )
|
||||||
|
else()
|
||||||
|
get_filename_component(git_version_string ${CMAKE_CURRENT_LIST_DIR}/.. NAME)
|
||||||
|
string(REGEX REPLACE "^netgen(.*)" "\\1" git_version_string "${git_version_string}")
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
MESSAGE(WARNING "Could not determine git-version from source code - assuming 6.2.0.0")
|
||||||
|
set(git_version_string "v6.2.0.0")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
string(REGEX REPLACE "^v([0-9]+)\\..*" "\\1" NETGEN_VERSION_MAJOR "${git_version_string}")
|
||||||
|
string(REGEX REPLACE "^v[0-9]+\\.([0-9]+).*" "\\1" NETGEN_VERSION_MINOR "${git_version_string}")
|
||||||
|
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" NETGEN_VERSION_PATCH "${git_version_string}")
|
||||||
|
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+\\-([0-9]+).*" "\\1" NETGEN_VERSION_TWEAK "${git_version_string}")
|
||||||
|
string(REGEX REPLACE "^v[0-9]+\\.[0-9]+\\.[0-9]+\\-[0-9]+\\-([0-9a-z]+).*" "\\1" NETGEN_VERSION_HASH "${git_version_string}")
|
||||||
|
|
||||||
|
set(NETGEN_VERSION_SHORT ${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}.${NETGEN_VERSION_PATCH})
|
||||||
|
set(NETGEN_VERSION_LONG ${NETGEN_VERSION_SHORT}-${NETGEN_VERSION_TWEAK}-${NETGEN_VERSION_HASH})
|
||||||
|
|
||||||
|
if(NETGEN_VERSION_TWEAK)
|
||||||
|
# no release version - nightly build
|
||||||
|
set(NETGEN_VERSION ${NETGEN_VERSION_LONG})
|
||||||
|
else()
|
||||||
|
# TWEAK is 0 -> current version has a tag assigned
|
||||||
|
set(NETGEN_VERSION ${NETGEN_VERSION_SHORT})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(NETGEN_VERSION_LONG ${NETGEN_VERSION_SHORT}-${NETGEN_VERSION_TWEAK}-${NETGEN_VERSION_HASH})
|
||||||
|
|
||||||
|
set(version_file ${BDIR}/netgen_version.hpp)
|
||||||
|
set(new_version_file_string "\
|
||||||
|
#ifndef NETGEN_VERSION_HPP_INCLUDED
|
||||||
|
#define NETGEN_VERSION_HPP_INCLUDED
|
||||||
|
#define NETGEN_VERSION \"${NETGEN_VERSION}\"
|
||||||
|
#define NETGEN_VERSION_MAJOR ${NETGEN_VERSION_MAJOR}
|
||||||
|
#define NETGEN_VERSION_MINOR ${NETGEN_VERSION_MINOR}
|
||||||
|
#define NETGEN_VERSION_PATCH ${NETGEN_VERSION_PATCH}
|
||||||
|
#define NETGEN_VERSION_TWEAK ${NETGEN_VERSION_TWEAK}
|
||||||
|
#define NETGEN_VERSION_HASH \"${NETGEN_VERSION_HASH}\"
|
||||||
|
#endif // NETGEN_VERSION_HPP_INCLUDED
|
||||||
|
")
|
||||||
|
if(EXISTS ${version_file})
|
||||||
|
file(READ ${version_file} old_version_file_string )
|
||||||
|
if(${old_version_file_string} STREQUAL ${new_version_file_string})
|
||||||
|
else()
|
||||||
|
file(WRITE ${BDIR}/netgen_version.hpp ${new_version_file_string})
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
file(WRITE ${BDIR}/netgen_version.hpp ${new_version_file_string})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
file(GENERATE OUTPUT netgen_config.hpp CONTENT
|
||||||
|
"\
|
||||||
|
#ifndef NETGEN_CONFIG_HPP_INCLUDED___
|
||||||
|
#define NETGEN_CONFIG_HPP_INCLUDED___
|
||||||
|
|
||||||
|
#define NETGEN_USE_NATIVE_ARCH $<BOOL:${USE_NATIVE_ARCH}>
|
||||||
|
#define NETGEN_USE_GUI $<BOOL:${USE_GUI}>
|
||||||
|
#define NETGEN_USE_PYTHON $<BOOL:${USE_PYTHON}>
|
||||||
|
#define NETGEN_USE_MPI $<BOOL:${USE_MPI}}>
|
||||||
|
#define NETGEN_USE_MPI4PY $<BOOL:${USE_MPI4PY}>
|
||||||
|
#define NETGEN_USE_OCC $<BOOL:${USE_OCC}}>
|
||||||
|
#define NETGEN_USE_JPEG $<BOOL:${USE_JPEG}}>
|
||||||
|
#define NETGEN_USE_MPEG $<BOOL:${USE_MPEG}}>
|
||||||
|
#define NETGEN_USE_CGNS $<BOOL:${USE_CGNS}}>
|
||||||
|
#define NETGEN_USE_NUMA $<BOOL:${USE_NUMA}}>
|
||||||
|
#define NETGEN_INTEL_MIC $<BOOL:${USE_INTEL_MIC}}>
|
||||||
|
#define NETGEN_INSTALL_PROFILES $<BOOL:${INSTALL_PROFILES}>
|
||||||
|
#define NETGEN_USE_CCACHE $<BOOL:${USE_CCACHE}}>
|
||||||
|
#define NETGEN_USE_INTERNAL_TCL $<BOOL:${USE_INTERNAL_TCL}>
|
||||||
|
#define NETGEN_ENABLE_UNIT_TESTS $<BOOL:${ENABLE_UNIT_TESTS}>
|
||||||
|
#define NETGEN_ENABLE_CPP_CORE_GUIDELINES_CHECK $<BOOL:${ENABLE_CPP_CORE_GUIDELINES_CHECK}>
|
||||||
|
#define NETGEN_USE_SPDLOG $<BOOL:${USE_SPDLOG}>
|
||||||
|
#define NETGEN_DEBUG_LOG $<BOOL:${DEBUG_LOG}>
|
||||||
|
#define NETGEN_USE_CHECK_RANGE $<BOOL:${CHECK_RANGE}>
|
||||||
|
#define NETGEN_BUILD_STUB_FILES $<BOOL:${BUILD_STUB_FILES}>
|
||||||
|
#define NETGEN_BUILD_FOR_CONDA $<BOOL:${BUILD_FOR_CONDA}>
|
||||||
|
|
||||||
|
#endif // NETGEN_CONFIG_HPP_INCLUDED___
|
||||||
|
")
|
@ -1 +1 @@
|
|||||||
Subproject commit deb3cb238a9f299d7c57f810165e90a1b14b3e6f
|
Subproject commit c16da993094988141101ac4d96a9b2c92f9ac714
|
@ -11,8 +11,11 @@ add_library(ngcore SHARED
|
|||||||
table.cpp
|
table.cpp
|
||||||
taskmanager.cpp
|
taskmanager.cpp
|
||||||
utils.cpp
|
utils.cpp
|
||||||
|
version.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_compile_options(ngcore PUBLIC "${NG_COMPILE_FLAGS}")
|
||||||
|
|
||||||
# Pybind11 2.3 Issue https://github.com/pybind/pybind11/issues/1604
|
# Pybind11 2.3 Issue https://github.com/pybind/pybind11/issues/1604
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
|
||||||
target_compile_options(ngcore PUBLIC -fsized-deallocation -faligned-allocation)
|
target_compile_options(ngcore PUBLIC -fsized-deallocation -faligned-allocation)
|
||||||
@ -39,6 +42,11 @@ if(CHECK_RANGE OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL
|
|||||||
target_compile_definitions(ngcore PUBLIC NETGEN_ENABLE_CHECK_RANGE)
|
target_compile_definitions(ngcore PUBLIC NETGEN_ENABLE_CHECK_RANGE)
|
||||||
endif(CHECK_RANGE OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG")
|
endif(CHECK_RANGE OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG")
|
||||||
|
|
||||||
|
if(TRACE_MEMORY OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG")
|
||||||
|
target_compile_definitions(ngcore PUBLIC NETGEN_TRACE_MEMORY)
|
||||||
|
endif(TRACE_MEMORY OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG")
|
||||||
|
|
||||||
|
|
||||||
if(USE_SPDLOG)
|
if(USE_SPDLOG)
|
||||||
include_directories(${SPDLOG_INCLUDE_DIR})
|
include_directories(${SPDLOG_INCLUDE_DIR})
|
||||||
install(DIRECTORY ${SPDLOG_INCLUDE_DIR}
|
install(DIRECTORY ${SPDLOG_INCLUDE_DIR}
|
||||||
@ -51,20 +59,29 @@ if(USE_SPDLOG)
|
|||||||
endif(DEBUG_LOG)
|
endif(DEBUG_LOG)
|
||||||
endif(USE_SPDLOG)
|
endif(USE_SPDLOG)
|
||||||
|
|
||||||
|
if(USE_NUMA)
|
||||||
|
find_library(NUMA_LIBRARY libnuma.so)
|
||||||
|
target_compile_definitions(ngcore PUBLIC USE_NUMA)
|
||||||
|
target_link_libraries(ngcore PRIVATE ${NUMA_LIBRARY})
|
||||||
|
endif(USE_NUMA)
|
||||||
|
|
||||||
install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen)
|
install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen)
|
||||||
|
|
||||||
target_link_libraries(ngcore PUBLIC netgen_mpi PRIVATE netgen_python ${CMAKE_THREAD_LIBS_INIT})
|
target_link_libraries(ngcore PUBLIC netgen_mpi PRIVATE "$<BUILD_INTERFACE:netgen_python>" ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
|
||||||
install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp
|
install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp
|
||||||
exception.hpp symboltable.hpp paje_trace.hpp utils.hpp profiler.hpp mpi_wrapper.hpp
|
exception.hpp symboltable.hpp paje_trace.hpp utils.hpp profiler.hpp mpi_wrapper.hpp
|
||||||
array.hpp taskmanager.hpp concurrentqueue.h localheap.hpp python_ngcore.hpp flags.hpp
|
array.hpp taskmanager.hpp concurrentqueue.h localheap.hpp python_ngcore.hpp flags.hpp
|
||||||
xbool.hpp signal.hpp bitarray.hpp table.hpp hashtable.hpp
|
xbool.hpp signal.hpp bitarray.hpp table.hpp hashtable.hpp ranges.hpp
|
||||||
|
simd.hpp simd_avx.hpp simd_avx512.hpp simd_generic.hpp simd_sse.hpp simd_arm64.hpp
|
||||||
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel)
|
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel)
|
||||||
|
|
||||||
if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
||||||
set_target_properties(ngcore PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
|
set_target_properties(ngcore PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
|
||||||
endif(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
endif(ENABLE_CPP_CORE_GUIDELINES_CHECK)
|
||||||
|
|
||||||
|
add_dependencies(ngcore ng_generate_version_file)
|
||||||
|
|
||||||
if(USE_PYTHON)
|
if(USE_PYTHON)
|
||||||
pybind11_add_module(pyngcore SHARED python_ngcore_export.cpp)
|
pybind11_add_module(pyngcore SHARED python_ngcore_export.cpp)
|
||||||
target_link_libraries(pyngcore PUBLIC ngcore netgen_python)
|
target_link_libraries(pyngcore PUBLIC ngcore netgen_python)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
|
||||||
#include "archive.hpp"
|
#include "archive.hpp"
|
||||||
|
#include "version.hpp"
|
||||||
|
|
||||||
#ifndef WIN32
|
#ifndef WIN32
|
||||||
#include <cxxabi.h>
|
#include <cxxabi.h>
|
||||||
@ -7,18 +8,6 @@
|
|||||||
|
|
||||||
namespace ngcore
|
namespace ngcore
|
||||||
{
|
{
|
||||||
// clang-tidy should ignore this static object
|
|
||||||
static std::map<std::string, VersionInfo> library_versions; // NOLINT
|
|
||||||
std::map<std::string, VersionInfo>& Archive :: GetLibraryVersions()
|
|
||||||
{
|
|
||||||
return library_versions;
|
|
||||||
}
|
|
||||||
const VersionInfo& GetLibraryVersion(const std::string& library)
|
|
||||||
{ return library_versions[library]; }
|
|
||||||
|
|
||||||
void SetLibraryVersion(const std::string& library, const VersionInfo& version)
|
|
||||||
{ library_versions[library] = version; }
|
|
||||||
|
|
||||||
// clang-tidy should ignore this static object
|
// clang-tidy should ignore this static object
|
||||||
static std::unique_ptr<std::map<std::string, detail::ClassArchiveInfo>> type_register; // NOLINT
|
static std::unique_ptr<std::map<std::string, detail::ClassArchiveInfo>> type_register; // NOLINT
|
||||||
const detail::ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname)
|
const detail::ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname)
|
||||||
|
@ -30,9 +30,6 @@ namespace pybind11
|
|||||||
|
|
||||||
namespace ngcore
|
namespace ngcore
|
||||||
{
|
{
|
||||||
// Libraries using this archive can store their version here to implement backwards compatibility
|
|
||||||
NGCORE_API const VersionInfo& GetLibraryVersion(const std::string& library);
|
|
||||||
NGCORE_API void SetLibraryVersion(const std::string& library, const VersionInfo& version);
|
|
||||||
|
|
||||||
class NGCORE_API Archive;
|
class NGCORE_API Archive;
|
||||||
|
|
||||||
@ -156,6 +153,7 @@ namespace ngcore
|
|||||||
virtual void NeedsVersion(const std::string& /*unused*/, const std::string& /*unused*/) {}
|
virtual void NeedsVersion(const std::string& /*unused*/, const std::string& /*unused*/) {}
|
||||||
|
|
||||||
// Pure virtual functions that have to be implemented by In-/OutArchive
|
// Pure virtual functions that have to be implemented by In-/OutArchive
|
||||||
|
virtual Archive & operator & (float & d) = 0;
|
||||||
virtual Archive & operator & (double & d) = 0;
|
virtual Archive & operator & (double & d) = 0;
|
||||||
virtual Archive & operator & (int & i) = 0;
|
virtual Archive & operator & (int & i) = 0;
|
||||||
virtual Archive & operator & (long & i) = 0;
|
virtual Archive & operator & (long & i) = 0;
|
||||||
@ -570,9 +568,10 @@ namespace ngcore
|
|||||||
|
|
||||||
virtual void FlushBuffer() {}
|
virtual void FlushBuffer() {}
|
||||||
|
|
||||||
protected:
|
bool parallel = false;
|
||||||
static std::map<std::string, VersionInfo>& GetLibraryVersions();
|
bool IsParallel() const { return parallel; }
|
||||||
|
void SetParallel (bool _parallel) { parallel = _parallel; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename T, typename ... Bases>
|
template<typename T, typename ... Bases>
|
||||||
friend class RegisterClassForArchive;
|
friend class RegisterClassForArchive;
|
||||||
@ -680,6 +679,8 @@ namespace ngcore
|
|||||||
BinaryOutArchive& operator=(BinaryOutArchive&&) = delete;
|
BinaryOutArchive& operator=(BinaryOutArchive&&) = delete;
|
||||||
|
|
||||||
using Archive::operator&;
|
using Archive::operator&;
|
||||||
|
Archive & operator & (float & f) override
|
||||||
|
{ return Write(f); }
|
||||||
Archive & operator & (double & d) override
|
Archive & operator & (double & d) override
|
||||||
{ return Write(d); }
|
{ return Write(d); }
|
||||||
Archive & operator & (int & i) override
|
Archive & operator & (int & i) override
|
||||||
@ -687,7 +688,11 @@ namespace ngcore
|
|||||||
Archive & operator & (short & i) override
|
Archive & operator & (short & i) override
|
||||||
{ return Write(i); }
|
{ return Write(i); }
|
||||||
Archive & operator & (long & i) override
|
Archive & operator & (long & i) override
|
||||||
{ return Write(i); }
|
{
|
||||||
|
// for platform independence
|
||||||
|
int64_t tmp = i;
|
||||||
|
return Write(tmp);
|
||||||
|
}
|
||||||
Archive & operator & (size_t & i) override
|
Archive & operator & (size_t & i) override
|
||||||
{ return Write(i); }
|
{ return Write(i); }
|
||||||
Archive & operator & (unsigned char & i) override
|
Archive & operator & (unsigned char & i) override
|
||||||
@ -725,14 +730,13 @@ namespace ngcore
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
Archive & Write (T x)
|
Archive & Write (T x)
|
||||||
{
|
{
|
||||||
|
static_assert(sizeof(T) < BUFFERSIZE, "Cannot write large types with this function!");
|
||||||
if (unlikely(ptr > BUFFERSIZE-sizeof(T)))
|
if (unlikely(ptr > BUFFERSIZE-sizeof(T)))
|
||||||
{
|
{
|
||||||
stream->write(&buffer[0], ptr);
|
stream->write(&buffer[0], ptr);
|
||||||
*reinterpret_cast<T*>(&buffer[0]) = x; // NOLINT
|
ptr = 0;
|
||||||
ptr = sizeof(T);
|
|
||||||
return *this;
|
|
||||||
}
|
}
|
||||||
*reinterpret_cast<T*>(&buffer[ptr]) = x; // NOLINT
|
memcpy(&buffer[ptr], &x, sizeof(T));
|
||||||
ptr += sizeof(T);
|
ptr += sizeof(T);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@ -751,6 +755,8 @@ namespace ngcore
|
|||||||
: BinaryInArchive(std::make_shared<std::ifstream>(filename)) { ; }
|
: BinaryInArchive(std::make_shared<std::ifstream>(filename)) { ; }
|
||||||
|
|
||||||
using Archive::operator&;
|
using Archive::operator&;
|
||||||
|
Archive & operator & (float & f) override
|
||||||
|
{ Read(f); return *this; }
|
||||||
Archive & operator & (double & d) override
|
Archive & operator & (double & d) override
|
||||||
{ Read(d); return *this; }
|
{ Read(d); return *this; }
|
||||||
Archive & operator & (int & i) override
|
Archive & operator & (int & i) override
|
||||||
@ -758,7 +764,12 @@ namespace ngcore
|
|||||||
Archive & operator & (short & i) override
|
Archive & operator & (short & i) override
|
||||||
{ Read(i); return *this; }
|
{ Read(i); return *this; }
|
||||||
Archive & operator & (long & i) override
|
Archive & operator & (long & i) override
|
||||||
{ Read(i); return *this; }
|
{
|
||||||
|
int64_t tmp;
|
||||||
|
Read(tmp);
|
||||||
|
i = tmp;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
Archive & operator & (size_t & i) override
|
Archive & operator & (size_t & i) override
|
||||||
{ Read(i); return *this; }
|
{ Read(i); return *this; }
|
||||||
Archive & operator & (unsigned char & i) override
|
Archive & operator & (unsigned char & i) override
|
||||||
@ -815,6 +826,8 @@ namespace ngcore
|
|||||||
TextOutArchive(std::make_shared<std::ofstream>(filename)) { }
|
TextOutArchive(std::make_shared<std::ofstream>(filename)) { }
|
||||||
|
|
||||||
using Archive::operator&;
|
using Archive::operator&;
|
||||||
|
Archive & operator & (float & f) override
|
||||||
|
{ *stream << f << '\n'; return *this; }
|
||||||
Archive & operator & (double & d) override
|
Archive & operator & (double & d) override
|
||||||
{ *stream << d << '\n'; return *this; }
|
{ *stream << d << '\n'; return *this; }
|
||||||
Archive & operator & (int & i) override
|
Archive & operator & (int & i) override
|
||||||
@ -866,6 +879,8 @@ namespace ngcore
|
|||||||
: TextInArchive(std::make_shared<std::ifstream>(filename)) {}
|
: TextInArchive(std::make_shared<std::ifstream>(filename)) {}
|
||||||
|
|
||||||
using Archive::operator&;
|
using Archive::operator&;
|
||||||
|
Archive & operator & (float & f) override
|
||||||
|
{ *stream >> f; return *this; }
|
||||||
Archive & operator & (double & d) override
|
Archive & operator & (double & d) override
|
||||||
{ *stream >> d; return *this; }
|
{ *stream >> d; return *this; }
|
||||||
Archive & operator & (int & i) override
|
Archive & operator & (int & i) override
|
||||||
@ -912,6 +927,55 @@ namespace ngcore
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// HashArchive =================================================================
|
||||||
|
// This class enables to easily create hashes for archivable objects by xoring
|
||||||
|
// threw its data
|
||||||
|
|
||||||
|
class NGCORE_API HashArchive : public Archive
|
||||||
|
{
|
||||||
|
size_t hash_value = 0;
|
||||||
|
char* h;
|
||||||
|
int offset = 0;
|
||||||
|
public:
|
||||||
|
HashArchive() : Archive(true)
|
||||||
|
{ h = (char*)&hash_value; }
|
||||||
|
|
||||||
|
using Archive::operator&;
|
||||||
|
Archive & operator & (float & f) override { return ApplyHash(f); }
|
||||||
|
Archive & operator & (double & d) override { return ApplyHash(d); }
|
||||||
|
Archive & operator & (int & i) override { return ApplyHash(i); }
|
||||||
|
Archive & operator & (short & i) override { return ApplyHash(i); }
|
||||||
|
Archive & operator & (long & i) override { return ApplyHash(i); }
|
||||||
|
Archive & operator & (size_t & i) override { return ApplyHash(i); }
|
||||||
|
Archive & operator & (unsigned char & i) override { return ApplyHash(i); }
|
||||||
|
Archive & operator & (bool & b) override { return ApplyHash(b); }
|
||||||
|
Archive & operator & (std::string & str) override
|
||||||
|
{ for(auto c : str) ApplyHash(c); return *this; }
|
||||||
|
Archive & operator & (char *& str) override
|
||||||
|
{ char* s = str; while(*s != '\0') ApplyHash(*(s++)); return *this; }
|
||||||
|
|
||||||
|
// HashArchive can be used in const context
|
||||||
|
template<typename T>
|
||||||
|
Archive & operator& (const T& val) const
|
||||||
|
{ return (*this) & const_cast<T&>(val); }
|
||||||
|
|
||||||
|
size_t GetHash() const { return hash_value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename T>
|
||||||
|
Archive& ApplyHash(T val)
|
||||||
|
{
|
||||||
|
size_t n = sizeof(T);
|
||||||
|
char* pval = (char*)&val;
|
||||||
|
for(size_t i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
h[offset++] ^= pval[i];
|
||||||
|
offset %= 8;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace ngcore
|
} // namespace ngcore
|
||||||
|
|
||||||
#endif // NETGEN_CORE_ARCHIVE_HPP
|
#endif // NETGEN_CORE_ARCHIVE_HPP
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "archive.hpp"
|
#include "archive.hpp"
|
||||||
#include "exception.hpp"
|
#include "exception.hpp"
|
||||||
#include "localheap.hpp"
|
#include "localheap.hpp"
|
||||||
|
#include "profiler.hpp"
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
|
||||||
namespace ngcore
|
namespace ngcore
|
||||||
@ -39,7 +40,7 @@ namespace ngcore
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename ... ARGS>
|
template <typename ... ARGS>
|
||||||
ostream & operator<< (ostream & ost, Tuple<ARGS...> tup)
|
ostream & operator<< (ostream & ost, Tuple<ARGS...> /* tup */)
|
||||||
{
|
{
|
||||||
return ost;
|
return ost;
|
||||||
}
|
}
|
||||||
@ -211,6 +212,20 @@ namespace ngcore
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr T IndexBASE () { return T(0); }
|
constexpr T IndexBASE () { return T(0); }
|
||||||
|
|
||||||
|
|
||||||
|
class IndexFromEnd
|
||||||
|
{
|
||||||
|
ptrdiff_t i;
|
||||||
|
public:
|
||||||
|
constexpr IndexFromEnd (ptrdiff_t ai) : i(ai) { }
|
||||||
|
IndexFromEnd operator+ (ptrdiff_t inc) const { return i+inc; }
|
||||||
|
IndexFromEnd operator- (ptrdiff_t dec) const { return i-dec; }
|
||||||
|
// operator ptrdiff_t () const { return i; }
|
||||||
|
ptrdiff_t Value() const { return i; }
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr IndexFromEnd END(0);
|
||||||
|
|
||||||
|
|
||||||
template <class T, class IndexType = size_t> class FlatArray;
|
template <class T, class IndexType = size_t> class FlatArray;
|
||||||
|
|
||||||
@ -268,7 +283,7 @@ namespace ngcore
|
|||||||
NETGEN_INLINE T & First() { return first; }
|
NETGEN_INLINE T & First() { return first; }
|
||||||
NETGEN_INLINE T & Next() { return next; }
|
NETGEN_INLINE T & Next() { return next; }
|
||||||
NETGEN_INLINE auto Size() const { return next-first; }
|
NETGEN_INLINE auto Size() const { return next-first; }
|
||||||
NETGEN_INLINE T operator[] (T i) const { return first+i; }
|
NETGEN_INLINE T operator[] (size_t i) const { return first+i; }
|
||||||
NETGEN_INLINE bool Contains (T i) const { return ((i >= first) && (i < next)); }
|
NETGEN_INLINE bool Contains (T i) const { return ((i >= first) && (i < next)); }
|
||||||
NETGEN_INLINE T_Range Modify(int inc_beg, int inc_end) const
|
NETGEN_INLINE T_Range Modify(int inc_beg, int inc_end) const
|
||||||
{ return T_Range(first+inc_beg, next+inc_end); }
|
{ return T_Range(first+inc_beg, next+inc_end); }
|
||||||
@ -559,6 +574,12 @@ namespace ngcore
|
|||||||
return FlatArray<T> (end-start, data+start);
|
return FlatArray<T> (end-start, data+start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// takes range starting from position start of end-start elements
|
||||||
|
NETGEN_INLINE FlatArray<T> Range (size_t start, IndexFromEnd indend) const
|
||||||
|
{
|
||||||
|
return this->Range(start, size_t(Size()+indend.Value()));
|
||||||
|
}
|
||||||
|
|
||||||
/// takes range starting from position start of end-start elements
|
/// takes range starting from position start of end-start elements
|
||||||
NETGEN_INLINE FlatArray<T> Range (T_Range<size_t> range) const
|
NETGEN_INLINE FlatArray<T> Range (T_Range<size_t> range) const
|
||||||
{
|
{
|
||||||
@ -599,9 +620,25 @@ namespace ngcore
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
FlatArray<T> View (FlatArray<T> fa) { return fa; }
|
FlatArray<T> View (FlatArray<T> fa) { return fa; }
|
||||||
|
|
||||||
|
template <typename T, typename TI>
|
||||||
|
auto Max (FlatArray<T,TI> array, T max = std::numeric_limits<T>::min()) -> T
|
||||||
|
{
|
||||||
|
for (auto & v : array)
|
||||||
|
if (v > max) max = v;
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename TI>
|
||||||
|
auto Min (FlatArray<T,TI> array, T min = std::numeric_limits<T>::max()) -> T
|
||||||
|
{
|
||||||
|
for (auto & v : array)
|
||||||
|
if (v < min) min = v;
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
/// print array
|
/// print array
|
||||||
template <class T>
|
template <class T, class TIND>
|
||||||
inline ostream & operator<< (ostream & s, const FlatArray<T> & a)
|
inline ostream & operator<< (ostream & s, const FlatArray<T, TIND> & a)
|
||||||
{
|
{
|
||||||
for (auto i : a.Range())
|
for (auto i : a.Range())
|
||||||
s << i << ": " << a[i] << "\n";
|
s << i << ": " << a[i] << "\n";
|
||||||
@ -638,6 +675,7 @@ namespace ngcore
|
|||||||
/// that's the data we have to delete, nullptr for not owning the memory
|
/// that's the data we have to delete, nullptr for not owning the memory
|
||||||
T * mem_to_delete;
|
T * mem_to_delete;
|
||||||
|
|
||||||
|
|
||||||
using FlatArray<T,IndexType>::size;
|
using FlatArray<T,IndexType>::size;
|
||||||
using FlatArray<T,IndexType>::data;
|
using FlatArray<T,IndexType>::data;
|
||||||
using FlatArray<T,IndexType>::BASE;
|
using FlatArray<T,IndexType>::BASE;
|
||||||
@ -682,6 +720,8 @@ namespace ngcore
|
|||||||
|
|
||||||
NETGEN_INLINE Array (Array && a2)
|
NETGEN_INLINE Array (Array && a2)
|
||||||
{
|
{
|
||||||
|
mt.Swap(sizeof(T) * allocsize, a2.mt, sizeof(T) * a2.allocsize);
|
||||||
|
|
||||||
size = a2.size;
|
size = a2.size;
|
||||||
data = a2.data;
|
data = a2.data;
|
||||||
allocsize = a2.allocsize;
|
allocsize = a2.allocsize;
|
||||||
@ -696,10 +736,15 @@ namespace ngcore
|
|||||||
NETGEN_INLINE explicit Array (const Array & a2)
|
NETGEN_INLINE explicit Array (const Array & a2)
|
||||||
: FlatArray<T,IndexType> (a2.Size(), a2.Size() ? new T[a2.Size()] : nullptr)
|
: FlatArray<T,IndexType> (a2.Size(), a2.Size() ? new T[a2.Size()] : nullptr)
|
||||||
{
|
{
|
||||||
allocsize = size;
|
if constexpr (std::is_copy_assignable<T>::value)
|
||||||
mem_to_delete = data;
|
{
|
||||||
for (size_t i = 0; i < size; i++)
|
allocsize = size;
|
||||||
data[i] = a2.data[i];
|
mem_to_delete = data;
|
||||||
|
for (size_t i = 0; i < size; i++)
|
||||||
|
data[i] = a2.data[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw Exception(std::string("cannot copy-construct Array of type ") + typeid(T).name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -747,6 +792,8 @@ namespace ngcore
|
|||||||
/// if responsible, deletes memory
|
/// if responsible, deletes memory
|
||||||
NETGEN_INLINE ~Array()
|
NETGEN_INLINE ~Array()
|
||||||
{
|
{
|
||||||
|
if(mem_to_delete)
|
||||||
|
mt.Free(sizeof(T)*allocsize);
|
||||||
delete [] mem_to_delete;
|
delete [] mem_to_delete;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -801,6 +848,8 @@ namespace ngcore
|
|||||||
/// assigns memory from local heap
|
/// assigns memory from local heap
|
||||||
NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh)
|
NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh)
|
||||||
{
|
{
|
||||||
|
if(mem_to_delete)
|
||||||
|
mt.Free(sizeof(T)*allocsize);
|
||||||
delete [] mem_to_delete;
|
delete [] mem_to_delete;
|
||||||
size = allocsize = asize;
|
size = allocsize = asize;
|
||||||
data = lh.Alloc<T> (asize);
|
data = lh.Alloc<T> (asize);
|
||||||
@ -858,7 +907,7 @@ namespace ngcore
|
|||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
NETGEN_INLINE Array<T> & operator += (const T & el)
|
NETGEN_INLINE Array & operator += (const T & el)
|
||||||
{
|
{
|
||||||
Append (el);
|
Append (el);
|
||||||
return *this;
|
return *this;
|
||||||
@ -908,6 +957,8 @@ namespace ngcore
|
|||||||
/// Deallocate memory
|
/// Deallocate memory
|
||||||
NETGEN_INLINE void DeleteAll ()
|
NETGEN_INLINE void DeleteAll ()
|
||||||
{
|
{
|
||||||
|
if(mem_to_delete)
|
||||||
|
mt.Free(sizeof(T)*allocsize);
|
||||||
delete [] mem_to_delete;
|
delete [] mem_to_delete;
|
||||||
mem_to_delete = NULL;
|
mem_to_delete = NULL;
|
||||||
data = 0;
|
data = 0;
|
||||||
@ -924,16 +975,24 @@ namespace ngcore
|
|||||||
/// array copy
|
/// array copy
|
||||||
NETGEN_INLINE Array & operator= (const Array & a2)
|
NETGEN_INLINE Array & operator= (const Array & a2)
|
||||||
{
|
{
|
||||||
SetSize0 ();
|
if constexpr (std::is_copy_assignable<T>::value)
|
||||||
SetSize (a2.Size());
|
{
|
||||||
for (size_t i = 0; i < size; i++)
|
SetSize0 ();
|
||||||
data[i] = a2.data[i];
|
SetSize (a2.Size());
|
||||||
return *this;
|
for (size_t i = 0; i < size; i++)
|
||||||
|
data[i] = a2.data[i];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw Exception(std::string("cannot copy Array of type ") + typeid(T).name());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// steal array
|
/// steal array
|
||||||
NETGEN_INLINE Array & operator= (Array && a2)
|
NETGEN_INLINE Array & operator= (Array && a2)
|
||||||
{
|
{
|
||||||
|
mt.Swap(sizeof(T)*allocsize, a2.mt, sizeof(T)*a2.allocsize);
|
||||||
|
|
||||||
ngcore::Swap (size, a2.size);
|
ngcore::Swap (size, a2.size);
|
||||||
ngcore::Swap (data, a2.data);
|
ngcore::Swap (data, a2.data);
|
||||||
ngcore::Swap (allocsize, a2.allocsize);
|
ngcore::Swap (allocsize, a2.allocsize);
|
||||||
@ -1007,16 +1066,26 @@ namespace ngcore
|
|||||||
|
|
||||||
NETGEN_INLINE void Swap (Array & b)
|
NETGEN_INLINE void Swap (Array & b)
|
||||||
{
|
{
|
||||||
|
mt.Swap(sizeof(T) * allocsize, b.mt, sizeof(T) * b.allocsize);
|
||||||
|
|
||||||
ngcore::Swap (size, b.size);
|
ngcore::Swap (size, b.size);
|
||||||
ngcore::Swap (data, b.data);
|
ngcore::Swap (data, b.data);
|
||||||
ngcore::Swap (allocsize, b.allocsize);
|
ngcore::Swap (allocsize, b.allocsize);
|
||||||
ngcore::Swap (mem_to_delete, b.mem_to_delete);
|
ngcore::Swap (mem_to_delete, b.mem_to_delete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE void StartMemoryTracing () const
|
||||||
|
{
|
||||||
|
mt.Alloc(sizeof(T) * allocsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
const MemoryTracer& GetMemoryTracer() const { return mt; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// resize array, at least to size minsize. copy contents
|
/// resize array, at least to size minsize. copy contents
|
||||||
NETGEN_INLINE void ReSize (size_t minsize);
|
NETGEN_INLINE void ReSize (size_t minsize);
|
||||||
|
MemoryTracer mt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1029,6 +1098,7 @@ namespace ngcore
|
|||||||
|
|
||||||
T * hdata = data;
|
T * hdata = data;
|
||||||
data = new T[nsize];
|
data = new T[nsize];
|
||||||
|
mt.Alloc(sizeof(T) * nsize);
|
||||||
|
|
||||||
if (hdata)
|
if (hdata)
|
||||||
{
|
{
|
||||||
@ -1041,6 +1111,8 @@ namespace ngcore
|
|||||||
else
|
else
|
||||||
for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]);
|
for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]);
|
||||||
#endif
|
#endif
|
||||||
|
if(mem_to_delete)
|
||||||
|
mt.Free(sizeof(T) * allocsize);
|
||||||
delete [] mem_to_delete;
|
delete [] mem_to_delete;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1124,6 +1196,14 @@ namespace ngcore
|
|||||||
data[cnt++] = val;
|
data[cnt++] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T2>
|
||||||
|
ArrayMem (const BaseArrayObject<T2> & a2)
|
||||||
|
: ArrayMem (a2.Size())
|
||||||
|
{
|
||||||
|
for (size_t i : ngcore::Range(size))
|
||||||
|
data[i] = a2[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ArrayMem & operator= (const T & val)
|
ArrayMem & operator= (const T & val)
|
||||||
{
|
{
|
||||||
@ -1179,7 +1259,7 @@ namespace ngcore
|
|||||||
|
|
||||||
|
|
||||||
template <typename ... ARGS>
|
template <typename ... ARGS>
|
||||||
size_t ArraySize (Tuple<ARGS...> tup)
|
size_t ArraySize (Tuple<ARGS...> /* tup */)
|
||||||
{ return 0;}
|
{ return 0;}
|
||||||
|
|
||||||
template <typename ... ARGS>
|
template <typename ... ARGS>
|
||||||
@ -1192,7 +1272,7 @@ namespace ngcore
|
|||||||
|
|
||||||
|
|
||||||
template <typename T, typename ... ARGS>
|
template <typename T, typename ... ARGS>
|
||||||
void StoreToArray (FlatArray<T> a, Tuple<ARGS...> tup) { ; }
|
void StoreToArray (FlatArray<T> /* a */, Tuple<ARGS...> /* tup */) { ; }
|
||||||
|
|
||||||
template <typename T, typename ... ARGS>
|
template <typename T, typename ... ARGS>
|
||||||
void StoreToArray (FlatArray<T> a, Tuple<int,ARGS...> tup)
|
void StoreToArray (FlatArray<T> a, Tuple<int,ARGS...> tup)
|
||||||
@ -1284,7 +1364,7 @@ namespace ngcore
|
|||||||
|
|
||||||
/// bubble sort array
|
/// bubble sort array
|
||||||
template <class T, class S>
|
template <class T, class S>
|
||||||
inline void BubbleSort (FlatArray<T> data, FlatArray<S> slave)
|
inline void BubbleSort (FlatArray<T> data, FlatArray<S> index)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < data.Size(); i++)
|
for (size_t i = 0; i < data.Size(); i++)
|
||||||
for (size_t j = i+1; j < data.Size(); j++)
|
for (size_t j = i+1; j < data.Size(); j++)
|
||||||
@ -1294,9 +1374,9 @@ namespace ngcore
|
|||||||
data[i] = data[j];
|
data[i] = data[j];
|
||||||
data[j] = hv;
|
data[j] = hv;
|
||||||
|
|
||||||
S hvs = slave[i];
|
S hvs = index[i];
|
||||||
slave[i] = slave[j];
|
index[i] = index[j];
|
||||||
slave[j] = hvs;
|
index[j] = hvs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +36,15 @@ namespace ngcore
|
|||||||
void BitArray :: SetSize (size_t asize)
|
void BitArray :: SetSize (size_t asize)
|
||||||
{
|
{
|
||||||
if (size == asize) return;
|
if (size == asize) return;
|
||||||
if (owns_data) delete [] data;
|
if (owns_data)
|
||||||
|
{
|
||||||
|
delete [] data;
|
||||||
|
mt.Free(Addr(size)+1);
|
||||||
|
}
|
||||||
|
|
||||||
size = asize;
|
size = asize;
|
||||||
data = new unsigned char [Addr (size)+1];
|
data = new unsigned char [Addr (size)+1];
|
||||||
|
mt.Alloc(Addr(size)+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
BitArray & BitArray :: Set () throw()
|
BitArray & BitArray :: Set () throw()
|
||||||
@ -83,6 +88,18 @@ namespace ngcore
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BitArray :: operator==(const BitArray& other) const
|
||||||
|
{
|
||||||
|
if(size != other.Size())
|
||||||
|
return false;
|
||||||
|
for(auto i : Range(size/CHAR_BIT))
|
||||||
|
if(data[i] != other.data[i])
|
||||||
|
return false;
|
||||||
|
for(auto i : Range(size%CHAR_BIT))
|
||||||
|
if(Test(i + CHAR_BIT * (size/CHAR_BIT)) != other.Test(i + CHAR_BIT * (size/CHAR_BIT)))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
BitArray & BitArray :: operator= (const BitArray & ba2)
|
BitArray & BitArray :: operator= (const BitArray & ba2)
|
||||||
{
|
{
|
||||||
@ -115,29 +132,52 @@ namespace ngcore
|
|||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
Archive & operator & (Archive & archive, BitArray & ba)
|
void BitArray :: DoArchive(Archive& archive)
|
||||||
{
|
{
|
||||||
if (archive.Output())
|
if(archive.GetVersion("netgen") >= "v6.2.2007-62")
|
||||||
{
|
{
|
||||||
archive << ba.Size();
|
archive.NeedsVersion("netgen", "v6.2.2007-62");
|
||||||
for (size_t i = 0; i < ba.Size(); i++)
|
auto size = Size();
|
||||||
archive << ba[i];
|
archive & size;
|
||||||
|
if(archive.Input())
|
||||||
|
SetSize(size);
|
||||||
|
if(archive.GetVersion("netgen") < "v6.2.2009-20")
|
||||||
|
archive.Do(data, size/CHAR_BIT+1);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
archive.NeedsVersion("netgen", "v6.2.2009-20");
|
||||||
|
archive.Do(data, size/CHAR_BIT);
|
||||||
|
for(size_t i = 0; i < size%CHAR_BIT; i++)
|
||||||
|
{
|
||||||
|
size_t index = CHAR_BIT * (size/CHAR_BIT) + i;
|
||||||
|
bool b = Test(index);
|
||||||
|
archive & b;
|
||||||
|
b ? SetBit(index) : Clear(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int size;
|
if (archive.Output())
|
||||||
archive & size;
|
|
||||||
ba.SetSize (size);
|
|
||||||
ba.Clear();
|
|
||||||
for (size_t i = 0; i < size; i++)
|
|
||||||
{
|
{
|
||||||
bool b;
|
throw Exception("should not get here");
|
||||||
archive & b;
|
archive << Size();
|
||||||
if (b) ba.SetBit(i);
|
for (size_t i = 0; i < Size(); i++)
|
||||||
|
archive << (*this)[i];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
archive & size;
|
||||||
|
SetSize (size);
|
||||||
|
Clear();
|
||||||
|
for (size_t i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
bool b;
|
||||||
|
archive & b;
|
||||||
|
if (b) SetBit(i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return archive;
|
|
||||||
}
|
}
|
||||||
|
} // namespace ngcore
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -131,6 +131,7 @@ public:
|
|||||||
return Test(i);
|
return Test(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NGCORE_API bool operator==(const BitArray& other) const;
|
||||||
|
|
||||||
/// invert all bits
|
/// invert all bits
|
||||||
NGCORE_API BitArray & Invert ();
|
NGCORE_API BitArray & Invert ();
|
||||||
@ -145,6 +146,18 @@ public:
|
|||||||
NGCORE_API BitArray & operator= (const BitArray & ba2);
|
NGCORE_API BitArray & operator= (const BitArray & ba2);
|
||||||
|
|
||||||
NGCORE_API size_t NumSet () const;
|
NGCORE_API size_t NumSet () const;
|
||||||
|
|
||||||
|
NGCORE_API void DoArchive(Archive& archive);
|
||||||
|
|
||||||
|
NGCORE_API auto * Data() const { return data; }
|
||||||
|
|
||||||
|
const MemoryTracer& GetMemoryTracer() const { return mt; }
|
||||||
|
void StartMemoryTracing() const
|
||||||
|
{
|
||||||
|
if(owns_data)
|
||||||
|
mt.Alloc(Addr(size)+1);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
///
|
///
|
||||||
unsigned char Mask (size_t i) const
|
unsigned char Mask (size_t i) const
|
||||||
@ -154,6 +167,7 @@ private:
|
|||||||
size_t Addr (size_t i) const
|
size_t Addr (size_t i) const
|
||||||
{ return (i / CHAR_BIT); }
|
{ return (i / CHAR_BIT); }
|
||||||
|
|
||||||
|
MemoryTracer mt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -190,11 +204,8 @@ private:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NGCORE_API std::ostream & operator<<(std::ostream & s, const BitArray & ba);
|
NGCORE_API std::ostream & operator<<(std::ostream & s, const BitArray & ba);
|
||||||
|
|
||||||
NGCORE_API Archive & operator & (Archive & archive, BitArray & ba);
|
|
||||||
|
|
||||||
} // namespace ngcore
|
} // namespace ngcore
|
||||||
|
|
||||||
#endif // NETGEN_CORE_BITARRAY
|
#endif // NETGEN_CORE_BITARRAY
|
||||||
|
@ -217,9 +217,12 @@ static void ngcore_signal_handler(int sig)
|
|||||||
// register signal handler when library is loaded
|
// register signal handler when library is loaded
|
||||||
static bool dummy = []()
|
static bool dummy = []()
|
||||||
{
|
{
|
||||||
signal(SIGABRT, ngcore_signal_handler);
|
if(getenv("NG_BACKTRACE"))
|
||||||
signal(SIGILL, ngcore_signal_handler);
|
{
|
||||||
signal(SIGSEGV, ngcore_signal_handler);
|
signal(SIGABRT, ngcore_signal_handler);
|
||||||
|
signal(SIGILL, ngcore_signal_handler);
|
||||||
|
signal(SIGSEGV, ngcore_signal_handler);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
|
@ -51,6 +51,10 @@ namespace ngcore
|
|||||||
auto lflags = flags.GetFlagsFlag (i, name);
|
auto lflags = flags.GetFlagsFlag (i, name);
|
||||||
SetFlag (name, lflags);
|
SetFlag (name, lflags);
|
||||||
}
|
}
|
||||||
|
for(auto i : Range(flags.anyflags.Size()))
|
||||||
|
{
|
||||||
|
SetFlag(flags.anyflags.GetName(i), flags.anyflags[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Flags :: Flags (Flags && flags)
|
Flags :: Flags (Flags && flags)
|
||||||
@ -178,7 +182,11 @@ namespace ngcore
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Flags & Flags :: SetFlag (const string & name, const std::any & val)
|
||||||
|
{
|
||||||
|
anyflags.Set(name, val);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
string Flags :: GetStringFlag (const string & name, const char * def) const
|
string Flags :: GetStringFlag (const string & name, const char * def) const
|
||||||
{
|
{
|
||||||
@ -279,6 +287,14 @@ namespace ngcore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::any& Flags:: GetAnyFlag(const std::string& name) const
|
||||||
|
{
|
||||||
|
if(anyflags.Used(name))
|
||||||
|
return anyflags[name];
|
||||||
|
static std::any empty;
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
bool Flags :: StringFlagDefined (const string & name) const
|
bool Flags :: StringFlagDefined (const string & name) const
|
||||||
{
|
{
|
||||||
return strflags.Used (name);
|
return strflags.Used (name);
|
||||||
@ -304,6 +320,11 @@ namespace ngcore
|
|||||||
return numlistflags.Used (name);
|
return numlistflags.Used (name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Flags :: AnyFlagDefined (const string& name) const
|
||||||
|
{
|
||||||
|
return anyflags.Used(name);
|
||||||
|
}
|
||||||
|
|
||||||
void Flags :: SaveFlags (ostream & str) const
|
void Flags :: SaveFlags (ostream & str) const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < strflags.Size(); i++)
|
for (int i = 0; i < strflags.Size(); i++)
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <any>
|
||||||
|
|
||||||
#include "array.hpp"
|
#include "array.hpp"
|
||||||
#include "symboltable.hpp"
|
#include "symboltable.hpp"
|
||||||
@ -38,6 +39,8 @@ namespace ngcore
|
|||||||
SymbolTable<std::shared_ptr<Array<double>>> numlistflags;
|
SymbolTable<std::shared_ptr<Array<double>>> numlistflags;
|
||||||
/// flags list flags
|
/// flags list flags
|
||||||
SymbolTable<Flags> flaglistflags;
|
SymbolTable<Flags> flaglistflags;
|
||||||
|
/// any object can be stored as a flag
|
||||||
|
SymbolTable<std::any> anyflags;
|
||||||
public:
|
public:
|
||||||
/// no flags
|
/// no flags
|
||||||
Flags ();
|
Flags ();
|
||||||
@ -94,6 +97,8 @@ namespace ngcore
|
|||||||
Flags & SetFlag (const std::string & name, const Array<std::string> & val);
|
Flags & SetFlag (const std::string & name, const Array<std::string> & val);
|
||||||
/// Sets double array flag
|
/// Sets double array flag
|
||||||
Flags & SetFlag (const std::string & name, const Array<double> & val);
|
Flags & SetFlag (const std::string & name, const Array<double> & val);
|
||||||
|
/// Sets any flag
|
||||||
|
Flags & SetFlag(const std::string& name, const std::any& val);
|
||||||
|
|
||||||
|
|
||||||
Flags SetFlag (const char * name, bool b = true) &&;
|
Flags SetFlag (const char * name, bool b = true) &&;
|
||||||
@ -135,6 +140,7 @@ namespace ngcore
|
|||||||
const Array<double> & GetNumListFlag (const std::string & name) const;
|
const Array<double> & GetNumListFlag (const std::string & name) const;
|
||||||
/// Returns flag list flag, empty flag if not exist
|
/// Returns flag list flag, empty flag if not exist
|
||||||
const Flags & GetFlagsFlag (const std::string & name) const;
|
const Flags & GetFlagsFlag (const std::string & name) const;
|
||||||
|
const std::any& GetAnyFlag (const std::string& name) const;
|
||||||
|
|
||||||
|
|
||||||
/// Test, if string flag is defined
|
/// Test, if string flag is defined
|
||||||
@ -147,6 +153,7 @@ namespace ngcore
|
|||||||
bool StringListFlagDefined (const std::string & name) const;
|
bool StringListFlagDefined (const std::string & name) const;
|
||||||
/// Test, if num list flag is defined
|
/// Test, if num list flag is defined
|
||||||
bool NumListFlagDefined (const std::string & name) const;
|
bool NumListFlagDefined (const std::string & name) const;
|
||||||
|
bool AnyFlagDefined (const std::string& name) const;
|
||||||
|
|
||||||
/// number of string flags
|
/// number of string flags
|
||||||
int GetNStringFlags () const { return strflags.Size(); }
|
int GetNStringFlags () const { return strflags.Size(); }
|
||||||
|
@ -174,6 +174,13 @@ namespace ngcore
|
|||||||
{
|
{
|
||||||
return MakeTupleFromInt<N>()(*this);
|
return MakeTupleFromInt<N>()(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Contains (T val)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < N; j++)
|
||||||
|
if (i[j] == val) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// sort 2 integers
|
/// sort 2 integers
|
||||||
@ -727,6 +734,11 @@ namespace ngcore
|
|||||||
acont = cont[pos];
|
acont = cont[pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
T GetData (size_t pos) const
|
||||||
|
{
|
||||||
|
return cont[pos];
|
||||||
|
}
|
||||||
|
|
||||||
std::pair<T_HASH,T> GetBoth (size_t pos) const
|
std::pair<T_HASH,T> GetBoth (size_t pos) const
|
||||||
{
|
{
|
||||||
return std::pair<T_HASH,T> (hash[pos], cont[pos]);
|
return std::pair<T_HASH,T> (hash[pos], cont[pos]);
|
||||||
|
@ -198,9 +198,9 @@ public:
|
|||||||
return reinterpret_cast<T*> (oldp);
|
return reinterpret_cast<T*> (oldp);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Delete(void* p) {}
|
virtual void Delete(void* /* p */) {}
|
||||||
|
|
||||||
virtual void ArrayDelete(void* p) {}
|
virtual void ArrayDelete(void* /* p */) {}
|
||||||
private:
|
private:
|
||||||
///
|
///
|
||||||
#ifndef __CUDA_ARCH__
|
#ifndef __CUDA_ARCH__
|
||||||
@ -211,7 +211,7 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/// free memory (dummy function)
|
/// free memory (dummy function)
|
||||||
NETGEN_INLINE void Free (void * data) throw ()
|
NETGEN_INLINE void Free (void * /* data */) throw ()
|
||||||
{
|
{
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "array.hpp"
|
#include "array.hpp"
|
||||||
#include "exception.hpp"
|
#include "exception.hpp"
|
||||||
|
#include "profiler.hpp"
|
||||||
|
|
||||||
namespace ngcore
|
namespace ngcore
|
||||||
{
|
{
|
||||||
@ -25,6 +26,9 @@ namespace ngcore
|
|||||||
template <> struct MPI_typetrait<char> {
|
template <> struct MPI_typetrait<char> {
|
||||||
static MPI_Datatype MPIType () { return MPI_CHAR; } };
|
static MPI_Datatype MPIType () { return MPI_CHAR; } };
|
||||||
|
|
||||||
|
template <> struct MPI_typetrait<signed char> {
|
||||||
|
static MPI_Datatype MPIType () { return MPI_CHAR; } };
|
||||||
|
|
||||||
template <> struct MPI_typetrait<unsigned char> {
|
template <> struct MPI_typetrait<unsigned char> {
|
||||||
static MPI_Datatype MPIType () { return MPI_CHAR; } };
|
static MPI_Datatype MPIType () { return MPI_CHAR; } };
|
||||||
|
|
||||||
@ -43,6 +47,10 @@ namespace ngcore
|
|||||||
return MPI_typetrait<T>::MPIType();
|
return MPI_typetrait<T>::MPIType();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline MPI_Datatype GetMPIType (T &) {
|
||||||
|
return GetMPIType<T>();
|
||||||
|
}
|
||||||
|
|
||||||
class NgMPI_Comm
|
class NgMPI_Comm
|
||||||
{
|
{
|
||||||
@ -59,6 +67,17 @@ namespace ngcore
|
|||||||
NgMPI_Comm (MPI_Comm _comm, bool owns = false)
|
NgMPI_Comm (MPI_Comm _comm, bool owns = false)
|
||||||
: comm(_comm), valid_comm(true)
|
: comm(_comm), valid_comm(true)
|
||||||
{
|
{
|
||||||
|
int flag;
|
||||||
|
MPI_Initialized (&flag);
|
||||||
|
if (!flag)
|
||||||
|
{
|
||||||
|
valid_comm = false;
|
||||||
|
refcount = nullptr;
|
||||||
|
rank = 0;
|
||||||
|
size = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!owns)
|
if (!owns)
|
||||||
refcount = nullptr;
|
refcount = nullptr;
|
||||||
else
|
else
|
||||||
@ -89,6 +108,11 @@ namespace ngcore
|
|||||||
MPI_Comm_free(&comm);
|
MPI_Comm_free(&comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ValidCommunicator() const
|
||||||
|
{
|
||||||
|
return valid_comm;
|
||||||
|
}
|
||||||
|
|
||||||
NgMPI_Comm & operator= (const NgMPI_Comm & c)
|
NgMPI_Comm & operator= (const NgMPI_Comm & c)
|
||||||
{
|
{
|
||||||
if (refcount)
|
if (refcount)
|
||||||
@ -117,6 +141,7 @@ namespace ngcore
|
|||||||
int Rank() const { return rank; }
|
int Rank() const { return rank; }
|
||||||
int Size() const { return size; }
|
int Size() const { return size; }
|
||||||
void Barrier() const {
|
void Barrier() const {
|
||||||
|
static Timer t("MPI - Barrier"); RegionTimer reg(t);
|
||||||
if (size > 1) MPI_Barrier (comm);
|
if (size > 1) MPI_Barrier (comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,9 +152,13 @@ namespace ngcore
|
|||||||
void Send (T & val, int dest, int tag) const {
|
void Send (T & val, int dest, int tag) const {
|
||||||
MPI_Send (&val, 1, GetMPIType<T>(), dest, tag, comm);
|
MPI_Send (&val, 1, GetMPIType<T>(), dest, tag, comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Send (const std::string & s, int dest, int tag) const {
|
||||||
|
MPI_Send( const_cast<char*> (&s[0]), s.length(), MPI_CHAR, dest, tag, comm);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename T, typename T2 = decltype(GetMPIType<T>())>
|
template<typename T, typename TI, typename T2 = decltype(GetMPIType<T>())>
|
||||||
void Send(FlatArray<T> s, int dest, int tag) const {
|
void Send(FlatArray<T,TI> s, int dest, int tag) const {
|
||||||
MPI_Send (s.Data(), s.Size(), GetMPIType<T>(), dest, tag, comm);
|
MPI_Send (s.Data(), s.Size(), GetMPIType<T>(), dest, tag, comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,13 +167,24 @@ namespace ngcore
|
|||||||
MPI_Recv (&val, 1, GetMPIType<T>(), src, tag, comm, MPI_STATUS_IGNORE);
|
MPI_Recv (&val, 1, GetMPIType<T>(), src, tag, comm, MPI_STATUS_IGNORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename T2 = decltype(GetMPIType<T>())>
|
void Recv (std::string & s, int src, int tag) const {
|
||||||
void Recv (FlatArray <T> s, int src, int tag) const {
|
MPI_Status status;
|
||||||
|
int len;
|
||||||
|
MPI_Probe (src, tag, comm, &status);
|
||||||
|
MPI_Get_count (&status, MPI_CHAR, &len);
|
||||||
|
// s.assign (len, ' ');
|
||||||
|
s.resize (len);
|
||||||
|
MPI_Recv( &s[0], len, MPI_CHAR, src, tag, comm, MPI_STATUS_IGNORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, typename TI, typename T2 = decltype(GetMPIType<T>())>
|
||||||
|
void Recv (FlatArray <T,TI> s, int src, int tag) const {
|
||||||
MPI_Recv (s.Data(), s.Size(), GetMPIType<T> (), src, tag, comm, MPI_STATUS_IGNORE);
|
MPI_Recv (s.Data(), s.Size(), GetMPIType<T> (), src, tag, comm, MPI_STATUS_IGNORE);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename T2 = decltype(GetMPIType<T>())>
|
template <typename T, typename TI, typename T2 = decltype(GetMPIType<T>())>
|
||||||
void Recv (Array <T> & s, int src, int tag) const
|
void Recv (Array <T,TI> & s, int src, int tag) const
|
||||||
{
|
{
|
||||||
MPI_Status status;
|
MPI_Status status;
|
||||||
int len;
|
int len;
|
||||||
@ -166,7 +206,7 @@ namespace ngcore
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename T2 = decltype(GetMPIType<T>())>
|
template<typename T, typename T2 = decltype(GetMPIType<T>())>
|
||||||
MPI_Request ISend (const FlatArray<T> & s, int dest, int tag) const
|
MPI_Request ISend (FlatArray<T> s, int dest, int tag) const
|
||||||
{
|
{
|
||||||
MPI_Request request;
|
MPI_Request request;
|
||||||
MPI_Isend (s.Data(), s.Size(), GetMPIType<T>(), dest, tag, comm, &request);
|
MPI_Isend (s.Data(), s.Size(), GetMPIType<T>(), dest, tag, comm, &request);
|
||||||
@ -182,7 +222,7 @@ namespace ngcore
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename T2 = decltype(GetMPIType<T>())>
|
template<typename T, typename T2 = decltype(GetMPIType<T>())>
|
||||||
MPI_Request IRecv (const FlatArray<T> & s, int src, int tag) const
|
MPI_Request IRecv (FlatArray<T> s, int src, int tag) const
|
||||||
{
|
{
|
||||||
MPI_Request request;
|
MPI_Request request;
|
||||||
MPI_Irecv (s.Data(), s.Size(), GetMPIType<T>(), src, tag, comm, &request);
|
MPI_Irecv (s.Data(), s.Size(), GetMPIType<T>(), src, tag, comm, &request);
|
||||||
@ -195,6 +235,7 @@ namespace ngcore
|
|||||||
template <typename T, typename T2 = decltype(GetMPIType<T>())>
|
template <typename T, typename T2 = decltype(GetMPIType<T>())>
|
||||||
T Reduce (T d, const MPI_Op & op, int root = 0) const
|
T Reduce (T d, const MPI_Op & op, int root = 0) const
|
||||||
{
|
{
|
||||||
|
static Timer t("MPI - Reduce"); RegionTimer reg(t);
|
||||||
if (size == 1) return d;
|
if (size == 1) return d;
|
||||||
|
|
||||||
T global_d;
|
T global_d;
|
||||||
@ -205,6 +246,7 @@ namespace ngcore
|
|||||||
template <typename T, typename T2 = decltype(GetMPIType<T>())>
|
template <typename T, typename T2 = decltype(GetMPIType<T>())>
|
||||||
T AllReduce (T d, const MPI_Op & op) const
|
T AllReduce (T d, const MPI_Op & op) const
|
||||||
{
|
{
|
||||||
|
static Timer t("MPI - AllReduce"); RegionTimer reg(t);
|
||||||
if (size == 1) return d;
|
if (size == 1) return d;
|
||||||
|
|
||||||
T global_d;
|
T global_d;
|
||||||
@ -227,6 +269,44 @@ namespace ngcore
|
|||||||
MPI_Bcast (&s[0], len, MPI_CHAR, root, comm);
|
MPI_Bcast (&s[0], len, MPI_CHAR, root, comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void AllToAll (FlatArray<T> send, FlatArray<T> recv) const
|
||||||
|
{
|
||||||
|
MPI_Alltoall (send.Data(), 1, GetMPIType<T>(),
|
||||||
|
recv.Data(), 1, GetMPIType<T>(), comm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void ScatterRoot (FlatArray<T> send) const
|
||||||
|
{
|
||||||
|
if (size == 1) return;
|
||||||
|
MPI_Scatter (send.Data(), 1, GetMPIType<T>(),
|
||||||
|
MPI_IN_PLACE, -1, GetMPIType<T>(), 0, comm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Scatter (T & recv) const
|
||||||
|
{
|
||||||
|
if (size == 1) return;
|
||||||
|
MPI_Scatter (NULL, 0, GetMPIType<T>(),
|
||||||
|
&recv, 1, GetMPIType<T>(), 0, comm);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void AllGather (T val, FlatArray<T> recv) const
|
||||||
|
{
|
||||||
|
if (size == 1)
|
||||||
|
{
|
||||||
|
recv[0] = val;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MPI_Allgather (&val, 1, GetMPIType<T>(),
|
||||||
|
recv.Data(), 1, GetMPIType<T>(),
|
||||||
|
comm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NgMPI_Comm SubCommunicator (FlatArray<int> procs) const
|
NgMPI_Comm SubCommunicator (FlatArray<int> procs) const
|
||||||
{
|
{
|
||||||
MPI_Comm subcomm;
|
MPI_Comm subcomm;
|
||||||
@ -241,6 +321,7 @@ namespace ngcore
|
|||||||
|
|
||||||
NETGEN_INLINE void MyMPI_WaitAll (FlatArray<MPI_Request> requests)
|
NETGEN_INLINE void MyMPI_WaitAll (FlatArray<MPI_Request> requests)
|
||||||
{
|
{
|
||||||
|
static Timer t("MPI - WaitAll"); RegionTimer reg(t);
|
||||||
if (!requests.Size()) return;
|
if (!requests.Size()) return;
|
||||||
MPI_Waitall (requests.Size(), requests.Data(), MPI_STATUSES_IGNORE);
|
MPI_Waitall (requests.Size(), requests.Data(), MPI_STATUSES_IGNORE);
|
||||||
}
|
}
|
||||||
@ -263,9 +344,10 @@ namespace ngcore
|
|||||||
static MPI_Comm MPI_COMM_WORLD = 12345, MPI_COMM_NULL = 10000;
|
static MPI_Comm MPI_COMM_WORLD = 12345, MPI_COMM_NULL = 10000;
|
||||||
|
|
||||||
typedef int MPI_Op;
|
typedef int MPI_Op;
|
||||||
|
typedef int MPI_Datatype;
|
||||||
typedef int MPI_Request;
|
typedef int MPI_Request;
|
||||||
|
|
||||||
enum { MPI_SUM = 0, MPI_MIN = 1, MPI_MAX = 2 };
|
enum { MPI_SUM = 0, MPI_MIN = 1, MPI_MAX = 2, MPI_LOR = 4711 };
|
||||||
|
|
||||||
class NgMPI_Comm
|
class NgMPI_Comm
|
||||||
{
|
{
|
||||||
@ -276,6 +358,7 @@ namespace ngcore
|
|||||||
|
|
||||||
size_t Rank() const { return 0; }
|
size_t Rank() const { return 0; }
|
||||||
size_t Size() const { return 1; }
|
size_t Size() const { return 1; }
|
||||||
|
bool ValidCommunicator() const { return false; }
|
||||||
void Barrier() const { ; }
|
void Barrier() const { ; }
|
||||||
operator MPI_Comm() const { return MPI_Comm(); }
|
operator MPI_Comm() const { return MPI_Comm(); }
|
||||||
|
|
||||||
@ -298,13 +381,13 @@ namespace ngcore
|
|||||||
MPI_Request ISend (T & val, int dest, int tag) const { return 0; }
|
MPI_Request ISend (T & val, int dest, int tag) const { return 0; }
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
MPI_Request ISend (const FlatArray<T> & s, int dest, int tag) const { return 0; }
|
MPI_Request ISend (FlatArray<T> s, int dest, int tag) const { return 0; }
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
MPI_Request IRecv (T & val, int dest, int tag) const { return 0; }
|
MPI_Request IRecv (T & val, int dest, int tag) const { return 0; }
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
MPI_Request IRecv (const FlatArray<T> & s, int src, int tag) const { return 0; }
|
MPI_Request IRecv (FlatArray<T> s, int src, int tag) const { return 0; }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T Reduce (T d, const MPI_Op & op, int root = 0) const { return d; }
|
T Reduce (T d, const MPI_Op & op, int root = 0) const { return d; }
|
||||||
|
@ -6,14 +6,15 @@
|
|||||||
#include "bitarray.hpp"
|
#include "bitarray.hpp"
|
||||||
#include "exception.hpp"
|
#include "exception.hpp"
|
||||||
#include "flags.hpp"
|
#include "flags.hpp"
|
||||||
|
#include "table.hpp"
|
||||||
#include "hashtable.hpp"
|
#include "hashtable.hpp"
|
||||||
#include "localheap.hpp"
|
#include "localheap.hpp"
|
||||||
#include "logging.hpp"
|
#include "logging.hpp"
|
||||||
#include "mpi_wrapper.hpp"
|
#include "mpi_wrapper.hpp"
|
||||||
#include "profiler.hpp"
|
#include "profiler.hpp"
|
||||||
#include "signal.hpp"
|
#include "signal.hpp"
|
||||||
|
#include "simd.hpp"
|
||||||
#include "symboltable.hpp"
|
#include "symboltable.hpp"
|
||||||
#include "table.hpp"
|
|
||||||
#include "taskmanager.hpp"
|
#include "taskmanager.hpp"
|
||||||
#include "version.hpp"
|
#include "version.hpp"
|
||||||
#include "xbool.hpp"
|
#include "xbool.hpp"
|
||||||
|
@ -67,6 +67,18 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(__amd64__) || defined(_M_AMD64)
|
||||||
|
#define NETGEN_ARCH_AMD64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__aarch64__) || defined(_M_ARM64)
|
||||||
|
#define NETGEN_ARCH_ARM64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__arm__) || defined(_M_ARM)
|
||||||
|
#define NETGEN_ARCH_ARM
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
|
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
|
||||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101400
|
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101400
|
||||||
// The c++ standard library on MacOS 10.13 and earlier has no aligned new operator,
|
// The c++ standard library on MacOS 10.13 and earlier has no aligned new operator,
|
||||||
|
@ -8,28 +8,46 @@
|
|||||||
#include "archive.hpp" // for Demangle
|
#include "archive.hpp" // for Demangle
|
||||||
#include "paje_trace.hpp"
|
#include "paje_trace.hpp"
|
||||||
#include "profiler.hpp"
|
#include "profiler.hpp"
|
||||||
|
#include "mpi_wrapper.hpp"
|
||||||
|
|
||||||
extern const char *header;
|
extern const char *header;
|
||||||
|
|
||||||
|
constexpr int MPI_PAJE_WRITER = 1;
|
||||||
|
|
||||||
namespace ngcore
|
namespace ngcore
|
||||||
{
|
{
|
||||||
|
static std::string GetTimerName( int id )
|
||||||
|
{
|
||||||
|
#ifndef PARALLEL
|
||||||
|
return NgProfiler::GetName(id);
|
||||||
|
#else // PARALLEL
|
||||||
|
if(id<NgProfiler::SIZE)
|
||||||
|
return NgProfiler::GetName(id);
|
||||||
|
|
||||||
|
NgMPI_Comm comm(MPI_COMM_WORLD);
|
||||||
|
return NgProfiler::GetName(id-NgProfiler::SIZE*comm.Rank());
|
||||||
|
#endif // PARALLEL
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<PajeTrace::MemoryEvent> PajeTrace::memory_events;
|
||||||
|
|
||||||
// Produce no traces by default
|
// Produce no traces by default
|
||||||
size_t PajeTrace::max_tracefile_size = 0;
|
size_t PajeTrace::max_tracefile_size = 0;
|
||||||
|
|
||||||
// If true, produce variable counting active threads
|
// If true, produce variable counting active threads
|
||||||
// increases trace by a factor of two
|
// increases trace by a factor of two
|
||||||
bool PajeTrace::trace_thread_counter = true;
|
bool PajeTrace::trace_thread_counter = false;
|
||||||
bool PajeTrace::trace_threads = true;
|
bool PajeTrace::trace_threads = true;
|
||||||
|
bool PajeTrace::mem_tracing_enabled = true;
|
||||||
|
|
||||||
PajeTrace :: PajeTrace(int anthreads, std::string aname)
|
PajeTrace :: PajeTrace(int anthreads, std::string aname)
|
||||||
{
|
{
|
||||||
start_time = GetTimeCounter();
|
|
||||||
|
|
||||||
nthreads = anthreads;
|
nthreads = anthreads;
|
||||||
tracefile_name = std::move(aname);
|
tracefile_name = std::move(aname);
|
||||||
|
|
||||||
int bytes_per_event=33;
|
int bytes_per_event=33;
|
||||||
max_num_events_per_thread = std::min( static_cast<size_t>(std::numeric_limits<int>::max()), max_tracefile_size/bytes_per_event/(2*nthreads+1)*10/7);
|
max_num_events_per_thread = std::min( static_cast<size_t>(std::numeric_limits<int>::max()), max_tracefile_size/bytes_per_event/(nthreads+1+trace_thread_counter*nthreads)*10/7);
|
||||||
if(max_num_events_per_thread>0)
|
if(max_num_events_per_thread>0)
|
||||||
{
|
{
|
||||||
logger->info( "Tracefile size = {}MB", max_tracefile_size/1024/1024);
|
logger->info( "Tracefile size = {}MB", max_tracefile_size/1024/1024);
|
||||||
@ -47,14 +65,61 @@ namespace ngcore
|
|||||||
|
|
||||||
jobs.reserve(reserve_size);
|
jobs.reserve(reserve_size);
|
||||||
timer_events.reserve(reserve_size);
|
timer_events.reserve(reserve_size);
|
||||||
|
memory_events.reserve(1024*1024);
|
||||||
|
|
||||||
|
// sync start time when running in parallel
|
||||||
|
#ifdef PARALLEL
|
||||||
|
NgMPI_Comm comm(MPI_COMM_WORLD);
|
||||||
|
for(auto i : Range(5))
|
||||||
|
comm.Barrier();
|
||||||
|
#endif // PARALLEL
|
||||||
|
|
||||||
|
start_time = GetTimeCounter();
|
||||||
tracing_enabled = true;
|
tracing_enabled = true;
|
||||||
|
mem_tracing_enabled = true;
|
||||||
|
n_memory_events_at_start = memory_events.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
PajeTrace :: ~PajeTrace()
|
PajeTrace :: ~PajeTrace()
|
||||||
{
|
{
|
||||||
if(!tracefile_name.empty())
|
for(auto & ltask : tasks)
|
||||||
|
for(auto & task : ltask)
|
||||||
|
{
|
||||||
|
task.start_time -= start_time;
|
||||||
|
task.stop_time -= start_time;
|
||||||
|
}
|
||||||
|
for(auto & job : jobs)
|
||||||
|
{
|
||||||
|
job.start_time -= start_time;
|
||||||
|
job.stop_time -= start_time;
|
||||||
|
}
|
||||||
|
for(auto & event : timer_events)
|
||||||
|
event.time -= start_time;
|
||||||
|
|
||||||
|
for(auto & llink : links)
|
||||||
|
for(auto & link : llink)
|
||||||
|
link.time -= start_time;
|
||||||
|
|
||||||
|
for(auto i : IntRange(n_memory_events_at_start, memory_events.size()))
|
||||||
|
memory_events[i].time -= start_time;
|
||||||
|
|
||||||
|
NgMPI_Comm comm(MPI_COMM_WORLD);
|
||||||
|
|
||||||
|
if(comm.Size()==1)
|
||||||
|
{
|
||||||
Write(tracefile_name);
|
Write(tracefile_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// make sure the timer id is unique across all ranks
|
||||||
|
for(auto & event : timer_events)
|
||||||
|
event.timer_id += NgProfiler::SIZE*comm.Rank();
|
||||||
|
|
||||||
|
if(comm.Rank() == MPI_PAJE_WRITER)
|
||||||
|
Write(tracefile_name);
|
||||||
|
else
|
||||||
|
SendData();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -90,7 +155,6 @@ namespace ngcore
|
|||||||
int alias_counter;
|
int alias_counter;
|
||||||
|
|
||||||
FILE * ctrace_stream;
|
FILE * ctrace_stream;
|
||||||
TTimePoint start_time;
|
|
||||||
std::shared_ptr<Logger> logger = GetLogger("PajeTrace");
|
std::shared_ptr<Logger> logger = GetLogger("PajeTrace");
|
||||||
|
|
||||||
|
|
||||||
@ -98,7 +162,7 @@ namespace ngcore
|
|||||||
// return time in milliseconds as double
|
// return time in milliseconds as double
|
||||||
// return std::chrono::duration<double>(t-start_time).count()*1000.0;
|
// return std::chrono::duration<double>(t-start_time).count()*1000.0;
|
||||||
// return std::chrono::duration<double>(t-start_time).count() / 2.7e3;
|
// return std::chrono::duration<double>(t-start_time).count() / 2.7e3;
|
||||||
return 1000.0*static_cast<double>(t-start_time) * seconds_per_tick;
|
return 1000.0*static_cast<double>(t) * seconds_per_tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PType
|
enum PType
|
||||||
@ -180,10 +244,10 @@ namespace ngcore
|
|||||||
void operator=(const PajeFile &) = delete;
|
void operator=(const PajeFile &) = delete;
|
||||||
void operator=(PajeFile &&) = delete;
|
void operator=(PajeFile &&) = delete;
|
||||||
|
|
||||||
PajeFile( const std::string & filename, TTimePoint astart_time )
|
PajeFile( const std::string & filename)
|
||||||
{
|
{
|
||||||
start_time = astart_time;
|
std::string fname = filename + ".trace";
|
||||||
ctrace_stream = fopen (filename.c_str(),"w"); // NOLINT
|
ctrace_stream = fopen (fname.c_str(),"w"); // NOLINT
|
||||||
fprintf(ctrace_stream, "%s", header ); // NOLINT
|
fprintf(ctrace_stream, "%s", header ); // NOLINT
|
||||||
alias_counter = 0;
|
alias_counter = 0;
|
||||||
}
|
}
|
||||||
@ -365,39 +429,85 @@ namespace ngcore
|
|||||||
logger->warn("Tracing stopped during computation due to tracefile size limit of {} megabytes.", max_tracefile_size/1024/1024);
|
logger->warn("Tracing stopped during computation due to tracefile size limit of {} megabytes.", max_tracefile_size/1024/1024);
|
||||||
}
|
}
|
||||||
|
|
||||||
PajeFile paje(filename, start_time);
|
PajeFile paje(filename);
|
||||||
|
|
||||||
const int container_type_task_manager = paje.DefineContainerType( 0, "Task Manager" );
|
const int container_type_task_manager = paje.DefineContainerType( 0, "Task Manager" );
|
||||||
const int container_type_node = paje.DefineContainerType( container_type_task_manager, "Node");
|
const int container_type_node = paje.DefineContainerType( container_type_task_manager, "Node");
|
||||||
const int container_type_thread = paje.DefineContainerType( container_type_task_manager, "Thread");
|
const int container_type_thread = paje.DefineContainerType( container_type_task_manager, "Thread");
|
||||||
const int container_type_timer = container_type_thread; //paje.DefineContainerType( container_type_task_manager, "Timers");
|
const int container_type_timer = container_type_thread; //paje.DefineContainerType( container_type_task_manager, "Timers");
|
||||||
const int container_type_jobs = paje.DefineContainerType( container_type_task_manager, "Jobs");
|
const int container_type_jobs = paje.DefineContainerType( container_type_task_manager, "Jobs");
|
||||||
|
const int container_type_memory = paje.DefineContainerType( container_type_task_manager, "Memory usage");
|
||||||
|
|
||||||
const int state_type_job = paje.DefineStateType( container_type_jobs, "Job" );
|
const int state_type_job = paje.DefineStateType( container_type_jobs, "Job" );
|
||||||
const int state_type_task = paje.DefineStateType( container_type_thread, "Task" );
|
const int state_type_task = paje.DefineStateType( container_type_thread, "Task" );
|
||||||
const int state_type_timer = paje.DefineStateType( container_type_timer, "Timer state" );
|
const int state_type_timer = paje.DefineStateType( container_type_timer, "Timer state" );
|
||||||
|
|
||||||
const int variable_type_active_threads = paje.DefineVariableType( container_type_jobs, "Active threads" );
|
int variable_type_active_threads = 0;
|
||||||
|
if(trace_thread_counter)
|
||||||
|
variable_type_active_threads = paje.DefineVariableType( container_type_jobs, "Active threads" );
|
||||||
|
|
||||||
const int container_task_manager = paje.CreateContainer( container_type_task_manager, 0, "The task manager" );
|
const int container_task_manager = paje.CreateContainer( container_type_task_manager, 0, "The task manager" );
|
||||||
const int container_jobs = paje.CreateContainer( container_type_jobs, container_task_manager, "Jobs" );
|
const int container_jobs = paje.CreateContainer( container_type_jobs, container_task_manager, "Jobs" );
|
||||||
paje.SetVariable( start_time, variable_type_active_threads, container_jobs, 0.0 );
|
|
||||||
|
|
||||||
const int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1;
|
int variable_type_memory = 0;
|
||||||
|
const int container_memory = paje.CreateContainer( container_type_memory, container_task_manager, "Memory" );
|
||||||
|
if(mem_tracing_enabled)
|
||||||
|
{
|
||||||
|
variable_type_memory = paje.DefineVariableType( container_type_task_manager, "Memory [MB]" );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1;
|
||||||
|
std::vector <int> thread_aliases;
|
||||||
std::vector<int> container_nodes;
|
std::vector<int> container_nodes;
|
||||||
container_nodes.reserve(num_nodes);
|
|
||||||
for(int i=0; i<num_nodes; i++)
|
#ifdef PARALLEL
|
||||||
|
// Hostnames
|
||||||
|
NgMPI_Comm comm(MPI_COMM_WORLD);
|
||||||
|
auto rank = comm.Rank();
|
||||||
|
auto nranks = comm.Size();
|
||||||
|
if(nranks>1)
|
||||||
|
{
|
||||||
|
nthreads = nranks;
|
||||||
|
thread_aliases.reserve(nthreads);
|
||||||
|
|
||||||
|
std::array<char, MPI_MAX_PROCESSOR_NAME+1> ahostname;
|
||||||
|
int len;
|
||||||
|
MPI_Get_processor_name(ahostname.data(), &len);
|
||||||
|
std::string hostname = ahostname.data();
|
||||||
|
|
||||||
|
std::map<std::string, int> host_map;
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
for(auto i : IntRange(0, nranks))
|
||||||
|
{
|
||||||
|
if(i!=MPI_PAJE_WRITER)
|
||||||
|
comm.Recv(name, i, 0);
|
||||||
|
else
|
||||||
|
name = hostname;
|
||||||
|
if(host_map.count(name)==0)
|
||||||
|
{
|
||||||
|
host_map[name] = container_nodes.size();
|
||||||
|
container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, name) );
|
||||||
|
}
|
||||||
|
thread_aliases.emplace_back( paje.CreateContainer( container_type_thread, container_nodes[host_map[name]], "Rank " + ToString(i) ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif // PARALLEL
|
||||||
|
{
|
||||||
|
container_nodes.reserve(num_nodes);
|
||||||
|
for(int i=0; i<num_nodes; i++)
|
||||||
container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, "Node " + ToString(i)) );
|
container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, "Node " + ToString(i)) );
|
||||||
|
|
||||||
std::vector <int> thread_aliases;
|
thread_aliases.reserve(nthreads);
|
||||||
thread_aliases.reserve(nthreads);
|
if(trace_threads)
|
||||||
if(trace_threads)
|
for (int i=0; i<nthreads; i++)
|
||||||
for (int i=0; i<nthreads; i++)
|
|
||||||
{
|
{
|
||||||
auto name = "Thread " + ToString(i);
|
auto name = "Thread " + ToString(i);
|
||||||
thread_aliases.emplace_back( paje.CreateContainer( container_type_thread, container_nodes[i*num_nodes/nthreads], name ) );
|
thread_aliases.emplace_back( paje.CreateContainer( container_type_thread, container_nodes[i*num_nodes/nthreads], name ) );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::map<const std::type_info *, int> job_map;
|
std::map<const std::type_info *, int> job_map;
|
||||||
std::map<const std::type_info *, int> job_task_map;
|
std::map<const std::type_info *, int> job_task_map;
|
||||||
@ -416,20 +526,73 @@ namespace ngcore
|
|||||||
paje.PopState( j.stop_time, state_type_job, container_jobs );
|
paje.PopState( j.stop_time, state_type_job, container_jobs );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t memory_at_start = 0;
|
||||||
|
|
||||||
|
for(const auto & i : IntRange(0, n_memory_events_at_start))
|
||||||
|
{
|
||||||
|
if(memory_events[i].is_alloc)
|
||||||
|
memory_at_start += memory_events[i].size;
|
||||||
|
else
|
||||||
|
memory_at_start -= memory_events[i].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
paje.SetVariable( 0, variable_type_memory, container_memory, 1.0*memory_at_start/(1024*1024));
|
||||||
|
|
||||||
|
for(const auto & i : IntRange(n_memory_events_at_start, memory_events.size()))
|
||||||
|
{
|
||||||
|
auto & m = memory_events[i];
|
||||||
|
if(m.size==0)
|
||||||
|
continue;
|
||||||
|
double size = 1.0*m.size/(1024*1024);
|
||||||
|
if(m.is_alloc)
|
||||||
|
paje.AddVariable( m.time, variable_type_memory, container_memory, size);
|
||||||
|
else
|
||||||
|
paje.SubVariable( m.time, variable_type_memory, container_memory, size);
|
||||||
|
}
|
||||||
|
|
||||||
std::set<int> timer_ids;
|
std::set<int> timer_ids;
|
||||||
std::map<int,int> timer_aliases;
|
std::map<int,int> timer_aliases;
|
||||||
|
std::map<int,std::string> timer_names;
|
||||||
|
|
||||||
for(auto & event : timer_events)
|
for(auto & event : timer_events)
|
||||||
timer_ids.insert(event.timer_id);
|
timer_ids.insert(event.timer_id);
|
||||||
|
|
||||||
|
|
||||||
|
// Timer names
|
||||||
for(auto & vtasks : tasks)
|
for(auto & vtasks : tasks)
|
||||||
for (Task & t : vtasks)
|
for (Task & t : vtasks)
|
||||||
if(t.id_type==Task::ID_TIMER)
|
if(t.id_type==Task::ID_TIMER)
|
||||||
timer_ids.insert(t.id);
|
timer_ids.insert(t.id);
|
||||||
|
|
||||||
for(auto id : timer_ids)
|
for(auto id : timer_ids)
|
||||||
timer_aliases[id] = paje.DefineEntityValue( state_type_timer, NgProfiler::GetName(id), -1 );
|
timer_names[id] = GetTimerName(id);
|
||||||
|
|
||||||
|
#ifdef PARALLEL
|
||||||
|
if(nranks>1)
|
||||||
|
{
|
||||||
|
for(auto src : IntRange(0, nranks))
|
||||||
|
{
|
||||||
|
if(src==MPI_PAJE_WRITER)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
size_t n_timers;
|
||||||
|
comm.Recv (n_timers, src, 0);
|
||||||
|
|
||||||
|
int id;
|
||||||
|
std::string name;
|
||||||
|
for(auto i : IntRange(n_timers))
|
||||||
|
{
|
||||||
|
comm.Recv (id, src, 0);
|
||||||
|
comm.Recv (name, src, 0);
|
||||||
|
timer_ids.insert(id);
|
||||||
|
timer_names[id] = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // PARALLEL
|
||||||
|
|
||||||
|
for(auto id : timer_ids)
|
||||||
|
timer_aliases[id] = paje.DefineEntityValue( state_type_timer, timer_names[id], -1 );
|
||||||
|
|
||||||
int timerdepth = 0;
|
int timerdepth = 0;
|
||||||
int maxdepth = 0;
|
int maxdepth = 0;
|
||||||
@ -494,6 +657,50 @@ namespace ngcore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef PARALLEL
|
||||||
|
if(nranks>1)
|
||||||
|
{
|
||||||
|
for(auto & event : timer_events)
|
||||||
|
{
|
||||||
|
if(event.is_start)
|
||||||
|
paje.PushState( event.time, state_type_timer, thread_aliases[MPI_PAJE_WRITER], timer_aliases[event.timer_id] );
|
||||||
|
else
|
||||||
|
paje.PopState( event.time, state_type_timer, thread_aliases[MPI_PAJE_WRITER] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Timer events
|
||||||
|
Array<int> timer_id;
|
||||||
|
Array<TTimePoint> time;
|
||||||
|
Array<bool> is_start;
|
||||||
|
Array<int> thread_id;
|
||||||
|
|
||||||
|
for(auto src : IntRange(0, nranks))
|
||||||
|
{
|
||||||
|
if(src==MPI_PAJE_WRITER)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
comm.Recv (timer_id, src, 0);
|
||||||
|
comm.Recv (time, src, 0);
|
||||||
|
comm.Recv (is_start, src, 0);
|
||||||
|
comm.Recv (thread_id, src, 0);
|
||||||
|
|
||||||
|
for(auto i : Range(timer_id.Size()))
|
||||||
|
{
|
||||||
|
TimerEvent event;
|
||||||
|
event.timer_id = timer_id[i];
|
||||||
|
event.time = time[i];
|
||||||
|
event.is_start = is_start[i];
|
||||||
|
event.thread_id = thread_id[i];
|
||||||
|
|
||||||
|
if(event.is_start)
|
||||||
|
paje.PushState( event.time, state_type_timer, thread_aliases[src], timer_aliases[event.timer_id] );
|
||||||
|
else
|
||||||
|
paje.PopState( event.time, state_type_timer, thread_aliases[src] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // PARALLEL
|
||||||
|
|
||||||
// Merge link event
|
// Merge link event
|
||||||
int nlinks = 0;
|
int nlinks = 0;
|
||||||
for( auto & l : links)
|
for( auto & l : links)
|
||||||
@ -552,25 +759,96 @@ namespace ngcore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
WriteSunburstHTML();
|
WriteTimingChart();
|
||||||
|
#ifdef NETGEN_TRACE_MEMORY
|
||||||
|
WriteMemoryChart("");
|
||||||
|
#endif // NETGEN_TRACE_MEMORY
|
||||||
paje.WriteEvents();
|
paje.WriteEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PajeTrace::SendData( )
|
||||||
|
{
|
||||||
|
#ifdef PARALLEL
|
||||||
|
// Hostname
|
||||||
|
NgMPI_Comm comm(MPI_COMM_WORLD);
|
||||||
|
auto rank = comm.Rank();
|
||||||
|
auto nranks = comm.Size();
|
||||||
|
|
||||||
|
std::string hostname;
|
||||||
|
{
|
||||||
|
std::array<char, MPI_MAX_PROCESSOR_NAME+1> ahostname;
|
||||||
|
int len;
|
||||||
|
MPI_Get_processor_name(ahostname.data(), &len);
|
||||||
|
hostname = ahostname.data();
|
||||||
|
}
|
||||||
|
|
||||||
|
comm.Send(hostname, MPI_PAJE_WRITER, 0);
|
||||||
|
|
||||||
|
// Timer names
|
||||||
|
std::set<int> timer_ids;
|
||||||
|
std::map<int,std::string> timer_names;
|
||||||
|
|
||||||
|
for(auto & event : timer_events)
|
||||||
|
timer_ids.insert(event.timer_id);
|
||||||
|
|
||||||
|
for(auto id : timer_ids)
|
||||||
|
timer_names[id] = GetTimerName(id);
|
||||||
|
size_t size = timer_ids.size();
|
||||||
|
comm.Send(size, MPI_PAJE_WRITER, 0);
|
||||||
|
for(auto id : timer_ids)
|
||||||
|
{
|
||||||
|
comm.Send(id, MPI_PAJE_WRITER, 0);
|
||||||
|
comm.Send(timer_names[id], MPI_PAJE_WRITER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Timer events
|
||||||
|
Array<int> timer_id;
|
||||||
|
Array<TTimePoint> time;
|
||||||
|
Array<bool> is_start;
|
||||||
|
Array<int> thread_id;
|
||||||
|
|
||||||
|
for(auto & event : timer_events)
|
||||||
|
{
|
||||||
|
timer_id.Append(event.timer_id);
|
||||||
|
time.Append(event.time);
|
||||||
|
is_start.Append(event.is_start);
|
||||||
|
thread_id.Append(event.thread_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
comm.Send (timer_id, MPI_PAJE_WRITER, 0);
|
||||||
|
comm.Send (time, MPI_PAJE_WRITER, 0);
|
||||||
|
comm.Send (is_start, MPI_PAJE_WRITER, 0);
|
||||||
|
comm.Send (thread_id, MPI_PAJE_WRITER, 0);
|
||||||
|
#endif // PARALLEL
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
||||||
// Write HTML file drawing a sunburst chart with cumulated timings
|
// Write HTML file drawing a sunburst chart with cumulated timings
|
||||||
struct TreeNode
|
struct TreeNode
|
||||||
{
|
{
|
||||||
int id = 0;
|
int id = 0;
|
||||||
std::map<int, TreeNode> children;
|
std::map<int, TreeNode> children;
|
||||||
double time = 0.0;
|
double chart_size = 0.0; // time without children (the chart lib accumulates children sizes again)
|
||||||
|
double size = 0.0;
|
||||||
|
double min_size = 1e99;
|
||||||
|
double max_size = 0.0;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
|
size_t calls = 0;
|
||||||
TTimePoint start_time = 0;
|
TTimePoint start_time = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void PrintNode (const TreeNode &n, int &level, std::ofstream & f);
|
void PrintNode (const TreeNode &n, std::ofstream & f)
|
||||||
void PrintNode (const TreeNode &n, int &level, std::ofstream & f)
|
|
||||||
{
|
{
|
||||||
f << "{ name: \"" + n.name + "\", size: " + ToString(n.time);
|
f << "{ name: \"" + n.name + "\"";
|
||||||
|
f << ", calls: " << n.calls;
|
||||||
|
f << ", size: " << n.chart_size;
|
||||||
|
f << ", value: " << n.size;
|
||||||
|
f << ", min: " << n.min_size;
|
||||||
|
f << ", max: " << n.max_size;
|
||||||
|
if(n.calls)
|
||||||
|
f << ", avg: " << n.size/n.calls;
|
||||||
int size = n.children.size();
|
int size = n.children.size();
|
||||||
if(size>0)
|
if(size>0)
|
||||||
{
|
{
|
||||||
@ -578,7 +856,7 @@ namespace ngcore
|
|||||||
f << ", children: [";
|
f << ", children: [";
|
||||||
for(auto & c : n.children)
|
for(auto & c : n.children)
|
||||||
{
|
{
|
||||||
PrintNode(c.second, level, f);
|
PrintNode(c.second, f);
|
||||||
if(++i<size)
|
if(++i<size)
|
||||||
f << " , ";
|
f << " , ";
|
||||||
}
|
}
|
||||||
@ -587,12 +865,224 @@ namespace ngcore
|
|||||||
f << '}';
|
f << '}';
|
||||||
}
|
}
|
||||||
|
|
||||||
void PajeTrace::WriteSunburstHTML( )
|
void WriteSunburstHTML( TreeNode & root, std::string filename, bool time_or_memory )
|
||||||
|
{
|
||||||
|
std::ofstream f(filename+".html");
|
||||||
|
f.precision(4);
|
||||||
|
f << R"CODE_(
|
||||||
|
<head>
|
||||||
|
<script src="https://d3js.org/d3.v5.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/sunburst-chart"></script>
|
||||||
|
|
||||||
|
<style>body { margin: 0 }</style>
|
||||||
|
)CODE_";
|
||||||
|
if(!time_or_memory)
|
||||||
|
f << "<title>Maximum Memory Consumption</title>\n";
|
||||||
|
f << R"CODE_(
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="chart"></div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const data =
|
||||||
|
)CODE_";
|
||||||
|
PrintNode(root, f);
|
||||||
|
f << ";\n\n";
|
||||||
|
if(time_or_memory)
|
||||||
|
f << "const chart_type = 'time';\n";
|
||||||
|
else
|
||||||
|
f << "const chart_type = 'memory';\n";
|
||||||
|
f << R"CODE_(
|
||||||
|
const color = d3.scaleOrdinal(d3.schemePaired);
|
||||||
|
|
||||||
|
let getTime = (t) =>
|
||||||
|
{
|
||||||
|
if(t>=1000) return (t/1000).toPrecision(4) + ' s';
|
||||||
|
if(t>=0.1) return t.toPrecision(4) + ' ms';
|
||||||
|
if(t>=1e-4) return (t*1e3).toPrecision(4) + ' us';
|
||||||
|
|
||||||
|
return (t/1e6).toPrecision(4) + ' ns';
|
||||||
|
};
|
||||||
|
|
||||||
|
const KB_ = 1024;
|
||||||
|
const MB_ = KB_*1024;
|
||||||
|
const GB_ = MB_*1024;
|
||||||
|
let getMemory = (m) =>
|
||||||
|
{
|
||||||
|
if(m>=GB_) return (m/GB_).toPrecision(4) + ' GB';
|
||||||
|
if(m>=MB_) return (m/MB_).toPrecision(4) + ' MB';
|
||||||
|
if(m>=KB_) return (m/KB_).toPrecision(4) + ' KB';
|
||||||
|
return m.toPrecision(4) + ' B';
|
||||||
|
};
|
||||||
|
|
||||||
|
Sunburst()
|
||||||
|
.data(data)
|
||||||
|
.size('size')
|
||||||
|
.color(d => color(d.name))
|
||||||
|
.tooltipTitle((d, node) => { return node.parent ? node.parent.data.name + " → " + d.name : d.name; })
|
||||||
|
.tooltipContent((d, node) => {
|
||||||
|
if(chart_type=="memory")
|
||||||
|
{
|
||||||
|
return `Total Memory: <i>${getMemory(d.value)}</i> <br>`
|
||||||
|
+ `Memory: <i>${getMemory(d.size)}</i>`
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return `Time: <i>${getTime(d.value)}</i> <br>`
|
||||||
|
+ `calls: <i>${d.calls}</i> <br>`
|
||||||
|
+ `min: <i>${getTime(d.min)}</i> <br>`
|
||||||
|
+ `max: <i>${getTime(d.max)}</i> <br>`
|
||||||
|
+ `avg: <i>${getTime(d.avg)}</i>`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
(document.getElementById('chart'));
|
||||||
|
|
||||||
|
// Line breaks in tooltip
|
||||||
|
var all = document.getElementsByClassName('sunbirst-tooltip');
|
||||||
|
for (var i = 0; i < all.length; i++) {
|
||||||
|
all[i].white_space = "";
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
)CODE_" << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef NETGEN_TRACE_MEMORY
|
||||||
|
void PajeTrace::WriteMemoryChart( std::string fname )
|
||||||
|
{
|
||||||
|
if(fname=="")
|
||||||
|
fname = tracefile_name + "_memory";
|
||||||
|
size_t mem_allocated = 0;
|
||||||
|
size_t max_mem_allocated = 0;
|
||||||
|
size_t imax_mem_allocated = 0;
|
||||||
|
|
||||||
|
const auto & names = MemoryTracer::GetNames();
|
||||||
|
const auto & parents = MemoryTracer::GetParents();
|
||||||
|
size_t N = names.size();
|
||||||
|
|
||||||
|
Array<size_t> mem_allocated_id;
|
||||||
|
mem_allocated_id.SetSize(N);
|
||||||
|
mem_allocated_id = 0;
|
||||||
|
|
||||||
|
// Find point with maximum memory allocation, check for missing allocs/frees
|
||||||
|
for(auto i : IntRange(memory_events.size()))
|
||||||
|
{
|
||||||
|
const auto & ev = memory_events[i];
|
||||||
|
|
||||||
|
if(ev.is_alloc)
|
||||||
|
{
|
||||||
|
mem_allocated += ev.size;
|
||||||
|
mem_allocated_id[ev.id] += ev.size;
|
||||||
|
if(mem_allocated > max_mem_allocated && i>=n_memory_events_at_start)
|
||||||
|
{
|
||||||
|
imax_mem_allocated = i;
|
||||||
|
max_mem_allocated = mem_allocated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(ev.size > mem_allocated)
|
||||||
|
{
|
||||||
|
std::cerr << "Error in memory tracer: have total allocated memory < 0" << std::endl;
|
||||||
|
mem_allocated = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mem_allocated -= ev.size;
|
||||||
|
if(ev.size > mem_allocated_id[ev.id])
|
||||||
|
{
|
||||||
|
std::cerr << "Error in memory tracer: have allocated memory < 0 in tracer " << names[ev.id] << std::endl;
|
||||||
|
mem_allocated_id[ev.id] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mem_allocated_id[ev.id] -= ev.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reconstruct again the memory consumption after event imax_mem_allocated
|
||||||
|
mem_allocated_id = 0;
|
||||||
|
for(auto i : IntRange(imax_mem_allocated+1))
|
||||||
|
{
|
||||||
|
const auto & ev = memory_events[i];
|
||||||
|
|
||||||
|
if(ev.is_alloc)
|
||||||
|
mem_allocated_id[ev.id] += ev.size;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(ev.size > mem_allocated_id[ev.id])
|
||||||
|
mem_allocated_id[ev.id] = 0;
|
||||||
|
else
|
||||||
|
mem_allocated_id[ev.id] -= ev.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeNode root;
|
||||||
|
root.name="all";
|
||||||
|
|
||||||
|
Array<TreeNode*> nodes;
|
||||||
|
nodes.SetSize(N);
|
||||||
|
nodes = nullptr;
|
||||||
|
nodes[0] = &root;
|
||||||
|
Array<Array<int>> children(N);
|
||||||
|
|
||||||
|
Array<size_t> sorting; // topological sorting (parents before children)
|
||||||
|
sorting.SetAllocSize(N);
|
||||||
|
|
||||||
|
for(auto i : IntRange(1, N))
|
||||||
|
children[parents[i]].Append(i);
|
||||||
|
|
||||||
|
ArrayMem<size_t, 100> stack;
|
||||||
|
sorting.Append(0);
|
||||||
|
stack.Append(0);
|
||||||
|
|
||||||
|
while(stack.Size())
|
||||||
|
{
|
||||||
|
auto current = stack.Last();
|
||||||
|
stack.DeleteLast();
|
||||||
|
|
||||||
|
for(const auto child : children[current])
|
||||||
|
{
|
||||||
|
sorting.Append(child);
|
||||||
|
if(children[child].Size())
|
||||||
|
stack.Append(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto i : sorting)
|
||||||
|
{
|
||||||
|
if(i==0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TreeNode * parent = nodes[parents[i]];
|
||||||
|
|
||||||
|
auto & node = parent->children[i];
|
||||||
|
nodes[i] = &node;
|
||||||
|
node.id = i;
|
||||||
|
node.chart_size = mem_allocated_id[i];
|
||||||
|
node.size = mem_allocated_id[i];
|
||||||
|
node.name = names[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto i_ : Range(sorting))
|
||||||
|
{
|
||||||
|
// reverse topological order to accumulate total memory usage of all children
|
||||||
|
auto i = sorting[sorting.Size()-1-i_];
|
||||||
|
if(i==0)
|
||||||
|
continue;
|
||||||
|
nodes[parents[i]]->size += nodes[i]->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteSunburstHTML( root, fname, false );
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // NETGEN_TRACE_MEMORY
|
||||||
|
|
||||||
|
void PajeTrace::WriteTimingChart( )
|
||||||
{
|
{
|
||||||
std::vector<TimerEvent> events;
|
std::vector<TimerEvent> events;
|
||||||
|
|
||||||
TreeNode root;
|
TreeNode root;
|
||||||
root.time=0;
|
|
||||||
root.name="all";
|
root.name="all";
|
||||||
TreeNode *current = &root;
|
TreeNode *current = &root;
|
||||||
|
|
||||||
@ -629,7 +1119,10 @@ namespace ngcore
|
|||||||
|
|
||||||
std::sort (events.begin(), events.end());
|
std::sort (events.begin(), events.end());
|
||||||
|
|
||||||
root.time = 1000.0*static_cast<double>(stop_time-start_time) * seconds_per_tick;
|
root.size = 1000.0*static_cast<double>(stop_time) * seconds_per_tick;
|
||||||
|
root.calls = 1;
|
||||||
|
root.min_size = root.size;
|
||||||
|
root.max_size = root.size;
|
||||||
|
|
||||||
for(auto & event : events)
|
for(auto & event : events)
|
||||||
{
|
{
|
||||||
@ -645,8 +1138,8 @@ namespace ngcore
|
|||||||
|
|
||||||
if(need_init)
|
if(need_init)
|
||||||
{
|
{
|
||||||
current->name = is_timer_event ? NgProfiler::GetName(id) : job_names[id];
|
current->name = is_timer_event ? GetTimerName(id) : job_names[id];
|
||||||
current->time = 0.0;
|
current->size = 0.0;
|
||||||
current->id = id;
|
current->id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,44 +1151,22 @@ namespace ngcore
|
|||||||
std::cout << "node stack empty!" << std::endl;
|
std::cout << "node stack empty!" << std::endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
double time = 1000.0*static_cast<double>(event.time-current->start_time) * seconds_per_tick;
|
double size = 1000.0*static_cast<double>(event.time-current->start_time) * seconds_per_tick;
|
||||||
current->time += time;
|
current->size += size;
|
||||||
|
current->chart_size += size;
|
||||||
|
current->min_size = std::min(current->min_size, size);
|
||||||
|
current->max_size = std::max(current->max_size, size);
|
||||||
|
current->calls++;
|
||||||
|
|
||||||
current = node_stack.back();
|
current = node_stack.back();
|
||||||
current->time -= time;
|
current->chart_size -= size;
|
||||||
node_stack.pop_back();
|
node_stack.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int level = 0;
|
root.chart_size = 0.0;
|
||||||
std::ofstream f(tracefile_name+".html");
|
|
||||||
f.precision(4);
|
|
||||||
f << R"CODE_(
|
|
||||||
<head>
|
|
||||||
<script src="https://d3js.org/d3.v5.min.js"></script>
|
|
||||||
<script src="https://unpkg.com/sunburst-chart"></script>
|
|
||||||
|
|
||||||
<style>body { margin: 0 }</style>
|
ngcore::WriteSunburstHTML( root, tracefile_name, true );
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="chart"></div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const data =
|
|
||||||
)CODE_";
|
|
||||||
PrintNode(root, level, f);
|
|
||||||
f << R"CODE_( ;
|
|
||||||
|
|
||||||
const color = d3.scaleOrdinal(d3.schemePaired);
|
|
||||||
|
|
||||||
Sunburst()
|
|
||||||
.data(data)
|
|
||||||
.size('size')
|
|
||||||
.color(d => color(d.name))
|
|
||||||
.tooltipContent((d, node) => `Time: <i>${node.value.toPrecision(6)}ms</i>`)
|
|
||||||
(document.getElementById('chart'));
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
)CODE_" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ngcore
|
} // namespace ngcore
|
||||||
|
@ -23,18 +23,28 @@ namespace ngcore
|
|||||||
NGCORE_API static size_t max_tracefile_size;
|
NGCORE_API static size_t max_tracefile_size;
|
||||||
NGCORE_API static bool trace_thread_counter;
|
NGCORE_API static bool trace_thread_counter;
|
||||||
NGCORE_API static bool trace_threads;
|
NGCORE_API static bool trace_threads;
|
||||||
|
NGCORE_API static bool mem_tracing_enabled;
|
||||||
|
|
||||||
bool tracing_enabled;
|
bool tracing_enabled;
|
||||||
TTimePoint start_time;
|
TTimePoint start_time;
|
||||||
int nthreads;
|
int nthreads;
|
||||||
|
size_t n_memory_events_at_start;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void WriteSunburstHTML();
|
NGCORE_API void WriteTimingChart();
|
||||||
|
#ifdef NETGEN_TRACE_MEMORY
|
||||||
|
NGCORE_API void WriteMemoryChart( std::string fname );
|
||||||
|
#endif // NETGEN_TRACE_MEMORY
|
||||||
|
|
||||||
// Approximate number of events to trace. Tracing will
|
// Approximate number of events to trace. Tracing will
|
||||||
// be stopped if any thread reaches this number of events
|
// be stopped if any thread reaches this number of events
|
||||||
unsigned int max_num_events_per_thread;
|
unsigned int max_num_events_per_thread;
|
||||||
|
|
||||||
|
static void SetTraceMemory( bool trace_memory )
|
||||||
|
{
|
||||||
|
mem_tracing_enabled = trace_memory;
|
||||||
|
}
|
||||||
|
|
||||||
static void SetTraceThreads( bool atrace_threads )
|
static void SetTraceThreads( bool atrace_threads )
|
||||||
{
|
{
|
||||||
trace_threads = atrace_threads;
|
trace_threads = atrace_threads;
|
||||||
@ -96,10 +106,21 @@ namespace ngcore
|
|||||||
bool operator < (const ThreadLink & other) const { return time < other.time; }
|
bool operator < (const ThreadLink & other) const { return time < other.time; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MemoryEvent
|
||||||
|
{
|
||||||
|
TTimePoint time;
|
||||||
|
size_t size;
|
||||||
|
int id;
|
||||||
|
bool is_alloc;
|
||||||
|
|
||||||
|
bool operator < (const MemoryEvent & other) const { return time < other.time; }
|
||||||
|
};
|
||||||
|
|
||||||
std::vector<std::vector<Task> > tasks;
|
std::vector<std::vector<Task> > tasks;
|
||||||
std::vector<Job> jobs;
|
std::vector<Job> jobs;
|
||||||
std::vector<TimerEvent> timer_events;
|
std::vector<TimerEvent> timer_events;
|
||||||
std::vector<std::vector<ThreadLink> > links;
|
std::vector<std::vector<ThreadLink> > links;
|
||||||
|
NGCORE_API static std::vector<MemoryEvent> memory_events;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
NGCORE_API void StopTracing();
|
NGCORE_API void StopTracing();
|
||||||
@ -129,6 +150,27 @@ namespace ngcore
|
|||||||
timer_events.push_back(TimerEvent{timer_id, GetTimeCounter(), false});
|
timer_events.push_back(TimerEvent{timer_id, GetTimeCounter(), false});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AllocMemory(int id, size_t size)
|
||||||
|
{
|
||||||
|
if(!mem_tracing_enabled) return;
|
||||||
|
memory_events.push_back(MemoryEvent{GetTimeCounter(), size, id, true});
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeMemory(int id, size_t size)
|
||||||
|
{
|
||||||
|
if(!mem_tracing_enabled) return;
|
||||||
|
memory_events.push_back(MemoryEvent{GetTimeCounter(), size, id, false});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChangeMemory(int id, long long size)
|
||||||
|
{
|
||||||
|
if(size>0)
|
||||||
|
AllocMemory(id, size);
|
||||||
|
if(size<0)
|
||||||
|
FreeMemory(id, -size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
NETGEN_INLINE int StartTask(int thread_id, int id, int id_type = Task::ID_NONE, int additional_value = -1)
|
NETGEN_INLINE int StartTask(int thread_id, int id, int id_type = Task::ID_NONE, int additional_value = -1)
|
||||||
{
|
{
|
||||||
if(!tracing_enabled) return -1;
|
if(!tracing_enabled) return -1;
|
||||||
@ -185,6 +227,8 @@ namespace ngcore
|
|||||||
|
|
||||||
void Write( const std::string & filename );
|
void Write( const std::string & filename );
|
||||||
|
|
||||||
|
void SendData(); // MPI parallel data reduction
|
||||||
|
|
||||||
};
|
};
|
||||||
} // namespace ngcore
|
} // namespace ngcore
|
||||||
|
|
||||||
|
@ -113,5 +113,9 @@ namespace ngcore
|
|||||||
|
|
||||||
NgProfiler prof; // NOLINT
|
NgProfiler prof; // NOLINT
|
||||||
|
|
||||||
|
#ifdef NETGEN_TRACE_MEMORY
|
||||||
|
std::vector<std::string> MemoryTracer::names{"all"};
|
||||||
|
std::vector<int> MemoryTracer::parents{-1};
|
||||||
|
#endif // NETGEN_TRACE_MEMORY
|
||||||
|
|
||||||
} // namespace ngcore
|
} // namespace ngcore
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "logging.hpp"
|
#include "logging.hpp"
|
||||||
@ -299,7 +300,171 @@ namespace ngcore
|
|||||||
return tres;
|
return tres;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MemoryTracer;
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
//Type trait to check if a class implements a 'void SetMemoryTacing(int)' function
|
||||||
|
template<typename T>
|
||||||
|
struct has_StartMemoryTracing
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
template<typename T2>
|
||||||
|
static constexpr auto check(T2*) ->
|
||||||
|
typename std::is_same<decltype(std::declval<T2>().StartMemoryTracing()),void>::type;
|
||||||
|
template<typename>
|
||||||
|
static constexpr std::false_type check(...);
|
||||||
|
using type = decltype(check<T>(nullptr)); // NOLINT
|
||||||
|
public:
|
||||||
|
static constexpr bool value = type::value;
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
class MemoryTracer
|
||||||
|
{
|
||||||
|
#ifdef NETGEN_TRACE_MEMORY
|
||||||
|
NGCORE_API static std::vector<std::string> names;
|
||||||
|
NGCORE_API static std::vector<int> parents;
|
||||||
|
|
||||||
|
static int CreateId(const std::string& name)
|
||||||
|
{
|
||||||
|
int id = names.size();
|
||||||
|
names.push_back(name);
|
||||||
|
parents.push_back(0);
|
||||||
|
if(id==10*NgProfiler::SIZE)
|
||||||
|
std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl;
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
int id;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
MemoryTracer( std::string name )
|
||||||
|
{
|
||||||
|
id = CreateId(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// not tracing
|
||||||
|
MemoryTracer() : id(0) {}
|
||||||
|
|
||||||
|
template <typename... TRest>
|
||||||
|
MemoryTracer( std::string name, TRest & ... rest )
|
||||||
|
{
|
||||||
|
id = CreateId(name);
|
||||||
|
Track(rest...);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE void Alloc(size_t size) const
|
||||||
|
{
|
||||||
|
if(id && trace)
|
||||||
|
trace->AllocMemory(id, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Free(size_t size) const
|
||||||
|
{
|
||||||
|
if(id && trace)
|
||||||
|
trace->FreeMemory(id, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Swap(size_t mysize, MemoryTracer& other, size_t other_size) const
|
||||||
|
{
|
||||||
|
if(!trace || (id == 0 && other.id == 0))
|
||||||
|
return;
|
||||||
|
if(id == 0)
|
||||||
|
return trace->ChangeMemory(other.id, mysize - other_size);
|
||||||
|
if(other.id == 0)
|
||||||
|
return trace->ChangeMemory(id, other_size - mysize);
|
||||||
|
|
||||||
|
// first decrease memory, otherwise have artificial/wrong high peak memory usage
|
||||||
|
if(mysize<other_size)
|
||||||
|
{
|
||||||
|
trace->ChangeMemory(other.id, mysize-other_size);
|
||||||
|
trace->ChangeMemory(id, other_size-mysize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
trace->ChangeMemory(id, other_size-mysize);
|
||||||
|
trace->ChangeMemory(other.id, mysize-other_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetId() const { return id; }
|
||||||
|
|
||||||
|
template <typename T1, typename... TRest>
|
||||||
|
void Track( T1 & obj, const std::string& name, TRest & ... rest ) const
|
||||||
|
{
|
||||||
|
Track(obj, name);
|
||||||
|
Track(rest...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Track( T & obj, const std::string& name ) const
|
||||||
|
{
|
||||||
|
obj.GetMemoryTracer().Activate(obj, name);
|
||||||
|
parents[obj.GetMemoryTracer().GetId()] = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string GetName(int id)
|
||||||
|
{
|
||||||
|
return names[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetName() const
|
||||||
|
{
|
||||||
|
return names[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void Activate(T& me, const std::string& name) const
|
||||||
|
{
|
||||||
|
if(!id)
|
||||||
|
{
|
||||||
|
const_cast<MemoryTracer*>(this)->id = CreateId(name);
|
||||||
|
if constexpr(detail::has_StartMemoryTracing<T>::value)
|
||||||
|
me.StartMemoryTracing();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
SetName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetName(const std::string& name) const
|
||||||
|
{
|
||||||
|
names[id] = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const std::vector<std::string> & GetNames() { return names; }
|
||||||
|
static const std::vector<int> & GetParents() { return parents; }
|
||||||
|
#else // NETGEN_TRACE_MEMORY
|
||||||
|
public:
|
||||||
|
MemoryTracer() {}
|
||||||
|
MemoryTracer( std::string /* name */ ) {}
|
||||||
|
template <typename... TRest>
|
||||||
|
MemoryTracer( std::string /* name */, TRest & ... ) {}
|
||||||
|
|
||||||
|
void Alloc(size_t /* size */) const {}
|
||||||
|
void Free(size_t /* size */) const {}
|
||||||
|
void Swap(...) const {}
|
||||||
|
int GetId() const { return 0; }
|
||||||
|
|
||||||
|
template <typename... TRest>
|
||||||
|
void Track(TRest&...) const {}
|
||||||
|
|
||||||
|
static std::string GetName(int /* id */) { return ""; }
|
||||||
|
std::string GetName() const { return ""; }
|
||||||
|
void SetName(std::string /* name */) const {}
|
||||||
|
#endif // NETGEN_TRACE_MEMORY
|
||||||
|
};
|
||||||
} // namespace ngcore
|
} // namespace ngcore
|
||||||
|
|
||||||
|
// Helper macro to easily add multiple timers in a function for profiling
|
||||||
|
// Usage: NETGEN_TIMER_FROM_HERE("my_timer_name")
|
||||||
|
// Effect: define static Timer and RegionTimer with given name and line number
|
||||||
|
#define NETGEN_TOKEN_CONCAT(x, y) x ## y
|
||||||
|
#define NETGEN_TOKEN_CONCAT2(x, y) NETGEN_TOKEN_CONCAT(x, y)
|
||||||
|
#define NETGEN_TIMER_FROM_HERE(name) \
|
||||||
|
static Timer NETGEN_TOKEN_CONCAT2(timer_, __LINE__)( string(name)+"_"+ToString(__LINE__)); \
|
||||||
|
RegionTimer NETGEN_TOKEN_CONCAT2(rt_,__LINE__)(NETGEN_TOKEN_CONCAT2(timer_,__LINE__));
|
||||||
|
|
||||||
|
|
||||||
#endif // NETGEN_CORE_PROFILER_HPP
|
#endif // NETGEN_CORE_PROFILER_HPP
|
||||||
|
@ -8,6 +8,8 @@ using std::string;
|
|||||||
namespace ngcore
|
namespace ngcore
|
||||||
{
|
{
|
||||||
bool ngcore_have_numpy = false;
|
bool ngcore_have_numpy = false;
|
||||||
|
bool parallel_pickling = true;
|
||||||
|
|
||||||
void SetFlag(Flags &flags, string s, py::object value)
|
void SetFlag(Flags &flags, string s, py::object value)
|
||||||
{
|
{
|
||||||
if (py::isinstance<py::dict>(value))
|
if (py::isinstance<py::dict>(value))
|
||||||
|
@ -5,17 +5,70 @@
|
|||||||
#include <pybind11/pybind11.h>
|
#include <pybind11/pybind11.h>
|
||||||
#include <pybind11/operators.h>
|
#include <pybind11/operators.h>
|
||||||
#include <pybind11/numpy.h>
|
#include <pybind11/numpy.h>
|
||||||
|
#include <pybind11/stl.h>
|
||||||
|
|
||||||
#include "array.hpp"
|
#include "array.hpp"
|
||||||
#include "archive.hpp"
|
#include "archive.hpp"
|
||||||
#include "flags.hpp"
|
#include "flags.hpp"
|
||||||
#include "ngcore_api.hpp"
|
#include "ngcore_api.hpp"
|
||||||
|
#include "profiler.hpp"
|
||||||
namespace py = pybind11;
|
namespace py = pybind11;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// automatic conversion of python list to Array<>
|
||||||
|
namespace pybind11 {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
template <typename Type, typename Value> struct ngcore_list_caster {
|
||||||
|
using value_conv = make_caster<Value>;
|
||||||
|
|
||||||
|
bool load(handle src, bool convert) {
|
||||||
|
if (!isinstance<sequence>(src) || isinstance<str>(src))
|
||||||
|
return false;
|
||||||
|
auto s = reinterpret_borrow<sequence>(src);
|
||||||
|
value.SetSize(s.size());
|
||||||
|
value.SetSize0();
|
||||||
|
for (auto it : s) {
|
||||||
|
value_conv conv;
|
||||||
|
if (!conv.load(it, convert))
|
||||||
|
return false;
|
||||||
|
value.Append(cast_op<Value &&>(std::move(conv)));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
static handle cast(T &&src, return_value_policy policy, handle parent) {
|
||||||
|
if (!std::is_lvalue_reference<T>::value)
|
||||||
|
policy = return_value_policy_override<Value>::policy(policy);
|
||||||
|
list l(src.Size());
|
||||||
|
size_t index = 0;
|
||||||
|
for (auto &&value : src) {
|
||||||
|
auto value_ = reinterpret_steal<object>(value_conv::cast(forward_like<T>(value), policy, parent));
|
||||||
|
if (!value_)
|
||||||
|
return handle();
|
||||||
|
PyList_SET_ITEM(l.ptr(), (ssize_t) index++, value_.release().ptr()); // steals a reference
|
||||||
|
}
|
||||||
|
return l.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
PYBIND11_TYPE_CASTER(Type, _("Array[") + value_conv::name + _("]"));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type> struct type_caster<ngcore::Array<Type>>
|
||||||
|
: ngcore_list_caster<ngcore::Array<Type>, Type> { };
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
} // namespace pybind11
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
namespace ngcore
|
namespace ngcore
|
||||||
{
|
{
|
||||||
NGCORE_API extern bool ngcore_have_numpy;
|
NGCORE_API extern bool ngcore_have_numpy;
|
||||||
|
NGCORE_API extern bool parallel_pickling;
|
||||||
|
|
||||||
// Python class name type traits
|
// Python class name type traits
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct PyNameTraits {
|
struct PyNameTraits {
|
||||||
@ -142,6 +195,10 @@ namespace ngcore
|
|||||||
return py::make_iterator (self.begin(),self.end());
|
return py::make_iterator (self.begin(),self.end());
|
||||||
}, py::keep_alive<0,1>()) // keep array alive while iterator is used
|
}, py::keep_alive<0,1>()) // keep array alive while iterator is used
|
||||||
|
|
||||||
|
.def("__str__", [](TFlat& self)
|
||||||
|
{
|
||||||
|
return ToString(self);
|
||||||
|
})
|
||||||
;
|
;
|
||||||
|
|
||||||
if constexpr (detail::HasPyFormat<T>::value)
|
if constexpr (detail::HasPyFormat<T>::value)
|
||||||
@ -225,7 +282,6 @@ namespace ngcore
|
|||||||
using ARCHIVE::stream;
|
using ARCHIVE::stream;
|
||||||
using ARCHIVE::version_map;
|
using ARCHIVE::version_map;
|
||||||
using ARCHIVE::logger;
|
using ARCHIVE::logger;
|
||||||
using ARCHIVE::GetLibraryVersions;
|
|
||||||
public:
|
public:
|
||||||
PyArchive(const pybind11::object& alst = pybind11::none()) :
|
PyArchive(const pybind11::object& alst = pybind11::none()) :
|
||||||
ARCHIVE(std::make_shared<std::stringstream>()),
|
ARCHIVE(std::make_shared<std::stringstream>()),
|
||||||
@ -270,10 +326,11 @@ namespace ngcore
|
|||||||
|
|
||||||
pybind11::list WriteOut()
|
pybind11::list WriteOut()
|
||||||
{
|
{
|
||||||
|
auto version_runtime = GetLibraryVersions();
|
||||||
FlushBuffer();
|
FlushBuffer();
|
||||||
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
|
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
|
||||||
stream = std::make_shared<std::stringstream>();
|
stream = std::make_shared<std::stringstream>();
|
||||||
*this & GetLibraryVersions();
|
*this & version_runtime;
|
||||||
FlushBuffer();
|
FlushBuffer();
|
||||||
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
|
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
|
||||||
stream = std::make_shared<std::stringstream>();
|
stream = std::make_shared<std::stringstream>();
|
||||||
@ -291,19 +348,14 @@ namespace ngcore
|
|||||||
return pybind11::pickle([](T* self)
|
return pybind11::pickle([](T* self)
|
||||||
{
|
{
|
||||||
PyArchive<T_ARCHIVE_OUT> ar;
|
PyArchive<T_ARCHIVE_OUT> ar;
|
||||||
|
ar.SetParallel(parallel_pickling);
|
||||||
ar & self;
|
ar & self;
|
||||||
auto output = pybind11::make_tuple(ar.WriteOut());
|
auto output = pybind11::make_tuple(ar.WriteOut());
|
||||||
GetLogger("Archive")->trace("Pickling output for object of type {} = {}",
|
|
||||||
Demangle(typeid(T).name()),
|
|
||||||
std::string(pybind11::str(output)));
|
|
||||||
return output;
|
return output;
|
||||||
},
|
},
|
||||||
[](const pybind11::tuple & state)
|
[](const pybind11::tuple & state)
|
||||||
{
|
{
|
||||||
T* val = nullptr;
|
T* val = nullptr;
|
||||||
GetLogger("Archive")->trace("State for unpickling of object of type {} = {}",
|
|
||||||
Demangle(typeid(T).name()),
|
|
||||||
std::string(pybind11::str(state[0])));
|
|
||||||
PyArchive<T_ARCHIVE_IN> ar(state[0]);
|
PyArchive<T_ARCHIVE_IN> ar(state[0]);
|
||||||
ar & val;
|
ar & val;
|
||||||
return val;
|
return val;
|
||||||
|
@ -30,6 +30,7 @@ PYBIND11_MODULE(pyngcore, m) // NOLINT
|
|||||||
if (a[i]) ba->SetBit(i);
|
if (a[i]) ba->SetBit(i);
|
||||||
return ba;
|
return ba;
|
||||||
} ), py::arg("vec"))
|
} ), py::arg("vec"))
|
||||||
|
.def(NGSPickle<BitArray>())
|
||||||
.def("__str__", &ToString<BitArray>)
|
.def("__str__", &ToString<BitArray>)
|
||||||
.def("__len__", &BitArray::Size)
|
.def("__len__", &BitArray::Size)
|
||||||
.def("__getitem__", [] (BitArray & self, int i)
|
.def("__getitem__", [] (BitArray & self, int i)
|
||||||
@ -69,6 +70,29 @@ PYBIND11_MODULE(pyngcore, m) // NOLINT
|
|||||||
}
|
}
|
||||||
}, py::arg("inds"), py::arg("value"), "Clear/Set bit at given positions")
|
}, py::arg("inds"), py::arg("value"), "Clear/Set bit at given positions")
|
||||||
|
|
||||||
|
.def("__setitem__", [] (BitArray & self, py::slice inds, BitArray & ba)
|
||||||
|
{
|
||||||
|
size_t start, step, stop, n;
|
||||||
|
if (!inds.compute(self.Size(), &start, &stop, &step, &n))
|
||||||
|
throw py::error_already_set();
|
||||||
|
|
||||||
|
if (start == 0 && n == self.Size() && step == 1)
|
||||||
|
{
|
||||||
|
self = ba;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < n; i++, start += step)
|
||||||
|
{
|
||||||
|
bool b = ba.Test(i);
|
||||||
|
if (b)
|
||||||
|
self.SetBit(start);
|
||||||
|
else
|
||||||
|
self.Clear(start);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, py::arg("inds"), py::arg("ba"), "copy BitArray")
|
||||||
|
|
||||||
.def("__setitem__", [](BitArray & self, IntRange range, bool b)
|
.def("__setitem__", [](BitArray & self, IntRange range, bool b)
|
||||||
{
|
{
|
||||||
if (b)
|
if (b)
|
||||||
@ -222,4 +246,30 @@ threads : int
|
|||||||
.def("__timing__", &TaskManager::Timing)
|
.def("__timing__", &TaskManager::Timing)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
py::class_<PajeTrace>(m, "PajeTrace")
|
||||||
|
.def(py::init( [] (string filename, size_t size_mb, bool threads, bool thread_counter, bool memory)
|
||||||
|
{
|
||||||
|
PajeTrace::SetMaxTracefileSize(size_mb*1014*1024);
|
||||||
|
PajeTrace::SetTraceThreads(threads);
|
||||||
|
PajeTrace::SetTraceMemory(memory);
|
||||||
|
PajeTrace::SetTraceThreadCounter(thread_counter);
|
||||||
|
trace = new PajeTrace(TaskManager::GetMaxThreads(), filename);
|
||||||
|
return trace;
|
||||||
|
}), py::arg("filename")="ng.trace", py::arg("size")=1000,
|
||||||
|
py::arg("threads")=true, py::arg("thread_counter")=false,
|
||||||
|
py::arg("memory")=true,
|
||||||
|
"size in Megabytes"
|
||||||
|
)
|
||||||
|
.def("__enter__", [](PajeTrace & self) { })
|
||||||
|
.def("__exit__", [](PajeTrace & self, py::args) { self.StopTracing(); })
|
||||||
|
.def("__del__", [](PajeTrace & self) { trace = nullptr; })
|
||||||
|
.def_static("SetTraceThreads", &PajeTrace::SetTraceThreads)
|
||||||
|
.def_static("SetTraceThreadCounter", &PajeTrace::SetTraceThreadCounter)
|
||||||
|
.def_static("SetMaxTracefileSize", &PajeTrace::SetMaxTracefileSize)
|
||||||
|
#ifdef NETGEN_TRACE_MEMORY
|
||||||
|
.def_static("WriteMemoryChart", [](string filename){ if(trace) trace->WriteMemoryChart(filename); }, py::arg("filename")="memory" )
|
||||||
|
#endif // NETGEN_TRACE_MEMORY
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
109
libsrc/core/ranges.hpp
Normal file
109
libsrc/core/ranges.hpp
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#ifndef NETGEN_CORE_RANGES_HPP
|
||||||
|
#define NETGEN_CORE_RANGES_HPP
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
namespace ngcore
|
||||||
|
{
|
||||||
|
template<typename Iterator>
|
||||||
|
class AdapterRange
|
||||||
|
{
|
||||||
|
Iterator _begin,_end;
|
||||||
|
public:
|
||||||
|
AdapterRange(Iterator abegin, Iterator aend) : _begin(abegin), _end(aend) { ; }
|
||||||
|
Iterator begin() const { return _begin; }
|
||||||
|
Iterator end() const { return _end; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename FUNC>
|
||||||
|
class FilterAdapter
|
||||||
|
{
|
||||||
|
FUNC f;
|
||||||
|
public:
|
||||||
|
FilterAdapter(FUNC af) : f(af) { ; }
|
||||||
|
FUNC GetFunction() const { return f; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename FUNC, typename Iterator>
|
||||||
|
class FilterIterator
|
||||||
|
{
|
||||||
|
Iterator iter;
|
||||||
|
Iterator end;
|
||||||
|
FUNC f;
|
||||||
|
public:
|
||||||
|
FilterIterator(FUNC af, Iterator aiter, Iterator aend)
|
||||||
|
: f(af), iter(aiter), end(aend)
|
||||||
|
{
|
||||||
|
while(iter!=end && !f(*iter))
|
||||||
|
++iter;
|
||||||
|
}
|
||||||
|
inline FilterIterator& operator ++()
|
||||||
|
{
|
||||||
|
++iter;
|
||||||
|
while(iter!=end && !f(*iter))
|
||||||
|
++iter;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator !=(FilterIterator other)
|
||||||
|
{
|
||||||
|
return iter != other.iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator ==(FilterIterator other)
|
||||||
|
{
|
||||||
|
return iter == other.iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline decltype(auto) operator *() const
|
||||||
|
{
|
||||||
|
return *iter;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename FUNC>
|
||||||
|
FilterAdapter<FUNC> filter(FUNC f) { return {f}; }
|
||||||
|
|
||||||
|
template<typename Range, typename FUNC>
|
||||||
|
auto operator |(Range&& range, FilterAdapter<FUNC> adapter)
|
||||||
|
-> AdapterRange<FilterIterator<FUNC,decltype(std::begin(range))>>
|
||||||
|
{
|
||||||
|
return {{adapter.GetFunction(),std::begin(range),std::end(range)},
|
||||||
|
{adapter.GetFunction(), std::end(range), std::end(range)}};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename FUNC, typename Iterator>
|
||||||
|
class TransformIterator
|
||||||
|
{
|
||||||
|
FUNC f;
|
||||||
|
Iterator iter;
|
||||||
|
public:
|
||||||
|
TransformIterator(FUNC af, Iterator aiter) : f(af), iter(aiter) { ; }
|
||||||
|
|
||||||
|
TransformIterator& operator++() { ++iter; }
|
||||||
|
bool operator !=(TransformIterator other) { return iter != other.iter; }
|
||||||
|
decltype(auto) operator *() const { return f(*iter); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename FUNC>
|
||||||
|
class TransformAdapter
|
||||||
|
{
|
||||||
|
FUNC f;
|
||||||
|
public:
|
||||||
|
TransformAdapter(FUNC af) : f(af) { ; }
|
||||||
|
FUNC GetFunction() const { return f; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename FUNC>
|
||||||
|
TransformAdapter<FUNC> transform(FUNC f) { return {f}; }
|
||||||
|
|
||||||
|
template<typename Range, typename FUNC>
|
||||||
|
auto operator |(Range&& range, TransformAdapter<FUNC> adapter)
|
||||||
|
-> AdapterRange<TransformIterator<FUNC,decltype(std::begin(range))>>
|
||||||
|
{
|
||||||
|
return {{adapter.GetFunction(), std::begin(range)},
|
||||||
|
{adapter.GetFunction(),std::end(range)}};
|
||||||
|
}
|
||||||
|
} // namespace ngcore
|
||||||
|
|
||||||
|
#endif // NETGEN_CORE_RANGES_HPP
|
75
libsrc/core/simd.hpp
Normal file
75
libsrc/core/simd.hpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#ifndef NETGEN_CORE_SIMD_HPP
|
||||||
|
#define NETGEN_CORE_SIMD_HPP
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* File: simd.hpp */
|
||||||
|
/* Author: Joachim Schoeberl, Matthias Hochsteger */
|
||||||
|
/* Date: 25. Mar. 16 */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include "ngcore_api.hpp"
|
||||||
|
|
||||||
|
#include "simd_generic.hpp"
|
||||||
|
|
||||||
|
#ifdef NETGEN_ARCH_AMD64
|
||||||
|
#ifndef __SSE__
|
||||||
|
#define __SSE__
|
||||||
|
#endif
|
||||||
|
#include "simd_sse.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __AVX__
|
||||||
|
#include "simd_avx.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __AVX512F__
|
||||||
|
#include "simd_avx512.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __aarch64__
|
||||||
|
#include "simd_arm64.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace ngcore
|
||||||
|
{
|
||||||
|
#ifdef NETGEN_ARCH_AMD64
|
||||||
|
NETGEN_INLINE auto HSum (SIMD<double,2> v1, SIMD<double,2> v2, SIMD<double,2> v3, SIMD<double,2> v4)
|
||||||
|
{
|
||||||
|
SIMD<double,2> hsum1 = my_mm_hadd_pd (v1.Data(), v2.Data());
|
||||||
|
SIMD<double,2> hsum2 = my_mm_hadd_pd (v3.Data(), v4.Data());
|
||||||
|
return SIMD<double,4> (hsum1, hsum2);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE auto GetMaskFromBits( unsigned int i )
|
||||||
|
{
|
||||||
|
return SIMD<mask64>::GetMaskFromBits(i);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE void SIMDTranspose (SIMD<double,4> a1, SIMD<double,4> a2, SIMD <double,4> a3, SIMD<double,4> a4,
|
||||||
|
SIMD<double,4> & b1, SIMD<double,4> & b2, SIMD<double,4> & b3, SIMD<double,4> & b4)
|
||||||
|
{
|
||||||
|
SIMD<double,4> h1,h2,h3,h4;
|
||||||
|
std::tie(h1,h2) = Unpack(a1,a2);
|
||||||
|
std::tie(h3,h4) = Unpack(a3,a4);
|
||||||
|
b1 = SIMD<double,4> (h1.Lo(), h3.Lo());
|
||||||
|
b2 = SIMD<double,4> (h2.Lo(), h4.Lo());
|
||||||
|
b3 = SIMD<double,4> (h1.Hi(), h3.Hi());
|
||||||
|
b4 = SIMD<double,4> (h2.Hi(), h4.Hi());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int N>
|
||||||
|
NETGEN_INLINE auto HSum (SIMD<double,N> s1, SIMD<double,N> s2)
|
||||||
|
{
|
||||||
|
return SIMD<double,2>(HSum(s1), HSum(s2));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int N>
|
||||||
|
NETGEN_INLINE auto HSum (SIMD<double,N> s1, SIMD<double,N> s2, SIMD<double,N> s3, SIMD<double,N> s4 )
|
||||||
|
{
|
||||||
|
return SIMD<double,4>(HSum(s1), HSum(s2), HSum(s3), HSum(s4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NETGEN_CORE_SIMD_HPP
|
175
libsrc/core/simd_arm64.hpp
Normal file
175
libsrc/core/simd_arm64.hpp
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#include "arm_neon.h"
|
||||||
|
|
||||||
|
namespace ngcore
|
||||||
|
{
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class SIMD<mask64,2>
|
||||||
|
{
|
||||||
|
int64x2_t mask;
|
||||||
|
public:
|
||||||
|
SIMD (int i)
|
||||||
|
{
|
||||||
|
mask[0] = i > 0 ? -1 : 0;
|
||||||
|
mask[1] = i > 1 ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SIMD (bool i0, bool i1) { mask[0] = i0 ? -1:0; mask[1] = i1 ? -1 : 0; }
|
||||||
|
SIMD (SIMD<mask64,1> i0, SIMD<mask64,1> i1) { mask[0] = i0[0]; mask[1] = i1[0]; }
|
||||||
|
SIMD (float64x2_t _data) : mask{_data} { }
|
||||||
|
auto Data() const { return mask; }
|
||||||
|
static constexpr int Size() { return 2; }
|
||||||
|
// static NETGEN_INLINE SIMD<mask64, 2> GetMaskFromBits (unsigned int i);
|
||||||
|
int64_t operator[] (int i) const { return mask[i]; }
|
||||||
|
|
||||||
|
template <int I>
|
||||||
|
int64_t Get() const { return mask[I]; }
|
||||||
|
|
||||||
|
auto Lo() const { return mask[0]; }
|
||||||
|
auto Hi() const { return mask[1]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class SIMD<double,2>
|
||||||
|
{
|
||||||
|
float64x2_t data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr int Size() { return 2; }
|
||||||
|
SIMD () {}
|
||||||
|
SIMD (const SIMD &) = default;
|
||||||
|
// SIMD (double v0, double v1) : data{v0,v1} { }
|
||||||
|
SIMD (double v0, double v1) : data{vcombine_f64(float64x1_t{v0}, float64x1_t{v1})} { }
|
||||||
|
SIMD (std::array<double, 2> arr) : data{arr[0], arr[1]} { }
|
||||||
|
|
||||||
|
SIMD & operator= (const SIMD &) = default;
|
||||||
|
|
||||||
|
SIMD (double val) : data{val,val} { }
|
||||||
|
SIMD (int val) : data{double(val),double(val)} { }
|
||||||
|
SIMD (size_t val) : data{double(val),double(val)} { }
|
||||||
|
|
||||||
|
SIMD (double const * p)
|
||||||
|
{
|
||||||
|
data = vld1q_f64(p);
|
||||||
|
// data[0] = p[0];
|
||||||
|
// data[1] = p[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
SIMD (double const * p, SIMD<mask64,2> mask)
|
||||||
|
{
|
||||||
|
data[0] = mask[0] ? p[0] : 0;
|
||||||
|
data[1] = mask[1] ? p[1] : 0;
|
||||||
|
}
|
||||||
|
SIMD (float64x2_t _data) { data = _data; }
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<std::is_convertible<T, std::function<double(int)>>::value, int>::type = 0>
|
||||||
|
SIMD (const T & func)
|
||||||
|
{
|
||||||
|
data[0] = func(0);
|
||||||
|
data[1] = func(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Store (double * p)
|
||||||
|
{
|
||||||
|
vst1q_f64(p, data);
|
||||||
|
/*
|
||||||
|
p[0] = data[0];
|
||||||
|
p[1] = data[1];
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void Store (double * p, SIMD<mask64,2> mask)
|
||||||
|
{
|
||||||
|
if (mask[0]) p[0] = data[0];
|
||||||
|
if (mask[1]) p[1] = data[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; }
|
||||||
|
NETGEN_INLINE double operator[] (int i) const { return data[i]; }
|
||||||
|
NETGEN_INLINE double & operator[] (int i) { return ((double*)&data)[i]; }
|
||||||
|
|
||||||
|
template <int I>
|
||||||
|
double Get() const { return data[I]; }
|
||||||
|
|
||||||
|
NETGEN_INLINE auto Data() const { return data; }
|
||||||
|
NETGEN_INLINE auto & Data() { return data; }
|
||||||
|
|
||||||
|
operator std::tuple<double&,double&> ()
|
||||||
|
{
|
||||||
|
auto pdata = (double*)&data;
|
||||||
|
return std::tuple<double&,double&>(pdata[0], pdata[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
double Lo() const { return Get<0>(); } // data[0]; }
|
||||||
|
double Hi() const { return Get<1>(); } // data[1]; }
|
||||||
|
// double Hi() const { return vget_high_f64(data)[0]; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE double HSum (SIMD<double,2> sd)
|
||||||
|
{
|
||||||
|
return sd.Lo()+sd.Hi(); // sd[0]+sd[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,2> HSum (SIMD<double,2> a, SIMD<double,2> b)
|
||||||
|
{
|
||||||
|
// return SIMD<double,2> (a[0]+a[1], b[0]+b[1]);
|
||||||
|
return vpaddq_f64(a.Data(), b.Data());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// a*b+c
|
||||||
|
NETGEN_INLINE SIMD<double,2> FMA (SIMD<double,2> a, SIMD<double,2> b, SIMD<double,2> c)
|
||||||
|
{
|
||||||
|
return vmlaq_f64(c.Data(), a.Data(), b.Data());
|
||||||
|
}
|
||||||
|
NETGEN_INLINE SIMD<double,2> FMA (const double & a, SIMD<double,2> b, SIMD<double,2> c)
|
||||||
|
{
|
||||||
|
return FMA(SIMD<double,2> (a), b, c);
|
||||||
|
}
|
||||||
|
// -a*b+c
|
||||||
|
NETGEN_INLINE SIMD<double,2> FNMA (SIMD<double,2> a, SIMD<double,2> b, SIMD<double,2> c)
|
||||||
|
{
|
||||||
|
return vmlsq_f64(c.Data(), a.Data(), b.Data());
|
||||||
|
// return c-a*b;
|
||||||
|
}
|
||||||
|
NETGEN_INLINE SIMD<double,2> FNMA (const double & a, SIMD<double,2> b, SIMD<double,2> c)
|
||||||
|
{
|
||||||
|
return FNMA(SIMD<double,2> (a), b, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator+ (SIMD<double,2> a, SIMD<double,2> b)
|
||||||
|
{ return a.Data()+b.Data(); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator- (SIMD<double,2> a, SIMD<double,2> b)
|
||||||
|
{ return a.Data()-b.Data(); }
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator- (SIMD<double,2> a)
|
||||||
|
{ return -a.Data(); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator* (SIMD<double,2> a, SIMD<double,2> b)
|
||||||
|
{ return a.Data()*b.Data(); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator/ (SIMD<double,2> a, SIMD<double,2> b)
|
||||||
|
{ return a.Data()/b.Data(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,2> If (SIMD<mask64,2> a, SIMD<double,2> b, SIMD<double,2> c)
|
||||||
|
{
|
||||||
|
// return { a[0] ? b[0] : c[0], a[1] ? b[1] : c[1] };
|
||||||
|
return vbslq_f64(a.Data(), b.Data(), c.Data());
|
||||||
|
}
|
||||||
|
NETGEN_INLINE SIMD<int64_t,2> If (SIMD<mask64,2> a, SIMD<int64_t,2> b, SIMD<int64_t,2> c)
|
||||||
|
{
|
||||||
|
return SIMD<int64_t,2> (a[0] ? b[0] : c[0], a[1] ? b[1] : c[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator&& (SIMD<mask64,2> a, SIMD<mask64,2> b)
|
||||||
|
{
|
||||||
|
return vandq_u64 (a.Data(), b.Data());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
309
libsrc/core/simd_avx.hpp
Normal file
309
libsrc/core/simd_avx.hpp
Normal file
@ -0,0 +1,309 @@
|
|||||||
|
#ifndef NETGEN_CORE_SIMD_AVX_HPP
|
||||||
|
#define NETGEN_CORE_SIMD_AVX_HPP
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* File: simd_avx.hpp */
|
||||||
|
/* Author: Joachim Schoeberl, Matthias Hochsteger */
|
||||||
|
/* Date: 25. Mar. 16 */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include <immintrin.h>
|
||||||
|
|
||||||
|
namespace ngcore
|
||||||
|
{
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && (__GNUC__ == 7)
|
||||||
|
// GCC7 does not have intrinsic _mm256_set_m128i, see
|
||||||
|
// https://stackoverflow.com/questions/32630458/setting-m256i-to-the-value-of-two-m128i-values
|
||||||
|
NETGEN_INLINE auto _mm256_set_m128i(__m128i v0, __m128i v1) {
|
||||||
|
return _mm256_insertf128_si256(_mm256_castsi128_si256(v1), (v0), 1);
|
||||||
|
}
|
||||||
|
#endif // defined(__GNUC__) && (__GNUC__ == 7)
|
||||||
|
|
||||||
|
#if defined(__AVX2__)
|
||||||
|
NETGEN_INLINE __m256i my_mm256_cmpgt_epi64 (__m256i a, __m256i b)
|
||||||
|
{
|
||||||
|
return _mm256_cmpgt_epi64 (a,b);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
NETGEN_INLINE __m256i my_mm256_cmpgt_epi64 (__m256i a, __m256i b)
|
||||||
|
{
|
||||||
|
__m128i rlo = _mm_cmpgt_epi64(_mm256_extractf128_si256(a, 0),
|
||||||
|
_mm256_extractf128_si256(b, 0));
|
||||||
|
__m128i rhi = _mm_cmpgt_epi64(_mm256_extractf128_si256(a, 1),
|
||||||
|
_mm256_extractf128_si256(b, 1));
|
||||||
|
return _mm256_insertf128_si256 (_mm256_castsi128_si256(rlo), rhi, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class SIMD<mask64,4>
|
||||||
|
{
|
||||||
|
__m256i mask;
|
||||||
|
public:
|
||||||
|
SIMD (int64_t i)
|
||||||
|
: mask(my_mm256_cmpgt_epi64(_mm256_set1_epi64x(i),
|
||||||
|
_mm256_set_epi64x(3, 2, 1, 0)))
|
||||||
|
{ ; }
|
||||||
|
SIMD (__m256i _mask) : mask(_mask) { ; }
|
||||||
|
SIMD (__m256d _mask) : mask(_mm256_castpd_si256(_mask)) { ; }
|
||||||
|
__m256i Data() const { return mask; }
|
||||||
|
static constexpr int Size() { return 4; }
|
||||||
|
static SIMD<mask64, 4> GetMaskFromBits (unsigned int i);
|
||||||
|
};
|
||||||
|
|
||||||
|
static SIMD<mask64, 4> masks_from_4bits[16] = {
|
||||||
|
_mm256_set_epi64x (0,0,0,0), _mm256_set_epi64x (0,0,0,-1),
|
||||||
|
_mm256_set_epi64x (0,0,-1,0), _mm256_set_epi64x (0,0,-1,-1),
|
||||||
|
_mm256_set_epi64x (0,-1,0,0), _mm256_set_epi64x (0,-1,0,-1),
|
||||||
|
_mm256_set_epi64x (0,-1,-1,0), _mm256_set_epi64x (0,-1,-1,-1),
|
||||||
|
_mm256_set_epi64x (-1,0,0,0), _mm256_set_epi64x (-1,0,0,-1),
|
||||||
|
_mm256_set_epi64x (-1,0,-1,0), _mm256_set_epi64x (-1,0,-1,-1),
|
||||||
|
_mm256_set_epi64x (-1,-1,0,0), _mm256_set_epi64x (-1,-1,0,-1),
|
||||||
|
_mm256_set_epi64x (-1,-1,-1,0), _mm256_set_epi64x (-1,-1,-1,-1)
|
||||||
|
};
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<mask64, 4> SIMD<mask64, 4> :: GetMaskFromBits (unsigned int i)
|
||||||
|
{
|
||||||
|
return masks_from_4bits[i & 15];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class alignas(32) SIMD<int64_t,4>
|
||||||
|
{
|
||||||
|
__m256i data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr int Size() { return 4; }
|
||||||
|
SIMD () {}
|
||||||
|
SIMD (const SIMD &) = default;
|
||||||
|
SIMD & operator= (const SIMD &) = default;
|
||||||
|
|
||||||
|
SIMD (int64_t val) { data = _mm256_set1_epi64x(val); }
|
||||||
|
SIMD (int64_t v0, int64_t v1, int64_t v2, int64_t v3) { data = _mm256_set_epi64x(v3,v2,v1,v0); }
|
||||||
|
SIMD (std::array<int64_t,4> a)
|
||||||
|
: data{_mm256_set_epi64x(a[3],a[2],a[1],a[0])}
|
||||||
|
{}
|
||||||
|
SIMD (SIMD<int64_t,2> v0, SIMD<int64_t,2> v1)
|
||||||
|
: data(_mm256_set_m128i(v0.Data(),v1.Data()))
|
||||||
|
{}
|
||||||
|
SIMD (__m256i _data) { data = _data; }
|
||||||
|
|
||||||
|
NETGEN_INLINE auto operator[] (int i) const { return ((int64_t*)(&data))[i]; }
|
||||||
|
NETGEN_INLINE __m256i Data() const { return data; }
|
||||||
|
NETGEN_INLINE __m256i & Data() { return data; }
|
||||||
|
|
||||||
|
SIMD<int64_t,2> Lo() const { return _mm256_extractf128_si256(data, 0); }
|
||||||
|
SIMD<int64_t,2> Hi() const { return _mm256_extractf128_si256(data, 1); }
|
||||||
|
static SIMD FirstInt(int n0=0) { return { n0+0, n0+1, n0+2, n0+3 }; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<int64_t,4> operator-(SIMD<int64_t,4> a) { return _mm256_sub_epi64(_mm256_setzero_si256(), a.Data()); }
|
||||||
|
|
||||||
|
#ifdef __AVX2__
|
||||||
|
NETGEN_INLINE SIMD<int64_t,4> operator+ (SIMD<int64_t,4> a, SIMD<int64_t,4> b) { return _mm256_add_epi64(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<int64_t,4> operator- (SIMD<int64_t,4> a, SIMD<int64_t,4> b) { return _mm256_sub_epi64(a.Data(),b.Data()); }
|
||||||
|
#endif // __AVX2__
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class alignas(32) SIMD<double,4>
|
||||||
|
{
|
||||||
|
__m256d data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr int Size() { return 4; }
|
||||||
|
SIMD () {}
|
||||||
|
SIMD (const SIMD &) = default;
|
||||||
|
SIMD & operator= (const SIMD &) = default;
|
||||||
|
|
||||||
|
SIMD (double val) { data = _mm256_set1_pd(val); }
|
||||||
|
SIMD (int val) { data = _mm256_set1_pd(val); }
|
||||||
|
SIMD (size_t val) { data = _mm256_set1_pd(val); }
|
||||||
|
SIMD (double v0, double v1, double v2, double v3) { data = _mm256_set_pd(v3,v2,v1,v0); }
|
||||||
|
SIMD (SIMD<double,2> v0, SIMD<double,2> v1) : SIMD(v0[0], v0[1], v1[0], v1[1]) { ; }
|
||||||
|
SIMD (double const * p) { data = _mm256_loadu_pd(p); }
|
||||||
|
SIMD (double const * p, SIMD<mask64,4> mask) { data = _mm256_maskload_pd(p, mask.Data()); }
|
||||||
|
SIMD (__m256d _data) { data = _data; }
|
||||||
|
SIMD (std::array<double,4> a)
|
||||||
|
: data{_mm256_set_pd(a[3],a[2],a[1],a[0])}
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Store (double * p) { _mm256_storeu_pd(p, data); }
|
||||||
|
void Store (double * p, SIMD<mask64,4> mask) { _mm256_maskstore_pd(p, mask.Data(), data); }
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<std::is_convertible<T, std::function<double(int)>>::value, int>::type = 0>
|
||||||
|
SIMD (const T & func)
|
||||||
|
{
|
||||||
|
data = _mm256_set_pd(func(3), func(2), func(1), func(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; }
|
||||||
|
NETGEN_INLINE double & operator[] (int i) { return ((double*)(&data))[i]; }
|
||||||
|
// [[deprecated("don't write to individual elments of SIMD")]]
|
||||||
|
// NETGEN_INLINE double & operator[] (int i) { return ((double*)(&data))[i]; }
|
||||||
|
template <int I>
|
||||||
|
double Get() const { return ((double*)(&data))[I]; }
|
||||||
|
NETGEN_INLINE __m256d Data() const { return data; }
|
||||||
|
NETGEN_INLINE __m256d & Data() { return data; }
|
||||||
|
|
||||||
|
SIMD<double,2> Lo() const { return _mm256_extractf128_pd(data, 0); }
|
||||||
|
SIMD<double,2> Hi() const { return _mm256_extractf128_pd(data, 1); }
|
||||||
|
|
||||||
|
operator std::tuple<double&,double&,double&,double&> ()
|
||||||
|
{ return std::tuple<double&,double&,double&,double&>((*this)[0], (*this)[1], (*this)[2], (*this)[3]); }
|
||||||
|
};
|
||||||
|
|
||||||
|
NETGEN_INLINE auto Unpack (SIMD<double,4> a, SIMD<double,4> b)
|
||||||
|
{
|
||||||
|
return std::make_tuple(SIMD<double,4>(_mm256_unpacklo_pd(a.Data(),b.Data())),
|
||||||
|
SIMD<double,4>(_mm256_unpackhi_pd(a.Data(),b.Data())));
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,4> operator- (SIMD<double,4> a) { return _mm256_xor_pd(a.Data(), _mm256_set1_pd(-0.0)); }
|
||||||
|
NETGEN_INLINE SIMD<double,4> operator+ (SIMD<double,4> a, SIMD<double,4> b) { return _mm256_add_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,4> operator- (SIMD<double,4> a, SIMD<double,4> b) { return _mm256_sub_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,4> operator* (SIMD<double,4> a, SIMD<double,4> b) { return _mm256_mul_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,4> operator/ (SIMD<double,4> a, SIMD<double,4> b) { return _mm256_div_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,4> operator* (double a, SIMD<double,4> b) { return _mm256_set1_pd(a)*b.Data(); }
|
||||||
|
NETGEN_INLINE SIMD<double,4> operator* (SIMD<double,4> b, double a) { return _mm256_set1_pd(a)*b.Data(); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,4> sqrt (SIMD<double,4> a) { return _mm256_sqrt_pd(a.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,4> floor (SIMD<double,4> a) { return _mm256_floor_pd(a.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,4> ceil (SIMD<double,4> a) { return _mm256_ceil_pd(a.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,4> fabs (SIMD<double,4> a) { return _mm256_max_pd(a.Data(), (-a).Data()); }
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __FMA__
|
||||||
|
NETGEN_INLINE SIMD<double,4> FMA (SIMD<double,4> a, SIMD<double,4> b, SIMD<double,4> c)
|
||||||
|
{
|
||||||
|
return _mm256_fmadd_pd (a.Data(), b.Data(), c.Data());
|
||||||
|
}
|
||||||
|
NETGEN_INLINE SIMD<double,4> FMA (const double & a, SIMD<double,4> b, SIMD<double,4> c)
|
||||||
|
{
|
||||||
|
return _mm256_fmadd_pd (_mm256_set1_pd(a), b.Data(), c.Data());
|
||||||
|
}
|
||||||
|
NETGEN_INLINE SIMD<double,4> FNMA (SIMD<double,4> a, SIMD<double,4> b, SIMD<double,4> c)
|
||||||
|
{
|
||||||
|
return _mm256_fnmadd_pd (a.Data(), b.Data(), c.Data());
|
||||||
|
}
|
||||||
|
NETGEN_INLINE SIMD<double,4> FNMA (const double & a, SIMD<double,4> b, SIMD<double,4> c)
|
||||||
|
{
|
||||||
|
return _mm256_fnmadd_pd (_mm256_set1_pd(a), b.Data(), c.Data());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__FMA__) && !defined(__AVX512F__)
|
||||||
|
// make sure to use the update-version of fma
|
||||||
|
// important in matrix kernels using 12 sum-registers, 3 a-values and updated b-value
|
||||||
|
// avx512 has enough registers, and gcc seems to use only the first 16 z-regs
|
||||||
|
NETGEN_INLINE void FMAasm (SIMD<double,4> a, SIMD<double,4> b, SIMD<double,4> & sum)
|
||||||
|
{
|
||||||
|
asm ("vfmadd231pd %[a], %[b], %[sum]"
|
||||||
|
: [sum] "+x" (sum.Data())
|
||||||
|
: [a] "x" (a.Data()), [b] "x" (b.Data())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE void FNMAasm (SIMD<double,4> a, SIMD<double,4> b, SIMD<double,4> & sum)
|
||||||
|
{
|
||||||
|
asm ("vfnmadd231pd %[a], %[b], %[sum]"
|
||||||
|
: [sum] "+x" (sum.Data())
|
||||||
|
: [a] "x" (a.Data()), [b] "x" (b.Data())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator<= (SIMD<double,4> a , SIMD<double,4> b)
|
||||||
|
{ return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_LE_OQ); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator< (SIMD<double,4> a , SIMD<double,4> b)
|
||||||
|
{ return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_LT_OQ); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator>= (SIMD<double,4> a , SIMD<double,4> b)
|
||||||
|
{ return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_GE_OQ); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator> (SIMD<double,4> a , SIMD<double,4> b)
|
||||||
|
{ return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_GT_OQ); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator== (SIMD<double,4> a , SIMD<double,4> b)
|
||||||
|
{ return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_EQ_OQ); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator!= (SIMD<double,4> a , SIMD<double,4> b)
|
||||||
|
{ return _mm256_cmp_pd (a.Data(), b.Data(), _CMP_NEQ_OQ); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator<= (SIMD<int64_t,4> a , SIMD<int64_t,4> b)
|
||||||
|
{ return _mm256_xor_si256(_mm256_cmpgt_epi64(a.Data(),b.Data()),_mm256_set1_epi32(-1)); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator< (SIMD<int64_t,4> a , SIMD<int64_t,4> b)
|
||||||
|
{ return my_mm256_cmpgt_epi64(b.Data(),a.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator>= (SIMD<int64_t,4> a , SIMD<int64_t,4> b)
|
||||||
|
{ return _mm256_xor_si256(_mm256_cmpgt_epi64(b.Data(),a.Data()),_mm256_set1_epi32(-1)); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator> (SIMD<int64_t,4> a , SIMD<int64_t,4> b)
|
||||||
|
{ return my_mm256_cmpgt_epi64(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator== (SIMD<int64_t,4> a , SIMD<int64_t,4> b)
|
||||||
|
{ return _mm256_cmpeq_epi64(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator!= (SIMD<int64_t,4> a , SIMD<int64_t,4> b)
|
||||||
|
{ return _mm256_xor_si256(_mm256_cmpeq_epi64(a.Data(),b.Data()),_mm256_set1_epi32(-1)); }
|
||||||
|
|
||||||
|
#ifdef __AVX2__
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator&& (SIMD<mask64,4> a, SIMD<mask64,4> b)
|
||||||
|
{ return _mm256_and_si256 (a.Data(), b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator|| (SIMD<mask64,4> a, SIMD<mask64,4> b)
|
||||||
|
{ return _mm256_or_si256 (a.Data(), b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator! (SIMD<mask64,4> a)
|
||||||
|
{ return _mm256_xor_si256 (a.Data(), _mm256_cmpeq_epi64(a.Data(),a.Data())); }
|
||||||
|
#else //AVX2 is a superset of AVX. Without it, it is necessary to reinterpret the types
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator&& (SIMD<mask64,4> a, SIMD<mask64,4> b)
|
||||||
|
{ return _mm256_castpd_si256(_mm256_and_pd (_mm256_castsi256_pd(a.Data()),_mm256_castsi256_pd( b.Data()))); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator|| (SIMD<mask64,4> a, SIMD<mask64,4> b)
|
||||||
|
{ return _mm256_castpd_si256(_mm256_or_pd (_mm256_castsi256_pd(a.Data()), _mm256_castsi256_pd(b.Data()))); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,4> operator! (SIMD<mask64,4> a)
|
||||||
|
{ return _mm256_castpd_si256(_mm256_xor_pd (_mm256_castsi256_pd(a.Data()),_mm256_castsi256_pd( _mm256_cmpeq_epi64(a.Data(),a.Data())))); }
|
||||||
|
#endif
|
||||||
|
NETGEN_INLINE SIMD<double,4> If (SIMD<mask64,4> a, SIMD<double,4> b, SIMD<double,4> c)
|
||||||
|
{ return _mm256_blendv_pd(c.Data(), b.Data(), _mm256_castsi256_pd(a.Data())); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,4> IfPos (SIMD<double,4> a, SIMD<double,4> b, SIMD<double,4> c)
|
||||||
|
{
|
||||||
|
auto cp = _mm256_cmp_pd (a.Data(), _mm256_setzero_pd(), _CMP_GT_OS);
|
||||||
|
return _mm256_blendv_pd(c.Data(), b.Data(), cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,4> IfZero (SIMD<double,4> a, SIMD<double,4> b, SIMD<double,4> c)
|
||||||
|
{
|
||||||
|
auto cp = _mm256_cmp_pd (a.Data(), _mm256_setzero_pd(), _CMP_EQ_OS);
|
||||||
|
return _mm256_blendv_pd(c.Data(), b.Data(), cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE double HSum (SIMD<double,4> sd)
|
||||||
|
{
|
||||||
|
// __m128d hv = _mm_add_pd (_mm256_extractf128_pd(sd.Data(),0), _mm256_extractf128_pd(sd.Data(),1));
|
||||||
|
__m128d hv = (sd.Lo()+sd.Hi()).Data();
|
||||||
|
return _mm_cvtsd_f64 (_mm_hadd_pd (hv, hv));
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE auto HSum (SIMD<double,4> sd1, SIMD<double,4> sd2)
|
||||||
|
{
|
||||||
|
__m256d hv = _mm256_hadd_pd(sd1.Data(), sd2.Data());
|
||||||
|
__m128d hv2 = _mm_add_pd (_mm256_extractf128_pd(hv,0), _mm256_extractf128_pd(hv,1));
|
||||||
|
return SIMD<double,2>(_mm_cvtsd_f64 (hv2), _mm_cvtsd_f64(_mm_shuffle_pd (hv2, hv2, 3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE auto HSum (SIMD<double,4> v1, SIMD<double,4> v2, SIMD<double,4> v3, SIMD<double,4> v4)
|
||||||
|
{
|
||||||
|
__m256d hsum1 = _mm256_hadd_pd (v1.Data(), v2.Data());
|
||||||
|
__m256d hsum2 = _mm256_hadd_pd (v3.Data(), v4.Data());
|
||||||
|
SIMD<double,4> hsum = _mm256_add_pd (_mm256_permute2f128_pd (hsum1, hsum2, 1+2*16),
|
||||||
|
_mm256_blend_pd (hsum1, hsum2, 12));
|
||||||
|
return hsum;
|
||||||
|
// return make_tuple(hsum[0], hsum[1], hsum[2], hsum[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<int64_t,4> If (SIMD<mask64,4> a, SIMD<int64_t,4> b, SIMD<int64_t,4> c)
|
||||||
|
{ return _mm256_castpd_si256(_mm256_blendv_pd(_mm256_castsi256_pd(c.Data()), _mm256_castsi256_pd(b.Data()),
|
||||||
|
_mm256_castsi256_pd(a.Data()))); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NETGEN_CORE_SIMD_AVX_HPP
|
||||||
|
|
249
libsrc/core/simd_avx512.hpp
Normal file
249
libsrc/core/simd_avx512.hpp
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
#ifndef NETGEN_CORE_SIMD_AVX512_HPP
|
||||||
|
#define NETGEN_CORE_SIMD_AVX512_HPP
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* File: simd_avx512.hpp */
|
||||||
|
/* Author: Joachim Schoeberl, Matthias Hochsteger */
|
||||||
|
/* Date: 25. Mar. 16 */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include <immintrin.h>
|
||||||
|
|
||||||
|
namespace ngcore
|
||||||
|
{
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class SIMD<mask64,8>
|
||||||
|
{
|
||||||
|
__mmask8 mask;
|
||||||
|
public:
|
||||||
|
SIMD (size_t i)
|
||||||
|
: mask(_mm512_cmpgt_epi64_mask(_mm512_set1_epi64(i),
|
||||||
|
_mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0)))
|
||||||
|
{ ; }
|
||||||
|
SIMD (int i)
|
||||||
|
: mask(_mm512_cmpgt_epi64_mask(_mm512_set1_epi64(i),
|
||||||
|
_mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0)))
|
||||||
|
{ ; }
|
||||||
|
SIMD (int64_t i)
|
||||||
|
: mask(_mm512_cmpgt_epi64_mask(_mm512_set1_epi64(i),
|
||||||
|
_mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0)))
|
||||||
|
{ ; }
|
||||||
|
SIMD (__mmask8 _mask) : mask(_mask) { ; }
|
||||||
|
__mmask8 Data() const { return mask; }
|
||||||
|
static constexpr int Size() { return 8; }
|
||||||
|
static NETGEN_INLINE SIMD<mask64, 8> GetMaskFromBits (unsigned int i)
|
||||||
|
{
|
||||||
|
return SIMD<mask64, 8>(__mmask8(i));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class alignas(64) SIMD<int64_t,8>
|
||||||
|
{
|
||||||
|
__m512i data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr int Size() { return 8; }
|
||||||
|
SIMD () {}
|
||||||
|
SIMD (const SIMD &) = default;
|
||||||
|
SIMD & operator= (const SIMD &) = default;
|
||||||
|
|
||||||
|
SIMD (int64_t val) { data = _mm512_set1_epi64(val); }
|
||||||
|
SIMD (int64_t v0, int64_t v1, int64_t v2, int64_t v3, int64_t v4, int64_t v5, int64_t v6, int64_t v7) { data = _mm512_set_epi64(v7,v6,v5,v4,v3,v2,v1,v0); }
|
||||||
|
SIMD (__m512i _data) { data = _data; }
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<std::is_convertible<T, std::function<int64_t(int)>>::value, int>::type = 0>
|
||||||
|
SIMD (const T & func)
|
||||||
|
{
|
||||||
|
data = _mm512_set_epi64(func(7), func(6), func(5), func(4), func(3), func(2), func(1), func(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE auto operator[] (int i) const { return ((int64_t*)(&data))[i]; }
|
||||||
|
NETGEN_INLINE __m512i Data() const { return data; }
|
||||||
|
NETGEN_INLINE __m512i & Data() { return data; }
|
||||||
|
static SIMD FirstInt() { return { 0, 1, 2, 3, 4, 5, 6, 7 }; }
|
||||||
|
};
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<int64_t,8> operator-(SIMD<int64_t,8> a) { return _mm512_sub_epi64(_mm512_setzero_si512(), a.Data()); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<int64_t,8> operator+ (SIMD<int64_t,8> a, SIMD<int64_t,8> b) { return _mm512_add_epi64(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<int64_t,8> operator- (SIMD<int64_t,8> a, SIMD<int64_t,8> b) { return _mm512_sub_epi64(a.Data(),b.Data()); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<int64_t,8> If (SIMD<mask64,8> a, SIMD<int64_t,8> b, SIMD<int64_t,8> c)
|
||||||
|
{ return _mm512_mask_blend_epi64(a.Data(), c.Data(), b.Data()); }
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class alignas(64) SIMD<double,8>
|
||||||
|
{
|
||||||
|
__m512d data;
|
||||||
|
public:
|
||||||
|
static constexpr int Size() { return 8; }
|
||||||
|
SIMD () {}
|
||||||
|
SIMD (const SIMD &) = default;
|
||||||
|
SIMD & operator= (const SIMD &) = default;
|
||||||
|
|
||||||
|
SIMD (double val) { data = _mm512_set1_pd(val); }
|
||||||
|
SIMD (int val) { data = _mm512_set1_pd(val); }
|
||||||
|
SIMD (size_t val) { data = _mm512_set1_pd(val); }
|
||||||
|
SIMD (double const * p) { data = _mm512_loadu_pd(p); }
|
||||||
|
SIMD (double const * p, SIMD<mask64,8> mask)
|
||||||
|
{ data = _mm512_mask_loadu_pd(_mm512_setzero_pd(), mask.Data(), p); }
|
||||||
|
SIMD (__m512d _data) { data = _data; }
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<std::is_convertible<T, std::function<double(int)>>::value, int>::type = 0>
|
||||||
|
SIMD (const T & func)
|
||||||
|
{
|
||||||
|
data = _mm512_set_pd(func(7), func(6), func(5), func(4), func(3), func(2), func(1), func(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Store (double * p) { _mm512_storeu_pd(p, data); }
|
||||||
|
void Store (double * p, SIMD<mask64,8> mask) { _mm512_mask_storeu_pd(p, mask.Data(), data); }
|
||||||
|
|
||||||
|
template <typename Function>
|
||||||
|
void SIMD_function (const Function & func, std::true_type)
|
||||||
|
{
|
||||||
|
data = (__m512){ func(7), func(6), func(5), func(4),
|
||||||
|
func(3), func(2), func(1), func(0) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// not a function
|
||||||
|
void SIMD_function (double const * p, std::false_type)
|
||||||
|
{
|
||||||
|
data = _mm512_loadu_pd(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SIMD_function (double val, std::false_type)
|
||||||
|
{
|
||||||
|
data = _mm512_set1_pd(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SIMD_function (__m512d _data, std::false_type)
|
||||||
|
{
|
||||||
|
data = _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; }
|
||||||
|
NETGEN_INLINE __m512d Data() const { return data; }
|
||||||
|
NETGEN_INLINE __m512d & Data() { return data; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,8> operator- (SIMD<double,8> a) { return -a.Data(); }
|
||||||
|
NETGEN_INLINE SIMD<double,8> operator+ (SIMD<double,8> a, SIMD<double,8> b) { return _mm512_add_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,8> operator- (SIMD<double,8> a, SIMD<double,8> b) { return _mm512_sub_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,8> operator* (SIMD<double,8> a, SIMD<double,8> b) { return _mm512_mul_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,8> operator/ (SIMD<double,8> a, SIMD<double,8> b) { return _mm512_div_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,8> operator* (double a, SIMD<double,8> b) { return _mm512_set1_pd(a)*b.Data(); }
|
||||||
|
NETGEN_INLINE SIMD<double,8> operator* (SIMD<double,8> b, double a) { return _mm512_set1_pd(a)*b.Data(); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,8> sqrt (SIMD<double,8> a) { return _mm512_sqrt_pd(a.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,8> floor (SIMD<double,8> a) { return _mm512_floor_pd(a.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,8> ceil (SIMD<double,8> a) { return _mm512_ceil_pd(a.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,8> fabs (SIMD<double,8> a) { return _mm512_max_pd(a.Data(), -a.Data()); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator<= (SIMD<double,8> a , SIMD<double,8> b)
|
||||||
|
{ return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_LE_OQ); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator< (SIMD<double,8> a , SIMD<double,8> b)
|
||||||
|
{ return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_LT_OQ); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator>= (SIMD<double,8> a , SIMD<double,8> b)
|
||||||
|
{ return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_GE_OQ); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator> (SIMD<double,8> a , SIMD<double,8> b)
|
||||||
|
{ return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_GT_OQ); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator== (SIMD<double,8> a , SIMD<double,8> b)
|
||||||
|
{ return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_EQ_OQ); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator!= (SIMD<double,8> a , SIMD<double,8> b)
|
||||||
|
{ return _mm512_cmp_pd_mask (a.Data(), b.Data(), _CMP_NEQ_OQ); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator<= (SIMD<int64_t,8> a , SIMD<int64_t,8> b)
|
||||||
|
{ return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_LE); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator< (SIMD<int64_t,8> a , SIMD<int64_t,8> b)
|
||||||
|
{ return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_LT); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator>= (SIMD<int64_t,8> a , SIMD<int64_t,8> b)
|
||||||
|
{ return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_NLT); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator> (SIMD<int64_t,8> a , SIMD<int64_t,8> b)
|
||||||
|
{ return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_NLE); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator== (SIMD<int64_t,8> a , SIMD<int64_t,8> b)
|
||||||
|
{ return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_EQ); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator!= (SIMD<int64_t,8> a , SIMD<int64_t,8> b)
|
||||||
|
{ return _mm512_cmp_epi64_mask (a.Data(), b.Data(), _MM_CMPINT_NE); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator&& (SIMD<mask64,8> a, SIMD<mask64,8> b)
|
||||||
|
{ return (__mmask8)(a.Data() & b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator|| (SIMD<mask64,8> a, SIMD<mask64,8> b)
|
||||||
|
{ return (__mmask8)(a.Data() | b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,8> operator! (SIMD<mask64,8> a)
|
||||||
|
{ return (__mmask8)(~a.Data()); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,8> If (SIMD<mask64,8> a, SIMD<double,8> b, SIMD<double,8> c)
|
||||||
|
{ return _mm512_mask_blend_pd(a.Data(), c.Data(), b.Data()); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,8> IfPos (SIMD<double,8> a, SIMD<double> b, SIMD<double> c)
|
||||||
|
{
|
||||||
|
auto k = _mm512_cmp_pd_mask(a.Data(),_mm512_setzero_pd(), _CMP_GT_OS);
|
||||||
|
return _mm512_mask_blend_pd(k,c.Data(),b.Data());
|
||||||
|
}
|
||||||
|
NETGEN_INLINE SIMD<double,8> IfZero (SIMD<double,8> a, SIMD<double,8> b, SIMD<double,8> c)
|
||||||
|
{
|
||||||
|
auto k = _mm512_cmp_pd_mask(a.Data(),_mm512_setzero_pd(), _CMP_EQ_OS);
|
||||||
|
return _mm512_mask_blend_pd(k,c.Data(),b.Data());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE auto Unpack (SIMD<double,8> a, SIMD<double,8> b)
|
||||||
|
{
|
||||||
|
return std::make_tuple(SIMD<double,8>(_mm512_unpacklo_pd(a.Data(),b.Data())),
|
||||||
|
SIMD<double,8>(_mm512_unpackhi_pd(a.Data(),b.Data())));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE double HSum (SIMD<double,8> sd)
|
||||||
|
{
|
||||||
|
SIMD<double,4> low = _mm512_extractf64x4_pd(sd.Data(),0);
|
||||||
|
SIMD<double,4> high = _mm512_extractf64x4_pd(sd.Data(),1);
|
||||||
|
return HSum(low)+HSum(high);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE auto HSum (SIMD<double,8> sd1, SIMD<double,8> sd2)
|
||||||
|
{
|
||||||
|
return SIMD<double,2>(HSum(sd1), HSum(sd2));
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,4> HSum (SIMD<double,8> v1, SIMD<double,8> v2, SIMD<double,8> v3, SIMD<double,8> v4)
|
||||||
|
{
|
||||||
|
SIMD<double> lo,hi;
|
||||||
|
std::tie(lo,hi) = Unpack(v1, v2);
|
||||||
|
SIMD<double> sum01 = lo+hi;
|
||||||
|
std::tie(lo,hi) = Unpack(v3, v4);
|
||||||
|
SIMD<double> sum23 = lo+hi;
|
||||||
|
// sum01 b a b a b a b a
|
||||||
|
// sum23 d c d c d c d c
|
||||||
|
// __m512 perm = _mm512_permutex2var_pd (sum01.Data(), _mm512_set_epi64(1,2,3,4,5,6,7,8), sum23.Data());
|
||||||
|
__m256d ab = _mm512_extractf64x4_pd(sum01.Data(),0) + _mm512_extractf64x4_pd(sum01.Data(),1);
|
||||||
|
__m256d cd = _mm512_extractf64x4_pd(sum23.Data(),0) + _mm512_extractf64x4_pd(sum23.Data(),1);
|
||||||
|
return _mm256_add_pd (_mm256_permute2f128_pd (ab, cd, 1+2*16), _mm256_blend_pd (ab, cd, 12));
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,8> FMA (SIMD<double,8> a, SIMD<double,8> b, SIMD<double,8> c)
|
||||||
|
{
|
||||||
|
return _mm512_fmadd_pd (a.Data(), b.Data(), c.Data());
|
||||||
|
}
|
||||||
|
NETGEN_INLINE SIMD<double,8> FMA (const double & a, SIMD<double,8> b, SIMD<double,8> c)
|
||||||
|
{
|
||||||
|
return _mm512_fmadd_pd (_mm512_set1_pd(a), b.Data(), c.Data());
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,8> FNMA (SIMD<double,8> a, SIMD<double,8> b, SIMD<double,8> c)
|
||||||
|
{
|
||||||
|
return _mm512_fnmadd_pd (a.Data(), b.Data(), c.Data());
|
||||||
|
}
|
||||||
|
NETGEN_INLINE SIMD<double,8> FNMA (const double & a, SIMD<double,8> b, SIMD<double,8> c)
|
||||||
|
{
|
||||||
|
return _mm512_fnmadd_pd (_mm512_set1_pd(a), b.Data(), c.Data());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NETGEN_CORE_SIMD_AVX512_HPP
|
707
libsrc/core/simd_generic.hpp
Normal file
707
libsrc/core/simd_generic.hpp
Normal file
@ -0,0 +1,707 @@
|
|||||||
|
#ifndef NETGEN_CORE_SIMD_GENERIC_HPP
|
||||||
|
#define NETGEN_CORE_SIMD_GENERIC_HPP
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* File: simd_base.hpp */
|
||||||
|
/* Author: Joachim Schoeberl, Matthias Hochsteger */
|
||||||
|
/* Date: 25. Mar. 16 */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
#include <functional>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "array.hpp"
|
||||||
|
|
||||||
|
namespace ngcore
|
||||||
|
{
|
||||||
|
|
||||||
|
constexpr int GetDefaultSIMDSize() {
|
||||||
|
#if defined __AVX512F__
|
||||||
|
return 8;
|
||||||
|
#elif defined __AVX__
|
||||||
|
return 4;
|
||||||
|
#elif defined NETGEN_ARCH_AMD64
|
||||||
|
return 2;
|
||||||
|
#else
|
||||||
|
return 2;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, int N=GetDefaultSIMDSize()> class SIMD;
|
||||||
|
|
||||||
|
class mask64;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
namespace detail {
|
||||||
|
template <typename T, size_t N, size_t... I>
|
||||||
|
auto array_range_impl(std::array<T, N> const& arr,
|
||||||
|
size_t first,
|
||||||
|
std::index_sequence<I...>)
|
||||||
|
-> std::array<T, sizeof...(I)> {
|
||||||
|
return {arr[first + I]...};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <size_t S, typename T, size_t N>
|
||||||
|
auto array_range(std::array<T, N> const& arr, size_t first) {
|
||||||
|
return array_range_impl(arr, first, std::make_index_sequence<S>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// mask
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class SIMD<mask64,1>
|
||||||
|
{
|
||||||
|
int64_t mask;
|
||||||
|
public:
|
||||||
|
SIMD (int64_t i)
|
||||||
|
: mask(i > 0 ? -1 : 0) { ; }
|
||||||
|
bool Data() const { return mask; }
|
||||||
|
static constexpr int Size() { return 1; }
|
||||||
|
auto operator[] (int /* i */) const { return mask; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
class alignas(GetDefaultSIMDSize()*sizeof(int64_t)) SIMD<mask64,N>
|
||||||
|
{
|
||||||
|
static constexpr int N1 = std::min(GetDefaultSIMDSize(), N/2);
|
||||||
|
static constexpr int N2 = N-N1;
|
||||||
|
|
||||||
|
SIMD<mask64,N1> lo;
|
||||||
|
SIMD<mask64,N2> hi;
|
||||||
|
public:
|
||||||
|
|
||||||
|
SIMD (int64_t i) : lo(i), hi(i-N1 ) { ; }
|
||||||
|
SIMD (SIMD<mask64,N1> lo_, SIMD<mask64,N2> hi_) : lo(lo_), hi(hi_) { ; }
|
||||||
|
SIMD<mask64,N1> Lo() const { return lo; }
|
||||||
|
SIMD<mask64,N2> Hi() const { return hi; }
|
||||||
|
static constexpr int Size() { return N; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<int N>
|
||||||
|
NETGEN_INLINE SIMD<mask64,N> operator&& (SIMD<mask64,N> a, SIMD<mask64,N> b)
|
||||||
|
{
|
||||||
|
if constexpr(N==1) return a.Data() && b.Data();
|
||||||
|
else return { a.Lo() && b.Lo(), a.Hi() && b.Hi() };
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// int64
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class SIMD<int64_t,1>
|
||||||
|
{
|
||||||
|
int64_t data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr int Size() { return 1; }
|
||||||
|
SIMD () {}
|
||||||
|
SIMD (const SIMD &) = default;
|
||||||
|
SIMD & operator= (const SIMD &) = default;
|
||||||
|
SIMD (int val) : data{val} {}
|
||||||
|
SIMD (int64_t val) : data{val} {}
|
||||||
|
SIMD (size_t val) : data(val) {}
|
||||||
|
explicit SIMD (std::array<int64_t, 1> arr)
|
||||||
|
: data{arr[0]}
|
||||||
|
{}
|
||||||
|
|
||||||
|
int64_t operator[] (int i) const { return ((int64_t*)(&data))[i]; }
|
||||||
|
auto Data() const { return data; }
|
||||||
|
static SIMD FirstInt(int64_t n0=0) { return {n0}; }
|
||||||
|
template <int I>
|
||||||
|
int64_t Get()
|
||||||
|
{
|
||||||
|
static_assert(I==0);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<int N>
|
||||||
|
class alignas(GetDefaultSIMDSize()*sizeof(int64_t)) SIMD<int64_t,N>
|
||||||
|
{
|
||||||
|
static constexpr int N1 = std::min(GetDefaultSIMDSize(), N/2);
|
||||||
|
static constexpr int N2 = N-N1;
|
||||||
|
|
||||||
|
SIMD<int64_t,N1> lo;
|
||||||
|
SIMD<int64_t,N2> high;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr int Size() { return N; }
|
||||||
|
|
||||||
|
SIMD () {}
|
||||||
|
SIMD (const SIMD &) = default;
|
||||||
|
SIMD & operator= (const SIMD &) = default;
|
||||||
|
|
||||||
|
SIMD (int val) : lo{val}, high{val} { ; }
|
||||||
|
SIMD (int64_t val) : lo{val}, high{val} { ; }
|
||||||
|
SIMD (size_t val) : lo{val}, high{val} { ; }
|
||||||
|
SIMD (SIMD<int64_t,N1> lo_, SIMD<int64_t,N2> high_) : lo(lo_), high(high_) { ; }
|
||||||
|
|
||||||
|
explicit SIMD( std::array<int64_t, N> arr )
|
||||||
|
: lo(detail::array_range<N1>(arr, 0)),
|
||||||
|
high(detail::array_range<N2>(arr, N1))
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename ...T>
|
||||||
|
explicit SIMD(const T... vals)
|
||||||
|
: lo(detail::array_range<N1>(std::array<int64_t, N>{vals...}, 0)),
|
||||||
|
high(detail::array_range<N2>(std::array<int64_t, N>{vals...}, N1))
|
||||||
|
{
|
||||||
|
static_assert(sizeof...(vals)==N, "wrong number of arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<std::is_convertible<T, std::function<int64_t(int)>>::value, int>::type = 0>
|
||||||
|
SIMD (const T & func)
|
||||||
|
{
|
||||||
|
for(auto i : IntRange(N1))
|
||||||
|
lo[i] = func(i);
|
||||||
|
for(auto i : IntRange(N2))
|
||||||
|
high[i] = func(N1+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Lo() const { return lo; }
|
||||||
|
auto Hi() const { return high; }
|
||||||
|
|
||||||
|
int64_t operator[] (int i) const { return ((int64_t*)(&lo))[i]; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
operator tuple<int64_t&,int64_t&,int64_t&,int64_t&> ()
|
||||||
|
{ return tuple<int64_t&,int64_t&,int64_t&,int64_t&>((*this)[0], (*this)[1], (*this)[2], (*this)[3]); }
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
static SIMD FirstInt() { return { 0, 1, 2, 3 }; }
|
||||||
|
*/
|
||||||
|
static SIMD FirstInt(int64_t n0=0) { return {SIMD<int64_t,N1>::FirstInt(n0), SIMD<int64_t,N2>::FirstInt(n0+N1)}; }
|
||||||
|
template <int I>
|
||||||
|
int64_t Get()
|
||||||
|
{
|
||||||
|
static_assert(I>=0 && I<N, "Index out of range");
|
||||||
|
if constexpr(I<N1) return lo.template Get<I>();
|
||||||
|
else return high.template Get<I-N1>();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// double
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class SIMD<double,1>
|
||||||
|
{
|
||||||
|
double data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr int Size() { return 1; }
|
||||||
|
SIMD () {}
|
||||||
|
SIMD (const SIMD &) = default;
|
||||||
|
SIMD & operator= (const SIMD &) = default;
|
||||||
|
SIMD (double val) { data = val; }
|
||||||
|
SIMD (int val) { data = val; }
|
||||||
|
SIMD (size_t val) { data = val; }
|
||||||
|
SIMD (double const * p) { data = *p; }
|
||||||
|
SIMD (double const * p, SIMD<mask64,1> mask) { data = mask.Data() ? *p : 0.0; }
|
||||||
|
explicit SIMD (std::array<double, 1> arr)
|
||||||
|
: data{arr[0]}
|
||||||
|
{}
|
||||||
|
|
||||||
|
template <typename T, typename std::enable_if<std::is_convertible<T,std::function<double(int)>>::value,int>::type = 0>
|
||||||
|
SIMD (const T & func)
|
||||||
|
{
|
||||||
|
data = func(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename std::enable_if<std::is_convertible<T,std::function<double(int)>>::value,int>::type = 0>
|
||||||
|
SIMD & operator= (const T & func)
|
||||||
|
{
|
||||||
|
data = func(0);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Store (double * p) { *p = data; }
|
||||||
|
void Store (double * p, SIMD<mask64,1> mask) { if (mask.Data()) *p = data; }
|
||||||
|
|
||||||
|
double operator[] (int i) const { return ((double*)(&data))[i]; }
|
||||||
|
double Data() const { return data; }
|
||||||
|
template <int I>
|
||||||
|
double Get()
|
||||||
|
{
|
||||||
|
static_assert(I==0);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<int N>
|
||||||
|
class alignas(GetDefaultSIMDSize()*sizeof(double)) SIMD<double, N>
|
||||||
|
{
|
||||||
|
static constexpr int N1 = std::min(GetDefaultSIMDSize(), N/2);
|
||||||
|
static constexpr int N2 = N-N1;
|
||||||
|
|
||||||
|
SIMD<double, N1> lo;
|
||||||
|
SIMD<double, N2> high;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr int Size() { return N; }
|
||||||
|
SIMD () {}
|
||||||
|
SIMD (const SIMD &) = default;
|
||||||
|
SIMD (SIMD<double,N1> lo_, SIMD<double,N2> hi_) : lo(lo_), high(hi_) { ; }
|
||||||
|
|
||||||
|
template <typename T, typename std::enable_if<std::is_convertible<T,std::function<double(int)>>::value,int>::type = 0>
|
||||||
|
SIMD (const T & func)
|
||||||
|
{
|
||||||
|
double *p = (double*)this;
|
||||||
|
for(auto i : IntRange(N))
|
||||||
|
p[i] = func(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename std::enable_if<std::is_convertible<T,std::function<double(int)>>::value,int>::type = 0>
|
||||||
|
SIMD & operator= (const T & func)
|
||||||
|
{
|
||||||
|
double *p = (double*)this;
|
||||||
|
for(auto i : IntRange(N))
|
||||||
|
p[i] = func(i);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SIMD & operator= (const SIMD &) = default;
|
||||||
|
|
||||||
|
SIMD (double val) : lo{val}, high{val} { ; }
|
||||||
|
SIMD (int val) : lo{val}, high{val} { ; }
|
||||||
|
SIMD (size_t val) : lo{val}, high{val} { ; }
|
||||||
|
|
||||||
|
SIMD (double const * p) : lo{p}, high{p+N1} { ; }
|
||||||
|
SIMD (double const * p, SIMD<mask64,N> mask)
|
||||||
|
: lo{p, mask.Lo()}, high{p+N1, mask.Hi()}
|
||||||
|
{ }
|
||||||
|
SIMD (double * p) : lo{p}, high{p+N1} { ; }
|
||||||
|
SIMD (double * p, SIMD<mask64,N> mask)
|
||||||
|
: lo{p, mask.Lo()}, high{p+N1, mask.Hi()}
|
||||||
|
{ }
|
||||||
|
|
||||||
|
explicit SIMD( std::array<double, N> arr )
|
||||||
|
: lo(detail::array_range<N1>(arr, 0)),
|
||||||
|
high(detail::array_range<N2>(arr, N1))
|
||||||
|
{}
|
||||||
|
|
||||||
|
template<typename ...T>
|
||||||
|
explicit SIMD(const T... vals)
|
||||||
|
: lo(detail::array_range<N1>(std::array<double, N>{vals...}, 0)),
|
||||||
|
high(detail::array_range<N2>(std::array<double, N>{vals...}, N1))
|
||||||
|
{
|
||||||
|
static_assert(sizeof...(vals)==N, "wrong number of arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Store (double * p) { lo.Store(p); high.Store(p+N1); }
|
||||||
|
void Store (double * p, SIMD<mask64,N> mask)
|
||||||
|
{
|
||||||
|
lo.Store(p, mask.Lo());
|
||||||
|
high.Store(p+N1, mask.Hi());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Lo() const { return lo; }
|
||||||
|
auto Hi() const { return high; }
|
||||||
|
|
||||||
|
double operator[] (int i) const { return ((double*)(&lo))[i]; }
|
||||||
|
|
||||||
|
template<typename=std::enable_if<N==2>>
|
||||||
|
operator std::tuple<double&,double&> ()
|
||||||
|
{
|
||||||
|
double *p = (double*)this;
|
||||||
|
return std::tuple<double&,double&>(p[0], p[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename=std::enable_if<N==4>>
|
||||||
|
operator std::tuple<double&,double&,double&,double&> ()
|
||||||
|
{ return std::tuple<double&,double&,double&,double&>((*this)[0], (*this)[1], (*this)[2], (*this)[3]); }
|
||||||
|
|
||||||
|
template <int I>
|
||||||
|
double Get()
|
||||||
|
{
|
||||||
|
static_assert(I>=0 && I<N, "Index out of range");
|
||||||
|
if constexpr(I<N1) return lo.template Get<I>();
|
||||||
|
else return high.template Get<I-N1>();
|
||||||
|
}
|
||||||
|
auto Data() const { return *this; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Generic operators for any arithmetic type/simd width
|
||||||
|
template <typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<T,N> operator+ (SIMD<T,N> a, SIMD<T,N> b) {
|
||||||
|
if constexpr(N==1) return a.Data()+b.Data();
|
||||||
|
else return { a.Lo()+b.Lo(), a.Hi()+b.Hi() };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<T,N> operator- (SIMD<T,N> a, SIMD<T,N> b) {
|
||||||
|
if constexpr(N==1) return a.Data()-b.Data();
|
||||||
|
else return { a.Lo()-b.Lo(), a.Hi()-b.Hi() };
|
||||||
|
}
|
||||||
|
template <typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<T,N> operator- (SIMD<T,N> a) {
|
||||||
|
if constexpr(N==1) return -a.Data();
|
||||||
|
else return { -a.Lo(), -a.Hi() };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<T,N> operator* (SIMD<T,N> a, SIMD<T,N> b) {
|
||||||
|
if constexpr(N==1) return a.Data()*b.Data();
|
||||||
|
else return { a.Lo()*b.Lo(), a.Hi()*b.Hi() };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<T,N> operator/ (SIMD<T,N> a, SIMD<T,N> b) {
|
||||||
|
if constexpr(N==1) return a.Data()/b.Data();
|
||||||
|
else return { a.Lo()/b.Lo(), a.Hi()/b.Hi() };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<mask64,N> operator< (SIMD<T,N> a, SIMD<T,N> b)
|
||||||
|
{
|
||||||
|
if constexpr(N==1) return a.Data() < b.Data();
|
||||||
|
else return { a.Lo()<b.Lo(), a.Hi()<b.Hi() };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<mask64,N> operator<= (SIMD<T,N> a, SIMD<T,N> b)
|
||||||
|
{
|
||||||
|
if constexpr(N==1) return a.Data() <= b.Data();
|
||||||
|
else return { a.Lo()<=b.Lo(), a.Hi()<=b.Hi() };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<mask64,N> operator> (SIMD<T,N> a, SIMD<T,N> b)
|
||||||
|
{
|
||||||
|
if constexpr(N==1) return a.Data() > b.Data();
|
||||||
|
else return { a.Lo()>b.Lo(), a.Hi()>b.Hi() };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<mask64,N> operator>= (SIMD<T,N> a, SIMD<T,N> b)
|
||||||
|
{
|
||||||
|
if constexpr(N==1) return a.Data() >= b.Data();
|
||||||
|
else return { a.Lo()>=b.Lo(), a.Hi()>=b.Hi() };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<mask64,N> operator== (SIMD<T,N> a, SIMD<T,N> b)
|
||||||
|
{
|
||||||
|
if constexpr(N==1) return a.Data() == b.Data();
|
||||||
|
else return { a.Lo()==b.Lo(), a.Hi()==b.Hi() };
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<mask64,N> operator!= (SIMD<T,N> a, SIMD<T,N> b)
|
||||||
|
{
|
||||||
|
if constexpr(N==1) return a.Data() != b.Data();
|
||||||
|
else return { a.Lo()!=b.Lo(), a.Hi()!=b.Hi() };
|
||||||
|
}
|
||||||
|
|
||||||
|
// int64_t operators with scalar operand (implement overloads to allow implicit casts for second operand)
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> operator+ (SIMD<int64_t,N> a, int64_t b) { return a+SIMD<int64_t,N>(b); }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> operator+ (int64_t a, SIMD<int64_t,N> b) { return SIMD<int64_t,N>(a)+b; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> operator- (int64_t a, SIMD<int64_t,N> b) { return SIMD<int64_t,N>(a)-b; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> operator- (SIMD<int64_t,N> a, int64_t b) { return a-SIMD<int64_t,N>(b); }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> operator* (int64_t a, SIMD<int64_t,N> b) { return SIMD<int64_t,N>(a)*b; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> operator* (SIMD<int64_t,N> b, int64_t a) { return SIMD<int64_t,N>(a)*b; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> operator/ (SIMD<int64_t,N> a, int64_t b) { return a/SIMD<int64_t,N>(b); }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> operator/ (int64_t a, SIMD<int64_t,N> b) { return SIMD<int64_t,N>(a)/b; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> & operator+= (SIMD<int64_t,N> & a, SIMD<int64_t,N> b) { a=a+b; return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> & operator+= (SIMD<int64_t,N> & a, int64_t b) { a+=SIMD<int64_t,N>(b); return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> & operator-= (SIMD<int64_t,N> & a, SIMD<int64_t,N> b) { a = a-b; return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> & operator-= (SIMD<int64_t,N> & a, int64_t b) { a-=SIMD<int64_t,N>(b); return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> & operator*= (SIMD<int64_t,N> & a, SIMD<int64_t,N> b) { a=a*b; return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> & operator*= (SIMD<int64_t,N> & a, int64_t b) { a*=SIMD<int64_t,N>(b); return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<int64_t,N> & operator/= (SIMD<int64_t,N> & a, SIMD<int64_t,N> b) { a = a/b; return a; }
|
||||||
|
|
||||||
|
// double operators with scalar operand (implement overloads to allow implicit casts for second operand)
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> operator+ (SIMD<double,N> a, double b) { return a+SIMD<double,N>(b); }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> operator+ (double a, SIMD<double,N> b) { return SIMD<double,N>(a)+b; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> operator- (double a, SIMD<double,N> b) { return SIMD<double,N>(a)-b; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> operator- (SIMD<double,N> a, double b) { return a-SIMD<double,N>(b); }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> operator* (double a, SIMD<double,N> b) { return SIMD<double,N>(a)*b; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> operator* (SIMD<double,N> b, double a) { return SIMD<double,N>(a)*b; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> operator/ (SIMD<double,N> a, double b) { return a/SIMD<double,N>(b); }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> operator/ (double a, SIMD<double,N> b) { return SIMD<double,N>(a)/b; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> & operator+= (SIMD<double,N> & a, SIMD<double,N> b) { a=a+b; return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> & operator+= (SIMD<double,N> & a, double b) { a+=SIMD<double,N>(b); return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> & operator-= (SIMD<double,N> & a, SIMD<double,N> b) { a = a-b; return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> & operator-= (SIMD<double,N> & a, double b) { a-=SIMD<double,N>(b); return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> & operator*= (SIMD<double,N> & a, SIMD<double,N> b) { a=a*b; return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> & operator*= (SIMD<double,N> & a, double b) { a*=SIMD<double,N>(b); return a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> & operator/= (SIMD<double,N> & a, SIMD<double,N> b) { a = a/b; return a; }
|
||||||
|
|
||||||
|
// double functions
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> L2Norm2 (SIMD<double,N> a) { return a*a; }
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE SIMD<double,N> Trans (SIMD<double,N> a) { return a; }
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE double HSum (SIMD<double,N> a)
|
||||||
|
{
|
||||||
|
if constexpr(N==1)
|
||||||
|
return a.Data();
|
||||||
|
else
|
||||||
|
return HSum(a.Lo()) + HSum(a.Hi());
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE double IfPos (double a, double b, double c) { return a>0 ? b : c; }
|
||||||
|
NETGEN_INLINE double IfZero (double a, double b, double c) { return a==0. ? b : c; }
|
||||||
|
|
||||||
|
template<typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<T,N> IfPos (SIMD<T,N> a, SIMD<T,N> b, SIMD<T,N> c)
|
||||||
|
{
|
||||||
|
if constexpr(N==1) return a.Data()>0.0 ? b : c;
|
||||||
|
else return { IfPos(a.Lo(), b.Lo(), c.Lo()), IfPos(a.Hi(), b.Hi(), c.Hi())};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<T,N> IfZero (SIMD<T,N> a, SIMD<T,N> b, SIMD<T,N> c)
|
||||||
|
{
|
||||||
|
if constexpr(N==1) return a.Data()==0.0 ? b : c;
|
||||||
|
else return { IfZero(a.Lo(), b.Lo(), c.Lo()), IfZero(a.Hi(), b.Hi(), c.Hi())};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, int N>
|
||||||
|
NETGEN_INLINE SIMD<T,N> If (SIMD<mask64,N> a, SIMD<T,N> b, SIMD<T,N> c)
|
||||||
|
{
|
||||||
|
if constexpr(N==1) return a.Data() ? b : c;
|
||||||
|
else return { If(a.Lo(), b.Lo(), c.Lo()), If(a.Hi(), b.Hi(), c.Hi())};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// a*b+c
|
||||||
|
template <typename T1, typename T2, typename T3>
|
||||||
|
NETGEN_INLINE auto FMA(T1 a, T2 b, T3 c)
|
||||||
|
{
|
||||||
|
return c+a*b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T1, typename T2, typename T3>
|
||||||
|
NETGEN_INLINE auto FNMA(T1 a, T2 b, T3 c)
|
||||||
|
{
|
||||||
|
return c-a*b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update form of fma
|
||||||
|
template <int N>
|
||||||
|
void FMAasm (SIMD<double,N> a, SIMD<double,N> b, SIMD<double,N> & sum)
|
||||||
|
{
|
||||||
|
sum = FMA(a,b,sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
// update form of fms
|
||||||
|
template <int N>
|
||||||
|
void FNMAasm (SIMD<double,N> a, SIMD<double,N> b, SIMD<double,N> & sum)
|
||||||
|
{
|
||||||
|
// sum -= a*b;
|
||||||
|
sum = FNMA(a,b,sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <int i, typename T, int N>
|
||||||
|
T get(SIMD<T,N> a) { return a[i]; }
|
||||||
|
|
||||||
|
template <int NUM, typename FUNC>
|
||||||
|
NETGEN_INLINE void Iterate2 (FUNC f)
|
||||||
|
{
|
||||||
|
if constexpr (NUM > 1) Iterate2<NUM-1> (f);
|
||||||
|
if constexpr (NUM >= 1) f(std::integral_constant<int,NUM-1>());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T, int N>
|
||||||
|
ostream & operator<< (ostream & ost, SIMD<T,N> simd)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
ost << simd[0];
|
||||||
|
for (int i = 1; i < simd.Size(); i++)
|
||||||
|
ost << " " << simd[i];
|
||||||
|
*/
|
||||||
|
Iterate2<simd.Size()> ([&] (auto I) {
|
||||||
|
if (I.value != 0) ost << " ";
|
||||||
|
ost << get<I.value>(simd);
|
||||||
|
});
|
||||||
|
return ost;
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::sqrt;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> sqrt (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double>([a](int i)->double { return sqrt(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::fabs;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> fabs (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double>([a](int i)->double { return fabs(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::floor;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> floor (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double>([a](int i)->double { return floor(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::ceil;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> ceil (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double>([a](int i)->double { return ceil(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::exp;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> exp (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double>([a](int i)->double { return exp(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::log;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> log (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double,N>([a](int i)->double { return log(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::pow;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> pow (ngcore::SIMD<double,N> a, double x) {
|
||||||
|
return ngcore::SIMD<double,N>([a,x](int i)->double { return pow(a[i],x); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> pow (ngcore::SIMD<double,N> a, ngcore::SIMD<double,N> b) {
|
||||||
|
return ngcore::SIMD<double,N>([a,b](int i)->double { return pow(a[i],b[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::sin;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> sin (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double,N>([a](int i)->double { return sin(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::cos;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> cos (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double,N>([a](int i)->double { return cos(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::tan;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> tan (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double,N>([a](int i)->double { return tan(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::atan;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> atan (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double,N>([a](int i)->double { return atan(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::atan2;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> atan2 (ngcore::SIMD<double,N> y, ngcore::SIMD<double,N> x) {
|
||||||
|
return ngcore::SIMD<double,N>([y,x](int i)->double { return atan2(y[i], x[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::acos;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> acos (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double,N>([a](int i)->double { return acos(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::asin;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> asin (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double,N>([a](int i)->double { return asin(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::sinh;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> sinh (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double,N>([a](int i)->double { return sinh(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
using std::cosh;
|
||||||
|
template <int N>
|
||||||
|
NETGEN_INLINE ngcore::SIMD<double,N> cosh (ngcore::SIMD<double,N> a) {
|
||||||
|
return ngcore::SIMD<double,N>([a](int i)->double { return cosh(a[i]); } );
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int N, typename T>
|
||||||
|
using MultiSIMD = SIMD<T, N*GetDefaultSIMDSize()>;
|
||||||
|
|
||||||
|
template<int N>
|
||||||
|
NETGEN_INLINE auto Unpack (SIMD<double,N> a, SIMD<double,N> b)
|
||||||
|
{
|
||||||
|
if constexpr(N==1)
|
||||||
|
{
|
||||||
|
return std::make_tuple(SIMD<double,N>{a.Data()}, SIMD<double,N>{b.Data()} );
|
||||||
|
}
|
||||||
|
else if constexpr(N==2)
|
||||||
|
{
|
||||||
|
return std::make_tuple(SIMD<double,N>{ a.Lo(), b.Lo() },
|
||||||
|
SIMD<double,N>{ a.Hi(), b.Hi() });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto [a1,b1] = Unpack(a.Lo(), b.Lo());
|
||||||
|
auto [a2,b2] = Unpack(a.Hi(), b.Hi());
|
||||||
|
return std::make_tuple(SIMD<double,N>{ a1, a2 },
|
||||||
|
SIMD<double,N>{ b1, b2 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace std
|
||||||
|
{
|
||||||
|
// structured binding support
|
||||||
|
template <typename T, int N >
|
||||||
|
struct tuple_size<ngcore::SIMD<T,N>> : std::integral_constant<std::size_t, N> {};
|
||||||
|
template<size_t N, typename T, int M> struct tuple_element<N,ngcore::SIMD<T,M>> { using type = T; };
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NETGEN_CORE_SIMD_GENERIC_HPP
|
266
libsrc/core/simd_sse.hpp
Normal file
266
libsrc/core/simd_sse.hpp
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
#ifndef NETGEN_CORE_SIMD_SSE_HPP
|
||||||
|
#define NETGEN_CORE_SIMD_SSE_HPP
|
||||||
|
|
||||||
|
/**************************************************************************/
|
||||||
|
/* File: simd_sse.hpp */
|
||||||
|
/* Author: Joachim Schoeberl, Matthias Hochsteger */
|
||||||
|
/* Date: 25. Mar. 16 */
|
||||||
|
/**************************************************************************/
|
||||||
|
|
||||||
|
#include <immintrin.h>
|
||||||
|
|
||||||
|
namespace ngcore
|
||||||
|
{
|
||||||
|
|
||||||
|
template <>
|
||||||
|
class SIMD<mask64,2>
|
||||||
|
{
|
||||||
|
__m128i mask;
|
||||||
|
public:
|
||||||
|
SIMD (int i)
|
||||||
|
: mask(_mm_cmpgt_epi32(_mm_set1_epi32(i),
|
||||||
|
_mm_set_epi32(1, 1, 0, 0)))
|
||||||
|
{ ; }
|
||||||
|
SIMD (__m128i _mask) : mask(_mask) { ; }
|
||||||
|
__m128i Data() const { return mask; }
|
||||||
|
static constexpr int Size() { return 2; }
|
||||||
|
static NETGEN_INLINE SIMD<mask64, 2> GetMaskFromBits (unsigned int i);
|
||||||
|
};
|
||||||
|
|
||||||
|
static SIMD<mask64, 2> masks_from_2bits[4] = {
|
||||||
|
_mm_set_epi32 (0,0,0,0), _mm_set_epi32 (0,0,-1,0),
|
||||||
|
_mm_set_epi32 (-1,0,0,0), _mm_set_epi32 (-1,0,-1,0),
|
||||||
|
};
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<mask64, 2> SIMD<mask64, 2> :: GetMaskFromBits (unsigned int i)
|
||||||
|
{
|
||||||
|
return masks_from_2bits[i & 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class alignas(16) SIMD<int64_t,2>
|
||||||
|
{
|
||||||
|
__m128i data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr int Size() { return 2; }
|
||||||
|
SIMD () {}
|
||||||
|
SIMD (const SIMD &) = default;
|
||||||
|
SIMD (int64_t v0, int64_t v1) { data = _mm_set_epi64x(v1,v0); }
|
||||||
|
SIMD (std::array<int64_t, 2> arr)
|
||||||
|
: data{_mm_set_epi64x(arr[1],arr[0])}
|
||||||
|
{}
|
||||||
|
|
||||||
|
SIMD & operator= (const SIMD &) = default;
|
||||||
|
|
||||||
|
SIMD (int64_t val) { data = _mm_set1_epi64x(val); }
|
||||||
|
SIMD (__m128i _data) { data = _data; }
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<std::is_convertible<T, std::function<int64_t(int)>>::value, int>::type = 0>
|
||||||
|
SIMD (const T & func)
|
||||||
|
{
|
||||||
|
data = _mm_set_epi64(func(1), func(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE auto operator[] (int i) const { return ((int64_t*)(&data))[i]; }
|
||||||
|
NETGEN_INLINE __m128i Data() const { return data; }
|
||||||
|
NETGEN_INLINE __m128i & Data() { return data; }
|
||||||
|
static SIMD FirstInt(int n0=0) { return { n0, n0+1 }; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<int64_t,2> operator-(SIMD<int64_t,2> a) { return _mm_sub_epi64(_mm_setzero_si128(), a.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<int64_t,2> operator+ (SIMD<int64_t,2> a, SIMD<int64_t,2> b) { return _mm_add_epi64(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<int64_t,2> operator- (SIMD<int64_t,2> a, SIMD<int64_t,2> b) { return _mm_sub_epi64(a.Data(),b.Data()); }
|
||||||
|
|
||||||
|
|
||||||
|
template<>
|
||||||
|
class alignas(16) SIMD<double,2>
|
||||||
|
{
|
||||||
|
__m128d data;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static constexpr int Size() { return 2; }
|
||||||
|
SIMD () {}
|
||||||
|
SIMD (const SIMD &) = default;
|
||||||
|
SIMD (double v0, double v1) { data = _mm_set_pd(v1,v0); }
|
||||||
|
SIMD (std::array<double, 2> arr)
|
||||||
|
: data{_mm_set_pd(arr[1], arr[0])}
|
||||||
|
{}
|
||||||
|
|
||||||
|
SIMD & operator= (const SIMD &) = default;
|
||||||
|
|
||||||
|
SIMD (double val) { data = _mm_set1_pd(val); }
|
||||||
|
SIMD (int val) { data = _mm_set1_pd(val); }
|
||||||
|
SIMD (size_t val) { data = _mm_set1_pd(val); }
|
||||||
|
|
||||||
|
SIMD (double const * p) { data = _mm_loadu_pd(p); }
|
||||||
|
SIMD (double const * p, SIMD<mask64,2> mask)
|
||||||
|
{
|
||||||
|
#ifdef __AVX__
|
||||||
|
data = _mm_maskload_pd(p, mask.Data());
|
||||||
|
#else
|
||||||
|
// this versions segfaults if p points to the last allowed element
|
||||||
|
// happened on Mac with the new SparseCholesky-factorization
|
||||||
|
// data = _mm_and_pd(_mm_castsi128_pd(mask.Data()), _mm_loadu_pd(p));
|
||||||
|
auto pmask = (int64_t*)&mask;
|
||||||
|
data = _mm_set_pd (pmask[1] ? p[1] : 0.0, pmask[0] ? p[0] : 0.0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
SIMD (__m128d _data) { data = _data; }
|
||||||
|
|
||||||
|
void Store (double * p) { _mm_storeu_pd(p, data); }
|
||||||
|
void Store (double * p, SIMD<mask64,2> mask)
|
||||||
|
{
|
||||||
|
#ifdef __AVX__
|
||||||
|
_mm_maskstore_pd(p, mask.Data(), data);
|
||||||
|
#else
|
||||||
|
/*
|
||||||
|
_mm_storeu_pd (p, _mm_or_pd (_mm_and_pd(_mm_castsi128_pd(mask.Data()), data),
|
||||||
|
_mm_andnot_pd(_mm_castsi128_pd(mask.Data()), _mm_loadu_pd(p))));
|
||||||
|
*/
|
||||||
|
auto pmask = (int64_t*)&mask;
|
||||||
|
if (pmask[0]) p[0] = (*this)[0];
|
||||||
|
if (pmask[1]) p[1] = (*this)[1];
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename std::enable_if<std::is_convertible<T, std::function<double(int)>>::value, int>::type = 0>
|
||||||
|
SIMD (const T & func)
|
||||||
|
{
|
||||||
|
data = _mm_set_pd(func(1), func(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; }
|
||||||
|
NETGEN_INLINE __m128d Data() const { return data; }
|
||||||
|
NETGEN_INLINE __m128d & Data() { return data; }
|
||||||
|
|
||||||
|
operator std::tuple<double&,double&> ()
|
||||||
|
{
|
||||||
|
auto pdata = (double*)&data;
|
||||||
|
return std::tuple<double&,double&>(pdata[0], pdata[1]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator- (SIMD<double,2> a) { return _mm_xor_pd(a.Data(), _mm_set1_pd(-0.0)); }
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator+ (SIMD<double,2> a, SIMD<double,2> b) { return _mm_add_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator- (SIMD<double,2> a, SIMD<double,2> b) { return _mm_sub_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator* (SIMD<double,2> a, SIMD<double,2> b) { return _mm_mul_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator/ (SIMD<double,2> a, SIMD<double,2> b) { return _mm_div_pd(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator* (double a, SIMD<double,2> b) { return _mm_set1_pd(a)*b; }
|
||||||
|
NETGEN_INLINE SIMD<double,2> operator* (SIMD<double,2> b, double a) { return _mm_set1_pd(a)*b; }
|
||||||
|
|
||||||
|
template<>
|
||||||
|
NETGEN_INLINE auto Unpack (SIMD<double,2> a, SIMD<double,2> b)
|
||||||
|
{
|
||||||
|
return std::make_tuple(SIMD<double,2>(_mm_unpacklo_pd(a.Data(),b.Data())),
|
||||||
|
SIMD<double,2>(_mm_unpackhi_pd(a.Data(),b.Data())));
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE __m128d my_mm_hadd_pd(__m128d a, __m128d b) {
|
||||||
|
#if defined(__SSE3__) || defined(__AVX__)
|
||||||
|
return _mm_hadd_pd(a,b);
|
||||||
|
#else
|
||||||
|
return _mm_add_pd( _mm_unpacklo_pd(a,b), _mm_unpackhi_pd(a,b) );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef __AVX__
|
||||||
|
NETGEN_INLINE __m128i my_mm_cmpgt_epi64(__m128i a, __m128i b) {
|
||||||
|
auto res_lo = _mm_cvtsi128_si64(a) > _mm_cvtsi128_si64(b) ? -1:0;
|
||||||
|
auto res_hi = _mm_cvtsi128_si64(_mm_srli_si128(a,8)) > _mm_cvtsi128_si64(_mm_srli_si128(b,8)) ? -1 : 0;
|
||||||
|
return _mm_set_epi64x(res_hi,res_lo);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
NETGEN_INLINE __m128i my_mm_cmpgt_epi64(__m128i a, __m128i b) {
|
||||||
|
return _mm_cmpgt_epi64(a,b);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,2> sqrt (SIMD<double,2> a) { return _mm_sqrt_pd(a.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<double,2> fabs (SIMD<double,2> a) { return _mm_max_pd(a.Data(), (-a).Data()); }
|
||||||
|
using std::floor;
|
||||||
|
NETGEN_INLINE SIMD<double,2> floor (SIMD<double,2> a)
|
||||||
|
{ return ngcore::SIMD<double,2>([&](int i)->double { return floor(a[i]); } ); }
|
||||||
|
using std::ceil;
|
||||||
|
NETGEN_INLINE SIMD<double,2> ceil (SIMD<double,2> a)
|
||||||
|
{ return ngcore::SIMD<double,2>([&](int i)->double { return ceil(a[i]); } ); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator<= (SIMD<double,2> a , SIMD<double,2> b)
|
||||||
|
{ return _mm_castpd_si128( _mm_cmple_pd(a.Data(),b.Data())); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator< (SIMD<double,2> a , SIMD<double,2> b)
|
||||||
|
{ return _mm_castpd_si128( _mm_cmplt_pd(a.Data(),b.Data())); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator>= (SIMD<double,2> a , SIMD<double,2> b)
|
||||||
|
{ return _mm_castpd_si128( _mm_cmpge_pd(a.Data(),b.Data())); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator> (SIMD<double,2> a , SIMD<double,2> b)
|
||||||
|
{ return _mm_castpd_si128( _mm_cmpgt_pd(a.Data(),b.Data())); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator== (SIMD<double,2> a , SIMD<double,2> b)
|
||||||
|
{ return _mm_castpd_si128( _mm_cmpeq_pd(a.Data(),b.Data())); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator!= (SIMD<double,2> a , SIMD<double,2> b)
|
||||||
|
{ return _mm_castpd_si128( _mm_cmpneq_pd(a.Data(),b.Data())); }
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator<= (SIMD<int64_t,2> a , SIMD<int64_t,2> b)
|
||||||
|
{ return _mm_xor_si128(_mm_cmpgt_epi64(a.Data(),b.Data()),_mm_set1_epi32(-1)); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator< (SIMD<int64_t,2> a , SIMD<int64_t,2> b)
|
||||||
|
{ return my_mm_cmpgt_epi64(b.Data(),a.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator>= (SIMD<int64_t,2> a , SIMD<int64_t,2> b)
|
||||||
|
{ return _mm_xor_si128(_mm_cmpgt_epi64(b.Data(),a.Data()),_mm_set1_epi32(-1)); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator> (SIMD<int64_t,2> a , SIMD<int64_t,2> b)
|
||||||
|
{ return my_mm_cmpgt_epi64(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator== (SIMD<int64_t,2> a , SIMD<int64_t,2> b)
|
||||||
|
{ return _mm_cmpeq_epi64(a.Data(),b.Data()); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator!= (SIMD<int64_t,2> a , SIMD<int64_t,2> b)
|
||||||
|
{ return _mm_xor_si128(_mm_cmpeq_epi64(a.Data(),b.Data()),_mm_set1_epi32(-1)); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator&& (SIMD<mask64,2> a, SIMD<mask64,2> b)
|
||||||
|
{ return _mm_castpd_si128(_mm_and_pd (_mm_castsi128_pd(a.Data()),_mm_castsi128_pd( b.Data()))); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator|| (SIMD<mask64,2> a, SIMD<mask64,2> b)
|
||||||
|
{ return _mm_castpd_si128(_mm_or_pd (_mm_castsi128_pd(a.Data()), _mm_castsi128_pd(b.Data()))); }
|
||||||
|
NETGEN_INLINE SIMD<mask64,2> operator! (SIMD<mask64,2> a)
|
||||||
|
{ return _mm_castpd_si128(_mm_xor_pd (_mm_castsi128_pd(a.Data()),_mm_castsi128_pd( _mm_cmpeq_epi64(a.Data(),a.Data())))); }
|
||||||
|
#ifdef __SSE4_1__
|
||||||
|
NETGEN_INLINE SIMD<double,2> If (SIMD<mask64,2> a, SIMD<double,2> b, SIMD<double,2> c)
|
||||||
|
{ return _mm_blendv_pd(c.Data(), b.Data(), _mm_castsi128_pd(a.Data())); }
|
||||||
|
#else
|
||||||
|
NETGEN_INLINE SIMD<double,2> If (SIMD<mask64,2> a, SIMD<double,2> b, SIMD<double,2> c)
|
||||||
|
{
|
||||||
|
return _mm_or_pd(
|
||||||
|
_mm_andnot_pd(_mm_castsi128_pd(a.Data()),c.Data()),
|
||||||
|
_mm_and_pd(b.Data(),_mm_castsi128_pd(a.Data()))
|
||||||
|
);}
|
||||||
|
#endif // __SSE4_1__
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<double,2> IfPos (SIMD<double,2> a, SIMD<double,2> b, SIMD<double,2> c)
|
||||||
|
{ return ngcore::SIMD<double,2>([&](int i)->double { return a[i]>0 ? b[i] : c[i]; }); }
|
||||||
|
NETGEN_INLINE SIMD<double,2> IfZero (SIMD<double,2> a, SIMD<double,2> b, SIMD<double,2> c)
|
||||||
|
{ return ngcore::SIMD<double,2>([&](int i)->double { return a[i]==0. ? b[i] : c[i]; }); }
|
||||||
|
|
||||||
|
|
||||||
|
NETGEN_INLINE double HSum (SIMD<double,2> sd)
|
||||||
|
{
|
||||||
|
return _mm_cvtsd_f64 (my_mm_hadd_pd (sd.Data(), sd.Data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE auto HSum (SIMD<double,2> sd1, SIMD<double,2> sd2)
|
||||||
|
{
|
||||||
|
__m128d hv2 = my_mm_hadd_pd(sd1.Data(), sd2.Data());
|
||||||
|
return SIMD<double,2> (hv2);
|
||||||
|
// return SIMD<double,2>(_mm_cvtsd_f64 (hv2), _mm_cvtsd_f64(_mm_shuffle_pd (hv2, hv2, 3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE SIMD<int64_t, 2> If(SIMD<mask64, 2> a, SIMD<int64_t, 2> b,
|
||||||
|
SIMD<int64_t, 2> c) {
|
||||||
|
return _mm_or_si128(
|
||||||
|
_mm_andnot_si128(a.Data(),c.Data()),
|
||||||
|
_mm_and_si128(b.Data(),a.Data())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // NETGEN_CORE_SIMD_SSE_HPP
|
@ -18,6 +18,19 @@ namespace ngcore
|
|||||||
size_t size = entrysize.Size();
|
size_t size = entrysize.Size();
|
||||||
size_t * index = new size_t[size+1];
|
size_t * index = new size_t[size+1];
|
||||||
|
|
||||||
|
if (entrysize.Size() < 100)
|
||||||
|
{
|
||||||
|
size_t mysum = 0;
|
||||||
|
for (size_t i = 0; i < entrysize.Size(); i++)
|
||||||
|
{
|
||||||
|
index[i] = mysum;
|
||||||
|
mysum += entrysize[i];
|
||||||
|
}
|
||||||
|
index[entrysize.Size()] = mysum;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Array<size_t> partial_sums(TaskManager::GetNumThreads()+1);
|
Array<size_t> partial_sums(TaskManager::GetNumThreads()+1);
|
||||||
partial_sums[0] = 0;
|
partial_sums[0] = 0;
|
||||||
ParallelJob
|
ParallelJob
|
||||||
@ -54,7 +67,7 @@ namespace ngcore
|
|||||||
NGCORE_API size_t * TablePrefixSum64 (FlatArray<size_t> entrysize)
|
NGCORE_API size_t * TablePrefixSum64 (FlatArray<size_t> entrysize)
|
||||||
{ return TablePrefixSum2 (entrysize); }
|
{ return TablePrefixSum2 (entrysize); }
|
||||||
|
|
||||||
|
/*
|
||||||
BaseDynamicTable :: BaseDynamicTable (int size)
|
BaseDynamicTable :: BaseDynamicTable (int size)
|
||||||
: data(size)
|
: data(size)
|
||||||
{
|
{
|
||||||
@ -88,7 +101,6 @@ namespace ngcore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BaseDynamicTable :: ~BaseDynamicTable ()
|
BaseDynamicTable :: ~BaseDynamicTable ()
|
||||||
{
|
{
|
||||||
if (oneblock)
|
if (oneblock)
|
||||||
@ -112,7 +124,7 @@ namespace ngcore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseDynamicTable :: IncSize (int i, int elsize)
|
void BaseDynamicTable :: IncSize (IndexType i, int elsize)
|
||||||
{
|
{
|
||||||
if (i < 0 || i >= data.Size())
|
if (i < 0 || i >= data.Size())
|
||||||
{
|
{
|
||||||
@ -135,7 +147,7 @@ namespace ngcore
|
|||||||
line.size++;
|
line.size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseDynamicTable :: DecSize (int i)
|
void BaseDynamicTable :: DecSize (IndexType i)
|
||||||
{
|
{
|
||||||
if (i < 0 || i >= data.Size())
|
if (i < 0 || i >= data.Size())
|
||||||
{
|
{
|
||||||
@ -153,6 +165,7 @@ namespace ngcore
|
|||||||
|
|
||||||
line.size--;
|
line.size--;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
void FilteredTableCreator::Add (size_t blocknr, int data)
|
void FilteredTableCreator::Add (size_t blocknr, int data)
|
||||||
{
|
{
|
||||||
|
@ -20,76 +20,76 @@ namespace ngcore
|
|||||||
|
|
||||||
|
|
||||||
template <class T, class IndexType = size_t>
|
template <class T, class IndexType = size_t>
|
||||||
class FlatTable
|
class FlatTable
|
||||||
{
|
|
||||||
protected:
|
|
||||||
static constexpr IndexType BASE = IndexBASE<IndexType>();
|
|
||||||
/// number of rows
|
|
||||||
size_t size;
|
|
||||||
/// pointer to first in row
|
|
||||||
size_t * index;
|
|
||||||
/// array of data
|
|
||||||
T * data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FlatTable() = delete;
|
|
||||||
|
|
||||||
NETGEN_INLINE FlatTable(size_t as, size_t * aindex, T * adata)
|
|
||||||
: size(as), index(aindex), data(adata) { ; }
|
|
||||||
|
|
||||||
/// Size of table
|
|
||||||
NETGEN_INLINE size_t Size() const { return size; }
|
|
||||||
|
|
||||||
/// Access entry
|
|
||||||
NETGEN_INLINE const FlatArray<T> operator[] (IndexType i) const
|
|
||||||
{
|
{
|
||||||
i = i-BASE;
|
protected:
|
||||||
return FlatArray<T> (index[i+1]-index[i], data+index[i]);
|
static constexpr IndexType BASE = IndexBASE<IndexType>();
|
||||||
}
|
/// number of rows
|
||||||
|
size_t size;
|
||||||
|
/// pointer to first in row
|
||||||
|
size_t * index;
|
||||||
|
/// array of data
|
||||||
|
T * data;
|
||||||
|
|
||||||
NETGEN_INLINE T * Data() const { return data; }
|
|
||||||
|
|
||||||
NETGEN_INLINE FlatArray<T> AsArray() const
|
|
||||||
{
|
|
||||||
return FlatArray<T> (index[size]-index[0], data+index[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
NETGEN_INLINE FlatArray<size_t> IndexArray() const
|
|
||||||
{
|
|
||||||
return FlatArray<size_t, IndexType> (size+1, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// takes range starting from position start of end-start elements
|
|
||||||
NETGEN_INLINE FlatTable<T> Range (size_t start, size_t end) const
|
|
||||||
{
|
|
||||||
return FlatTable<T> (end-start, index+start-BASE, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// takes range starting from position start of end-start elements
|
|
||||||
NETGEN_INLINE FlatTable<T> Range (T_Range<size_t> range) const
|
|
||||||
{
|
|
||||||
return FlatTable<T> (range.Size(), index+range.First()-BASE, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
NETGEN_INLINE T_Range<IndexType> Range () const
|
|
||||||
{
|
|
||||||
return T_Range<IndexType> (BASE, size+BASE);
|
|
||||||
}
|
|
||||||
|
|
||||||
class Iterator
|
|
||||||
{
|
|
||||||
const FlatTable & tab;
|
|
||||||
size_t row;
|
|
||||||
public:
|
public:
|
||||||
Iterator (const FlatTable & _tab, size_t _row) : tab(_tab), row(_row) { ; }
|
FlatTable() = delete;
|
||||||
Iterator & operator++ () { ++row; return *this; }
|
|
||||||
FlatArray<T> operator* () const { return tab[row]; }
|
|
||||||
bool operator!= (const Iterator & it2) { return row != it2.row; }
|
|
||||||
};
|
|
||||||
|
|
||||||
Iterator begin() const { return Iterator(*this, BASE); }
|
NETGEN_INLINE FlatTable(size_t as, size_t * aindex, T * adata)
|
||||||
Iterator end() const { return Iterator(*this, BASE+size); }
|
: size(as), index(aindex), data(adata) { ; }
|
||||||
};
|
|
||||||
|
/// Size of table
|
||||||
|
NETGEN_INLINE size_t Size() const { return size; }
|
||||||
|
|
||||||
|
/// Access entry
|
||||||
|
NETGEN_INLINE const FlatArray<T> operator[] (IndexType i) const
|
||||||
|
{
|
||||||
|
i = i-BASE;
|
||||||
|
return FlatArray<T> (index[i+1]-index[i], data+index[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE T * Data() const { return data; }
|
||||||
|
|
||||||
|
NETGEN_INLINE FlatArray<T> AsArray() const
|
||||||
|
{
|
||||||
|
return FlatArray<T> (index[size]-index[0], data+index[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE FlatArray<size_t> IndexArray() const
|
||||||
|
{
|
||||||
|
return FlatArray<size_t, IndexType> (size+1, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// takes range starting from position start of end-start elements
|
||||||
|
NETGEN_INLINE FlatTable<T> Range (size_t start, size_t end) const
|
||||||
|
{
|
||||||
|
return FlatTable<T> (end-start, index+start-BASE, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// takes range starting from position start of end-start elements
|
||||||
|
NETGEN_INLINE FlatTable<T> Range (T_Range<size_t> range) const
|
||||||
|
{
|
||||||
|
return FlatTable<T> (range.Size(), index+range.First()-BASE, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE T_Range<IndexType> Range () const
|
||||||
|
{
|
||||||
|
return T_Range<IndexType> (BASE, size+BASE);
|
||||||
|
}
|
||||||
|
|
||||||
|
class Iterator
|
||||||
|
{
|
||||||
|
const FlatTable & tab;
|
||||||
|
size_t row;
|
||||||
|
public:
|
||||||
|
Iterator (const FlatTable & _tab, size_t _row) : tab(_tab), row(_row) { ; }
|
||||||
|
Iterator & operator++ () { ++row; return *this; }
|
||||||
|
FlatArray<T> operator* () const { return tab[row]; }
|
||||||
|
bool operator!= (const Iterator & it2) { return row != it2.row; }
|
||||||
|
};
|
||||||
|
|
||||||
|
Iterator begin() const { return Iterator(*this, BASE); }
|
||||||
|
Iterator end() const { return Iterator(*this, BASE+size); }
|
||||||
|
};
|
||||||
|
|
||||||
NGCORE_API extern size_t * TablePrefixSum32 (FlatArray<unsigned int> entrysize);
|
NGCORE_API extern size_t * TablePrefixSum32 (FlatArray<unsigned int> entrysize);
|
||||||
NGCORE_API extern size_t * TablePrefixSum64 (FlatArray<size_t> entrysize);
|
NGCORE_API extern size_t * TablePrefixSum64 (FlatArray<size_t> entrysize);
|
||||||
@ -105,106 +105,119 @@ public:
|
|||||||
{ return TablePrefixSum64 (entrysize); }
|
{ return TablePrefixSum64 (entrysize); }
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A compact Table container.
|
A compact Table container.
|
||||||
A table contains size entries of variable size.
|
A table contains size entries of variable size.
|
||||||
The entry sizes must be known at construction.
|
The entry sizes must be known at construction.
|
||||||
*/
|
*/
|
||||||
template <class T, class IndexType = size_t>
|
template <class T, class IndexType = size_t>
|
||||||
class Table : public FlatTable<T, IndexType>
|
class Table : public FlatTable<T, IndexType>
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
using FlatTable<T,IndexType>::size;
|
|
||||||
using FlatTable<T,IndexType>::index;
|
|
||||||
using FlatTable<T,IndexType>::data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
///
|
|
||||||
NETGEN_INLINE Table () : FlatTable<T,IndexType> (0,nullptr,nullptr) { ; }
|
|
||||||
/// Construct table of uniform entrysize
|
|
||||||
NETGEN_INLINE Table (size_t asize, size_t entrysize)
|
|
||||||
: FlatTable<T,IndexType>( asize, new size_t[asize+1], new T[asize*entrysize] )
|
|
||||||
{
|
{
|
||||||
for (size_t i : IntRange(size+1))
|
protected:
|
||||||
index[i] = i*entrysize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct table of variable entrysize
|
using FlatTable<T,IndexType>::size;
|
||||||
template <typename TI>
|
using FlatTable<T,IndexType>::index;
|
||||||
NETGEN_INLINE Table (FlatArray<TI,IndexType> entrysize)
|
using FlatTable<T,IndexType>::data;
|
||||||
: FlatTable<T,IndexType> (0, nullptr, nullptr)
|
|
||||||
{
|
|
||||||
size = entrysize.Size();
|
|
||||||
index = TablePrefixSum (FlatArray<TI> (entrysize.Size(), entrysize.Data()));
|
|
||||||
size_t cnt = index[size];
|
|
||||||
data = new T[cnt];
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit NETGEN_INLINE Table (const Table & tab2)
|
public:
|
||||||
: FlatTable<T,IndexType>(0, nullptr, nullptr)
|
///
|
||||||
{
|
NETGEN_INLINE Table () : FlatTable<T,IndexType> (0,nullptr,nullptr) { ; }
|
||||||
size = tab2.Size();
|
/// Construct table of uniform entrysize
|
||||||
|
NETGEN_INLINE Table (size_t asize, size_t entrysize)
|
||||||
|
: FlatTable<T,IndexType>( asize, new size_t[asize+1], new T[asize*entrysize] )
|
||||||
|
{
|
||||||
|
for (size_t i : IntRange(size+1))
|
||||||
|
index[i] = i*entrysize;
|
||||||
|
}
|
||||||
|
|
||||||
index = new size_t[size+1];
|
/// Construct table of variable entrysize
|
||||||
for (size_t i = 0; i <= size; i++)
|
template <typename TI>
|
||||||
index[i] = tab2.index[i];
|
NETGEN_INLINE Table (FlatArray<TI,IndexType> entrysize)
|
||||||
|
: FlatTable<T,IndexType> (0, nullptr, nullptr)
|
||||||
|
{
|
||||||
|
size = entrysize.Size();
|
||||||
|
index = TablePrefixSum (FlatArray<TI> (entrysize.Size(), entrysize.Data()));
|
||||||
|
size_t cnt = index[size];
|
||||||
|
data = new T[cnt];
|
||||||
|
}
|
||||||
|
|
||||||
size_t cnt = index[size];
|
explicit NETGEN_INLINE Table (const Table & tab2)
|
||||||
data = new T[cnt];
|
: FlatTable<T,IndexType>(0, nullptr, nullptr)
|
||||||
for (size_t i = 0; i < cnt; i++)
|
{
|
||||||
data[i] = tab2.data[i];
|
size = tab2.Size();
|
||||||
}
|
|
||||||
|
|
||||||
NETGEN_INLINE Table (Table && tab2)
|
index = new size_t[size+1];
|
||||||
: FlatTable<T,IndexType>(0, nullptr, nullptr)
|
for (size_t i = 0; i <= size; i++)
|
||||||
{
|
index[i] = tab2.index[i];
|
||||||
Swap (size, tab2.size);
|
|
||||||
Swap (index, tab2.index);
|
|
||||||
Swap (data, tab2.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
NETGEN_INLINE Table & operator= (Table && tab2)
|
size_t cnt = index[size];
|
||||||
{
|
data = new T[cnt];
|
||||||
Swap (size, tab2.size);
|
for (size_t i = 0; i < cnt; i++)
|
||||||
Swap (index, tab2.index);
|
data[i] = tab2.data[i];
|
||||||
Swap (data, tab2.data);
|
}
|
||||||
return *this;
|
|
||||||
}
|
NETGEN_INLINE Table (Table && tab2)
|
||||||
|
: FlatTable<T,IndexType>(0, nullptr, nullptr)
|
||||||
|
{
|
||||||
|
tab2.mt.Free(tab2.GetMemUsage());
|
||||||
|
Swap (size, tab2.size);
|
||||||
|
Swap (index, tab2.index);
|
||||||
|
Swap (data, tab2.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
NETGEN_INLINE Table & operator= (Table && tab2)
|
||||||
|
{
|
||||||
|
mt.Swap(GetMemUsage(), tab2.mt, tab2.GetMemUsage());
|
||||||
|
Swap (size, tab2.size);
|
||||||
|
Swap (index, tab2.index);
|
||||||
|
Swap (data, tab2.data);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Delete data
|
/// Delete data
|
||||||
NETGEN_INLINE ~Table ()
|
NETGEN_INLINE ~Table ()
|
||||||
{
|
{
|
||||||
delete [] data;
|
mt.Free(GetMemUsage());
|
||||||
delete [] index;
|
delete [] data;
|
||||||
}
|
delete [] index;
|
||||||
|
}
|
||||||
|
|
||||||
/// Size of table
|
/// Size of table
|
||||||
using FlatTable<T,IndexType>::Size;
|
using FlatTable<T,IndexType>::Size;
|
||||||
|
|
||||||
/// number of elements in all rows
|
/// number of elements in all rows
|
||||||
NETGEN_INLINE size_t NElements() const { return index[size]; }
|
NETGEN_INLINE size_t NElements() const { return index[size]; }
|
||||||
|
|
||||||
using FlatTable<T,IndexType>::operator[];
|
using FlatTable<T,IndexType>::operator[];
|
||||||
};
|
|
||||||
|
NETGEN_INLINE void StartMemoryTracing (int /* mem_id */)
|
||||||
|
{
|
||||||
|
mt.Alloc(GetMemUsage());
|
||||||
|
}
|
||||||
|
const MemoryTracer& GetMemoryTracer() const { return mt; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t GetMemUsage() const { return size == 0 ? 0 : sizeof(T)*index[size] + sizeof(IndexType) * size+1; }
|
||||||
|
MemoryTracer mt;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Print table
|
/// Print table
|
||||||
template <class T, typename IndexType>
|
template <class T, typename IndexType>
|
||||||
inline ostream & operator<< (ostream & s, const Table<T,IndexType> & table)
|
inline ostream & operator<< (ostream & s, const Table<T,IndexType> & table)
|
||||||
{
|
{
|
||||||
for (auto i : table.Range())
|
for (auto i : table.Range())
|
||||||
{
|
{
|
||||||
s << i << ":";
|
s << i << ":";
|
||||||
for (auto el : table[i])
|
for (auto el : table[i])
|
||||||
s << " " << el;
|
s << " " << el;
|
||||||
s << "\n";
|
s << "\n";
|
||||||
}
|
}
|
||||||
s << std::flush;
|
s << std::flush;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -349,142 +362,262 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/// Base class to generic DynamicTable.
|
|
||||||
class BaseDynamicTable
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
|
|
||||||
///
|
|
||||||
struct linestruct
|
|
||||||
{
|
|
||||||
///
|
|
||||||
int size;
|
|
||||||
///
|
|
||||||
int maxsize;
|
|
||||||
///
|
|
||||||
void * col;
|
|
||||||
};
|
|
||||||
|
|
||||||
///
|
|
||||||
Array<linestruct> data;
|
|
||||||
///
|
|
||||||
char * oneblock;
|
|
||||||
|
|
||||||
public:
|
|
||||||
///
|
|
||||||
NGCORE_API BaseDynamicTable (int size);
|
|
||||||
///
|
|
||||||
NGCORE_API BaseDynamicTable (const Array<int> & entrysizes, int elemsize);
|
|
||||||
///
|
|
||||||
NGCORE_API ~BaseDynamicTable ();
|
|
||||||
|
|
||||||
/// Changes Size of table to size, deletes data
|
|
||||||
NGCORE_API void SetSize (int size);
|
|
||||||
///
|
|
||||||
NGCORE_API void IncSize (int i, int elsize);
|
|
||||||
|
|
||||||
NGCORE_API void DecSize (int i);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A dynamic table class.
|
A dynamic table class.
|
||||||
|
|
||||||
A DynamicTable contains entries of variable size. Entry sizes can
|
A DynamicTable contains entries of variable size. Entry sizes can
|
||||||
be increased dynamically.
|
be increased dynamically.
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T, class IndexType = size_t>
|
||||||
class DynamicTable : public BaseDynamicTable
|
class DynamicTable
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
static constexpr IndexType BASE = IndexBASE<IndexType>();
|
||||||
|
|
||||||
|
struct linestruct
|
||||||
|
{
|
||||||
|
int size;
|
||||||
|
int maxsize;
|
||||||
|
T * col;
|
||||||
|
};
|
||||||
|
|
||||||
|
Array<linestruct, IndexType> data;
|
||||||
|
T * oneblock = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Creates table of size size
|
/// Creates table of size size
|
||||||
DynamicTable (int size = 0)
|
DynamicTable (int size = 0)
|
||||||
: BaseDynamicTable (size) { ; }
|
: data(size)
|
||||||
|
|
||||||
/// Creates table with a priori fixed entry sizes.
|
|
||||||
DynamicTable (const Array<int> & entrysizes)
|
|
||||||
: BaseDynamicTable (entrysizes, sizeof(T)) { ; }
|
|
||||||
|
|
||||||
/// Inserts element acont into row i. Does not test if already used.
|
|
||||||
void Add (int i, const T & acont)
|
|
||||||
{
|
{
|
||||||
if (data[i].size == data[i].maxsize)
|
for (auto & d : data)
|
||||||
IncSize (i, sizeof (T));
|
{
|
||||||
else
|
d.maxsize = 0;
|
||||||
data[i].size++;
|
d.size = 0;
|
||||||
static_cast<T*> (data[i].col) [data[i].size-1] = acont;
|
d.col = nullptr;
|
||||||
|
}
|
||||||
|
oneblock = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates table with a priori fixed entry sizes.
|
||||||
|
DynamicTable (const Array<int, IndexType> & entrysizes)
|
||||||
|
: data(entrysizes.Size())
|
||||||
|
{
|
||||||
|
size_t cnt = 0;
|
||||||
|
// size_t n = entrysizes.Size();
|
||||||
|
|
||||||
|
for (auto es : entrysizes)
|
||||||
|
cnt += es;
|
||||||
|
oneblock = new T[cnt];
|
||||||
|
|
||||||
|
cnt = 0;
|
||||||
|
for (auto i : data.Range())
|
||||||
|
{
|
||||||
|
data[i].maxsize = entrysizes[i];
|
||||||
|
data[i].size = 0;
|
||||||
|
data[i].col = &oneblock[cnt];
|
||||||
|
cnt += entrysizes[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicTable (DynamicTable && tab2)
|
||||||
|
{
|
||||||
|
Swap (data, tab2.data);
|
||||||
|
Swap (oneblock, tab2.oneblock);
|
||||||
|
}
|
||||||
|
|
||||||
|
~DynamicTable ()
|
||||||
|
{
|
||||||
|
if (oneblock)
|
||||||
|
delete [] oneblock;
|
||||||
|
else
|
||||||
|
for (auto & d : data)
|
||||||
|
delete [] d.col;
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicTable & operator= (DynamicTable && tab2)
|
||||||
|
{
|
||||||
|
Swap (data, tab2.data);
|
||||||
|
Swap (oneblock, tab2.oneblock);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Changes Size of table to size, deletes data
|
||||||
|
void SetSize (int size)
|
||||||
|
{
|
||||||
|
for (auto & d : data)
|
||||||
|
delete [] d.col;
|
||||||
|
|
||||||
|
data.SetSize(size);
|
||||||
|
for (auto & d : data)
|
||||||
|
{
|
||||||
|
d.maxsize = 0;
|
||||||
|
d.size = 0;
|
||||||
|
d.col = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChangeSize (size_t size)
|
||||||
|
{
|
||||||
|
if (oneblock)
|
||||||
|
throw Exception ("cannot change size of oneblock dynamic table");
|
||||||
|
|
||||||
|
size_t oldsize = data.Size();
|
||||||
|
if (size == oldsize)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (size < oldsize)
|
||||||
|
for (int i = size; i < oldsize; i++)
|
||||||
|
delete [] data[i+BASE].col;
|
||||||
|
|
||||||
|
data.SetSize(size);
|
||||||
|
|
||||||
|
for (int i = oldsize; i < size; i++)
|
||||||
|
{
|
||||||
|
data[i+BASE].maxsize = 0;
|
||||||
|
data[i+BASE].size = 0;
|
||||||
|
data[i+BASE].col = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///
|
||||||
|
void IncSize (IndexType i)
|
||||||
|
{
|
||||||
|
NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE);
|
||||||
|
|
||||||
|
linestruct & line = data[i];
|
||||||
|
|
||||||
|
if (line.size == line.maxsize)
|
||||||
|
{
|
||||||
|
T * p;
|
||||||
|
if constexpr (std::is_default_constructible<T>::value)
|
||||||
|
p = new T[(2*line.maxsize+5)];
|
||||||
|
else
|
||||||
|
p = reinterpret_cast<T*>(new char[(2*line.maxsize+5)*sizeof(T)]);
|
||||||
|
for (size_t i = 0; i < line.maxsize; i++)
|
||||||
|
p[i] = std::move(line.col[i]);
|
||||||
|
// memcpy (p, line.col, line.maxsize * sizeof(T));
|
||||||
|
delete [] line.col;
|
||||||
|
line.col = p;
|
||||||
|
line.maxsize = 2*line.maxsize+5;
|
||||||
|
}
|
||||||
|
|
||||||
|
line.size++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DecSize (IndexType i)
|
||||||
|
{
|
||||||
|
NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE);
|
||||||
|
linestruct & line = data[i];
|
||||||
|
|
||||||
|
#ifdef NETGEN_ENABLE_CHECK_RANGE
|
||||||
|
if (line.size == 0)
|
||||||
|
throw Exception ("BaseDynamicTable::Dec: EntrySize < 0");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
line.size--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Inserts element acont into row i. Does not test if already used.
|
||||||
|
void Add (IndexType i, const T & acont)
|
||||||
|
{
|
||||||
|
if (data[i].size == data[i].maxsize)
|
||||||
|
this->IncSize (i);
|
||||||
|
else
|
||||||
|
data[i].size++;
|
||||||
|
data[i].col[data[i].size-1] = acont;
|
||||||
|
}
|
||||||
|
|
||||||
/// Inserts element acont into row i, iff not yet exists.
|
/// Inserts element acont into row i, iff not yet exists.
|
||||||
void AddUnique (int i, const T & cont)
|
void AddUnique (IndexType i, const T & cont)
|
||||||
{
|
{
|
||||||
int es = EntrySize (i);
|
int es = EntrySize (i);
|
||||||
int * line = const_cast<int*> (GetLine (i));
|
T * line = data[i].col;
|
||||||
for (int j = 0; j < es; j++)
|
for (int j = 0; j < es; j++)
|
||||||
if (line[j] == cont)
|
if (line[j] == cont)
|
||||||
return;
|
return;
|
||||||
Add (i, cont);
|
Add (i, cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Inserts element acont into row i. Does not test if already used.
|
/// Inserts element acont into row i. Does not test if already used.
|
||||||
void AddEmpty (int i)
|
void AddEmpty (IndexType i)
|
||||||
{
|
{
|
||||||
IncSize (i, sizeof (T));
|
IncSize (i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Set the nr-th element in the i-th row to acont.
|
/** Set the nr-th element in the i-th row to acont.
|
||||||
Does not check for overflow. */
|
Does not check for overflow. */
|
||||||
void Set (int i, int nr, const T & acont)
|
void Set (IndexType i, int nr, const T & acont)
|
||||||
{ static_cast<T*> (data[i].col)[nr] = acont; }
|
{
|
||||||
|
data[i].col[nr] = acont;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns the nr-th element in the i-th row.
|
/** Returns the nr-th element in the i-th row.
|
||||||
Does not check for overflow. */
|
Does not check for overflow. */
|
||||||
const T & Get (int i, int nr) const
|
const T & Get (IndexType i, int nr) const
|
||||||
{ return static_cast<T*> (data[i].col)[nr]; }
|
{
|
||||||
|
return data[i].col[nr];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns pointer to the first element in row i. */
|
/** Returns pointer to the first element in row i. */
|
||||||
const T * GetLine (int i) const
|
const T * GetLine (IndexType i) const
|
||||||
{ return static_cast<T*> (data[i].col); }
|
{
|
||||||
|
return data[i].col;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns size of the table.
|
/// Returns size of the table.
|
||||||
int Size () const
|
size_t Size () const
|
||||||
{ return data.Size(); }
|
{
|
||||||
|
return data.Size();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Range () const
|
||||||
|
{
|
||||||
|
return data.Range();
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns size of the i-th row.
|
/// Returns size of the i-th row.
|
||||||
int EntrySize (int i) const
|
int EntrySize (IndexType i) const
|
||||||
{ return data[i].size; }
|
{
|
||||||
|
return data[i].size;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
void DecEntrySize (int i)
|
void DecEntrySize (IndexType i)
|
||||||
{ DecSize(i); }
|
{
|
||||||
|
DecSize(i);
|
||||||
|
}
|
||||||
|
|
||||||
/// Access entry i
|
/// Access entry i
|
||||||
FlatArray<T> operator[] (int i)
|
FlatArray<T> operator[] (IndexType i)
|
||||||
{ return FlatArray<T> (data[i].size, static_cast<T*> (data[i].col)); }
|
{
|
||||||
|
return FlatArray<T> (data[i].size, data[i].col);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
typedef const FlatArray<T> ConstFlatArray;
|
typedef const FlatArray<T> ConstFlatArray;
|
||||||
/// Access entry i
|
/// Access entry i
|
||||||
ConstFlatArray operator[] (int i) const
|
ConstFlatArray operator[] (int i) const
|
||||||
{ return FlatArray<T> (data[i].size, static_cast<T*> (data[i].col)); }
|
{ return FlatArray<T> (data[i].size, static_cast<T*> (data[i].col)); }
|
||||||
*/
|
*/
|
||||||
FlatArray<T> operator[] (int i) const
|
FlatArray<T> operator[] (IndexType i) const
|
||||||
{ return FlatArray<T> (data[i].size, static_cast<T*> (data[i].col)); }
|
{
|
||||||
|
return FlatArray<T> (data[i].size, data[i].col);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Print table
|
/// Print table
|
||||||
template <class T>
|
template <class T>
|
||||||
inline ostream & operator<< (ostream & s, const DynamicTable<T> & table)
|
inline ostream & operator<< (ostream & s, const DynamicTable<T> & table)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < table.Size(); i++)
|
for (auto i : Range(table))
|
||||||
{
|
{
|
||||||
s << i << ":";
|
s << i << ":";
|
||||||
for (int j = 0; j < table[i].Size(); j++)
|
for (int j = 0; j < table[i].Size(); j++)
|
||||||
|
@ -159,29 +159,18 @@ namespace ngcore
|
|||||||
active_workers = 0;
|
active_workers = 0;
|
||||||
|
|
||||||
static int cnt = 0;
|
static int cnt = 0;
|
||||||
char buf[100];
|
|
||||||
if (use_paje_trace)
|
if (use_paje_trace)
|
||||||
{
|
trace = new PajeTrace(num_threads, "ng" + ToString(cnt++));
|
||||||
#ifdef PARALLEL
|
|
||||||
int is_init = -1;
|
|
||||||
MPI_Initialized(&is_init);
|
|
||||||
if (is_init)
|
|
||||||
sprintf(buf, "ng%d_rank%d.trace", cnt++, NgMPI_Comm(MPI_COMM_WORLD).Rank());
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
sprintf(buf, "ng%d.trace", cnt++);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
buf[0] = 0;
|
|
||||||
//sprintf(buf, "");
|
|
||||||
trace = new PajeTrace(num_threads, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TaskManager :: ~TaskManager ()
|
TaskManager :: ~TaskManager ()
|
||||||
{
|
{
|
||||||
delete trace;
|
if (use_paje_trace)
|
||||||
trace = nullptr;
|
{
|
||||||
|
delete trace;
|
||||||
|
trace = nullptr;
|
||||||
|
}
|
||||||
num_threads = 1;
|
num_threads = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,14 +201,14 @@ namespace ngcore
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t calibrate_init_tsc = __rdtsc();
|
static size_t calibrate_init_tsc = GetTimeCounter();
|
||||||
typedef std::chrono::system_clock TClock;
|
typedef std::chrono::system_clock TClock;
|
||||||
static TClock::time_point calibrate_init_clock = TClock::now();
|
static TClock::time_point calibrate_init_clock = TClock::now();
|
||||||
|
|
||||||
void TaskManager :: StopWorkers()
|
void TaskManager :: StopWorkers()
|
||||||
{
|
{
|
||||||
done = true;
|
done = true;
|
||||||
double delta_tsc = __rdtsc()-calibrate_init_tsc;
|
double delta_tsc = GetTimeCounter()-calibrate_init_tsc;
|
||||||
double delta_sec = std::chrono::duration<double>(TClock::now()-calibrate_init_clock).count();
|
double delta_sec = std::chrono::duration<double>(TClock::now()-calibrate_init_clock).count();
|
||||||
double frequ = (delta_sec != 0) ? delta_tsc/delta_sec : 2.7e9;
|
double frequ = (delta_sec != 0) ? delta_tsc/delta_sec : 2.7e9;
|
||||||
|
|
||||||
@ -348,8 +337,28 @@ namespace ngcore
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (antasks == 1)
|
||||||
|
{
|
||||||
|
if (trace)
|
||||||
|
trace->StartJob(jobnr, afunc.target_type());
|
||||||
|
jobnr++;
|
||||||
|
if (startup_function) (*startup_function)();
|
||||||
|
TaskInfo ti;
|
||||||
|
ti.task_nr = 0;
|
||||||
|
ti.ntasks = 1;
|
||||||
|
ti.thread_nr = 0; ti.nthreads = 1;
|
||||||
|
{
|
||||||
|
RegionTracer t(ti.thread_nr, jobnr, RegionTracer::ID_JOB, ti.task_nr);
|
||||||
|
afunc(ti);
|
||||||
|
}
|
||||||
|
if (cleanup_function) (*cleanup_function)();
|
||||||
|
if (trace)
|
||||||
|
trace->StopJob();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
trace->StartJob(jobnr, afunc.target_type());
|
if (trace)
|
||||||
|
trace->StartJob(jobnr, afunc.target_type());
|
||||||
|
|
||||||
func = &afunc;
|
func = &afunc;
|
||||||
|
|
||||||
@ -412,14 +421,19 @@ namespace ngcore
|
|||||||
if (workers_on_node[j])
|
if (workers_on_node[j])
|
||||||
{
|
{
|
||||||
while (complete[j] != jobnr)
|
while (complete[j] != jobnr)
|
||||||
|
{
|
||||||
|
#ifdef NETGEN_ARCH_AMD64
|
||||||
_mm_pause();
|
_mm_pause();
|
||||||
|
#endif // NETGEN_ARCH_AMD64
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func = nullptr;
|
func = nullptr;
|
||||||
if (ex)
|
if (ex)
|
||||||
throw Exception (*ex);
|
throw Exception (*ex);
|
||||||
|
|
||||||
trace->StopJob();
|
if (trace)
|
||||||
|
trace->StopJob();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskManager :: Loop(int thd)
|
void TaskManager :: Loop(int thd)
|
||||||
|
@ -17,6 +17,12 @@
|
|||||||
#include "paje_trace.hpp"
|
#include "paje_trace.hpp"
|
||||||
#include "profiler.hpp"
|
#include "profiler.hpp"
|
||||||
|
|
||||||
|
#ifdef USE_NUMA
|
||||||
|
#include <numa.h>
|
||||||
|
#include <sched.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace ngcore
|
namespace ngcore
|
||||||
{
|
{
|
||||||
using std::atomic;
|
using std::atomic;
|
||||||
@ -1062,11 +1068,11 @@ public:
|
|||||||
{
|
{
|
||||||
static Timer timer("ComputeColoring - "+Demangle(typeid(Tmask).name())); RegionTimer rt(timer);
|
static Timer timer("ComputeColoring - "+Demangle(typeid(Tmask).name())); RegionTimer rt(timer);
|
||||||
static_assert(sizeof(unsigned int)==4, "Adapt type of mask array");
|
static_assert(sizeof(unsigned int)==4, "Adapt type of mask array");
|
||||||
auto n = colors.Size();
|
size_t n = colors.Size();
|
||||||
|
|
||||||
Array<unsigned int> mask(ndofs);
|
Array<unsigned int> mask(ndofs);
|
||||||
|
|
||||||
int colored_blocks = 0;
|
size_t colored_blocks = 0;
|
||||||
|
|
||||||
// We are coloring with 32 colors at once and use each bit to mask conflicts
|
// We are coloring with 32 colors at once and use each bit to mask conflicts
|
||||||
unsigned int check = 0;
|
unsigned int check = 0;
|
||||||
|
@ -13,7 +13,15 @@ namespace ngcore
|
|||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
// windows does demangling in typeid(T).name()
|
// windows does demangling in typeid(T).name()
|
||||||
NGCORE_API std::string Demangle(const char* typeinfo) { return typeinfo; }
|
NGCORE_API std::string Demangle(const char* typeinfo) {
|
||||||
|
std::string name = typeinfo;
|
||||||
|
// remove "class " and "struct " at beginning of type names to be consistent with demangled names of gcc/clang
|
||||||
|
if(name.find("class ") == 0)
|
||||||
|
name.erase(0,6);
|
||||||
|
if(name.find("struct ") == 0)
|
||||||
|
name.erase(0,7);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
NGCORE_API std::string Demangle(const char* typeinfo)
|
NGCORE_API std::string Demangle(const char* typeinfo)
|
||||||
{
|
{
|
||||||
|
@ -8,13 +8,19 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "ngcore_api.hpp" // for NGCORE_API and CPU arch macros
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && defined(NETGEN_ARCH_ARM64)
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef NETGEN_ARCH_AMD64
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <intrin.h> // for __rdtsc() CPU time step counter
|
#include <intrin.h> // for __rdtsc() CPU time step counter
|
||||||
#else
|
#else
|
||||||
#include <x86intrin.h> // for __rdtsc() CPU time step counter
|
#include <x86intrin.h> // for __rdtsc() CPU time step counter
|
||||||
#endif // WIN32
|
#endif // WIN32
|
||||||
|
#endif // NETGEN_ARCH_AMD64
|
||||||
#include "ngcore_api.hpp" // for NGCORE_API
|
|
||||||
|
|
||||||
namespace ngcore
|
namespace ngcore
|
||||||
{
|
{
|
||||||
@ -23,6 +29,10 @@ namespace ngcore
|
|||||||
|
|
||||||
NGCORE_API std::string Demangle(const char* typeinfo);
|
NGCORE_API std::string Demangle(const char* typeinfo);
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
std::string GetName(const T& obj)
|
||||||
|
{ return Demangle(typeid(obj).name()); }
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
inline bool likely (bool x) { return bool(__builtin_expect(long(x), 1L)); }
|
inline bool likely (bool x) { return bool(__builtin_expect(long(x), 1L)); }
|
||||||
inline bool unlikely (bool x) { return bool(__builtin_expect(long(x), 0L)); }
|
inline bool unlikely (bool x) { return bool(__builtin_expect(long(x), 0L)); }
|
||||||
@ -48,7 +58,19 @@ namespace ngcore
|
|||||||
|
|
||||||
inline TTimePoint GetTimeCounter() noexcept
|
inline TTimePoint GetTimeCounter() noexcept
|
||||||
{
|
{
|
||||||
return TTimePoint(__rdtsc());
|
#if defined(__APPLE__) && defined(NETGEN_ARCH_ARM64)
|
||||||
|
return mach_absolute_time();
|
||||||
|
#elif defined(NETGEN_ARCH_AMD64)
|
||||||
|
return __rdtsc();
|
||||||
|
#elif defined(NETGEN_ARCH_ARM64) && defined(__GNUC__)
|
||||||
|
// __GNUC__ is also defined by CLANG. Use inline asm to read Generic Timer
|
||||||
|
unsigned long long tics;
|
||||||
|
__asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (tics));
|
||||||
|
return tics;
|
||||||
|
#else
|
||||||
|
#warning "Unsupported CPU architecture"
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@ -157,7 +179,9 @@ namespace ngcore
|
|||||||
while (!m.compare_exchange_weak(should, true))
|
while (!m.compare_exchange_weak(should, true))
|
||||||
{
|
{
|
||||||
should = false;
|
should = false;
|
||||||
|
#ifdef NETGEN_ARCH_AMD64
|
||||||
_mm_pause();
|
_mm_pause();
|
||||||
|
#endif // NETGEN_ARCH_AMD64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void unlock()
|
void unlock()
|
||||||
|
29
libsrc/core/version.cpp
Normal file
29
libsrc/core/version.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <netgen_version.hpp>
|
||||||
|
#include "exception.hpp"
|
||||||
|
#include "version.hpp"
|
||||||
|
|
||||||
|
namespace ngcore
|
||||||
|
{
|
||||||
|
// clang-tidy should ignore this static object
|
||||||
|
static std::map<std::string, VersionInfo> library_versions; // NOLINT
|
||||||
|
|
||||||
|
const VersionInfo& GetLibraryVersion(const std::string& library)
|
||||||
|
{ return library_versions[library]; }
|
||||||
|
|
||||||
|
const std::map<std::string, VersionInfo>& GetLibraryVersions()
|
||||||
|
{ return library_versions; }
|
||||||
|
|
||||||
|
void SetLibraryVersion(const std::string& library, const VersionInfo& version)
|
||||||
|
{
|
||||||
|
if(library_versions.count(library) && (library_versions[library] != version))
|
||||||
|
throw Exception("Failed to set library version for " + library + " to " + version.to_string() + ": version already set to " + library_versions[library].to_string());
|
||||||
|
library_versions[library] = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool dummy = [](){
|
||||||
|
SetLibraryVersion("netgen", NETGEN_VERSION);
|
||||||
|
return true;
|
||||||
|
}();
|
||||||
|
} // namespace ngcore
|
@ -80,6 +80,10 @@ namespace ngcore
|
|||||||
return mayor_ == other.mayor_ && minor_ == other.minor_ && release == other.release
|
return mayor_ == other.mayor_ && minor_ == other.minor_ && release == other.release
|
||||||
&& patch == other.patch;
|
&& patch == other.patch;
|
||||||
}
|
}
|
||||||
|
bool operator !=(const VersionInfo& other) const
|
||||||
|
{
|
||||||
|
return !(*this==other);
|
||||||
|
}
|
||||||
bool operator >(const VersionInfo& other) const { return other < (*this); }
|
bool operator >(const VersionInfo& other) const { return other < (*this); }
|
||||||
bool operator <=(const VersionInfo& other) const { return !((*this) > other); }
|
bool operator <=(const VersionInfo& other) const { return !((*this) > other); }
|
||||||
bool operator >=(const VersionInfo& other) const { return !((*this) < other); }
|
bool operator >=(const VersionInfo& other) const { return !((*this) < other); }
|
||||||
@ -89,6 +93,10 @@ namespace ngcore
|
|||||||
{
|
{
|
||||||
return ost << version.to_string();
|
return ost << version.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NGCORE_API const VersionInfo& GetLibraryVersion(const std::string& library);
|
||||||
|
NGCORE_API const std::map<std::string, VersionInfo>& GetLibraryVersions();
|
||||||
|
NGCORE_API void SetLibraryVersion(const std::string& library, const VersionInfo& version);
|
||||||
} // namespace ngcore
|
} // namespace ngcore
|
||||||
|
|
||||||
#endif // NETGEN_CORE_VERSION_HPP
|
#endif // NETGEN_CORE_VERSION_HPP
|
||||||
|
@ -20,17 +20,27 @@ namespace ngcore
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
xbool (bool b) : state(b ? 2 : 0) { ; }
|
xbool (bool b) : state(b ? 2 : 0) { ; }
|
||||||
xbool (TMAYBE x) : state(1) { ; }
|
xbool (TMAYBE /* x */) : state(1) { ; }
|
||||||
xbool () = default;
|
xbool () = default;
|
||||||
xbool (const xbool &) = default;
|
xbool (const xbool &) = default;
|
||||||
|
|
||||||
xbool & operator= (bool b) { state = b ? 2 : 0; return *this; }
|
xbool & operator= (bool b) { state = b ? 2 : 0; return *this; }
|
||||||
xbool & operator= (TMAYBE x) { state = 1; return *this; }
|
xbool & operator= (TMAYBE /* x */) { state = 1; return *this; }
|
||||||
|
|
||||||
bool IsTrue () const { return state == 2; }
|
bool IsTrue () const { return state == 2; }
|
||||||
bool IsMaybe () const { return state == 1; }
|
bool IsMaybe () const { return state == 1; }
|
||||||
bool IsFalse () const { return state == 0; }
|
bool IsFalse () const { return state == 0; }
|
||||||
|
bool IsMaybeTrue() const { return state >= 1; }
|
||||||
|
bool IsMaybeFalse() const { return state <= 1; }
|
||||||
|
friend ostream & operator<< (ostream & ost, xbool xb);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static char output[] = "0?1";
|
||||||
|
inline ostream & operator<< (ostream & ost, xbool xb)
|
||||||
|
{
|
||||||
|
return ost << output[xb.state];
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ngcore
|
} // namespace ngcore
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ if(APPLE)
|
|||||||
set_target_properties( csg PROPERTIES SUFFIX ".so")
|
set_target_properties( csg PROPERTIES SUFFIX ".so")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
target_link_libraries(csg PUBLIC mesh PRIVATE netgen_python)
|
target_link_libraries(csg PUBLIC mesh PRIVATE "$<BUILD_INTERFACE:netgen_python>")
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
install( TARGETS csg ${NG_INSTALL_DIR})
|
install( TARGETS csg ${NG_INSTALL_DIR})
|
||||||
endif(NOT WIN32)
|
endif(NOT WIN32)
|
||||||
@ -20,7 +20,7 @@ target_link_libraries(csg PUBLIC ngcore)
|
|||||||
|
|
||||||
if(USE_GUI)
|
if(USE_GUI)
|
||||||
add_library(csgvis ${NG_LIB_TYPE} vscsg.cpp )
|
add_library(csgvis ${NG_LIB_TYPE} vscsg.cpp )
|
||||||
target_link_libraries(csgvis PRIVATE netgen_python PUBLIC ngcore)
|
target_link_libraries(csgvis PRIVATE "$<BUILD_INTERFACE:netgen_python>" PUBLIC ngcore)
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
target_link_libraries(csgvis PUBLIC csg visual)
|
target_link_libraries(csgvis PUBLIC csg visual)
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
|
@ -130,6 +130,7 @@ namespace netgen
|
|||||||
Point<3> & newp, EdgePointGeomInfo & newgi) const
|
Point<3> & newp, EdgePointGeomInfo & newgi) const
|
||||||
{
|
{
|
||||||
Point<3> hnewp = p1+secpoint*(p2-p1);
|
Point<3> hnewp = p1+secpoint*(p2-p1);
|
||||||
|
|
||||||
//(*testout) << "hnewp " << hnewp << " s1 " << surfi1 << " s2 " << surfi2 << endl;
|
//(*testout) << "hnewp " << hnewp << " s1 " << surfi1 << " s2 " << surfi2 << endl;
|
||||||
if (surfi1 != -1 && surfi2 != -1 && surfi1 != surfi2)
|
if (surfi1 != -1 && surfi2 != -1 && surfi1 != surfi2)
|
||||||
{
|
{
|
||||||
@ -175,9 +176,8 @@ namespace netgen
|
|||||||
|
|
||||||
solids.DeleteAll ();
|
solids.DeleteAll ();
|
||||||
|
|
||||||
for (int i = 0; i < splinecurves2d.Size(); i++)
|
|
||||||
delete splinecurves2d[i];
|
|
||||||
splinecurves2d.DeleteAll();
|
splinecurves2d.DeleteAll();
|
||||||
|
splinecurves3d.DeleteAll();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
for (int i = 0; i < surfaces.Size(); i++)
|
for (int i = 0; i < surfaces.Size(); i++)
|
||||||
@ -711,24 +711,24 @@ namespace netgen
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void CSGeometry :: SetSplineCurve (const char * name, SplineGeometry<2> * spl)
|
void CSGeometry :: SetSplineCurve (const char * name, shared_ptr<SplineGeometry<2>> spl)
|
||||||
{
|
{
|
||||||
splinecurves2d.Set(name,spl);
|
splinecurves2d.Set(name,spl);
|
||||||
}
|
}
|
||||||
void CSGeometry :: SetSplineCurve (const char * name, SplineGeometry<3> * spl)
|
void CSGeometry :: SetSplineCurve (const char * name, shared_ptr<SplineGeometry<3>> spl)
|
||||||
{
|
{
|
||||||
splinecurves3d.Set(name,spl);
|
splinecurves3d.Set(name,spl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const SplineGeometry<2> * CSGeometry :: GetSplineCurve2d (const string & name) const
|
shared_ptr<SplineGeometry<2>> CSGeometry :: GetSplineCurve2d (const string & name) const
|
||||||
{
|
{
|
||||||
if (splinecurves2d.Used(name))
|
if (splinecurves2d.Used(name))
|
||||||
return splinecurves2d[name];
|
return splinecurves2d[name];
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
const SplineGeometry<3> * CSGeometry :: GetSplineCurve3d (const string & name) const
|
shared_ptr<SplineGeometry<3>> CSGeometry :: GetSplineCurve3d (const string & name) const
|
||||||
{
|
{
|
||||||
if (splinecurves3d.Used(name))
|
if (splinecurves3d.Used(name))
|
||||||
return splinecurves3d[name];
|
return splinecurves3d[name];
|
||||||
|
@ -115,9 +115,9 @@ namespace netgen
|
|||||||
SymbolTable<Solid*> solids;
|
SymbolTable<Solid*> solids;
|
||||||
|
|
||||||
/// all 2d splinecurves
|
/// all 2d splinecurves
|
||||||
SymbolTable< SplineGeometry<2>* > splinecurves2d;
|
SymbolTable<shared_ptr<SplineGeometry<2>>> splinecurves2d;
|
||||||
/// all 3d splinecurves
|
/// all 3d splinecurves
|
||||||
SymbolTable< SplineGeometry<3>* > splinecurves3d;
|
SymbolTable<shared_ptr<SplineGeometry<3>>> splinecurves3d;
|
||||||
|
|
||||||
/// all top level objects: solids and surfaces
|
/// all top level objects: solids and surfaces
|
||||||
NgArray<TopLevelObject*> toplevelobjects;
|
NgArray<TopLevelObject*> toplevelobjects;
|
||||||
@ -232,10 +232,10 @@ namespace netgen
|
|||||||
const SymbolTable<Solid*> & GetSolids () const { return solids; }
|
const SymbolTable<Solid*> & GetSolids () const { return solids; }
|
||||||
|
|
||||||
|
|
||||||
void SetSplineCurve (const char * name, SplineGeometry<2> * spl);
|
void SetSplineCurve (const char * name, shared_ptr<SplineGeometry<2>> spl);
|
||||||
void SetSplineCurve (const char * name, SplineGeometry<3> * spl);
|
void SetSplineCurve (const char * name, shared_ptr<SplineGeometry<3>> spl);
|
||||||
const SplineGeometry<2> * GetSplineCurve2d (const string & name) const;
|
shared_ptr<SplineGeometry<2>> GetSplineCurve2d (const string & name) const;
|
||||||
const SplineGeometry<3> * GetSplineCurve3d (const string & name) const;
|
shared_ptr<SplineGeometry<3>> GetSplineCurve3d (const string & name) const;
|
||||||
|
|
||||||
void DoArchive(Archive& archive) override;
|
void DoArchive(Archive& archive) override;
|
||||||
|
|
||||||
|
@ -511,8 +511,8 @@ namespace netgen
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Primitive * nprim = new Extrusion(*(geom->GetSplineCurve3d(epath)),
|
Primitive * nprim = new Extrusion(geom->GetSplineCurve3d(epath),
|
||||||
*(geom->GetSplineCurve2d(profile)),
|
geom->GetSplineCurve2d(profile),
|
||||||
z_dir);
|
z_dir);
|
||||||
geom->AddSurfaces (nprim);
|
geom->AddSurfaces (nprim);
|
||||||
return new Solid(nprim);
|
return new Solid(nprim);
|
||||||
@ -1186,7 +1186,7 @@ namespace netgen
|
|||||||
ParseChar (scan, '=');
|
ParseChar (scan, '=');
|
||||||
ParseChar (scan, '(');
|
ParseChar (scan, '(');
|
||||||
|
|
||||||
SplineGeometry<2> * newspline = new SplineGeometry<2>;
|
auto newspline = make_shared<SplineGeometry<2>>();
|
||||||
// newspline->CSGLoad(scan);
|
// newspline->CSGLoad(scan);
|
||||||
LoadSpline (*newspline, scan);
|
LoadSpline (*newspline, scan);
|
||||||
|
|
||||||
@ -1212,7 +1212,7 @@ namespace netgen
|
|||||||
ParseChar (scan, '=');
|
ParseChar (scan, '=');
|
||||||
ParseChar (scan, '(');
|
ParseChar (scan, '(');
|
||||||
|
|
||||||
SplineGeometry<3> * newspline = new SplineGeometry<3>;
|
auto newspline = make_shared<SplineGeometry<3>>();
|
||||||
// newspline->CSGLoad(scan);
|
// newspline->CSGLoad(scan);
|
||||||
LoadSpline (*newspline, scan);
|
LoadSpline (*newspline, scan);
|
||||||
|
|
||||||
|
@ -970,7 +970,7 @@ namespace netgen
|
|||||||
|
|
||||||
for (int i = 0; i < geometry.GetNTopLevelObjects(); i++)
|
for (int i = 0; i < geometry.GetNTopLevelObjects(); i++)
|
||||||
{
|
{
|
||||||
Solid * locsol;
|
// Solid * locsol;
|
||||||
|
|
||||||
if (geometry.GetTopLevelObject(i)->GetLayer() != layer)
|
if (geometry.GetTopLevelObject(i)->GetLayer() != layer)
|
||||||
continue;
|
continue;
|
||||||
@ -978,7 +978,8 @@ namespace netgen
|
|||||||
const Solid * sol = geometry.GetTopLevelObject(i)->GetSolid();
|
const Solid * sol = geometry.GetTopLevelObject(i)->GetSolid();
|
||||||
const Surface * surf = geometry.GetTopLevelObject(i)->GetSurface();
|
const Surface * surf = geometry.GetTopLevelObject(i)->GetSurface();
|
||||||
|
|
||||||
sol -> TangentialSolid (hp, locsol, locsurfind, size*ideps);
|
// sol -> TangentialSolid (hp, locsol, locsurfind, size*ideps);
|
||||||
|
auto locsol = sol -> TangentialSolid (hp, locsurfind, size*ideps);
|
||||||
|
|
||||||
//*testout << "hp = " << hp << endl;
|
//*testout << "hp = " << hp << endl;
|
||||||
//(*testout) << "locsol: " << endl;
|
//(*testout) << "locsol: " << endl;
|
||||||
@ -995,7 +996,8 @@ namespace netgen
|
|||||||
ReducePrimitiveIterator rpi(boxp);
|
ReducePrimitiveIterator rpi(boxp);
|
||||||
UnReducePrimitiveIterator urpi;
|
UnReducePrimitiveIterator urpi;
|
||||||
|
|
||||||
((Solid*)locsol) -> IterateSolid (rpi);
|
// ((Solid*)locsol) -> IterateSolid (rpi);
|
||||||
|
locsol -> IterateSolid (rpi);
|
||||||
|
|
||||||
locsol -> CalcSurfaceInverse ();
|
locsol -> CalcSurfaceInverse ();
|
||||||
|
|
||||||
@ -1020,7 +1022,8 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
((Solid*)locsol) -> IterateSolid (urpi);
|
// ((Solid*)locsol) -> IterateSolid (urpi);
|
||||||
|
locsol -> IterateSolid (urpi);
|
||||||
|
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
@ -1085,23 +1088,33 @@ namespace netgen
|
|||||||
//int k;
|
//int k;
|
||||||
double eps = 1e-8*size;
|
double eps = 1e-8*size;
|
||||||
|
|
||||||
NgArray<bool> pre_ok(2);
|
ArrayMem<bool,2> pre_ok(2);
|
||||||
|
bool flip = false;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
eps *= 0.5;
|
eps *= 0.5;
|
||||||
pre_ok[0] = (locsol -> VectorIn2 (hp, m, n, eps) == IS_OUTSIDE &&
|
auto in00 = locsol -> VectorIn2 (hp, m, n, eps);
|
||||||
locsol -> VectorIn2 (hp, m, -1. * n, eps) == IS_INSIDE);
|
auto in01 = locsol -> VectorIn2 (hp, m, -1. * n, eps);
|
||||||
pre_ok[1] = (locsol -> VectorIn2 (hp, -1.*m, n, eps) == IS_OUTSIDE &&
|
pre_ok[0] = in00 == IS_OUTSIDE && in01 == IS_INSIDE;
|
||||||
locsol -> VectorIn2 (hp, -1.*m, -1. * n, eps) == IS_INSIDE);
|
|
||||||
|
if(in00 == IS_INSIDE && in01 == IS_OUTSIDE)
|
||||||
|
pre_ok[0] = flip = true;
|
||||||
|
|
||||||
|
auto in10 = locsol -> VectorIn2 (hp, -1.*m, n, eps);
|
||||||
|
auto in11 = locsol -> VectorIn2 (hp, -1.*m, -1. * n, eps);
|
||||||
|
pre_ok[1] = (in10 == IS_OUTSIDE && in11 == IS_INSIDE);
|
||||||
|
|
||||||
|
if(in10 == IS_INSIDE && in11 == IS_OUTSIDE)
|
||||||
|
pre_ok[1] = flip = true;
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
{
|
{
|
||||||
*testout << "eps = " << eps << endl;
|
*testout << "eps = " << eps << endl;
|
||||||
*testout << "in,1 = " << locsol -> VectorIn2 (hp, m, n, eps) << endl;
|
*testout << "in,1 = " << in00 << endl;
|
||||||
*testout << "in,1 = " << locsol -> VectorIn2 (hp, m, -1. * n, eps) << endl;
|
*testout << "in,1 = " << in01 << endl;
|
||||||
*testout << "in,1 = " << locsol -> VectorIn2 (hp, -1.*m, n, eps) << endl;
|
*testout << "in,1 = " << in10 << endl;
|
||||||
*testout << "in,1 = " << locsol -> VectorIn2 (hp, -1.*m, -1. * n, eps) << endl;
|
*testout << "in,1 = " << in11 << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(pre_ok[0] && pre_ok[1] && eps > 1e-16*size);
|
while(pre_ok[0] && pre_ok[1] && eps > 1e-16*size);
|
||||||
@ -1150,10 +1163,10 @@ namespace netgen
|
|||||||
m2 = fac * grad;
|
m2 = fac * grad;
|
||||||
// (*testout) << "hp = " << hp << ", m = " << m << ", m2 = " << m2 << endl;
|
// (*testout) << "hp = " << hp << ", m = " << m << ", m2 = " << m2 << endl;
|
||||||
|
|
||||||
Solid * locsol2;
|
// Solid * locsol2;
|
||||||
locsol -> TangentialSolid3 (hp, m, m2, locsol2, locsurfind2, ideps*size);
|
auto locsol2 = locsol -> TangentialSolid3 (hp, m, m2, locsurfind2, ideps*size);
|
||||||
if (!locsol2) ok = 0;
|
if (!locsol2) ok = 0;
|
||||||
delete locsol2;
|
// delete locsol2;
|
||||||
|
|
||||||
|
|
||||||
if (ok)
|
if (ok)
|
||||||
@ -1197,7 +1210,10 @@ namespace netgen
|
|||||||
|
|
||||||
if (!surf)
|
if (!surf)
|
||||||
{
|
{
|
||||||
if (sameasref)
|
bool inside = sameasref;
|
||||||
|
if(flip)
|
||||||
|
inside = !inside;
|
||||||
|
if (inside)
|
||||||
refedges.Elem(hi).domin = i;
|
refedges.Elem(hi).domin = i;
|
||||||
else
|
else
|
||||||
refedges.Elem(hi).domout = i;
|
refedges.Elem(hi).domout = i;
|
||||||
@ -1246,7 +1262,7 @@ namespace netgen
|
|||||||
m *= -1;
|
m *= -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete locsol;
|
// delete locsol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1255,6 +1271,9 @@ namespace netgen
|
|||||||
*testout << "Refsegments, before delete: " << endl << refedges << endl;
|
*testout << "Refsegments, before delete: " << endl << refedges << endl;
|
||||||
*testout << "inv: " << endl << refedgesinv << endl;
|
*testout << "inv: " << endl << refedgesinv << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(refedges.Size() == 0)
|
||||||
|
throw Exception("No edges found, something wrong.");
|
||||||
|
|
||||||
NgBitArray todelete(refedges.Size());
|
NgBitArray todelete(refedges.Size());
|
||||||
todelete.Clear();
|
todelete.Clear();
|
||||||
@ -1764,7 +1783,7 @@ namespace netgen
|
|||||||
int nsurf = geometry.GetNSurf();
|
int nsurf = geometry.GetNSurf();
|
||||||
int layer = 0;
|
int layer = 0;
|
||||||
|
|
||||||
Solid * tansol;
|
// Solid * tansol;
|
||||||
NgArray<int> tansurfind;
|
NgArray<int> tansurfind;
|
||||||
|
|
||||||
double size = geometry.MaxSize();
|
double size = geometry.MaxSize();
|
||||||
@ -1822,7 +1841,8 @@ namespace netgen
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const Solid * sol = geometry.GetTopLevelObject(j)->GetSolid();
|
const Solid * sol = geometry.GetTopLevelObject(j)->GetSolid();
|
||||||
sol -> TangentialSolid (p1, tansol, tansurfind, ideps*size);
|
// sol -> TangentialSolid (p1, tansol, tansurfind, ideps*size);
|
||||||
|
auto tansol = sol -> TangentialSolid (p1, tansurfind, ideps*size);
|
||||||
layer = geometry.GetTopLevelObject(j)->GetLayer();
|
layer = geometry.GetTopLevelObject(j)->GetLayer();
|
||||||
|
|
||||||
|
|
||||||
@ -1852,7 +1872,7 @@ namespace netgen
|
|||||||
// seg.invs1 = surfaces[i] -> Inverse();
|
// seg.invs1 = surfaces[i] -> Inverse();
|
||||||
// seg.invs2 = ! (surfaces[i] -> Inverse());
|
// seg.invs2 = ! (surfaces[i] -> Inverse());
|
||||||
}
|
}
|
||||||
delete tansol;
|
// delete tansol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,6 +41,18 @@ namespace netgen
|
|||||||
loc_z_dir[i] = glob_z_direction;
|
loc_z_dir[i] = glob_z_direction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double cum_angle = 0.;
|
||||||
|
for(auto i : Range(path->GetSplines()))
|
||||||
|
{
|
||||||
|
const auto& sp = path->GetSpline(i);
|
||||||
|
auto t1 = sp.GetTangent(0.);
|
||||||
|
t1.Normalize();
|
||||||
|
auto t2 = sp.GetTangent(1.);
|
||||||
|
t2.Normalize();
|
||||||
|
cum_angle += acos(t1 * t2);
|
||||||
|
angles.Append(cum_angle);
|
||||||
|
}
|
||||||
|
|
||||||
profile->GetCoeff(profile_spline_coeff);
|
profile->GetCoeff(profile_spline_coeff);
|
||||||
latest_point3d = -1.111e30;
|
latest_point3d = -1.111e30;
|
||||||
@ -415,6 +427,14 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ExtrusionFace :: PointInFace (const Point<3> & p, const double eps) const
|
||||||
|
{
|
||||||
|
Point<3> hp = p;
|
||||||
|
Project(hp);
|
||||||
|
return Dist2(p,hp) < sqr(eps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ExtrusionFace :: LineIntersections ( const Point<3> & p,
|
void ExtrusionFace :: LineIntersections ( const Point<3> & p,
|
||||||
const Vec<3> & v,
|
const Vec<3> & v,
|
||||||
const double eps,
|
const double eps,
|
||||||
@ -648,20 +668,35 @@ namespace netgen
|
|||||||
dez /= lenz;
|
dez /= lenz;
|
||||||
dez -= (dez * ez) * ez;
|
dez -= (dez * ez) * ez;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Extrusion :: Extrusion(const SplineGeometry<3> & path_in,
|
void ExtrusionFace :: DefineTangentialPlane(const Point<3>& ap1,
|
||||||
const SplineGeometry<2> & profile_in,
|
const Point<3>& ap2)
|
||||||
|
{
|
||||||
|
Surface::DefineTangentialPlane(ap1, ap2);
|
||||||
|
tangential_plane_seg = latest_seg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExtrusionFace :: ToPlane(const Point<3>& p3d, Point<2>& p2d,
|
||||||
|
double h, int& zone) const
|
||||||
|
{
|
||||||
|
Surface::ToPlane(p3d, p2d, h, zone);
|
||||||
|
double angle = angles[tangential_plane_seg] - angles[latest_seg];
|
||||||
|
if(fabs(angle) > 3.14/2.)
|
||||||
|
zone = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Extrusion :: Extrusion(shared_ptr<SplineGeometry<3>> path_in,
|
||||||
|
shared_ptr<SplineGeometry<2>> profile_in,
|
||||||
const Vec<3> & z_dir) :
|
const Vec<3> & z_dir) :
|
||||||
path(&path_in), profile(&profile_in), z_direction(z_dir)
|
path(path_in), profile(profile_in), z_direction(z_dir)
|
||||||
{
|
{
|
||||||
surfaceactive.SetSize(0);
|
surfaceactive.SetSize(0);
|
||||||
surfaceids.SetSize(0);
|
surfaceids.SetSize(0);
|
||||||
|
|
||||||
for(int j=0; j<profile->GetNSplines(); j++)
|
for(int j=0; j<profile->GetNSplines(); j++)
|
||||||
{
|
{
|
||||||
ExtrusionFace * face = new ExtrusionFace(&((*profile).GetSpline(j)),
|
ExtrusionFace * face = new ExtrusionFace(&(profile->GetSpline(j)),
|
||||||
path,
|
path.get(),
|
||||||
z_direction);
|
z_direction);
|
||||||
faces.Append(face);
|
faces.Append(face);
|
||||||
surfaceactive.Append(true);
|
surfaceactive.Append(true);
|
||||||
@ -737,6 +772,16 @@ namespace netgen
|
|||||||
return PointInSolid(p,eps,NULL);
|
return PointInSolid(p,eps,NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Extrusion :: GetTangentialSurfaceIndices (const Point<3> & p,
|
||||||
|
NgArray<int> & surfind, double eps) const
|
||||||
|
{
|
||||||
|
for (int j = 0; j < faces.Size(); j++)
|
||||||
|
if (faces[j] -> PointInFace(p, eps))
|
||||||
|
if (!surfind.Contains (GetSurfaceId(j)))
|
||||||
|
surfind.Append (GetSurfaceId(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
INSOLID_TYPE Extrusion :: VecInSolid (const Point<3> & p,
|
INSOLID_TYPE Extrusion :: VecInSolid (const Point<3> & p,
|
||||||
const Vec<3> & v,
|
const Vec<3> & v,
|
||||||
double eps) const
|
double eps) const
|
||||||
@ -838,7 +883,7 @@ namespace netgen
|
|||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
if(latestfacenum >= 0)
|
if(latestfacenum >= 0)
|
||||||
return faces[latestfacenum]->VecInFace(p,v2,0);
|
return faces[latestfacenum]->VecInFace(p,v2,eps);
|
||||||
else
|
else
|
||||||
return VecInSolid(p,v2,eps);
|
return VecInSolid(p,v2,eps);
|
||||||
}
|
}
|
||||||
|
@ -12,8 +12,10 @@ namespace netgen
|
|||||||
const SplineSeg<2> * profile;
|
const SplineSeg<2> * profile;
|
||||||
const SplineGeometry<3> * path;
|
const SplineGeometry<3> * path;
|
||||||
Vec<3> glob_z_direction;
|
Vec<3> glob_z_direction;
|
||||||
|
Array<double> angles;
|
||||||
|
|
||||||
bool deletable;
|
bool deletable;
|
||||||
|
int tangential_plane_seg;
|
||||||
|
|
||||||
NgArray< const SplineSeg3<3> * > spline3_path;
|
NgArray< const SplineSeg3<3> * > spline3_path;
|
||||||
NgArray< const LineSeg<3> * > line_path;
|
NgArray< const LineSeg<3> * > line_path;
|
||||||
@ -54,7 +56,7 @@ namespace netgen
|
|||||||
|
|
||||||
~ExtrusionFace();
|
~ExtrusionFace();
|
||||||
|
|
||||||
virtual void DoArchive(Archive& ar)
|
void DoArchive(Archive& ar) override
|
||||||
{
|
{
|
||||||
Surface::DoArchive(ar);
|
Surface::DoArchive(ar);
|
||||||
ar & profile & path & glob_z_direction & deletable & spline3_path & line_path &
|
ar & profile & path & glob_z_direction & deletable & spline3_path & line_path &
|
||||||
@ -62,25 +64,25 @@ namespace netgen
|
|||||||
profile_spline_coeff & latest_seg & latest_t & latest_point2d & latest_point3d;
|
profile_spline_coeff & latest_seg & latest_t & latest_point2d & latest_point3d;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual int IsIdentic (const Surface & s2, int & inv, double eps) const;
|
int IsIdentic (const Surface & s2, int & inv, double eps) const override;
|
||||||
|
|
||||||
virtual double CalcFunctionValue (const Point<3> & point) const;
|
double CalcFunctionValue (const Point<3> & point) const override;
|
||||||
virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const;
|
void CalcGradient (const Point<3> & point, Vec<3> & grad) const override;
|
||||||
virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const;
|
void CalcHesse (const Point<3> & point, Mat<3> & hesse) const override;
|
||||||
virtual double HesseNorm () const;
|
double HesseNorm () const override;
|
||||||
|
|
||||||
virtual double MaxCurvature () const;
|
double MaxCurvature () const override;
|
||||||
//virtual double MaxCurvatureLoc (const Point<3> & /* c */ ,
|
//virtual double MaxCurvatureLoc (const Point<3> & /* c */ ,
|
||||||
// double /* rad */) const;
|
// double /* rad */) const;
|
||||||
|
|
||||||
virtual void Project (Point<3> & p) const;
|
void Project (Point<3> & p) const override;
|
||||||
|
|
||||||
virtual Point<3> GetSurfacePoint () const;
|
Point<3> GetSurfacePoint () const override;
|
||||||
virtual void Print (ostream & str) const;
|
void Print (ostream & str) const override;
|
||||||
|
|
||||||
virtual void GetTriangleApproximation (TriangleApproximation & tas,
|
void GetTriangleApproximation (TriangleApproximation & tas,
|
||||||
const Box<3> & boundingbox,
|
const Box<3> & boundingbox,
|
||||||
double facets) const;
|
double facets) const override;
|
||||||
|
|
||||||
const SplineGeometry<3> & GetPath(void) const {return *path;}
|
const SplineGeometry<3> & GetPath(void) const {return *path;}
|
||||||
const SplineSeg<2> & GetProfile(void) const {return *profile;}
|
const SplineSeg<2> & GetProfile(void) const {return *profile;}
|
||||||
@ -94,6 +96,9 @@ namespace netgen
|
|||||||
int & after,
|
int & after,
|
||||||
bool & intersecting ) const;
|
bool & intersecting ) const;
|
||||||
|
|
||||||
|
|
||||||
|
bool PointInFace (const Point<3> & p, const double eps) const;
|
||||||
|
|
||||||
INSOLID_TYPE VecInFace ( const Point<3> & p,
|
INSOLID_TYPE VecInFace ( const Point<3> & p,
|
||||||
const Vec<3> & v,
|
const Vec<3> & v,
|
||||||
const double eps ) const;
|
const double eps ) const;
|
||||||
@ -111,6 +116,11 @@ namespace netgen
|
|||||||
Vec<3> & ex, Vec<3> & ey, Vec<3> & ez,
|
Vec<3> & ex, Vec<3> & ey, Vec<3> & ez,
|
||||||
Vec<3> & dex, Vec<3> & dey, Vec<3> & dez) const;
|
Vec<3> & dex, Vec<3> & dey, Vec<3> & dez) const;
|
||||||
|
|
||||||
|
void DefineTangentialPlane(const Point<3>& ap1,
|
||||||
|
const Point<3>& ap2) override;
|
||||||
|
void ToPlane(const Point<3>& p3d, Point<2>& p2d,
|
||||||
|
double h, int& zone) const override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -118,8 +128,8 @@ namespace netgen
|
|||||||
class Extrusion : public Primitive
|
class Extrusion : public Primitive
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
const SplineGeometry<3>* path;
|
shared_ptr<SplineGeometry<3>> path;
|
||||||
const SplineGeometry<2>* profile; // closed, clockwise oriented curve
|
shared_ptr<SplineGeometry<2>> profile; // closed, clockwise oriented curve
|
||||||
|
|
||||||
Vec<3> z_direction;
|
Vec<3> z_direction;
|
||||||
|
|
||||||
@ -128,43 +138,46 @@ namespace netgen
|
|||||||
mutable int latestfacenum;
|
mutable int latestfacenum;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Extrusion(const SplineGeometry<3> & path_in,
|
Extrusion(shared_ptr<SplineGeometry<3>> path_in,
|
||||||
const SplineGeometry<2> & profile_in,
|
shared_ptr<SplineGeometry<2>> profile_in,
|
||||||
const Vec<3> & z_dir);
|
const Vec<3> & z_dir);
|
||||||
// default constructor for archive
|
// default constructor for archive
|
||||||
Extrusion() {}
|
Extrusion() {}
|
||||||
~Extrusion();
|
~Extrusion();
|
||||||
|
|
||||||
virtual void DoArchive(Archive& ar)
|
void DoArchive(Archive& ar) override
|
||||||
{
|
{
|
||||||
Primitive::DoArchive(ar);
|
Primitive::DoArchive(ar);
|
||||||
ar & path & profile & z_direction & faces & latestfacenum;
|
ar & path & profile & z_direction & faces & latestfacenum;
|
||||||
}
|
}
|
||||||
virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
|
INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const override;
|
||||||
virtual INSOLID_TYPE PointInSolid (const Point<3> & p,
|
INSOLID_TYPE PointInSolid (const Point<3> & p,
|
||||||
double eps) const;
|
double eps) const override;
|
||||||
INSOLID_TYPE PointInSolid (const Point<3> & p,
|
INSOLID_TYPE PointInSolid (const Point<3> & p,
|
||||||
double eps,
|
double eps,
|
||||||
NgArray<int> * const facenums) const;
|
NgArray<int> * const facenums) const;
|
||||||
virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
|
|
||||||
const Vec<3> & v,
|
void GetTangentialSurfaceIndices (const Point<3> & p,
|
||||||
double eps) const;
|
NgArray<int> & surfind, double eps) const override;
|
||||||
|
|
||||||
|
INSOLID_TYPE VecInSolid (const Point<3> & p,
|
||||||
|
const Vec<3> & v,
|
||||||
|
double eps) const override;
|
||||||
|
|
||||||
// checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid
|
// checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid
|
||||||
virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p,
|
INSOLID_TYPE VecInSolid2 (const Point<3> & p,
|
||||||
const Vec<3> & v1,
|
const Vec<3> & v1,
|
||||||
const Vec<3> & v2,
|
const Vec<3> & v2,
|
||||||
double eps) const;
|
double eps) const override;
|
||||||
|
|
||||||
|
|
||||||
virtual int GetNSurfaces() const;
|
int GetNSurfaces() const override;
|
||||||
virtual Surface & GetSurface (int i = 0);
|
Surface & GetSurface (int i = 0) override;
|
||||||
virtual const Surface & GetSurface (int i = 0) const;
|
const Surface & GetSurface (int i = 0) const override;
|
||||||
|
|
||||||
|
|
||||||
virtual void Reduce (const BoxSphere<3> & box);
|
void Reduce (const BoxSphere<3> & box) override;
|
||||||
virtual void UnReduce ();
|
void UnReduce () override;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -318,6 +318,10 @@ GetIdentifiedPoint (class Mesh & mesh, int pi)
|
|||||||
|
|
||||||
void PeriodicIdentification :: IdentifyPoints (class Mesh & mesh)
|
void PeriodicIdentification :: IdentifyPoints (class Mesh & mesh)
|
||||||
{
|
{
|
||||||
|
Point3d p1, p2;
|
||||||
|
mesh.GetBox(p1, p2);
|
||||||
|
auto eps = 1e-6 * (p2-p1).Length();
|
||||||
|
|
||||||
for (int i = 1; i <= mesh.GetNP(); i++)
|
for (int i = 1; i <= mesh.GetNP(); i++)
|
||||||
{
|
{
|
||||||
Point<3> p = mesh.Point(i);
|
Point<3> p = mesh.Point(i);
|
||||||
@ -327,7 +331,7 @@ void PeriodicIdentification :: IdentifyPoints (class Mesh & mesh)
|
|||||||
pp = trafo(pp);
|
pp = trafo(pp);
|
||||||
s2->Project (pp);
|
s2->Project (pp);
|
||||||
for (int j = 1; j <= mesh.GetNP(); j++)
|
for (int j = 1; j <= mesh.GetNP(); j++)
|
||||||
if (Dist2(mesh.Point(j), pp) < 1e-6)
|
if (Dist2(mesh.Point(j), pp) < eps)
|
||||||
{
|
{
|
||||||
mesh.GetIdentifications().Add (i, j, nr);
|
mesh.GetIdentifications().Add (i, j, nr);
|
||||||
/*
|
/*
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -48,46 +48,63 @@ namespace netgen
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
Polyhedra ();
|
Polyhedra ();
|
||||||
virtual ~Polyhedra ();
|
virtual ~Polyhedra () override;
|
||||||
static Primitive * CreateDefault ();
|
static Primitive * CreateDefault ();
|
||||||
|
|
||||||
virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
|
virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const override;
|
||||||
virtual INSOLID_TYPE PointInSolid (const Point<3> & p,
|
virtual INSOLID_TYPE PointInSolid (const Point<3> & p,
|
||||||
double eps) const;
|
double eps) const override;
|
||||||
virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
|
virtual INSOLID_TYPE VecInSolidNew (const Point<3> & p,
|
||||||
|
const Vec<3> & v,
|
||||||
|
double eps, bool printing = false) const;
|
||||||
|
virtual INSOLID_TYPE VecInSolidOld (const Point<3> & p,
|
||||||
const Vec<3> & v,
|
const Vec<3> & v,
|
||||||
double eps) const;
|
double eps) const;
|
||||||
|
|
||||||
|
virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
|
||||||
|
const Vec<3> & v,
|
||||||
|
double eps) const override;
|
||||||
|
|
||||||
// checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid
|
|
||||||
virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p,
|
virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p,
|
||||||
const Vec<3> & v1,
|
const Vec<3> & v1,
|
||||||
const Vec<3> & v2,
|
const Vec<3> & v2,
|
||||||
double eps) const;
|
double eps) const override;
|
||||||
|
|
||||||
|
virtual INSOLID_TYPE VecInSolid3 (const Point<3> & p,
|
||||||
|
const Vec<3> & v1,
|
||||||
|
const Vec<3> & v2,
|
||||||
|
double eps) const override;
|
||||||
|
|
||||||
|
virtual INSOLID_TYPE VecInSolid4 (const Point<3> & p,
|
||||||
|
const Vec<3> & v,
|
||||||
|
const Vec<3> & v2,
|
||||||
|
const Vec<3> & m,
|
||||||
|
double eps) const override;
|
||||||
|
|
||||||
virtual void GetTangentialSurfaceIndices (const Point<3> & p,
|
virtual void GetTangentialSurfaceIndices (const Point<3> & p,
|
||||||
NgArray<int> & surfind, double eps) const;
|
NgArray<int> & surfind, double eps) const override;
|
||||||
|
|
||||||
|
|
||||||
virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
||||||
NgArray<int> & surfind, double eps) const;
|
NgArray<int> & surfind, double eps) const override;
|
||||||
|
|
||||||
virtual void CalcSpecialPoints (NgArray<Point<3> > & pts) const;
|
virtual void CalcSpecialPoints (NgArray<Point<3> > & pts) const override;
|
||||||
virtual void AnalyzeSpecialPoint (const Point<3> & pt,
|
virtual void AnalyzeSpecialPoint (const Point<3> & pt,
|
||||||
NgArray<Point<3> > & specpts) const;
|
NgArray<Point<3> > & specpts) const override;
|
||||||
virtual Vec<3> SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const;
|
virtual Vec<3> SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const override;
|
||||||
|
|
||||||
virtual int GetNSurfaces() const
|
virtual int GetNSurfaces() const override
|
||||||
{ return planes.Size(); }
|
{ return planes.Size(); }
|
||||||
virtual Surface & GetSurface (int i)
|
virtual Surface & GetSurface (int i) override
|
||||||
{ return *planes[i]; }
|
{ return *planes[i]; }
|
||||||
virtual const Surface & GetSurface (int i) const
|
virtual const Surface & GetSurface (int i) const override
|
||||||
{ return *planes[i]; }
|
{ return *planes[i]; }
|
||||||
|
|
||||||
virtual void GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const;
|
virtual void GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const override;
|
||||||
virtual void SetPrimitiveData (NgArray<double> & coeffs);
|
virtual void SetPrimitiveData (NgArray<double> & coeffs) override;
|
||||||
|
|
||||||
virtual void Reduce (const BoxSphere<3> & box);
|
virtual void Reduce (const BoxSphere<3> & box) override;
|
||||||
virtual void UnReduce ();
|
virtual void UnReduce () override;
|
||||||
|
|
||||||
int AddPoint (const Point<3> & p);
|
int AddPoint (const Point<3> & p);
|
||||||
int AddFace (int pi1, int pi2, int pi3, int inputnum);
|
int AddFace (int pi1, int pi2, int pi3, int inputnum);
|
||||||
|
@ -170,7 +170,8 @@ namespace netgen
|
|||||||
|
|
||||||
DLL_HEADER void ExportCSG(py::module &m)
|
DLL_HEADER void ExportCSG(py::module &m)
|
||||||
{
|
{
|
||||||
py::class_<SplineGeometry<2>> (m, "SplineCurve2d")
|
py::class_<SplineGeometry<2>, shared_ptr<SplineGeometry<2>>>
|
||||||
|
(m, "SplineCurve2d")
|
||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def ("AddPoint", FunctionPointer
|
.def ("AddPoint", FunctionPointer
|
||||||
([] (SplineGeometry<2> & self, double x, double y)
|
([] (SplineGeometry<2> & self, double x, double y)
|
||||||
@ -329,14 +330,31 @@ DLL_HEADER void ExportCSG(py::module &m)
|
|||||||
Solid * sol = new Solid(rev);
|
Solid * sol = new Solid(rev);
|
||||||
return make_shared<SPSolid> (sol);
|
return make_shared<SPSolid> (sol);
|
||||||
}));
|
}));
|
||||||
m.def ("Extrusion", FunctionPointer([](const SplineGeometry<3> & path,
|
m.def ("Extrusion", [](shared_ptr<SplineGeometry<3>> path,
|
||||||
const SplineGeometry<2> & profile,
|
shared_ptr<SplineGeometry<2>> profile,
|
||||||
Vec<3> n)
|
Vec<3> d)
|
||||||
{
|
{
|
||||||
Extrusion * extr = new Extrusion (path,profile,n);
|
Extrusion * extr = new Extrusion (path,profile,d);
|
||||||
Solid * sol = new Solid(extr);
|
Solid * sol = new Solid(extr);
|
||||||
return make_shared<SPSolid> (sol);
|
return make_shared<SPSolid> (sol);
|
||||||
}));
|
}, py::arg("path"), py::arg("profile"), py::arg("d"),
|
||||||
|
R"delimiter(A body of extrusion is defined by its profile
|
||||||
|
(which has to be a closed, clockwiseoriented 2D curve),
|
||||||
|
by a path (a 3D curve) and a vector d. It is constructed
|
||||||
|
as follows: Take a point p on the path and denote the
|
||||||
|
(unit-)tangent of the path in this point by t. If we cut
|
||||||
|
the body by the plane given by p and t as normal vector,
|
||||||
|
the cut is the profile. The profile is oriented by the
|
||||||
|
(local) y-direction `y:=d−(d·t)t` and the (local) x-direction
|
||||||
|
`x:=t \times y`.
|
||||||
|
The following points have to be noticed:
|
||||||
|
* If the path is not closed, then also the body is NOT closed.
|
||||||
|
In this case e.g. planes or orthobricks have to be used to
|
||||||
|
construct a closed body.
|
||||||
|
* The path has to be smooth, i.e. the tangents at the end- resp.
|
||||||
|
start-point of two consecutive spline or line patches have to
|
||||||
|
have the same directions.
|
||||||
|
)delimiter");
|
||||||
m.def("EllipticCone", [](const Point<3>& a, const Vec<3>& v, const Vec<3>& w,
|
m.def("EllipticCone", [](const Point<3>& a, const Vec<3>& v, const Vec<3>& w,
|
||||||
double h, double r)
|
double h, double r)
|
||||||
{
|
{
|
||||||
@ -354,6 +372,35 @@ When r =1, the truncated elliptic cone becomes an elliptic cylinder.
|
|||||||
When r tends to zero, the truncated elliptic cone tends to a full elliptic cone.
|
When r tends to zero, the truncated elliptic cone tends to a full elliptic cone.
|
||||||
However, when r = 0, the top part becomes a point(tip) and meshing fails!
|
However, when r = 0, the top part becomes a point(tip) and meshing fails!
|
||||||
)raw_string");
|
)raw_string");
|
||||||
|
|
||||||
|
m.def("Polyhedron", [](py::list points, py::list faces)
|
||||||
|
{
|
||||||
|
auto poly = new Polyhedra();
|
||||||
|
for(auto p : points)
|
||||||
|
poly->AddPoint(py::cast<Point<3>>(p));
|
||||||
|
int fnr = 0;
|
||||||
|
for(auto face : faces)
|
||||||
|
{
|
||||||
|
auto lface = py::cast<py::list>(face);
|
||||||
|
if(py::len(lface) == 3)
|
||||||
|
poly->AddFace(py::cast<int>(lface[0]),
|
||||||
|
py::cast<int>(lface[1]),
|
||||||
|
py::cast<int>(lface[2]),
|
||||||
|
fnr++);
|
||||||
|
else if(py::len(lface) == 4)
|
||||||
|
{
|
||||||
|
poly->AddFace(py::cast<int>(lface[0]),
|
||||||
|
py::cast<int>(lface[1]),
|
||||||
|
py::cast<int>(lface[2]),
|
||||||
|
fnr);
|
||||||
|
poly->AddFace(py::cast<int>(lface[0]),
|
||||||
|
py::cast<int>(lface[2]),
|
||||||
|
py::cast<int>(lface[3]),
|
||||||
|
fnr++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return make_shared<SPSolid>(new Solid(poly));
|
||||||
|
});
|
||||||
|
|
||||||
m.def ("Or", FunctionPointer([](shared_ptr<SPSolid> s1, shared_ptr<SPSolid> s2)
|
m.def ("Or", FunctionPointer([](shared_ptr<SPSolid> s1, shared_ptr<SPSolid> s2)
|
||||||
{
|
{
|
||||||
|
@ -670,6 +670,23 @@ namespace netgen
|
|||||||
surfaceactive.Append(1);
|
surfaceactive.Append(1);
|
||||||
surfaceids.Append(0);
|
surfaceids.Append(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// checking
|
||||||
|
if (type == 2)
|
||||||
|
{
|
||||||
|
auto t0 = spline_in.GetSpline(0).GetTangent(0);
|
||||||
|
cout << "tstart (must be vertically): " << t0 << endl;
|
||||||
|
|
||||||
|
auto tn = spline_in.GetSpline(nsplines-1).GetTangent(1);
|
||||||
|
cout << "tend (must be vertically): " << tn << endl;
|
||||||
|
|
||||||
|
for (int i = 0; i < nsplines-1; i++)
|
||||||
|
{
|
||||||
|
auto ta = spline_in.GetSpline(i).GetTangent(1);
|
||||||
|
auto tb = spline_in.GetSpline(i+1).GetTangent(0);
|
||||||
|
cout << "sin (must not be 0) = " << abs(ta(0)*tb(1)-ta(1)*tb(0)) / (Abs(ta)*Abs(tb));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Revolution::~Revolution()
|
Revolution::~Revolution()
|
||||||
@ -764,8 +781,9 @@ namespace netgen
|
|||||||
int intersections_before(0), intersections_after(0);
|
int intersections_before(0), intersections_after(0);
|
||||||
double randomx = 7.42357;
|
double randomx = 7.42357;
|
||||||
double randomy = 1.814756;
|
double randomy = 1.814756;
|
||||||
randomx *= 1./sqrt(randomx*randomx+randomy*randomy);
|
double randomlen = sqrt(randomx*randomx+randomy*randomy);
|
||||||
randomy *= 1./sqrt(randomx*randomx+randomy*randomy);
|
randomx *= 1./randomlen;
|
||||||
|
randomy *= 1./randomlen;
|
||||||
|
|
||||||
|
|
||||||
const double a = randomy;
|
const double a = randomy;
|
||||||
@ -930,6 +948,67 @@ namespace netgen
|
|||||||
|
|
||||||
return VecInSolid(p,v1+0.01*v2,eps);
|
return VecInSolid(p,v1+0.01*v2,eps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Revolution ::
|
||||||
|
GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
||||||
|
NgArray<int> & surfind, double eps) const
|
||||||
|
{
|
||||||
|
*testout << "tangentialvecsurfind2, p = " << p << endl;
|
||||||
|
for (int i = 0; i < faces.Size(); i++)
|
||||||
|
if (faces[i]->PointInFace (p, eps))
|
||||||
|
{
|
||||||
|
*testout << "check face " << i << endl;
|
||||||
|
Point<2> p2d;
|
||||||
|
Vec<2> v12d;
|
||||||
|
faces[i]->CalcProj(p,p2d,v1,v12d);
|
||||||
|
*testout << "v12d = " << v12d << endl;
|
||||||
|
auto & spline = faces[i]->GetSpline();
|
||||||
|
if (Dist2 (spline.StartPI(), p2d) < sqr(eps))
|
||||||
|
{
|
||||||
|
*testout << "start pi" << endl;
|
||||||
|
Vec<2> tang = spline.GetTangent(0);
|
||||||
|
double ip = tang*v12d;
|
||||||
|
*testout << "ip = " << ip << endl;
|
||||||
|
if (ip > eps)
|
||||||
|
surfind.Append(GetSurfaceId(i));
|
||||||
|
else if (ip > -eps)
|
||||||
|
{
|
||||||
|
Vec<2> v22d;
|
||||||
|
faces[i]->CalcProj(p,p2d,v2,v22d);
|
||||||
|
double ip2 = tang*v22d;
|
||||||
|
*testout << "ip2 = " << ip2 << endl;
|
||||||
|
if (ip2 > -eps)
|
||||||
|
surfind.Append(GetSurfaceId(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Dist2 (faces[i]->GetSpline().EndPI(), p2d) < sqr(eps))
|
||||||
|
{
|
||||||
|
*testout << "end pi" << endl;
|
||||||
|
|
||||||
|
Vec<2> tang = spline.GetTangent(1);
|
||||||
|
double ip = tang*v12d;
|
||||||
|
*testout << "ip = " << ip << endl;
|
||||||
|
if (ip < -eps)
|
||||||
|
surfind.Append(GetSurfaceId(i));
|
||||||
|
else if (ip < eps)
|
||||||
|
{
|
||||||
|
Vec<2> v22d;
|
||||||
|
faces[i]->CalcProj(p,p2d,v2,v22d);
|
||||||
|
double ip2 = tang*v22d;
|
||||||
|
*testout << "ip2 = " << ip2 << endl;
|
||||||
|
if (ip2 < eps)
|
||||||
|
surfind.Append(GetSurfaceId(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*testout << "inner point" << endl;
|
||||||
|
surfind.Append(GetSurfaceId(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int Revolution :: GetNSurfaces() const
|
int Revolution :: GetNSurfaces() const
|
||||||
{
|
{
|
||||||
|
@ -67,7 +67,10 @@ namespace netgen
|
|||||||
virtual double MaxCurvature () const;
|
virtual double MaxCurvature () const;
|
||||||
//virtual double MaxCurvatureLoc (const Point<3> & /* c */ ,
|
//virtual double MaxCurvatureLoc (const Point<3> & /* c */ ,
|
||||||
// double /* rad */) const;
|
// double /* rad */) const;
|
||||||
|
|
||||||
|
Point<3> P0() const { return p0; }
|
||||||
|
Vec<3> Axis() const { return v_axis; }
|
||||||
|
|
||||||
virtual void Project (Point<3> & p) const;
|
virtual void Project (Point<3> & p) const;
|
||||||
|
|
||||||
virtual Point<3> GetSurfacePoint () const;
|
virtual Point<3> GetSurfacePoint () const;
|
||||||
@ -155,7 +158,10 @@ namespace netgen
|
|||||||
const Vec<3> & v2,
|
const Vec<3> & v2,
|
||||||
double eps) const;
|
double eps) const;
|
||||||
|
|
||||||
|
virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
||||||
|
NgArray<int> & surfind, double eps) const;
|
||||||
|
|
||||||
|
|
||||||
virtual int GetNSurfaces() const;
|
virtual int GetNSurfaces() const;
|
||||||
virtual Surface & GetSurface (int i = 0);
|
virtual Surface & GetSurface (int i = 0);
|
||||||
virtual const Surface & GetSurface (int i = 0) const;
|
virtual const Surface & GetSurface (int i = 0) const;
|
||||||
|
@ -168,7 +168,7 @@ void SingularPoint :: FindPoints (class Mesh & mesh)
|
|||||||
for (int k = 1; k <= 3; k++)
|
for (int k = 1; k <= 3; k++)
|
||||||
{
|
{
|
||||||
const Solid * solk(NULL);
|
const Solid * solk(NULL);
|
||||||
Solid *tansol;
|
// Solid *tansol;
|
||||||
switch (k)
|
switch (k)
|
||||||
{
|
{
|
||||||
case 1: solk = sol1; break;
|
case 1: solk = sol1; break;
|
||||||
@ -176,7 +176,7 @@ void SingularPoint :: FindPoints (class Mesh & mesh)
|
|||||||
case 3: solk = sol3; break;
|
case 3: solk = sol3; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
solk -> TangentialSolid (p, tansol, surfk, 1e-3);
|
auto tansol = solk -> TangentialSolid (p, surfk, 1e-3);
|
||||||
(*testout) << "Tansol = " << *tansol << endl;
|
(*testout) << "Tansol = " << *tansol << endl;
|
||||||
|
|
||||||
if (!tansol) continue;
|
if (!tansol) continue;
|
||||||
@ -195,7 +195,7 @@ void SingularPoint :: FindPoints (class Mesh & mesh)
|
|||||||
if (!surf.Contains (surfk[i]))
|
if (!surf.Contains (surfk[i]))
|
||||||
surf.Append (surfk[i]);
|
surf.Append (surfk[i]);
|
||||||
|
|
||||||
delete tansol;
|
// delete tansol;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surf.Size() < 3) continue;
|
if (surf.Size() < 3) continue;
|
||||||
|
@ -6,21 +6,6 @@
|
|||||||
|
|
||||||
namespace netgen
|
namespace netgen
|
||||||
{
|
{
|
||||||
//using namespace netgen;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
SolidIterator :: SolidIterator ()
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
SolidIterator :: ~SolidIterator ()
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// int Solid :: cntnames = 0;
|
// int Solid :: cntnames = 0;
|
||||||
@ -193,9 +178,70 @@ namespace netgen
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
INSOLID_TYPE Solid ::
|
||||||
|
PointInSolid (const Point<3> & p, double eps) const
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case TERM: case TERM_REF:
|
||||||
|
return prim->PointInSolid (p, eps);
|
||||||
|
case SECTION:
|
||||||
|
return Intersection (s1->PointInSolid (p, eps), s2->PointInSolid (p, eps));
|
||||||
|
case UNION:
|
||||||
|
return Union (s1->PointInSolid (p, eps), s2->PointInSolid (p, eps));
|
||||||
|
case SUB:
|
||||||
|
return Complement (s1->PointInSolid (p, eps));
|
||||||
|
case ROOT:
|
||||||
|
return s1->PointInSolid (p, eps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
INSOLID_TYPE Solid ::
|
||||||
|
VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case TERM: case TERM_REF:
|
||||||
|
return prim->VecInSolid (p, v, eps);
|
||||||
|
case SECTION:
|
||||||
|
return Intersection (s1->VecInSolid (p, v, eps), s2->VecInSolid (p, v, eps));
|
||||||
|
case UNION:
|
||||||
|
return Union (s1->VecInSolid (p, v, eps), s2->VecInSolid (p, v, eps));
|
||||||
|
case SUB:
|
||||||
|
return Complement (s1->VecInSolid (p, v, eps));
|
||||||
|
case ROOT:
|
||||||
|
return s1->VecInSolid (p, v, eps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid
|
||||||
|
INSOLID_TYPE Solid ::
|
||||||
|
VecInSolid2 (const Point<3> & p, const Vec<3> & v1,
|
||||||
|
const Vec<3> & v2, double eps) const
|
||||||
|
{
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case TERM: case TERM_REF:
|
||||||
|
return prim->VecInSolid2 (p, v1, v2, eps);
|
||||||
|
case SECTION:
|
||||||
|
return Intersection (s1->VecInSolid2 (p, v1, v2, eps), s2->VecInSolid2 (p, v1, v2, eps));
|
||||||
|
case UNION:
|
||||||
|
return Union (s1->VecInSolid2 (p, v1, v2, eps), s2->VecInSolid2 (p, v1, v2, eps));
|
||||||
|
case SUB:
|
||||||
|
return Complement (s1->VecInSolid2 (p, v1, v2, eps));
|
||||||
|
case ROOT:
|
||||||
|
return s1->VecInSolid2 (p, v1, v2, eps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool Solid :: IsIn (const Point<3> & p, double eps) const
|
bool Solid :: IsIn (const Point<3> & p, double eps) const
|
||||||
{
|
{
|
||||||
|
return PointInSolid (p,eps) != IS_OUTSIDE;
|
||||||
|
/*
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case TERM: case TERM_REF:
|
case TERM: case TERM_REF:
|
||||||
@ -213,10 +259,13 @@ namespace netgen
|
|||||||
return s1->IsIn (p, eps);
|
return s1->IsIn (p, eps);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Solid :: IsStrictIn (const Point<3> & p, double eps) const
|
bool Solid :: IsStrictIn (const Point<3> & p, double eps) const
|
||||||
{
|
{
|
||||||
|
return PointInSolid (p,eps) == IS_INSIDE;
|
||||||
|
/*
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case TERM: case TERM_REF:
|
case TERM: case TERM_REF:
|
||||||
@ -234,11 +283,14 @@ namespace netgen
|
|||||||
return s1->IsStrictIn (p, eps);
|
return s1->IsStrictIn (p, eps);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Solid :: VectorIn (const Point<3> & p, const Vec<3> & v,
|
bool Solid :: VectorIn (const Point<3> & p, const Vec<3> & v,
|
||||||
double eps) const
|
double eps) const
|
||||||
{
|
{
|
||||||
|
return VecInSolid (p,v,eps) != IS_OUTSIDE;
|
||||||
|
/*
|
||||||
Vec<3> hv;
|
Vec<3> hv;
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
@ -257,11 +309,14 @@ namespace netgen
|
|||||||
return s1->VectorIn(p, v, eps);
|
return s1->VectorIn(p, v, eps);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Solid :: VectorStrictIn (const Point<3> & p, const Vec<3> & v,
|
bool Solid :: VectorStrictIn (const Point<3> & p, const Vec<3> & v,
|
||||||
double eps) const
|
double eps) const
|
||||||
{
|
{
|
||||||
|
return VecInSolid (p,v,eps) == IS_INSIDE;
|
||||||
|
/*
|
||||||
Vec<3> hv;
|
Vec<3> hv;
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
@ -282,9 +337,11 @@ namespace netgen
|
|||||||
return s1->VectorStrictIn(p, v, eps);
|
return s1->VectorStrictIn(p, v, eps);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
bool Solid::VectorIn2 (const Point<3> & p, const Vec<3> & v1,
|
bool Solid::VectorIn2 (const Point<3> & p, const Vec<3> & v1,
|
||||||
const Vec<3> & v2, double eps) const
|
const Vec<3> & v2, double eps) const
|
||||||
{
|
{
|
||||||
@ -317,10 +374,57 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
bool Solid::VectorIn2 (const Point<3> & p, const Vec<3> & v1,
|
||||||
|
const Vec<3> & v2, double eps) const
|
||||||
|
{
|
||||||
|
return VecInSolid2 (p,v1,v2,eps) != IS_OUTSIDE;
|
||||||
|
/*
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case TERM: case TERM_REF:
|
||||||
|
{
|
||||||
|
auto res = prim->VecInSolid2 (p, v1, v2, eps);
|
||||||
|
return res != IS_OUTSIDE;
|
||||||
|
}
|
||||||
|
case SECTION:
|
||||||
|
return s1->VectorIn2 (p, v1, v2, eps) && s2->VectorIn2 (p, v1, v2, eps);
|
||||||
|
case UNION:
|
||||||
|
return s1->VectorIn2 (p, v1, v2, eps) || s2->VectorIn2 (p, v1, v2, eps);
|
||||||
|
case SUB:
|
||||||
|
return !s1->VectorStrictIn2 (p, v1, v2, eps);
|
||||||
|
case ROOT:
|
||||||
|
return s1->VectorIn2 (p, v1, v2, eps);
|
||||||
|
}
|
||||||
|
// return 0;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Solid :: VectorStrictIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
||||||
|
double eps) const
|
||||||
|
{
|
||||||
|
return VecInSolid2 (p,v1,v2,eps) == IS_INSIDE;
|
||||||
|
/*
|
||||||
|
switch (op)
|
||||||
|
{
|
||||||
|
case TERM: case TERM_REF:
|
||||||
|
{
|
||||||
|
auto res = prim->VecInSolid2 (p, v1, v2, eps);
|
||||||
|
return (res == IS_INSIDE);
|
||||||
|
}
|
||||||
|
case SECTION:
|
||||||
|
return s1->VectorStrictIn2 (p, v1, v2, eps) && s2->VectorStrictIn2 (p, v1, v2, eps);
|
||||||
|
case UNION:
|
||||||
|
return s1->VectorStrictIn2 (p, v1, v2, eps) || s2->VectorStrictIn2 (p, v1, v2, eps);
|
||||||
|
case SUB:
|
||||||
|
return !s1->VectorIn2 (p, v1, v2, eps);
|
||||||
|
case ROOT:
|
||||||
|
return s1->VectorStrictIn2 (p, v1, v2, eps);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void Solid :: Print (ostream & str) const
|
void Solid :: Print (ostream & str) const
|
||||||
@ -638,18 +742,20 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Solid :: TangentialSolid (const Point<3> & p, Solid *& tansol, NgArray<int> & surfids, double eps) const
|
unique_ptr<Solid> Solid :: TangentialSolid (const Point<3> & p, NgArray<int> & surfids, double eps) const
|
||||||
{
|
{
|
||||||
int in, strin;
|
bool in, strin;
|
||||||
|
Solid * tansol = nullptr;
|
||||||
RecTangentialSolid (p, tansol, surfids, in, strin, eps);
|
RecTangentialSolid (p, tansol, surfids, in, strin, eps);
|
||||||
surfids.SetSize (0);
|
surfids.SetSize (0);
|
||||||
if (tansol)
|
if (tansol)
|
||||||
tansol -> GetTangentialSurfaceIndices (p, surfids, eps);
|
tansol -> GetTangentialSurfaceIndices (p, surfids, eps);
|
||||||
|
return unique_ptr<Solid> (tansol);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Solid :: RecTangentialSolid (const Point<3> & p, Solid *& tansol, NgArray<int> & surfids,
|
void Solid :: RecTangentialSolid (const Point<3> & p, Solid *& tansol, NgArray<int> & surfids,
|
||||||
int & in, int & strin, double eps) const
|
bool & in, bool & strin, double eps) const
|
||||||
{
|
{
|
||||||
tansol = NULL;
|
tansol = NULL;
|
||||||
|
|
||||||
@ -671,7 +777,7 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
case SECTION:
|
case SECTION:
|
||||||
{
|
{
|
||||||
int in1, in2, strin1, strin2;
|
bool in1, in2, strin1, strin2;
|
||||||
Solid * tansol1, * tansol2;
|
Solid * tansol1, * tansol2;
|
||||||
|
|
||||||
s1 -> RecTangentialSolid (p, tansol1, surfids, in1, strin1, eps);
|
s1 -> RecTangentialSolid (p, tansol1, surfids, in1, strin1, eps);
|
||||||
@ -686,13 +792,13 @@ namespace netgen
|
|||||||
else if (tansol2)
|
else if (tansol2)
|
||||||
tansol = tansol2;
|
tansol = tansol2;
|
||||||
}
|
}
|
||||||
in = (in1 && in2);
|
in = in1 && in2;
|
||||||
strin = (strin1 && strin2);
|
strin = strin1 && strin2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case UNION:
|
case UNION:
|
||||||
{
|
{
|
||||||
int in1, in2, strin1, strin2;
|
bool in1, in2, strin1, strin2;
|
||||||
Solid * tansol1 = 0, * tansol2 = 0;
|
Solid * tansol1 = 0, * tansol2 = 0;
|
||||||
|
|
||||||
s1 -> RecTangentialSolid (p, tansol1, surfids, in1, strin1, eps);
|
s1 -> RecTangentialSolid (p, tansol1, surfids, in1, strin1, eps);
|
||||||
@ -712,13 +818,13 @@ namespace netgen
|
|||||||
delete tansol1;
|
delete tansol1;
|
||||||
delete tansol2;
|
delete tansol2;
|
||||||
}
|
}
|
||||||
in = (in1 || in2);
|
in = in1 || in2;
|
||||||
strin = (strin1 || strin2);
|
strin = strin1 || strin2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SUB:
|
case SUB:
|
||||||
{
|
{
|
||||||
int hin, hstrin;
|
bool hin, hstrin;
|
||||||
Solid * tansol1;
|
Solid * tansol1;
|
||||||
|
|
||||||
s1 -> RecTangentialSolid (p, tansol1, surfids, hin, hstrin, eps);
|
s1 -> RecTangentialSolid (p, tansol1, surfids, hin, hstrin, eps);
|
||||||
@ -740,22 +846,24 @@ namespace netgen
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Solid :: TangentialSolid2 (const Point<3> & p,
|
unique_ptr<Solid> Solid :: TangentialSolid2 (const Point<3> & p,
|
||||||
const Vec<3> & t,
|
const Vec<3> & t,
|
||||||
Solid *& tansol, NgArray<int> & surfids, double eps) const
|
NgArray<int> & surfids, double eps) const
|
||||||
{
|
{
|
||||||
int in, strin;
|
Solid * tansol = nullptr;
|
||||||
|
bool in, strin;
|
||||||
surfids.SetSize (0);
|
surfids.SetSize (0);
|
||||||
RecTangentialSolid2 (p, t, tansol, surfids, in, strin, eps);
|
RecTangentialSolid2 (p, t, tansol, surfids, in, strin, eps);
|
||||||
if (tansol)
|
if (tansol)
|
||||||
tansol -> GetTangentialSurfaceIndices2 (p, t, surfids, eps);
|
tansol -> GetTangentialSurfaceIndices2 (p, t, surfids, eps);
|
||||||
|
return unique_ptr<Solid> (tansol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Solid :: RecTangentialSolid2 (const Point<3> & p, const Vec<3> & t,
|
void Solid :: RecTangentialSolid2 (const Point<3> & p, const Vec<3> & t,
|
||||||
Solid *& tansol, NgArray<int> & surfids,
|
Solid *& tansol, NgArray<int> & surfids,
|
||||||
int & in, int & strin, double eps) const
|
bool & in, bool & strin, double eps) const
|
||||||
{
|
{
|
||||||
tansol = NULL;
|
tansol = nullptr;
|
||||||
|
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
@ -774,8 +882,8 @@ namespace netgen
|
|||||||
if (ist == DOES_INTERSECT)
|
if (ist == DOES_INTERSECT)
|
||||||
ist = prim->VecInSolid (p, t, eps);
|
ist = prim->VecInSolid (p, t, eps);
|
||||||
|
|
||||||
in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
|
in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT);
|
||||||
strin = (ist == IS_INSIDE);
|
strin = ist == IS_INSIDE;
|
||||||
|
|
||||||
if (ist == DOES_INTERSECT)
|
if (ist == DOES_INTERSECT)
|
||||||
{
|
{
|
||||||
@ -786,7 +894,7 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
case SECTION:
|
case SECTION:
|
||||||
{
|
{
|
||||||
int in1, in2, strin1, strin2;
|
bool in1, in2, strin1, strin2;
|
||||||
Solid * tansol1, * tansol2;
|
Solid * tansol1, * tansol2;
|
||||||
|
|
||||||
s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, in1, strin1, eps);
|
s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, in1, strin1, eps);
|
||||||
@ -801,13 +909,13 @@ namespace netgen
|
|||||||
else if (tansol2)
|
else if (tansol2)
|
||||||
tansol = tansol2;
|
tansol = tansol2;
|
||||||
}
|
}
|
||||||
in = (in1 && in2);
|
in = in1 && in2;
|
||||||
strin = (strin1 && strin2);
|
strin = strin1 && strin2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case UNION:
|
case UNION:
|
||||||
{
|
{
|
||||||
int in1, in2, strin1, strin2;
|
bool in1, in2, strin1, strin2;
|
||||||
Solid * tansol1, * tansol2;
|
Solid * tansol1, * tansol2;
|
||||||
|
|
||||||
s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, in1, strin1, eps);
|
s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, in1, strin1, eps);
|
||||||
@ -822,13 +930,13 @@ namespace netgen
|
|||||||
else if (tansol2)
|
else if (tansol2)
|
||||||
tansol = tansol2;
|
tansol = tansol2;
|
||||||
}
|
}
|
||||||
in = (in1 || in2);
|
in = in1 || in2;
|
||||||
strin = (strin1 || strin2);
|
strin = strin1 || strin2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SUB:
|
case SUB:
|
||||||
{
|
{
|
||||||
int hin, hstrin;
|
bool hin, hstrin;
|
||||||
Solid * tansol1;
|
Solid * tansol1;
|
||||||
|
|
||||||
s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, hin, hstrin, eps);
|
s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, hin, hstrin, eps);
|
||||||
@ -854,25 +962,28 @@ namespace netgen
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Solid :: TangentialSolid3 (const Point<3> & p,
|
unique_ptr<Solid> Solid :: TangentialSolid3 (const Point<3> & p,
|
||||||
const Vec<3> & t, const Vec<3> & t2,
|
const Vec<3> & t, const Vec<3> & t2,
|
||||||
Solid *& tansol, NgArray<int> & surfids,
|
NgArray<int> & surfids,
|
||||||
double eps) const
|
double eps) const
|
||||||
{
|
{
|
||||||
int in, strin;
|
bool in, strin;
|
||||||
|
Solid * tansol = nullptr;
|
||||||
surfids.SetSize (0);
|
surfids.SetSize (0);
|
||||||
RecTangentialSolid3 (p, t, t2, tansol, surfids, in, strin, eps);
|
RecTangentialSolid3 (p, t, t2, tansol, surfids, in, strin, eps);
|
||||||
|
|
||||||
if (tansol)
|
if (tansol)
|
||||||
tansol -> GetTangentialSurfaceIndices3 (p, t, t2, surfids, eps);
|
tansol -> GetTangentialSurfaceIndices3 (p, t, t2, surfids, eps);
|
||||||
|
|
||||||
|
return unique_ptr<Solid>(tansol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Solid :: RecTangentialSolid3 (const Point<3> & p,
|
void Solid :: RecTangentialSolid3 (const Point<3> & p,
|
||||||
const Vec<3> & t, const Vec<3> & t2,
|
const Vec<3> & t, const Vec<3> & t2,
|
||||||
Solid *& tansol, NgArray<int> & surfids,
|
Solid *& tansol, NgArray<int> & surfids,
|
||||||
int & in, int & strin, double eps) const
|
bool & in, bool & strin, double eps) const
|
||||||
{
|
{
|
||||||
tansol = NULL;
|
tansol = nullptr;
|
||||||
|
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
@ -882,8 +993,8 @@ namespace netgen
|
|||||||
|
|
||||||
if (ist == DOES_INTERSECT)
|
if (ist == DOES_INTERSECT)
|
||||||
ist = prim->VecInSolid3 (p, t, t2, eps);
|
ist = prim->VecInSolid3 (p, t, t2, eps);
|
||||||
in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
|
in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT);
|
||||||
strin = (ist == IS_INSIDE);
|
strin = ist == IS_INSIDE;
|
||||||
|
|
||||||
if (ist == DOES_INTERSECT)
|
if (ist == DOES_INTERSECT)
|
||||||
{
|
{
|
||||||
@ -894,7 +1005,7 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
case SECTION:
|
case SECTION:
|
||||||
{
|
{
|
||||||
int in1, in2, strin1, strin2;
|
bool in1, in2, strin1, strin2;
|
||||||
Solid * tansol1, * tansol2;
|
Solid * tansol1, * tansol2;
|
||||||
|
|
||||||
s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, in1, strin1, eps);
|
s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, in1, strin1, eps);
|
||||||
@ -909,13 +1020,13 @@ namespace netgen
|
|||||||
else if (tansol2)
|
else if (tansol2)
|
||||||
tansol = tansol2;
|
tansol = tansol2;
|
||||||
}
|
}
|
||||||
in = (in1 && in2);
|
in = in1 && in2;
|
||||||
strin = (strin1 && strin2);
|
strin = strin1 && strin2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case UNION:
|
case UNION:
|
||||||
{
|
{
|
||||||
int in1, in2, strin1, strin2;
|
bool in1, in2, strin1, strin2;
|
||||||
Solid * tansol1, * tansol2;
|
Solid * tansol1, * tansol2;
|
||||||
|
|
||||||
s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, in1, strin1, eps);
|
s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, in1, strin1, eps);
|
||||||
@ -930,13 +1041,13 @@ namespace netgen
|
|||||||
else if (tansol2)
|
else if (tansol2)
|
||||||
tansol = tansol2;
|
tansol = tansol2;
|
||||||
}
|
}
|
||||||
in = (in1 || in2);
|
in = in1 || in2;
|
||||||
strin = (strin1 || strin2);
|
strin = strin1 || strin2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SUB:
|
case SUB:
|
||||||
{
|
{
|
||||||
int hin, hstrin;
|
bool hin, hstrin;
|
||||||
Solid * tansol1;
|
Solid * tansol1;
|
||||||
|
|
||||||
s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, hin, hstrin, eps);
|
s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, hin, hstrin, eps);
|
||||||
@ -965,12 +1076,13 @@ namespace netgen
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Solid :: TangentialEdgeSolid (const Point<3> & p,
|
unique_ptr<Solid> Solid :: TangentialEdgeSolid (const Point<3> & p,
|
||||||
const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m,
|
const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m,
|
||||||
Solid *& tansol, NgArray<int> & surfids,
|
NgArray<int> & surfids,
|
||||||
double eps) const
|
double eps) const
|
||||||
{
|
{
|
||||||
int in, strin;
|
Solid * tansol = nullptr;
|
||||||
|
bool in, strin;
|
||||||
surfids.SetSize (0);
|
surfids.SetSize (0);
|
||||||
|
|
||||||
// *testout << "tangentialedgesolid,sol = " << (*this) << endl;
|
// *testout << "tangentialedgesolid,sol = " << (*this) << endl;
|
||||||
@ -978,12 +1090,14 @@ namespace netgen
|
|||||||
|
|
||||||
if (tansol)
|
if (tansol)
|
||||||
tansol -> RecGetTangentialEdgeSurfaceIndices (p, t, t2, m, surfids, eps);
|
tansol -> RecGetTangentialEdgeSurfaceIndices (p, t, t2, m, surfids, eps);
|
||||||
|
|
||||||
|
return unique_ptr<Solid> (tansol);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Solid :: RecTangentialEdgeSolid (const Point<3> & p,
|
void Solid :: RecTangentialEdgeSolid (const Point<3> & p,
|
||||||
const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m,
|
const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m,
|
||||||
Solid *& tansol, NgArray<int> & surfids,
|
Solid *& tansol, NgArray<int> & surfids,
|
||||||
int & in, int & strin, double eps) const
|
bool & in, bool & strin, double eps) const
|
||||||
{
|
{
|
||||||
tansol = NULL;
|
tansol = NULL;
|
||||||
|
|
||||||
@ -1005,8 +1119,8 @@ namespace netgen
|
|||||||
|
|
||||||
// (*testout) << "ist2 = " << ist << endl;
|
// (*testout) << "ist2 = " << ist << endl;
|
||||||
|
|
||||||
in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
|
in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT);
|
||||||
strin = (ist == IS_INSIDE);
|
strin = ist == IS_INSIDE;
|
||||||
|
|
||||||
if (ist == DOES_INTERSECT)
|
if (ist == DOES_INTERSECT)
|
||||||
{
|
{
|
||||||
@ -1017,7 +1131,7 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
case SECTION:
|
case SECTION:
|
||||||
{
|
{
|
||||||
int in1, in2, strin1, strin2;
|
bool in1, in2, strin1, strin2;
|
||||||
Solid * tansol1, * tansol2;
|
Solid * tansol1, * tansol2;
|
||||||
|
|
||||||
s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, in1, strin1, eps);
|
s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, in1, strin1, eps);
|
||||||
@ -1032,13 +1146,13 @@ namespace netgen
|
|||||||
else if (tansol2)
|
else if (tansol2)
|
||||||
tansol = tansol2;
|
tansol = tansol2;
|
||||||
}
|
}
|
||||||
in = (in1 && in2);
|
in = in1 && in2;
|
||||||
strin = (strin1 && strin2);
|
strin = strin1 && strin2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case UNION:
|
case UNION:
|
||||||
{
|
{
|
||||||
int in1, in2, strin1, strin2;
|
bool in1, in2, strin1, strin2;
|
||||||
Solid * tansol1, * tansol2;
|
Solid * tansol1, * tansol2;
|
||||||
|
|
||||||
s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, in1, strin1, eps);
|
s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, in1, strin1, eps);
|
||||||
@ -1053,13 +1167,13 @@ namespace netgen
|
|||||||
else if (tansol2)
|
else if (tansol2)
|
||||||
tansol = tansol2;
|
tansol = tansol2;
|
||||||
}
|
}
|
||||||
in = (in1 || in2);
|
in = in1 || in2;
|
||||||
strin = (strin1 || strin2);
|
strin = strin1 || strin2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SUB:
|
case SUB:
|
||||||
{
|
{
|
||||||
int hin, hstrin;
|
bool hin, hstrin;
|
||||||
Solid * tansol1;
|
Solid * tansol1;
|
||||||
|
|
||||||
s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, hin, hstrin, eps);
|
s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, hin, hstrin, eps);
|
||||||
@ -1095,29 +1209,31 @@ namespace netgen
|
|||||||
|
|
||||||
int Solid :: Edge (const Point<3> & p, const Vec<3> & v, double eps) const
|
int Solid :: Edge (const Point<3> & p, const Vec<3> & v, double eps) const
|
||||||
{
|
{
|
||||||
int in, strin, faces;
|
bool in, strin;
|
||||||
|
int faces;
|
||||||
RecEdge (p, v, in, strin, faces, eps);
|
RecEdge (p, v, in, strin, faces, eps);
|
||||||
return faces >= 2;
|
return faces >= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Solid :: OnFace (const Point<3> & p, const Vec<3> & v, double eps) const
|
int Solid :: OnFace (const Point<3> & p, const Vec<3> & v, double eps) const
|
||||||
{
|
{
|
||||||
int in, strin, faces;
|
bool in, strin;
|
||||||
|
int faces;
|
||||||
RecEdge (p, v, in, strin, faces, eps);
|
RecEdge (p, v, in, strin, faces, eps);
|
||||||
return faces >= 1;
|
return faces >= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Solid :: RecEdge (const Point<3> & p, const Vec<3> & v,
|
void Solid :: RecEdge (const Point<3> & p, const Vec<3> & v,
|
||||||
int & in, int & strin, int & faces, double eps) const
|
bool & in, bool & strin, int & faces, double eps) const
|
||||||
{
|
{
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case TERM: case TERM_REF:
|
case TERM: case TERM_REF:
|
||||||
{
|
{
|
||||||
INSOLID_TYPE ist = prim->VecInSolid (p, v, eps);
|
INSOLID_TYPE ist = prim->VecInSolid (p, v, eps);
|
||||||
in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
|
in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT);
|
||||||
strin = (ist == IS_INSIDE);
|
strin = ist == IS_INSIDE;
|
||||||
/*
|
/*
|
||||||
in = VectorIn (p, v);
|
in = VectorIn (p, v);
|
||||||
strin = VectorStrictIn (p, v);
|
strin = VectorStrictIn (p, v);
|
||||||
@ -1143,7 +1259,8 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
case SECTION:
|
case SECTION:
|
||||||
{
|
{
|
||||||
int in1, in2, strin1, strin2, faces1, faces2;
|
bool in1, in2, strin1, strin2;
|
||||||
|
int faces1, faces2;
|
||||||
|
|
||||||
s1 -> RecEdge (p, v, in1, strin1, faces1, eps);
|
s1 -> RecEdge (p, v, in1, strin1, faces1, eps);
|
||||||
s2 -> RecEdge (p, v, in2, strin2, faces2, eps);
|
s2 -> RecEdge (p, v, in2, strin2, faces2, eps);
|
||||||
@ -1157,7 +1274,8 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
case UNION:
|
case UNION:
|
||||||
{
|
{
|
||||||
int in1, in2, strin1, strin2, faces1, faces2;
|
bool in1, in2, strin1, strin2;
|
||||||
|
int faces1, faces2;
|
||||||
|
|
||||||
s1 -> RecEdge (p, v, in1, strin1, faces1, eps);
|
s1 -> RecEdge (p, v, in1, strin1, faces1, eps);
|
||||||
s2 -> RecEdge (p, v, in2, strin2, faces2, eps);
|
s2 -> RecEdge (p, v, in2, strin2, faces2, eps);
|
||||||
@ -1171,7 +1289,7 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
case SUB:
|
case SUB:
|
||||||
{
|
{
|
||||||
int in1, strin1;
|
bool in1, strin1;
|
||||||
s1 -> RecEdge (p, v, in1, strin1, faces, eps);
|
s1 -> RecEdge (p, v, in1, strin1, faces, eps);
|
||||||
in = !strin1;
|
in = !strin1;
|
||||||
strin = !in1;
|
strin = !in1;
|
||||||
|
@ -33,6 +33,26 @@ namespace netgen
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline INSOLID_TYPE Intersection (INSOLID_TYPE ina, INSOLID_TYPE inb)
|
||||||
|
{
|
||||||
|
if (ina == IS_INSIDE && inb == IS_INSIDE) return IS_INSIDE;
|
||||||
|
if (ina == IS_OUTSIDE || inb == IS_OUTSIDE) return IS_OUTSIDE;
|
||||||
|
return DOES_INTERSECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline INSOLID_TYPE Union (INSOLID_TYPE ina, INSOLID_TYPE inb)
|
||||||
|
{
|
||||||
|
if (ina == IS_INSIDE || inb == IS_INSIDE) return IS_INSIDE;
|
||||||
|
if (ina == IS_OUTSIDE && inb == IS_OUTSIDE) return IS_OUTSIDE;
|
||||||
|
return DOES_INTERSECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline INSOLID_TYPE Complement (INSOLID_TYPE in)
|
||||||
|
{
|
||||||
|
if (in == IS_INSIDE) return IS_OUTSIDE;
|
||||||
|
if (in == IS_OUTSIDE) return IS_INSIDE;
|
||||||
|
return DOES_INTERSECT;
|
||||||
|
}
|
||||||
|
|
||||||
class Solid
|
class Solid
|
||||||
{
|
{
|
||||||
@ -102,6 +122,14 @@ namespace netgen
|
|||||||
|
|
||||||
// geometric tests
|
// geometric tests
|
||||||
|
|
||||||
|
INSOLID_TYPE PointInSolid (const Point<3> & p, double eps) const;
|
||||||
|
INSOLID_TYPE VecInSolid (const Point<3> & p, const Vec<3> & v, double eps) const;
|
||||||
|
|
||||||
|
// checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid
|
||||||
|
INSOLID_TYPE VecInSolid2 (const Point<3> & p, const Vec<3> & v1,
|
||||||
|
const Vec<3> & v2, double eps) const;
|
||||||
|
|
||||||
|
|
||||||
bool IsIn (const Point<3> & p, double eps = 1e-6) const;
|
bool IsIn (const Point<3> & p, double eps = 1e-6) const;
|
||||||
bool IsStrictIn (const Point<3> & p, double eps = 1e-6) const;
|
bool IsStrictIn (const Point<3> & p, double eps = 1e-6) const;
|
||||||
bool VectorIn (const Point<3> & p, const Vec<3> & v, double eps = 1e-6) const;
|
bool VectorIn (const Point<3> & p, const Vec<3> & v, double eps = 1e-6) const;
|
||||||
@ -109,21 +137,24 @@ namespace netgen
|
|||||||
|
|
||||||
bool VectorIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
bool VectorIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
||||||
double eps) const;
|
double eps) const;
|
||||||
|
/*
|
||||||
bool VectorIn2Rec (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
bool VectorIn2Rec (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
||||||
double eps) const;
|
double eps) const;
|
||||||
|
*/
|
||||||
|
bool VectorStrictIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
||||||
|
double eps) const;
|
||||||
|
|
||||||
/// compute localization in point p
|
/// compute localization in point p
|
||||||
void TangentialSolid (const Point<3> & p, Solid *& tansol, NgArray<int> & surfids, double eps) const;
|
unique_ptr<Solid> TangentialSolid (const Point<3> & p, NgArray<int> & surfids, double eps) const;
|
||||||
|
|
||||||
/// compute localization in point p tangential to vector t
|
/// compute localization in point p tangential to vector t
|
||||||
void TangentialSolid2 (const Point<3> & p, const Vec<3> & t,
|
unique_ptr<Solid> TangentialSolid2 (const Point<3> & p, const Vec<3> & t,
|
||||||
Solid *& tansol, NgArray<int> & surfids, double eps) const;
|
NgArray<int> & surfids, double eps) const;
|
||||||
|
|
||||||
/** compute localization in point p, with second order approximation to edge
|
/** compute localization in point p, with second order approximation to edge
|
||||||
p + s t + s*s/2 t2 **/
|
p + s t + s*s/2 t2 **/
|
||||||
void TangentialSolid3 (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2,
|
unique_ptr<Solid> TangentialSolid3 (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2,
|
||||||
Solid *& tansol, NgArray<int> & surfids, double eps) const;
|
NgArray<int> & surfids, double eps) const;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -133,9 +164,9 @@ namespace netgen
|
|||||||
p + s t + s*s/2 t2 + r m
|
p + s t + s*s/2 t2 + r m
|
||||||
with first order
|
with first order
|
||||||
**/
|
**/
|
||||||
void TangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2,
|
unique_ptr<Solid> TangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2,
|
||||||
const Vec<3> & m,
|
const Vec<3> & m,
|
||||||
Solid *& tansol, NgArray<int> & surfids, double eps) const;
|
NgArray<int> & surfids, double eps) const;
|
||||||
|
|
||||||
|
|
||||||
void CalcOnePrimitiveSpecialPoints (const Box<3> & box, NgArray<Point<3> > & pts) const;
|
void CalcOnePrimitiveSpecialPoints (const Box<3> & box, NgArray<Point<3> > & pts) const;
|
||||||
@ -180,24 +211,24 @@ namespace netgen
|
|||||||
int & in, int & strin) const;
|
int & in, int & strin) const;
|
||||||
///
|
///
|
||||||
void RecTangentialSolid (const Point<3> & p, Solid *& tansol, NgArray<int> & surfids,
|
void RecTangentialSolid (const Point<3> & p, Solid *& tansol, NgArray<int> & surfids,
|
||||||
int & in, int & strin, double eps) const;
|
bool & in, bool & strin, double eps) const;
|
||||||
|
|
||||||
void RecTangentialSolid2 (const Point<3> & p, const Vec<3> & vec,
|
void RecTangentialSolid2 (const Point<3> & p, const Vec<3> & vec,
|
||||||
Solid *& tansol, NgArray<int> & surfids,
|
Solid *& tansol, NgArray<int> & surfids,
|
||||||
int & in, int & strin, double eps) const;
|
bool & in, bool & strin, double eps) const;
|
||||||
///
|
///
|
||||||
void RecTangentialSolid3 (const Point<3> & p, const Vec<3> & vec,const Vec<3> & vec2,
|
void RecTangentialSolid3 (const Point<3> & p, const Vec<3> & vec,const Vec<3> & vec2,
|
||||||
Solid *& tansol, NgArray<int> & surfids,
|
Solid *& tansol, NgArray<int> & surfids,
|
||||||
int & in, int & strin, double eps) const;
|
bool & in, bool & strin, double eps) const;
|
||||||
///
|
///
|
||||||
void RecTangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2,
|
void RecTangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2,
|
||||||
const Vec<3> & m,
|
const Vec<3> & m,
|
||||||
Solid *& tansol, NgArray<int> & surfids,
|
Solid *& tansol, NgArray<int> & surfids,
|
||||||
int & in, int & strin, double eps) const;
|
bool & in, bool & strin, double eps) const;
|
||||||
|
|
||||||
///
|
///
|
||||||
void RecEdge (const Point<3> & p, const Vec<3> & v,
|
void RecEdge (const Point<3> & p, const Vec<3> & v,
|
||||||
int & in, int & strin, int & faces, double eps) const;
|
bool & in, bool & strin, int & faces, double eps) const;
|
||||||
///
|
///
|
||||||
void CalcSurfaceInverseRec (int inv);
|
void CalcSurfaceInverseRec (int inv);
|
||||||
///
|
///
|
||||||
|
@ -286,36 +286,30 @@ namespace netgen
|
|||||||
dynamic_cast<const Plane*> (geometry->GetSurface(locsurf[k3])),
|
dynamic_cast<const Plane*> (geometry->GetSurface(locsurf[k3])),
|
||||||
pts);
|
pts);
|
||||||
|
|
||||||
for (int j = 0; j < pts.Size(); j++)
|
for (auto pnt : pts)
|
||||||
if (Dist (pts[j], box.Center()) < box.Diam()/2)
|
if (Dist (pnt, box.Center()) < box.Diam()/2)
|
||||||
{
|
{
|
||||||
Solid * tansol;
|
auto tansol = sol -> TangentialSolid (pnt, surfids, 1e-9*size);
|
||||||
sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
|
if (tansol)
|
||||||
|
{
|
||||||
if(!tansol)
|
bool ok1 = false, ok2 = false, ok3 = false;
|
||||||
continue;
|
int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
|
||||||
|
int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
|
||||||
bool ok1 = false, ok2 = false, ok3 = false;
|
int rep3 = geometry->GetSurfaceClassRepresentant(locsurf[k3]);
|
||||||
int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
|
|
||||||
int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
|
for (auto surfid : surfids)
|
||||||
int rep3 = geometry->GetSurfaceClassRepresentant(locsurf[k3]);
|
{
|
||||||
for(int jj=0; jj<surfids.Size(); jj++)
|
int actrep = geometry->GetSurfaceClassRepresentant(surfid);
|
||||||
{
|
if (actrep == rep1) ok1 = true;
|
||||||
int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
|
if (actrep == rep2) ok2 = true;
|
||||||
if(actrep == rep1) ok1 = true;
|
if (actrep == rep3) ok3 = true;
|
||||||
if(actrep == rep2) ok2 = true;
|
}
|
||||||
if(actrep == rep3) ok3 = true;
|
|
||||||
}
|
if (ok1 && ok2 && ok3)
|
||||||
|
if (AddPoint (pnt, layer))
|
||||||
|
(*testout) << "cross point found, 1: " << pnt << endl;
|
||||||
if (tansol && ok1 && ok2 && ok3)
|
}
|
||||||
// if (sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size))
|
}
|
||||||
{
|
|
||||||
if (AddPoint (pts[j], layer))
|
|
||||||
(*testout) << "cross point found, 1: " << pts[j] << endl;
|
|
||||||
}
|
|
||||||
delete tansol;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -330,39 +324,30 @@ namespace netgen
|
|||||||
qsurf, pts);
|
qsurf, pts);
|
||||||
//(*testout) << "checking pot. crosspoints: " << pts << endl;
|
//(*testout) << "checking pot. crosspoints: " << pts << endl;
|
||||||
|
|
||||||
for (int j = 0; j < pts.Size(); j++)
|
for (auto pnt : pts)
|
||||||
if (Dist (pts[j], box.Center()) < box.Diam()/2)
|
if (Dist (pnt, box.Center()) < box.Diam()/2)
|
||||||
{
|
{
|
||||||
Solid * tansol;
|
auto tansol = sol -> TangentialSolid (pnt, surfids, 1e-9*size);
|
||||||
sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
|
if (tansol)
|
||||||
|
{
|
||||||
if(!tansol)
|
bool ok1 = false, ok2 = false, ok3 = true;//false;
|
||||||
continue;
|
int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
|
||||||
|
int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
|
||||||
bool ok1 = false, ok2 = false, ok3 = true;//false;
|
|
||||||
int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
|
for (auto surfid : surfids)
|
||||||
int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
|
{
|
||||||
//int rep3 = geometry->GetSurfaceClassRepresentant(quadi);
|
int actrep = geometry->GetSurfaceClassRepresentant(surfid);
|
||||||
for(int jj=0; jj<surfids.Size(); jj++)
|
if (actrep == rep1) ok1 = true;
|
||||||
{
|
if (actrep == rep2) ok2 = true;
|
||||||
int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
|
}
|
||||||
if(actrep == rep1) ok1 = true;
|
|
||||||
if(actrep == rep2) ok2 = true;
|
if (ok1 && ok2 && ok3)
|
||||||
//if(actrep == rep3) ok3 = true;
|
if (AddPoint (pnt, layer))
|
||||||
}
|
(*testout) << "cross point found, 2: " << pnt << endl;
|
||||||
|
}
|
||||||
|
|
||||||
if (tansol && ok1 && ok2 && ok3)
|
|
||||||
//if (sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size) )
|
|
||||||
{
|
|
||||||
if (AddPoint (pts[j], layer))
|
|
||||||
(*testout) << "cross point found, 2: " << pts[j] << endl;
|
|
||||||
}
|
|
||||||
delete tansol;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (int k1 = 0; k1 < numprim; k1++)
|
for (int k1 = 0; k1 < numprim; k1++)
|
||||||
if (k1 != quadi)
|
if (k1 != quadi)
|
||||||
{
|
{
|
||||||
@ -372,15 +357,10 @@ namespace netgen
|
|||||||
for (int j = 0; j < pts.Size(); j++)
|
for (int j = 0; j < pts.Size(); j++)
|
||||||
if (Dist (pts[j], box.Center()) < box.Diam()/2)
|
if (Dist (pts[j], box.Center()) < box.Diam()/2)
|
||||||
{
|
{
|
||||||
Solid * tansol;
|
auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size);
|
||||||
sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
|
|
||||||
if (tansol)
|
if (tansol)
|
||||||
// sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size) )
|
if (AddPoint (pts[j], layer))
|
||||||
{
|
(*testout) << "extremal point found, 1: " << pts[j] << endl;
|
||||||
if (AddPoint (pts[j], layer))
|
|
||||||
(*testout) << "extremal point found, 1: " << pts[j] << endl;
|
|
||||||
}
|
|
||||||
delete tansol;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -395,8 +375,6 @@ namespace netgen
|
|||||||
NgArray<Point<3> > pts;
|
NgArray<Point<3> > pts;
|
||||||
NgArray<int> surfids;
|
NgArray<int> surfids;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (int k1 = 0; k1 < numprim; k1++)
|
for (int k1 = 0; k1 < numprim; k1++)
|
||||||
for (int k2 = 0; k2 < k1; k2++)
|
for (int k2 = 0; k2 < k1; k2++)
|
||||||
for (int k3 = 0; k3 < k2; k3++)
|
for (int k3 = 0; k3 < k2; k3++)
|
||||||
@ -409,16 +387,14 @@ namespace netgen
|
|||||||
for (int j = 0; j < pts.Size(); j++)
|
for (int j = 0; j < pts.Size(); j++)
|
||||||
if (Dist (pts[j], box.Center()) < box.Diam()/2)
|
if (Dist (pts[j], box.Center()) < box.Diam()/2)
|
||||||
{
|
{
|
||||||
Solid * tansol;
|
auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size);
|
||||||
sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
|
if (!tansol) continue;
|
||||||
|
|
||||||
if(!tansol)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bool ok1 = false, ok2 = false, ok3 = false;
|
bool ok1 = false, ok2 = false, ok3 = false;
|
||||||
int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
|
int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
|
||||||
int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
|
int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
|
||||||
int rep3 = geometry->GetSurfaceClassRepresentant(locsurf[k3]);
|
int rep3 = geometry->GetSurfaceClassRepresentant(locsurf[k3]);
|
||||||
|
|
||||||
for(int jj=0; jj<surfids.Size(); jj++)
|
for(int jj=0; jj<surfids.Size(); jj++)
|
||||||
{
|
{
|
||||||
int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
|
int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
|
||||||
@ -427,14 +403,9 @@ namespace netgen
|
|||||||
if(actrep == rep3) ok3 = true;
|
if(actrep == rep3) ok3 = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ok1 && ok2 && ok3)
|
||||||
if (tansol && ok1 && ok2 && ok3)
|
if (AddPoint (pts[j], layer))
|
||||||
// if (sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size))
|
(*testout) << "cross point found, 1: " << pts[j] << endl;
|
||||||
{
|
|
||||||
if (AddPoint (pts[j], layer))
|
|
||||||
(*testout) << "cross point found, 1: " << pts[j] << endl;
|
|
||||||
}
|
|
||||||
delete tansol;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -449,23 +420,37 @@ namespace netgen
|
|||||||
for (int j = 0; j < pts.Size(); j++)
|
for (int j = 0; j < pts.Size(); j++)
|
||||||
if (Dist (pts[j], box.Center()) < box.Diam()/2)
|
if (Dist (pts[j], box.Center()) < box.Diam()/2)
|
||||||
{
|
{
|
||||||
Solid * tansol;
|
auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size);
|
||||||
sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
|
|
||||||
if (tansol)
|
if (tansol)
|
||||||
// sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size) )
|
if (AddPoint (pts[j], layer))
|
||||||
{
|
(*testout) << "extremal point found, spheres: " << pts[j] << endl;
|
||||||
if (AddPoint (pts[j], layer))
|
|
||||||
(*testout) << "extremal point found, spheres: " << pts[j] << endl;
|
|
||||||
}
|
|
||||||
delete tansol;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
if (numprim == 2)
|
||||||
|
{
|
||||||
|
auto rev0 = dynamic_cast<const RevolutionFace*> (geometry->GetSurface(locsurf[0]));
|
||||||
|
auto rev1 = dynamic_cast<const RevolutionFace*> (geometry->GetSurface(locsurf[1]));
|
||||||
|
if (rev0 && rev1)
|
||||||
|
{
|
||||||
|
NgArray<Point<3>> pts;
|
||||||
|
bool check = ComputeExtremalPoints (rev0, rev1, pts);
|
||||||
|
if (check)
|
||||||
|
{
|
||||||
|
for (auto p : pts)
|
||||||
|
if (box.IsIn(p))
|
||||||
|
AddPoint (p, layer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end if (numprim <= check_crosspoint)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
possiblecrossp = (numprim >= 3) && calccp;
|
possiblecrossp = (numprim >= 3) && calccp;
|
||||||
surecrossp = 0;
|
surecrossp = 0;
|
||||||
@ -494,7 +479,6 @@ namespace netgen
|
|||||||
(*testout) << "k1,2,3 = " << k1 << "," << k2 << "," << k3 << ", nc = " << nc << ", deg = " << deg << endl;
|
(*testout) << "k1,2,3 = " << k1 << "," << k2 << "," << k3 << ", nc = " << nc << ", deg = " << deg << endl;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
if (!nc && !deg) decision = 0;
|
if (!nc && !deg) decision = 0;
|
||||||
if (nc) surecrossp = 1;
|
if (nc) surecrossp = 1;
|
||||||
}
|
}
|
||||||
@ -608,9 +592,9 @@ namespace netgen
|
|||||||
decision = 0;
|
decision = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef DEVELOP
|
||||||
// (*testout) << "l = " << level << " dec/sureexp = " << decision << sureexp << endl;
|
(*testout) << "edgepnt decision = " << decision << " sure = " << sureexp << endl;
|
||||||
|
#endif
|
||||||
if (decision && sureexp)
|
if (decision && sureexp)
|
||||||
{
|
{
|
||||||
for (int k1 = 0; k1 < locsurf.Size() - 1; k1++)
|
for (int k1 = 0; k1 < locsurf.Size() - 1; k1++)
|
||||||
@ -890,9 +874,18 @@ namespace netgen
|
|||||||
f1->CalcGradient (p, g1);
|
f1->CalcGradient (p, g1);
|
||||||
f2->CalcGradient (p, g2);
|
f2->CalcGradient (p, g2);
|
||||||
|
|
||||||
if ( sqr (g1 * g2) > (1 - 1e-10) * Abs2 (g1) * Abs2 (g2))
|
// if ( sqr (g1 * g2) > (1 - 1e-10) * Abs2 (g1) * Abs2 (g2))
|
||||||
return 1;
|
// return 1;
|
||||||
|
if ( Abs2 (Cross(g1,g2)) < 1e-10 * Abs2 (g1) * Abs2 (g2)) // same, but stable
|
||||||
|
{
|
||||||
|
if (Abs2(vrs) < 1e-12*sqr(size)) // degenerate only if on both surfaces
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (int j = 0; j < 3; j++)
|
for (int j = 0; j < 3; j++)
|
||||||
{
|
{
|
||||||
mat(0,j) = g1(j);
|
mat(0,j) = g1(j);
|
||||||
@ -1534,7 +1527,61 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool SpecialPointCalculation ::
|
||||||
|
ComputeExtremalPoints (const RevolutionFace * rev1,
|
||||||
|
const RevolutionFace * rev2,
|
||||||
|
NgArray<Point<3> > & pts)
|
||||||
|
{
|
||||||
|
// if (rev1 -> P0() != rev2 -> P0()) return false; // missing ????
|
||||||
|
if (Dist2 (rev1 -> P0(), rev2 -> P0()) > 1e-20*sqr(size)) return false;
|
||||||
|
// if (rev1 -> Axis() != rev2 -> Axis()) return false;
|
||||||
|
if ( (rev1 -> Axis()-rev2 -> Axis()).Length2() > 1e-16) return false;
|
||||||
|
|
||||||
|
Point<2> p1s = rev1->GetSpline().StartPI();
|
||||||
|
Point<2> p1e = rev1->GetSpline().EndPI();
|
||||||
|
Point<2> p2s = rev2->GetSpline().StartPI();
|
||||||
|
Point<2> p2e = rev2->GetSpline().EndPI();
|
||||||
|
|
||||||
|
Point<2> p2d;
|
||||||
|
if (Dist2(p1s,p2e) < 1e-20*sqr(size))
|
||||||
|
p2d = p1s;
|
||||||
|
else if (Dist2(p1e, p2s) < 1e-20*sqr(size))
|
||||||
|
p2d = p1e;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
*testout << "Norm axis = " << rev1->Axis().Length() << endl;
|
||||||
|
Point<3> center = rev1->P0() + p2d(0)*rev1->Axis();
|
||||||
|
Vec<3> n = rev1->Axis();
|
||||||
|
// extremal points of circle, center, normal axis, radius p2d(1)
|
||||||
|
// Lagrange:
|
||||||
|
// L(x, lam1, lam2) = x_i + lam1 * (x-c)*v + lam2 * ( |x-c|^2 - r^2 )
|
||||||
|
for (double i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
double lam1 = -n(i) / n.Length2();
|
||||||
|
Vec<3> ei(0,0,0); ei(i) = 1;
|
||||||
|
// double lam2 = 1/(2*p2d(1)) * sqrt(1 - sqr(n(i))/n.Length2());
|
||||||
|
double fac = 1-sqr(n(i))/n.Length2();
|
||||||
|
// if (fabs(lam2) > 1e-10)
|
||||||
|
if (fac > 1e-10)
|
||||||
|
{
|
||||||
|
double lam2 = 1/(2*p2d(1)) * sqrt(fac);
|
||||||
|
Point<3> x = center - 1.0/(2*lam2) * (ei + lam1*n);
|
||||||
|
pts.Append (x);
|
||||||
|
x = center + 1.0/(2*lam2) * (ei + lam1*n);
|
||||||
|
pts.Append (x);
|
||||||
|
|
||||||
|
/*
|
||||||
|
// check:
|
||||||
|
Point<2> p2d;
|
||||||
|
rev1 -> CalcProj (x, p2d);
|
||||||
|
*testout << "special solution, p2d = " << p2d << endl;
|
||||||
|
rev2 -> CalcProj (x, p2d);
|
||||||
|
*testout << "special solution, p2d = " << p2d << endl;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1739,9 +1786,7 @@ namespace netgen
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
Solid * locsol;
|
auto locsol = sol -> TangentialSolid (p, surfind, ideps*geomsize);
|
||||||
sol -> TangentialSolid (p, locsol, surfind, ideps*geomsize);
|
|
||||||
|
|
||||||
|
|
||||||
rep_surfind.SetSize (surfind.Size());
|
rep_surfind.SetSize (surfind.Size());
|
||||||
int num_indep_surfs = 0;
|
int num_indep_surfs = 0;
|
||||||
@ -1769,10 +1814,10 @@ namespace netgen
|
|||||||
if (surf)
|
if (surf)
|
||||||
{
|
{
|
||||||
// locsol -> GetSurfaceIndices (surfind);
|
// locsol -> GetSurfaceIndices (surfind);
|
||||||
bool hassurf = 0;
|
bool hassurf = false;
|
||||||
for (int m = 0; m < surfind.Size(); m++)
|
for (int m = 0; m < surfind.Size(); m++)
|
||||||
if (ageometry.GetSurface(surfind[m]) == surf)
|
if (ageometry.GetSurface(surfind[m]) == surf)
|
||||||
hassurf = 1;
|
hassurf = true;
|
||||||
|
|
||||||
if (!hassurf)
|
if (!hassurf)
|
||||||
continue;
|
continue;
|
||||||
@ -1818,8 +1863,11 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (Abs2 (t) < 1e-8)
|
if (Abs2 (t) < 1e-16)
|
||||||
continue;
|
{
|
||||||
|
// cerr << "normal vectors degenerated" << endl;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEVELOP
|
#ifdef DEVELOP
|
||||||
*testout << " tangential vector " << t << endl;
|
*testout << " tangential vector " << t << endl;
|
||||||
@ -1860,17 +1908,17 @@ namespace netgen
|
|||||||
rhs(0) = -t * (hessej * t);
|
rhs(0) = -t * (hessej * t);
|
||||||
rhs(1) = -t * (hessek * t);
|
rhs(1) = -t * (hessek * t);
|
||||||
|
|
||||||
CalcInverse (mat, inv);
|
CalcInverse (mat, inv);
|
||||||
t2 = inv * rhs;
|
t2 = inv * rhs;
|
||||||
|
#ifdef DEVELOP
|
||||||
|
*testout << "t = " << t << ", t2 = " << t2 << endl;
|
||||||
|
#endif
|
||||||
/*
|
/*
|
||||||
ageometry.GetIndependentSurfaceIndices
|
ageometry.GetIndependentSurfaceIndices
|
||||||
(locsol, p, t, surfind2);
|
(locsol, p, t, surfind2);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Solid * locsol2;
|
auto locsol2 = locsol -> TangentialSolid3 (p, t, t2, surfind2, ideps*geomsize);
|
||||||
locsol -> TangentialSolid3 (p, t, t2, locsol2, surfind2, ideps*geomsize);
|
|
||||||
if (!locsol2) continue;
|
if (!locsol2) continue;
|
||||||
|
|
||||||
// locsol2 -> GetTangentialSurfaceIndices3 (p, t, t2, surfind2, 1e-9*geomsize);
|
// locsol2 -> GetTangentialSurfaceIndices3 (p, t, t2, surfind2, 1e-9*geomsize);
|
||||||
@ -1911,31 +1959,31 @@ namespace netgen
|
|||||||
Vec<3> nv =
|
Vec<3> nv =
|
||||||
ageometry.GetSurface(surfind2[l]) -> GetNormalVector(p);
|
ageometry.GetSurface(surfind2[l]) -> GetNormalVector(p);
|
||||||
|
|
||||||
|
|
||||||
Vec<3> m1 = Cross (t, nv);
|
Vec<3> m1 = Cross (t, nv);
|
||||||
Vec<3> m2 = -m1;
|
Vec<3> m2 = -m1;
|
||||||
bool isface1 = 0, isface2 = 0;
|
bool isface1 = 0, isface2 = 0;
|
||||||
|
|
||||||
Solid * locsol3;
|
|
||||||
|
|
||||||
// locsol2 -> TangentialSolid2 (p, m1, locsol3, surfind3, 1e-9*geomsize);
|
// locsol2 -> TangentialSolid2 (p, m1, locsol3, surfind3, 1e-9*geomsize);
|
||||||
locsol -> TangentialEdgeSolid (p, t, t2, m1, locsol3, surfind3, ideps*geomsize);
|
auto locsol3 = locsol -> TangentialEdgeSolid (p, t, t2, m1, surfind3, ideps*geomsize);
|
||||||
|
#ifdef DEVELOP
|
||||||
|
(*testout) << "m1 = " << m1 << ", surfind3 = " << surfind3 << endl;
|
||||||
|
#endif
|
||||||
//ageometry.GetIndependentSurfaceIndices (surfind3);
|
//ageometry.GetIndependentSurfaceIndices (surfind3);
|
||||||
|
|
||||||
if (surfind3.Contains(surfind2[l]))
|
if (surfind3.Contains(surfind2[l]))
|
||||||
isface1 = 1;
|
isface1 = 1;
|
||||||
delete locsol3;
|
|
||||||
|
|
||||||
// locsol2 -> TangentialSolid2 (p, m2, locsol3, surfind3, 1e-9*geomsize);
|
// locsol2 -> TangentialSolid2 (p, m2, locsol3, surfind3, 1e-9*geomsize);
|
||||||
locsol -> TangentialEdgeSolid (p, t, t2, m2, locsol3, surfind3, ideps*geomsize);
|
locsol3 = locsol -> TangentialEdgeSolid (p, t, t2, m2, surfind3, ideps*geomsize);
|
||||||
|
#ifdef DEVELOP
|
||||||
|
(*testout) << "m2 = " << m2 << ", surfind3 = " << surfind3 << endl;
|
||||||
|
#endif
|
||||||
|
|
||||||
// ageometry.GetIndependentSurfaceIndices (surfind3);
|
// ageometry.GetIndependentSurfaceIndices (surfind3);
|
||||||
|
|
||||||
|
|
||||||
if (surfind3.Contains(surfind2[l]))
|
if (surfind3.Contains(surfind2[l]))
|
||||||
isface2 = 1;
|
isface2 = 1;
|
||||||
delete locsol3;
|
|
||||||
|
|
||||||
if (isface1 != isface2)
|
if (isface1 != isface2)
|
||||||
cnt_tang_faces++;
|
cnt_tang_faces++;
|
||||||
@ -1948,7 +1996,6 @@ namespace netgen
|
|||||||
if (cnt_tang_faces < 1)
|
if (cnt_tang_faces < 1)
|
||||||
ok = false;
|
ok = false;
|
||||||
|
|
||||||
delete locsol2;
|
|
||||||
if (!ok) continue;
|
if (!ok) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1973,16 +2020,47 @@ namespace netgen
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
Vec<3> s = Cross (normalvecs[m], t);
|
Vec<3> s = Cross (normalvecs[m], t);
|
||||||
|
|
||||||
Vec<3> t2a = t + 0.01 *s;
|
Vec<3> t2a = t + 0.01 *s;
|
||||||
Vec<3> t2b = t - 0.01 *s;
|
Vec<3> t2b = t - 0.01 *s;
|
||||||
|
|
||||||
bool isface =
|
bool isfaceold =
|
||||||
(locsol->VectorIn (p, t2a, 1e-6*geomsize) &&
|
(locsol->VectorIn (p, t2a, 1e-6*geomsize) &&
|
||||||
!locsol->VectorStrictIn (p, t2a, 1e-6*geomsize))
|
!locsol->VectorStrictIn (p, t2a, 1e-6*geomsize))
|
||||||
||
|
||
|
||||||
(locsol->VectorIn (p, t2b, 1e-6*geomsize) &&
|
(locsol->VectorIn (p, t2b, 1e-6*geomsize) &&
|
||||||
!locsol->VectorStrictIn (p, t2b, 1e-6*geomsize));
|
!locsol->VectorStrictIn (p, t2b, 1e-6*geomsize));
|
||||||
|
|
||||||
|
bool isfacenew =
|
||||||
|
locsol -> VecInSolid2(p, t, s, 1e-6*geomsize) == DOES_INTERSECT ||
|
||||||
|
locsol -> VecInSolid2(p, t, -s, 1e-6*geomsize) == DOES_INTERSECT;
|
||||||
|
/*
|
||||||
|
(locsol->VectorIn2 (p, t, s, 1e-6*geomsize) && !locsol->VectorStrictIn2 (p, t, s, 1e-6*geomsize)) ||
|
||||||
|
(locsol->VectorIn2 (p, t, -s, 1e-6*geomsize) && !locsol->VectorStrictIn2 (p, t, -s, 1e-6*geomsize));
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool isface = isfacenew;
|
||||||
|
|
||||||
|
if (isfaceold != isfacenew)
|
||||||
|
{
|
||||||
|
*testout << "different, p = " << p << ", t = " << t << ", s = " << s << endl;
|
||||||
|
*testout << "tlo = " << si << endl;
|
||||||
|
*testout << "isface, old = " << isface << ", isfacenew = " << isfacenew << endl;
|
||||||
|
|
||||||
|
*testout << "t2a = " << t2a << endl;
|
||||||
|
*testout << "vecin(p,t2a) = " << locsol->VectorIn (p, t2a, 1e-6*geomsize) << endl;
|
||||||
|
*testout << "vecstrictin(p,t2a) = " << locsol->VectorStrictIn (p, t2a, 1e-6*geomsize) << endl;
|
||||||
|
*testout << "vectorin2 = " << locsol->VectorIn2 (p, t, s, 1e-6*geomsize) << endl;
|
||||||
|
*testout << "vectorstrictin2 = " << locsol->VectorStrictIn2 (p, t, s, 1e-6*geomsize) << endl;
|
||||||
|
|
||||||
|
*testout << "t2b = " << t2b << endl;
|
||||||
|
*testout << "vecin(p,t2b) = " << locsol->VectorIn (p, t2b, 1e-6*geomsize) << endl;
|
||||||
|
*testout << "vecstrictin(p,t2b) = " << locsol->VectorStrictIn (p, t2b, 1e-6*geomsize) << endl;
|
||||||
|
*testout << "vectorin2- = " << locsol->VectorIn2 (p, t, -s, 1e-6*geomsize) << endl;
|
||||||
|
*testout << "vectorstrictin2- = " << locsol->VectorStrictIn2 (p, t, -s, 1e-6*geomsize) << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bool isface =
|
bool isface =
|
||||||
(locsol->VectorIn (p, t2a) &&
|
(locsol->VectorIn (p, t2a) &&
|
||||||
@ -1992,10 +2070,8 @@ namespace netgen
|
|||||||
!locsol->VectorStrictIn (p, t2b));
|
!locsol->VectorStrictIn (p, t2b));
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (isface)
|
if (isface)
|
||||||
{
|
cnts++;
|
||||||
cnts++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (cnts < 2) isedge = 0;
|
if (cnts < 2) isedge = 0;
|
||||||
}
|
}
|
||||||
@ -2054,54 +2130,22 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
delete locsol;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
NgBitArray testuncond (specpoints.Size());
|
|
||||||
testuncond.Clear();
|
|
||||||
for(int i = 0; i<specpoints.Size(); i++)
|
|
||||||
{
|
|
||||||
if(testuncond.Test(i))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
NgArray<int> same;
|
|
||||||
same.Append(i);
|
|
||||||
|
|
||||||
for(int j = i+1; j<specpoints.Size(); j++)
|
|
||||||
{
|
|
||||||
if(Dist(specpoints[i].p,specpoints[j].p) < 1e-20)
|
|
||||||
{
|
|
||||||
same.Append(j);
|
|
||||||
testuncond.Set(j);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(same.Size() < 3)
|
|
||||||
for(int j=0; j<same.Size(); j++)
|
|
||||||
{
|
|
||||||
(*testout) << "setting " << specpoints[same[j]].p << "; " << specpoints[same[j]].v << "; "
|
|
||||||
<<specpoints[same[j]].unconditional << " to conditional" << endl;
|
|
||||||
specpoints[same[j]].unconditional=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// if special point is unconditional on some solid,
|
// if special point is unconditional on some solid,
|
||||||
// it must be unconditional everywhere:
|
// it must be unconditional everywhere:
|
||||||
|
|
||||||
NgBitArray uncond (apoints.Size());
|
BitArray uncond (apoints.Size());
|
||||||
uncond.Clear();
|
uncond.Clear();
|
||||||
|
|
||||||
for (int i = 0; i < specpoints.Size(); i++)
|
for (int i = 0; i < specpoints.Size(); i++)
|
||||||
if (specpoints[i].unconditional)
|
if (specpoints[i].unconditional)
|
||||||
uncond.Set (specpoint2point[i]);
|
uncond.SetBit (specpoint2point[i]);
|
||||||
|
|
||||||
for (int i = 0; i < specpoints.Size(); i++)
|
for (int i = 0; i < specpoints.Size(); i++)
|
||||||
specpoints[i].unconditional =
|
specpoints[i].unconditional = uncond.Test (specpoint2point[i]);
|
||||||
uncond.Test (specpoint2point[i]) ? 1 : 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -167,6 +167,9 @@ namespace netgen
|
|||||||
const Sphere * sphere2,
|
const Sphere * sphere2,
|
||||||
NgArray<Point<3> > & pts);
|
NgArray<Point<3> > & pts);
|
||||||
|
|
||||||
|
bool ComputeExtremalPoints (const RevolutionFace * rev1,
|
||||||
|
const RevolutionFace * rev2,
|
||||||
|
NgArray<Point<3> > & pts);
|
||||||
|
|
||||||
void ComputeCrossPoints (const Plane * plane1,
|
void ComputeCrossPoints (const Plane * plane1,
|
||||||
const Plane * plane2,
|
const Plane * plane2,
|
||||||
|
@ -16,6 +16,7 @@ Surface :: Surface ()
|
|||||||
strcpy (name, "noname");
|
strcpy (name, "noname");
|
||||||
bcprop = -1;
|
bcprop = -1;
|
||||||
bcname = "default";
|
bcname = "default";
|
||||||
|
inverse = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Surface :: ~Surface()
|
Surface :: ~Surface()
|
||||||
@ -427,11 +428,20 @@ VecInSolid2 (const Point<3> & p,
|
|||||||
if (hv1 >= eps)
|
if (hv1 >= eps)
|
||||||
return IS_OUTSIDE;
|
return IS_OUTSIDE;
|
||||||
|
|
||||||
|
double hv2 = v2 * hv;
|
||||||
|
if (hv2 <= -eps)
|
||||||
|
return IS_INSIDE;
|
||||||
|
if (hv2 >= eps)
|
||||||
|
return IS_OUTSIDE;
|
||||||
|
return DOES_INTERSECT;
|
||||||
|
|
||||||
|
/*
|
||||||
double hv2 = v2 * hv;
|
double hv2 = v2 * hv;
|
||||||
if (hv2 <= 0)
|
if (hv2 <= 0)
|
||||||
return IS_INSIDE;
|
return IS_INSIDE;
|
||||||
else
|
else
|
||||||
return IS_OUTSIDE;
|
return IS_OUTSIDE;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -213,8 +213,6 @@ namespace netgen
|
|||||||
INSOLID_TYPE;
|
INSOLID_TYPE;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DummySurface : public Surface
|
class DummySurface : public Surface
|
||||||
{
|
{
|
||||||
virtual double CalcFunctionValue (const Point<3> & /* point */) const
|
virtual double CalcFunctionValue (const Point<3> & /* point */) const
|
||||||
@ -293,9 +291,13 @@ namespace netgen
|
|||||||
const Vec<3> & m,
|
const Vec<3> & m,
|
||||||
double eps) const;
|
double eps) const;
|
||||||
|
|
||||||
|
// for a point p in the surface, into which (closed) surfaces does v point into ?
|
||||||
virtual void GetTangentialVecSurfaceIndices (const Point<3> & p, const Vec<3> & v,
|
virtual void GetTangentialVecSurfaceIndices (const Point<3> & p, const Vec<3> & v,
|
||||||
NgArray<int> & surfind, double eps) const;
|
NgArray<int> & surfind, double eps) const;
|
||||||
|
|
||||||
|
// a point p in the surface, and v a tangential vector
|
||||||
|
// for arbitrary small, but positive t consider q := Project(p+t*v)
|
||||||
|
// into which (closed) surfaces does v2 point into, when starting from q ?
|
||||||
virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
virtual void GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
|
||||||
NgArray<int> & surfind, double eps) const;
|
NgArray<int> & surfind, double eps) const;
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ target_sources(gen INTERFACE
|
|||||||
install(FILES
|
install(FILES
|
||||||
ngarray.hpp autodiff.hpp autoptr.hpp ngbitarray.hpp
|
ngarray.hpp autodiff.hpp autoptr.hpp ngbitarray.hpp
|
||||||
dynamicmem.hpp hashtabl.hpp mpi_interface.hpp myadt.hpp
|
dynamicmem.hpp hashtabl.hpp mpi_interface.hpp myadt.hpp
|
||||||
ngsimd.hpp mystring.hpp netgenout.hpp ngpython.hpp
|
mystring.hpp netgenout.hpp ngpython.hpp
|
||||||
optmem.hpp parthreads.hpp seti.hpp sort.hpp
|
optmem.hpp parthreads.hpp seti.hpp sort.hpp
|
||||||
spbita2d.hpp stack.hpp table.hpp template.hpp
|
spbita2d.hpp stack.hpp table.hpp template.hpp
|
||||||
gzstream.h
|
gzstream.h
|
||||||
|
@ -14,65 +14,8 @@
|
|||||||
|
|
||||||
namespace netgen
|
namespace netgen
|
||||||
{
|
{
|
||||||
// using ngcore::id;
|
|
||||||
// using ngcore::ntasks;
|
|
||||||
|
|
||||||
#ifndef PARALLEL
|
|
||||||
/** without MPI, we need a dummy typedef **/
|
|
||||||
// typedef int MPI_Comm;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/** This is the "standard" communicator that will be used for netgen-objects. **/
|
|
||||||
// extern DLL_HEADER NgMPI_Comm ng_comm;
|
|
||||||
|
|
||||||
#ifdef OLD
|
#ifdef OLD
|
||||||
#ifdef PARALLEL
|
|
||||||
inline int MyMPI_GetNTasks (MPI_Comm comm /* = ng_comm */)
|
|
||||||
{
|
|
||||||
int ntasks;
|
|
||||||
MPI_Comm_size(comm, &ntasks);
|
|
||||||
return ntasks;
|
|
||||||
}
|
|
||||||
inline int MyMPI_GetId (MPI_Comm comm /* = ng_comm */)
|
|
||||||
{
|
|
||||||
int id;
|
|
||||||
MPI_Comm_rank(comm, &id);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
// enum { MPI_COMM_WORLD = 12345, MPI_COMM_NULL = 0};
|
|
||||||
inline int MyMPI_GetNTasks (MPI_Comm comm /* = ng_comm */) { return 1; }
|
|
||||||
inline int MyMPI_GetId (MPI_Comm comm /* = ng_comm */) { return 0; }
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
#ifdef PARALLEL
|
|
||||||
// For python wrapping of communicators
|
|
||||||
struct PyMPI_Comm {
|
|
||||||
MPI_Comm comm;
|
|
||||||
bool owns_comm;
|
|
||||||
PyMPI_Comm (MPI_Comm _comm, bool _owns_comm = false) : comm(_comm), owns_comm(_owns_comm) { }
|
|
||||||
PyMPI_Comm (const PyMPI_Comm & c) = delete;
|
|
||||||
~PyMPI_Comm () {
|
|
||||||
if (owns_comm)
|
|
||||||
MPI_Comm_free(&comm);
|
|
||||||
}
|
|
||||||
inline int Rank() const { return MyMPI_GetId(comm); }
|
|
||||||
inline int Size() const { return MyMPI_GetNTasks(comm); }
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
// dummy without MPI
|
|
||||||
struct PyMPI_Comm {
|
|
||||||
MPI_Comm comm = 0;
|
|
||||||
PyMPI_Comm (MPI_Comm _comm, bool _owns_comm = false) { }
|
|
||||||
~PyMPI_Comm () { }
|
|
||||||
inline int Rank() const { return 0; }
|
|
||||||
inline int Size() const { return 1; }
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef PARALLEL
|
#ifdef PARALLEL
|
||||||
template <class T>
|
template <class T>
|
||||||
inline MPI_Datatype MyGetMPIType ( )
|
inline MPI_Datatype MyGetMPIType ( )
|
||||||
@ -93,32 +36,37 @@ namespace netgen
|
|||||||
typedef int MPI_Datatype;
|
typedef int MPI_Datatype;
|
||||||
template <class T> inline MPI_Datatype MyGetMPIType ( ) { return 0; }
|
template <class T> inline MPI_Datatype MyGetMPIType ( ) { return 0; }
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef PARALLEL
|
#ifdef PARALLEL
|
||||||
enum { MPI_TAG_CMD = 110 };
|
enum { MPI_TAG_CMD = 110 };
|
||||||
enum { MPI_TAG_MESH = 210 };
|
enum { MPI_TAG_MESH = 210 };
|
||||||
enum { MPI_TAG_VIS = 310 };
|
enum { MPI_TAG_VIS = 310 };
|
||||||
|
|
||||||
inline void MyMPI_Send (int i, int dest, int tag, MPI_Comm comm /* = ng_comm */)
|
|
||||||
|
[[deprecated("mympi_send int, use comm.Send instead")]]
|
||||||
|
inline void MyMPI_Send (int i, int dest, int tag, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
int hi = i;
|
int hi = i;
|
||||||
MPI_Send( &hi, 1, MPI_INT, dest, tag, comm);
|
MPI_Send( &hi, 1, MPI_INT, dest, tag, comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MyMPI_Recv (int & i, int src, int tag, MPI_Comm comm /* = ng_comm */)
|
[[deprecated("mympi_revc int, use comm.Recv instead")]]
|
||||||
|
inline void MyMPI_Recv (int & i, int src, int tag, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
MPI_Status status;
|
MPI_Status status;
|
||||||
MPI_Recv( &i, 1, MPI_INT, src, tag, comm, &status);
|
MPI_Recv( &i, 1, MPI_INT, src, tag, comm, &status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[deprecated("mympi_send string, use comm.Send instead")]]
|
||||||
|
inline void MyMPI_Send (const string & s, int dest, int tag, MPI_Comm comm)
|
||||||
inline void MyMPI_Send (const string & s, int dest, int tag, MPI_Comm comm /* = ng_comm */)
|
|
||||||
{
|
{
|
||||||
MPI_Send( const_cast<char*> (s.c_str()), s.length(), MPI_CHAR, dest, tag, comm);
|
MPI_Send( const_cast<char*> (s.c_str()), s.length(), MPI_CHAR, dest, tag, comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void MyMPI_Recv (string & s, int src, int tag, MPI_Comm comm /* = ng_comm */)
|
[[deprecated("mympi_revc string, use comm.Recv instead")]]
|
||||||
|
inline void MyMPI_Recv (string & s, int src, int tag, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
MPI_Status status;
|
MPI_Status status;
|
||||||
int len;
|
int len;
|
||||||
@ -130,34 +78,35 @@ namespace netgen
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <class T, int BASE>
|
template <class T, int BASE>
|
||||||
inline void MyMPI_Send (NgFlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm /* = ng_comm */)
|
[[deprecated("mympi_send ngflatarray, use comm.send instead")]]
|
||||||
|
inline void MyMPI_Send (NgFlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
MPI_Send( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, comm);
|
MPI_Send( &s.First(), s.Size(), GetMPIType<T>(), dest, tag, comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, int BASE>
|
template <class T, int BASE>
|
||||||
inline void MyMPI_Recv ( NgFlatArray<T, BASE> s, int src, int tag, MPI_Comm comm /* = ng_comm */)
|
[[deprecated("mympi_recv ngflatarray, use comm.Recv instead")]]
|
||||||
|
inline void MyMPI_Recv ( NgFlatArray<T, BASE> s, int src, int tag, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
MPI_Status status;
|
MPI_Status status;
|
||||||
MPI_Recv( &s.First(), s.Size(), MyGetMPIType<T>(), src, tag, comm, &status);
|
MPI_Recv( &s.First(), s.Size(), GetMPIType<T>(), src, tag, comm, &status);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, int BASE>
|
template <class T, int BASE>
|
||||||
inline void MyMPI_Recv ( NgArray <T, BASE> & s, int src, int tag, MPI_Comm comm /* = ng_comm */)
|
inline void MyMPI_Recv ( NgArray <T, BASE> & s, int src, int tag, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
MPI_Status status;
|
MPI_Status status;
|
||||||
int len;
|
int len;
|
||||||
MPI_Probe (src, tag, comm, &status);
|
MPI_Probe (src, tag, comm, &status);
|
||||||
MPI_Get_count (&status, MyGetMPIType<T>(), &len);
|
MPI_Get_count (&status, GetMPIType<T>(), &len);
|
||||||
|
|
||||||
s.SetSize (len);
|
s.SetSize (len);
|
||||||
MPI_Recv( &s.First(), len, MyGetMPIType<T>(), src, tag, comm, &status);
|
MPI_Recv( &s.First(), len, GetMPIType<T>(), src, tag, comm, &status);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, int BASE>
|
template <class T, int BASE>
|
||||||
inline int MyMPI_Recv ( NgArray <T, BASE> & s, int tag, MPI_Comm comm /* = ng_comm */)
|
inline int MyMPI_Recv ( NgArray <T, BASE> & s, int tag, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
MPI_Status status;
|
MPI_Status status;
|
||||||
int len;
|
int len;
|
||||||
@ -165,10 +114,10 @@ namespace netgen
|
|||||||
|
|
||||||
int src = status.MPI_SOURCE;
|
int src = status.MPI_SOURCE;
|
||||||
|
|
||||||
MPI_Get_count (&status, MyGetMPIType<T>(), &len);
|
MPI_Get_count (&status, GetMPIType<T>(), &len);
|
||||||
|
|
||||||
s.SetSize (len);
|
s.SetSize (len);
|
||||||
MPI_Recv( &s.First(), len, MyGetMPIType<T>(), src, tag, comm, &status);
|
MPI_Recv( &s.First(), len, GetMPIType<T>(), src, tag, comm, &status);
|
||||||
|
|
||||||
return src;
|
return src;
|
||||||
}
|
}
|
||||||
@ -190,22 +139,23 @@ namespace netgen
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
template <class T, int BASE>
|
template <class T, int BASE>
|
||||||
inline MPI_Request MyMPI_ISend (NgFlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm /* = ng_comm */)
|
[[deprecated("mympi_isend ngflatarray, use comm.send instead")]]
|
||||||
|
inline MPI_Request MyMPI_ISend (NgFlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
MPI_Request request;
|
MPI_Request request;
|
||||||
MPI_Isend( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, comm, &request);
|
MPI_Isend( &s.First(), s.Size(), GetMPIType<T>(), dest, tag, comm, &request);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class T, int BASE>
|
template <class T, int BASE>
|
||||||
inline MPI_Request MyMPI_IRecv (NgFlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm /* = ng_comm */)
|
[[deprecated("mympi_irecv ngflatarray, use comm.recv instead")]]
|
||||||
|
inline MPI_Request MyMPI_IRecv (NgFlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
MPI_Request request;
|
MPI_Request request;
|
||||||
MPI_Irecv( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, comm, &request);
|
MPI_Irecv( &s.First(), s.Size(), GetMPIType<T>(), dest, tag, comm, &request);
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
template <class T, int BASE>
|
template <class T, int BASE>
|
||||||
inline void MyMPI_ISend (NgFlatArray<T, BASE> s, int dest, int tag)
|
inline void MyMPI_ISend (NgFlatArray<T, BASE> s, int dest, int tag)
|
||||||
@ -232,106 +182,59 @@ namespace netgen
|
|||||||
receive-table entries will be set
|
receive-table entries will be set
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void MyMPI_ExchangeTable (TABLE<T> & send_data,
|
inline void MyMPI_ExchangeTable (TABLE<T> & send_data,
|
||||||
TABLE<T> & recv_data, int tag,
|
TABLE<T> & recv_data, int tag,
|
||||||
MPI_Comm comm = MPI_COMM_WORLD)
|
const NgMPI_Comm & comm)
|
||||||
{
|
{
|
||||||
int ntasks, rank;
|
|
||||||
MPI_Comm_size(comm, &ntasks);
|
|
||||||
MPI_Comm_rank(comm, &rank);
|
|
||||||
|
|
||||||
NgArray<MPI_Request> requests;
|
|
||||||
for (int dest = 0; dest < ntasks; dest++)
|
|
||||||
if (dest != rank)
|
|
||||||
requests.Append (MyMPI_ISend (send_data[dest], dest, tag, comm));
|
|
||||||
|
|
||||||
for (int i = 0; i < ntasks-1; i++)
|
|
||||||
{
|
|
||||||
MPI_Status status;
|
|
||||||
MPI_Probe (MPI_ANY_SOURCE, tag, comm, &status);
|
|
||||||
int size, src = status.MPI_SOURCE;
|
|
||||||
MPI_Get_count (&status, MPI_INT, &size);
|
|
||||||
recv_data.SetEntrySize (src, size, sizeof(T));
|
|
||||||
requests.Append (MyMPI_IRecv (recv_data[src], src, tag, comm));
|
|
||||||
}
|
|
||||||
MPI_Barrier (comm);
|
|
||||||
MPI_Waitall (requests.Size(), &requests[0], MPI_STATUS_IGNORE);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
inline void MyMPI_ExchangeTable (TABLE<T> & send_data,
|
|
||||||
TABLE<T> & recv_data, int tag,
|
|
||||||
const NgMPI_Comm & comm /* = ng_comm */)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
int rank = MyMPI_GetId(comm);
|
|
||||||
int ntasks = MyMPI_GetNTasks(comm);
|
|
||||||
*/
|
|
||||||
int rank = comm.Rank();
|
int rank = comm.Rank();
|
||||||
int ntasks = comm.Size();
|
int ntasks = comm.Size();
|
||||||
|
|
||||||
NgArray<int> send_sizes(ntasks);
|
Array<int> send_sizes(ntasks);
|
||||||
NgArray<int> recv_sizes(ntasks);
|
Array<int> recv_sizes(ntasks);
|
||||||
for (int i = 0; i < ntasks; i++)
|
for (int i = 0; i < ntasks; i++)
|
||||||
send_sizes[i] = send_data[i].Size();
|
send_sizes[i] = send_data[i].Size();
|
||||||
|
|
||||||
|
comm.AllToAll (send_sizes, recv_sizes);
|
||||||
|
|
||||||
MPI_Alltoall (&send_sizes[0], 1, MPI_INT,
|
|
||||||
&recv_sizes[0], 1, MPI_INT, comm);
|
|
||||||
|
|
||||||
// in-place is buggy !
|
|
||||||
// MPI_Alltoall (MPI_IN_PLACE, 1, MPI_INT,
|
|
||||||
// &recv_sizes[0], 1, MPI_INT, comm);
|
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < ntasks; i++)
|
for (int i = 0; i < ntasks; i++)
|
||||||
recv_data.SetEntrySize (i, recv_sizes[i], sizeof(T));
|
recv_data.SetEntrySize (i, recv_sizes[i], sizeof(T));
|
||||||
|
|
||||||
NgArray<MPI_Request> requests;
|
Array<MPI_Request> requests;
|
||||||
for (int dest = 0; dest < ntasks; dest++)
|
for (int dest = 0; dest < ntasks; dest++)
|
||||||
if (dest != rank && send_data[dest].Size())
|
if (dest != rank && send_data[dest].Size())
|
||||||
requests.Append (MyMPI_ISend (send_data[dest], dest, tag, comm));
|
requests.Append (comm.ISend (FlatArray<T>(send_data[dest]), dest, tag));
|
||||||
|
|
||||||
for (int dest = 0; dest < ntasks; dest++)
|
for (int dest = 0; dest < ntasks; dest++)
|
||||||
if (dest != rank && recv_data[dest].Size())
|
if (dest != rank && recv_data[dest].Size())
|
||||||
requests.Append (MyMPI_IRecv (recv_data[dest], dest, tag, comm));
|
requests.Append (comm.IRecv (FlatArray<T>(recv_data[dest]), dest, tag));
|
||||||
|
|
||||||
// MPI_Barrier (comm);
|
MyMPI_WaitAll (requests);
|
||||||
MPI_Waitall (requests.Size(), &requests[0], MPI_STATUS_IGNORE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
extern void MyMPI_SendCmd (const char * cmd);
|
extern void MyMPI_SendCmd (const char * cmd);
|
||||||
extern string MyMPI_RecvCmd ();
|
extern string MyMPI_RecvCmd ();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void MyMPI_Bcast (T & s, MPI_Comm comm /* = ng_comm */)
|
inline void MyMPI_Bcast (T & s, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
MPI_Bcast (&s, 1, MyGetMPIType<T>(), 0, comm);
|
MPI_Bcast (&s, 1, GetMPIType<T>(), 0, comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void MyMPI_Bcast (NgArray<T, 0> & s, NgMPI_Comm comm /* = ng_comm */)
|
inline void MyMPI_Bcast (NgArray<T, 0> & s, NgMPI_Comm comm)
|
||||||
{
|
{
|
||||||
int size = s.Size();
|
int size = s.Size();
|
||||||
MyMPI_Bcast (size, comm);
|
MyMPI_Bcast (size, comm);
|
||||||
// if (MyMPI_GetId(comm) != 0) s.SetSize (size);
|
// if (MyMPI_GetId(comm) != 0) s.SetSize (size);
|
||||||
if (comm.Rank() != 0) s.SetSize (size);
|
if (comm.Rank() != 0) s.SetSize (size);
|
||||||
MPI_Bcast (&s[0], size, MyGetMPIType<T>(), 0, comm);
|
MPI_Bcast (&s[0], size, GetMPIType<T>(), 0, comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
inline void MyMPI_Bcast (NgArray<T, 0> & s, int root, MPI_Comm comm /* = ng_comm */)
|
inline void MyMPI_Bcast (NgArray<T, 0> & s, int root, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
MPI_Comm_rank(comm, &id);
|
MPI_Comm_rank(comm, &id);
|
||||||
@ -340,67 +243,23 @@ namespace netgen
|
|||||||
MPI_Bcast (&size, 1, MPI_INT, root, comm);
|
MPI_Bcast (&size, 1, MPI_INT, root, comm);
|
||||||
if (id != root) s.SetSize (size);
|
if (id != root) s.SetSize (size);
|
||||||
if ( !size ) return;
|
if ( !size ) return;
|
||||||
MPI_Bcast (&s[0], size, MyGetMPIType<T>(), root, comm);
|
MPI_Bcast (&s[0], size, GetMPIType<T>(), root, comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class T2>
|
template <class T, class T2>
|
||||||
inline void MyMPI_Allgather (const T & send, NgFlatArray<T2> recv, MPI_Comm comm /* = ng_comm */)
|
[[deprecated("mympi_allgather deprecated, use comm.allgather")]]
|
||||||
|
inline void MyMPI_Allgather (const T & send, NgFlatArray<T2> recv, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
MPI_Allgather( const_cast<T*> (&send), 1, MyGetMPIType<T>(), &recv[0], 1, MyGetMPIType<T2>(), comm);
|
MPI_Allgather( const_cast<T*> (&send), 1, GetMPIType<T>(), &recv[0], 1, GetMPIType<T2>(), comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class T2>
|
template <class T, class T2>
|
||||||
inline void MyMPI_Alltoall (NgFlatArray<T> send, NgFlatArray<T2> recv, MPI_Comm comm /* = ng_comm */)
|
[[deprecated("mympi_alltoall deprecated, use comm.alltoall")]]
|
||||||
|
inline void MyMPI_Alltoall (NgFlatArray<T> send, NgFlatArray<T2> recv, MPI_Comm comm)
|
||||||
{
|
{
|
||||||
MPI_Alltoall( &send[0], 1, MyGetMPIType<T>(), &recv[0], 1, MyGetMPIType<T2>(), comm);
|
MPI_Alltoall( &send[0], 1, GetMPIType<T>(), &recv[0], 1, GetMPIType<T2>(), comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
// template <class T, class T2>
|
|
||||||
// inline void MyMPI_Alltoall_Block (NgFlatArray<T> send, NgFlatArray<T2> recv, int blocklen, MPI_Comm comm = ng_comm)
|
|
||||||
// {
|
|
||||||
// MPI_Alltoall( &send[0], blocklen, MyGetMPIType<T>(), &recv[0], blocklen, MyGetMPIType<T2>(), comm);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
inline void MyMPI_Send ( int *& s, int len, int dest, int tag)
|
|
||||||
{
|
|
||||||
int hlen = len;
|
|
||||||
MPI_Send( &hlen, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
|
|
||||||
MPI_Send( s, len, MPI_INT, dest, tag, MPI_COMM_WORLD);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void MyMPI_Recv ( int *& s, int & len, int src, int tag)
|
|
||||||
{
|
|
||||||
MPI_Status status;
|
|
||||||
MPI_Recv( &len, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
|
|
||||||
if ( s )
|
|
||||||
delete [] s;
|
|
||||||
s = new int [len];
|
|
||||||
MPI_Recv( s, len, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline void MyMPI_Send ( double * s, int len, int dest, int tag)
|
|
||||||
{
|
|
||||||
MPI_Send( &len, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
|
|
||||||
MPI_Send( s, len, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void MyMPI_Recv ( double *& s, int & len, int src, int tag)
|
|
||||||
{
|
|
||||||
MPI_Status status;
|
|
||||||
MPI_Recv( &len, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
|
|
||||||
if ( s )
|
|
||||||
delete [] s;
|
|
||||||
s = new double [len];
|
|
||||||
MPI_Recv( s, len, MPI_DOUBLE, src, tag, MPI_COMM_WORLD, &status);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
#endif // PARALLEL
|
#endif // PARALLEL
|
||||||
|
|
||||||
|
@ -47,7 +47,5 @@ namespace netgen
|
|||||||
#include "netgenout.hpp"
|
#include "netgenout.hpp"
|
||||||
#include "gzstream.h"
|
#include "gzstream.h"
|
||||||
|
|
||||||
#include "ngsimd.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -205,6 +205,12 @@ namespace netgen
|
|||||||
{
|
{
|
||||||
return ( Pos(elem) >= 0 );
|
return ( Pos(elem) >= 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
operator FlatArray<T> () const
|
||||||
|
{
|
||||||
|
static_assert (BASE==0);
|
||||||
|
return FlatArray<T>(size, data);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -730,7 +736,7 @@ namespace netgen
|
|||||||
|
|
||||||
/// bubble sort array
|
/// bubble sort array
|
||||||
template <class T, class S>
|
template <class T, class S>
|
||||||
inline void BubbleSort (NgFlatArray<T> & data, NgFlatArray<S> & slave)
|
inline void BubbleSort (NgFlatArray<T> & data, NgFlatArray<S> & index)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < data.Size(); i++)
|
for (int i = 0; i < data.Size(); i++)
|
||||||
for (int j = i+1; j < data.Size(); j++)
|
for (int j = i+1; j < data.Size(); j++)
|
||||||
@ -740,16 +746,16 @@ namespace netgen
|
|||||||
data[i] = data[j];
|
data[i] = data[j];
|
||||||
data[j] = hv;
|
data[j] = hv;
|
||||||
|
|
||||||
S hvs = slave[i];
|
S hvs = index[i];
|
||||||
slave[i] = slave[j];
|
index[i] = index[j];
|
||||||
slave[j] = hvs;
|
index[j] = hvs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class T, class S>
|
template <class T, class S>
|
||||||
void QuickSortRec (NgFlatArray<T> & data,
|
void QuickSortRec (NgFlatArray<T> & data,
|
||||||
NgFlatArray<S> & slave,
|
NgFlatArray<S> & index,
|
||||||
int left, int right)
|
int left, int right)
|
||||||
{
|
{
|
||||||
int i = left;
|
int i = left;
|
||||||
@ -764,20 +770,20 @@ namespace netgen
|
|||||||
if (i <= j)
|
if (i <= j)
|
||||||
{
|
{
|
||||||
ngcore::Swap (data[i], data[j]);
|
ngcore::Swap (data[i], data[j]);
|
||||||
ngcore::Swap (slave[i], slave[j]);
|
ngcore::Swap (index[i], index[j]);
|
||||||
i++; j--;
|
i++; j--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (i <= j);
|
while (i <= j);
|
||||||
if (left < j) QuickSortRec (data, slave, left, j);
|
if (left < j) QuickSortRec (data, index, left, j);
|
||||||
if (i < right) QuickSortRec (data, slave, i, right);
|
if (i < right) QuickSortRec (data, index, i, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, class S>
|
template <class T, class S>
|
||||||
void QuickSort (NgFlatArray<T> & data, NgFlatArray<S> & slave)
|
void QuickSort (NgFlatArray<T> & data, NgFlatArray<S> & index)
|
||||||
{
|
{
|
||||||
if (data.Size() > 1)
|
if (data.Size() > 1)
|
||||||
QuickSortRec (data, slave, 0, data.Size()-1);
|
QuickSortRec (data, index, 0, data.Size()-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,672 +0,0 @@
|
|||||||
#ifndef FILE_NGSIMD
|
|
||||||
#define FILE_NGSIMD
|
|
||||||
/**************************************************************************/
|
|
||||||
/* File: ngsimd.hpp */
|
|
||||||
/* Author: Joachim Schoeberl */
|
|
||||||
/* Date: 25. Mar. 16 */
|
|
||||||
/**************************************************************************/
|
|
||||||
|
|
||||||
#include <immintrin.h>
|
|
||||||
#include <tuple>
|
|
||||||
#include <ostream>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include <core/utils.hpp>
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#ifndef AVX_OPERATORS_DEFINED
|
|
||||||
#define AVX_OPERATORS_DEFINED
|
|
||||||
NG_INLINE __m128d operator- (__m128d a) { return _mm_xor_pd(a, _mm_set1_pd(-0.0)); }
|
|
||||||
NG_INLINE __m128d operator+ (__m128d a, __m128d b) { return _mm_add_pd(a,b); }
|
|
||||||
NG_INLINE __m128d operator- (__m128d a, __m128d b) { return _mm_sub_pd(a,b); }
|
|
||||||
NG_INLINE __m128d operator* (__m128d a, __m128d b) { return _mm_mul_pd(a,b); }
|
|
||||||
NG_INLINE __m128d operator/ (__m128d a, __m128d b) { return _mm_div_pd(a,b); }
|
|
||||||
NG_INLINE __m128d operator* (double a, __m128d b) { return _mm_set1_pd(a)*b; }
|
|
||||||
NG_INLINE __m128d operator* (__m128d b, double a) { return _mm_set1_pd(a)*b; }
|
|
||||||
|
|
||||||
NG_INLINE __m128d operator+= (__m128d &a, __m128d b) { return a = a+b; }
|
|
||||||
NG_INLINE __m128d operator-= (__m128d &a, __m128d b) { return a = a-b; }
|
|
||||||
NG_INLINE __m128d operator*= (__m128d &a, __m128d b) { return a = a*b; }
|
|
||||||
NG_INLINE __m128d operator/= (__m128d &a, __m128d b) { return a = a/b; }
|
|
||||||
|
|
||||||
NG_INLINE __m256d operator- (__m256d a) { return _mm256_xor_pd(a, _mm256_set1_pd(-0.0)); }
|
|
||||||
NG_INLINE __m256d operator+ (__m256d a, __m256d b) { return _mm256_add_pd(a,b); }
|
|
||||||
NG_INLINE __m256d operator- (__m256d a, __m256d b) { return _mm256_sub_pd(a,b); }
|
|
||||||
NG_INLINE __m256d operator* (__m256d a, __m256d b) { return _mm256_mul_pd(a,b); }
|
|
||||||
NG_INLINE __m256d operator/ (__m256d a, __m256d b) { return _mm256_div_pd(a,b); }
|
|
||||||
NG_INLINE __m256d operator* (double a, __m256d b) { return _mm256_set1_pd(a)*b; }
|
|
||||||
NG_INLINE __m256d operator* (__m256d b, double a) { return _mm256_set1_pd(a)*b; }
|
|
||||||
|
|
||||||
NG_INLINE __m256d operator+= (__m256d &a, __m256d b) { return a = a+b; }
|
|
||||||
NG_INLINE __m256d operator-= (__m256d &a, __m256d b) { return a = a-b; }
|
|
||||||
NG_INLINE __m256d operator*= (__m256d &a, __m256d b) { return a = a*b; }
|
|
||||||
NG_INLINE __m256d operator/= (__m256d &a, __m256d b) { return a = a/b; }
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
namespace ngsimd
|
|
||||||
{
|
|
||||||
// MSVC does not define SSE. It's always present on 64bit cpus
|
|
||||||
#if (defined(_M_AMD64) || defined(_M_X64) || defined(__AVX__))
|
|
||||||
#ifndef __SSE__
|
|
||||||
#define __SSE__
|
|
||||||
#endif
|
|
||||||
#ifndef __SSE2__
|
|
||||||
#define __SSE2__
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
constexpr int GetDefaultSIMDSize() {
|
|
||||||
#if defined __AVX512F__
|
|
||||||
return 8;
|
|
||||||
#elif defined __AVX__
|
|
||||||
return 4;
|
|
||||||
#elif defined __SSE__
|
|
||||||
return 2;
|
|
||||||
#else
|
|
||||||
return 1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined __AVX512F__
|
|
||||||
typedef __m512 tAVX;
|
|
||||||
typedef __m512d tAVXd;
|
|
||||||
#elif defined __AVX__
|
|
||||||
typedef __m256 tAVX;
|
|
||||||
typedef __m256d tAVXd;
|
|
||||||
#elif defined __SSE__
|
|
||||||
typedef __m128 tAVX;
|
|
||||||
typedef __m128d tAVXd;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T, int N=GetDefaultSIMDSize()> class SIMD;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct has_call_operator
|
|
||||||
{
|
|
||||||
template <typename C> static std::true_type check( decltype( sizeof(&C::operator() )) ) { return std::true_type(); }
|
|
||||||
template <typename> static std::false_type check(...) { return std::false_type(); }
|
|
||||||
typedef decltype( check<T>(sizeof(char)) ) type;
|
|
||||||
static constexpr type value = type();
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T1, typename T2, typename T3>
|
|
||||||
// a*b+c
|
|
||||||
NG_INLINE auto FMA(T1 a, T2 b, T3 c)
|
|
||||||
{
|
|
||||||
return a*b+c;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<int N, typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
NG_INLINE SIMD<double,N> operator+ (T a, SIMD<double,N> b) { return SIMD<double,N>(a) + b; }
|
|
||||||
template<int N, typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
NG_INLINE SIMD<double,N> operator- (T a, SIMD<double,N> b) { return SIMD<double,N>(a) - b; }
|
|
||||||
template<int N, typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
NG_INLINE SIMD<double,N> operator* (T a, SIMD<double,N> b) { return SIMD<double,N>(a) * b; }
|
|
||||||
template<int N, typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
NG_INLINE SIMD<double,N> operator/ (T a, SIMD<double,N> b) { return SIMD<double,N>(a) / b; }
|
|
||||||
template<int N, typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
NG_INLINE SIMD<double,N> operator+ (SIMD<double,N> a, T b) { return a + SIMD<double,N>(b); }
|
|
||||||
template<int N, typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
NG_INLINE SIMD<double,N> operator- (SIMD<double,N> a, T b) { return a - SIMD<double,N>(b); }
|
|
||||||
template<int N, typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
NG_INLINE SIMD<double,N> operator* (SIMD<double,N> a, T b) { return a * SIMD<double,N>(b); }
|
|
||||||
template<int N, typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
NG_INLINE SIMD<double,N> operator/ (SIMD<double,N> a, T b) { return a / SIMD<double,N>(b); }
|
|
||||||
|
|
||||||
|
|
||||||
using std::sqrt;
|
|
||||||
using std::fabs;
|
|
||||||
|
|
||||||
class ExceptionNOSIMD : public std::runtime_error
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using std::runtime_error::runtime_error;
|
|
||||||
std::string What() { return what(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
using std::exp;
|
|
||||||
template<int N> NG_INLINE SIMD<double,N> exp (SIMD<double,N> a)
|
|
||||||
{
|
|
||||||
return SIMD<double,N>([&](int i)->double { return exp(a[i]); } );
|
|
||||||
}
|
|
||||||
|
|
||||||
using std::log;
|
|
||||||
template<int N> NG_INLINE SIMD<double,N> log (SIMD<double,N> a)
|
|
||||||
{
|
|
||||||
return SIMD<double,N>([&](int i)->double { return log(a[i]); } );
|
|
||||||
}
|
|
||||||
|
|
||||||
using std::pow;
|
|
||||||
template<int N> NG_INLINE SIMD<double,N> pow (SIMD<double,N> a, double x)
|
|
||||||
{
|
|
||||||
return SIMD<double,N>([&](int i)->double { return pow(a[i],x); } );
|
|
||||||
}
|
|
||||||
|
|
||||||
using std::sin;
|
|
||||||
template<int N> NG_INLINE SIMD<double,N> sin (SIMD<double,N> a)
|
|
||||||
{
|
|
||||||
return SIMD<double,N>([&](int i)->double { return sin(a[i]); } );
|
|
||||||
}
|
|
||||||
|
|
||||||
using std::cos;
|
|
||||||
template<int N> NG_INLINE SIMD<double,N> cos (SIMD<double,N> a)
|
|
||||||
{
|
|
||||||
return SIMD<double,N>([&](int i)->double { return cos(a[i]); } );
|
|
||||||
}
|
|
||||||
|
|
||||||
using std::tan;
|
|
||||||
template<int N> NG_INLINE SIMD<double,N> tan (SIMD<double,N> a)
|
|
||||||
{
|
|
||||||
return SIMD<double,N>([&](int i)->double { return tan(a[i]); } );
|
|
||||||
}
|
|
||||||
|
|
||||||
using std::atan;
|
|
||||||
template<int N> NG_INLINE SIMD<double,N> atan (SIMD<double,N> a)
|
|
||||||
{
|
|
||||||
return SIMD<double,N>([&](int i)->double { return atan(a[i]); } );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// SIMD width 1 (in case no AVX support is available)
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
template<>
|
|
||||||
class SIMD<double,1>
|
|
||||||
{
|
|
||||||
double data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr int Size() { return 1; }
|
|
||||||
SIMD () = default;
|
|
||||||
SIMD (const SIMD &) = default;
|
|
||||||
SIMD & operator= (const SIMD &) = default;
|
|
||||||
|
|
||||||
// only called if T has a call operator of appropriate type
|
|
||||||
template<typename T, typename std::enable_if<std::is_convertible<T, std::function<double(int)>>::value, int>::type = 0>
|
|
||||||
SIMD (const T & func)
|
|
||||||
{
|
|
||||||
data = func(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// only called if T is arithmetic (integral or floating point types)
|
|
||||||
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
SIMD (const T & val)
|
|
||||||
{
|
|
||||||
data = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
SIMD (double const * p)
|
|
||||||
{
|
|
||||||
data = *p;
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE operator double() const { return data; }
|
|
||||||
NG_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; }
|
|
||||||
NG_INLINE double Data() const { return data; }
|
|
||||||
NG_INLINE double & Data() { return data; }
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,1> &operator+= (SIMD<double,1> b) { data+=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,1> &operator-= (SIMD<double,1> b) { data-=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,1> &operator*= (SIMD<double,1> b) { data*=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,1> &operator/= (SIMD<double,1> b) { data/=b.Data(); return *this; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,1> operator+ (SIMD<double,1> a, SIMD<double,1> b) { return a.Data()+b.Data(); }
|
|
||||||
NG_INLINE SIMD<double,1> operator- (SIMD<double,1> a, SIMD<double,1> b) { return a.Data()-b.Data(); }
|
|
||||||
NG_INLINE SIMD<double,1> operator- (SIMD<double,1> a) { return -a.Data(); }
|
|
||||||
NG_INLINE SIMD<double,1> operator* (SIMD<double,1> a, SIMD<double,1> b) { return a.Data()*b.Data(); }
|
|
||||||
NG_INLINE SIMD<double,1> operator/ (SIMD<double,1> a, SIMD<double,1> b) { return a.Data()/b.Data(); }
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,1> sqrt (SIMD<double,1> a) { return std::sqrt(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,1> floor (SIMD<double,1> a) { return std::floor(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,1> ceil (SIMD<double,1> a) { return std::ceil(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,1> fabs (SIMD<double,1> a) { return std::fabs(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,1> L2Norm2 (SIMD<double,1> a) { return a.Data()*a.Data(); }
|
|
||||||
NG_INLINE SIMD<double,1> Trans (SIMD<double,1> a) { return a; }
|
|
||||||
NG_INLINE SIMD<double,1> IfPos (SIMD<double,1> a, SIMD<double,1> b, SIMD<double,1> c)
|
|
||||||
{
|
|
||||||
return (a.Data() > 0) ? b : c;
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE double HSum (SIMD<double,1> sd)
|
|
||||||
{
|
|
||||||
return sd.Data();
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE auto HSum (SIMD<double,1> sd1, SIMD<double,1> sd2)
|
|
||||||
{
|
|
||||||
return std::make_tuple(sd1.Data(), sd2.Data());
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE auto HSum (SIMD<double,1> sd1, SIMD<double,1> sd2, SIMD<double,1> sd3, SIMD<double,1> sd4)
|
|
||||||
{
|
|
||||||
return std::make_tuple(sd1.Data(), sd2.Data(), sd3.Data(), sd4.Data());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// SSE - Simd width 2
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
#ifdef __SSE__
|
|
||||||
template<>
|
|
||||||
class alignas(16) SIMD<double,2>
|
|
||||||
{
|
|
||||||
__m128d data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr int Size() { return 2; }
|
|
||||||
SIMD () = default;
|
|
||||||
SIMD (const SIMD &) = default;
|
|
||||||
SIMD & operator= (const SIMD &) = default;
|
|
||||||
|
|
||||||
SIMD (__m128d adata)
|
|
||||||
: data(adata)
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
// only called if T has a call operator of appropriate type
|
|
||||||
template<typename T, typename std::enable_if<std::is_convertible<T, std::function<double(int)>>::value, int>::type = 0>
|
|
||||||
SIMD (const T & func)
|
|
||||||
{
|
|
||||||
data = _mm_set_pd(func(1), func(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// only called if T is arithmetic (integral or floating point types)
|
|
||||||
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
SIMD (const T & val)
|
|
||||||
{
|
|
||||||
data = _mm_set1_pd(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
SIMD (double const * p)
|
|
||||||
{
|
|
||||||
data = _mm_loadu_pd(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE operator __m128d() const { return data; }
|
|
||||||
NG_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; }
|
|
||||||
NG_INLINE double& operator[] (int i) { return ((double*)(&data))[i]; }
|
|
||||||
NG_INLINE __m128d Data() const { return data; }
|
|
||||||
NG_INLINE __m128d & Data() { return data; }
|
|
||||||
|
|
||||||
// NG_INLINE operator std::tuple<double&,double&,double&,double&> ()
|
|
||||||
// { return std::tuple<double&,double&,double&,double&>((*this)[0], (*this)[1], (*this)[2], (*this)[3]); }
|
|
||||||
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,2> &operator+= (SIMD<double,2> b) { data+=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,2> &operator-= (SIMD<double,2> b) { data-=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,2> &operator*= (SIMD<double,2> b) { data*=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,2> &operator/= (SIMD<double,2> b) { data/=b.Data(); return *this; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,2> operator+ (SIMD<double,2> a, SIMD<double,2> b) { return a.Data()+b.Data(); }
|
|
||||||
NG_INLINE SIMD<double,2> operator- (SIMD<double,2> a, SIMD<double,2> b) { return a.Data()-b.Data(); }
|
|
||||||
NG_INLINE SIMD<double,2> operator- (SIMD<double,2> a) { return -a.Data(); }
|
|
||||||
NG_INLINE SIMD<double,2> operator* (SIMD<double,2> a, SIMD<double,2> b) { return a.Data()*b.Data(); }
|
|
||||||
NG_INLINE SIMD<double,2> operator/ (SIMD<double,2> a, SIMD<double,2> b) { return a.Data()/b.Data(); }
|
|
||||||
|
|
||||||
/*
|
|
||||||
NG_INLINE SIMD<double,4> sqrt (SIMD<double,4> a) { return _mm256_sqrt_pd(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,4> floor (SIMD<double,4> a) { return _mm256_floor_pd(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,4> ceil (SIMD<double,4> a) { return _mm256_ceil_pd(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,4> fabs (SIMD<double,4> a) { return _mm256_max_pd(a.Data(), -a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,4> L2Norm2 (SIMD<double,4> a) { return a.Data()*a.Data(); }
|
|
||||||
NG_INLINE SIMD<double,4> Trans (SIMD<double,4> a) { return a; }
|
|
||||||
NG_INLINE SIMD<double,4> IfPos (SIMD<double,4> a, SIMD<double,4> b, SIMD<double,4> c)
|
|
||||||
{
|
|
||||||
auto cp = _mm256_cmp_pd (a.Data(), _mm256_setzero_pd(), _CMP_GT_OS);
|
|
||||||
return _mm256_blendv_pd(c.Data(), b.Data(), cp);
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE double HSum (SIMD<double,4> sd)
|
|
||||||
{
|
|
||||||
__m128d hv = _mm_add_pd (_mm256_extractf128_pd(sd.Data(),0), _mm256_extractf128_pd(sd.Data(),1));
|
|
||||||
return _mm_cvtsd_f64 (_mm_hadd_pd (hv, hv));
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE auto HSum (SIMD<double,4> sd1, SIMD<double,4> sd2)
|
|
||||||
{
|
|
||||||
__m256d hv = _mm256_hadd_pd(sd1.Data(), sd2.Data());
|
|
||||||
__m128d hv2 = _mm_add_pd (_mm256_extractf128_pd(hv,0), _mm256_extractf128_pd(hv,1));
|
|
||||||
return std::make_tuple(_mm_cvtsd_f64 (hv2), _mm_cvtsd_f64(_mm_shuffle_pd (hv2, hv2, 3)));
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE auto HSum (SIMD<double,4> v1, SIMD<double,4> v2, SIMD<double,4> v3, SIMD<double,4> v4)
|
|
||||||
{
|
|
||||||
__m256d hsum1 = _mm256_hadd_pd (v1.Data(), v2.Data());
|
|
||||||
__m256d hsum2 = _mm256_hadd_pd (v3.Data(), v4.Data());
|
|
||||||
__m256d hsum = _mm256_add_pd (_mm256_permute2f128_pd (hsum1, hsum2, 1+2*16),
|
|
||||||
_mm256_blend_pd (hsum1, hsum2, 12));
|
|
||||||
return SIMD<double,4>(hsum);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
#endif // __SSE__
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// AVX - Simd width 4
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
#ifdef __AVX__
|
|
||||||
template<>
|
|
||||||
class alignas(32) SIMD<double,4>
|
|
||||||
{
|
|
||||||
__m256d data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr int Size() { return 4; }
|
|
||||||
SIMD () = default;
|
|
||||||
SIMD (const SIMD &) = default;
|
|
||||||
SIMD & operator= (const SIMD &) = default;
|
|
||||||
|
|
||||||
SIMD (__m256d adata)
|
|
||||||
: data(adata)
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
// only called if T has a call operator of appropriate type
|
|
||||||
template<typename T, typename std::enable_if<std::is_convertible<T, std::function<double(int)>>::value, int>::type = 0>
|
|
||||||
SIMD (const T & func)
|
|
||||||
{
|
|
||||||
data = _mm256_set_pd(func(3), func(2), func(1), func(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// only called if T is arithmetic (integral or floating point types)
|
|
||||||
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
SIMD (const T & val)
|
|
||||||
{
|
|
||||||
data = _mm256_set1_pd(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
SIMD (double const * p)
|
|
||||||
{
|
|
||||||
data = _mm256_loadu_pd(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE operator __m256d() const { return data; }
|
|
||||||
NG_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; }
|
|
||||||
NG_INLINE double& operator[] (int i) { return ((double*)(&data))[i]; }
|
|
||||||
NG_INLINE __m256d Data() const { return data; }
|
|
||||||
NG_INLINE __m256d & Data() { return data; }
|
|
||||||
|
|
||||||
NG_INLINE operator std::tuple<double&,double&,double&,double&> ()
|
|
||||||
{ return std::tuple<double&,double&,double&,double&>((*this)[0], (*this)[1], (*this)[2], (*this)[3]); }
|
|
||||||
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,4> &operator+= (SIMD<double,4> b) { data+=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,4> &operator-= (SIMD<double,4> b) { data-=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,4> &operator*= (SIMD<double,4> b) { data*=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,4> &operator/= (SIMD<double,4> b) { data/=b.Data(); return *this; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,4> operator+ (SIMD<double,4> a, SIMD<double,4> b) { return a.Data()+b.Data(); }
|
|
||||||
NG_INLINE SIMD<double,4> operator- (SIMD<double,4> a, SIMD<double,4> b) { return a.Data()-b.Data(); }
|
|
||||||
NG_INLINE SIMD<double,4> operator- (SIMD<double,4> a) { return -a.Data(); }
|
|
||||||
NG_INLINE SIMD<double,4> operator* (SIMD<double,4> a, SIMD<double,4> b) { return a.Data()*b.Data(); }
|
|
||||||
NG_INLINE SIMD<double,4> operator/ (SIMD<double,4> a, SIMD<double,4> b) { return a.Data()/b.Data(); }
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,4> sqrt (SIMD<double,4> a) { return _mm256_sqrt_pd(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,4> floor (SIMD<double,4> a) { return _mm256_floor_pd(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,4> ceil (SIMD<double,4> a) { return _mm256_ceil_pd(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,4> fabs (SIMD<double,4> a) { return _mm256_max_pd(a.Data(), -a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,4> L2Norm2 (SIMD<double,4> a) { return a.Data()*a.Data(); }
|
|
||||||
NG_INLINE SIMD<double,4> Trans (SIMD<double,4> a) { return a; }
|
|
||||||
NG_INLINE SIMD<double,4> IfPos (SIMD<double,4> a, SIMD<double,4> b, SIMD<double,4> c)
|
|
||||||
{
|
|
||||||
auto cp = _mm256_cmp_pd (a.Data(), _mm256_setzero_pd(), _CMP_GT_OS);
|
|
||||||
return _mm256_blendv_pd(c.Data(), b.Data(), cp);
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE double HSum (SIMD<double,4> sd)
|
|
||||||
{
|
|
||||||
__m128d hv = _mm_add_pd (_mm256_extractf128_pd(sd.Data(),0), _mm256_extractf128_pd(sd.Data(),1));
|
|
||||||
return _mm_cvtsd_f64 (_mm_hadd_pd (hv, hv));
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE auto HSum (SIMD<double,4> sd1, SIMD<double,4> sd2)
|
|
||||||
{
|
|
||||||
__m256d hv = _mm256_hadd_pd(sd1.Data(), sd2.Data());
|
|
||||||
__m128d hv2 = _mm_add_pd (_mm256_extractf128_pd(hv,0), _mm256_extractf128_pd(hv,1));
|
|
||||||
return std::make_tuple(_mm_cvtsd_f64 (hv2), _mm_cvtsd_f64(_mm_shuffle_pd (hv2, hv2, 3)));
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE auto HSum (SIMD<double,4> v1, SIMD<double,4> v2, SIMD<double,4> v3, SIMD<double,4> v4)
|
|
||||||
{
|
|
||||||
__m256d hsum1 = _mm256_hadd_pd (v1.Data(), v2.Data());
|
|
||||||
__m256d hsum2 = _mm256_hadd_pd (v3.Data(), v4.Data());
|
|
||||||
__m256d hsum = _mm256_add_pd (_mm256_permute2f128_pd (hsum1, hsum2, 1+2*16),
|
|
||||||
_mm256_blend_pd (hsum1, hsum2, 12));
|
|
||||||
return SIMD<double,4>(hsum);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // __AVX__
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// AVX512 - Simd width 8
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
#ifdef __AVX512F__
|
|
||||||
template<>
|
|
||||||
class alignas(64) SIMD<double,8>
|
|
||||||
{
|
|
||||||
__m512d data;
|
|
||||||
|
|
||||||
public:
|
|
||||||
static constexpr int Size() { return 8; }
|
|
||||||
SIMD () = default;
|
|
||||||
SIMD (const SIMD &) = default;
|
|
||||||
SIMD & operator= (const SIMD &) = default;
|
|
||||||
|
|
||||||
SIMD (__m512d adata)
|
|
||||||
: data(adata)
|
|
||||||
{ ; }
|
|
||||||
|
|
||||||
// only called if T has a call operator of appropriate type
|
|
||||||
template<typename T, typename std::enable_if<std::is_convertible<T, std::function<double(int)>>::value, int>::type = 0>
|
|
||||||
SIMD (const T & func)
|
|
||||||
{
|
|
||||||
data = _mm512_set_pd(func(7), func(6), func(5), func(4),
|
|
||||||
func(3), func(2), func(1), func(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// only called if T is arithmetic (integral or floating point types)
|
|
||||||
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value, int>::type = 0>
|
|
||||||
SIMD (const T & val)
|
|
||||||
{
|
|
||||||
data = _mm512_set1_pd(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
SIMD (double const * p)
|
|
||||||
{
|
|
||||||
data = _mm512_loadu_pd(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE operator __m512d() const { return data; }
|
|
||||||
NG_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; }
|
|
||||||
NG_INLINE __m512d Data() const { return data; }
|
|
||||||
NG_INLINE __m512d & Data() { return data; }
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,8> &operator+= (SIMD<double,8> b) { data+=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,8> &operator-= (SIMD<double,8> b) { data-=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,8> &operator*= (SIMD<double,8> b) { data*=b.Data(); return *this; }
|
|
||||||
NG_INLINE SIMD<double,8> &operator/= (SIMD<double,8> b) { data/=b.Data(); return *this; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,8> operator- (SIMD<double,8> a) { return _mm512_sub_pd(_mm512_setzero_pd(), a.Data()); }
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,8> operator+ (SIMD<double,8> a, SIMD<double,8> b) { return _mm512_add_pd(a.Data(),b.Data()); }
|
|
||||||
NG_INLINE SIMD<double,8> operator- (SIMD<double,8> a, SIMD<double,8> b) { return _mm512_sub_pd(a.Data(),b.Data()); }
|
|
||||||
NG_INLINE SIMD<double,8> operator* (SIMD<double,8> a, SIMD<double,8> b) { return _mm512_mul_pd(a.Data(),b.Data()); }
|
|
||||||
NG_INLINE SIMD<double,8> operator/ (SIMD<double,8> a, SIMD<double,8> b) { return _mm512_div_pd(a.Data(),b.Data()); }
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,8> sqrt (SIMD<double,8> a) { return _mm512_sqrt_pd(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,8> floor (SIMD<double,8> a) { return _mm512_floor_pd(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,8> ceil (SIMD<double,8> a) { return _mm512_ceil_pd(a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,8> fabs (SIMD<double,8> a) { return _mm512_max_pd(a.Data(), -a.Data()); }
|
|
||||||
NG_INLINE SIMD<double,8> L2Norm2 (SIMD<double,8> a) { return a.Data()*a.Data(); }
|
|
||||||
NG_INLINE SIMD<double,8> Trans (SIMD<double,8> a) { return a; }
|
|
||||||
NG_INLINE SIMD<double,8> IfPos (SIMD<double,8> a, SIMD<double,8> b, SIMD<double,8> c)
|
|
||||||
{
|
|
||||||
auto cp = _mm512_cmp_pd_mask (a.Data(), _mm512_setzero_pd(), _MM_CMPINT_GT);
|
|
||||||
return _mm512_mask_blend_pd(cp, c.Data(), b.Data());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<> NG_INLINE auto FMA (SIMD<double,8> a, SIMD<double,8> b, SIMD<double,8> c)
|
|
||||||
{
|
|
||||||
return _mm512_fmadd_pd (a.Data(), b.Data(), c.Data());
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE double HSum (SIMD<double,8> sd)
|
|
||||||
{
|
|
||||||
SIMD<double,4> low = _mm512_extractf64x4_pd(sd.Data(),0);
|
|
||||||
SIMD<double,4> high = _mm512_extractf64x4_pd(sd.Data(),1);
|
|
||||||
return HSum(low)+HSum(high);
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE auto HSum (SIMD<double,8> sd1, SIMD<double,8> sd2)
|
|
||||||
{
|
|
||||||
return std::make_tuple(HSum(sd1), HSum(sd2));
|
|
||||||
}
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double,4> HSum (SIMD<double,8> v1, SIMD<double,8> v2, SIMD<double,8> v3, SIMD<double,8> v4)
|
|
||||||
{
|
|
||||||
SIMD<double,4> high1 = _mm512_extractf64x4_pd(v1.Data(),1);
|
|
||||||
SIMD<double,4> high2 = _mm512_extractf64x4_pd(v2.Data(),1);
|
|
||||||
SIMD<double,4> high3 = _mm512_extractf64x4_pd(v3.Data(),1);
|
|
||||||
SIMD<double,4> high4 = _mm512_extractf64x4_pd(v4.Data(),1);
|
|
||||||
SIMD<double,4> low1 = _mm512_extractf64x4_pd(v1.Data(),0);
|
|
||||||
SIMD<double,4> low2 = _mm512_extractf64x4_pd(v2.Data(),0);
|
|
||||||
SIMD<double,4> low3 = _mm512_extractf64x4_pd(v3.Data(),0);
|
|
||||||
SIMD<double,4> low4 = _mm512_extractf64x4_pd(v4.Data(),0);
|
|
||||||
return HSum(low1,low2,low3,low4) + HSum(high1,high2,high3,high4);
|
|
||||||
}
|
|
||||||
#endif // __AVX512F__
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// MultiSIMD - Multiple SIMD values in one struct using head-tail implementation
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
template <int D, typename T>
|
|
||||||
class MultiSIMD
|
|
||||||
{
|
|
||||||
SIMD<T> head;
|
|
||||||
MultiSIMD<D-1,T> tail;
|
|
||||||
public:
|
|
||||||
MultiSIMD () = default;
|
|
||||||
MultiSIMD (const MultiSIMD & ) = default;
|
|
||||||
MultiSIMD (T v) : head(v), tail(v) { ; }
|
|
||||||
MultiSIMD (SIMD<T> _head, MultiSIMD<D-1,T> _tail)
|
|
||||||
: head(_head), tail(_tail) { ; }
|
|
||||||
SIMD<T> Head() const { return head; }
|
|
||||||
MultiSIMD<D-1,T> Tail() const { return tail; }
|
|
||||||
SIMD<T> & Head() { return head; }
|
|
||||||
MultiSIMD<D-1,T> & Tail() { return tail; }
|
|
||||||
|
|
||||||
template <int NR>
|
|
||||||
SIMD<T> Get() const { return NR==0 ? head : tail.template Get<NR-1>(); }
|
|
||||||
template <int NR>
|
|
||||||
SIMD<T> & Get() { return NR==0 ? head : tail.template Get<NR-1>(); }
|
|
||||||
auto MakeTuple() { return std::tuple_cat(std::tuple<SIMD<T>&> (head), tail.MakeTuple()); }
|
|
||||||
// not yet possible for MSVC
|
|
||||||
// operator auto () { return MakeTuple(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
class MultiSIMD<2,T>
|
|
||||||
{
|
|
||||||
SIMD<T> v0, v1;
|
|
||||||
public:
|
|
||||||
MultiSIMD () = default;
|
|
||||||
MultiSIMD (const MultiSIMD & ) = default;
|
|
||||||
MultiSIMD (T v) : v0(v), v1(v) { ; }
|
|
||||||
MultiSIMD (SIMD<T> _v0, SIMD<T> _v1) : v0(_v0), v1(_v1) { ; }
|
|
||||||
|
|
||||||
SIMD<T> Head() const { return v0; }
|
|
||||||
SIMD<T> Tail() const { return v1; }
|
|
||||||
SIMD<T> & Head() { return v0; }
|
|
||||||
SIMD<T> & Tail() { return v1; }
|
|
||||||
|
|
||||||
template <int NR>
|
|
||||||
SIMD<T> Get() const { return NR==0 ? v0 : v1; }
|
|
||||||
template <int NR>
|
|
||||||
SIMD<T> & Get() { return NR==0 ? v0 : v1; }
|
|
||||||
auto MakeTuple() { return std::tuple<SIMD<T>&, SIMD<T>&> (v0, v1); }
|
|
||||||
operator std::tuple<SIMD<T>&, SIMD<T>&>() { return MakeTuple(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator+ (MultiSIMD<D,double> a, MultiSIMD<D,double> b)
|
|
||||||
{ return MultiSIMD<D,double> (a.Head()+b.Head(), a.Tail()+b.Tail()); }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator+ (double a, MultiSIMD<D,double> b)
|
|
||||||
{ return MultiSIMD<D,double> (a+b.Head(), a+b.Tail()); }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator+ (MultiSIMD<D,double> b, double a)
|
|
||||||
{ return MultiSIMD<D,double> (a+b.Head(), a+b.Tail()); }
|
|
||||||
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator- (MultiSIMD<D,double> a, MultiSIMD<D,double> b)
|
|
||||||
{ return MultiSIMD<D,double> (a.Head()-b.Head(), a.Tail()-b.Tail()); }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator- (double a, MultiSIMD<D,double> b)
|
|
||||||
{ return MultiSIMD<D,double> (a-b.Head(), a-b.Tail()); }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator- (MultiSIMD<D,double> b, double a)
|
|
||||||
{ return MultiSIMD<D,double> (b.Head()-a, b.Tail()-a); }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator- (MultiSIMD<D,double> a)
|
|
||||||
{ return MultiSIMD<D,double> (-a.Head(), -a.Tail()); }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator* (MultiSIMD<D,double> a, MultiSIMD<D,double> b)
|
|
||||||
{ return MultiSIMD<D,double> (a.Head()*b.Head(), a.Tail()*b.Tail()); }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator/ (MultiSIMD<D,double> a, MultiSIMD<D,double> b)
|
|
||||||
{ return MultiSIMD<D,double> (a.Head()/b.Head(), a.Tail()/b.Tail()); }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator* (double a, MultiSIMD<D,double> b)
|
|
||||||
{ return MultiSIMD<D,double> ( a*b.Head(), a*b.Tail()); }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator* (MultiSIMD<D,double> b, double a)
|
|
||||||
{ return MultiSIMD<D,double> ( a*b.Head(), a*b.Tail()); }
|
|
||||||
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> & operator+= (MultiSIMD<D,double> & a, MultiSIMD<D,double> b)
|
|
||||||
{ a.Head()+=b.Head(); a.Tail()+=b.Tail(); return a; }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator-= (MultiSIMD<D,double> & a, double b)
|
|
||||||
{ a.Head()-=b; a.Tail()-=b; return a; }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> operator-= (MultiSIMD<D,double> & a, MultiSIMD<D,double> b)
|
|
||||||
{ a.Head()-=b.Head(); a.Tail()-=b.Tail(); return a; }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> & operator*= (MultiSIMD<D,double> & a, MultiSIMD<D,double> b)
|
|
||||||
{ a.Head()*=b.Head(); a.Tail()*=b.Tail(); return a; }
|
|
||||||
template <int D> NG_INLINE MultiSIMD<D,double> & operator*= (MultiSIMD<D,double> & a, double b)
|
|
||||||
{ a.Head()*=b; a.Tail()*=b; return a; }
|
|
||||||
// NG_INLINE MultiSIMD<double> operator/= (MultiSIMD<double> & a, MultiSIMD<double> b) { return a.Data()/=b.Data(); }
|
|
||||||
|
|
||||||
NG_INLINE SIMD<double> HVSum (SIMD<double> a) { return a; }
|
|
||||||
template <int D>
|
|
||||||
NG_INLINE SIMD<double> HVSum (MultiSIMD<D,double> a) { return a.Head() + HVSum(a.Tail()); }
|
|
||||||
|
|
||||||
template <int D> NG_INLINE double HSum (MultiSIMD<D,double> a) { return HSum(HVSum(a)); }
|
|
||||||
template <int D> NG_INLINE auto HSum (MultiSIMD<D,double> a, MultiSIMD<D,double> b)
|
|
||||||
{ return HSum(HVSum(a), HVSum(b)); }
|
|
||||||
|
|
||||||
template <int D, typename T>
|
|
||||||
std::ostream & operator<< (std::ostream & ost, MultiSIMD<D,T> multi)
|
|
||||||
{
|
|
||||||
ost << multi.Head() << " " << multi.Tail();
|
|
||||||
return ost;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
std::ostream & operator<< (std::ostream & ost, SIMD<T> simd)
|
|
||||||
{
|
|
||||||
ost << simd[0];
|
|
||||||
for (int i = 1; i < simd.Size(); i++)
|
|
||||||
ost << " " << simd[i];
|
|
||||||
return ost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace netgen
|
|
||||||
{
|
|
||||||
using namespace ngsimd;
|
|
||||||
}
|
|
||||||
#endif
|
|
@ -26,39 +26,13 @@ private:
|
|||||||
mutex block_allocator_mutex;
|
mutex block_allocator_mutex;
|
||||||
public:
|
public:
|
||||||
///
|
///
|
||||||
BlockAllocator (unsigned asize, unsigned ablocks = 100);
|
DLL_HEADER BlockAllocator (unsigned asize, unsigned ablocks = 100);
|
||||||
///
|
///
|
||||||
~BlockAllocator ();
|
DLL_HEADER ~BlockAllocator ();
|
||||||
///
|
///
|
||||||
|
DLL_HEADER void * Alloc ();
|
||||||
void * Alloc ();
|
|
||||||
/*
|
|
||||||
{
|
|
||||||
if (!freelist)
|
|
||||||
Alloc2();
|
|
||||||
|
|
||||||
void * p = freelist;
|
|
||||||
// freelist = *(void**)freelist;
|
|
||||||
freelist = *static_cast<void**> (freelist);
|
|
||||||
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
///
|
///
|
||||||
void Free (void * p);
|
DLL_HEADER void Free (void * p);
|
||||||
/*
|
|
||||||
{
|
|
||||||
if (!bablocks.Size()) return;
|
|
||||||
*(void**)p = freelist;
|
|
||||||
freelist = p;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
// void Alloc2 ();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -96,8 +96,8 @@ void ParallelFor( int first, int next, const TFunc & f )
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef void (*TaskManager)(std::function<void(int,int)>);
|
typedef void (*NgTaskManager)(std::function<void(int,int)>);
|
||||||
typedef void (*Tracer)(string, bool); // false .. start, true .. stop
|
typedef void (*NgTracer)(string, bool); // false .. start, true .. stop
|
||||||
|
|
||||||
inline void DummyTaskManager (std::function<void(int,int)> func)
|
inline void DummyTaskManager (std::function<void(int,int)> func)
|
||||||
{
|
{
|
||||||
@ -108,7 +108,7 @@ void ParallelFor( int first, int next, const TFunc & f )
|
|||||||
inline void DummyTracer (string, bool) { ; }
|
inline void DummyTracer (string, bool) { ; }
|
||||||
|
|
||||||
template <typename FUNC>
|
template <typename FUNC>
|
||||||
inline void ParallelFor (TaskManager tm, size_t n, FUNC func)
|
inline void ParallelFor (NgTaskManager tm, size_t n, FUNC func)
|
||||||
{
|
{
|
||||||
(*tm) ([n,func] (size_t nr, size_t nums)
|
(*tm) ([n,func] (size_t nr, size_t nums)
|
||||||
{
|
{
|
||||||
@ -121,7 +121,7 @@ void ParallelFor( int first, int next, const TFunc & f )
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename FUNC>
|
template <typename FUNC>
|
||||||
inline void ParallelForRange (TaskManager tm, size_t n, FUNC func)
|
inline void ParallelForRange (NgTaskManager tm, size_t n, FUNC func)
|
||||||
{
|
{
|
||||||
(*tm) ([n,func] (size_t nr, size_t nums)
|
(*tm) ([n,func] (size_t nr, size_t nums)
|
||||||
{
|
{
|
||||||
|
@ -114,11 +114,22 @@ public:
|
|||||||
/// Creates table of size size
|
/// Creates table of size size
|
||||||
inline TABLE (int size) : BASE_TABLE (size) { ; }
|
inline TABLE (int size) : BASE_TABLE (size) { ; }
|
||||||
|
|
||||||
|
TABLE (TABLE && tab2)
|
||||||
|
: BASE_TABLE(move(tab2))
|
||||||
|
{ }
|
||||||
|
|
||||||
/// Creates fixed maximal element size table
|
/// Creates fixed maximal element size table
|
||||||
inline TABLE (const NgFlatArray<int,BASE> & entrysizes)
|
inline TABLE (const NgFlatArray<int,BASE> & entrysizes)
|
||||||
: BASE_TABLE (NgFlatArray<int> (entrysizes.Size(), const_cast<int*>(&entrysizes[BASE])),
|
: BASE_TABLE (NgFlatArray<int> (entrysizes.Size(), const_cast<int*>(&entrysizes[BASE])),
|
||||||
sizeof(T))
|
sizeof(T))
|
||||||
{ ; }
|
{ ; }
|
||||||
|
|
||||||
|
TABLE & operator= (TABLE && tab2)
|
||||||
|
{
|
||||||
|
BASE_TABLE::operator=(move(tab2));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Changes Size of table to size, deletes data
|
/// Changes Size of table to size, deletes data
|
||||||
inline void SetSize (int size)
|
inline void SetSize (int size)
|
||||||
|
@ -14,6 +14,8 @@ namespace netgen
|
|||||||
templates, global types, defines and variables
|
templates, global types, defines and variables
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
DLL_HEADER extern const string netgen_version;
|
||||||
|
|
||||||
/// The following value may be adapted to the hardware !
|
/// The following value may be adapted to the hardware !
|
||||||
#ifndef CLOCKS_PER_SEC
|
#ifndef CLOCKS_PER_SEC
|
||||||
#define CLOCKS_PER_SEC 1000000
|
#define CLOCKS_PER_SEC 1000000
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
add_definitions(-DNGLIB_EXPORTS)
|
add_definitions(-DNGINTERFACE_EXPORTS)
|
||||||
add_library(geom2d ${NG_LIB_TYPE} genmesh2d.cpp geometry2d.cpp python_geom2d.cpp )
|
add_library(geom2d ${NG_LIB_TYPE} csg2d.cpp genmesh2d.cpp geometry2d.cpp python_geom2d.cpp )
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
set_target_properties( geom2d PROPERTIES SUFFIX ".so")
|
set_target_properties( geom2d PROPERTIES SUFFIX ".so")
|
||||||
endif(APPLE)
|
endif(APPLE)
|
||||||
|
|
||||||
target_link_libraries(geom2d PUBLIC ngcore mesh PRIVATE netgen_python)
|
target_link_libraries(geom2d PUBLIC ngcore mesh PRIVATE "$<BUILD_INTERFACE:netgen_python>")
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
install( TARGETS geom2d ${NG_INSTALL_DIR})
|
install( TARGETS geom2d ${NG_INSTALL_DIR})
|
||||||
endif(NOT WIN32)
|
endif(NOT WIN32)
|
||||||
@ -20,6 +20,6 @@ endif(USE_GUI)
|
|||||||
|
|
||||||
install(FILES
|
install(FILES
|
||||||
geometry2d.hpp spline2d.hpp
|
geometry2d.hpp spline2d.hpp
|
||||||
vsgeom2d.hpp
|
vsgeom2d.hpp csg2d.hpp
|
||||||
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/geom2d COMPONENT netgen_devel
|
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/geom2d COMPONENT netgen_devel
|
||||||
)
|
)
|
||||||
|
2235
libsrc/geom2d/csg2d.cpp
Normal file
2235
libsrc/geom2d/csg2d.cpp
Normal file
File diff suppressed because it is too large
Load Diff
741
libsrc/geom2d/csg2d.hpp
Normal file
741
libsrc/geom2d/csg2d.hpp
Normal file
@ -0,0 +1,741 @@
|
|||||||
|
#ifndef NETGEN_CSG2D_HPP_INCLUDED
|
||||||
|
#define NETGEN_CSG2D_HPP_INCLUDED
|
||||||
|
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include "geometry2d.hpp"
|
||||||
|
|
||||||
|
namespace netgen
|
||||||
|
{
|
||||||
|
|
||||||
|
using namespace ngcore;
|
||||||
|
using netgen::Point;
|
||||||
|
using netgen::Vec;
|
||||||
|
using Spline = SplineSeg3<2>;
|
||||||
|
using netgen::Box;
|
||||||
|
|
||||||
|
inline double Area(const Point<2>& P, const Point<2>& Q, const Point<2>& R)
|
||||||
|
{
|
||||||
|
return (Q[0]-P[0]) * (R[1]-P[1]) - (Q[1]-P[1]) * (R[0]-P[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute weight of spline such that p lies on it
|
||||||
|
void ComputeWeight( Spline & s, Point<2> p );
|
||||||
|
|
||||||
|
enum IntersectionType
|
||||||
|
{ // types of intersection (detected in the first phase)
|
||||||
|
NO_INTERSECTION = 0,
|
||||||
|
X_INTERSECTION,
|
||||||
|
T_INTERSECTION_Q,
|
||||||
|
T_INTERSECTION_P,
|
||||||
|
V_INTERSECTION,
|
||||||
|
X_OVERLAP, // Q0 -- P1 -- Q1 -- P0 (different direction)
|
||||||
|
T_OVERLAP_Q, // same direction or P inside Q
|
||||||
|
T_OVERLAP_P, // same direction or Q inside P
|
||||||
|
V_OVERLAP // one common point
|
||||||
|
};
|
||||||
|
|
||||||
|
enum IntersectionLabel
|
||||||
|
{ // for the classification of intersection vertices in the second phase
|
||||||
|
NONE,
|
||||||
|
CROSSING,
|
||||||
|
BOUNCING,
|
||||||
|
LEFT_ON,
|
||||||
|
RIGHT_ON,
|
||||||
|
ON_ON,
|
||||||
|
ON_LEFT,
|
||||||
|
ON_RIGHT,
|
||||||
|
DELAYED_CROSSING,
|
||||||
|
DELAYED_BOUNCING
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EntryExitLabel
|
||||||
|
{ // for marking intersection vertices as "entry" or "exit"
|
||||||
|
EXIT,
|
||||||
|
ENTRY,
|
||||||
|
NEITHER
|
||||||
|
};
|
||||||
|
|
||||||
|
enum IteratorType
|
||||||
|
{
|
||||||
|
SOURCE,
|
||||||
|
INTERSECTION,
|
||||||
|
CROSSING_INTERSECTION,
|
||||||
|
ALL
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr const double MAXH_DEFAULT{1e99};
|
||||||
|
inline const string POINT_NAME_DEFAULT{""};
|
||||||
|
inline const string BC_DEFAULT{""};
|
||||||
|
inline const string MAT_DEFAULT{""};
|
||||||
|
|
||||||
|
struct EdgeInfo
|
||||||
|
{
|
||||||
|
optional<Point<2>> control_point = nullopt; // for spline segments
|
||||||
|
double maxh = MAXH_DEFAULT;
|
||||||
|
string bc = BC_DEFAULT;
|
||||||
|
|
||||||
|
EdgeInfo() = default;
|
||||||
|
EdgeInfo(Point<2> p) : control_point(p) {}
|
||||||
|
EdgeInfo(double h) : maxh(h) {}
|
||||||
|
EdgeInfo(string s) : bc(s) {}
|
||||||
|
EdgeInfo(optional<Point<2>> p, double h, string s)
|
||||||
|
: control_point(p), maxh(h), bc(s)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void Assign( EdgeInfo other )
|
||||||
|
{
|
||||||
|
if(other.control_point != nullopt)
|
||||||
|
control_point = other.control_point;
|
||||||
|
if(other.bc != BC_DEFAULT)
|
||||||
|
bc = other.bc;
|
||||||
|
if(other.maxh != MAXH_DEFAULT)
|
||||||
|
maxh = min(maxh, other.maxh);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PointInfo
|
||||||
|
{
|
||||||
|
double maxh = MAXH_DEFAULT;
|
||||||
|
string name = POINT_NAME_DEFAULT;
|
||||||
|
PointInfo() = default;
|
||||||
|
PointInfo(const PointInfo& other) = default;
|
||||||
|
PointInfo(double amaxh) : maxh(amaxh) {}
|
||||||
|
PointInfo(string aname) : name(aname) {}
|
||||||
|
PointInfo(double amaxh, string aname) : maxh(amaxh), name(aname) {}
|
||||||
|
|
||||||
|
void Assign(const PointInfo& other)
|
||||||
|
{
|
||||||
|
maxh = min(maxh, other.maxh);
|
||||||
|
if(other.name != POINT_NAME_DEFAULT)
|
||||||
|
name = other.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Vertex : Point<2>
|
||||||
|
{
|
||||||
|
Vertex (Point<2> p) : Point<2>(p) {}
|
||||||
|
Vertex (const Vertex & v) : Point<2>(v)
|
||||||
|
{
|
||||||
|
spline = v.spline;
|
||||||
|
info = v.info;
|
||||||
|
pinfo = v.pinfo;
|
||||||
|
is_source = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex * prev = nullptr;
|
||||||
|
Vertex * next = nullptr;
|
||||||
|
unique_ptr<Vertex> pnext = nullptr;
|
||||||
|
Vertex * neighbour = nullptr; // same vertex in other polygon (at intersections)
|
||||||
|
double lam = -1.0;
|
||||||
|
bool is_intersection = false;
|
||||||
|
bool is_source = false;
|
||||||
|
|
||||||
|
IntersectionLabel label = NONE; // type of intersection vertex
|
||||||
|
EntryExitLabel enex = NEITHER; // entry/exit "flag"
|
||||||
|
|
||||||
|
// In case the edge this - next is curved, store the spline information here
|
||||||
|
optional<Spline> spline = nullopt;
|
||||||
|
EdgeInfo info;
|
||||||
|
PointInfo pinfo;
|
||||||
|
|
||||||
|
DLL_HEADER Vertex * Insert(Point<2> p, double lam = -1.0);
|
||||||
|
|
||||||
|
void Link( Vertex * v )
|
||||||
|
{
|
||||||
|
neighbour = v;
|
||||||
|
v->neighbour = this;
|
||||||
|
is_intersection = true;
|
||||||
|
v->is_intersection = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct VertexIterator
|
||||||
|
{
|
||||||
|
struct iterator
|
||||||
|
{
|
||||||
|
iterator(Vertex* root, IteratorType IterType) :
|
||||||
|
root(root), V(NULL), iterType(IterType)
|
||||||
|
{
|
||||||
|
if (root == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (nextVertex() == NULL) // no (source/intersection) vertex found
|
||||||
|
root = V = NULL; // -> mark iterator as "end"
|
||||||
|
}
|
||||||
|
|
||||||
|
const iterator& operator++()
|
||||||
|
{
|
||||||
|
nextVertex();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex* operator*()
|
||||||
|
{
|
||||||
|
return V;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const iterator& other) const
|
||||||
|
{
|
||||||
|
return (root != other.root) || (V != other.V);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vertex* root;
|
||||||
|
Vertex* V;
|
||||||
|
IteratorType iterType;
|
||||||
|
|
||||||
|
//
|
||||||
|
// find the next vertex
|
||||||
|
// if iterType is ALL, then it is just the next vertex
|
||||||
|
// if iterType is SOURCE, then it is the next source vertex
|
||||||
|
// if iterType is INTERSECTION, then it is the next intersection vertex
|
||||||
|
// if iterType is CROSSING_INTERSECTION, then it is the next intersection vertex with CROSSING label
|
||||||
|
//
|
||||||
|
Vertex* nextVertex()
|
||||||
|
{
|
||||||
|
bool nextFound = false;
|
||||||
|
|
||||||
|
if (V == NULL)
|
||||||
|
{ // find first (source/intersection) vertex
|
||||||
|
V = root;
|
||||||
|
switch(iterType)
|
||||||
|
{
|
||||||
|
case ALL:
|
||||||
|
nextFound = true;
|
||||||
|
break;
|
||||||
|
case SOURCE:
|
||||||
|
if (V->is_source)
|
||||||
|
nextFound = true;
|
||||||
|
break;
|
||||||
|
case INTERSECTION:
|
||||||
|
if (V->is_intersection)
|
||||||
|
nextFound = true;
|
||||||
|
break;
|
||||||
|
case CROSSING_INTERSECTION:
|
||||||
|
if (V->is_intersection && (V->label == CROSSING))
|
||||||
|
nextFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!nextFound)
|
||||||
|
{ // find next (source/intersection) vertex
|
||||||
|
switch(iterType)
|
||||||
|
{
|
||||||
|
case ALL:
|
||||||
|
V = V->next;
|
||||||
|
break;
|
||||||
|
case SOURCE:
|
||||||
|
do {
|
||||||
|
V = V->next;
|
||||||
|
} while (!V->is_source && V != root);
|
||||||
|
break;
|
||||||
|
case INTERSECTION:
|
||||||
|
do {
|
||||||
|
V = V->next;
|
||||||
|
} while (!V->is_intersection && V != root);
|
||||||
|
break;
|
||||||
|
case CROSSING_INTERSECTION:
|
||||||
|
do {
|
||||||
|
V = V->next;
|
||||||
|
} while ( ( !V->is_intersection || (V->label != CROSSING) ) && V != root);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (V == root)
|
||||||
|
{ // back at the root vertex?
|
||||||
|
root = V = NULL; // -> mark iterator as "end"
|
||||||
|
return(V);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(iterType)
|
||||||
|
{
|
||||||
|
case ALL:
|
||||||
|
nextFound = true;
|
||||||
|
break;
|
||||||
|
case SOURCE:
|
||||||
|
if (V->is_source)
|
||||||
|
nextFound = true;
|
||||||
|
break;
|
||||||
|
case INTERSECTION:
|
||||||
|
if (V->is_intersection)
|
||||||
|
nextFound = true;
|
||||||
|
break;
|
||||||
|
case CROSSING_INTERSECTION:
|
||||||
|
if (V->is_intersection && (V->label == CROSSING))
|
||||||
|
nextFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(V);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
VertexIterator() : root(NULL) {};
|
||||||
|
|
||||||
|
iterator begin() { return iterator(root, iterType); }
|
||||||
|
iterator end() { return iterator(NULL, iterType); }
|
||||||
|
|
||||||
|
Vertex* root;
|
||||||
|
IteratorType iterType;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Edge
|
||||||
|
{
|
||||||
|
Vertex * v0 = nullptr;
|
||||||
|
Vertex * v1 = nullptr;
|
||||||
|
|
||||||
|
Edge (Vertex* v, Vertex* w) : v0(v), v1(w) { };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EdgeIterator
|
||||||
|
{
|
||||||
|
struct iterator
|
||||||
|
{
|
||||||
|
iterator(Vertex* root, IteratorType IterType) :
|
||||||
|
root(root), one(NULL), two(NULL), iterType(IterType)
|
||||||
|
{
|
||||||
|
if (root == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (nextEdge() == NULL) // no source edge found
|
||||||
|
root = one = two = NULL; // -> mark iterator as "end"
|
||||||
|
}
|
||||||
|
|
||||||
|
const iterator& operator++() { nextEdge(); return *this; }
|
||||||
|
|
||||||
|
Edge operator*()
|
||||||
|
{
|
||||||
|
return Edge(one,two);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const iterator& other) const
|
||||||
|
{
|
||||||
|
return (root != other.root) || (one != other.one) || (two != other.two);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vertex* root;
|
||||||
|
Vertex* one;
|
||||||
|
Vertex* two;
|
||||||
|
IteratorType iterType;
|
||||||
|
|
||||||
|
//
|
||||||
|
// find the next vertex, starting at curr
|
||||||
|
// if iterType is ALL, then it is just the next vertex
|
||||||
|
// if iterType is SOURCE, then it is the next source vertex
|
||||||
|
//
|
||||||
|
Vertex* nextVertex(Vertex* curr)
|
||||||
|
{
|
||||||
|
if (curr == NULL)
|
||||||
|
return(NULL);
|
||||||
|
|
||||||
|
switch(iterType)
|
||||||
|
{
|
||||||
|
case ALL:
|
||||||
|
curr = curr->next;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOURCE:
|
||||||
|
do {
|
||||||
|
curr = curr->next;
|
||||||
|
} while (!curr->is_source);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(curr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// find the next edge
|
||||||
|
//
|
||||||
|
Vertex* nextEdge()
|
||||||
|
{
|
||||||
|
if (root == NULL) // empty polygon?
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
if (one == NULL)
|
||||||
|
{ // find one (source) vertex
|
||||||
|
one = root; // note: root is always a (source) vertex
|
||||||
|
two = nextVertex(one);
|
||||||
|
if (two == one) // just one (source) vertex
|
||||||
|
return(NULL); // -> no (source) edges
|
||||||
|
return(one);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (two == root)
|
||||||
|
{ // back at the root vertex?
|
||||||
|
root = one = two = NULL; // -> mark iterator as "end"
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
one = two;
|
||||||
|
two = nextVertex(one);
|
||||||
|
|
||||||
|
return (one);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
EdgeIterator() : root(NULL) {};
|
||||||
|
|
||||||
|
iterator begin() { return iterator(root, iterType); }
|
||||||
|
iterator end() { return iterator(NULL, iterType); }
|
||||||
|
|
||||||
|
Vertex* root;
|
||||||
|
IteratorType iterType;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline int CalcSide( const Point<2> & p0, const Point<2> & p1, const Point<2> & r )
|
||||||
|
{
|
||||||
|
if ( (p0[1] < r[1]) != (p1[1] < r[1]) )
|
||||||
|
{
|
||||||
|
if (p0[0] >= r[0])
|
||||||
|
{
|
||||||
|
if (p1[0] > r[0])
|
||||||
|
return 2 * (p1[1] > p0[1]) - 1;
|
||||||
|
else
|
||||||
|
if ( (Area(p0,p1,r) > 0) == (p1[1] > p0[1]) )
|
||||||
|
return 2 * (p1[1] > p0[1]) - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (p1[0] > r[0])
|
||||||
|
if ( (Area(p0,p1,r) > 0) == (p1[1] > p0[1]) )
|
||||||
|
return 2 * (p1[1] > p0[1]) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Loop
|
||||||
|
{
|
||||||
|
unique_ptr<Vertex> first = nullptr;
|
||||||
|
unique_ptr<Box<2>> bbox = nullptr;
|
||||||
|
|
||||||
|
Loop() = default;
|
||||||
|
|
||||||
|
Loop(const Loop & p)
|
||||||
|
: first(nullptr)
|
||||||
|
{
|
||||||
|
for(auto v : p.Vertices(ALL))
|
||||||
|
AppendVertex(*v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Loop(Loop && p) = default;
|
||||||
|
|
||||||
|
Loop & operator=(Loop && p) = default;
|
||||||
|
|
||||||
|
Loop & operator=(const Loop & p)
|
||||||
|
{
|
||||||
|
// static Timer t("Loop::operator="); RegionTimer rt(t);
|
||||||
|
first = nullptr;
|
||||||
|
if(p.first)
|
||||||
|
{
|
||||||
|
size_t n = p.Size();
|
||||||
|
Array<unique_ptr<Vertex>> new_verts(n);
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
for(const auto v : p.Vertices(ALL))
|
||||||
|
new_verts[i++] = make_unique<Vertex>(*v);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto i : IntRange(n-1))
|
||||||
|
{
|
||||||
|
Vertex * v = new_verts[i].get();
|
||||||
|
Vertex * vn = new_verts[i+1].get();
|
||||||
|
v->next = vn;
|
||||||
|
vn->prev = v;
|
||||||
|
}
|
||||||
|
Vertex * vfirst = new_verts[0].get();
|
||||||
|
Vertex * vlast = new_verts[n-1].get();
|
||||||
|
vfirst->prev = vlast;
|
||||||
|
vlast->next = vfirst;
|
||||||
|
|
||||||
|
for(auto i : IntRange(1,n))
|
||||||
|
new_verts[n-1-i]->pnext = std::move(new_verts[n-i]);
|
||||||
|
|
||||||
|
first = std::move(new_verts[0]);
|
||||||
|
}
|
||||||
|
bbox = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
first = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex & AppendVertex(const Vertex & v)
|
||||||
|
{
|
||||||
|
auto & vnew = Append( static_cast<Point<2>>(v), true );
|
||||||
|
vnew.info = v.info;
|
||||||
|
vnew.pinfo = v.pinfo;
|
||||||
|
if(v.spline)
|
||||||
|
vnew.spline = *v.spline;
|
||||||
|
if(bbox)
|
||||||
|
bbox->Add(v);
|
||||||
|
return vnew;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vertex & Append(Point<2> p, bool source = false)
|
||||||
|
{
|
||||||
|
Vertex * vnew;
|
||||||
|
if(first==nullptr)
|
||||||
|
{
|
||||||
|
first = make_unique<Vertex>(p);
|
||||||
|
first->next = first.get();
|
||||||
|
first->prev = first.get();
|
||||||
|
vnew = first.get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vnew = first->prev->Insert(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
vnew->is_source = source;
|
||||||
|
// cout << "size after " << Size() << endl;
|
||||||
|
if(bbox)
|
||||||
|
bbox->Add(p);
|
||||||
|
return *vnew;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Remove (Vertex* v)
|
||||||
|
{
|
||||||
|
v->prev->next = v->next;
|
||||||
|
v->next->prev = v->prev;
|
||||||
|
if(first.get() == v)
|
||||||
|
first = std::move(v->pnext);
|
||||||
|
else
|
||||||
|
v->prev->pnext = std::move(v->pnext);
|
||||||
|
bbox.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInside( Point<2> r ) const;
|
||||||
|
bool IsLeftInside( const Vertex & p0 );
|
||||||
|
bool IsRightInside( const Vertex & p0 );
|
||||||
|
|
||||||
|
EdgeIterator Edges(IteratorType iterType) const
|
||||||
|
{
|
||||||
|
EdgeIterator it;
|
||||||
|
it.iterType = iterType;
|
||||||
|
it.root = first.get();
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexIterator Vertices(IteratorType iterType, Vertex* first_ = nullptr) const
|
||||||
|
{
|
||||||
|
VertexIterator it;
|
||||||
|
it.iterType = iterType;
|
||||||
|
it.root = (first_ == nullptr) ? first.get() : first_;
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// check, if all vertices have the ON_ON label
|
||||||
|
//
|
||||||
|
bool allOnOn()
|
||||||
|
{
|
||||||
|
for (Vertex* v : Vertices(ALL))
|
||||||
|
if (v->label != ON_ON)
|
||||||
|
return(false);
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// check, if the polygon does not contain any crossing intersection vertex
|
||||||
|
// or crossing intersection chain or (if we want to compute the union instead
|
||||||
|
// of the intersection) a bouncing vertex or a bouncing intersection chain
|
||||||
|
//
|
||||||
|
bool noCrossingVertex(bool union_case = false)
|
||||||
|
{
|
||||||
|
for (Vertex* v : Vertices(ALL))
|
||||||
|
if (v->is_intersection)
|
||||||
|
{
|
||||||
|
if ( (v->label == CROSSING) || (v->label == DELAYED_CROSSING) )
|
||||||
|
return(false);
|
||||||
|
|
||||||
|
if (union_case && ( (v->label == BOUNCING) || (v->label == DELAYED_BOUNCING) ) )
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// return a non-intersection point
|
||||||
|
//
|
||||||
|
Point<2> getNonIntersectionPoint()
|
||||||
|
{
|
||||||
|
for (Vertex* v : Vertices(ALL))
|
||||||
|
if (!v->is_intersection)
|
||||||
|
return *v;
|
||||||
|
|
||||||
|
// no non-intersection vertex found -> find suitable edge midpoint
|
||||||
|
for (Vertex* v : Vertices(ALL))
|
||||||
|
// make sure that edge from V to V->next is not collinear with other polygon
|
||||||
|
if ( (v->next->neighbour != v->neighbour->prev) && (v->next->neighbour != v->neighbour->next) )
|
||||||
|
// return edge midpoint
|
||||||
|
return Center(*v, *v->next);
|
||||||
|
throw Exception("no point found");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// return and insert a non-intersection vertex
|
||||||
|
//
|
||||||
|
Vertex* getNonIntersectionVertex();
|
||||||
|
|
||||||
|
void SetBC(string bc)
|
||||||
|
{
|
||||||
|
for(auto v : Vertices(ALL))
|
||||||
|
v->info.bc = bc;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Size() const
|
||||||
|
{
|
||||||
|
if(first==nullptr) return 0;
|
||||||
|
|
||||||
|
size_t cnt = 0;
|
||||||
|
|
||||||
|
for(auto v : Vertices(ALL))
|
||||||
|
cnt++;
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Box<2> & GetBoundingBox()
|
||||||
|
{
|
||||||
|
if(bbox==nullptr)
|
||||||
|
{
|
||||||
|
static Timer tall("Loop::GetBoundingBox"); RegionTimer rt(tall);
|
||||||
|
bbox = make_unique<Box<2>>(Box<2>::EMPTY_BOX);
|
||||||
|
for(auto v : Vertices(ALL))
|
||||||
|
{
|
||||||
|
bbox->Add(*v);
|
||||||
|
if(v->spline)
|
||||||
|
bbox->Add(v->spline->TangentPoint());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *bbox;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Solid2d
|
||||||
|
{
|
||||||
|
Array<Loop> polys;
|
||||||
|
|
||||||
|
string name = MAT_DEFAULT;
|
||||||
|
|
||||||
|
Solid2d() = default;
|
||||||
|
Solid2d(string name_) : name(name_) {}
|
||||||
|
DLL_HEADER Solid2d(const Array<std::variant<Point<2>, EdgeInfo, PointInfo>> & points, string name_=MAT_DEFAULT, string bc_=BC_DEFAULT);
|
||||||
|
Solid2d(Solid2d && other) = default;
|
||||||
|
Solid2d(const Solid2d & other) = default;
|
||||||
|
|
||||||
|
DLL_HEADER Solid2d operator+(const Solid2d & other) const;
|
||||||
|
DLL_HEADER Solid2d operator*(const Solid2d & other) const;
|
||||||
|
DLL_HEADER Solid2d operator-(const Solid2d & other) const;
|
||||||
|
|
||||||
|
Solid2d& operator=(Solid2d && other) = default;
|
||||||
|
Solid2d& operator=(const Solid2d & other) = default;
|
||||||
|
DLL_HEADER Solid2d& operator+=(const Solid2d & other);
|
||||||
|
DLL_HEADER Solid2d& operator*=(const Solid2d & other);
|
||||||
|
DLL_HEADER Solid2d& operator-=(const Solid2d & other);
|
||||||
|
|
||||||
|
void Append( const Loop & poly )
|
||||||
|
{
|
||||||
|
polys.Append(poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInside( Point<2> r ) const;
|
||||||
|
bool IsLeftInside( const Vertex & p0 );
|
||||||
|
bool IsRightInside( const Vertex & p0 );
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
Solid2d & Transform( const TFunc & func )
|
||||||
|
{
|
||||||
|
for(auto & poly : polys)
|
||||||
|
for(auto v : poly.Vertices(ALL))
|
||||||
|
{
|
||||||
|
auto p = func(*v);
|
||||||
|
(*v)[0] = p[0];
|
||||||
|
(*v)[1] = p[1];
|
||||||
|
if(v->spline)
|
||||||
|
{
|
||||||
|
auto &s = *v->spline;
|
||||||
|
auto pmid = func(s.GetPoint(0.5));
|
||||||
|
s = Spline(func(s.StartPI()), func(s.TangentPoint()), func(s.EndPI()));
|
||||||
|
ComputeWeight(s, pmid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Solid2d & Move( Vec<2> v );
|
||||||
|
Solid2d & Scale( double s );
|
||||||
|
Solid2d & Scale( Vec<2> s );
|
||||||
|
Solid2d & RotateRad( double ang, Point<2> center = {0,0} );
|
||||||
|
Solid2d & RotateDeg( double ang, Point<2> center = {0,0} )
|
||||||
|
{
|
||||||
|
return RotateRad( ang/180.*M_PI, center );
|
||||||
|
}
|
||||||
|
|
||||||
|
Solid2d & BC(string bc)
|
||||||
|
{
|
||||||
|
for(auto & p : polys)
|
||||||
|
for(auto v : p.Vertices(ALL))
|
||||||
|
v->info.bc = bc;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Solid2d & Maxh(double maxh)
|
||||||
|
{
|
||||||
|
for(auto & p : polys)
|
||||||
|
for(auto v : p.Vertices(ALL))
|
||||||
|
v->info.maxh = maxh;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Solid2d & Mat(string mat)
|
||||||
|
{
|
||||||
|
name = mat;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Box<2> GetBoundingBox() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CSG2d
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Array<Solid2d> solids;
|
||||||
|
|
||||||
|
void Add ( Solid2d s )
|
||||||
|
{
|
||||||
|
solids.Append(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
DLL_HEADER shared_ptr<netgen::SplineGeometry2d> GenerateSplineGeometry();
|
||||||
|
DLL_HEADER shared_ptr<netgen::Mesh> GenerateMesh(MeshingParameters & mp);
|
||||||
|
};
|
||||||
|
|
||||||
|
DLL_HEADER Solid2d Circle( Point<2> center, double r, string name="", string bc="");
|
||||||
|
DLL_HEADER Solid2d Rectangle( Point<2> p0, Point<2> p1, string mat=MAT_DEFAULT, string bc=BC_DEFAULT );
|
||||||
|
|
||||||
|
DLL_HEADER void AddIntersectionPoints ( Solid2d & s1, Solid2d & s2 );
|
||||||
|
DLL_HEADER Solid2d ClipSolids ( const Solid2d & s1, const Solid2d & s2, char op);
|
||||||
|
DLL_HEADER Solid2d ClipSolids ( const Solid2d & s1, Solid2d && s2, char op);
|
||||||
|
DLL_HEADER Solid2d ClipSolids ( Solid2d && s1, const Solid2d & s2, char op);
|
||||||
|
DLL_HEADER Solid2d ClipSolids ( Solid2d && s1, Solid2d && s2, char op);
|
||||||
|
|
||||||
|
DLL_HEADER IntersectionType intersect(const Point<2> P1, const Point<2> P2, const Point<2> Q1, const Point<2> Q2, double& alpha, double& beta);
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif // NETGEN_CSG2D_HPP_INCLUDED
|
@ -18,29 +18,44 @@ namespace netgen
|
|||||||
{
|
{
|
||||||
double fperel, oldf, f;
|
double fperel, oldf, f;
|
||||||
|
|
||||||
int n = 10000;
|
int n = 1;
|
||||||
|
NgArray<Point<2> > xi;
|
||||||
NgArray<Point<2> > xi(n);
|
NgArray<double> hi;
|
||||||
NgArray<double> hi(n);
|
|
||||||
|
// do one extra step
|
||||||
for (int i = 0; i < n; i++)
|
int not_fine_enough = 2;
|
||||||
|
|
||||||
|
while(not_fine_enough && n < 10000)
|
||||||
|
{
|
||||||
|
not_fine_enough--;
|
||||||
|
n*=4;
|
||||||
|
|
||||||
|
xi.SetSize(n);
|
||||||
|
hi.SetSize(n);
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
xi[i] = spline.GetPoint ( (i+0.5) / n );
|
xi[i] = spline.GetPoint ( (i+0.5) / n );
|
||||||
hi[i] = mesh.GetH (Point<3> (xi[i](0), xi[i](1), 0));
|
hi[i] = mesh.GetH (Point<3> (xi[i](0), xi[i](1), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// limit slope
|
// limit slope
|
||||||
double gradh = min(1/elto0,mp.grading);
|
double gradh = min(1/elto0,mp.grading);
|
||||||
for (int i = 0; i < n-1; i++)
|
for (int i = 0; i < n-1; i++)
|
||||||
{
|
{
|
||||||
double hnext = hi[i] + gradh * (xi[i+1]-xi[i]).Length();
|
double hnext = hi[i] + gradh * (xi[i+1]-xi[i]).Length();
|
||||||
hi[i+1] = min(hi[i+1], hnext);
|
if(hnext > 2*hi[i])
|
||||||
|
not_fine_enough = 2;
|
||||||
|
hi[i+1] = min(hi[i+1], hnext);
|
||||||
}
|
}
|
||||||
for (int i = n-1; i > 1; i--)
|
for (int i = n-1; i > 1; i--)
|
||||||
{
|
{
|
||||||
double hnext = hi[i] + gradh * (xi[i-1]-xi[i]).Length();
|
double hnext = hi[i] + gradh * (xi[i-1]-xi[i]).Length();
|
||||||
hi[i-1] = min(hi[i-1], hnext);
|
if(hnext > 2*hi[i])
|
||||||
|
not_fine_enough = 2;
|
||||||
|
hi[i-1] = min(hi[i-1], hnext);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
points.SetSize (0);
|
points.SetSize (0);
|
||||||
|
|
||||||
@ -233,13 +248,22 @@ namespace netgen
|
|||||||
double hr = GetDomainMaxh (spline.rightdom);
|
double hr = GetDomainMaxh (spline.rightdom);
|
||||||
if (hr > 0) hcurve = min2 (hcurve, hr);
|
if (hr > 0) hcurve = min2 (hcurve, hr);
|
||||||
|
|
||||||
int np = 1000;
|
// skip curvature restrictions for straight lines
|
||||||
for (double t = 0.5/np; t < 1; t += 1.0/np)
|
if(spline.MaxCurvature()==0)
|
||||||
{
|
{
|
||||||
Point<2> x = spline.GetPoint(t);
|
mesh2d.RestrictLocalHLine (Point<3>(p1(0),p1(1),0),
|
||||||
double hc = 1.0/mp.curvaturesafety / (1e-99+spline.CalcCurvature (t));
|
Point<3>(p2(0),p2(1),0), hcurve);
|
||||||
mesh2d.RestrictLocalH (Point<3> (x(0), x(1), 0), min2(hc, hcurve));
|
}
|
||||||
}
|
else
|
||||||
|
{
|
||||||
|
int np = 1000;
|
||||||
|
for (double t = 0.5/np; t < 1; t += 1.0/np)
|
||||||
|
{
|
||||||
|
Point<2> x = spline.GetPoint(t);
|
||||||
|
double hc = 1.0/mp.curvaturesafety / (1e-99+spline.CalcCurvature (t));
|
||||||
|
mesh2d.RestrictLocalH (Point<3> (x(0), x(1), 0), min2(hc, hcurve));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto mspnt : mp.meshsize_points)
|
for (auto mspnt : mp.meshsize_points)
|
||||||
@ -278,6 +302,11 @@ namespace netgen
|
|||||||
{
|
{
|
||||||
npi = mesh2d.AddPoint (newp, layer);
|
npi = mesh2d.AddPoint (newp, layer);
|
||||||
searchtree.Insert (newp, npi);
|
searchtree.Insert (newp, npi);
|
||||||
|
mesh2d.AddLockedPoint(npi);
|
||||||
|
Element0d el(npi, npi);
|
||||||
|
el.name = "";
|
||||||
|
mesh2d.SetCD2Name(npi, "");
|
||||||
|
mesh2d.pointelements.Append (el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -392,10 +421,16 @@ namespace netgen
|
|||||||
shared_ptr<Mesh> & mesh,
|
shared_ptr<Mesh> & mesh,
|
||||||
MeshingParameters & mp)
|
MeshingParameters & mp)
|
||||||
{
|
{
|
||||||
|
static Timer tall("MeshFromSpline2D"); RegionTimer rtall(tall);
|
||||||
|
static Timer t_h("SetH");
|
||||||
|
static Timer t_tensor("tensor domain meshing");
|
||||||
|
static Timer t_part_boundary("PartitionBoundary");
|
||||||
|
static Timer t_hpref("mark hpref points");
|
||||||
PrintMessage (1, "Generate Mesh from spline geometry");
|
PrintMessage (1, "Generate Mesh from spline geometry");
|
||||||
|
|
||||||
Box<2> bbox = geometry.GetBoundingBox ();
|
Box<2> bbox = geometry.GetBoundingBox ();
|
||||||
|
|
||||||
|
t_h.Start();
|
||||||
if (bbox.Diam() < mp.maxh)
|
if (bbox.Diam() < mp.maxh)
|
||||||
mp.maxh = bbox.Diam();
|
mp.maxh = bbox.Diam();
|
||||||
|
|
||||||
@ -412,11 +447,14 @@ namespace netgen
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
t_part_boundary.Start();
|
||||||
geometry.PartitionBoundary (mp, mp.maxh, *mesh);
|
geometry.PartitionBoundary (mp, mp.maxh, *mesh);
|
||||||
|
t_part_boundary.Stop();
|
||||||
|
|
||||||
PrintMessage (3, "Boundary mesh done, np = ", mesh->GetNP());
|
PrintMessage (3, "Boundary mesh done, np = ", mesh->GetNP());
|
||||||
|
|
||||||
|
|
||||||
|
t_hpref.Start();
|
||||||
// marks mesh points for hp-refinement
|
// marks mesh points for hp-refinement
|
||||||
for (int i = 0; i < geometry.GetNP(); i++)
|
for (int i = 0; i < geometry.GetNP(); i++)
|
||||||
if (geometry.GetPoint(i).hpref)
|
if (geometry.GetPoint(i).hpref)
|
||||||
@ -434,6 +472,7 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
(*mesh)[mpi].Singularity(geometry.GetPoint(i).hpref);
|
(*mesh)[mpi].Singularity(geometry.GetPoint(i).hpref);
|
||||||
}
|
}
|
||||||
|
t_hpref.Stop();
|
||||||
|
|
||||||
|
|
||||||
int maxdomnr = 0;
|
int maxdomnr = 0;
|
||||||
@ -443,6 +482,16 @@ namespace netgen
|
|||||||
if ( (*mesh)[si].domout > maxdomnr) maxdomnr = (*mesh)[si].domout;
|
if ( (*mesh)[si].domout > maxdomnr) maxdomnr = (*mesh)[si].domout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TableCreator<const Segment*> dom2seg_creator(maxdomnr+1);
|
||||||
|
for ( ; !dom2seg_creator.Done(); dom2seg_creator++)
|
||||||
|
for (const Segment & seg : mesh->LineSegments())
|
||||||
|
{
|
||||||
|
dom2seg_creator.Add (seg.domin, &seg);
|
||||||
|
if (seg.domin != seg.domout)
|
||||||
|
dom2seg_creator.Add (seg.domout, &seg);
|
||||||
|
}
|
||||||
|
auto dom2seg = dom2seg_creator.MoveTable();
|
||||||
|
|
||||||
mesh->ClearFaceDescriptors();
|
mesh->ClearFaceDescriptors();
|
||||||
for (int i = 1; i <= maxdomnr; i++)
|
for (int i = 1; i <= maxdomnr; i++)
|
||||||
mesh->AddFaceDescriptor (FaceDescriptor (i, 0, 0, i));
|
mesh->AddFaceDescriptor (FaceDescriptor (i, 0, 0, i));
|
||||||
@ -458,10 +507,8 @@ namespace netgen
|
|||||||
for ( int sindex = 0; sindex < maxsegmentindex; sindex++ )
|
for ( int sindex = 0; sindex < maxsegmentindex; sindex++ )
|
||||||
mesh->SetBCName ( sindex, geometry.GetBCName( sindex+1 ) );
|
mesh->SetBCName ( sindex, geometry.GetBCName( sindex+1 ) );
|
||||||
|
|
||||||
for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
|
|
||||||
(*mesh)[si].SetBCName ( (*mesh).GetBCNamePtr( (*mesh)[si].si-1 ) );
|
|
||||||
|
|
||||||
mesh->CalcLocalH(mp.grading);
|
mesh->CalcLocalH(mp.grading);
|
||||||
|
t_h.Stop();
|
||||||
|
|
||||||
int bnp = mesh->GetNP(); // boundary points
|
int bnp = mesh->GetNP(); // boundary points
|
||||||
auto BndPntRange = mesh->Points().Range();
|
auto BndPntRange = mesh->Points().Range();
|
||||||
@ -472,6 +519,7 @@ namespace netgen
|
|||||||
for (int domnr = 1; domnr <= maxdomnr; domnr++)
|
for (int domnr = 1; domnr <= maxdomnr; domnr++)
|
||||||
if (geometry.GetDomainTensorMeshing (domnr))
|
if (geometry.GetDomainTensorMeshing (domnr))
|
||||||
{ // tensor product mesh
|
{ // tensor product mesh
|
||||||
|
RegionTimer rt(t_tensor);
|
||||||
|
|
||||||
NgArray<PointIndex, PointIndex::BASE> nextpi(bnp);
|
NgArray<PointIndex, PointIndex::BASE> nextpi(bnp);
|
||||||
NgArray<int, PointIndex::BASE> si1(bnp), si2(bnp);
|
NgArray<int, PointIndex::BASE> si1(bnp), si2(bnp);
|
||||||
@ -527,11 +575,16 @@ namespace netgen
|
|||||||
|
|
||||||
|
|
||||||
for (PointIndex pix = nextpi[c1], ix = 0; pix != c2; pix = nextpi[pix], ix++)
|
for (PointIndex pix = nextpi[c1], ix = 0; pix != c2; pix = nextpi[pix], ix++)
|
||||||
|
{
|
||||||
|
Point<3> px = (*mesh)[pix];
|
||||||
for (PointIndex piy = nextpi[c2], iy = 0; piy != c3; piy = nextpi[piy], iy++)
|
for (PointIndex piy = nextpi[c2], iy = 0; piy != c3; piy = nextpi[piy], iy++)
|
||||||
{
|
{
|
||||||
Point<3> p = (*mesh)[pix] + ( (*mesh)[piy] - (*mesh)[c2] );
|
double lam = Dist((*mesh)[piy],(*mesh)[c2]) / Dist((*mesh)[c3],(*mesh)[c2]);
|
||||||
pts[(nex+1)*(iy+1) + ix+1] = mesh -> AddPoint (p , 1, FIXEDPOINT);
|
auto pix1 = pts[(nex+1)*ney+ix+1];
|
||||||
|
auto pnew = px + lam*((*mesh)[pix1]-px);
|
||||||
|
pts[(nex+1)*(iy+1) + ix+1] = mesh -> AddPoint (pnew, 1, FIXEDPOINT);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < ney; i++)
|
for (int i = 0; i < ney; i++)
|
||||||
for (int j = 0; j < nex; j++)
|
for (int j = 0; j < nex; j++)
|
||||||
@ -545,13 +598,20 @@ namespace netgen
|
|||||||
|
|
||||||
mesh -> AddSurfaceElement (el);
|
mesh -> AddSurfaceElement (el);
|
||||||
}
|
}
|
||||||
|
char* material;
|
||||||
|
geometry.GetMaterial(domnr, material);
|
||||||
|
if(material)
|
||||||
|
mesh->SetMaterial(domnr, material);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static Timer t_domain("Mesh domain");
|
||||||
|
static Timer t_points("Mesh domain - find points");
|
||||||
for (int domnr = 1; domnr <= maxdomnr; domnr++)
|
for (int domnr = 1; domnr <= maxdomnr; domnr++)
|
||||||
{
|
{
|
||||||
|
RegionTimer rt(t_domain);
|
||||||
if (geometry.GetDomainTensorMeshing (domnr)) continue;
|
if (geometry.GetDomainTensorMeshing (domnr)) continue;
|
||||||
|
|
||||||
double h = mp.maxh;
|
double h = mp.maxh;
|
||||||
@ -567,19 +627,43 @@ namespace netgen
|
|||||||
|
|
||||||
Meshing2 meshing (geometry, mp, Box<3> (pmin, pmax));
|
Meshing2 meshing (geometry, mp, Box<3> (pmin, pmax));
|
||||||
|
|
||||||
NgArray<int, PointIndex::BASE> compress(bnp);
|
NgArray<int, PointIndex::BASE> compress(mesh->GetNP());
|
||||||
compress = -1;
|
compress = -1;
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
for (PointIndex pi : BndPntRange)
|
|
||||||
if ( (*mesh)[pi].GetLayer() == geometry.GetDomainLayer(domnr))
|
t_points.Start();
|
||||||
{
|
/*
|
||||||
meshing.AddPoint ((*mesh)[pi], pi);
|
for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
|
||||||
cnt++;
|
{
|
||||||
compress[pi] = cnt;
|
const auto & s = (*mesh)[si];
|
||||||
}
|
if ( s.domin==domnr || s.domout==domnr )
|
||||||
|
{
|
||||||
|
for (auto pi : {s[0], s[1]})
|
||||||
|
{
|
||||||
|
if(compress[pi]==-1)
|
||||||
|
{
|
||||||
|
meshing.AddPoint((*mesh)[pi], pi);
|
||||||
|
cnt++;
|
||||||
|
compress[pi] = cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
for (const Segment * seg : dom2seg[domnr])
|
||||||
|
if (seg->domin==domnr || seg->domout==domnr )
|
||||||
|
for (auto pi : {(*seg)[0], (*seg)[1]})
|
||||||
|
if (compress[pi]==-1)
|
||||||
|
{
|
||||||
|
meshing.AddPoint((*mesh)[pi], pi);
|
||||||
|
cnt++;
|
||||||
|
compress[pi] = cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PointGeomInfo gi;
|
PointGeomInfo gi;
|
||||||
gi.trignum = 1;
|
gi.trignum = 1;
|
||||||
|
/*
|
||||||
for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
|
for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
|
||||||
{
|
{
|
||||||
if ( (*mesh)[si].domin == domnr)
|
if ( (*mesh)[si].domin == domnr)
|
||||||
@ -593,13 +677,31 @@ namespace netgen
|
|||||||
compress[(*mesh)[si][0]], gi, gi);
|
compress[(*mesh)[si][0]], gi, gi);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// not complete, use at own risk ...
|
for (const Segment * seg : dom2seg[domnr])
|
||||||
// meshing.Delaunay(*mesh, domnr, mp);
|
{
|
||||||
mp.checkoverlap = 0;
|
if (seg->domin == domnr)
|
||||||
auto res = meshing.GenerateMesh (*mesh, mp, h, domnr);
|
meshing.AddBoundaryElement (compress[(*seg)[0]],
|
||||||
if (res != 0)
|
compress[(*seg)[1]], gi, gi);
|
||||||
throw NgException("meshing failed");
|
|
||||||
|
if (seg->domout == domnr)
|
||||||
|
meshing.AddBoundaryElement (compress[(*seg)[1]],
|
||||||
|
compress[(*seg)[0]], gi, gi);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
t_points.Stop();
|
||||||
|
|
||||||
|
if(mp.delaunay2d && cnt>1)
|
||||||
|
meshing.Delaunay(*mesh, domnr, mp);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// mp.checkoverlap = 0;
|
||||||
|
auto res = meshing.GenerateMesh (*mesh, mp, h, domnr);
|
||||||
|
if (res != 0)
|
||||||
|
throw NgException("meshing failed");
|
||||||
|
}
|
||||||
|
|
||||||
for (SurfaceElementIndex sei = oldnf; sei < mesh->GetNSE(); sei++)
|
for (SurfaceElementIndex sei = oldnf; sei < mesh->GetNSE(); sei++)
|
||||||
(*mesh)[sei].SetIndex (domnr);
|
(*mesh)[sei].SetIndex (domnr);
|
||||||
@ -611,6 +713,8 @@ namespace netgen
|
|||||||
mesh->SetMaterial (domnr, material);
|
mesh->SetMaterial (domnr, material);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mesh->Compress();
|
||||||
|
|
||||||
mp.quad = hquad;
|
mp.quad = hquad;
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
#include <myadt.hpp>
|
#include <myadt.hpp>
|
||||||
#include <gprim.hpp>
|
#include <gprim.hpp>
|
||||||
|
#include <meshing.hpp>
|
||||||
|
|
||||||
|
|
||||||
// #include "../gprim/spline.hpp"
|
// #include "../gprim/spline.hpp"
|
||||||
@ -133,7 +134,7 @@ namespace netgen
|
|||||||
NgArray<char*> materials;
|
NgArray<char*> materials;
|
||||||
NgArray<double> maxh;
|
NgArray<double> maxh;
|
||||||
NgArray<bool> quadmeshing;
|
NgArray<bool> quadmeshing;
|
||||||
NgArray<bool> tensormeshing;
|
Array<bool> tensormeshing;
|
||||||
NgArray<int> layer;
|
NgArray<int> layer;
|
||||||
NgArray<string*> bcnames;
|
NgArray<string*> bcnames;
|
||||||
double elto0 = 1.0;
|
double elto0 = 1.0;
|
||||||
@ -203,8 +204,8 @@ namespace netgen
|
|||||||
|
|
||||||
|
|
||||||
size_t GetNDomains() const { return materials.Size(); }
|
size_t GetNDomains() const { return materials.Size(); }
|
||||||
void GetMaterial (int domnr, char* & material );
|
DLL_HEADER void GetMaterial (int domnr, char* & material );
|
||||||
void SetMaterial (int domnr, const string & material);
|
DLL_HEADER void SetMaterial (int domnr, const string & material);
|
||||||
|
|
||||||
double GetDomainMaxh ( const int domnr );
|
double GetDomainMaxh ( const int domnr );
|
||||||
void SetDomainMaxh ( const int domnr, double maxh );
|
void SetDomainMaxh ( const int domnr, double maxh );
|
||||||
@ -214,11 +215,36 @@ namespace netgen
|
|||||||
if ( quadmeshing.Size() ) return quadmeshing[domnr-1];
|
if ( quadmeshing.Size() ) return quadmeshing[domnr-1];
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
void SetDomainQuadMeshing ( int domnr, bool quad_meshing )
|
||||||
|
{
|
||||||
|
auto oldsize = quadmeshing.Size();
|
||||||
|
|
||||||
|
if ( oldsize<domnr )
|
||||||
|
{
|
||||||
|
quadmeshing.SetSize(domnr);
|
||||||
|
for(auto dom : IntRange(oldsize, domnr-1))
|
||||||
|
quadmeshing[dom] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
quadmeshing[domnr-1] = quad_meshing;
|
||||||
|
}
|
||||||
|
|
||||||
bool GetDomainTensorMeshing ( int domnr )
|
bool GetDomainTensorMeshing ( int domnr )
|
||||||
{
|
{
|
||||||
if ( tensormeshing.Size() ) return tensormeshing[domnr-1];
|
if ( tensormeshing.Size()>=domnr ) return tensormeshing[domnr-1];
|
||||||
else return false;
|
else return false;
|
||||||
}
|
}
|
||||||
|
void SetDomainTensorMeshing ( int domnr, bool tm )
|
||||||
|
{
|
||||||
|
if ( tensormeshing.Size()<domnr )
|
||||||
|
{
|
||||||
|
auto oldsize = tensormeshing.Size();
|
||||||
|
tensormeshing.SetSize(domnr);
|
||||||
|
for(auto i : IntRange(oldsize, domnr-1))
|
||||||
|
tensormeshing[i] = false;
|
||||||
|
}
|
||||||
|
tensormeshing[domnr-1] = tm;
|
||||||
|
}
|
||||||
int GetDomainLayer ( int domnr )
|
int GetDomainLayer ( int domnr )
|
||||||
{
|
{
|
||||||
if ( layer.Size() ) return layer[domnr-1];
|
if ( layer.Size() ) return layer[domnr-1];
|
||||||
|
@ -6,8 +6,10 @@
|
|||||||
|
|
||||||
#include <meshing.hpp>
|
#include <meshing.hpp>
|
||||||
#include <geometry2d.hpp>
|
#include <geometry2d.hpp>
|
||||||
|
#include <csg2d.hpp>
|
||||||
|
|
||||||
using namespace netgen;
|
using namespace netgen;
|
||||||
|
using namespace pybind11::literals;
|
||||||
|
|
||||||
namespace netgen
|
namespace netgen
|
||||||
{
|
{
|
||||||
@ -15,7 +17,7 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DLL_HEADER void ExportGeom2d(py::module &m)
|
NGCORE_API_EXPORT void ExportGeom2d(py::module &m)
|
||||||
{
|
{
|
||||||
py::class_<SplineSegExt, shared_ptr<SplineSegExt>>
|
py::class_<SplineSegExt, shared_ptr<SplineSegExt>>
|
||||||
(m, "Spline", "Spline of a SplineGeometry object")
|
(m, "Spline", "Spline of a SplineGeometry object")
|
||||||
@ -65,24 +67,45 @@ DLL_HEADER void ExportGeom2d(py::module &m)
|
|||||||
optional<variant<int, string>> bc, optional<int> copy, double maxh,
|
optional<variant<int, string>> bc, optional<int> copy, double maxh,
|
||||||
double hpref, double hprefleft, double hprefright)
|
double hpref, double hprefleft, double hprefright)
|
||||||
{
|
{
|
||||||
auto segtype = py::cast<std::string>(segment[0]);
|
|
||||||
|
|
||||||
SplineSegExt * seg;
|
SplineSegExt * seg;
|
||||||
if (segtype == "line")
|
if(py::isinstance<py::str>(segment[0]))
|
||||||
{
|
{
|
||||||
LineSeg<2> * l = new LineSeg<2>(self.GetPoint(py::cast<int>(segment[1])),
|
auto segtype = py::cast<std::string>(segment[0]);
|
||||||
self.GetPoint(py::cast<int>(segment[2])));
|
|
||||||
seg = new SplineSegExt(*l);
|
if (segtype == "line")
|
||||||
}
|
{
|
||||||
else if (segtype == "spline3")
|
LineSeg<2> * l = new LineSeg<2>(self.GetPoint(py::cast<int>(segment[1])),
|
||||||
{
|
self.GetPoint(py::cast<int>(segment[2])));
|
||||||
SplineSeg3<2> * seg3 = new SplineSeg3<2>(self.GetPoint(py::cast<int>(segment[1])),
|
seg = new SplineSegExt(*l);
|
||||||
self.GetPoint(py::cast<int>(segment[2])),
|
}
|
||||||
self.GetPoint(py::cast<int>(segment[3])));
|
else if (segtype == "spline3")
|
||||||
seg = new SplineSegExt(*seg3);
|
{
|
||||||
|
SplineSeg3<2> * seg3 = new SplineSeg3<2>(self.GetPoint(py::cast<int>(segment[1])),
|
||||||
|
self.GetPoint(py::cast<int>(segment[2])),
|
||||||
|
self.GetPoint(py::cast<int>(segment[3])));
|
||||||
|
seg = new SplineSegExt(*seg3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw Exception("Appended segment is not a line or a spline3");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw Exception("Appended segment is not a line or a spline3");
|
{
|
||||||
|
if(py::len(segment) == 2)
|
||||||
|
{
|
||||||
|
auto l = new LineSeg<2>(self.GetPoint(py::cast<int>(segment[0])),
|
||||||
|
self.GetPoint(py::cast<int>(segment[1])));
|
||||||
|
seg = new SplineSegExt(*l);
|
||||||
|
}
|
||||||
|
else if(py::len(segment) == 3)
|
||||||
|
{
|
||||||
|
SplineSeg3<2> * seg3 = new SplineSeg3<2>(self.GetPoint(py::cast<int>(segment[0])),
|
||||||
|
self.GetPoint(py::cast<int>(segment[1])),
|
||||||
|
self.GetPoint(py::cast<int>(segment[2])));
|
||||||
|
seg = new SplineSegExt(*seg3);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw Exception("Appended segment must either have 2 or 3 points");
|
||||||
|
}
|
||||||
seg->leftdom = leftdomain;
|
seg->leftdom = leftdomain;
|
||||||
seg->rightdom = rightdomain;
|
seg->rightdom = rightdomain;
|
||||||
seg->hmax = maxh;
|
seg->hmax = maxh;
|
||||||
@ -265,6 +288,7 @@ DLL_HEADER void ExportGeom2d(py::module &m)
|
|||||||
{
|
{
|
||||||
double len = self.splines[i]->Length();
|
double len = self.splines[i]->Length();
|
||||||
int n = floor(len/(0.05*min(xdist,ydist)));
|
int n = floor(len/(0.05*min(xdist,ydist)));
|
||||||
|
n = max(3, n);
|
||||||
lst.push_back(self.splines[i]->StartPI());
|
lst.push_back(self.splines[i]->StartPI());
|
||||||
for (int j = 1; j < n; j++){
|
for (int j = 1; j < n; j++){
|
||||||
lst.push_back(self.splines[i]->GetPoint(j*1./n));
|
lst.push_back(self.splines[i]->GetPoint(j*1./n));
|
||||||
@ -371,9 +395,8 @@ DLL_HEADER void ExportGeom2d(py::module &m)
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
// If we change to c++17 this can become optional<MeshingParameters>
|
|
||||||
.def("GenerateMesh", [](shared_ptr<SplineGeometry2d> self,
|
.def("GenerateMesh", [](shared_ptr<SplineGeometry2d> self,
|
||||||
MeshingParameters* pars, py::kwargs kwargs)
|
optional<MeshingParameters> pars, py::kwargs kwargs)
|
||||||
{
|
{
|
||||||
MeshingParameters mp;
|
MeshingParameters mp;
|
||||||
if(pars) mp = *pars;
|
if(pars) mp = *pars;
|
||||||
@ -389,11 +412,89 @@ DLL_HEADER void ExportGeom2d(py::module &m)
|
|||||||
if(result != 0)
|
if(result != 0)
|
||||||
throw Exception("Meshing failed!");
|
throw Exception("Meshing failed!");
|
||||||
return mesh;
|
return mesh;
|
||||||
}, py::arg("mp") = nullptr,
|
}, py::arg("mp") = nullopt,
|
||||||
|
py::call_guard<py::gil_scoped_release>(),
|
||||||
|
meshingparameter_description.c_str())
|
||||||
|
.def("_SetDomainTensorMeshing", &SplineGeometry2d::SetDomainTensorMeshing)
|
||||||
|
;
|
||||||
|
|
||||||
|
py::class_<Solid2d>(m, "Solid2d")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::init<Array<std::variant<Point<2>, EdgeInfo, PointInfo>>, std::string, std::string>(), py::arg("points"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT)
|
||||||
|
|
||||||
|
.def(py::self+py::self)
|
||||||
|
.def(py::self-py::self)
|
||||||
|
.def(py::self*py::self)
|
||||||
|
.def(py::self+=py::self)
|
||||||
|
.def(py::self-=py::self)
|
||||||
|
.def(py::self*=py::self)
|
||||||
|
|
||||||
|
.def("Mat", &Solid2d::Mat)
|
||||||
|
.def("BC", &Solid2d::BC)
|
||||||
|
.def("Maxh", &Solid2d::Maxh)
|
||||||
|
|
||||||
|
.def("Copy", [](Solid2d & self) -> Solid2d { return self; })
|
||||||
|
.def("Move", &Solid2d::Move)
|
||||||
|
.def("Scale", static_cast<Solid2d& (Solid2d::*)(double)>(&Solid2d::Scale))
|
||||||
|
.def("Scale", static_cast<Solid2d& (Solid2d::*)(Vec<2>)>(&Solid2d::Scale))
|
||||||
|
.def("Rotate", &Solid2d::RotateDeg, py::arg("angle"), py::arg("center")=Point<2>{0,0})
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
m.def("Rectangle", [](Point<2> p0, Point<2> p1, string mat, string bc, optional<string> bottom, optional<string> right, optional<string> top, optional<string> left) -> Solid2d
|
||||||
|
{
|
||||||
|
using P = Point<2>;
|
||||||
|
return { {
|
||||||
|
p0, EdgeInfo{bottom ? *bottom : bc},
|
||||||
|
P{p1[0],p0[1]}, EdgeInfo {right ? *right : bc},
|
||||||
|
p1, EdgeInfo {top ? *top : bc},
|
||||||
|
P{p0[0],p1[1]}, EdgeInfo {left ? *left : bc},
|
||||||
|
}, mat};
|
||||||
|
},
|
||||||
|
"pmin"_a, "pmax"_a, "mat"_a=MAT_DEFAULT, "bc"_a=BC_DEFAULT,
|
||||||
|
"bottom"_a=nullopt, "right"_a=nullopt, "top"_a=nullopt, "left"_a=nullopt
|
||||||
|
);
|
||||||
|
m.def("Circle", Circle, py::arg("center"), py::arg("radius"), py::arg("mat")=MAT_DEFAULT, py::arg("bc")=BC_DEFAULT);
|
||||||
|
|
||||||
|
py::class_<CSG2d>(m, "CSG2d")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def("GenerateSplineGeometry", &CSG2d::GenerateSplineGeometry)
|
||||||
|
.def("Add", &CSG2d::Add)
|
||||||
|
.def("GenerateMesh", [](CSG2d & self, optional<MeshingParameters> pars, py::kwargs kwargs)
|
||||||
|
{
|
||||||
|
MeshingParameters mp;
|
||||||
|
if(pars) mp = *pars;
|
||||||
|
{
|
||||||
|
py::gil_scoped_acquire aq;
|
||||||
|
CreateMPfromKwargs(mp, kwargs);
|
||||||
|
}
|
||||||
|
auto mesh = make_shared<Mesh>();
|
||||||
|
auto geo = self.GenerateSplineGeometry();
|
||||||
|
mesh->SetGeometry(geo);
|
||||||
|
SetGlobalMesh (mesh);
|
||||||
|
ng_geometry = geo;
|
||||||
|
auto result = geo->GenerateMesh(mesh, mp);
|
||||||
|
if(result != 0)
|
||||||
|
throw Exception("Meshing failed!");
|
||||||
|
return mesh;
|
||||||
|
}, py::arg("mp") = nullopt,
|
||||||
py::call_guard<py::gil_scoped_release>(),
|
py::call_guard<py::gil_scoped_release>(),
|
||||||
meshingparameter_description.c_str())
|
meshingparameter_description.c_str())
|
||||||
;
|
;
|
||||||
|
|
||||||
|
py::class_<EdgeInfo>(m, "EdgeInfo")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::init<const Point<2>&>(), py::arg("control_point"))
|
||||||
|
.def(py::init<double>(), py::arg("maxh"))
|
||||||
|
.def(py::init<string>(), py::arg("bc"))
|
||||||
|
.def(py::init<optional<Point<2>>, double, string>(), py::arg("control_point")=nullopt, py::arg("maxh")=MAXH_DEFAULT, py::arg("bc")=BC_DEFAULT)
|
||||||
|
;
|
||||||
|
py::class_<PointInfo>(m, "PointInfo")
|
||||||
|
.def(py::init<>())
|
||||||
|
.def(py::init<double>(), "maxh"_a)
|
||||||
|
.def(py::init<string>(), "name"_a)
|
||||||
|
.def(py::init<double, string>(), "maxh"_a, "name"_a)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_MODULE(libgeom2d, m) {
|
PYBIND11_MODULE(libgeom2d, m) {
|
||||||
|
@ -1099,6 +1099,284 @@ public:
|
|||||||
// auto & Tree() { return *tree; };
|
// auto & Tree() { return *tree; };
|
||||||
// };
|
// };
|
||||||
|
|
||||||
|
template<int dim, typename T=INDEX, typename TSCAL=double>
|
||||||
|
class DelaunayTree
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Number of entries per leaf
|
||||||
|
static constexpr int N = 100;
|
||||||
|
|
||||||
|
struct Node;
|
||||||
|
|
||||||
|
struct Leaf
|
||||||
|
{
|
||||||
|
Point<2*dim, TSCAL> p[N];
|
||||||
|
T index[N];
|
||||||
|
int n_elements;
|
||||||
|
int nr;
|
||||||
|
|
||||||
|
Leaf() : n_elements(0)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
|
||||||
|
void Add( Array<Leaf*> &leaves, Array<T> &leaf_index, const Point<2*dim> &ap, T aindex )
|
||||||
|
{
|
||||||
|
p[n_elements] = ap;
|
||||||
|
index[n_elements] = aindex;
|
||||||
|
n_elements++;
|
||||||
|
if(leaf_index.Size()<aindex+1)
|
||||||
|
leaf_index.SetSize(aindex+1);
|
||||||
|
leaf_index[aindex] = nr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
union
|
||||||
|
{
|
||||||
|
Node *children[2];
|
||||||
|
Leaf *leaf;
|
||||||
|
};
|
||||||
|
double sep;
|
||||||
|
int level;
|
||||||
|
|
||||||
|
Node()
|
||||||
|
: children{nullptr,nullptr}
|
||||||
|
{ }
|
||||||
|
|
||||||
|
~Node()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Leaf *GetLeaf() const
|
||||||
|
{
|
||||||
|
return children[1] ? nullptr : leaf;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
Node root;
|
||||||
|
|
||||||
|
Array<Leaf*> leaves;
|
||||||
|
Array<T> leaf_index;
|
||||||
|
|
||||||
|
Point<dim> global_min, global_max;
|
||||||
|
double tol;
|
||||||
|
size_t n_leaves;
|
||||||
|
size_t n_nodes;
|
||||||
|
BlockAllocator ball_nodes;
|
||||||
|
BlockAllocator ball_leaves;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
DelaunayTree (const Point<dim> & pmin, const Point<dim> & pmax)
|
||||||
|
: global_min(pmin), global_max(pmax), n_leaves(1), n_nodes(1), ball_nodes(sizeof(Node)), ball_leaves(sizeof(Leaf))
|
||||||
|
{
|
||||||
|
root.leaf = (Leaf*) ball_leaves.Alloc(); new (root.leaf) Leaf();
|
||||||
|
root.leaf->nr = 0;
|
||||||
|
leaves.Append(root.leaf);
|
||||||
|
root.level = 0;
|
||||||
|
tol = 1e-7 * Dist(pmax, pmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
DelaunayTree (const Box<dim> & box)
|
||||||
|
: DelaunayTree(box.PMin(), box.PMax())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
size_t GetNLeaves()
|
||||||
|
{
|
||||||
|
return n_leaves;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetNNodes()
|
||||||
|
{
|
||||||
|
return n_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename TFunc>
|
||||||
|
void GetFirstIntersecting (const Point<dim> & pmin, const Point<dim> & pmax,
|
||||||
|
TFunc func=[](auto pi){return false;}) const
|
||||||
|
{
|
||||||
|
// static Timer timer("DelaunayTree::GetIntersecting"); RegionTimer rt(timer);
|
||||||
|
// static Timer timer1("DelaunayTree::GetIntersecting-LinearSearch");
|
||||||
|
ArrayMem<const Node*, 100> stack;
|
||||||
|
ArrayMem<int, 100> dir_stack;
|
||||||
|
|
||||||
|
|
||||||
|
Point<2*dim> tpmin, tpmax;
|
||||||
|
|
||||||
|
for (size_t i : IntRange(dim))
|
||||||
|
{
|
||||||
|
tpmin(i) = global_min(i);
|
||||||
|
tpmax(i) = pmax(i)+tol;
|
||||||
|
|
||||||
|
tpmin(i+dim) = pmin(i)-tol;
|
||||||
|
tpmax(i+dim) = global_max(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
stack.SetSize(0);
|
||||||
|
stack.Append(&root);
|
||||||
|
dir_stack.SetSize(0);
|
||||||
|
dir_stack.Append(0);
|
||||||
|
|
||||||
|
while(stack.Size())
|
||||||
|
{
|
||||||
|
const Node *node = stack.Last();
|
||||||
|
stack.DeleteLast();
|
||||||
|
|
||||||
|
int dir = dir_stack.Last();
|
||||||
|
dir_stack.DeleteLast();
|
||||||
|
|
||||||
|
if(Leaf *leaf = node->GetLeaf())
|
||||||
|
{
|
||||||
|
// RegionTimer rt1(timer1);
|
||||||
|
for (auto i : IntRange(leaf->n_elements))
|
||||||
|
{
|
||||||
|
bool intersect = true;
|
||||||
|
const auto p = leaf->p[i];
|
||||||
|
|
||||||
|
for (int d = 0; d < dim; d++)
|
||||||
|
if (p[d] > tpmax[d])
|
||||||
|
intersect = false;
|
||||||
|
for (int d = dim; d < 2*dim; d++)
|
||||||
|
if (p[d] < tpmin[d])
|
||||||
|
intersect = false;
|
||||||
|
if(intersect)
|
||||||
|
if(func(leaf->index[i])) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int newdir = dir+1;
|
||||||
|
if(newdir==2*dim) newdir = 0;
|
||||||
|
if (tpmin[dir] <= node->sep)
|
||||||
|
{
|
||||||
|
stack.Append(node->children[0]);
|
||||||
|
dir_stack.Append(newdir);
|
||||||
|
}
|
||||||
|
if (tpmax[dir] >= node->sep)
|
||||||
|
{
|
||||||
|
stack.Append(node->children[1]);
|
||||||
|
dir_stack.Append(newdir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetIntersecting (const Point<dim> & pmin, const Point<dim> & pmax,
|
||||||
|
NgArray<T> & pis) const
|
||||||
|
{
|
||||||
|
pis.SetSize(0);
|
||||||
|
GetFirstIntersecting(pmin, pmax, [&pis](auto pi) { pis.Append(pi); return false;});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Insert (const Box<dim> & box, T pi)
|
||||||
|
{
|
||||||
|
Insert (box.PMin(), box.PMax(), pi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Insert (const Point<dim> & pmin, const Point<dim> & pmax, T pi)
|
||||||
|
{
|
||||||
|
// static Timer timer("DelaunayTree::Insert"); RegionTimer rt(timer);
|
||||||
|
int dir = 0;
|
||||||
|
Point<2*dim> p;
|
||||||
|
for (auto i : IntRange(dim))
|
||||||
|
{
|
||||||
|
p(i) = pmin[i];
|
||||||
|
p(i+dim) = pmax[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Node * node = &root;
|
||||||
|
Leaf * leaf = node->GetLeaf();
|
||||||
|
|
||||||
|
// search correct leaf to add point
|
||||||
|
while(!leaf)
|
||||||
|
{
|
||||||
|
node = p[dir] < node->sep ? node->children[0] : node->children[1];
|
||||||
|
dir++;
|
||||||
|
if(dir==2*dim) dir = 0;
|
||||||
|
leaf = node->GetLeaf();
|
||||||
|
}
|
||||||
|
|
||||||
|
// add point to leaf
|
||||||
|
if(leaf->n_elements < N)
|
||||||
|
leaf->Add(leaves, leaf_index, p,pi);
|
||||||
|
else // assume leaf->n_elements == N
|
||||||
|
{
|
||||||
|
// add two new nodes and one new leaf
|
||||||
|
int n_elements = leaf->n_elements;
|
||||||
|
ArrayMem<TSCAL, N> coords(n_elements);
|
||||||
|
ArrayMem<int, N> order(n_elements);
|
||||||
|
|
||||||
|
// separate points in two halves, first sort all coordinates in direction dir
|
||||||
|
for (auto i : IntRange(n_elements))
|
||||||
|
{
|
||||||
|
order[i] = i;
|
||||||
|
coords[i] = leaf->p[i][dir];
|
||||||
|
}
|
||||||
|
|
||||||
|
QuickSortI(coords, order);
|
||||||
|
int isplit = N/2;
|
||||||
|
Leaf *leaf1 = (Leaf*) ball_leaves.Alloc(); new (leaf1) Leaf();
|
||||||
|
Leaf *leaf2 = (Leaf*) ball_leaves.Alloc(); new (leaf2) Leaf();
|
||||||
|
|
||||||
|
leaf1->nr = leaf->nr;
|
||||||
|
leaf2->nr = leaves.Size();
|
||||||
|
leaves.Append(leaf2);
|
||||||
|
leaves[leaf1->nr] = leaf1;
|
||||||
|
|
||||||
|
for (auto i : order.Range(isplit))
|
||||||
|
leaf1->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] );
|
||||||
|
for (auto i : order.Range(isplit, N))
|
||||||
|
leaf2->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] );
|
||||||
|
|
||||||
|
Node *node1 = (Node*) ball_nodes.Alloc(); new (node1) Node();
|
||||||
|
node1->leaf = leaf1;
|
||||||
|
node1->level = node->level+1;
|
||||||
|
|
||||||
|
Node *node2 = (Node*) ball_nodes.Alloc(); new (node2) Node();
|
||||||
|
node2->leaf = leaf2;
|
||||||
|
node2->level = node->level+1;
|
||||||
|
|
||||||
|
node->children[0] = node1;
|
||||||
|
node->children[1] = node2;
|
||||||
|
node->sep = 0.5 * (leaf->p[order[isplit-1]][dir] + leaf->p[order[isplit]][dir]);
|
||||||
|
|
||||||
|
// add new point to one of the new leaves
|
||||||
|
if (p[dir] < node->sep)
|
||||||
|
leaf1->Add( leaves, leaf_index, p, pi );
|
||||||
|
else
|
||||||
|
leaf2->Add( leaves, leaf_index, p, pi );
|
||||||
|
|
||||||
|
ball_leaves.Free(leaf);
|
||||||
|
n_leaves++;
|
||||||
|
n_nodes+=2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeleteElement (T pi)
|
||||||
|
{
|
||||||
|
// static Timer timer("DelaunayTree::DeleteElement"); RegionTimer rt(timer);
|
||||||
|
Leaf *leaf = leaves[leaf_index[pi]];
|
||||||
|
leaf_index[pi] = -1;
|
||||||
|
auto & n_elements = leaf->n_elements;
|
||||||
|
auto & index = leaf->index;
|
||||||
|
auto & p = leaf->p;
|
||||||
|
|
||||||
|
for (auto i : IntRange(n_elements))
|
||||||
|
{
|
||||||
|
if(index[i] == pi)
|
||||||
|
{
|
||||||
|
n_elements--;
|
||||||
|
if(i!=n_elements)
|
||||||
|
{
|
||||||
|
index[i] = index[n_elements];
|
||||||
|
p[i] = p[n_elements];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -3,10 +3,6 @@
|
|||||||
#include <myadt.hpp>
|
#include <myadt.hpp>
|
||||||
#include <gprim.hpp>
|
#include <gprim.hpp>
|
||||||
|
|
||||||
#ifndef M_PI
|
|
||||||
#define M_PI 3.14159265358979323846
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace netgen
|
namespace netgen
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -251,239 +247,4 @@ int PTRIANGLE2D :: IsIn (const Point2d & p) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Polygon2d :: Polygon2d ()
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
Polygon2d :: ~Polygon2d ()
|
|
||||||
{
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Polygon2d :: AddPoint (const Point2d & p)
|
|
||||||
{
|
|
||||||
points.Append(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
double Polygon2d :: HArea () const
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
double ar = 0;
|
|
||||||
for (i = 1; i <= points.Size(); i++)
|
|
||||||
{
|
|
||||||
const Point2d & p1 = points.Get(i);
|
|
||||||
const Point2d & p2 = points.Get(i%points.Size()+1);
|
|
||||||
ar +=
|
|
||||||
(p2.X()-p1.X()) * p1.Y() -
|
|
||||||
(p2.Y()-p1.Y()) * p1.X();
|
|
||||||
}
|
|
||||||
return ar/2;
|
|
||||||
/*
|
|
||||||
CURSOR c;
|
|
||||||
double ar = 0;
|
|
||||||
Point2d * p1, * p2, p0 = Point2d(0, 0);
|
|
||||||
Vec2d v1, v2 = Vec2d(1, 0);
|
|
||||||
|
|
||||||
p2 = points[points.Last()];
|
|
||||||
for (c = points.First(); c != points.Head(); c++)
|
|
||||||
{
|
|
||||||
p1 = p2;
|
|
||||||
p2 = points[c];
|
|
||||||
ar += Cross ( (*p2-*p1), (*p1 - p0));
|
|
||||||
}
|
|
||||||
return ar / 2;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int Polygon2d :: IsOn (const Point2d & p) const
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 1; i <= points.Size(); i++)
|
|
||||||
{
|
|
||||||
const Point2d & p1 = points.Get(i);
|
|
||||||
const Point2d & p2 = points.Get(i%points.Size()+1);
|
|
||||||
if (IsOnLine (Line2d(p1, p2), p)) return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
/*
|
|
||||||
CURSOR c;
|
|
||||||
Point2d * p1, * p2;
|
|
||||||
|
|
||||||
p2 = points[points.Last()];
|
|
||||||
for (c = points.First(); c != points.Head(); c++)
|
|
||||||
{
|
|
||||||
p1 = p2;
|
|
||||||
p2 = points[c];
|
|
||||||
if (IsOnLine (Line2d(*p1, *p2), p)) return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int Polygon2d :: IsIn (const Point2d & p) const
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
double sum = 0, ang;
|
|
||||||
for (i = 1; i <= points.Size(); i++)
|
|
||||||
{
|
|
||||||
const Point2d & p1 = points.Get(i);
|
|
||||||
const Point2d & p2 = points.Get(i%points.Size()+1);
|
|
||||||
ang = Angle ( (p1 - p), (p2 - p) );
|
|
||||||
if (ang > M_PI) ang -= 2 * M_PI;
|
|
||||||
sum += ang;
|
|
||||||
}
|
|
||||||
return fabs(sum) > M_PI;
|
|
||||||
/*
|
|
||||||
CURSOR c;
|
|
||||||
Point2d * p1, * p2;
|
|
||||||
double sum = 0, ang;
|
|
||||||
|
|
||||||
p2 = points[points.Last()];
|
|
||||||
for (c = points.First(); c != points.Head(); c++)
|
|
||||||
{
|
|
||||||
p1 = p2;
|
|
||||||
p2 = points[c];
|
|
||||||
ang = Angle ( (*p1 - p), (*p2 - p) );
|
|
||||||
if (ang > M_PI) ang -= 2 * M_PI;
|
|
||||||
sum += ang;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fabs(sum) > M_PI;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
int Polygon2d :: IsConvex () const
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Point2d *p, *pold, *pnew;
|
|
||||||
char cw;
|
|
||||||
CURSOR c;
|
|
||||||
|
|
||||||
if (points.Length() < 3) return 0;
|
|
||||||
|
|
||||||
c = points.Last();
|
|
||||||
p = points[c];
|
|
||||||
c--;
|
|
||||||
pold = points[c];
|
|
||||||
pnew = points[points.First()];
|
|
||||||
cw = ::CW (*pold, *p, *pnew);
|
|
||||||
|
|
||||||
for (c = points.First(); c != points.Head(); c++)
|
|
||||||
{
|
|
||||||
pnew = points[c];
|
|
||||||
if (cw != ::CW (*pold, *p, *pnew))
|
|
||||||
return 0;
|
|
||||||
pold = p;
|
|
||||||
p = pnew;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int Polygon2d :: IsStarPoint (const Point2d & p) const
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Point2d *pnew, *pold;
|
|
||||||
char cw;
|
|
||||||
CURSOR c;
|
|
||||||
|
|
||||||
if (points.Length() < 3) return 0;
|
|
||||||
|
|
||||||
pold = points[points.Last()];
|
|
||||||
pnew = points[points.First()];
|
|
||||||
|
|
||||||
cw = ::CW (p, *pold, *pnew);
|
|
||||||
|
|
||||||
for (c = points.First(); c != points.Head(); c++)
|
|
||||||
{
|
|
||||||
pnew = points[c];
|
|
||||||
if (cw != ::CW (p, *pold, *pnew))
|
|
||||||
return 0;
|
|
||||||
pold = pnew;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Point2d Polygon2d :: Center () const
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
double ai, a = 0, x = 0, y = 0;
|
|
||||||
Point2d * p, *p2;
|
|
||||||
Point2d p0 = Point2d(0, 0);
|
|
||||||
CURSOR c;
|
|
||||||
|
|
||||||
p2 = points[points.Last()];
|
|
||||||
|
|
||||||
for (c = points.First(); c != points.Head(); c++)
|
|
||||||
{
|
|
||||||
p = points[c];
|
|
||||||
ai = Cross (*p2 - p0, *p - p0);
|
|
||||||
x += ai / 3 * (p2->X() + p->X());
|
|
||||||
y += ai / 3 * (p2->Y() + p->Y());
|
|
||||||
a+= ai;
|
|
||||||
p2 = p;
|
|
||||||
}
|
|
||||||
if (a != 0)
|
|
||||||
return Point2d (x / a, y / a);
|
|
||||||
else
|
|
||||||
return Point2d (0, 0);
|
|
||||||
*/
|
|
||||||
return Point2d (0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Point2d Polygon2d :: EqualAreaPoint () const
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
double a11 = 0, a12 = 0, a21= 0, a22 = 0;
|
|
||||||
double b1 = 0, b2 = 0, dx, dy;
|
|
||||||
double det;
|
|
||||||
Point2d * p, *p2;
|
|
||||||
CURSOR c;
|
|
||||||
|
|
||||||
p = points[points.Last()];
|
|
||||||
|
|
||||||
for (c = points.First(); c != points.Head(); c++)
|
|
||||||
{
|
|
||||||
p2 = p;
|
|
||||||
p = points[c];
|
|
||||||
|
|
||||||
dx = p->X() - p2->X();
|
|
||||||
dy = p->Y() - p2->Y();
|
|
||||||
|
|
||||||
a11 += sqr (dy);
|
|
||||||
a12 -= dx * dy;
|
|
||||||
a21 -= dx * dy;
|
|
||||||
a22 += sqr (dx);
|
|
||||||
b1 -= dy * (p->X() * p2->Y() - p2->X() * p->Y());
|
|
||||||
b2 -= dx * (p->Y() * p2->X() - p2->Y() * p->X());
|
|
||||||
}
|
|
||||||
|
|
||||||
det = a11 * a22 - a21 * a12;
|
|
||||||
|
|
||||||
if (det != 0)
|
|
||||||
return Point2d ( (b1 * a22 - b2 * a12) / det,
|
|
||||||
(a11 * b2 - a21 * b1) / det);
|
|
||||||
else
|
|
||||||
return Point2d (0, 0);
|
|
||||||
*/
|
|
||||||
return Point2d (0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -609,40 +609,6 @@ namespace netgen
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Polygon2d
|
|
||||||
{
|
|
||||||
protected:
|
|
||||||
NgArray<Point2d> points;
|
|
||||||
|
|
||||||
public:
|
|
||||||
Polygon2d ();
|
|
||||||
~Polygon2d ();
|
|
||||||
|
|
||||||
void AddPoint (const Point2d & p);
|
|
||||||
int GetNP() const { return points.Size(); }
|
|
||||||
void GetPoint (int i, Point2d & p) const
|
|
||||||
{ p = points.Get(i); }
|
|
||||||
void GetLine (int i, Point2d & p1, Point2d & p2) const
|
|
||||||
{ p1 = points.Get(i); p2 = points.Get(i%points.Size()+1); }
|
|
||||||
|
|
||||||
double Area () const { return fabs (HArea()); }
|
|
||||||
int CW () const { return HArea() > 0; }
|
|
||||||
int CCW () const { return HArea() < 0; }
|
|
||||||
|
|
||||||
int IsOn (const Point2d & p) const;
|
|
||||||
int IsIn (const Point2d & p) const;
|
|
||||||
|
|
||||||
int IsConvex () const;
|
|
||||||
|
|
||||||
int IsStarPoint (const Point2d & p) const;
|
|
||||||
Point2d Center() const;
|
|
||||||
Point2d EqualAreaPoint () const;
|
|
||||||
private:
|
|
||||||
double HArea () const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** Cheap approximation to atan2.
|
/** Cheap approximation to atan2.
|
||||||
A monotone function of atan2(x,y) is computed.
|
A monotone function of atan2(x,y) is computed.
|
||||||
*/
|
*/
|
||||||
|
@ -83,7 +83,7 @@ double Det (const Mat<3,3> & m)
|
|||||||
|
|
||||||
void EigenValues (const Mat<3,3> & m, Vec<3> & ev)
|
void EigenValues (const Mat<3,3> & m, Vec<3> & ev)
|
||||||
{
|
{
|
||||||
const double pi = 3.141592;
|
const double pi = M_PI;
|
||||||
double a, b, c, d;
|
double a, b, c, d;
|
||||||
double p, q;
|
double p, q;
|
||||||
double arg;
|
double arg;
|
||||||
|
@ -142,10 +142,24 @@ namespace netgen
|
|||||||
|
|
||||||
inline void CalcInverse (const Mat<2,3> & m, Mat<3,2> & inv)
|
inline void CalcInverse (const Mat<2,3> & m, Mat<3,2> & inv)
|
||||||
{
|
{
|
||||||
|
Vec<3> a0 = m.Row(0);
|
||||||
|
Vec<3> a1 = m.Row(1);
|
||||||
|
Vec<3> n = Cross(a0, a1);
|
||||||
|
Vec<3> d0 = Cross(a1, n);
|
||||||
|
Vec<3> d1 = Cross(a0, n);
|
||||||
|
double s0 = 1.0/(a0*d0);
|
||||||
|
double s1 = 1.0/(a1*d1);
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
inv(i,0) = s0*d0(i);
|
||||||
|
inv(i,1) = s1*d1(i);
|
||||||
|
}
|
||||||
|
/*
|
||||||
Mat<2,2> a = m * Trans (m);
|
Mat<2,2> a = m * Trans (m);
|
||||||
Mat<2,2> ainv;
|
Mat<2,2> ainv;
|
||||||
CalcInverse (a, ainv);
|
CalcInverse (a, ainv);
|
||||||
inv = Trans (m) * ainv;
|
inv = Trans (m) * ainv;
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void CalcInverse (const Mat<3,2> & m, Mat<2,3> & inv);
|
void CalcInverse (const Mat<3,2> & m, Mat<2,3> & inv);
|
||||||
@ -166,6 +180,31 @@ namespace netgen
|
|||||||
void EigenValues (const Mat<3,3> & m, Vec<3> & ev);
|
void EigenValues (const Mat<3,3> & m, Vec<3> & ev);
|
||||||
void EigenValues (const Mat<2,2> & m, Vec<3> & ev);
|
void EigenValues (const Mat<2,2> & m, Vec<3> & ev);
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
Vec<3,T> StableSolve (Mat<2,3,T> mat, Vec<2,T> rhs)
|
||||||
|
{
|
||||||
|
Vec<3> a0 = mat.Row(0);
|
||||||
|
Vec<3> a1 = mat.Row(1);
|
||||||
|
/*
|
||||||
|
Vec<3> d = Cross ( Cross (a0, a1), a0);
|
||||||
|
|
||||||
|
double alpha = rhs(0) / a0.Length2();
|
||||||
|
double beta = (rhs(1)-alpha* (a0*a1)) / (d*a1);
|
||||||
|
return alpha * a0 + beta * d;
|
||||||
|
*/
|
||||||
|
Vec<3> n = Cross(a0, a1);
|
||||||
|
Vec<3> d0 = Cross(a1, n);
|
||||||
|
Vec<3> d1 = Cross(a0, n);
|
||||||
|
double alpha = rhs(0) / (a0*d0);
|
||||||
|
double beta = rhs(1) / (a1*d1);
|
||||||
|
return alpha * d0 + beta * d1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -384,8 +384,16 @@ namespace netgen
|
|||||||
bool IsIn (const Point<D> & p) const
|
bool IsIn (const Point<D> & p) const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < D; i++)
|
for (int i = 0; i < D; i++)
|
||||||
if (p(i) < pmin(i) || p(i) > pmax(i)) return 0;
|
if (p(i) < pmin(i) || p(i) > pmax(i)) return false;
|
||||||
return 1;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is point in eps-increased box
|
||||||
|
bool IsIn (const Point<D> & p, double eps) const
|
||||||
|
{
|
||||||
|
for (int i = 0; i < D; i++)
|
||||||
|
if (p(i) < pmin(i)-eps || p(i) > pmax(i)+eps) return false;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -478,7 +486,7 @@ namespace netgen
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#ifdef PARALLEL
|
#ifdef PARALLEL_OLD
|
||||||
template <>
|
template <>
|
||||||
inline MPI_Datatype MyGetMPIType<Vec<3, double> > ()
|
inline MPI_Datatype MyGetMPIType<Vec<3, double> > ()
|
||||||
{
|
{
|
||||||
|
@ -1035,6 +1035,39 @@ double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p, double & lam)
|
||||||
|
{
|
||||||
|
Vec3d v(lp1, lp2);
|
||||||
|
Vec3d vlp(lp1, p);
|
||||||
|
|
||||||
|
// dist(lam) = \| vlp \|^2 - 2 lam (v1p, v) + lam^2 \| v \|^2
|
||||||
|
|
||||||
|
// lam = (v * vlp) / (v * v);
|
||||||
|
// if (lam < 0) lam = 0;
|
||||||
|
// if (lam > 1) lam = 1;
|
||||||
|
|
||||||
|
double num = v*vlp;
|
||||||
|
double den = v*v;
|
||||||
|
|
||||||
|
if (num <= 0)
|
||||||
|
{
|
||||||
|
lam = 0.0;
|
||||||
|
return Dist2 (lp1, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num >= den)
|
||||||
|
{
|
||||||
|
lam = 1.0;
|
||||||
|
return Dist2 (lp2, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
lam = num/den;
|
||||||
|
if (den > 0)
|
||||||
|
return vlp.Length2() - num * num /den;
|
||||||
|
else
|
||||||
|
return vlp.Length2();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
double MinDistTP2 (const Point3d & tp1, const Point3d & tp2,
|
double MinDistTP2 (const Point3d & tp1, const Point3d & tp2,
|
||||||
const Point3d & tp3, const Point3d & p)
|
const Point3d & tp3, const Point3d & p)
|
||||||
@ -1102,7 +1135,7 @@ double MinDistTP2 (const Point3d & tp1, const Point3d & tp2,
|
|||||||
|
|
||||||
// 0 checks !!!
|
// 0 checks !!!
|
||||||
double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
|
double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
|
||||||
const Point3d & l2p1, const Point3d & l2p2)
|
const Point3d & l2p1, const Point3d & l2p2, double & lam1, double & lam2 )
|
||||||
{
|
{
|
||||||
// dist(lam1,lam2) = \| l2p1+lam2v2 - (l1p1+lam1 v1) \|
|
// dist(lam1,lam2) = \| l2p1+lam2v2 - (l1p1+lam1 v1) \|
|
||||||
// min !
|
// min !
|
||||||
@ -1112,7 +1145,7 @@ double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
|
|||||||
Vec3d v2 (l2p1, l2p2);
|
Vec3d v2 (l2p1, l2p2);
|
||||||
|
|
||||||
double a11, a12, a22, rs1, rs2;
|
double a11, a12, a22, rs1, rs2;
|
||||||
double lam1, lam2, det;
|
double det;
|
||||||
|
|
||||||
a11 = v1*v1;
|
a11 = v1*v1;
|
||||||
a12 = -(v1*v2);
|
a12 = -(v1*v2);
|
||||||
@ -1138,14 +1171,27 @@ double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
|
|||||||
}
|
}
|
||||||
|
|
||||||
double minv, hv;
|
double minv, hv;
|
||||||
minv = MinDistLP2 (l1p1, l1p2, l2p1);
|
minv = MinDistLP2 (l1p1, l1p2, l2p1, lam1);
|
||||||
hv = MinDistLP2 (l1p1, l1p2, l2p2);
|
lam2 = 0.;
|
||||||
if (hv < minv) minv = hv;
|
hv = MinDistLP2 (l1p1, l1p2, l2p2, lam1);
|
||||||
|
if (hv < minv)
|
||||||
|
{
|
||||||
|
lam2 = 1.;
|
||||||
|
minv = hv;
|
||||||
|
}
|
||||||
|
|
||||||
hv = MinDistLP2 (l2p1, l2p2, l1p1);
|
hv = MinDistLP2 (l2p1, l2p2, l1p1, lam2);
|
||||||
if (hv < minv) minv = hv;
|
if (hv < minv)
|
||||||
hv = MinDistLP2 (l2p1, l2p2, l1p2);
|
{
|
||||||
if (hv < minv) minv = hv;
|
lam1 = 0.;
|
||||||
|
minv = hv;
|
||||||
|
}
|
||||||
|
hv = MinDistLP2 (l2p1, l2p2, l1p2, lam2);
|
||||||
|
if (hv < minv)
|
||||||
|
{
|
||||||
|
lam1 = 1.;
|
||||||
|
minv = hv;
|
||||||
|
}
|
||||||
|
|
||||||
return minv;
|
return minv;
|
||||||
}
|
}
|
||||||
|
@ -75,7 +75,7 @@ extern double MinDistLP2 (const Point2d & lp1, const Point2d & lp2, const Point2
|
|||||||
extern double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p);
|
extern double MinDistLP2 (const Point3d & lp1, const Point3d & lp2, const Point3d & p);
|
||||||
|
|
||||||
/// Minimal distance of point p to the triangle segment [tp1,tp2,pt3]
|
/// Minimal distance of point p to the triangle segment [tp1,tp2,pt3]
|
||||||
extern double MinDistTP2 (const Point3d & tp1, const Point3d & tp2,
|
DLL_HEADER double MinDistTP2 (const Point3d & tp1, const Point3d & tp2,
|
||||||
const Point3d & tp3, const Point3d & p);
|
const Point3d & tp3, const Point3d & p);
|
||||||
|
|
||||||
inline double MinDistTP2 (const Point<2> & tp1, const Point<2> & tp2,
|
inline double MinDistTP2 (const Point<2> & tp1, const Point<2> & tp2,
|
||||||
@ -91,6 +91,9 @@ extern double MinDistTP2 (const Point3d & tp1, const Point3d & tp2,
|
|||||||
extern double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
|
extern double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
|
||||||
const Point3d & l2p1, const Point3d & l2p2);
|
const Point3d & l2p1, const Point3d & l2p2);
|
||||||
|
|
||||||
|
extern double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
|
||||||
|
const Point3d & l2p1, const Point3d & l2p2, double & lam1, double & lam2 );
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -98,6 +98,16 @@ namespace netgen
|
|||||||
proj_latest_t = 0.5;
|
proj_latest_t = 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<int D>
|
||||||
|
SplineSeg3<D> :: SplineSeg3 (const GeomPoint<D> & ap1,
|
||||||
|
const GeomPoint<D> & ap2,
|
||||||
|
const GeomPoint<D> & ap3,
|
||||||
|
double aweight)
|
||||||
|
: p1(ap1), p2(ap2), p3(ap3), weight(aweight)
|
||||||
|
{
|
||||||
|
proj_latest_t = 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
template<int D>
|
template<int D>
|
||||||
Point<D> SplineSeg3<D> :: GetPoint (double t) const
|
Point<D> SplineSeg3<D> :: GetPoint (double t) const
|
||||||
{
|
{
|
||||||
|
@ -185,6 +185,10 @@ namespace netgen
|
|||||||
SplineSeg3 (const GeomPoint<D> & ap1,
|
SplineSeg3 (const GeomPoint<D> & ap1,
|
||||||
const GeomPoint<D> & ap2,
|
const GeomPoint<D> & ap2,
|
||||||
const GeomPoint<D> & ap3);
|
const GeomPoint<D> & ap3);
|
||||||
|
SplineSeg3 (const GeomPoint<D> & ap1,
|
||||||
|
const GeomPoint<D> & ap2,
|
||||||
|
const GeomPoint<D> & ap3,
|
||||||
|
double aweight);
|
||||||
// default constructor for archive
|
// default constructor for archive
|
||||||
SplineSeg3() {}
|
SplineSeg3() {}
|
||||||
///
|
///
|
||||||
@ -192,9 +196,13 @@ namespace netgen
|
|||||||
{
|
{
|
||||||
ar & p1 & p2 & p3 & weight & proj_latest_t;
|
ar & p1 & p2 & p3 & weight & proj_latest_t;
|
||||||
}
|
}
|
||||||
virtual Point<D> GetPoint (double t) const;
|
|
||||||
///
|
///
|
||||||
virtual Vec<D> GetTangent (const double t) const;
|
double GetWeight () const { return weight; }
|
||||||
|
void SetWeight (double w) { weight = w; }
|
||||||
|
///
|
||||||
|
DLL_HEADER virtual Point<D> GetPoint (double t) const;
|
||||||
|
///
|
||||||
|
DLL_HEADER virtual Vec<D> GetTangent (const double t) const;
|
||||||
|
|
||||||
|
|
||||||
DLL_HEADER virtual void GetDerivatives (const double t,
|
DLL_HEADER virtual void GetDerivatives (const double t,
|
||||||
@ -202,12 +210,12 @@ namespace netgen
|
|||||||
Vec<D> & first,
|
Vec<D> & first,
|
||||||
Vec<D> & second) const;
|
Vec<D> & second) const;
|
||||||
///
|
///
|
||||||
virtual const GeomPoint<D> & StartPI () const { return p1; };
|
DLL_HEADER virtual const GeomPoint<D> & StartPI () const { return p1; };
|
||||||
///
|
///
|
||||||
virtual const GeomPoint<D> & EndPI () const { return p3; }
|
DLL_HEADER virtual const GeomPoint<D> & EndPI () const { return p3; }
|
||||||
///
|
///
|
||||||
virtual void GetCoeff (Vector & coeffs) const;
|
DLL_HEADER virtual void GetCoeff (Vector & coeffs) const;
|
||||||
virtual void GetCoeff (Vector & coeffs, Point<D> p0) const;
|
DLL_HEADER virtual void GetCoeff (Vector & coeffs, Point<D> p0) const;
|
||||||
|
|
||||||
virtual string GetType(void) const {return "spline3";}
|
virtual string GetType(void) const {return "spline3";}
|
||||||
|
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
#define INCOPENGL_HPP___
|
#define INCOPENGL_HPP___
|
||||||
#define GL_GLEXT_PROTOTYPES
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
|
||||||
|
#include <mystdlib.h>
|
||||||
#include <mydefs.hpp>
|
#include <mydefs.hpp>
|
||||||
|
|
||||||
# if defined(TOGL_AGL) || defined(TOGL_AGL_CLASSIC) || defined(TOGL_NSOPENGL)
|
# ifdef __APPLE__
|
||||||
#define GL_SILENCE_DEPRECATION
|
#define GL_SILENCE_DEPRECATION
|
||||||
#define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED
|
#define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED
|
||||||
# include <OpenGL/gl3.h>
|
# include <OpenGL/gl3.h>
|
||||||
|
@ -11,22 +11,15 @@
|
|||||||
defines for graphics, testmodes, ...
|
defines for graphics, testmodes, ...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <core/ngcore.hpp>
|
||||||
#define PACKAGE_VERSION "6.2-dev"
|
#define PACKAGE_VERSION "6.2-dev"
|
||||||
|
|
||||||
// #define DEBUG
|
// #define DEBUG
|
||||||
|
|
||||||
#ifdef WIN32
|
#if defined(NGINTERFACE_EXPORTS) || ( defined(WIN32) && (defined(NGLIB_EXPORTS) || defined(nglib_EXPORTS)) )
|
||||||
#if NGINTERFACE_EXPORTS || NGLIB_EXPORTS || nglib_EXPORTS
|
#define DLL_HEADER NGCORE_API_EXPORT
|
||||||
#define DLL_HEADER __declspec(dllexport)
|
|
||||||
#else
|
|
||||||
#define DLL_HEADER __declspec(dllimport)
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
#if __GNUC__ >= 4
|
#define DLL_HEADER NGCORE_API_IMPORT
|
||||||
#define DLL_HEADER __attribute__ ((visibility ("default")))
|
|
||||||
#else
|
|
||||||
#define DLL_HEADER
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,22 +11,13 @@
|
|||||||
/* Date: 20. Nov. 99 */
|
/* Date: 20. Nov. 99 */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
|
||||||
#include <core/ngcore.hpp>
|
#include "mydefs.hpp"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Application program interface to Netgen
|
Application program interface to Netgen
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef DLL_HEADER
|
|
||||||
#if NGINTERFACE_EXPORTS || NGLIB_EXPORTS || nglib_EXPORTS
|
|
||||||
#define DLL_HEADER NGCORE_API_EXPORT
|
|
||||||
#else
|
|
||||||
#define DLL_HEADER NGCORE_API_IMPORT
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// max number of nodes per element
|
// max number of nodes per element
|
||||||
#define NG_ELEMENT_MAXPOINTS 20
|
#define NG_ELEMENT_MAXPOINTS 20
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
/* Date: May 09 */
|
/* Date: May 09 */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
|
||||||
#include <core/ngcore.hpp>
|
#include "mydefs.hpp"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
C++ interface to Netgen
|
C++ interface to Netgen
|
||||||
@ -276,7 +276,7 @@ namespace netgen
|
|||||||
void UpdateTopology ();
|
void UpdateTopology ();
|
||||||
void DoArchive (Archive & archive);
|
void DoArchive (Archive & archive);
|
||||||
|
|
||||||
NgMPI_Comm GetCommunicator() const;
|
const NgMPI_Comm & GetCommunicator() const;
|
||||||
|
|
||||||
virtual ~Ngx_Mesh();
|
virtual ~Ngx_Mesh();
|
||||||
|
|
||||||
@ -343,8 +343,11 @@ namespace netgen
|
|||||||
void SetRefinementFlag (size_t elnr, bool flag);
|
void SetRefinementFlag (size_t elnr, bool flag);
|
||||||
|
|
||||||
void Curve (int order);
|
void Curve (int order);
|
||||||
|
int GetCurveOrder ();
|
||||||
|
|
||||||
void Refine (NG_REFINEMENT_TYPE reftype,
|
void EnableTable (string name, bool set);
|
||||||
|
|
||||||
|
void Refine (NG_REFINEMENT_TYPE reftype, bool onlyonce,
|
||||||
void (*taskmanager)(function<void(int,int)>) = &DummyTaskManager2,
|
void (*taskmanager)(function<void(int,int)>) = &DummyTaskManager2,
|
||||||
void (*tracer)(string, bool) = &DummyTracer2);
|
void (*tracer)(string, bool) = &DummyTracer2);
|
||||||
|
|
||||||
@ -354,6 +357,10 @@ namespace netgen
|
|||||||
int GetParentElement (int ei) const;
|
int GetParentElement (int ei) const;
|
||||||
int GetParentSElement (int ei) const;
|
int GetParentSElement (int ei) const;
|
||||||
|
|
||||||
|
bool HasParentEdges() const;
|
||||||
|
tuple<int, std::array<int,3>> GetParentEdges (int enr) const;
|
||||||
|
tuple<int, std::array<int,4>> GetParentFaces (int fnr) const;
|
||||||
|
|
||||||
int GetNIdentifications() const;
|
int GetNIdentifications() const;
|
||||||
int GetIdentificationType(int idnr) const;
|
int GetIdentificationType(int idnr) const;
|
||||||
Ng_Buffer<int[2]> GetPeriodicVertices(int idnr) const;
|
Ng_Buffer<int[2]> GetPeriodicVertices(int idnr) const;
|
||||||
@ -367,8 +374,9 @@ namespace netgen
|
|||||||
|
|
||||||
|
|
||||||
// for MPI-parallel
|
// for MPI-parallel
|
||||||
std::tuple<int,int*> GetDistantProcs (int nodetype, int locnum) const;
|
FlatArray<int> GetDistantProcs (int nodetype, int locnum) const;
|
||||||
|
size_t GetGlobalVertexNum (int locnum) const;
|
||||||
|
|
||||||
shared_ptr<Mesh> GetMesh () const { return mesh; }
|
shared_ptr<Mesh> GetMesh () const { return mesh; }
|
||||||
shared_ptr<Mesh> SelectMesh () const;
|
shared_ptr<Mesh> SelectMesh () const;
|
||||||
inline auto GetTimeStamp() const;
|
inline auto GetTimeStamp() const;
|
||||||
|
@ -111,7 +111,13 @@ NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<1> (size_t nr) const
|
|||||||
ret.faces.num = 0;
|
ret.faces.num = 0;
|
||||||
ret.faces.ptr = NULL;
|
ret.faces.ptr = NULL;
|
||||||
|
|
||||||
if (mesh->GetDimension() == 2)
|
if (mesh->GetDimension() == 3)
|
||||||
|
{
|
||||||
|
ret.facets.num = 0;
|
||||||
|
ret.facets.base = 0;
|
||||||
|
ret.facets.ptr = nullptr;
|
||||||
|
}
|
||||||
|
else if (mesh->GetDimension() == 2)
|
||||||
{
|
{
|
||||||
ret.facets.num = 1;
|
ret.facets.num = 1;
|
||||||
ret.facets.base = 0;
|
ret.facets.base = 0;
|
||||||
@ -330,6 +336,20 @@ NGX_INLINE void Ngx_Mesh :: GetParentNodes (int ni, int * parents) const
|
|||||||
parents[0] = parents[1] = -1;
|
parents[0] = parents[1] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool Ngx_Mesh :: HasParentEdges() const
|
||||||
|
{
|
||||||
|
return mesh->GetTopology().HasParentEdges();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline tuple<int, std::array<int,3>> Ngx_Mesh :: GetParentEdges (int enr) const
|
||||||
|
{
|
||||||
|
return mesh->GetTopology().GetParentEdges(enr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline tuple<int, std::array<int,4>> Ngx_Mesh :: GetParentFaces (int fnr) const
|
||||||
|
{
|
||||||
|
return mesh->GetTopology().GetParentFaces(fnr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline auto Ngx_Mesh :: GetTimeStamp() const { return mesh->GetTimeStamp(); }
|
inline auto Ngx_Mesh :: GetTimeStamp() const { return mesh->GetTimeStamp(); }
|
||||||
|
@ -4,10 +4,10 @@ add_library(interface ${NG_LIB_TYPE}
|
|||||||
read_fnf_mesh.cpp readtetmesh.cpp readuser.cpp writeabaqus.cpp writediffpack.cpp
|
read_fnf_mesh.cpp readtetmesh.cpp readuser.cpp writeabaqus.cpp writediffpack.cpp
|
||||||
writedolfin.cpp writeelmer.cpp writefeap.cpp writefluent.cpp writegmsh.cpp writejcm.cpp
|
writedolfin.cpp writeelmer.cpp writefeap.cpp writefluent.cpp writegmsh.cpp writejcm.cpp
|
||||||
writepermas.cpp writetecplot.cpp writetet.cpp writetochnog.cpp writeuser.cpp
|
writepermas.cpp writetecplot.cpp writetet.cpp writetochnog.cpp writeuser.cpp
|
||||||
wuchemnitz.cpp writegmsh2.cpp writeOpenFOAM15x.cpp
|
wuchemnitz.cpp writegmsh2.cpp writeOpenFOAM15x.cpp rw_cgns.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(interface mesh csg geom2d stl visual)
|
target_link_libraries(interface PUBLIC mesh csg geom2d stl visual PRIVATE netgen_cgns)
|
||||||
|
|
||||||
if(NOT WIN32)
|
if(NOT WIN32)
|
||||||
install( TARGETS interface ${NG_INSTALL_DIR})
|
install( TARGETS interface ${NG_INSTALL_DIR})
|
||||||
|
@ -560,7 +560,7 @@ char * Ng_GetSurfaceElementBCName (int ei)
|
|||||||
if ( mesh->GetDimension() == 3 )
|
if ( mesh->GetDimension() == 3 )
|
||||||
return const_cast<char *>(mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).GetBCName().c_str());
|
return const_cast<char *>(mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).GetBCName().c_str());
|
||||||
else
|
else
|
||||||
return const_cast<char *>(mesh->LineSegment(ei).GetBCName().c_str());
|
return const_cast<char *>(mesh->GetBCName(mesh->LineSegment(ei).si).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -905,6 +905,7 @@ void Ng_GetSurfaceElementNeighbouringDomains(const int selnr, int & in, int & ou
|
|||||||
|
|
||||||
// gibt anzahl an distant pnums zurueck
|
// gibt anzahl an distant pnums zurueck
|
||||||
// * pnums entspricht ARRAY<int[2] >
|
// * pnums entspricht ARRAY<int[2] >
|
||||||
|
[[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]]
|
||||||
int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * distnums )
|
int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * distnums )
|
||||||
{
|
{
|
||||||
int size = NgPar_GetNDistantNodeNums (nodetype, locnum);
|
int size = NgPar_GetNDistantNodeNums (nodetype, locnum);
|
||||||
@ -931,6 +932,7 @@ int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * distnums )
|
|||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]]
|
||||||
int NgPar_GetNDistantNodeNums ( int nodetype, int locnum )
|
int NgPar_GetNDistantNodeNums ( int nodetype, int locnum )
|
||||||
{
|
{
|
||||||
locnum++;
|
locnum++;
|
||||||
@ -944,6 +946,7 @@ int NgPar_GetNDistantNodeNums ( int nodetype, int locnum )
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]]
|
||||||
int NgPar_GetGlobalNodeNum (int nodetype, int locnum)
|
int NgPar_GetGlobalNodeNum (int nodetype, int locnum)
|
||||||
{
|
{
|
||||||
locnum++;
|
locnum++;
|
||||||
|
@ -61,8 +61,12 @@ namespace netgen
|
|||||||
SetGlobalMesh (mesh);
|
SetGlobalMesh (mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
NgMPI_Comm Ngx_Mesh :: GetCommunicator() const
|
const NgMPI_Comm & Ngx_Mesh :: GetCommunicator() const
|
||||||
{ return Valid() ? mesh->GetCommunicator() : NgMPI_Comm{}; }
|
{
|
||||||
|
// return Valid() ? mesh->GetCommunicator() : NgMPI_Comm{};
|
||||||
|
if (!Valid()) throw Exception("Ngx_mesh::GetCommunicator: don't have a valid mesh");
|
||||||
|
return mesh->GetCommunicator();
|
||||||
|
}
|
||||||
|
|
||||||
void Ngx_Mesh :: SaveMesh (ostream & ost) const
|
void Ngx_Mesh :: SaveMesh (ostream & ost) const
|
||||||
{
|
{
|
||||||
@ -775,29 +779,23 @@ namespace netgen
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __SSE__
|
|
||||||
#include <immintrin.h>
|
|
||||||
|
|
||||||
template<> DLL_HEADER void Ngx_Mesh ::
|
template<> DLL_HEADER void Ngx_Mesh ::
|
||||||
MultiElementTransformation<1,1> (int elnr, int npts,
|
MultiElementTransformation<1,1> (int elnr, int npts,
|
||||||
const tAVXd * xi, size_t sxi,
|
const SIMD<double> * xi, size_t sxi,
|
||||||
tAVXd * x, size_t sx,
|
SIMD<double> * x, size_t sx,
|
||||||
tAVXd * dxdxi, size_t sdxdxi) const
|
SIMD<double> * dxdxi, size_t sdxdxi) const
|
||||||
{
|
{
|
||||||
cout << "multi-eltrafo simd called, 1,1,simd" << endl;
|
cout << "multi-eltrafo simd called, 1,1,simd" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> DLL_HEADER void Ngx_Mesh ::
|
template<> DLL_HEADER void Ngx_Mesh ::
|
||||||
MultiElementTransformation<2,2> (int elnr, int npts,
|
MultiElementTransformation<2,2> (int elnr, int npts,
|
||||||
const tAVXd * xi, size_t sxi,
|
const SIMD<double> * xi, size_t sxi,
|
||||||
tAVXd * x, size_t sx,
|
SIMD<double> * x, size_t sx,
|
||||||
tAVXd * dxdxi, size_t sdxdxi) const
|
SIMD<double> * dxdxi, size_t sdxdxi) const
|
||||||
{
|
{
|
||||||
mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<2>
|
mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<2>
|
||||||
(elnr, npts,
|
(elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
|
||||||
reinterpret_cast<const SIMD<double>*> (xi), sxi,
|
|
||||||
reinterpret_cast<SIMD<double>*> (x), sx,
|
|
||||||
reinterpret_cast<SIMD<double>*> (dxdxi), sdxdxi);
|
|
||||||
/*
|
/*
|
||||||
for (int i = 0; i < npts; i++)
|
for (int i = 0; i < npts; i++)
|
||||||
{
|
{
|
||||||
@ -824,15 +822,15 @@ namespace netgen
|
|||||||
|
|
||||||
template<> DLL_HEADER void Ngx_Mesh ::
|
template<> DLL_HEADER void Ngx_Mesh ::
|
||||||
MultiElementTransformation<3,3> (int elnr, int npts,
|
MultiElementTransformation<3,3> (int elnr, int npts,
|
||||||
const tAVXd * xi, size_t sxi,
|
const SIMD<double> * xi, size_t sxi,
|
||||||
tAVXd * x, size_t sx,
|
SIMD<double> * x, size_t sx,
|
||||||
tAVXd * dxdxi, size_t sdxdxi) const
|
SIMD<double> * dxdxi, size_t sdxdxi) const
|
||||||
{
|
{
|
||||||
mesh->GetCurvedElements().CalcMultiPointElementTransformation
|
mesh->GetCurvedElements().CalcMultiPointElementTransformation
|
||||||
(elnr, npts,
|
(elnr, npts,
|
||||||
reinterpret_cast<const SIMD<double>*> (xi), sxi,
|
xi, sxi,
|
||||||
reinterpret_cast<SIMD<double>*> (x), sx,
|
x, sx,
|
||||||
reinterpret_cast<SIMD<double>*> (dxdxi), sdxdxi);
|
dxdxi, sdxdxi);
|
||||||
/*
|
/*
|
||||||
for (int i = 0; i < npts; i++)
|
for (int i = 0; i < npts; i++)
|
||||||
{
|
{
|
||||||
@ -859,33 +857,43 @@ namespace netgen
|
|||||||
|
|
||||||
template<> DLL_HEADER void Ngx_Mesh ::
|
template<> DLL_HEADER void Ngx_Mesh ::
|
||||||
MultiElementTransformation<0,2> (int elnr, int npts,
|
MultiElementTransformation<0,2> (int elnr, int npts,
|
||||||
const tAVXd *xi, size_t sxi,
|
const SIMD<double> *xi, size_t sxi,
|
||||||
tAVXd * x, size_t sx,
|
SIMD<double> * x, size_t sx,
|
||||||
tAVXd * dxdxi, size_t sdxdxi) const
|
SIMD<double> * dxdxi, size_t sdxdxi) const
|
||||||
{
|
{
|
||||||
cout << "MultiElementtransformation<0,2> simd not implemented" << endl;
|
//cout << "MultiElementtransformation<0,2> simd not implemented" << endl;
|
||||||
|
|
||||||
|
PointIndex pi = mesh->pointelements[elnr].pnum;
|
||||||
|
Point<3> xg = mesh->Point(pi);
|
||||||
|
if (x)
|
||||||
|
for (int j = 0; j < npts; j++)
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
x[j*sx+i] = xg(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> DLL_HEADER void Ngx_Mesh ::
|
template<> DLL_HEADER void Ngx_Mesh ::
|
||||||
MultiElementTransformation<0,1> (int elnr, int npts,
|
MultiElementTransformation<0,1> (int elnr, int npts,
|
||||||
const tAVXd * xi, size_t sxi,
|
const SIMD<double> * xi, size_t sxi,
|
||||||
tAVXd * x, size_t sx,
|
SIMD<double> * x, size_t sx,
|
||||||
tAVXd * dxdxi, size_t sdxdxi) const
|
SIMD<double> * dxdxi, size_t sdxdxi) const
|
||||||
{
|
{
|
||||||
cout << "multi-eltrafo simd called, 0,1,simd" << endl;
|
//cout << "multi-eltrafo simd called, 0,1,simd" << endl;
|
||||||
|
PointIndex pi = mesh->pointelements[elnr].pnum;
|
||||||
|
Point<3> xg = mesh->Point(pi);
|
||||||
|
if (x)
|
||||||
|
for (int j = 0; j < npts; j++)
|
||||||
|
for (int i = 0; i < 1; i++)
|
||||||
|
x[j*sx+i] = xg(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> DLL_HEADER void Ngx_Mesh ::
|
template<> DLL_HEADER void Ngx_Mesh ::
|
||||||
MultiElementTransformation<1,3> (int elnr, int npts,
|
MultiElementTransformation<1,3> (int elnr, int npts,
|
||||||
const tAVXd * xi, size_t sxi,
|
const SIMD<double> * xi, size_t sxi,
|
||||||
tAVXd * x, size_t sx,
|
SIMD<double> * x, size_t sx,
|
||||||
tAVXd * dxdxi, size_t sdxdxi) const
|
SIMD<double> * dxdxi, size_t sdxdxi) const
|
||||||
{
|
{
|
||||||
mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<3>
|
mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<3>
|
||||||
(elnr, npts,
|
(elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
|
||||||
reinterpret_cast<const SIMD<double>*> (xi), sxi,
|
|
||||||
reinterpret_cast<SIMD<double>*> (x), sx,
|
|
||||||
reinterpret_cast<SIMD<double>*> (dxdxi), sdxdxi);
|
|
||||||
/*
|
/*
|
||||||
double hxi[4][1];
|
double hxi[4][1];
|
||||||
double hx[4][3];
|
double hx[4][3];
|
||||||
@ -908,15 +916,12 @@ namespace netgen
|
|||||||
|
|
||||||
template<> DLL_HEADER void Ngx_Mesh ::
|
template<> DLL_HEADER void Ngx_Mesh ::
|
||||||
MultiElementTransformation<1,2> (int elnr, int npts,
|
MultiElementTransformation<1,2> (int elnr, int npts,
|
||||||
const tAVXd * xi, size_t sxi,
|
const SIMD<double> * xi, size_t sxi,
|
||||||
tAVXd * x, size_t sx,
|
SIMD<double> * x, size_t sx,
|
||||||
tAVXd * dxdxi, size_t sdxdxi) const
|
SIMD<double> * dxdxi, size_t sdxdxi) const
|
||||||
{
|
{
|
||||||
mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<2>
|
mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<2>
|
||||||
(elnr, npts,
|
(elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
|
||||||
reinterpret_cast<const SIMD<double>*> (xi), sxi,
|
|
||||||
reinterpret_cast<SIMD<double>*> (x), sx,
|
|
||||||
reinterpret_cast<SIMD<double>*> (dxdxi), sdxdxi);
|
|
||||||
/*
|
/*
|
||||||
for (int i = 0; i < npts; i++)
|
for (int i = 0; i < npts; i++)
|
||||||
{
|
{
|
||||||
@ -943,15 +948,12 @@ namespace netgen
|
|||||||
|
|
||||||
template<> DLL_HEADER void Ngx_Mesh ::
|
template<> DLL_HEADER void Ngx_Mesh ::
|
||||||
MultiElementTransformation<2,3> (int elnr, int npts,
|
MultiElementTransformation<2,3> (int elnr, int npts,
|
||||||
const tAVXd * xi, size_t sxi,
|
const SIMD<double> * xi, size_t sxi,
|
||||||
tAVXd * x, size_t sx,
|
SIMD<double> * x, size_t sx,
|
||||||
tAVXd * dxdxi, size_t sdxdxi) const
|
SIMD<double> * dxdxi, size_t sdxdxi) const
|
||||||
{
|
{
|
||||||
mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<3>
|
mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<3>
|
||||||
(elnr, npts,
|
(elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
|
||||||
reinterpret_cast<const SIMD<double>*> (xi), sxi,
|
|
||||||
reinterpret_cast<SIMD<double>*> (x), sx,
|
|
||||||
reinterpret_cast<SIMD<double>*> (dxdxi), sdxdxi);
|
|
||||||
/*
|
/*
|
||||||
for (int i = 0; i < npts; i++)
|
for (int i = 0; i < npts; i++)
|
||||||
{
|
{
|
||||||
@ -978,9 +980,9 @@ namespace netgen
|
|||||||
|
|
||||||
template<> DLL_HEADER void Ngx_Mesh ::
|
template<> DLL_HEADER void Ngx_Mesh ::
|
||||||
MultiElementTransformation<0,3> (int elnr, int npts,
|
MultiElementTransformation<0,3> (int elnr, int npts,
|
||||||
const tAVXd * xi, size_t sxi,
|
const SIMD<double> * xi, size_t sxi,
|
||||||
tAVXd * x, size_t sx,
|
SIMD<double> * x, size_t sx,
|
||||||
tAVXd * dxdxi, size_t sdxdxi) const
|
SIMD<double> * dxdxi, size_t sdxdxi) const
|
||||||
{
|
{
|
||||||
for (int i = 0; i < npts; i++)
|
for (int i = 0; i < npts; i++)
|
||||||
{
|
{
|
||||||
@ -999,10 +1001,6 @@ namespace netgen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1037,6 +1035,14 @@ namespace netgen
|
|||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
Point<3> p(hp[0], hp[1],0);
|
Point<3> p(hp[0], hp[1],0);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
auto ind = mesh->GetSurfaceElementOfPoint(p, lami, nullptr,
|
||||||
|
build_searchtree);
|
||||||
|
return ind - 1;
|
||||||
|
}
|
||||||
|
catch(NgException e) // quads not implemented curved yet
|
||||||
|
{
|
||||||
for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
|
for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
|
||||||
{
|
{
|
||||||
auto & seg = (*mesh)[si];
|
auto & seg = (*mesh)[si];
|
||||||
@ -1060,6 +1066,7 @@ namespace netgen
|
|||||||
return si;
|
return si;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
@ -1134,7 +1141,18 @@ namespace netgen
|
|||||||
mesh->BuildCurvedElements(order);
|
mesh->BuildCurvedElements(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Ngx_Mesh :: GetCurveOrder ()
|
||||||
|
{
|
||||||
|
return mesh->GetCurvedElements().GetOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ngx_Mesh :: EnableTable (string name, bool set)
|
||||||
|
{
|
||||||
|
mesh->GetTopology().EnableTable (name, set);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
DLL_HEADER void Ngx_Mesh :: SetRefinementFlag<2> (size_t elnr, bool flag)
|
DLL_HEADER void Ngx_Mesh :: SetRefinementFlag<2> (size_t elnr, bool flag)
|
||||||
{
|
{
|
||||||
@ -1147,9 +1165,9 @@ namespace netgen
|
|||||||
mesh->VolumeElement(elnr+1).SetRefinementFlag(flag);
|
mesh->VolumeElement(elnr+1).SetRefinementFlag(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Ngx_Mesh :: Refine (NG_REFINEMENT_TYPE reftype,
|
void Ngx_Mesh :: Refine (NG_REFINEMENT_TYPE reftype, bool onlyonce,
|
||||||
void (*task_manager)(function<void(int,int)>),
|
void (*task_manager)(function<void(int,int)>),
|
||||||
Tracer tracer)
|
NgTracer tracer)
|
||||||
{
|
{
|
||||||
NgLock meshlock (mesh->MajorMutex(), 1);
|
NgLock meshlock (mesh->MajorMutex(), 1);
|
||||||
|
|
||||||
@ -1157,6 +1175,7 @@ namespace netgen
|
|||||||
biopt.usemarkedelements = 1;
|
biopt.usemarkedelements = 1;
|
||||||
biopt.refine_p = 0;
|
biopt.refine_p = 0;
|
||||||
biopt.refine_hp = 0;
|
biopt.refine_hp = 0;
|
||||||
|
biopt.onlyonce = onlyonce;
|
||||||
if (reftype == NG_REFINE_P)
|
if (reftype == NG_REFINE_P)
|
||||||
biopt.refine_p = 1;
|
biopt.refine_p = 1;
|
||||||
if (reftype == NG_REFINE_HP)
|
if (reftype == NG_REFINE_HP)
|
||||||
@ -1288,33 +1307,35 @@ void Ngx_Mesh::SetSurfaceElementOrders (int enr, int ox, int oy)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t Ngx_Mesh :: GetGlobalVertexNum (int locnum) const
|
||||||
|
{
|
||||||
|
#ifdef PARALLEL
|
||||||
|
return mesh->GetParallelTopology().GetGlobalPNum (locnum+1)-1;
|
||||||
|
#else
|
||||||
|
return locnum;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
std::tuple<int,int*> Ngx_Mesh :: GetDistantProcs (int nodetype, int locnum) const
|
FlatArray<int> Ngx_Mesh :: GetDistantProcs (int nodetype, int locnum) const
|
||||||
{
|
{
|
||||||
#ifdef PARALLEL
|
#ifdef PARALLEL
|
||||||
|
if (mesh->GetCommunicator().Size() == 1)
|
||||||
|
return FlatArray<int>(0,nullptr);
|
||||||
|
|
||||||
switch (nodetype)
|
switch (nodetype)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
return mesh->GetParallelTopology().GetDistantPNums(locnum);
|
||||||
NgFlatArray<int> dn = mesh->GetParallelTopology().GetDistantPNums(locnum);
|
|
||||||
return std::tuple<int,int*>(dn.Size(), &dn[0]);
|
|
||||||
}
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
return mesh->GetParallelTopology().GetDistantEdgeNums(locnum);
|
||||||
NgFlatArray<int> dn = mesh->GetParallelTopology().GetDistantEdgeNums(locnum);
|
|
||||||
return std::tuple<int,int*>(dn.Size(), &dn[0]);
|
|
||||||
}
|
|
||||||
case 2:
|
case 2:
|
||||||
{
|
return mesh->GetParallelTopology().GetDistantFaceNums(locnum);
|
||||||
NgFlatArray<int> dn = mesh->GetParallelTopology().GetDistantFaceNums(locnum);
|
|
||||||
return std::tuple<int,int*>(dn.Size(), &dn[0]);
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
return std::tuple<int,int*>(0,nullptr);
|
return FlatArray<int>(0, nullptr);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
return std::tuple<int,int*>(0,nullptr);
|
return FlatArray<int>(0,nullptr);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user