Merge remote-tracking branch 'origin/master' into rules_files_not_matching_cpp

This commit is contained in:
Matthias Hochsteger 2021-04-28 11:21:15 +02:00
commit 4592123f68
202 changed files with 18063 additions and 5742 deletions

View File

@ -15,8 +15,8 @@ push_github_sourceforge:
- git remote update
- git checkout master
- git pull origin master
- git push sourceforge master
- git push github master
- git push sourceforge master --tags
- git push github master --tags
only:
- master
@ -55,6 +55,8 @@ build_win:
cmake %SRC_DIR%
-G Ninja
-DCMAKE_INSTALL_PREFIX=%INSTALL_DIR%
-DCHECK_RANGE=ON
-DUSE_CGNS=ON
-DUSE_OCC=ON
-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
@ -68,6 +70,7 @@ test_win:
<<: *win
stage: test
script:
- pip install pytest-check
- cd tests\pytest
- cd %NETGEN_BUILD_DIR%\netgen
- ctest -C Release -V --output-on-failure
@ -237,11 +240,13 @@ build_mac:
cmake $SRC_DIR
-DCMAKE_INSTALL_PREFIX=$CMAKE_INSTALL_PREFIX
-DCMAKE_BUILD_TYPE=Release
-DCHECK_RANGE=ON
-DUSE_NATIVE_ARCH=OFF
-DUSE_CCACHE=ON
-DENABLE_UNIT_TESTS=ON
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.12
-DCMAKE_OSX_SYSROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
-DUSE_CGNS=ON
-DUSE_OCC=ON
-DOCC_LIBRARY=/usr/local/opt/opencascade-7.4.0/lib/libTKernel.a
-DOCC_INCLUDE_DIR=/usr/local/opt/opencascade-7.4.0/include/opencascade

BIN
CLA.pdf Normal file

Binary file not shown.

View File

@ -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_PYTHON "build with python interface" ON )
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_JPEG "enable snapshots using library libjpeg" 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( INSTALL_PROFILES "install environment variable settings to /etc/profile.d" OFF )
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( 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_EXPORT_COMPILE_COMMANDS ON)
if(APPLE)
set(INSTALL_DIR_DEFAULT /Applications/Netgen.app)
else(APPLE)
@ -50,14 +54,14 @@ if(INSTALL_DIR)
set(INSTALL_DIR_DEFAULT ${INSTALL_DIR})
endif(INSTALL_DIR)
if(UNIX)
if(UNIX AND USE_SUPERBUILD)
message("Checking for write permissions in install directory...")
execute_process(COMMAND mkdir -p ${CMAKE_INSTALL_PREFIX})
execute_process(COMMAND test -w ${CMAKE_INSTALL_PREFIX} RESULT_VARIABLE res)
if(res)
message(WARNING "No write access at install directory, please set correct permissions")
endif()
endif(UNIX)
endif(UNIX AND USE_SUPERBUILD)
if (USE_SUPERBUILD)
project (SUPERBUILD)
@ -76,12 +80,10 @@ else()
endif()
endif()
set(NETGEN_VERSION_MAJOR 6)
set(NETGEN_VERSION_MINOR 2)
string(TIMESTAMP NETGEN_VERSION_PATCH "%y%U%w" )
set(NETGEN_VERSION "${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}-dev")
set(PACKAGE_VERSION "${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}-${NETGEN_VERSION_PATCH}")
set(CPACK_PACKAGE_VERSION "${PACKAGE_VERSION}")
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include (${CMAKE_CURRENT_LIST_DIR}/cmake/generate_version_file.cmake)
set(CPACK_PACKAGE_VERSION "${NETGEN_VERSION}")
#######################################################################
@ -193,7 +195,6 @@ check_include_files (dlfcn.h HAVE_DLFCN_H)
if(HAVE_DLFCN_H)
add_definitions(-DHAVE_DLFCN_H)
endif()
add_definitions(-DNETGEN_VERSION="${NETGEN_VERSION}")
include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
@ -300,6 +301,14 @@ if (USE_MPI)
target_include_directories(netgen_metis INTERFACE ${METIS_INCLUDE_DIR})
target_link_libraries(netgen_metis INTERFACE ${METIS_LIBRARY} )
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)
install(TARGETS netgen_mpi netgen_metis ${NG_INSTALL_DIR})
@ -324,6 +333,12 @@ if (USE_MPEG)
include_directories(${FFMPEG_INCLUDE_DIR})
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)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/netgen.sh "#!/bin/sh\n")
@ -388,12 +403,27 @@ if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
endif()
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(ng)
add_subdirectory(tutorials)
add_subdirectory(py_tutorials)
add_subdirectory(doc)
add_subdirectory(windows)
add_subdirectory(nglib)
if (USE_PYTHON)
add_subdirectory(python)
@ -444,6 +474,8 @@ if(USE_NATIVE_ARCH)
else()
message(STATUS "Build for generic CPU")
endif()
elseif(APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
# no flag necessary/available on Apple M1
else()
target_compile_options(ngcore PUBLIC "-march=native")
endif(WIN32)

18
CONTRIBUTING.md Normal file
View 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).

View File

@ -1,4 +1,8 @@
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)
@ -27,6 +31,7 @@ set(NETGEN_METIS_LIBRARY "@METIS_LIBRARY@")
set(NETGEN_MKL_LIBRARIES "@MKL_LIBRARIES@")
set(NETGEN_MPI_CXX_INCLUDE_PATH "@MPI_CXX_INCLUDE_PATH@")
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_LIBRARIES_BIN "@OCC_LIBRARIES_BIN@")
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_JPEG @USE_JPEG@)
set(NETGEN_USE_MPEG @USE_MPEG@)
set(NETGEN_USE_CGNS @USE_CGNS@)
set(NETGEN_INTEL_MIC @INTEL_MIC@)
set(NETGEN_INSTALL_PROFILES @INSTALL_PROFILES@)
set(NETGEN_USE_CCACHE @USE_CCACHE@)
set(NETGEN_USE_NATIVE_ARCH @USE_NATIVE_ARCH@)
set(NETGEN_USE_NUMA @USE_NUMA@)
set(NETGEN_PYTHON_RPATH "@NETGEN_PYTHON_RPATH@")
set(NETGEN_RPATH_TOKEN "@NG_RPATH_TOKEN@")

View File

@ -15,12 +15,12 @@ macro(set_vars VAR_OUT)
endforeach()
endmacro()
#######################################################################
if(WIN32)
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 (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)
endif(WIN32)
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 (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 (CGNS_DOWNLOAD_URL_WIN "${DEPS_DOWNLOAD_URL}/cgns_win64.zip" CACHE STRING INTERNAL)
set (CGNS_DOWNLOAD_URL_MAC "${DEPS_DOWNLOAD_URL}/cgns_mac.zip" CACHE STRING INTERNAL)
if(UNIX)
message("Checking for write permissions in install directory...")
@ -86,6 +86,10 @@ if(USE_GUI)
include(cmake/external_projects/tcltk.cmake)
endif(USE_GUI)
if(USE_CGNS)
include(cmake/external_projects/cgns.cmake)
endif(USE_CGNS)
#######################################################################
if(USE_MPI)
if(UNIX)
@ -128,6 +132,7 @@ set_vars( NETGEN_CMAKE_ARGS
USE_OCC
USE_MPEG
USE_JPEG
USE_CGNS
USE_INTERNAL_TCL
INSTALL_PROFILES
INTEL_MIC
@ -138,8 +143,10 @@ set_vars( NETGEN_CMAKE_ARGS
USE_SPDLOG
DEBUG_LOG
CHECK_RANGE
TRACE_MEMORY
BUILD_STUB_FILES
BUILD_FOR_CONDA
NG_COMPILE_FLAGS
)
# propagate all variables set on the command line using cmake -DFOO=BAR

View File

@ -25,9 +25,9 @@ else(WIN32)
)
endif(WIN32)
if(OCC_LIBRARY)
if(OCC_LIBRARY AND NOT OCC_LIBRARY_DIR)
get_filename_component(OCC_LIBRARY_DIR ${OCC_LIBRARY} PATH)
endif(OCC_LIBRARY)
endif(OCC_LIBRARY AND NOT OCC_LIBRARY_DIR)
if(OCC_INCLUDE_DIR)
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()
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}})
endforeach()

View 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)

View 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

View File

@ -11,8 +11,11 @@ add_library(ngcore SHARED
table.cpp
taskmanager.cpp
utils.cpp
version.cpp
)
target_compile_options(ngcore PUBLIC "${NG_COMPILE_FLAGS}")
# Pybind11 2.3 Issue https://github.com/pybind/pybind11/issues/1604
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
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)
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)
include_directories(${SPDLOG_INCLUDE_DIR})
install(DIRECTORY ${SPDLOG_INCLUDE_DIR}
@ -51,20 +59,29 @@ if(USE_SPDLOG)
endif(DEBUG_LOG)
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)
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
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
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)
if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
set_target_properties(ngcore PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
endif(ENABLE_CPP_CORE_GUIDELINES_CHECK)
add_dependencies(ngcore ng_generate_version_file)
if(USE_PYTHON)
pybind11_add_module(pyngcore SHARED python_ngcore_export.cpp)
target_link_libraries(pyngcore PUBLIC ngcore netgen_python)

View File

@ -1,5 +1,6 @@
#include "archive.hpp"
#include "version.hpp"
#ifndef WIN32
#include <cxxabi.h>
@ -7,18 +8,6 @@
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
static std::unique_ptr<std::map<std::string, detail::ClassArchiveInfo>> type_register; // NOLINT
const detail::ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname)

View File

@ -30,9 +30,6 @@ namespace pybind11
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;
@ -156,6 +153,7 @@ namespace ngcore
virtual void NeedsVersion(const std::string& /*unused*/, const std::string& /*unused*/) {}
// 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 & (int & i) = 0;
virtual Archive & operator & (long & i) = 0;
@ -570,8 +568,9 @@ namespace ngcore
virtual void FlushBuffer() {}
protected:
static std::map<std::string, VersionInfo>& GetLibraryVersions();
bool parallel = false;
bool IsParallel() const { return parallel; }
void SetParallel (bool _parallel) { parallel = _parallel; }
private:
template<typename T, typename ... Bases>
@ -680,6 +679,8 @@ namespace ngcore
BinaryOutArchive& operator=(BinaryOutArchive&&) = delete;
using Archive::operator&;
Archive & operator & (float & f) override
{ return Write(f); }
Archive & operator & (double & d) override
{ return Write(d); }
Archive & operator & (int & i) override
@ -687,7 +688,11 @@ namespace ngcore
Archive & operator & (short & i) override
{ return Write(i); }
Archive & operator & (long & i) override
{ return Write(i); }
{
// for platform independence
int64_t tmp = i;
return Write(tmp);
}
Archive & operator & (size_t & i) override
{ return Write(i); }
Archive & operator & (unsigned char & i) override
@ -725,14 +730,13 @@ namespace ngcore
template <typename T>
Archive & Write (T x)
{
static_assert(sizeof(T) < BUFFERSIZE, "Cannot write large types with this function!");
if (unlikely(ptr > BUFFERSIZE-sizeof(T)))
{
stream->write(&buffer[0], ptr);
*reinterpret_cast<T*>(&buffer[0]) = x; // NOLINT
ptr = sizeof(T);
return *this;
ptr = 0;
}
*reinterpret_cast<T*>(&buffer[ptr]) = x; // NOLINT
memcpy(&buffer[ptr], &x, sizeof(T));
ptr += sizeof(T);
return *this;
}
@ -751,6 +755,8 @@ namespace ngcore
: BinaryInArchive(std::make_shared<std::ifstream>(filename)) { ; }
using Archive::operator&;
Archive & operator & (float & f) override
{ Read(f); return *this; }
Archive & operator & (double & d) override
{ Read(d); return *this; }
Archive & operator & (int & i) override
@ -758,7 +764,12 @@ namespace ngcore
Archive & operator & (short & i) override
{ Read(i); return *this; }
Archive & operator & (long & i) override
{ Read(i); return *this; }
{
int64_t tmp;
Read(tmp);
i = tmp;
return *this;
}
Archive & operator & (size_t & i) override
{ Read(i); return *this; }
Archive & operator & (unsigned char & i) override
@ -815,6 +826,8 @@ namespace ngcore
TextOutArchive(std::make_shared<std::ofstream>(filename)) { }
using Archive::operator&;
Archive & operator & (float & f) override
{ *stream << f << '\n'; return *this; }
Archive & operator & (double & d) override
{ *stream << d << '\n'; return *this; }
Archive & operator & (int & i) override
@ -866,6 +879,8 @@ namespace ngcore
: TextInArchive(std::make_shared<std::ifstream>(filename)) {}
using Archive::operator&;
Archive & operator & (float & f) override
{ *stream >> f; return *this; }
Archive & operator & (double & d) override
{ *stream >> d; return *this; }
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
#endif // NETGEN_CORE_ARCHIVE_HPP

View File

@ -11,6 +11,7 @@
#include "archive.hpp"
#include "exception.hpp"
#include "localheap.hpp"
#include "profiler.hpp"
#include "utils.hpp"
namespace ngcore
@ -39,7 +40,7 @@ namespace ngcore
};
template <typename ... ARGS>
ostream & operator<< (ostream & ost, Tuple<ARGS...> tup)
ostream & operator<< (ostream & ost, Tuple<ARGS...> /* tup */)
{
return ost;
}
@ -212,6 +213,20 @@ namespace ngcore
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;
@ -268,7 +283,7 @@ namespace ngcore
NETGEN_INLINE T & First() { return first; }
NETGEN_INLINE T & Next() { return next; }
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 T_Range Modify(int inc_beg, int inc_end) const
{ return T_Range(first+inc_beg, next+inc_end); }
@ -559,6 +574,12 @@ namespace ngcore
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
NETGEN_INLINE FlatArray<T> Range (T_Range<size_t> range) const
{
@ -599,9 +620,25 @@ namespace ngcore
template <typename T>
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
template <class T>
inline ostream & operator<< (ostream & s, const FlatArray<T> & a)
template <class T, class TIND>
inline ostream & operator<< (ostream & s, const FlatArray<T, TIND> & a)
{
for (auto i : a.Range())
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
T * mem_to_delete;
using FlatArray<T,IndexType>::size;
using FlatArray<T,IndexType>::data;
using FlatArray<T,IndexType>::BASE;
@ -682,6 +720,8 @@ namespace ngcore
NETGEN_INLINE Array (Array && a2)
{
mt.Swap(sizeof(T) * allocsize, a2.mt, sizeof(T) * a2.allocsize);
size = a2.size;
data = a2.data;
allocsize = a2.allocsize;
@ -695,12 +735,17 @@ namespace ngcore
/// array copy
NETGEN_INLINE explicit Array (const Array & a2)
: FlatArray<T,IndexType> (a2.Size(), a2.Size() ? new T[a2.Size()] : nullptr)
{
if constexpr (std::is_copy_assignable<T>::value)
{
allocsize = size;
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());
}
template <typename TA>
@ -747,6 +792,8 @@ namespace ngcore
/// if responsible, deletes memory
NETGEN_INLINE ~Array()
{
if(mem_to_delete)
mt.Free(sizeof(T)*allocsize);
delete [] mem_to_delete;
}
@ -801,6 +848,8 @@ namespace ngcore
/// assigns memory from local heap
NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh)
{
if(mem_to_delete)
mt.Free(sizeof(T)*allocsize);
delete [] mem_to_delete;
size = allocsize = asize;
data = lh.Alloc<T> (asize);
@ -858,7 +907,7 @@ namespace ngcore
size++;
}
NETGEN_INLINE Array<T> & operator += (const T & el)
NETGEN_INLINE Array & operator += (const T & el)
{
Append (el);
return *this;
@ -908,6 +957,8 @@ namespace ngcore
/// Deallocate memory
NETGEN_INLINE void DeleteAll ()
{
if(mem_to_delete)
mt.Free(sizeof(T)*allocsize);
delete [] mem_to_delete;
mem_to_delete = NULL;
data = 0;
@ -923,6 +974,8 @@ namespace ngcore
/// array copy
NETGEN_INLINE Array & operator= (const Array & a2)
{
if constexpr (std::is_copy_assignable<T>::value)
{
SetSize0 ();
SetSize (a2.Size());
@ -930,10 +983,16 @@ namespace ngcore
data[i] = a2.data[i];
return *this;
}
else
throw Exception(std::string("cannot copy Array of type ") + typeid(T).name());
}
/// steal array
NETGEN_INLINE Array & operator= (Array && a2)
{
mt.Swap(sizeof(T)*allocsize, a2.mt, sizeof(T)*a2.allocsize);
ngcore::Swap (size, a2.size);
ngcore::Swap (data, a2.data);
ngcore::Swap (allocsize, a2.allocsize);
@ -1007,16 +1066,26 @@ namespace ngcore
NETGEN_INLINE void Swap (Array & b)
{
mt.Swap(sizeof(T) * allocsize, b.mt, sizeof(T) * b.allocsize);
ngcore::Swap (size, b.size);
ngcore::Swap (data, b.data);
ngcore::Swap (allocsize, b.allocsize);
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:
/// resize array, at least to size minsize. copy contents
NETGEN_INLINE void ReSize (size_t minsize);
MemoryTracer mt;
};
@ -1029,6 +1098,7 @@ namespace ngcore
T * hdata = data;
data = new T[nsize];
mt.Alloc(sizeof(T) * nsize);
if (hdata)
{
@ -1041,6 +1111,8 @@ namespace ngcore
else
for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]);
#endif
if(mem_to_delete)
mt.Free(sizeof(T) * allocsize);
delete [] mem_to_delete;
}
@ -1124,6 +1196,14 @@ namespace ngcore
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)
{
@ -1179,7 +1259,7 @@ namespace ngcore
template <typename ... ARGS>
size_t ArraySize (Tuple<ARGS...> tup)
size_t ArraySize (Tuple<ARGS...> /* tup */)
{ return 0;}
template <typename ... ARGS>
@ -1192,7 +1272,7 @@ namespace ngcore
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>
void StoreToArray (FlatArray<T> a, Tuple<int,ARGS...> tup)
@ -1284,7 +1364,7 @@ namespace ngcore
/// bubble sort array
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 j = i+1; j < data.Size(); j++)
@ -1294,9 +1374,9 @@ namespace ngcore
data[i] = data[j];
data[j] = hv;
S hvs = slave[i];
slave[i] = slave[j];
slave[j] = hvs;
S hvs = index[i];
index[i] = index[j];
index[j] = hvs;
}
}

View File

@ -36,10 +36,15 @@ namespace ngcore
void BitArray :: SetSize (size_t asize)
{
if (size == asize) return;
if (owns_data) delete [] data;
if (owns_data)
{
delete [] data;
mt.Free(Addr(size)+1);
}
size = asize;
data = new unsigned char [Addr (size)+1];
mt.Alloc(Addr(size)+1);
}
BitArray & BitArray :: Set () throw()
@ -83,6 +88,18 @@ namespace ngcore
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)
{
@ -115,29 +132,52 @@ namespace ngcore
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();
for (size_t i = 0; i < ba.Size(); i++)
archive << ba[i];
archive.NeedsVersion("netgen", "v6.2.2007-62");
auto size = Size();
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
{
int size;
if (archive.Output())
{
throw Exception("should not get here");
archive << Size();
for (size_t i = 0; i < Size(); i++)
archive << (*this)[i];
}
else
{
size_t size;
archive & size;
ba.SetSize (size);
ba.Clear();
SetSize (size);
Clear();
for (size_t i = 0; i < size; i++)
{
bool b;
archive & b;
if (b) ba.SetBit(i);
if (b) SetBit(i);
}
}
return archive;
}
}
}
} // namespace ngcore

View File

@ -131,6 +131,7 @@ public:
return Test(i);
}
NGCORE_API bool operator==(const BitArray& other) const;
/// invert all bits
NGCORE_API BitArray & Invert ();
@ -145,6 +146,18 @@ public:
NGCORE_API BitArray & operator= (const BitArray & ba2);
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:
///
unsigned char Mask (size_t i) const
@ -154,6 +167,7 @@ private:
size_t Addr (size_t i) const
{ return (i / CHAR_BIT); }
MemoryTracer mt;
};
@ -190,11 +204,8 @@ private:
return res;
}
NGCORE_API std::ostream & operator<<(std::ostream & s, const BitArray & ba);
NGCORE_API Archive & operator & (Archive & archive, BitArray & ba);
} // namespace ngcore
#endif // NETGEN_CORE_BITARRAY

View File

@ -217,9 +217,12 @@ static void ngcore_signal_handler(int sig)
// register signal handler when library is loaded
static bool dummy = []()
{
if(getenv("NG_BACKTRACE"))
{
signal(SIGABRT, ngcore_signal_handler);
signal(SIGILL, ngcore_signal_handler);
signal(SIGSEGV, ngcore_signal_handler);
}
return true;
}();

View File

@ -51,6 +51,10 @@ namespace ngcore
auto lflags = flags.GetFlagsFlag (i, name);
SetFlag (name, lflags);
}
for(auto i : Range(flags.anyflags.Size()))
{
SetFlag(flags.anyflags.GetName(i), flags.anyflags[i]);
}
}
Flags :: Flags (Flags && flags)
@ -178,7 +182,11 @@ namespace ngcore
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
{
@ -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
{
return strflags.Used (name);
@ -304,6 +320,11 @@ namespace ngcore
return numlistflags.Used (name);
}
bool Flags :: AnyFlagDefined (const string& name) const
{
return anyflags.Used(name);
}
void Flags :: SaveFlags (ostream & str) const
{
for (int i = 0; i < strflags.Size(); i++)

View File

@ -11,6 +11,7 @@
#include <iostream>
#include <memory>
#include <string>
#include <any>
#include "array.hpp"
#include "symboltable.hpp"
@ -38,6 +39,8 @@ namespace ngcore
SymbolTable<std::shared_ptr<Array<double>>> numlistflags;
/// flags list flags
SymbolTable<Flags> flaglistflags;
/// any object can be stored as a flag
SymbolTable<std::any> anyflags;
public:
/// no flags
Flags ();
@ -94,6 +97,8 @@ namespace ngcore
Flags & SetFlag (const std::string & name, const Array<std::string> & val);
/// Sets double array flag
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) &&;
@ -135,6 +140,7 @@ namespace ngcore
const Array<double> & GetNumListFlag (const std::string & name) const;
/// Returns flag list flag, empty flag if not exist
const Flags & GetFlagsFlag (const std::string & name) const;
const std::any& GetAnyFlag (const std::string& name) const;
/// Test, if string flag is defined
@ -147,6 +153,7 @@ namespace ngcore
bool StringListFlagDefined (const std::string & name) const;
/// Test, if num list flag is defined
bool NumListFlagDefined (const std::string & name) const;
bool AnyFlagDefined (const std::string& name) const;
/// number of string flags
int GetNStringFlags () const { return strflags.Size(); }

View File

@ -174,6 +174,13 @@ namespace ngcore
{
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
@ -727,6 +734,11 @@ namespace ngcore
acont = cont[pos];
}
T GetData (size_t pos) const
{
return cont[pos];
}
std::pair<T_HASH,T> GetBoth (size_t pos) const
{
return std::pair<T_HASH,T> (hash[pos], cont[pos]);

View File

@ -198,9 +198,9 @@ public:
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:
///
#ifndef __CUDA_ARCH__
@ -211,7 +211,7 @@ public:
public:
/// free memory (dummy function)
NETGEN_INLINE void Free (void * data) throw ()
NETGEN_INLINE void Free (void * /* data */) throw ()
{
;
}

View File

@ -8,6 +8,7 @@
#include "array.hpp"
#include "exception.hpp"
#include "profiler.hpp"
namespace ngcore
{
@ -25,6 +26,9 @@ namespace ngcore
template <> struct MPI_typetrait<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> {
static MPI_Datatype MPIType () { return MPI_CHAR; } };
@ -43,6 +47,10 @@ namespace ngcore
return MPI_typetrait<T>::MPIType();
}
template <class T>
inline MPI_Datatype GetMPIType (T &) {
return GetMPIType<T>();
}
class NgMPI_Comm
{
@ -59,6 +67,17 @@ namespace ngcore
NgMPI_Comm (MPI_Comm _comm, bool owns = false)
: comm(_comm), valid_comm(true)
{
int flag;
MPI_Initialized (&flag);
if (!flag)
{
valid_comm = false;
refcount = nullptr;
rank = 0;
size = 1;
return;
}
if (!owns)
refcount = nullptr;
else
@ -89,6 +108,11 @@ namespace ngcore
MPI_Comm_free(&comm);
}
bool ValidCommunicator() const
{
return valid_comm;
}
NgMPI_Comm & operator= (const NgMPI_Comm & c)
{
if (refcount)
@ -117,6 +141,7 @@ namespace ngcore
int Rank() const { return rank; }
int Size() const { return size; }
void Barrier() const {
static Timer t("MPI - Barrier"); RegionTimer reg(t);
if (size > 1) MPI_Barrier (comm);
}
@ -128,8 +153,12 @@ namespace ngcore
MPI_Send (&val, 1, GetMPIType<T>(), dest, tag, comm);
}
template<typename T, typename T2 = decltype(GetMPIType<T>())>
void Send(FlatArray<T> s, int dest, int tag) const {
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 TI, typename T2 = decltype(GetMPIType<T>())>
void Send(FlatArray<T,TI> s, int dest, int tag) const {
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);
}
template <typename T, typename T2 = decltype(GetMPIType<T>())>
void Recv (FlatArray <T> s, int src, int tag) const {
void Recv (std::string & 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);
}
template <typename T, typename T2 = decltype(GetMPIType<T>())>
void Recv (Array <T> & s, int src, int tag) const
template <typename T, typename TI, typename T2 = decltype(GetMPIType<T>())>
void Recv (Array <T,TI> & s, int src, int tag) const
{
MPI_Status status;
int len;
@ -166,7 +206,7 @@ namespace ngcore
}
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_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>())>
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_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>())>
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;
T global_d;
@ -205,6 +246,7 @@ namespace ngcore
template <typename T, typename T2 = decltype(GetMPIType<T>())>
T AllReduce (T d, const MPI_Op & op) const
{
static Timer t("MPI - AllReduce"); RegionTimer reg(t);
if (size == 1) return d;
T global_d;
@ -227,6 +269,44 @@ namespace ngcore
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
{
MPI_Comm subcomm;
@ -241,6 +321,7 @@ namespace ngcore
NETGEN_INLINE void MyMPI_WaitAll (FlatArray<MPI_Request> requests)
{
static Timer t("MPI - WaitAll"); RegionTimer reg(t);
if (!requests.Size()) return;
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;
typedef int MPI_Op;
typedef int MPI_Datatype;
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
{
@ -276,6 +358,7 @@ namespace ngcore
size_t Rank() const { return 0; }
size_t Size() const { return 1; }
bool ValidCommunicator() const { return false; }
void Barrier() const { ; }
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; }
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>
MPI_Request IRecv (T & val, int dest, int tag) const { return 0; }
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>
T Reduce (T d, const MPI_Op & op, int root = 0) const { return d; }

View File

@ -6,14 +6,15 @@
#include "bitarray.hpp"
#include "exception.hpp"
#include "flags.hpp"
#include "table.hpp"
#include "hashtable.hpp"
#include "localheap.hpp"
#include "logging.hpp"
#include "mpi_wrapper.hpp"
#include "profiler.hpp"
#include "signal.hpp"
#include "simd.hpp"
#include "symboltable.hpp"
#include "table.hpp"
#include "taskmanager.hpp"
#include "version.hpp"
#include "xbool.hpp"

View File

@ -67,6 +67,18 @@
#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
#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101400
// The c++ standard library on MacOS 10.13 and earlier has no aligned new operator,

View File

@ -8,28 +8,46 @@
#include "archive.hpp" // for Demangle
#include "paje_trace.hpp"
#include "profiler.hpp"
#include "mpi_wrapper.hpp"
extern const char *header;
constexpr int MPI_PAJE_WRITER = 1;
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
size_t PajeTrace::max_tracefile_size = 0;
// If true, produce variable counting active threads
// 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::mem_tracing_enabled = true;
PajeTrace :: PajeTrace(int anthreads, std::string aname)
{
start_time = GetTimeCounter();
nthreads = anthreads;
tracefile_name = std::move(aname);
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)
{
logger->info( "Tracefile size = {}MB", max_tracefile_size/1024/1024);
@ -47,15 +65,62 @@ namespace ngcore
jobs.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;
mem_tracing_enabled = true;
n_memory_events_at_start = memory_events.size();
}
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);
}
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();
}
}
void PajeTrace::StopTracing()
@ -90,7 +155,6 @@ namespace ngcore
int alias_counter;
FILE * ctrace_stream;
TTimePoint start_time;
std::shared_ptr<Logger> logger = GetLogger("PajeTrace");
@ -98,7 +162,7 @@ namespace ngcore
// 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() / 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
@ -180,10 +244,10 @@ namespace ngcore
void operator=(const PajeFile &) = delete;
void operator=(PajeFile &&) = delete;
PajeFile( const std::string & filename, TTimePoint astart_time )
PajeFile( const std::string & filename)
{
start_time = astart_time;
ctrace_stream = fopen (filename.c_str(),"w"); // NOLINT
std::string fname = filename + ".trace";
ctrace_stream = fopen (fname.c_str(),"w"); // NOLINT
fprintf(ctrace_stream, "%s", header ); // NOLINT
alias_counter = 0;
}
@ -365,32 +429,77 @@ namespace ngcore
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_node = paje.DefineContainerType( container_type_task_manager, "Node");
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_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_task = paje.DefineStateType( container_type_thread, "Task" );
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_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;
#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)) );
std::vector <int> thread_aliases;
thread_aliases.reserve(nthreads);
if(trace_threads)
for (int i=0; i<nthreads; i++)
@ -398,6 +507,7 @@ namespace ngcore
auto name = "Thread " + ToString(i);
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_task_map;
@ -416,20 +526,73 @@ namespace ngcore
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::map<int,int> timer_aliases;
std::map<int,std::string> timer_names;
for(auto & event : timer_events)
timer_ids.insert(event.timer_id);
// Timer names
for(auto & vtasks : tasks)
for (Task & t : vtasks)
if(t.id_type==Task::ID_TIMER)
timer_ids.insert(t.id);
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 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
int nlinks = 0;
for( auto & l : links)
@ -552,25 +759,96 @@ namespace ngcore
}
}
}
WriteSunburstHTML();
WriteTimingChart();
#ifdef NETGEN_TRACE_MEMORY
WriteMemoryChart("");
#endif // NETGEN_TRACE_MEMORY
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
struct TreeNode
{
int id = 0;
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;
size_t calls = 0;
TTimePoint start_time = 0;
};
void PrintNode (const TreeNode &n, int &level, std::ofstream & f);
void PrintNode (const TreeNode &n, int &level, std::ofstream & f)
void PrintNode (const TreeNode &n, 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();
if(size>0)
{
@ -578,7 +856,7 @@ namespace ngcore
f << ", children: [";
for(auto & c : n.children)
{
PrintNode(c.second, level, f);
PrintNode(c.second, f);
if(++i<size)
f << " , ";
}
@ -587,12 +865,224 @@ namespace ngcore
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 + " &rarr; " + 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;
TreeNode root;
root.time=0;
root.name="all";
TreeNode *current = &root;
@ -629,7 +1119,10 @@ namespace ngcore
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)
{
@ -645,8 +1138,8 @@ namespace ngcore
if(need_init)
{
current->name = is_timer_event ? NgProfiler::GetName(id) : job_names[id];
current->time = 0.0;
current->name = is_timer_event ? GetTimerName(id) : job_names[id];
current->size = 0.0;
current->id = id;
}
@ -658,44 +1151,22 @@ namespace ngcore
std::cout << "node stack empty!" << std::endl;
break;
}
double time = 1000.0*static_cast<double>(event.time-current->start_time) * seconds_per_tick;
current->time += time;
double size = 1000.0*static_cast<double>(event.time-current->start_time) * seconds_per_tick;
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->time -= time;
current->chart_size -= size;
node_stack.pop_back();
}
}
int level = 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>
root.chart_size = 0.0;
<style>body { margin: 0 }</style>
</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;
ngcore::WriteSunburstHTML( root, tracefile_name, true );
}
} // namespace ngcore

View File

@ -23,18 +23,28 @@ namespace ngcore
NGCORE_API static size_t max_tracefile_size;
NGCORE_API static bool trace_thread_counter;
NGCORE_API static bool trace_threads;
NGCORE_API static bool mem_tracing_enabled;
bool tracing_enabled;
TTimePoint start_time;
int nthreads;
size_t n_memory_events_at_start;
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
// be stopped if any thread reaches this number of events
unsigned int max_num_events_per_thread;
static void SetTraceMemory( bool trace_memory )
{
mem_tracing_enabled = trace_memory;
}
static void SetTraceThreads( bool atrace_threads )
{
trace_threads = atrace_threads;
@ -96,10 +106,21 @@ namespace ngcore
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<Job> jobs;
std::vector<TimerEvent> timer_events;
std::vector<std::vector<ThreadLink> > links;
NGCORE_API static std::vector<MemoryEvent> memory_events;
public:
NGCORE_API void StopTracing();
@ -129,6 +150,27 @@ namespace ngcore
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)
{
if(!tracing_enabled) return -1;
@ -185,6 +227,8 @@ namespace ngcore
void Write( const std::string & filename );
void SendData(); // MPI parallel data reduction
};
} // namespace ngcore

View File

@ -113,5 +113,9 @@ namespace ngcore
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

View File

@ -3,6 +3,7 @@
#include <array>
#include <chrono>
#include <functional>
#include <string>
#include "logging.hpp"
@ -299,7 +300,171 @@ namespace ngcore
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
// 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

View File

@ -8,6 +8,8 @@ using std::string;
namespace ngcore
{
bool ngcore_have_numpy = false;
bool parallel_pickling = true;
void SetFlag(Flags &flags, string s, py::object value)
{
if (py::isinstance<py::dict>(value))

View File

@ -5,16 +5,69 @@
#include <pybind11/pybind11.h>
#include <pybind11/operators.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include "array.hpp"
#include "archive.hpp"
#include "flags.hpp"
#include "ngcore_api.hpp"
#include "profiler.hpp"
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
{
NGCORE_API extern bool ngcore_have_numpy;
NGCORE_API extern bool parallel_pickling;
// Python class name type traits
template <typename T>
@ -142,6 +195,10 @@ namespace ngcore
return py::make_iterator (self.begin(),self.end());
}, 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)
@ -225,7 +282,6 @@ namespace ngcore
using ARCHIVE::stream;
using ARCHIVE::version_map;
using ARCHIVE::logger;
using ARCHIVE::GetLibraryVersions;
public:
PyArchive(const pybind11::object& alst = pybind11::none()) :
ARCHIVE(std::make_shared<std::stringstream>()),
@ -270,10 +326,11 @@ namespace ngcore
pybind11::list WriteOut()
{
auto version_runtime = GetLibraryVersions();
FlushBuffer();
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
stream = std::make_shared<std::stringstream>();
*this & GetLibraryVersions();
*this & version_runtime;
FlushBuffer();
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
stream = std::make_shared<std::stringstream>();
@ -291,19 +348,14 @@ namespace ngcore
return pybind11::pickle([](T* self)
{
PyArchive<T_ARCHIVE_OUT> ar;
ar.SetParallel(parallel_pickling);
ar & self;
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;
},
[](const pybind11::tuple & state)
{
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]);
ar & val;
return val;

View File

@ -30,6 +30,7 @@ PYBIND11_MODULE(pyngcore, m) // NOLINT
if (a[i]) ba->SetBit(i);
return ba;
} ), py::arg("vec"))
.def(NGSPickle<BitArray>())
.def("__str__", &ToString<BitArray>)
.def("__len__", &BitArray::Size)
.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")
.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)
{
if (b)
@ -222,4 +246,30 @@ threads : int
.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
View 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
View 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
View 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
View 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
View 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

View 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
View 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

View File

@ -18,6 +18,19 @@ namespace ngcore
size_t size = entrysize.Size();
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);
partial_sums[0] = 0;
ParallelJob
@ -54,7 +67,7 @@ namespace ngcore
NGCORE_API size_t * TablePrefixSum64 (FlatArray<size_t> entrysize)
{ return TablePrefixSum2 (entrysize); }
/*
BaseDynamicTable :: BaseDynamicTable (int size)
: data(size)
{
@ -88,7 +101,6 @@ namespace ngcore
}
}
BaseDynamicTable :: ~BaseDynamicTable ()
{
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())
{
@ -135,7 +147,7 @@ namespace ngcore
line.size++;
}
void BaseDynamicTable :: DecSize (int i)
void BaseDynamicTable :: DecSize (IndexType i)
{
if (i < 0 || i >= data.Size())
{
@ -153,6 +165,7 @@ namespace ngcore
line.size--;
}
*/
void FilteredTableCreator::Add (size_t blocknr, int data)
{

View File

@ -20,9 +20,9 @@ namespace ngcore
template <class T, class IndexType = size_t>
class FlatTable
{
protected:
class FlatTable
{
protected:
static constexpr IndexType BASE = IndexBASE<IndexType>();
/// number of rows
size_t size;
@ -31,7 +31,7 @@ protected:
/// array of data
T * data;
public:
public:
FlatTable() = delete;
NETGEN_INLINE FlatTable(size_t as, size_t * aindex, T * adata)
@ -89,7 +89,7 @@ public:
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 * TablePrefixSum64 (FlatArray<size_t> entrysize);
@ -105,21 +105,21 @@ public:
{ return TablePrefixSum64 (entrysize); }
/**
/**
A compact Table container.
A table contains size entries of variable size.
The entry sizes must be known at construction.
*/
*/
template <class T, class IndexType = size_t>
class Table : public FlatTable<T, IndexType>
{
protected:
{
protected:
using FlatTable<T,IndexType>::size;
using FlatTable<T,IndexType>::index;
using FlatTable<T,IndexType>::data;
public:
public:
///
NETGEN_INLINE Table () : FlatTable<T,IndexType> (0,nullptr,nullptr) { ; }
/// Construct table of uniform entrysize
@ -159,6 +159,7 @@ public:
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);
@ -166,6 +167,7 @@ public:
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);
@ -177,6 +179,7 @@ public:
/// Delete data
NETGEN_INLINE ~Table ()
{
mt.Free(GetMemUsage());
delete [] data;
delete [] index;
}
@ -188,13 +191,23 @@ public:
NETGEN_INLINE size_t NElements() const { return index[size]; }
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>
inline ostream & operator<< (ostream & s, const Table<T,IndexType> & table)
{
{
for (auto i : table.Range())
{
s << i << ":";
@ -204,7 +217,7 @@ public:
}
s << std::flush;
return s;
}
}
@ -349,44 +362,6 @@ 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.
@ -394,33 +369,173 @@ public:
A DynamicTable contains entries of variable size. Entry sizes can
be increased dynamically.
*/
template <class T>
class DynamicTable : public BaseDynamicTable
template <class T, class IndexType = size_t>
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:
/// Creates table of size size
DynamicTable (int size = 0)
: BaseDynamicTable (size) { ; }
: data(size)
{
for (auto & d : data)
{
d.maxsize = 0;
d.size = 0;
d.col = nullptr;
}
oneblock = nullptr;
}
/// Creates table with a priori fixed entry sizes.
DynamicTable (const Array<int> & entrysizes)
: BaseDynamicTable (entrysizes, sizeof(T)) { ; }
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 (int i, const T & acont)
void Add (IndexType i, const T & acont)
{
if (data[i].size == data[i].maxsize)
IncSize (i, sizeof (T));
this->IncSize (i);
else
data[i].size++;
static_cast<T*> (data[i].col) [data[i].size-1] = acont;
data[i].col[data[i].size-1] = acont;
}
/// 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 * line = const_cast<int*> (GetLine (i));
T * line = data[i].col;
for (int j = 0; j < es; j++)
if (line[j] == cont)
return;
@ -429,43 +544,61 @@ public:
/// 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.
Does not check for overflow. */
void Set (int i, int nr, const T & acont)
{ static_cast<T*> (data[i].col)[nr] = acont; }
void Set (IndexType i, int nr, const T & acont)
{
data[i].col[nr] = acont;
}
/** Returns the nr-th element in the i-th row.
Does not check for overflow. */
const T & Get (int i, int nr) const
{ return static_cast<T*> (data[i].col)[nr]; }
const T & Get (IndexType i, int nr) const
{
return data[i].col[nr];
}
/** Returns pointer to the first element in row i. */
const T * GetLine (int i) const
{ return static_cast<T*> (data[i].col); }
const T * GetLine (IndexType i) const
{
return data[i].col;
}
/// Returns size of the table.
int Size () const
{ return data.Size(); }
size_t Size () const
{
return data.Size();
}
auto Range () const
{
return data.Range();
}
/// Returns size of the i-th row.
int EntrySize (int i) const
{ return data[i].size; }
int EntrySize (IndexType i) const
{
return data[i].size;
}
///
void DecEntrySize (int i)
{ DecSize(i); }
void DecEntrySize (IndexType i)
{
DecSize(i);
}
/// Access entry i
FlatArray<T> operator[] (int i)
{ return FlatArray<T> (data[i].size, static_cast<T*> (data[i].col)); }
FlatArray<T> operator[] (IndexType i)
{
return FlatArray<T> (data[i].size, data[i].col);
}
/*
typedef const FlatArray<T> ConstFlatArray;
@ -473,18 +606,18 @@ public:
ConstFlatArray operator[] (int i) const
{ return FlatArray<T> (data[i].size, static_cast<T*> (data[i].col)); }
*/
FlatArray<T> operator[] (int i) const
{ return FlatArray<T> (data[i].size, static_cast<T*> (data[i].col)); }
FlatArray<T> operator[] (IndexType i) const
{
return FlatArray<T> (data[i].size, data[i].col);
}
};
/// Print table
template <class T>
inline ostream & operator<< (ostream & s, const DynamicTable<T> & table)
{
for (int i = 0; i < table.Size(); i++)
for (auto i : Range(table))
{
s << i << ":";
for (int j = 0; j < table[i].Size(); j++)

View File

@ -159,29 +159,18 @@ namespace ngcore
active_workers = 0;
static int cnt = 0;
char buf[100];
if (use_paje_trace)
{
#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);
trace = new PajeTrace(num_threads, "ng" + ToString(cnt++));
}
TaskManager :: ~TaskManager ()
{
if (use_paje_trace)
{
delete trace;
trace = nullptr;
}
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;
static TClock::time_point calibrate_init_clock = TClock::now();
void TaskManager :: StopWorkers()
{
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 frequ = (delta_sec != 0) ? delta_tsc/delta_sec : 2.7e9;
@ -348,7 +337,27 @@ namespace ngcore
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;
}
if (trace)
trace->StartJob(jobnr, afunc.target_type());
func = &afunc;
@ -412,13 +421,18 @@ namespace ngcore
if (workers_on_node[j])
{
while (complete[j] != jobnr)
{
#ifdef NETGEN_ARCH_AMD64
_mm_pause();
#endif // NETGEN_ARCH_AMD64
}
}
func = nullptr;
if (ex)
throw Exception (*ex);
if (trace)
trace->StopJob();
}

View File

@ -17,6 +17,12 @@
#include "paje_trace.hpp"
#include "profiler.hpp"
#ifdef USE_NUMA
#include <numa.h>
#include <sched.h>
#endif
namespace ngcore
{
using std::atomic;
@ -1062,11 +1068,11 @@ public:
{
static Timer timer("ComputeColoring - "+Demangle(typeid(Tmask).name())); RegionTimer rt(timer);
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);
int colored_blocks = 0;
size_t colored_blocks = 0;
// We are coloring with 32 colors at once and use each bit to mask conflicts
unsigned int check = 0;

View File

@ -13,7 +13,15 @@ namespace ngcore
#ifdef WIN32
// 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
NGCORE_API std::string Demangle(const char* typeinfo)
{

View File

@ -8,13 +8,19 @@
#include <sstream>
#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
#include <intrin.h> // for __rdtsc() CPU time step counter
#else
#include <x86intrin.h> // for __rdtsc() CPU time step counter
#endif // WIN32
#include "ngcore_api.hpp" // for NGCORE_API
#endif // NETGEN_ARCH_AMD64
namespace ngcore
{
@ -23,6 +29,10 @@ namespace ngcore
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__)
inline bool likely (bool x) { return bool(__builtin_expect(long(x), 1L)); }
inline bool unlikely (bool x) { return bool(__builtin_expect(long(x), 0L)); }
@ -48,7 +58,19 @@ namespace ngcore
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>
@ -157,7 +179,9 @@ namespace ngcore
while (!m.compare_exchange_weak(should, true))
{
should = false;
#ifdef NETGEN_ARCH_AMD64
_mm_pause();
#endif // NETGEN_ARCH_AMD64
}
}
void unlock()

29
libsrc/core/version.cpp Normal file
View 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

View File

@ -80,6 +80,10 @@ namespace ngcore
return mayor_ == other.mayor_ && minor_ == other.minor_ && release == other.release
&& 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 !((*this) > other); }
bool operator >=(const VersionInfo& other) const { return !((*this) < other); }
@ -89,6 +93,10 @@ namespace ngcore
{
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
#endif // NETGEN_CORE_VERSION_HPP

View File

@ -20,18 +20,28 @@ namespace ngcore
public:
xbool (bool b) : state(b ? 2 : 0) { ; }
xbool (TMAYBE x) : state(1) { ; }
xbool (TMAYBE /* x */) : state(1) { ; }
xbool () = default;
xbool (const xbool &) = default;
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 IsMaybe () const { return state == 1; }
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
#endif // NETGEN_CORE_XBOOL_HPP

View File

@ -11,7 +11,7 @@ if(APPLE)
set_target_properties( csg PROPERTIES SUFFIX ".so")
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)
install( TARGETS csg ${NG_INSTALL_DIR})
endif(NOT WIN32)
@ -20,7 +20,7 @@ target_link_libraries(csg PUBLIC ngcore)
if(USE_GUI)
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)
target_link_libraries(csgvis PUBLIC csg visual)
if(APPLE)

View File

@ -130,6 +130,7 @@ namespace netgen
Point<3> & newp, EdgePointGeomInfo & newgi) const
{
Point<3> hnewp = p1+secpoint*(p2-p1);
//(*testout) << "hnewp " << hnewp << " s1 " << surfi1 << " s2 " << surfi2 << endl;
if (surfi1 != -1 && surfi2 != -1 && surfi1 != surfi2)
{
@ -175,9 +176,8 @@ namespace netgen
solids.DeleteAll ();
for (int i = 0; i < splinecurves2d.Size(); i++)
delete splinecurves2d[i];
splinecurves2d.DeleteAll();
splinecurves3d.DeleteAll();
/*
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);
}
void CSGeometry :: SetSplineCurve (const char * name, SplineGeometry<3> * spl)
void CSGeometry :: SetSplineCurve (const char * name, shared_ptr<SplineGeometry<3>> 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))
return splinecurves2d[name];
else
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))
return splinecurves3d[name];

View File

@ -115,9 +115,9 @@ namespace netgen
SymbolTable<Solid*> solids;
/// all 2d splinecurves
SymbolTable< SplineGeometry<2>* > splinecurves2d;
SymbolTable<shared_ptr<SplineGeometry<2>>> splinecurves2d;
/// all 3d splinecurves
SymbolTable< SplineGeometry<3>* > splinecurves3d;
SymbolTable<shared_ptr<SplineGeometry<3>>> splinecurves3d;
/// all top level objects: solids and surfaces
NgArray<TopLevelObject*> toplevelobjects;
@ -232,10 +232,10 @@ namespace netgen
const SymbolTable<Solid*> & GetSolids () const { return solids; }
void SetSplineCurve (const char * name, SplineGeometry<2> * spl);
void SetSplineCurve (const char * name, SplineGeometry<3> * spl);
const SplineGeometry<2> * GetSplineCurve2d (const string & name) const;
const SplineGeometry<3> * GetSplineCurve3d (const string & name) const;
void SetSplineCurve (const char * name, shared_ptr<SplineGeometry<2>> spl);
void SetSplineCurve (const char * name, shared_ptr<SplineGeometry<3>> spl);
shared_ptr<SplineGeometry<2>> GetSplineCurve2d (const string & name) const;
shared_ptr<SplineGeometry<3>> GetSplineCurve3d (const string & name) const;
void DoArchive(Archive& archive) override;

View File

@ -511,8 +511,8 @@ namespace netgen
break;
}
Primitive * nprim = new Extrusion(*(geom->GetSplineCurve3d(epath)),
*(geom->GetSplineCurve2d(profile)),
Primitive * nprim = new Extrusion(geom->GetSplineCurve3d(epath),
geom->GetSplineCurve2d(profile),
z_dir);
geom->AddSurfaces (nprim);
return new Solid(nprim);
@ -1186,7 +1186,7 @@ namespace netgen
ParseChar (scan, '=');
ParseChar (scan, '(');
SplineGeometry<2> * newspline = new SplineGeometry<2>;
auto newspline = make_shared<SplineGeometry<2>>();
// newspline->CSGLoad(scan);
LoadSpline (*newspline, scan);
@ -1212,7 +1212,7 @@ namespace netgen
ParseChar (scan, '=');
ParseChar (scan, '(');
SplineGeometry<3> * newspline = new SplineGeometry<3>;
auto newspline = make_shared<SplineGeometry<3>>();
// newspline->CSGLoad(scan);
LoadSpline (*newspline, scan);

View File

@ -970,7 +970,7 @@ namespace netgen
for (int i = 0; i < geometry.GetNTopLevelObjects(); i++)
{
Solid * locsol;
// Solid * locsol;
if (geometry.GetTopLevelObject(i)->GetLayer() != layer)
continue;
@ -978,7 +978,8 @@ namespace netgen
const Solid * sol = geometry.GetTopLevelObject(i)->GetSolid();
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) << "locsol: " << endl;
@ -995,7 +996,8 @@ namespace netgen
ReducePrimitiveIterator rpi(boxp);
UnReducePrimitiveIterator urpi;
((Solid*)locsol) -> IterateSolid (rpi);
// ((Solid*)locsol) -> IterateSolid (rpi);
locsol -> IterateSolid (rpi);
locsol -> CalcSurfaceInverse ();
@ -1020,7 +1022,8 @@ namespace netgen
}
}
((Solid*)locsol) -> IterateSolid (urpi);
// ((Solid*)locsol) -> IterateSolid (urpi);
locsol -> IterateSolid (urpi);
if (debug)
@ -1085,23 +1088,33 @@ namespace netgen
//int k;
double eps = 1e-8*size;
NgArray<bool> pre_ok(2);
ArrayMem<bool,2> pre_ok(2);
bool flip = false;
do
{
eps *= 0.5;
pre_ok[0] = (locsol -> VectorIn2 (hp, m, n, eps) == IS_OUTSIDE &&
locsol -> VectorIn2 (hp, m, -1. * n, eps) == IS_INSIDE);
pre_ok[1] = (locsol -> VectorIn2 (hp, -1.*m, n, eps) == IS_OUTSIDE &&
locsol -> VectorIn2 (hp, -1.*m, -1. * n, eps) == IS_INSIDE);
auto in00 = locsol -> VectorIn2 (hp, m, n, eps);
auto in01 = locsol -> VectorIn2 (hp, m, -1. * n, eps);
pre_ok[0] = in00 == IS_OUTSIDE && in01 == 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)
{
*testout << "eps = " << eps << endl;
*testout << "in,1 = " << locsol -> VectorIn2 (hp, m, n, eps) << endl;
*testout << "in,1 = " << locsol -> VectorIn2 (hp, m, -1. * n, eps) << endl;
*testout << "in,1 = " << locsol -> VectorIn2 (hp, -1.*m, n, eps) << endl;
*testout << "in,1 = " << locsol -> VectorIn2 (hp, -1.*m, -1. * n, eps) << endl;
*testout << "in,1 = " << in00 << endl;
*testout << "in,1 = " << in01 << endl;
*testout << "in,1 = " << in10 << endl;
*testout << "in,1 = " << in11 << endl;
}
}
while(pre_ok[0] && pre_ok[1] && eps > 1e-16*size);
@ -1150,10 +1163,10 @@ namespace netgen
m2 = fac * grad;
// (*testout) << "hp = " << hp << ", m = " << m << ", m2 = " << m2 << endl;
Solid * locsol2;
locsol -> TangentialSolid3 (hp, m, m2, locsol2, locsurfind2, ideps*size);
// Solid * locsol2;
auto locsol2 = locsol -> TangentialSolid3 (hp, m, m2, locsurfind2, ideps*size);
if (!locsol2) ok = 0;
delete locsol2;
// delete locsol2;
if (ok)
@ -1197,7 +1210,10 @@ namespace netgen
if (!surf)
{
if (sameasref)
bool inside = sameasref;
if(flip)
inside = !inside;
if (inside)
refedges.Elem(hi).domin = i;
else
refedges.Elem(hi).domout = i;
@ -1246,7 +1262,7 @@ namespace netgen
m *= -1;
}
}
delete locsol;
// delete locsol;
}
@ -1256,6 +1272,9 @@ namespace netgen
*testout << "inv: " << endl << refedgesinv << endl;
}
if(refedges.Size() == 0)
throw Exception("No edges found, something wrong.");
NgBitArray todelete(refedges.Size());
todelete.Clear();
@ -1764,7 +1783,7 @@ namespace netgen
int nsurf = geometry.GetNSurf();
int layer = 0;
Solid * tansol;
// Solid * tansol;
NgArray<int> tansurfind;
double size = geometry.MaxSize();
@ -1822,7 +1841,8 @@ namespace netgen
continue;
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();
@ -1852,7 +1872,7 @@ namespace netgen
// seg.invs1 = surfaces[i] -> Inverse();
// seg.invs2 = ! (surfaces[i] -> Inverse());
}
delete tansol;
// delete tansol;
}
}

View File

@ -42,6 +42,18 @@ namespace netgen
}
}
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);
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,
const Vec<3> & v,
const double eps,
@ -649,19 +669,34 @@ namespace netgen
dez -= (dez * ez) * ez;
}
void ExtrusionFace :: DefineTangentialPlane(const Point<3>& ap1,
const Point<3>& ap2)
{
Surface::DefineTangentialPlane(ap1, ap2);
tangential_plane_seg = latest_seg;
}
Extrusion :: Extrusion(const SplineGeometry<3> & path_in,
const SplineGeometry<2> & profile_in,
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) :
path(&path_in), profile(&profile_in), z_direction(z_dir)
path(path_in), profile(profile_in), z_direction(z_dir)
{
surfaceactive.SetSize(0);
surfaceids.SetSize(0);
for(int j=0; j<profile->GetNSplines(); j++)
{
ExtrusionFace * face = new ExtrusionFace(&((*profile).GetSpline(j)),
path,
ExtrusionFace * face = new ExtrusionFace(&(profile->GetSpline(j)),
path.get(),
z_direction);
faces.Append(face);
surfaceactive.Append(true);
@ -737,6 +772,16 @@ namespace netgen
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,
const Vec<3> & v,
double eps) const
@ -838,7 +883,7 @@ namespace netgen
return retval;
if(latestfacenum >= 0)
return faces[latestfacenum]->VecInFace(p,v2,0);
return faces[latestfacenum]->VecInFace(p,v2,eps);
else
return VecInSolid(p,v2,eps);
}

View File

@ -12,8 +12,10 @@ namespace netgen
const SplineSeg<2> * profile;
const SplineGeometry<3> * path;
Vec<3> glob_z_direction;
Array<double> angles;
bool deletable;
int tangential_plane_seg;
NgArray< const SplineSeg3<3> * > spline3_path;
NgArray< const LineSeg<3> * > line_path;
@ -54,7 +56,7 @@ namespace netgen
~ExtrusionFace();
virtual void DoArchive(Archive& ar)
void DoArchive(Archive& ar) override
{
Surface::DoArchive(ar);
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;
}
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;
virtual void CalcGradient (const Point<3> & point, Vec<3> & grad) const;
virtual void CalcHesse (const Point<3> & point, Mat<3> & hesse) const;
virtual double HesseNorm () const;
double CalcFunctionValue (const Point<3> & point) const override;
void CalcGradient (const Point<3> & point, Vec<3> & grad) const override;
void CalcHesse (const Point<3> & point, Mat<3> & hesse) const override;
double HesseNorm () const override;
virtual double MaxCurvature () const;
double MaxCurvature () const override;
//virtual double MaxCurvatureLoc (const Point<3> & /* c */ ,
// double /* rad */) const;
virtual void Project (Point<3> & p) const;
void Project (Point<3> & p) const override;
virtual Point<3> GetSurfacePoint () const;
virtual void Print (ostream & str) const;
Point<3> GetSurfacePoint () const override;
void Print (ostream & str) const override;
virtual void GetTriangleApproximation (TriangleApproximation & tas,
void GetTriangleApproximation (TriangleApproximation & tas,
const Box<3> & boundingbox,
double facets) const;
double facets) const override;
const SplineGeometry<3> & GetPath(void) const {return *path;}
const SplineSeg<2> & GetProfile(void) const {return *profile;}
@ -94,6 +96,9 @@ namespace netgen
int & after,
bool & intersecting ) const;
bool PointInFace (const Point<3> & p, const double eps) const;
INSOLID_TYPE VecInFace ( const Point<3> & p,
const Vec<3> & v,
const double eps ) const;
@ -111,6 +116,11 @@ namespace netgen
Vec<3> & ex, Vec<3> & ey, Vec<3> & ez,
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
{
private:
const SplineGeometry<3>* path;
const SplineGeometry<2>* profile; // closed, clockwise oriented curve
shared_ptr<SplineGeometry<3>> path;
shared_ptr<SplineGeometry<2>> profile; // closed, clockwise oriented curve
Vec<3> z_direction;
@ -128,43 +138,46 @@ namespace netgen
mutable int latestfacenum;
public:
Extrusion(const SplineGeometry<3> & path_in,
const SplineGeometry<2> & profile_in,
Extrusion(shared_ptr<SplineGeometry<3>> path_in,
shared_ptr<SplineGeometry<2>> profile_in,
const Vec<3> & z_dir);
// default constructor for archive
Extrusion() {}
~Extrusion();
virtual void DoArchive(Archive& ar)
void DoArchive(Archive& ar) override
{
Primitive::DoArchive(ar);
ar & path & profile & z_direction & faces & latestfacenum;
}
virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
virtual INSOLID_TYPE PointInSolid (const Point<3> & p,
double eps) const;
INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const override;
INSOLID_TYPE PointInSolid (const Point<3> & p,
double eps) const override;
INSOLID_TYPE PointInSolid (const Point<3> & p,
double eps,
NgArray<int> * const facenums) const;
virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
void GetTangentialSurfaceIndices (const Point<3> & p,
NgArray<int> & surfind, double eps) const override;
INSOLID_TYPE VecInSolid (const Point<3> & p,
const Vec<3> & v,
double eps) const;
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,
INSOLID_TYPE VecInSolid2 (const Point<3> & p,
const Vec<3> & v1,
const Vec<3> & v2,
double eps) const;
double eps) const override;
virtual int GetNSurfaces() const;
virtual Surface & GetSurface (int i = 0);
virtual const Surface & GetSurface (int i = 0) const;
int GetNSurfaces() const override;
Surface & GetSurface (int i = 0) override;
const Surface & GetSurface (int i = 0) const override;
virtual void Reduce (const BoxSphere<3> & box);
virtual void UnReduce ();
void Reduce (const BoxSphere<3> & box) override;
void UnReduce () override;
};
}

View File

@ -318,6 +318,10 @@ GetIdentifiedPoint (class Mesh & mesh, int pi)
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++)
{
Point<3> p = mesh.Point(i);
@ -327,7 +331,7 @@ void PeriodicIdentification :: IdentifyPoints (class Mesh & mesh)
pp = trafo(pp);
s2->Project (pp);
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);
/*

View File

@ -6,10 +6,10 @@
namespace netgen
{
Polyhedra::Face::Face (int pi1, int pi2, int pi3,
Polyhedra::Face::Face (int pi1, int pi2, int pi3,
const NgArray<Point<3> > & points,
int ainputnr)
{
{
inputnr = ainputnr;
pnums[0] = pi1;
@ -43,28 +43,28 @@ Polyhedra::Face::Face (int pi1, int pi2, int pi3,
w1(i) = inv(i,0);
w2(i) = inv(i,1);
}
}
}
Polyhedra :: Polyhedra ()
{
Polyhedra :: Polyhedra ()
{
surfaceactive.SetSize(0);
surfaceids.SetSize(0);
eps_base1 = 1e-8;
}
}
Polyhedra :: ~Polyhedra ()
{
Polyhedra :: ~Polyhedra ()
{
;
}
}
Primitive * Polyhedra :: CreateDefault ()
{
Primitive * Polyhedra :: CreateDefault ()
{
return new Polyhedra();
}
}
INSOLID_TYPE Polyhedra :: BoxInSolid (const BoxSphere<3> & box) const
{
INSOLID_TYPE Polyhedra :: BoxInSolid (const BoxSphere<3> & box) const
{
/*
for (i = 1; i <= faces.Size(); i++)
if (FaceBoxIntersection (i, box))
@ -97,101 +97,81 @@ INSOLID_TYPE Polyhedra :: BoxInSolid (const BoxSphere<3> & box) const
};
return PointInSolid (box.Center(), 1e-3 * box.Diam());
}
INSOLID_TYPE Polyhedra :: PointInSolid (const Point<3> & p,
double eps) const
{
//(*testout) << "PointInSolid p " << p << " eps " << eps << endl;
//(*testout) << "bbox " << poly_bbox << endl;
if((p(0) > poly_bbox.PMax()(0) + eps) || (p(0) < poly_bbox.PMin()(0) - eps) ||
(p(1) > poly_bbox.PMax()(1) + eps) || (p(1) < poly_bbox.PMin()(1) - eps) ||
(p(2) > poly_bbox.PMax()(2) + eps) || (p(2) < poly_bbox.PMin()(2) - eps))
{
//(*testout) << "returning IS_OUTSIDE" << endl;
return IS_OUTSIDE;
}
Vec<3> n, v1, v2;
// random (?) numbers:
n(0) = -0.424621;
n(1) = 0.15432;
n(2) = 0.89212238;
// check how many faces a ray starting in p intersects
INSOLID_TYPE Polyhedra :: PointInSolid (const Point<3> & p,
double eps) const
{
if (!poly_bbox.IsIn (p, eps))
return IS_OUTSIDE;
// random (?) direction:
Vec<3> n(-0.424621, 0.1543, 0.89212238);
int cnt = 0;
for (int i = 0; i < faces.Size(); i++)
for (auto & face : faces)
{
const Point<3> & p1 = points[faces[i].pnums[0]];
Vec<3> v0 = p - points[face.pnums[0]];
Vec<3> v0 = p - p1;
double lam3 = face.nn * v0;
double lam3 = faces[i].nn * v0;
if(fabs(lam3) < eps)
if (fabs(lam3) < eps) // point is in plance of face
{
double lam1 = (faces[i].w1 * v0);
double lam2 = (faces[i].w2 * v0);
double lam1 = face.w1 * v0;
double lam2 = face.w2 * v0;
if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1)
{
//(*testout) << "returning DOES_INTERSECT" << endl;
return DOES_INTERSECT;
}
}
else
{
lam3 = -(faces[i].n * v0) / (faces[i].n * n);
double lam3 = -(face.n * v0) / (face.n * n);
if (lam3 < 0) continue;
if (lam3 < 0) continue; // ray goes not in direction of face
Vec<3> rs = v0 + lam3 * n;
double lam1 = (faces[i].w1 * rs);
double lam2 = (faces[i].w2 * rs);
double lam1 = face.w1 * rs;
double lam2 = face.w2 * rs;
if (lam1 >= 0 && lam2 >= 0 && lam1+lam2 <= 1)
cnt++;
}
}
//(*testout) << " cnt = " << cnt%2 << endl;
return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE;
}
}
void Polyhedra :: GetTangentialSurfaceIndices (const Point<3> & p,
void Polyhedra :: GetTangentialSurfaceIndices (const Point<3> & p,
NgArray<int> & surfind, double eps) const
{
{
for (int i = 0; i < faces.Size(); i++)
{
const Point<3> & p1 = points[faces[i].pnums[0]];
auto & face = faces[i];
const Point<3> & p1 = points[face.pnums[0]];
Vec<3> v0 = p - p1;
double lam3 = -(faces[i].nn * v0); // n->nn
double lam3 = -(face.nn * v0); // n->nn
if (fabs (lam3) > eps) continue;
double lam1 = (faces[i].w1 * v0);
double lam2 = (faces[i].w2 * v0);
double lam1 = (face.w1 * v0);
double lam2 = (face.w2 * v0);
if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam1+lam2 <= 1+eps_base1)
if (!surfind.Contains (GetSurfaceId(i)))
surfind.Append (GetSurfaceId(i));
}
}
}
INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p,
INSOLID_TYPE Polyhedra :: VecInSolidOld (const Point<3> & p,
const Vec<3> & v,
double eps) const
{
{
NgArray<int> point_on_faces;
INSOLID_TYPE res(DOES_INTERSECT);
@ -250,23 +230,166 @@ INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p,
}
}
Point<3> p2 = p + (1e-2*mindist) * vn;
Point<3> p2 = p + (1e-4*mindist) * vn;
res = PointInSolid (p2, eps);
// (*testout) << "mindist " << mindist << " res " << res << endl;
return res;
}
}
// check how many faces a ray starting in p+alpha*v intersects
INSOLID_TYPE Polyhedra :: VecInSolidNew (const Point<3> & p,
const Vec<3> & v,
double eps, bool printing) const
{
if (!poly_bbox.IsIn (p, eps))
return IS_OUTSIDE;
// random (?) direction:
Vec<3> n(-0.424621, 0.1543, 0.89212238);
int cnt = 0;
for (auto & face : faces)
{
Vec<3> v0 = p - points[face.pnums[0]];
if (printing)
{
*testout << "face: ";
for (int j = 0; j < 3; j++)
*testout << points[face.pnums[j]] << " ";
*testout << endl;
}
double lamn = face.nn * v0;
if (fabs(lamn) < eps) // point is in plane of face
{
double lam1 = face.w1 * v0;
double lam2 = face.w2 * v0;
double lam3 = 1-lam1-lam2;
if (printing)
*testout << "lam = " << lam1 << " " << lam2 << " " << lam3 << endl;
if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam3 >= -eps_base1)
{ // point is close to trianlge, perturbe by alpha*v
double dlamn = face.nn*v;
if (fabs(dlamn) < 1e-8) // vec also in plane
{
if (printing)
*testout << "tang in plane" << endl;
double dlam1 = face.w1 * v;
double dlam2 = face.w2 * v;
double dlam3 = -dlam1-dlam2;
if (printing)
*testout << "dlam = " << dlam1 << " " << dlam2 << " " << dlam3 << endl;
bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1;
bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1;
bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1;
if (in1 && in2 && in3)
return DOES_INTERSECT;
}
else // vec out of plane
{
if (printing)
*testout << "out of plane";
double dlamn = -(face.n * v) / (face.n * n);
if (printing)
*testout << "dlamn = " << dlamn << endl;
if (dlamn < 0) continue; // ray goes not in direction of face
Vec<3> drs = v + dlamn * n;
if (printing)
{
*testout << "drs = " << drs << endl;
*testout << "face.w1 = " << face.w1 << endl;
*testout << "face.w2 = " << face.w2 << endl;
}
double dlam1 = face.w1 * drs;
double dlam2 = face.w2 * drs;
double dlam3 = -dlam1-dlam2;
if (printing)
*testout << "dlam = " << dlam1 << " " << dlam2 << " " << dlam3 << endl;
bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1;
bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1;
bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1;
if (in1 && in2 && in3)
{
if (printing)
*testout << "hit" << endl;
cnt++;
}
}
}
}
else
{
double lamn = -(face.n * v0) / (face.n * n);
if (lamn < 0) continue; // ray goes not in direction of face
Vec<3> rs = v0 + lamn * n;
double lam1 = face.w1 * rs;
double lam2 = face.w2 * rs;
double lam3 = 1-lam1-lam2;
if (lam1 >= 0 && lam2 >= 0 && lam3 >= 0)
{
if (printing)
*testout << "hit" << endl;
cnt++;
}
}
}
return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE;
}
/*
INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p,
INSOLID_TYPE Polyhedra :: VecInSolid (const Point<3> & p,
const Vec<3> & v,
double eps) const
{
return VecInSolidNew (p, v, eps);
/*
auto oldval = VecInSolidOld (p, v, eps);
auto newval = VecInSolidNew (p, v, eps);
if (oldval != newval)
{
*testout << "different decision: oldval = " << oldval
<< " newval = " << newval << endl;
*testout << "p = " << p << ", v = " << v << endl;
VecInSolidNew (p, v, eps, true);
*testout << "Poly:" << endl;
for (auto & face : faces)
{
for (int j = 0; j < 3; j++)
*testout << points[face.pnums[j]] << " ";
*testout << endl;
}
}
return newval;
*/
}
/*
INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p,
const Vec<3> & v1,
const Vec<3> & v2,
double eps) const
{
{
INSOLID_TYPE res;
res = VecInSolid(p,v1,eps);
@ -314,16 +437,17 @@ INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p,
cerr << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl;
return Primitive :: VecInSolid2 (p, v1, v2, eps);
}
*/
}
*/
INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p,
// #define OLDVECINSOLID2
#ifdef OLDVECINSOLID2
INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p,
const Vec<3> & v1,
const Vec<3> & v2,
double eps) const
{
{
//(*testout) << "VecInSolid2 eps " << eps << endl;
INSOLID_TYPE res = VecInSolid(p,v1,eps);
//(*testout) << "VecInSolid = " <<res <<endl;
@ -383,13 +507,169 @@ INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p,
cerr << "primitive::vecinsolid2 makes nonsense for polyhedra" << endl;
return Primitive :: VecInSolid2 (p, v1, v2, eps);
}
}
void Polyhedra :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
#else
// check how many faces a ray starting in p+alpha*v+alpha^2/2 v2 intersects:
// if p + alpha v is in plane, use v2
INSOLID_TYPE Polyhedra :: VecInSolid2 (const Point<3> & p,
const Vec<3> & v,
const Vec<3> & v2,
double eps) const
{
if (!poly_bbox.IsIn (p, eps))
return IS_OUTSIDE;
// random (?) direction:
Vec<3> n(-0.424621, 0.1543, 0.89212238);
int cnt = 0;
for (auto & face : faces)
{
Vec<3> v0 = p - points[face.pnums[0]];
double lamn = face.nn * v0;
if (fabs(lamn) < eps) // point is in plane of face
{
double lam1 = face.w1 * v0;
double lam2 = face.w2 * v0;
double lam3 = 1-lam1-lam2;
if (lam1 >= -eps_base1 && lam2 >= -eps_base1 && lam3 >= -eps_base1)
{ // point is close to trianlge, perturbe by alpha*v
double dlamn = face.nn*v;
if (fabs(dlamn) < 1e-8) // vec also in plane
{
double dlam1 = face.w1 * v;
double dlam2 = face.w2 * v;
double dlam3 = -dlam1-dlam2;
bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1;
bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1;
bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1;
// and the same thing for v2
if (in1 && in2 && in3)
{
double ddlamn = face.nn*v2;
if (fabs(ddlamn) < 1e-8) // vec2 also in plane
{
double ddlam1 = face.w1 * v2;
double ddlam2 = face.w2 * v2;
double ddlam3 = -ddlam1-ddlam2;
bool ddin1 = lam1 > eps_base1 || dlam1 > eps_base1 || ddlam1 > -eps_base1;
bool ddin2 = lam2 > eps_base1 || dlam2 > eps_base1 || ddlam2 > -eps_base1;
bool ddin3 = lam3 > eps_base1 || dlam3 > eps_base1 || ddlam3 > -eps_base1;
if (ddin1 && ddin2 && ddin3)
return DOES_INTERSECT;
}
else // vec2 out of plane
{
double ddlamn = -(face.n * v2) / (face.n * n);
if (ddlamn < 0) continue; // ray goes not in direction of face
Vec<3> drs = v; // + dlamn * n; but dlamn==0
Vec<3> ddrs = v2 + ddlamn * n;
double dlam1 = face.w1 * drs;
double dlam2 = face.w2 * drs;
double dlam3 = -dlam1-dlam2;
double ddlam1 = face.w1 * ddrs;
double ddlam2 = face.w2 * ddrs;
double ddlam3 = -ddlam1-ddlam2;
bool ddin1 = lam1 > eps_base1 || dlam1 > eps_base1 || ddlam1 > -eps_base1;
bool ddin2 = lam2 > eps_base1 || dlam2 > eps_base1 || ddlam2 > -eps_base1;
bool ddin3 = lam3 > eps_base1 || dlam3 > eps_base1 || ddlam3 > -eps_base1;
if (ddin1 && ddin2 && ddin3)
cnt++;
}
}
}
else // vec out of plane
{
double dlamn = -(face.n * v) / (face.n * n);
if (dlamn < 0) continue; // ray goes not in direction of face
Vec<3> drs = v + dlamn * n;
double dlam1 = face.w1 * drs;
double dlam2 = face.w2 * drs;
double dlam3 = -dlam1-dlam2;
bool in1 = lam1 > eps_base1 || dlam1 > -eps_base1;
bool in2 = lam2 > eps_base1 || dlam2 > -eps_base1;
bool in3 = lam3 > eps_base1 || dlam3 > -eps_base1;
if (in1 && in2 && in3)
cnt++;
}
}
}
else
{
double lamn = -(face.n * v0) / (face.n * n);
if (lamn < 0) continue; // ray goes not in direction of face
Vec<3> rs = v0 + lamn * n;
double lam1 = face.w1 * rs;
double lam2 = face.w2 * rs;
double lam3 = 1-lam1-lam2;
if (lam1 >= 0 && lam2 >= 0 && lam3 >= 0)
cnt++;
}
}
return (cnt % 2) ? IS_INSIDE : IS_OUTSIDE;
}
#endif
INSOLID_TYPE Polyhedra :: VecInSolid3 (const Point<3> & p,
const Vec<3> & v1,
const Vec<3> & v2,
double eps) const
{
return VecInSolid2 (p, v1, v2, eps);
}
INSOLID_TYPE Polyhedra :: VecInSolid4 (const Point<3> & p,
const Vec<3> & v,
const Vec<3> & v2,
const Vec<3> & m,
double eps) const
{
auto res = VecInSolid2 (p, v, v2, eps);
if (res == DOES_INTERSECT) // following edge second order, let m decide
return VecInSolid2 (p, v, m, eps);
return res;
}
void Polyhedra :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
NgArray<int> & surfind, double eps) const
{
{
Vec<3> v1n = v1;
v1n.Normalize();
Vec<3> v2n = v2; // - (v2 * v1n) * v1n;
@ -433,7 +713,7 @@ void Polyhedra :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec
surfind.Append (GetSurfaceId(faces[i].planenr));
}
}
}
}
@ -446,9 +726,9 @@ void Polyhedra :: GetTangentialVecSurfaceIndices2 (const Point<3> & p, const Vec
void Polyhedra :: GetPrimitiveData (const char *& classname,
void Polyhedra :: GetPrimitiveData (const char *& classname,
NgArray<double> & coeffs) const
{
{
classname = "Polyhedra";
coeffs.SetSize(0);
coeffs.Append (points.Size());
@ -469,31 +749,31 @@ void Polyhedra :: GetPrimitiveData (const char *& classname,
(*testout) << endl;
}
*/
}
}
void Polyhedra :: SetPrimitiveData (NgArray<double> & /* coeffs */)
{
void Polyhedra :: SetPrimitiveData (NgArray<double> & /* coeffs */)
{
;
}
}
void Polyhedra :: Reduce (const BoxSphere<3> & box)
{
void Polyhedra :: Reduce (const BoxSphere<3> & box)
{
for (int i = 0; i < planes.Size(); i++)
surfaceactive[i] = 0;
for (int i = 0; i < faces.Size(); i++)
if (FaceBoxIntersection (i, box))
surfaceactive[faces[i].planenr] = 1;
}
}
void Polyhedra :: UnReduce ()
{
void Polyhedra :: UnReduce ()
{
for (int i = 0; i < planes.Size(); i++)
surfaceactive[i] = 1;
}
}
int Polyhedra :: AddPoint (const Point<3> & p)
{
int Polyhedra :: AddPoint (const Point<3> & p)
{
if(points.Size() == 0)
poly_bbox.Set(p);
else
@ -501,10 +781,10 @@ int Polyhedra :: AddPoint (const Point<3> & p)
points.Append (p);
return points.Size();
}
}
int Polyhedra :: AddFace (int pi1, int pi2, int pi3, int inputnum)
{
int Polyhedra :: AddFace (int pi1, int pi2, int pi3, int inputnum)
{
(*testout) << "polyhedra, add face " << pi1 << ", " << pi2 << ", " << pi3 << endl;
if(pi1 == pi2 || pi2 == pi3 || pi3 == pi1)
@ -527,20 +807,20 @@ int Polyhedra :: AddFace (int pi1, int pi2, int pi3, int inputnum)
n.Normalize();
Plane pl (p1, n);
// int inverse;
// int identicto = -1;
// for (int i = 0; i < planes.Size(); i++)
// if (pl.IsIdentic (*planes[i], inverse, 1e-9*max3(v1.Length(),v2.Length(),Dist(p2,p3))))
// {
// if (!inverse)
// identicto = i;
// }
// // cout << "is identic = " << identicto << endl;
// identicto = -1; // changed April 10, JS
// int inverse;
// int identicto = -1;
// for (int i = 0; i < planes.Size(); i++)
// if (pl.IsIdentic (*planes[i], inverse, 1e-9*max3(v1.Length(),v2.Length(),Dist(p2,p3))))
// {
// if (!inverse)
// identicto = i;
// }
// // cout << "is identic = " << identicto << endl;
// identicto = -1; // changed April 10, JS
// if (identicto != -1)
// faces.Last().planenr = identicto;
// else
// if (identicto != -1)
// faces.Last().planenr = identicto;
// else
{
planes.Append (new Plane (p1, n));
surfaceactive.Append (1);
@ -548,15 +828,15 @@ int Polyhedra :: AddFace (int pi1, int pi2, int pi3, int inputnum)
faces.Last().planenr = planes.Size()-1;
}
// (*testout) << "is plane nr " << faces.Last().planenr << endl;
// (*testout) << "is plane nr " << faces.Last().planenr << endl;
return faces.Size();
}
}
int Polyhedra :: FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const
{
int Polyhedra :: FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const
{
/*
(*testout) << "check face box intersection, fnr = " << fnr << endl;
(*testout) << "box = " << box << endl;
@ -587,11 +867,11 @@ int Polyhedra :: FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const
return 1;
}
return 0;
}
}
void Polyhedra :: GetPolySurfs(NgArray < NgArray<int> * > & polysurfs)
{
void Polyhedra :: GetPolySurfs(NgArray < NgArray<int> * > & polysurfs)
{
int maxnum = -1;
for(int i = 0; i<faces.Size(); i++)
@ -606,24 +886,24 @@ void Polyhedra :: GetPolySurfs(NgArray < NgArray<int> * > & polysurfs)
for(int i = 0; i<faces.Size(); i++)
polysurfs[faces[i].inputnr]->Append(faces[i].planenr);
}
}
void Polyhedra::CalcSpecialPoints (NgArray<Point<3> > & pts) const
{
void Polyhedra::CalcSpecialPoints (NgArray<Point<3> > & pts) const
{
for (int i = 0; i < points.Size(); i++)
pts.Append (points[i]);
}
}
void Polyhedra :: AnalyzeSpecialPoint (const Point<3> & /* pt */,
void Polyhedra :: AnalyzeSpecialPoint (const Point<3> & /* pt */,
NgArray<Point<3> > & /* specpts */) const
{
{
;
}
}
Vec<3> Polyhedra :: SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const
{
Vec<3> Polyhedra :: SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const
{
const double eps = 1e-10*poly_bbox.Diam();
for (int fi1 = 0; fi1 < faces.Size(); fi1++)
@ -731,7 +1011,7 @@ Vec<3> Polyhedra :: SpecialPointTangentialVector (const Point<3> & p, int s1, in
}
return Vec<3> (0,0,0);
}
}
}

View File

@ -48,46 +48,63 @@ namespace netgen
public:
Polyhedra ();
virtual ~Polyhedra ();
virtual ~Polyhedra () override;
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,
double eps) const;
virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
double eps) const override;
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,
double eps) const;
// checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid
virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
const Vec<3> & v,
double eps) const override;
virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p,
const Vec<3> & v1,
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,
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,
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,
NgArray<Point<3> > & specpts) const;
virtual Vec<3> SpecialPointTangentialVector (const Point<3> & p, int s1, int s2) const;
NgArray<Point<3> > & specpts) const override;
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(); }
virtual Surface & GetSurface (int i)
virtual Surface & GetSurface (int i) override
{ return *planes[i]; }
virtual const Surface & GetSurface (int i) const
virtual const Surface & GetSurface (int i) const override
{ return *planes[i]; }
virtual void GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const;
virtual void SetPrimitiveData (NgArray<double> & coeffs);
virtual void GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const override;
virtual void SetPrimitiveData (NgArray<double> & coeffs) override;
virtual void Reduce (const BoxSphere<3> & box);
virtual void UnReduce ();
virtual void Reduce (const BoxSphere<3> & box) override;
virtual void UnReduce () override;
int AddPoint (const Point<3> & p);
int AddFace (int pi1, int pi2, int pi3, int inputnum);

View File

@ -170,7 +170,8 @@ namespace netgen
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 ("AddPoint", FunctionPointer
([] (SplineGeometry<2> & self, double x, double y)
@ -329,14 +330,31 @@ DLL_HEADER void ExportCSG(py::module &m)
Solid * sol = new Solid(rev);
return make_shared<SPSolid> (sol);
}));
m.def ("Extrusion", FunctionPointer([](const SplineGeometry<3> & path,
const SplineGeometry<2> & profile,
Vec<3> n)
m.def ("Extrusion", [](shared_ptr<SplineGeometry<3>> path,
shared_ptr<SplineGeometry<2>> profile,
Vec<3> d)
{
Extrusion * extr = new Extrusion (path,profile,n);
Extrusion * extr = new Extrusion (path,profile,d);
Solid * sol = new Solid(extr);
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,
double h, double r)
{
@ -355,6 +373,35 @@ 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!
)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)
{
return make_shared<SPSolid> (SPSolid::UNION, s1, s2);

View File

@ -670,6 +670,23 @@ namespace netgen
surfaceactive.Append(1);
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()
@ -764,8 +781,9 @@ namespace netgen
int intersections_before(0), intersections_after(0);
double randomx = 7.42357;
double randomy = 1.814756;
randomx *= 1./sqrt(randomx*randomx+randomy*randomy);
randomy *= 1./sqrt(randomx*randomx+randomy*randomy);
double randomlen = sqrt(randomx*randomx+randomy*randomy);
randomx *= 1./randomlen;
randomy *= 1./randomlen;
const double a = randomy;
@ -931,6 +949,67 @@ namespace netgen
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
{
return faces.Size();

View File

@ -68,6 +68,9 @@ namespace netgen
//virtual double MaxCurvatureLoc (const Point<3> & /* c */ ,
// double /* rad */) const;
Point<3> P0() const { return p0; }
Vec<3> Axis() const { return v_axis; }
virtual void Project (Point<3> & p) const;
virtual Point<3> GetSurfacePoint () const;
@ -155,6 +158,9 @@ namespace netgen
const Vec<3> & v2,
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 Surface & GetSurface (int i = 0);

View File

@ -168,7 +168,7 @@ void SingularPoint :: FindPoints (class Mesh & mesh)
for (int k = 1; k <= 3; k++)
{
const Solid * solk(NULL);
Solid *tansol;
// Solid *tansol;
switch (k)
{
case 1: solk = sol1; break;
@ -176,7 +176,7 @@ void SingularPoint :: FindPoints (class Mesh & mesh)
case 3: solk = sol3; break;
}
solk -> TangentialSolid (p, tansol, surfk, 1e-3);
auto tansol = solk -> TangentialSolid (p, surfk, 1e-3);
(*testout) << "Tansol = " << *tansol << endl;
if (!tansol) continue;
@ -195,7 +195,7 @@ void SingularPoint :: FindPoints (class Mesh & mesh)
if (!surf.Contains (surfk[i]))
surf.Append (surfk[i]);
delete tansol;
// delete tansol;
}
if (surf.Size() < 3) continue;

View File

@ -6,21 +6,6 @@
namespace netgen
{
//using namespace netgen;
/*
SolidIterator :: SolidIterator ()
{
;
}
SolidIterator :: ~SolidIterator ()
{
;
}
*/
// 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
{
return PointInSolid (p,eps) != IS_OUTSIDE;
/*
switch (op)
{
case TERM: case TERM_REF:
@ -213,10 +259,13 @@ namespace netgen
return s1->IsIn (p, eps);
}
return 0;
*/
}
bool Solid :: IsStrictIn (const Point<3> & p, double eps) const
{
return PointInSolid (p,eps) == IS_INSIDE;
/*
switch (op)
{
case TERM: case TERM_REF:
@ -234,11 +283,14 @@ namespace netgen
return s1->IsStrictIn (p, eps);
}
return 0;
*/
}
bool Solid :: VectorIn (const Point<3> & p, const Vec<3> & v,
double eps) const
{
return VecInSolid (p,v,eps) != IS_OUTSIDE;
/*
Vec<3> hv;
switch (op)
{
@ -257,11 +309,14 @@ namespace netgen
return s1->VectorIn(p, v, eps);
}
return 0;
*/
}
bool Solid :: VectorStrictIn (const Point<3> & p, const Vec<3> & v,
double eps) const
{
return VecInSolid (p,v,eps) == IS_INSIDE;
/*
Vec<3> hv;
switch (op)
{
@ -282,9 +337,11 @@ namespace netgen
return s1->VectorStrictIn(p, v, eps);
}
return 0;
*/
}
/*
bool Solid::VectorIn2 (const Point<3> & p, const Vec<3> & v1,
const Vec<3> & v2, double eps) const
{
@ -317,10 +374,57 @@ namespace netgen
}
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
@ -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);
surfids.SetSize (0);
if (tansol)
tansol -> GetTangentialSurfaceIndices (p, surfids, eps);
return unique_ptr<Solid> (tansol);
}
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;
@ -671,7 +777,7 @@ namespace netgen
}
case SECTION:
{
int in1, in2, strin1, strin2;
bool in1, in2, strin1, strin2;
Solid * tansol1, * tansol2;
s1 -> RecTangentialSolid (p, tansol1, surfids, in1, strin1, eps);
@ -686,13 +792,13 @@ namespace netgen
else if (tansol2)
tansol = tansol2;
}
in = (in1 && in2);
strin = (strin1 && strin2);
in = in1 && in2;
strin = strin1 && strin2;
break;
}
case UNION:
{
int in1, in2, strin1, strin2;
bool in1, in2, strin1, strin2;
Solid * tansol1 = 0, * tansol2 = 0;
s1 -> RecTangentialSolid (p, tansol1, surfids, in1, strin1, eps);
@ -712,13 +818,13 @@ namespace netgen
delete tansol1;
delete tansol2;
}
in = (in1 || in2);
strin = (strin1 || strin2);
in = in1 || in2;
strin = strin1 || strin2;
break;
}
case SUB:
{
int hin, hstrin;
bool hin, hstrin;
Solid * tansol1;
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,
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);
RecTangentialSolid2 (p, t, tansol, surfids, in, strin, eps);
if (tansol)
tansol -> GetTangentialSurfaceIndices2 (p, t, surfids, eps);
return unique_ptr<Solid> (tansol);
}
void Solid :: RecTangentialSolid2 (const Point<3> & p, const Vec<3> & t,
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)
{
@ -774,8 +882,8 @@ namespace netgen
if (ist == DOES_INTERSECT)
ist = prim->VecInSolid (p, t, eps);
in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
strin = (ist == IS_INSIDE);
in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT);
strin = ist == IS_INSIDE;
if (ist == DOES_INTERSECT)
{
@ -786,7 +894,7 @@ namespace netgen
}
case SECTION:
{
int in1, in2, strin1, strin2;
bool in1, in2, strin1, strin2;
Solid * tansol1, * tansol2;
s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, in1, strin1, eps);
@ -801,13 +909,13 @@ namespace netgen
else if (tansol2)
tansol = tansol2;
}
in = (in1 && in2);
strin = (strin1 && strin2);
in = in1 && in2;
strin = strin1 && strin2;
break;
}
case UNION:
{
int in1, in2, strin1, strin2;
bool in1, in2, strin1, strin2;
Solid * tansol1, * tansol2;
s1 -> RecTangentialSolid2 (p, t, tansol1, surfids, in1, strin1, eps);
@ -822,13 +930,13 @@ namespace netgen
else if (tansol2)
tansol = tansol2;
}
in = (in1 || in2);
strin = (strin1 || strin2);
in = in1 || in2;
strin = strin1 || strin2;
break;
}
case SUB:
{
int hin, hstrin;
bool hin, hstrin;
Solid * tansol1;
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,
Solid *& tansol, NgArray<int> & surfids,
NgArray<int> & surfids,
double eps) const
{
int in, strin;
bool in, strin;
Solid * tansol = nullptr;
surfids.SetSize (0);
RecTangentialSolid3 (p, t, t2, tansol, surfids, in, strin, eps);
if (tansol)
tansol -> GetTangentialSurfaceIndices3 (p, t, t2, surfids, eps);
return unique_ptr<Solid>(tansol);
}
void Solid :: RecTangentialSolid3 (const Point<3> & p,
const Vec<3> & t, const Vec<3> & t2,
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)
{
@ -882,8 +993,8 @@ namespace netgen
if (ist == DOES_INTERSECT)
ist = prim->VecInSolid3 (p, t, t2, eps);
in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
strin = (ist == IS_INSIDE);
in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT);
strin = ist == IS_INSIDE;
if (ist == DOES_INTERSECT)
{
@ -894,7 +1005,7 @@ namespace netgen
}
case SECTION:
{
int in1, in2, strin1, strin2;
bool in1, in2, strin1, strin2;
Solid * tansol1, * tansol2;
s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, in1, strin1, eps);
@ -909,13 +1020,13 @@ namespace netgen
else if (tansol2)
tansol = tansol2;
}
in = (in1 && in2);
strin = (strin1 && strin2);
in = in1 && in2;
strin = strin1 && strin2;
break;
}
case UNION:
{
int in1, in2, strin1, strin2;
bool in1, in2, strin1, strin2;
Solid * tansol1, * tansol2;
s1 -> RecTangentialSolid3 (p, t, t2, tansol1, surfids, in1, strin1, eps);
@ -930,13 +1041,13 @@ namespace netgen
else if (tansol2)
tansol = tansol2;
}
in = (in1 || in2);
strin = (strin1 || strin2);
in = in1 || in2;
strin = strin1 || strin2;
break;
}
case SUB:
{
int hin, hstrin;
bool hin, hstrin;
Solid * tansol1;
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,
Solid *& tansol, NgArray<int> & surfids,
NgArray<int> & surfids,
double eps) const
{
int in, strin;
Solid * tansol = nullptr;
bool in, strin;
surfids.SetSize (0);
// *testout << "tangentialedgesolid,sol = " << (*this) << endl;
@ -978,12 +1090,14 @@ namespace netgen
if (tansol)
tansol -> RecGetTangentialEdgeSurfaceIndices (p, t, t2, m, surfids, eps);
return unique_ptr<Solid> (tansol);
}
void Solid :: RecTangentialEdgeSolid (const Point<3> & p,
const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m,
Solid *& tansol, NgArray<int> & surfids,
int & in, int & strin, double eps) const
bool & in, bool & strin, double eps) const
{
tansol = NULL;
@ -1005,8 +1119,8 @@ namespace netgen
// (*testout) << "ist2 = " << ist << endl;
in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
strin = (ist == IS_INSIDE);
in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT);
strin = ist == IS_INSIDE;
if (ist == DOES_INTERSECT)
{
@ -1017,7 +1131,7 @@ namespace netgen
}
case SECTION:
{
int in1, in2, strin1, strin2;
bool in1, in2, strin1, strin2;
Solid * tansol1, * tansol2;
s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, in1, strin1, eps);
@ -1032,13 +1146,13 @@ namespace netgen
else if (tansol2)
tansol = tansol2;
}
in = (in1 && in2);
strin = (strin1 && strin2);
in = in1 && in2;
strin = strin1 && strin2;
break;
}
case UNION:
{
int in1, in2, strin1, strin2;
bool in1, in2, strin1, strin2;
Solid * tansol1, * tansol2;
s1 -> RecTangentialEdgeSolid (p, t, t2, m, tansol1, surfids, in1, strin1, eps);
@ -1053,13 +1167,13 @@ namespace netgen
else if (tansol2)
tansol = tansol2;
}
in = (in1 || in2);
strin = (strin1 || strin2);
in = in1 || in2;
strin = strin1 || strin2;
break;
}
case SUB:
{
int hin, hstrin;
bool hin, hstrin;
Solid * tansol1;
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 in, strin, faces;
bool in, strin;
int faces;
RecEdge (p, v, in, strin, faces, eps);
return faces >= 2;
}
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);
return faces >= 1;
}
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)
{
case TERM: case TERM_REF:
{
INSOLID_TYPE ist = prim->VecInSolid (p, v, eps);
in = (ist == IS_INSIDE || ist == DOES_INTERSECT);
strin = (ist == IS_INSIDE);
in = (ist == IS_INSIDE) || (ist == DOES_INTERSECT);
strin = ist == IS_INSIDE;
/*
in = VectorIn (p, v);
strin = VectorStrictIn (p, v);
@ -1143,7 +1259,8 @@ namespace netgen
}
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);
s2 -> RecEdge (p, v, in2, strin2, faces2, eps);
@ -1157,7 +1274,8 @@ namespace netgen
}
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);
s2 -> RecEdge (p, v, in2, strin2, faces2, eps);
@ -1171,7 +1289,7 @@ namespace netgen
}
case SUB:
{
int in1, strin1;
bool in1, strin1;
s1 -> RecEdge (p, v, in1, strin1, faces, eps);
in = !strin1;
strin = !in1;

View File

@ -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
{
@ -102,6 +122,14 @@ namespace netgen
// 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 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;
@ -109,21 +137,24 @@ namespace netgen
bool VectorIn2 (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
double eps) const;
/*
bool VectorIn2Rec (const Point<3> & p, const Vec<3> & v1, const Vec<3> & v2,
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
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
void TangentialSolid2 (const Point<3> & p, const Vec<3> & t,
Solid *& tansol, NgArray<int> & surfids, double eps) const;
unique_ptr<Solid> TangentialSolid2 (const Point<3> & p, const Vec<3> & t,
NgArray<int> & surfids, double eps) const;
/** compute localization in point p, with second order approximation to edge
p + s t + s*s/2 t2 **/
void TangentialSolid3 (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2,
Solid *& tansol, NgArray<int> & surfids, double eps) const;
unique_ptr<Solid> TangentialSolid3 (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2,
NgArray<int> & surfids, double eps) const;
@ -133,9 +164,9 @@ namespace netgen
p + s t + s*s/2 t2 + r m
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,
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;
@ -180,24 +211,24 @@ namespace netgen
int & in, int & strin) const;
///
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,
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,
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,
const Vec<3> & m,
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,
int & in, int & strin, int & faces, double eps) const;
bool & in, bool & strin, int & faces, double eps) const;
///
void CalcSurfaceInverseRec (int inv);
///

View File

@ -286,35 +286,29 @@ namespace netgen
dynamic_cast<const Plane*> (geometry->GetSurface(locsurf[k3])),
pts);
for (int j = 0; j < pts.Size(); j++)
if (Dist (pts[j], box.Center()) < box.Diam()/2)
for (auto pnt : pts)
if (Dist (pnt, box.Center()) < box.Diam()/2)
{
auto tansol = sol -> TangentialSolid (pnt, surfids, 1e-9*size);
if (tansol)
{
Solid * tansol;
sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
if(!tansol)
continue;
bool ok1 = false, ok2 = false, ok3 = false;
int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
int rep3 = geometry->GetSurfaceClassRepresentant(locsurf[k3]);
for(int jj=0; jj<surfids.Size(); jj++)
for (auto surfid : surfids)
{
int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
if(actrep == rep1) ok1 = true;
if(actrep == rep2) ok2 = true;
if(actrep == rep3) ok3 = true;
int actrep = geometry->GetSurfaceClassRepresentant(surfid);
if (actrep == rep1) ok1 = true;
if (actrep == rep2) ok2 = true;
if (actrep == rep3) ok3 = true;
}
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;
if (ok1 && ok2 && ok3)
if (AddPoint (pnt, layer))
(*testout) << "cross point found, 1: " << pnt << endl;
}
delete tansol;
}
}
@ -330,38 +324,29 @@ namespace netgen
qsurf, pts);
//(*testout) << "checking pot. crosspoints: " << pts << endl;
for (int j = 0; j < pts.Size(); j++)
if (Dist (pts[j], box.Center()) < box.Diam()/2)
for (auto pnt : pts)
if (Dist (pnt, box.Center()) < box.Diam()/2)
{
auto tansol = sol -> TangentialSolid (pnt, surfids, 1e-9*size);
if (tansol)
{
Solid * tansol;
sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
if(!tansol)
continue;
bool ok1 = false, ok2 = false, ok3 = true;//false;
int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
//int rep3 = geometry->GetSurfaceClassRepresentant(quadi);
for(int jj=0; jj<surfids.Size(); jj++)
for (auto surfid : surfids)
{
int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
if(actrep == rep1) ok1 = true;
if(actrep == rep2) ok2 = true;
//if(actrep == rep3) ok3 = true;
int actrep = geometry->GetSurfaceClassRepresentant(surfid);
if (actrep == rep1) ok1 = true;
if (actrep == rep2) ok2 = true;
}
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;
if (ok1 && ok2 && ok3)
if (AddPoint (pnt, layer))
(*testout) << "cross point found, 2: " << pnt << endl;
}
}
}
for (int k1 = 0; k1 < numprim; k1++)
if (k1 != quadi)
@ -372,16 +357,11 @@ namespace netgen
for (int j = 0; j < pts.Size(); j++)
if (Dist (pts[j], box.Center()) < box.Diam()/2)
{
Solid * tansol;
sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size);
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;
}
delete tansol;
}
}
}
@ -395,8 +375,6 @@ namespace netgen
NgArray<Point<3> > pts;
NgArray<int> surfids;
for (int k1 = 0; k1 < numprim; k1++)
for (int k2 = 0; k2 < k1; k2++)
for (int k3 = 0; k3 < k2; k3++)
@ -409,16 +387,14 @@ namespace netgen
for (int j = 0; j < pts.Size(); j++)
if (Dist (pts[j], box.Center()) < box.Diam()/2)
{
Solid * tansol;
sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
if(!tansol)
continue;
auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size);
if (!tansol) continue;
bool ok1 = false, ok2 = false, ok3 = false;
int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
int rep3 = geometry->GetSurfaceClassRepresentant(locsurf[k3]);
for(int jj=0; jj<surfids.Size(); jj++)
{
int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
@ -427,15 +403,10 @@ namespace netgen
if(actrep == rep3) ok3 = true;
}
if (tansol && ok1 && ok2 && ok3)
// if (sol -> IsIn (pts[j], 1e-6*size) && !sol->IsStrictIn (pts[j], 1e-6*size))
{
if (ok1 && ok2 && ok3)
if (AddPoint (pts[j], layer))
(*testout) << "cross point found, 1: " << pts[j] << endl;
}
delete tansol;
}
}
@ -449,21 +420,35 @@ namespace netgen
for (int j = 0; j < pts.Size(); j++)
if (Dist (pts[j], box.Center()) < box.Diam()/2)
{
Solid * tansol;
sol -> TangentialSolid (pts[j], tansol, surfids, 1e-9*size);
auto tansol = sol -> TangentialSolid (pts[j], surfids, 1e-9*size);
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;
}
delete tansol;
}
}
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)
@ -494,7 +479,6 @@ namespace netgen
(*testout) << "k1,2,3 = " << k1 << "," << k2 << "," << k3 << ", nc = " << nc << ", deg = " << deg << endl;
#endif
if (!nc && !deg) decision = 0;
if (nc) surecrossp = 1;
}
@ -608,9 +592,9 @@ namespace netgen
decision = 0;
}
}
// (*testout) << "l = " << level << " dec/sureexp = " << decision << sureexp << endl;
#ifdef DEVELOP
(*testout) << "edgepnt decision = " << decision << " sure = " << sureexp << endl;
#endif
if (decision && sureexp)
{
for (int k1 = 0; k1 < locsurf.Size() - 1; k1++)
@ -890,8 +874,17 @@ namespace netgen
f1->CalcGradient (p, g1);
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;
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++)
{
@ -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;
Solid * locsol;
sol -> TangentialSolid (p, locsol, surfind, ideps*geomsize);
auto locsol = sol -> TangentialSolid (p, surfind, ideps*geomsize);
rep_surfind.SetSize (surfind.Size());
int num_indep_surfs = 0;
@ -1769,10 +1814,10 @@ namespace netgen
if (surf)
{
// locsol -> GetSurfaceIndices (surfind);
bool hassurf = 0;
bool hassurf = false;
for (int m = 0; m < surfind.Size(); m++)
if (ageometry.GetSurface(surfind[m]) == surf)
hassurf = 1;
hassurf = true;
if (!hassurf)
continue;
@ -1818,8 +1863,11 @@ namespace netgen
}
if (Abs2 (t) < 1e-8)
if (Abs2 (t) < 1e-16)
{
// cerr << "normal vectors degenerated" << endl;
continue;
}
#ifdef DEVELOP
*testout << " tangential vector " << t << endl;
@ -1862,15 +1910,15 @@ namespace netgen
CalcInverse (mat, inv);
t2 = inv * rhs;
#ifdef DEVELOP
*testout << "t = " << t << ", t2 = " << t2 << endl;
#endif
/*
ageometry.GetIndependentSurfaceIndices
(locsol, p, t, surfind2);
*/
Solid * locsol2;
locsol -> TangentialSolid3 (p, t, t2, locsol2, surfind2, ideps*geomsize);
auto locsol2 = locsol -> TangentialSolid3 (p, t, t2, surfind2, ideps*geomsize);
if (!locsol2) continue;
// locsol2 -> GetTangentialSurfaceIndices3 (p, t, t2, surfind2, 1e-9*geomsize);
@ -1911,31 +1959,31 @@ namespace netgen
Vec<3> nv =
ageometry.GetSurface(surfind2[l]) -> GetNormalVector(p);
Vec<3> m1 = Cross (t, nv);
Vec<3> m2 = -m1;
bool isface1 = 0, isface2 = 0;
Solid * locsol3;
// 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);
if (surfind3.Contains(surfind2[l]))
isface1 = 1;
delete locsol3;
// 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);
if (surfind3.Contains(surfind2[l]))
isface2 = 1;
delete locsol3;
if (isface1 != isface2)
cnt_tang_faces++;
@ -1948,7 +1996,6 @@ namespace netgen
if (cnt_tang_faces < 1)
ok = false;
delete locsol2;
if (!ok) continue;
}
@ -1973,16 +2020,47 @@ namespace netgen
continue;
Vec<3> s = Cross (normalvecs[m], t);
Vec<3> t2a = t + 0.01 *s;
Vec<3> t2b = t - 0.01 *s;
bool isface =
bool isfaceold =
(locsol->VectorIn (p, t2a, 1e-6*geomsize) &&
!locsol->VectorStrictIn (p, t2a, 1e-6*geomsize))
||
(locsol->VectorIn (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 =
(locsol->VectorIn (p, t2a) &&
@ -1993,10 +2071,8 @@ namespace netgen
*/
if (isface)
{
cnts++;
}
}
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,
// it must be unconditional everywhere:
NgBitArray uncond (apoints.Size());
BitArray uncond (apoints.Size());
uncond.Clear();
for (int i = 0; i < specpoints.Size(); i++)
if (specpoints[i].unconditional)
uncond.Set (specpoint2point[i]);
uncond.SetBit (specpoint2point[i]);
for (int i = 0; i < specpoints.Size(); i++)
specpoints[i].unconditional =
uncond.Test (specpoint2point[i]) ? 1 : 0;
specpoints[i].unconditional = uncond.Test (specpoint2point[i]);
}
}

View File

@ -167,6 +167,9 @@ namespace netgen
const Sphere * sphere2,
NgArray<Point<3> > & pts);
bool ComputeExtremalPoints (const RevolutionFace * rev1,
const RevolutionFace * rev2,
NgArray<Point<3> > & pts);
void ComputeCrossPoints (const Plane * plane1,
const Plane * plane2,

View File

@ -16,6 +16,7 @@ Surface :: Surface ()
strcpy (name, "noname");
bcprop = -1;
bcname = "default";
inverse = false;
}
Surface :: ~Surface()
@ -427,11 +428,20 @@ VecInSolid2 (const Point<3> & p,
if (hv1 >= eps)
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;
if (hv2 <= 0)
return IS_INSIDE;
else
return IS_OUTSIDE;
*/
}

View File

@ -213,8 +213,6 @@ namespace netgen
INSOLID_TYPE;
class DummySurface : public Surface
{
virtual double CalcFunctionValue (const Point<3> & /* point */) const
@ -293,9 +291,13 @@ namespace netgen
const Vec<3> & m,
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,
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,
NgArray<int> & surfind, double eps) const;

View File

@ -11,7 +11,7 @@ target_sources(gen INTERFACE
install(FILES
ngarray.hpp autodiff.hpp autoptr.hpp ngbitarray.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
spbita2d.hpp stack.hpp table.hpp template.hpp
gzstream.h

View File

@ -14,65 +14,8 @@
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 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
template <class T>
inline MPI_Datatype MyGetMPIType ( )
@ -93,32 +36,37 @@ namespace netgen
typedef int MPI_Datatype;
template <class T> inline MPI_Datatype MyGetMPIType ( ) { return 0; }
#endif
#endif
#ifdef PARALLEL
enum { MPI_TAG_CMD = 110 };
enum { MPI_TAG_MESH = 210 };
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;
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_Recv( &i, 1, MPI_INT, src, tag, comm, &status);
}
inline void MyMPI_Send (const string & s, int dest, int tag, MPI_Comm comm /* = ng_comm */)
[[deprecated("mympi_send string, use comm.Send instead")]]
inline void MyMPI_Send (const string & s, int dest, int tag, MPI_Comm 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;
int len;
@ -130,34 +78,35 @@ namespace netgen
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>
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_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>
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;
int len;
MPI_Probe (src, tag, comm, &status);
MPI_Get_count (&status, MyGetMPIType<T>(), &len);
MPI_Get_count (&status, GetMPIType<T>(), &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>
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;
int len;
@ -165,10 +114,10 @@ namespace netgen
int src = status.MPI_SOURCE;
MPI_Get_count (&status, MyGetMPIType<T>(), &len);
MPI_Get_count (&status, GetMPIType<T>(), &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;
}
@ -190,19 +139,20 @@ namespace netgen
*/
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_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;
}
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_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;
}
@ -232,106 +182,59 @@ namespace netgen
receive-table entries will be set
*/
/*
template <typename T>
inline void MyMPI_ExchangeTable (TABLE<T> & send_data,
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 ntasks = comm.Size();
NgArray<int> send_sizes(ntasks);
NgArray<int> recv_sizes(ntasks);
Array<int> send_sizes(ntasks);
Array<int> recv_sizes(ntasks);
for (int i = 0; i < ntasks; i++)
send_sizes[i] = send_data[i].Size();
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);
comm.AllToAll (send_sizes, recv_sizes);
for (int i = 0; i < ntasks; i++)
recv_data.SetEntrySize (i, recv_sizes[i], sizeof(T));
NgArray<MPI_Request> requests;
Array<MPI_Request> requests;
for (int dest = 0; dest < ntasks; dest++)
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++)
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);
MPI_Waitall (requests.Size(), &requests[0], MPI_STATUS_IGNORE);
MyMPI_WaitAll (requests);
}
extern void MyMPI_SendCmd (const char * cmd);
extern string MyMPI_RecvCmd ();
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>
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();
MyMPI_Bcast (size, comm);
// if (MyMPI_GetId(comm) != 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>
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;
MPI_Comm_rank(comm, &id);
@ -340,67 +243,23 @@ namespace netgen
MPI_Bcast (&size, 1, MPI_INT, root, comm);
if (id != root) s.SetSize (size);
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>
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>
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

View File

@ -47,7 +47,5 @@ namespace netgen
#include "netgenout.hpp"
#include "gzstream.h"
#include "ngsimd.hpp"
#endif

View File

@ -205,6 +205,12 @@ namespace netgen
{
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
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 j = i+1; j < data.Size(); j++)
@ -740,16 +746,16 @@ namespace netgen
data[i] = data[j];
data[j] = hv;
S hvs = slave[i];
slave[i] = slave[j];
slave[j] = hvs;
S hvs = index[i];
index[i] = index[j];
index[j] = hvs;
}
}
template <class T, class S>
void QuickSortRec (NgFlatArray<T> & data,
NgFlatArray<S> & slave,
NgFlatArray<S> & index,
int left, int right)
{
int i = left;
@ -764,20 +770,20 @@ namespace netgen
if (i <= j)
{
ngcore::Swap (data[i], data[j]);
ngcore::Swap (slave[i], slave[j]);
ngcore::Swap (index[i], index[j]);
i++; j--;
}
}
while (i <= j);
if (left < j) QuickSortRec (data, slave, left, j);
if (i < right) QuickSortRec (data, slave, i, right);
if (left < j) QuickSortRec (data, index, left, j);
if (i < right) QuickSortRec (data, index, i, right);
}
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)
QuickSortRec (data, slave, 0, data.Size()-1);
QuickSortRec (data, index, 0, data.Size()-1);
}

View File

@ -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

View File

@ -26,39 +26,13 @@ private:
mutex block_allocator_mutex;
public:
///
BlockAllocator (unsigned asize, unsigned ablocks = 100);
DLL_HEADER BlockAllocator (unsigned asize, unsigned ablocks = 100);
///
~BlockAllocator ();
DLL_HEADER ~BlockAllocator ();
///
void * Alloc ();
/*
{
if (!freelist)
Alloc2();
void * p = freelist;
// freelist = *(void**)freelist;
freelist = *static_cast<void**> (freelist);
return p;
}
*/
DLL_HEADER void * Alloc ();
///
void Free (void * p);
/*
{
if (!bablocks.Size()) return;
*(void**)p = freelist;
freelist = p;
}
*/
private:
// void Alloc2 ();
DLL_HEADER void Free (void * p);
};
}

View File

@ -96,8 +96,8 @@ void ParallelFor( int first, int next, const TFunc & f )
typedef void (*TaskManager)(std::function<void(int,int)>);
typedef void (*Tracer)(string, bool); // false .. start, true .. stop
typedef void (*NgTaskManager)(std::function<void(int,int)>);
typedef void (*NgTracer)(string, bool); // false .. start, true .. stop
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) { ; }
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)
{
@ -121,7 +121,7 @@ void ParallelFor( int first, int next, const TFunc & f )
}
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)
{

View File

@ -114,12 +114,23 @@ public:
/// Creates table of size size
inline TABLE (int size) : BASE_TABLE (size) { ; }
TABLE (TABLE && tab2)
: BASE_TABLE(move(tab2))
{ }
/// Creates fixed maximal element size table
inline TABLE (const NgFlatArray<int,BASE> & entrysizes)
: BASE_TABLE (NgFlatArray<int> (entrysizes.Size(), const_cast<int*>(&entrysizes[BASE])),
sizeof(T))
{ ; }
TABLE & operator= (TABLE && tab2)
{
BASE_TABLE::operator=(move(tab2));
return *this;
}
/// Changes Size of table to size, deletes data
inline void SetSize (int size)
{

View File

@ -14,6 +14,8 @@ namespace netgen
templates, global types, defines and variables
*/
DLL_HEADER extern const string netgen_version;
/// The following value may be adapted to the hardware !
#ifndef CLOCKS_PER_SEC
#define CLOCKS_PER_SEC 1000000

View File

@ -1,10 +1,10 @@
add_definitions(-DNGLIB_EXPORTS)
add_library(geom2d ${NG_LIB_TYPE} genmesh2d.cpp geometry2d.cpp python_geom2d.cpp )
add_definitions(-DNGINTERFACE_EXPORTS)
add_library(geom2d ${NG_LIB_TYPE} csg2d.cpp genmesh2d.cpp geometry2d.cpp python_geom2d.cpp )
if(APPLE)
set_target_properties( geom2d PROPERTIES SUFFIX ".so")
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)
install( TARGETS geom2d ${NG_INSTALL_DIR})
endif(NOT WIN32)
@ -20,6 +20,6 @@ endif(USE_GUI)
install(FILES
geometry2d.hpp spline2d.hpp
vsgeom2d.hpp
vsgeom2d.hpp csg2d.hpp
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/geom2d COMPONENT netgen_devel
)

2235
libsrc/geom2d/csg2d.cpp Normal file

File diff suppressed because it is too large Load Diff

741
libsrc/geom2d/csg2d.hpp Normal file
View 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

View File

@ -18,10 +18,20 @@ namespace netgen
{
double fperel, oldf, f;
int n = 10000;
int n = 1;
NgArray<Point<2> > xi;
NgArray<double> hi;
NgArray<Point<2> > xi(n);
NgArray<double> hi(n);
// do one extra step
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++)
{
@ -34,13 +44,18 @@ namespace netgen
for (int i = 0; i < n-1; i++)
{
double hnext = hi[i] + gradh * (xi[i+1]-xi[i]).Length();
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--)
{
double hnext = hi[i] + gradh * (xi[i-1]-xi[i]).Length();
if(hnext > 2*hi[i])
not_fine_enough = 2;
hi[i-1] = min(hi[i-1], hnext);
}
}
points.SetSize (0);
@ -233,6 +248,14 @@ namespace netgen
double hr = GetDomainMaxh (spline.rightdom);
if (hr > 0) hcurve = min2 (hcurve, hr);
// skip curvature restrictions for straight lines
if(spline.MaxCurvature()==0)
{
mesh2d.RestrictLocalHLine (Point<3>(p1(0),p1(1),0),
Point<3>(p2(0),p2(1),0), hcurve);
}
else
{
int np = 1000;
for (double t = 0.5/np; t < 1; t += 1.0/np)
{
@ -241,6 +264,7 @@ namespace netgen
mesh2d.RestrictLocalH (Point<3> (x(0), x(1), 0), min2(hc, hcurve));
}
}
}
for (auto mspnt : mp.meshsize_points)
mesh2d.RestrictLocalH (mspnt.pnt, mspnt.h);
@ -278,6 +302,11 @@ namespace netgen
{
npi = mesh2d.AddPoint (newp, layer);
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,
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");
Box<2> bbox = geometry.GetBoundingBox ();
t_h.Start();
if (bbox.Diam() < mp.maxh)
mp.maxh = bbox.Diam();
@ -412,11 +447,14 @@ namespace netgen
t_part_boundary.Start();
geometry.PartitionBoundary (mp, mp.maxh, *mesh);
t_part_boundary.Stop();
PrintMessage (3, "Boundary mesh done, np = ", mesh->GetNP());
t_hpref.Start();
// marks mesh points for hp-refinement
for (int i = 0; i < geometry.GetNP(); i++)
if (geometry.GetPoint(i).hpref)
@ -434,6 +472,7 @@ namespace netgen
}
(*mesh)[mpi].Singularity(geometry.GetPoint(i).hpref);
}
t_hpref.Stop();
int maxdomnr = 0;
@ -443,6 +482,16 @@ namespace netgen
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();
for (int i = 1; i <= maxdomnr; i++)
mesh->AddFaceDescriptor (FaceDescriptor (i, 0, 0, i));
@ -458,10 +507,8 @@ namespace netgen
for ( int sindex = 0; sindex < maxsegmentindex; sindex++ )
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);
t_h.Stop();
int bnp = mesh->GetNP(); // boundary points
auto BndPntRange = mesh->Points().Range();
@ -472,6 +519,7 @@ namespace netgen
for (int domnr = 1; domnr <= maxdomnr; domnr++)
if (geometry.GetDomainTensorMeshing (domnr))
{ // tensor product mesh
RegionTimer rt(t_tensor);
NgArray<PointIndex, PointIndex::BASE> nextpi(bnp);
NgArray<int, PointIndex::BASE> si1(bnp), si2(bnp);
@ -527,10 +575,15 @@ namespace netgen
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++)
{
Point<3> p = (*mesh)[pix] + ( (*mesh)[piy] - (*mesh)[c2] );
pts[(nex+1)*(iy+1) + ix+1] = mesh -> AddPoint (p , 1, FIXEDPOINT);
double lam = Dist((*mesh)[piy],(*mesh)[c2]) / Dist((*mesh)[c3],(*mesh)[c2]);
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++)
@ -545,13 +598,20 @@ namespace netgen
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++)
{
RegionTimer rt(t_domain);
if (geometry.GetDomainTensorMeshing (domnr)) continue;
double h = mp.maxh;
@ -567,19 +627,43 @@ namespace netgen
Meshing2 meshing (geometry, mp, Box<3> (pmin, pmax));
NgArray<int, PointIndex::BASE> compress(bnp);
NgArray<int, PointIndex::BASE> compress(mesh->GetNP());
compress = -1;
int cnt = 0;
for (PointIndex pi : BndPntRange)
if ( (*mesh)[pi].GetLayer() == geometry.GetDomainLayer(domnr))
t_points.Start();
/*
for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
{
meshing.AddPoint ((*mesh)[pi], pi);
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;
gi.trignum = 1;
/*
for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
{
if ( (*mesh)[si].domin == domnr)
@ -593,13 +677,31 @@ namespace netgen
compress[(*mesh)[si][0]], gi, gi);
}
}
*/
// not complete, use at own risk ...
// meshing.Delaunay(*mesh, domnr, mp);
mp.checkoverlap = 0;
for (const Segment * seg : dom2seg[domnr])
{
if (seg->domin == domnr)
meshing.AddBoundaryElement (compress[(*seg)[0]],
compress[(*seg)[1]], gi, gi);
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++)
(*mesh)[sei].SetIndex (domnr);
@ -611,6 +713,8 @@ namespace netgen
mesh->SetMaterial (domnr, material);
}
mesh->Compress();
mp.quad = hquad;

View File

@ -9,6 +9,7 @@
#include <myadt.hpp>
#include <gprim.hpp>
#include <meshing.hpp>
// #include "../gprim/spline.hpp"
@ -133,7 +134,7 @@ namespace netgen
NgArray<char*> materials;
NgArray<double> maxh;
NgArray<bool> quadmeshing;
NgArray<bool> tensormeshing;
Array<bool> tensormeshing;
NgArray<int> layer;
NgArray<string*> bcnames;
double elto0 = 1.0;
@ -203,8 +204,8 @@ namespace netgen
size_t GetNDomains() const { return materials.Size(); }
void GetMaterial (int domnr, char* & material );
void SetMaterial (int domnr, const string & material);
DLL_HEADER void GetMaterial (int domnr, char* & material );
DLL_HEADER void SetMaterial (int domnr, const string & material);
double GetDomainMaxh ( const int domnr );
void SetDomainMaxh ( const int domnr, double maxh );
@ -214,11 +215,36 @@ namespace netgen
if ( quadmeshing.Size() ) return quadmeshing[domnr-1];
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 )
{
if ( tensormeshing.Size() ) return tensormeshing[domnr-1];
if ( tensormeshing.Size()>=domnr ) return tensormeshing[domnr-1];
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 )
{
if ( layer.Size() ) return layer[domnr-1];

View File

@ -6,8 +6,10 @@
#include <meshing.hpp>
#include <geometry2d.hpp>
#include <csg2d.hpp>
using namespace netgen;
using namespace pybind11::literals;
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>>
(m, "Spline", "Spline of a SplineGeometry object")
@ -64,10 +66,12 @@ DLL_HEADER void ExportGeom2d(py::module &m)
.def("Append", FunctionPointer([](SplineGeometry2d &self, py::list segment, int leftdomain, int rightdomain,
optional<variant<int, string>> bc, optional<int> copy, double maxh,
double hpref, double hprefleft, double hprefright)
{
SplineSegExt * seg;
if(py::isinstance<py::str>(segment[0]))
{
auto segtype = py::cast<std::string>(segment[0]);
SplineSegExt * seg;
if (segtype == "line")
{
LineSeg<2> * l = new LineSeg<2>(self.GetPoint(py::cast<int>(segment[1])),
@ -83,6 +87,25 @@ DLL_HEADER void ExportGeom2d(py::module &m)
}
else
throw Exception("Appended segment is not a line or a spline3");
}
else
{
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->rightdom = rightdomain;
seg->hmax = maxh;
@ -265,6 +288,7 @@ DLL_HEADER void ExportGeom2d(py::module &m)
{
double len = self.splines[i]->Length();
int n = floor(len/(0.05*min(xdist,ydist)));
n = max(3, n);
lst.push_back(self.splines[i]->StartPI());
for (int j = 1; j < n; j++){
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,
MeshingParameters* pars, py::kwargs kwargs)
optional<MeshingParameters> pars, py::kwargs kwargs)
{
MeshingParameters mp;
if(pars) mp = *pars;
@ -389,11 +412,89 @@ DLL_HEADER void ExportGeom2d(py::module &m)
if(result != 0)
throw Exception("Meshing failed!");
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>(),
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) {

View File

@ -1099,6 +1099,284 @@ public:
// 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

View File

@ -3,10 +3,6 @@
#include <myadt.hpp>
#include <gprim.hpp>
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
namespace netgen
{
@ -251,239 +247,4 @@ int PTRIANGLE2D :: IsIn (const Point2d & p) const
}
#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);
}
}

View File

@ -609,40 +609,6 @@ namespace netgen
#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.
A monotone function of atan2(x,y) is computed.
*/

View File

@ -83,7 +83,7 @@ double Det (const Mat<3,3> & m)
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 p, q;
double arg;

View File

@ -142,10 +142,24 @@ namespace netgen
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> ainv;
CalcInverse (a, ainv);
inv = Trans (m) * ainv;
*/
}
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<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

View File

@ -384,8 +384,16 @@ namespace netgen
bool IsIn (const Point<D> & p) const
{
for (int i = 0; i < D; i++)
if (p(i) < pmin(i) || p(i) > pmax(i)) return 0;
return 1;
if (p(i) < pmin(i) || p(i) > pmax(i)) return false;
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 <>
inline MPI_Datatype MyGetMPIType<Vec<3, double> > ()
{

View File

@ -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,
const Point3d & tp3, const Point3d & p)
@ -1102,7 +1135,7 @@ double MinDistTP2 (const Point3d & tp1, const Point3d & tp2,
// 0 checks !!!
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) \|
// min !
@ -1112,7 +1145,7 @@ double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
Vec3d v2 (l2p1, l2p2);
double a11, a12, a22, rs1, rs2;
double lam1, lam2, det;
double det;
a11 = v1*v1;
a12 = -(v1*v2);
@ -1138,14 +1171,27 @@ double MinDistLL2 (const Point3d & l1p1, const Point3d & l1p2,
}
double minv, hv;
minv = MinDistLP2 (l1p1, l1p2, l2p1);
hv = MinDistLP2 (l1p1, l1p2, l2p2);
if (hv < minv) minv = hv;
minv = MinDistLP2 (l1p1, l1p2, l2p1, lam1);
lam2 = 0.;
hv = MinDistLP2 (l1p1, l1p2, l2p2, lam1);
if (hv < minv)
{
lam2 = 1.;
minv = hv;
}
hv = MinDistLP2 (l2p1, l2p2, l1p1);
if (hv < minv) minv = hv;
hv = MinDistLP2 (l2p1, l2p2, l1p2);
if (hv < minv) minv = hv;
hv = MinDistLP2 (l2p1, l2p2, l1p1, lam2);
if (hv < minv)
{
lam1 = 0.;
minv = hv;
}
hv = MinDistLP2 (l2p1, l2p2, l1p2, lam2);
if (hv < minv)
{
lam1 = 1.;
minv = hv;
}
return minv;
}

View File

@ -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);
/// 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);
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,
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

View File

@ -98,6 +98,16 @@ namespace netgen
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>
Point<D> SplineSeg3<D> :: GetPoint (double t) const
{

View File

@ -185,6 +185,10 @@ namespace netgen
SplineSeg3 (const GeomPoint<D> & ap1,
const GeomPoint<D> & ap2,
const GeomPoint<D> & ap3);
SplineSeg3 (const GeomPoint<D> & ap1,
const GeomPoint<D> & ap2,
const GeomPoint<D> & ap3,
double aweight);
// default constructor for archive
SplineSeg3() {}
///
@ -192,9 +196,13 @@ namespace netgen
{
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,
@ -202,12 +210,12 @@ namespace netgen
Vec<D> & first,
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;
virtual void GetCoeff (Vector & coeffs, Point<D> p0) const;
DLL_HEADER virtual void GetCoeff (Vector & coeffs) const;
DLL_HEADER virtual void GetCoeff (Vector & coeffs, Point<D> p0) const;
virtual string GetType(void) const {return "spline3";}

View File

@ -2,9 +2,10 @@
#define INCOPENGL_HPP___
#define GL_GLEXT_PROTOTYPES
#include <mystdlib.h>
#include <mydefs.hpp>
# if defined(TOGL_AGL) || defined(TOGL_AGL_CLASSIC) || defined(TOGL_NSOPENGL)
# ifdef __APPLE__
#define GL_SILENCE_DEPRECATION
#define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED
# include <OpenGL/gl3.h>

View File

@ -11,22 +11,15 @@
defines for graphics, testmodes, ...
*/
#include <core/ngcore.hpp>
#define PACKAGE_VERSION "6.2-dev"
// #define DEBUG
#ifdef WIN32
#if NGINTERFACE_EXPORTS || NGLIB_EXPORTS || nglib_EXPORTS
#define DLL_HEADER __declspec(dllexport)
#else
#define DLL_HEADER __declspec(dllimport)
#endif
#if defined(NGINTERFACE_EXPORTS) || ( defined(WIN32) && (defined(NGLIB_EXPORTS) || defined(nglib_EXPORTS)) )
#define DLL_HEADER NGCORE_API_EXPORT
#else
#if __GNUC__ >= 4
#define DLL_HEADER __attribute__ ((visibility ("default")))
#else
#define DLL_HEADER
#endif
#define DLL_HEADER NGCORE_API_IMPORT
#endif

View File

@ -11,22 +11,13 @@
/* Date: 20. Nov. 99 */
/**************************************************************************/
#include <core/ngcore.hpp>
#include "mydefs.hpp"
/*
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
#define NG_ELEMENT_MAXPOINTS 20

View File

@ -8,7 +8,7 @@
/* Date: May 09 */
/**************************************************************************/
#include <core/ngcore.hpp>
#include "mydefs.hpp"
/*
C++ interface to Netgen
@ -276,7 +276,7 @@ namespace netgen
void UpdateTopology ();
void DoArchive (Archive & archive);
NgMPI_Comm GetCommunicator() const;
const NgMPI_Comm & GetCommunicator() const;
virtual ~Ngx_Mesh();
@ -343,8 +343,11 @@ namespace netgen
void SetRefinementFlag (size_t elnr, bool flag);
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 (*tracer)(string, bool) = &DummyTracer2);
@ -354,6 +357,10 @@ namespace netgen
int GetParentElement (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 GetIdentificationType(int idnr) const;
Ng_Buffer<int[2]> GetPeriodicVertices(int idnr) const;
@ -367,7 +374,8 @@ namespace netgen
// 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> SelectMesh () const;

View File

@ -111,7 +111,13 @@ NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<1> (size_t nr) const
ret.faces.num = 0;
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.base = 0;
@ -330,6 +336,20 @@ NGX_INLINE void Ngx_Mesh :: GetParentNodes (int ni, int * parents) const
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(); }

View File

@ -4,10 +4,10 @@ add_library(interface ${NG_LIB_TYPE}
read_fnf_mesh.cpp readtetmesh.cpp readuser.cpp writeabaqus.cpp writediffpack.cpp
writedolfin.cpp writeelmer.cpp writefeap.cpp writefluent.cpp writegmsh.cpp writejcm.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)
install( TARGETS interface ${NG_INSTALL_DIR})

View File

@ -560,7 +560,7 @@ char * Ng_GetSurfaceElementBCName (int ei)
if ( mesh->GetDimension() == 3 )
return const_cast<char *>(mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).GetBCName().c_str());
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
// * pnums entspricht ARRAY<int[2] >
[[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]]
int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * distnums )
{
int size = NgPar_GetNDistantNodeNums (nodetype, locnum);
@ -931,6 +932,7 @@ int NgPar_GetDistantNodeNums ( int nodetype, int locnum, int * distnums )
return size;
}
[[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]]
int NgPar_GetNDistantNodeNums ( int nodetype, int locnum )
{
locnum++;
@ -944,6 +946,7 @@ int NgPar_GetNDistantNodeNums ( int nodetype, int locnum )
return -1;
}
[[deprecated("Use GetDistantNodeNums(locnum) -> FlatArray instead!")]]
int NgPar_GetGlobalNodeNum (int nodetype, int locnum)
{
locnum++;

View File

@ -61,8 +61,12 @@ namespace netgen
SetGlobalMesh (mesh);
}
NgMPI_Comm Ngx_Mesh :: GetCommunicator() const
{ return Valid() ? mesh->GetCommunicator() : NgMPI_Comm{}; }
const NgMPI_Comm & Ngx_Mesh :: GetCommunicator() const
{
// 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
{
@ -775,29 +779,23 @@ namespace netgen
#ifdef __SSE__
#include <immintrin.h>
template<> DLL_HEADER void Ngx_Mesh ::
MultiElementTransformation<1,1> (int elnr, int npts,
const tAVXd * xi, size_t sxi,
tAVXd * x, size_t sx,
tAVXd * dxdxi, size_t sdxdxi) const
const SIMD<double> * xi, size_t sxi,
SIMD<double> * x, size_t sx,
SIMD<double> * dxdxi, size_t sdxdxi) const
{
cout << "multi-eltrafo simd called, 1,1,simd" << endl;
}
template<> DLL_HEADER void Ngx_Mesh ::
MultiElementTransformation<2,2> (int elnr, int npts,
const tAVXd * xi, size_t sxi,
tAVXd * x, size_t sx,
tAVXd * dxdxi, size_t sdxdxi) const
const SIMD<double> * xi, size_t sxi,
SIMD<double> * x, size_t sx,
SIMD<double> * dxdxi, size_t sdxdxi) const
{
mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<2>
(elnr, npts,
reinterpret_cast<const SIMD<double>*> (xi), sxi,
reinterpret_cast<SIMD<double>*> (x), sx,
reinterpret_cast<SIMD<double>*> (dxdxi), sdxdxi);
(elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
/*
for (int i = 0; i < npts; i++)
{
@ -824,15 +822,15 @@ namespace netgen
template<> DLL_HEADER void Ngx_Mesh ::
MultiElementTransformation<3,3> (int elnr, int npts,
const tAVXd * xi, size_t sxi,
tAVXd * x, size_t sx,
tAVXd * dxdxi, size_t sdxdxi) const
const SIMD<double> * xi, size_t sxi,
SIMD<double> * x, size_t sx,
SIMD<double> * dxdxi, size_t sdxdxi) const
{
mesh->GetCurvedElements().CalcMultiPointElementTransformation
(elnr, npts,
reinterpret_cast<const SIMD<double>*> (xi), sxi,
reinterpret_cast<SIMD<double>*> (x), sx,
reinterpret_cast<SIMD<double>*> (dxdxi), sdxdxi);
xi, sxi,
x, sx,
dxdxi, sdxdxi);
/*
for (int i = 0; i < npts; i++)
{
@ -859,33 +857,43 @@ namespace netgen
template<> DLL_HEADER void Ngx_Mesh ::
MultiElementTransformation<0,2> (int elnr, int npts,
const tAVXd *xi, size_t sxi,
tAVXd * x, size_t sx,
tAVXd * dxdxi, size_t sdxdxi) const
const SIMD<double> *xi, size_t sxi,
SIMD<double> * x, size_t sx,
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 ::
MultiElementTransformation<0,1> (int elnr, int npts,
const tAVXd * xi, size_t sxi,
tAVXd * x, size_t sx,
tAVXd * dxdxi, size_t sdxdxi) const
const SIMD<double> * xi, size_t sxi,
SIMD<double> * x, size_t sx,
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 ::
MultiElementTransformation<1,3> (int elnr, int npts,
const tAVXd * xi, size_t sxi,
tAVXd * x, size_t sx,
tAVXd * dxdxi, size_t sdxdxi) const
const SIMD<double> * xi, size_t sxi,
SIMD<double> * x, size_t sx,
SIMD<double> * dxdxi, size_t sdxdxi) const
{
mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<3>
(elnr, npts,
reinterpret_cast<const SIMD<double>*> (xi), sxi,
reinterpret_cast<SIMD<double>*> (x), sx,
reinterpret_cast<SIMD<double>*> (dxdxi), sdxdxi);
(elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
/*
double hxi[4][1];
double hx[4][3];
@ -908,15 +916,12 @@ namespace netgen
template<> DLL_HEADER void Ngx_Mesh ::
MultiElementTransformation<1,2> (int elnr, int npts,
const tAVXd * xi, size_t sxi,
tAVXd * x, size_t sx,
tAVXd * dxdxi, size_t sdxdxi) const
const SIMD<double> * xi, size_t sxi,
SIMD<double> * x, size_t sx,
SIMD<double> * dxdxi, size_t sdxdxi) const
{
mesh->GetCurvedElements().CalcMultiPointSegmentTransformation<2>
(elnr, npts,
reinterpret_cast<const SIMD<double>*> (xi), sxi,
reinterpret_cast<SIMD<double>*> (x), sx,
reinterpret_cast<SIMD<double>*> (dxdxi), sdxdxi);
(elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
/*
for (int i = 0; i < npts; i++)
{
@ -943,15 +948,12 @@ namespace netgen
template<> DLL_HEADER void Ngx_Mesh ::
MultiElementTransformation<2,3> (int elnr, int npts,
const tAVXd * xi, size_t sxi,
tAVXd * x, size_t sx,
tAVXd * dxdxi, size_t sdxdxi) const
const SIMD<double> * xi, size_t sxi,
SIMD<double> * x, size_t sx,
SIMD<double> * dxdxi, size_t sdxdxi) const
{
mesh->GetCurvedElements().CalcMultiPointSurfaceTransformation<3>
(elnr, npts,
reinterpret_cast<const SIMD<double>*> (xi), sxi,
reinterpret_cast<SIMD<double>*> (x), sx,
reinterpret_cast<SIMD<double>*> (dxdxi), sdxdxi);
(elnr, npts, xi, sxi, x, sx, dxdxi, sdxdxi);
/*
for (int i = 0; i < npts; i++)
{
@ -978,9 +980,9 @@ namespace netgen
template<> DLL_HEADER void Ngx_Mesh ::
MultiElementTransformation<0,3> (int elnr, int npts,
const tAVXd * xi, size_t sxi,
tAVXd * x, size_t sx,
tAVXd * dxdxi, size_t sdxdxi) const
const SIMD<double> * xi, size_t sxi,
SIMD<double> * x, size_t sx,
SIMD<double> * dxdxi, size_t sdxdxi) const
{
for (int i = 0; i < npts; i++)
{
@ -1000,10 +1002,6 @@ namespace netgen
}
#endif
@ -1037,6 +1035,14 @@ namespace netgen
case 2:
{
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++)
{
auto & seg = (*mesh)[si];
@ -1061,6 +1067,7 @@ namespace netgen
}
}
}
}
break;
case 3:
default:
@ -1134,6 +1141,17 @@ namespace netgen
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 <>
DLL_HEADER void Ngx_Mesh :: SetRefinementFlag<2> (size_t elnr, bool flag)
@ -1147,9 +1165,9 @@ namespace netgen
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)>),
Tracer tracer)
NgTracer tracer)
{
NgLock meshlock (mesh->MajorMutex(), 1);
@ -1157,6 +1175,7 @@ namespace netgen
biopt.usemarkedelements = 1;
biopt.refine_p = 0;
biopt.refine_hp = 0;
biopt.onlyonce = onlyonce;
if (reftype == NG_REFINE_P)
biopt.refine_p = 1;
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
if (mesh->GetCommunicator().Size() == 1)
return FlatArray<int>(0,nullptr);
switch (nodetype)
{
case 0:
{
NgFlatArray<int> dn = mesh->GetParallelTopology().GetDistantPNums(locnum);
return std::tuple<int,int*>(dn.Size(), &dn[0]);
}
return mesh->GetParallelTopology().GetDistantPNums(locnum);
case 1:
{
NgFlatArray<int> dn = mesh->GetParallelTopology().GetDistantEdgeNums(locnum);
return std::tuple<int,int*>(dn.Size(), &dn[0]);
}
return mesh->GetParallelTopology().GetDistantEdgeNums(locnum);
case 2:
{
NgFlatArray<int> dn = mesh->GetParallelTopology().GetDistantFaceNums(locnum);
return std::tuple<int,int*>(dn.Size(), &dn[0]);
}
return mesh->GetParallelTopology().GetDistantFaceNums(locnum);
default:
return std::tuple<int,int*>(0,nullptr);
return FlatArray<int>(0, nullptr);
}
#else
return std::tuple<int,int*>(0,nullptr);
return FlatArray<int>(0,nullptr);
#endif
}
}

Some files were not shown because too many files have changed in this diff Show More