Merge branch 'master' into feature/extend_nglib_api

This commit is contained in:
Bryn Lloyd 2023-05-30 14:45:20 +02:00
commit a931afa7d0
472 changed files with 78243 additions and 28961 deletions

View File

@ -1,9 +1,25 @@
stages:
- build
- test
- test_ngsolve
- deploy
- cleanup
push_github:
stage: build
tags:
- linux
- docker
- bash
script:
- git remote add github git@github.com:NGSolve/netgen.git || true
- git remote update
- git checkout --track origin/master
- git pull origin master
- git push github master --tags
only:
- master
############################################
# Windows
############################################
@ -14,7 +30,7 @@ stages:
- x64
before_script:
- "echo off"
- 'call "%VS2017INSTALLDIR%\VC\Auxiliary\Build\vcvars64"'
- call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64"
- set CI_DIR=C:\ci\%CI_PIPELINE_ID%
- set CLCACHE_BASEDIR=C:\ci\%CI_PIPELINE_ID%
- set NETGEN_BUILD_DIR=%CI_DIR%\build
@ -22,6 +38,7 @@ stages:
- set SRC_DIR=%CI_DIR%\src
- set NETGENDIR=%INSTALL_DIR%\bin
- set PYTHONPATH=%INSTALL_DIR%\lib\site-packages
- set PATH=%NETGENDIR%;%PATH%
build_win:
<<: *win
@ -38,8 +55,11 @@ build_win:
cmake %SRC_DIR%
-G Ninja
-DCMAKE_INSTALL_PREFIX=%INSTALL_DIR%
-DCHECK_RANGE=ON
-DUSE_CGNS=ON
-DUSE_OCC=ON
-DUSE_CCACHE=ON
-DENABLE_UNIT_TESTS=ON
-DCMAKE_BUILD_TYPE=Release
- cmake --build . --target install --config Release
@ -47,9 +67,12 @@ test_win:
<<: *win
stage: test
script:
- pip install pytest-check
- cd tests\pytest
- cd %NETGEN_BUILD_DIR%\netgen
- ctest -C Release -V
- ctest -C Release -V --output-on-failure
- cd ..
needs: ["build_win"]
cleanup_win:
<<: *win
@ -62,6 +85,7 @@ cleanup_win:
- rd /s /q %CI_DIR%
when: always
allow_failure: true
needs: ["test_win"]
############################################
# Ubuntu/Linux
@ -70,24 +94,48 @@ cleanup_win:
.template_ubuntu: &ubuntu
tags:
- linux
- bash
before_script:
- pwd
- ls
- docker info
variables:
UBUNTU_VERSION: "18.04"
UBUNTU_VERSION: "22.04"
build_ubuntu:
build_ubuntu_debug:
<<: *ubuntu
stage: build
script:
- docker build -t netgen_${CI_BUILD_REF_NAME}:${UBUNTU_VERSION} -f tests/dockerfile .
- rm -f netgen_${CI_BUILD_REF_NAME}_$UBUNTU_VERSION.id
- docker run --cidfile netgen_${CI_BUILD_REF_NAME}_${UBUNTU_VERSION}.id -e CCACHE_DIR=/ccache -v /mnt/ccache:/ccache netgen_${CI_BUILD_REF_NAME}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build.sh
- docker commit `cat netgen_${CI_BUILD_REF_NAME}_${UBUNTU_VERSION}.id` netgen_${CI_BUILD_REF_NAME}_installed:${UBUNTU_VERSION}
- rm netgen_${CI_BUILD_REF_NAME}_${UBUNTU_VERSION}.id
- docker build -t netgen_${CI_PIPELINE_ID}:${UBUNTU_VERSION} -f tests/dockerfile .
- rm -f netgen_${CI_PIPELINE_ID}_$UBUNTU_VERSION.id
- >-
docker run
--cidfile netgen_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id
-e CCACHE_DIR=/ccache
-v /mnt/ccache:/ccache
netgen_${CI_PIPELINE_ID}:${UBUNTU_VERSION}
bash /root/src/netgen/tests/build_debug.sh
- docker commit `cat netgen_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id` netgen_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION}
- rm netgen_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id
test_ubuntu:
build_ubuntu_mpi:
<<: *ubuntu
stage: build
script:
- docker build -t netgen_mpi_${CI_PIPELINE_ID}:${UBUNTU_VERSION} -f tests/dockerfile_mpi .
- rm -f netgen_mpi_${CI_PIPELINE_ID}_$UBUNTU_VERSION.id_mpi
- >-
docker run>-
--cidfile netgen_mpi_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id>-
-e CCACHE_DIR=/ccache
-e RUN_SLOW_TESTS=${RUN_SLOW_TESTS}
-v /mnt/ccache:/ccache
netgen_mpi_${CI_PIPELINE_ID}:${UBUNTU_VERSION}
bash /root/src/netgen/tests/build_mpi.sh
- docker commit `cat netgen_mpi_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id` netgen_mpi_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION}
- rm netgen_mpi_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id
test_ubuntu_debug:
<<: *ubuntu
stage: test
script:
@ -95,36 +143,72 @@ test_ubuntu:
docker run
-e NETGENDIR=/opt/netgen/bin
-e PYTHONPATH=/opt/netgen/lib/python3/dist-packages
netgen_${CI_BUILD_REF_NAME}_installed:${UBUNTU_VERSION}
bash -c 'cd /root/build/netgen && make test_netgen ARGS="-V"'
netgen_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION}
bash -c 'cd /root/build/netgen && make test_netgen ARGS="-V --output-on-failure"'
needs: ["build_ubuntu_debug"]
# cpp guideline checks
test_guidelines:
test_ubuntu_mpi:
<<: *ubuntu
stage: test
script:
- docker run -e CCACHE_DIR=/ccache -v /mnt/ccache:/ccache netgen_${CI_BUILD_REF_NAME}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_guidelines.sh
when: always
- >-
docker run
-e RUN_SLOW_TESTS=${RUN_SLOW_TESTS}
-e NETGENDIR=/opt/netgen/bin
-e PYTHONPATH=/opt/netgen/lib/python3/dist-packages
netgen_mpi_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION}
bash -c 'cd /root/build/netgen && make test_netgen ARGS="-V --output-on-failure"'
needs: ["build_ubuntu_mpi"]
test_build_ngsolve:
<<: *ubuntu
allow_failure: true
stage: test_ngsolve
script:
- >-
docker run
-e NETGENDIR=/opt/netgen/bin
-e PYTHONPATH=/opt/netgen/lib/python3/dist-packages
-e MKLROOT=/opt/intel/mkl
-v /opt/intel:/opt/intel
-e CCACHE_DIR=/ccache
-v /mnt/ccache:/ccache
netgen_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION}
bash -c 'cd /root/src/netgen/tests/ && ./build_ngsolve.sh'
# cpp guideline checks
# test_guidelines:
# <<: *ubuntu
# stage: test
# script:
# - docker run -e CCACHE_DIR=/ccache -v /mnt/ccache:/ccache netgen_${CI_PIPELINE_ID}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_guidelines.sh
# when: always
# allow_failure: true
# check if it compiles without spdlog
test_noSpdlog:
<<: *ubuntu
stage: test
script:
- docker run -e CCACHE_DIR=/ccache -v /mnt/ccache:/ccache netgen_${CI_BUILD_REF_NAME}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_nospdlog.sh
- docker run -e CCACHE_DIR=/ccache -v /mnt/ccache:/ccache netgen_${CI_PIPELINE_ID}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_nospdlog.sh
cleanup_ubuntu:
stage: cleanup
tags:
- linux
- bash
script:
# remove intermediate and old docker images and containers
- docker rm -f `docker ps --no-trunc -aq`
- docker images --no-trunc -aqf "dangling=true" | xargs docker rmi -f || true
- docker rmi -f netgen_${CI_PIPELINE_ID}:${UBUNTU_VERSION} || true
- docker rmi -f netgen_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION} || true
- docker rmi -f netgen_mpi_${CI_PIPELINE_ID}:${UBUNTU_VERSION} || true
- docker rmi -f netgen_mpi_${CI_PIPELINE_ID}_installed:${UBUNTU_VERSION} || true
when: always
allow_failure: true
############################################
# MacOSX
############################################
@ -132,6 +216,7 @@ cleanup_ubuntu:
.template_mac: &mac
tags:
- mac
- x64
before_script:
- export ROOT_DIR=/tmp/$CI_PIPELINE_ID
- export SRC_DIR=$ROOT_DIR/src
@ -155,11 +240,14 @@ 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.9
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.15
-DCMAKE_OSX_SYSROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
-DUSE_CGNS=ON
-DUSE_OCC=ON
- make -j5 install
test_mac:
@ -167,7 +255,8 @@ test_mac:
stage: test
script:
- cd $BUILD_DIR/netgen
- ctest . --output-on-failure
- ctest . -V --output-on-failure
needs: ["build_mac"]
cleanup_mac:
<<: *mac
@ -176,23 +265,40 @@ cleanup_mac:
- rm -rf $ROOT_DIR
when: always
allow_failure: true
needs: ["test_mac"]
############################################
# Deploy stage
############################################
deploy_sourceforge:
stage: deploy
pip_linux:
image: quay.io/pypa/manylinux2014_x86_64
stage: build
tags:
- pip
- linux
- docker
script:
- git remote add sourceforge ssh://mhochste@git.code.sf.net/p/netgen-mesher/git || true
- git remote add github git@github.com:NGSolve/netgen.git || true
- git remote update
- git checkout master
- git pull origin master
- git push sourceforge master
- git push github master
only:
- master
- ./tests/build_pip.sh
when: manual
pip_windows:
stage: build
tags:
- pip
- windows
script:
- .\tests\build_pip.ps1 C:\Python38
- .\tests\build_pip.ps1 C:\Python39
- .\tests\build_pip.ps1 C:\Python310
- .\tests\build_pip.ps1 C:\Python311
when: manual
pip_macos:
stage: build
tags:
- pip
- macosx
- m1
script:
- ./tests/build_pip_mac.sh 3.8
- ./tests/build_pip_mac.sh 3.9
- ./tests/build_pip_mac.sh 3.10
- ./tests/build_pip_mac.sh 3.11
when: manual

BIN
CLA.pdf Normal file

Binary file not shown.

View File

@ -2,23 +2,26 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING INTERNAL)
endif(NOT CMAKE_BUILD_TYPE)
if(WIN32)
# we are linking to object libraries on Windows
cmake_minimum_required(VERSION 3.12)
else(WIN32)
cmake_minimum_required(VERSION 3.1.3)
endif(WIN32)
cmake_minimum_required(VERSION 3.13)
cmake_policy(VERSION 3.13)
if(NOT WIN32)
option( USE_NATIVE_ARCH "build which -march=native" ON)
endif(NOT WIN32)
include (CMakeDependentOption)
option( USE_NATIVE_ARCH "build for native cpu architecture" ON)
option( USE_GUI "don't build netgen with GUI" ON )
option( USE_GUI "build with GUI" ON )
option( USE_PYTHON "build with python interface" ON )
cmake_dependent_option( PREFER_SYSTEM_PYBIND11 "Use system wide PyBind11" OFF "USE_PYTHON" OFF)
option( USE_MPI "enable mpi parallelization" OFF )
option( USE_OCC "(not supported) compile with OpenCascade geometry kernel" OFF)
option( USE_MPI4PY "enable mpi4py interface" ON )
option( USE_OCC "build with OpenCascade geometry kernel interface" OFF)
option( USE_STLGEOM "build with STL geometry support" ON)
option( USE_CSG "build with CSG kernel" ON)
option( USE_INTERFACE "build nginterface" ON)
option( USE_GEOM2D "build 2d geometry kernels" ON)
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")
@ -28,8 +31,17 @@ option( ENABLE_CPP_CORE_GUIDELINES_CHECK "Enable cpp core guideline checks on ng
option( USE_SPDLOG "Enable spd log logging" OFF)
option( DEBUG_LOG "Enable more debug output (may increase computation time) - only works with USE_SPDLOG=ON" OFF)
option( CHECK_RANGE "Check array range access, automatically enabled if built in debug mode" OFF)
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( USE_SUPERBUILD "build dependencies automatically" ON)
option( TRACE_MEMORY "Enable memory tracing" OFF)
set(NG_COMPILE_FLAGS "" CACHE STRING "Additional compile flags")
set(NGLIB_LIBRARY_TYPE SHARED CACHE STRING "nglib library type")
set(NGCORE_LIBRARY_TYPE SHARED CACHE STRING "ngcore library type")
set(NGGUI_LIBRARY_TYPE SHARED CACHE STRING "nggui library type")
set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_modules")
@ -48,14 +60,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)
@ -74,12 +86,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}")
#######################################################################
@ -90,11 +100,6 @@ if(USE_CCACHE)
endif(CCACHE_FOUND)
endif(USE_CCACHE)
#######################################################################
if(USE_NATIVE_ARCH)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native")
endif(USE_NATIVE_ARCH)
#######################################################################
if(INTEL_MIC)
set(MKL_ARCH "mic")
@ -114,6 +119,7 @@ endif (ADDITIONAL_PATHS)
#######################################################################
# build options
include_directories ("${PROJECT_SOURCE_DIR}/include")
include_directories ("${PROJECT_SOURCE_DIR}/libsrc")
include_directories ("${PROJECT_SOURCE_DIR}/libsrc/include")
include_directories ("${PROJECT_BINARY_DIR}")
@ -121,7 +127,9 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
if(USE_PYTHON)
find_package(PythonInterp 3 REQUIRED)
find_package(PythonLibs 3 REQUIRED)
if(NOT BUILD_FOR_CONDA)
find_package(PythonLibs 3 REQUIRED)
endif()
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1,0,''))" OUTPUT_VARIABLE PYTHON_PACKAGES_INSTALL_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
file(TO_CMAKE_PATH ${PYTHON_PACKAGES_INSTALL_DIR} PYTHON_PACKAGES_INSTALL_DIR)
@ -189,13 +197,16 @@ install(EXPORT netgen-targets DESTINATION ${NG_INSTALL_DIR_CMAKE} COMPONENT netg
set(CMAKE_MACOSX_RPATH TRUE)
set(CMAKE_INSTALL_RPATH "${NG_RPATH_TOKEN};${NG_RPATH_TOKEN}/${NETGEN_RPATH}")
if(BUILD_FOR_CONDA)
file(RELATIVE_PATH py_rpath "/bin" "/${NG_INSTALL_DIR_LIB}")
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_RPATH};${py_rpath}")
endif(BUILD_FOR_CONDA)
include (CheckIncludeFiles)
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})
@ -215,90 +226,193 @@ macro(get_dll_from_lib dll_path lib_path)
get_filename_component(lib_name ${lib} name)
endmacro()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_CXX_STANDARD 17)
if(WIN32)
get_WIN32_WINNT(ver)
add_definitions(-D_WIN32_WINNT=${ver} -DWNT -DWNT_WINDOW -DNOMINMAX)
set(CMAKE_MFC_FLAG 0)
add_definitions(-DMSVC_EXPRESS -D_CRT_SECURE_NO_WARNINGS -DHAVE_STRUCT_TIMESPEC)
# build convenience (aka object) libraries in windows)
set(NG_LIB_TYPE OBJECT)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /wd4244 /wd4800")
else(WIN32)
# build shared libraries
set(NG_LIB_TYPE SHARED)
endif(WIN32)
if(APPLE)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -undefined dynamic_lookup")
endif(APPLE)
#######################################################################
add_library(nglib ${NGLIB_LIBRARY_TYPE})
if(USE_GUI)
add_library(nggui ${NGGUI_LIBRARY_TYPE})
if(WIN32)
set_target_properties( nggui PROPERTIES OUTPUT_NAME "libnggui")
endif(WIN32)
endif(USE_GUI)
#######################################################################
if(NOT ZLIB_INCLUDE_DIRS)
find_package(ZLIB REQUIRED)
endif(NOT ZLIB_INCLUDE_DIRS)
include_directories(${ZLIB_INCLUDE_DIRS})
target_include_directories(nglib PRIVATE ${ZLIB_INCLUDE_DIRS})
if(USE_GUI)
target_include_directories(nggui PRIVATE ${ZLIB_INCLUDE_DIRS})
endif(USE_GUI)
target_link_libraries(nglib PRIVATE ${ZLIB_LIBRARIES})
#######################################################################
if(WIN32)
add_library(netgen_gui INTERFACE IMPORTED)
else()
add_library(netgen_gui INTERFACE)
endif()
if (USE_GUI)
find_package(TCL 8.5 REQUIRED)
find_package(TclStub 8.5 REQUIRED)
find_package(Threads REQUIRED)
if(APPLE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AppKit")
target_link_libraries(netgen_gui INTERFACE "-framework AppKit")
else(APPLE)
find_package(X11 REQUIRED)
target_link_libraries( netgen_gui INTERFACE ${X11_Xmu_LIB} ${X11_X11_LIB})
endif(APPLE)
find_package(OpenGL REQUIRED)
add_definitions(-DTCL -DOPENGL -DUSE_TOGL_2)
include_directories(${TCL_INCLUDE_PATH})
include_directories(${TK_INCLUDE_PATH})
set(LIBTOGL togl)
target_compile_definitions(netgen_gui INTERFACE -DTCL -DOPENGL -DUSE_TOGL_2 -DUSE_TCL_STUBS -DUSE_TK_STUBS)
target_include_directories(netgen_gui INTERFACE ${TCL_INCLUDE_PATH} ${TK_INCLUDE_PATH})
target_link_libraries(netgen_gui INTERFACE ${TCL_STUB_LIBRARY} ${TK_STUB_LIBRARY})
if(NOT EXISTS ${TK_INCLUDE_PATH}/tkWin.h AND EXISTS ${TK_INCLUDE_PATH}/../win/tkWin.h)
target_include_directories(netgen_gui INTERFACE ${TK_INCLUDE_PATH}/../win)
endif()
if(NOT EXISTS ${TK_INCLUDE_PATH}/x11/Xlib.h AND EXISTS ${TK_INCLUDE_PATH}/../xlib/X11/Xlib.h)
target_include_directories(netgen_gui INTERFACE ${TK_INCLUDE_PATH}/../xlib)
endif()
target_link_libraries(nggui PUBLIC nglib togl PRIVATE "$<BUILD_INTERFACE:netgen_python>" )
if(WIN32)
add_definitions(-DTOGL_WGL)
else(WIN32)
if(APPLE)
ADD_DEFINITIONS(-DTOGL_NSOPENGL)
else(APPLE)
ADD_DEFINITIONS(-DTOGL_X11)
endif(APPLE)
endif(WIN32)
target_compile_definitions(netgen_gui INTERFACE -DTOGL_WGL)
endif()
if(APPLE)
target_compile_definitions(netgen_gui INTERFACE -DTOGL_NSOPENGL)
endif()
if(UNIX AND NOT APPLE)
target_compile_definitions(netgen_gui INTERFACE -DTOGL_X11)
endif()
endif (USE_GUI)
#######################################################################
if (USE_PYTHON)
add_subdirectory(external_dependencies/pybind11)
add_definitions(-DNG_PYTHON)
find_path(PYBIND_INCLUDE_DIR pybind11/pybind11.h HINTS ${PYTHON_INCLUDE_DIR})
if( PYBIND_INCLUDE_DIR )
message(STATUS "Found Pybind11: ${PYBIND_INCLUDE_DIR}")
else( PYBIND_INCLUDE_DIR )
message(FATAL_ERROR "Could NOT find pybind11!")
endif( PYBIND_INCLUDE_DIR )
if(WIN32)
add_library(netgen_python INTERFACE IMPORTED)
else()
add_library(netgen_python INTERFACE)
endif()
include_directories(${PYBIND_INCLUDE_DIR})
include_directories(${PYTHON_INCLUDE_DIRS})
if (USE_PYTHON)
if (PREFER_SYSTEM_PYBIND11)
set(NG_INSTALL_PYBIND OFF)
find_package(pybind11 CONFIG REQUIRED)
else()
add_subdirectory(external_dependencies/pybind11)
endif()
target_include_directories(netgen_python INTERFACE ${pybind11_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS})
target_include_directories(nglib PRIVATE ${pybind11_INCLUDE_DIR} ${PYTHON_INCLUDE_DIRS})
if(NOT ${BUILD_FOR_CONDA} OR WIN32)
# Don't link python libraries in conda environments
target_link_libraries(netgen_python INTERFACE ${PYTHON_LIBRARIES})
endif()
if(NG_INSTALL_PYBIND)
install(DIRECTORY ${PYBIND_INCLUDE_DIR}/pybind11 DESTINATION ${NG_INSTALL_DIR_INCLUDE} COMPONENT netgen_devel)
install(FILES ${PYBIND_INCLUDE_DIR}/../LICENSE DESTINATION ${NG_INSTALL_DIR_INCLUDE}/pybind11 COMPONENT netgen_devel)
install(DIRECTORY ${pybind11_INCLUDE_DIR}/pybind11 DESTINATION ${NG_INSTALL_DIR_INCLUDE} COMPONENT netgen_devel)
install(FILES ${pybind11_INCLUDE_DIR}/../LICENSE DESTINATION ${NG_INSTALL_DIR_INCLUDE}/pybind11 COMPONENT netgen_devel)
endif(NG_INSTALL_PYBIND)
endif (USE_PYTHON)
#######################################################################
add_library(netgen_mpi INTERFACE)
add_library(netgen_metis INTERFACE)
if (USE_MPI)
find_package(MPI REQUIRED)
target_include_directories(netgen_mpi INTERFACE ${MPI_CXX_INCLUDE_PATH})
target_link_libraries(netgen_mpi INTERFACE ${MPI_mpi_LIBRARY} ${MPI_CXX_LIBRARIES} )
target_compile_definitions(netgen_mpi INTERFACE PARALLEL )
find_package(METIS REQUIRED)
add_definitions(-DPARALLEL -DMETIS)
include_directories(${MPI_CXX_INCLUDE_PATH})
include_directories(${METIS_INCLUDE_DIR})
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})
#######################################################################
if (USE_OCC)
find_package(OpenCasCade REQUIRED)
add_definitions(-DOCCGEOMETRY -D_OCC64)
include_directories(${OCC_INCLUDE_DIR})
find_package(OpenCascade NAMES OpenCASCADE opencascade REQUIRED CMAKE_FIND_ROOT_PATH_BOTH)
add_definitions(-DOCCGEOMETRY)
set(OCC_LIBRARIES
TKBO
TKBRep
TKBool
TKCAF
TKCDF
TKFillet
TKG2d
TKG3d
TKGeomAlgo
TKGeomBase
TKHLR
TKIGES
TKLCAF
TKMath
TKMesh
TKOffset
TKPrim
TKSTEP
TKSTEP209
TKSTEPAttr
TKSTEPBase
TKSTL
TKService
TKShHealing
TKTopAlgo
TKV3d
TKVCAF
TKXCAF
TKXDEIGES
TKXDESTEP
TKXSBase
TKernel
)
include_directories(${OpenCASCADE_INCLUDE_DIR})
if(NOT OpenCASCADE_BUILD_SHARED_LIBS)
if(OpenCASCADE_WITH_FREETYPE)
find_library( FREETYPE NAMES freetype HINTS ${OpenCASCADE_INSTALL_PREFIX}/lib)
list(APPEND OCC_LIBRARIES ${FREETYPE})
if(UNIX AND NOT APPLE)
find_package(Fontconfig REQUIRED)
list(APPEND OCC_LIBRARIES ${Fontconfig_LIBRARIES})
endif()
endif(OpenCASCADE_WITH_FREETYPE)
if(UNIX AND NOT APPLE)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
list(APPEND OCC_LIBRARIES Threads::Threads)
list(PREPEND OCC_LIBRARIES -Wl,--start-group)
list(APPEND OCC_LIBRARIES -Wl,--end-group)
endif()
if(WIN32)
list(APPEND OCC_LIBRARIES Ws2_32.lib)
endif()
endif()
message(STATUS "OCC DIRS ${OpenCASCADE_INCLUDE_DIR}")
if(WIN32 AND USE_GUI)
target_link_libraries(nggui PRIVATE ${OCC_LIBRARIES})
endif(WIN32 AND USE_GUI)
endif (USE_OCC)
#######################################################################
@ -315,6 +429,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")
@ -379,18 +499,91 @@ 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)
# include instead of add_subdirectory to recognize the generated source files properly
include(rules/CMakeLists.txt)
add_subdirectory(windows)
add_subdirectory(libsrc)
add_subdirectory(ng)
add_subdirectory(tutorials)
if (USE_PYTHON)
add_subdirectory(python)
endif (USE_PYTHON)
add_subdirectory(py_tutorials)
add_subdirectory(doc)
add_subdirectory(windows)
add_subdirectory(nglib)
add_subdirectory(tests)
#######################################################################
if(USE_NATIVE_ARCH)
if(WIN32)
include(CheckCXXSourceRuns)
check_cxx_source_runs("
#include <immintrin.h>
int main()
{
__m256d a{1.,2.,3.,4.};
__m256d b{2.,0.,3.,5.};
__m256d c = _mm256_mul_pd(a,b);
return 0;
} " NG_HAVE_AVX)
check_cxx_source_runs("
#include <immintrin.h>
int main()
{
__m256i a{1,2,3,4};
__m256i b{2,0,3,5};
__m256i c = _mm256_cmpgt_epi64 (a,b);
return 0;
} " NG_HAVE_AVX2)
check_cxx_source_runs("
#include <immintrin.h>
int main()
{
__m512d a{1.,2.,3.,4.};
__m512d b{5.,6.,7.,8.};
__m512d c = _mm512_mul_pd(a,b);
return 0;
} " NG_HAVE_AVX512)
if(NG_HAVE_AVX512)
target_compile_options(ngcore PUBLIC "/arch:AVX512")
message(STATUS "Build for AVX512 CPU")
elseif(NG_HAVE_AVX2)
target_compile_options(ngcore PUBLIC "/arch:AVX2")
message(STATUS "Build for AVX2 CPU")
elseif(NG_HAVE_AVX)
target_compile_options(ngcore PUBLIC "/arch:AVX")
message(STATUS "Build for AVX CPU")
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)
if(APPLE)
# work-around for bug in Xcode 11.3: https://forums.developer.apple.com/thread/121887
target_compile_options(ngcore PUBLIC "-fno-stack-check")
endif(APPLE)
endif(USE_NATIVE_ARCH)
if (USE_PYTHON)
add_subdirectory(python)
endif (USE_PYTHON)
#######################################################################
# Debian packager
@ -428,7 +621,7 @@ if(UNIX)
endif(temp)
endif(UNIX)
if(APPLE)
if(APPLE AND NOT SKBUILD)
# create some auxiliary files
set(mac_startup ${CMAKE_CURRENT_BINARY_DIR}/startup.sh)
file(WRITE ${mac_startup} "\
@ -450,7 +643,7 @@ $Netgen_MACOS/netgen
#!/bin/sh
Netgen_BUNDLE=\"`echo \"$0\" | sed -e 's/\\/Contents\\/MacOS\\/Netgen1//'`\"
Netgen_MACOS=\"$Netgen_BUNDLE/Contents/MacOS\"
open -a /Applications/Utilities/Terminal.app $Netgen_MACOS/startup.sh
open -a /Applications/Utilities/Terminal.app $Netgen_MACOS/startup.sh || open -a /System/Applications/Utilities/Terminal.app $Netgen_MACOS/startup.sh
")
install(PROGRAMS ${mac_ngsuite} DESTINATION ${NG_INSTALL_DIR_BIN} RENAME Netgen1)
@ -473,7 +666,7 @@ open -a /Applications/Utilities/Terminal.app $Netgen_MACOS/startup.sh
install(FILES ${mac_plist} DESTINATION ${NG_INSTALL_DIR_BIN}/../)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/netgen.icns DESTINATION ${NG_INSTALL_DIR_RES}/../ RENAME Netgen.icns)
endif(APPLE)
endif(APPLE AND NOT SKBUILD)
if(NOT APPLE)
include(CPack)

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,3 +1,6 @@
Netgen mesh generator
NETGEN is an automatic 3d tetrahedral mesh generator. It accepts input from constructive solid geometry (CSG) or boundary representation (BRep) from STL file format. The connection to a geometry kernel allows the handling of IGES and STEP files. NETGEN contains modules for mesh optimization and hierarchical mesh refinement. Netgen 6.x supports scripting via a Python interface. Netgen is open source based on the LGPL license. It is available for Unix/Linux, Windows, and OSX.
NETGEN is an automatic 3d tetrahedral mesh generator. It accepts input from constructive solid geometry (CSG) or boundary representation (BRep) from STL file format. The connection to a geometry kernel allows the handling of IGES and STEP files. NETGEN contains modules for mesh optimization and hierarchical mesh refinement. Netgen 6.x supports scripting via a Python interface. Netgen is open source based on the LGPL license. It is available for Unix/Linux, Windows, and OSX.
Find the Open Source Community on https://ngsolve.org
Support & Services: https://cerbsim.com

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)
@ -14,6 +18,8 @@ get_filename_component(NETGEN_RESOURCE_DIR "${NETGEN_CMAKE_DIR}/@NETGEN_RESOURCE
set(NETGEN_SOURCE_DIR "@PROJECT_SOURCE_DIR@")
set(NETGEN_BUILD_FOR_CONDA "@BUILD_FOR_CONDA@")
set(NETGEN_CHECK_RANGE "@CHECK_RANGE@")
set(NETGEN_INCLUDE_DIRS "${NETGEN_INCLUDE_DIR}/include;${NETGEN_INCLUDE_DIR}")
set(NETGEN_CMAKE_THREAD_LIBS_INIT "@CMAKE_THREAD_LIBS_INIT@")
set(NETGEN_FFMPEG_LIBRARIES "@FFMPEG_LIBRARIES@")
@ -25,19 +31,21 @@ 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_OCC_INCLUDE_DIR "@OCC_INCLUDE_DIR@")
set(NETGEN_OCC_LIBRARIES_BIN "@OCC_LIBRARIES_BIN@")
set(NETGEN_NUMA_LIBRARY "@NUMA_LIBRARY@")
set(NETGEN_OCC_DIR "@OpenCasCade_DIR@")
set(NETGEN_OCC_INCLUDE_DIR "@OpenCASCADE_INCLUDE_DIR@")
set(NETGEN_OCC_LIBRARIES_BIN "@OpenCASCADE_BINARY_DIR@")
set(NETGEN_OCC_LIBRARIES "@OCC_LIBRARIES@")
set(NETGEN_OCC_LIBRARY_DIR "@OCC_LIBRARY_DIR@")
set(NETGEN_OCC_LIBRARY_DIR "@OpenCASCADE_LIBRARY_DIR@")
set(NETGEN_OPENGL_LIBRARIES "@OPENGL_LIBRARIES@")
set(NETGEN_PYTHON_EXECUTABLE "@PYTHON_EXECUTABLE@")
set(NETGEN_PYTHON_INCLUDE_DIRS "@PYTHON_INCLUDE_DIRS@")
set(NETGEN_PYTHON_LIBRARIES "@PYTHON_LIBRARIES@")
set(NETGEN_TCL_INCLUDE_PATH "@TCL_INCLUDE_PATH@")
set(NETGEN_TCL_LIBRARY "@TCL_LIBRARY@")
set(NETGEN_TCL_LIBRARY "@TCL_STUB_LIBRARY@")
set(NETGEN_TK_DND_LIBRARY "@TK_DND_LIBRARY@")
set(NETGEN_TK_INCLUDE_PATH "@TK_INCLUDE_PATH@")
set(NETGEN_TK_LIBRARY "@TK_LIBRARY@")
set(NETGEN_TK_LIBRARY "@TK_STUB_LIBRARY@")
set(NETGEN_X11_X11_LIB "@X11_X11_LIB@")
set(NETGEN_X11_Xmu_LIB "@X11_Xmu_LIB@")
set(NETGEN_ZLIB_INCLUDE_DIRS "@ZLIB_INCLUDE_DIRS@")
@ -49,9 +57,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

@ -1,38 +1,72 @@
include (ExternalProject)
option( BUILD_ZLIB "Build and link static version of zlib (useful for pip binaries)" OFF )
option( BUILD_OCC "Build and link static version of occ (useful for pip binaries)" OFF )
set_property (DIRECTORY PROPERTY EP_PREFIX dependencies)
set (NETGEN_DEPENDENCIES)
set (LAPACK_DEPENDENCIES)
set (NETGEN_CMAKE_ARGS "" CACHE INTERNAL "")
set (SUBPROJECT_CMAKE_ARGS "" CACHE INTERNAL "")
set (SUBPROJECT_ARGS
LIST_SEPARATOR |
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dependencies
)
# only show output on failure in ci-builds
if(DEFINED ENV{CI})
set (SUBPROJECT_ARGS
LOG_DOWNLOAD ON
LOG_BUILD ON
LOG_INSTALL ON
LOG_CONFIGURE ON
)
if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0")
set (SUBPROJECT_ARGS
${SUBPROJECT_ARGS}
LOG_OUTPUT_ON_FAILURE ON
LOG_MERGED_STDOUTERR ON
)
endif()
endif()
set (NETGEN_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} )
macro(set_vars VAR_OUT)
foreach(varname ${ARGN})
if(NOT "${${varname}}" STREQUAL "")
string(REPLACE ";" "$<SEMICOLON>" varvalue "${${varname}}" )
set(${VAR_OUT} ${${VAR_OUT}};-D${varname}=${varvalue} CACHE INTERNAL "")
string(REPLACE ";" "|" varvalue "${${varname}}" )
set(${VAR_OUT} "${${VAR_OUT}};-D${varname}=${varvalue}" CACHE INTERNAL "")
endif()
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)
if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
string(REGEX REPLACE "/W[0-4]" "/W0" CMAKE_CXX_FLAGS_NEW ${CMAKE_CXX_FLAGS})
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS_NEW} CACHE STRING "compile flags" FORCE)
string(REGEX REPLACE "/W[0-4]" "/W0" CMAKE_CXX_FLAGS_NEW ${CMAKE_CXX_FLAGS_RELEASE})
set(CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_NEW} CACHE STRING "compile flags" FORCE)
string(REGEX REPLACE "/W[0-4]" "/W0" CMAKE_SHARED_LINKER_FLAGS_NEW ${CMAKE_SHARED_LINKER_FLAGS})
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS_NEW} /IGNORE:4217,4049" CACHE STRING "compile flags" FORCE)
string(REGEX REPLACE "/W[0-4]" "/W0" CMAKE_EXE_LINKER_FLAGS_NEW ${CMAKE_EXE_LINKER_FLAGS})
set(CMAKE_EXE_LINKER_FLAGS"${CMAKE_EXE_LINKER_FLAGS_NEW}/IGNORE:4217,4049" CACHE STRING "compile flags" FORCE)
set_vars(SUBPROJECT_CMAKE_ARGS CMAKE_OSX_DEPLOYMENT_TARGET)
set_vars(SUBPROJECT_CMAKE_ARGS CMAKE_OSX_SYSROOT)
set_vars(SUBPROJECT_CMAKE_ARGS CMAKE_C_COMPILER)
set_vars(SUBPROJECT_CMAKE_ARGS CMAKE_CXX_COMPILER)
set_vars(SUBPROJECT_CMAKE_ARGS CMAKE_BUILD_TYPE)
set(SUBPROJECT_CMAKE_ARGS "${SUBPROJECT_CMAKE_ARGS};-DCMAKE_POSITION_INDEPENDENT_CODE=ON" CACHE INTERNAL "")
if(USE_CCACHE)
find_program(CCACHE_FOUND NAMES ccache ccache.bat)
if(CCACHE_FOUND)
set(SUBPROJECT_CMAKE_ARGS "${SUBPROJECT_CMAKE_ARGS};-DCMAKE_CXX_COMPILER_LAUNCHER=${CCACHE_FOUND}" CACHE INTERNAL "")
endif()
endif()
#######################################################################
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}/occ75_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)
endif(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
endif(WIN32)
if(UNIX)
message("Checking for write permissions in install directory...")
@ -43,10 +77,79 @@ if(UNIX)
endif()
endif(UNIX)
if(NOT WIN32)
find_package(ZLIB REQUIRED)
set_vars(NETGEN_CMAKE_ARGS ZLIB_INCLUDE_DIRS ZLIB_LIBRARIES)
endif(NOT WIN32)
if(USE_OCC)
if(BUILD_OCC)
set(OCC_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/occ)
ExternalProject_Add(project_occ
URL https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V7_6_1.zip
URL_MD5 e891d85cad61c5cc7ccba3d0110f0c8c
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
${SUBPROJECT_ARGS}
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${OCC_DIR}
-DCMAKE_PREFIX_PATH=${OCC_DIR}
-DBUILD_LIBRARY_TYPE:STRING=Static
-DBUILD_MODULE_FoundationClasses:BOOL=ON
-DBUILD_MODULE_ModelingData:BOOL=ON
-DBUILD_MODULE_ModelingAlgorithms:BOOL=ON
-DBUILD_MODULE_DataExchange:BOOL=ON
-DBUILD_MODULE_Visualization:BOOL=OFF
-DBUILD_MODULE_ApplicationFramework:BOOL=OFF
-DBUILD_MODULE_Draw:BOOL=OFF
-DUSE_FREETYPE:BOOL=OFF
-DUSE_OPENGL:BOOL=OFF
-DUSE_XLIB:BOOL=OFF
-DBUILD_DOC_Overview:BOOL=OFF
${SUBPROJECT_CMAKE_ARGS}
UPDATE_COMMAND ""
)
list(APPEND NETGEN_DEPENDENCIES project_occ)
set(OpenCascade_ROOT ${OCC_DIR})
else(BUILD_OCC)
if(WIN32 AND NOT OCC_INCLUDE_DIR AND NOT OpenCASCADE_DIR)
# we can download prebuilt occ binaries for windows
ExternalProject_Add(win_download_occ
${SUBPROJECT_ARGS}
URL ${OCC_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}
)
list(APPEND NETGEN_DEPENDENCIES win_download_occ)
else()
find_package(OpenCascade NAMES OpenCasCade OpenCASCADE opencascade REQUIRED)
endif()
endif(BUILD_OCC)
endif(USE_OCC)
if(BUILD_ZLIB)
set(ZLIB_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/zlib)
ExternalProject_Add(project_zlib
${SUBPROJECT_ARGS}
URL https://github.com/madler/zlib/archive/refs/tags/v1.2.11.zip
URL_MD5 9d6a627693163bbbf3f26403a3a0b0b1
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${ZLIB_DIR}
${SUBPROJECT_CMAKE_ARGS}
UPDATE_COMMAND "" # Disable update
BUILD_IN_SOURCE 1
)
list(APPEND NETGEN_DEPENDENCIES project_zlib)
list(APPEND NETGEN_CMAKE_PREFIX_PATH ${ZLIB_DIR})
if(WIN32)
# force linking the static library
set(ZLIB_INCLUDE_DIRS ${ZLIB_DIR}/include)
set(ZLIB_LIBRARIES ${ZLIB_DIR}/lib/zlibstatic.lib)
endif(WIN32)
else()
include(cmake/external_projects/zlib.cmake)
endif()
#######################################################################
if (USE_PYTHON)
@ -63,7 +166,9 @@ if (USE_PYTHON)
message(FATAL_ERROR "Could NOT find pybind11!")
endif( PYBIND_INCLUDE_DIR )
find_package(PythonInterp 3 REQUIRED)
find_package(PythonLibs 3 REQUIRED)
if(NOT BUILD_FOR_CONDA)
find_package(PythonLibs 3 REQUIRED)
endif()
set_vars(NETGEN_CMAKE_ARGS
PYTHON_INCLUDE_DIRS
@ -77,35 +182,27 @@ endif (USE_PYTHON)
#######################################################################
if(USE_OCC AND WIN32 AND NOT OCC_INCLUDE_DIR)
ExternalProject_Add(win_download_occ
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/tcl
URL ${OCC_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 win_download_occ)
endif(USE_OCC AND WIN32 AND NOT OCC_INCLUDE_DIR)
#######################################################################
include(cmake/external_projects/zlib.cmake)
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)
find_package(METIS QUIET)
if(NOT METIS_FOUND)
message(STATUS "Could not find METIS, it will be built from source")
include(cmake/external_projects/metis.cmake)
endif()
if (METIS_DIR)
message(STATUS "Using external METIS at: ${METIS_DIR}")
else (METIS_DIR)
message(STATUS "Looking for system METIS")
find_package(METIS QUIET)
if(NOT METIS_FOUND)
message(WARNING "Could not find METIS, it will be built from source (this might conflict with NGSolve MUMPS)!")
include(cmake/external_projects/metis.cmake)
endif(NOT METIS_FOUND)
endif(METIS_DIR)
else(UNIX)
find_package(METIS REQUIRED)
endif(UNIX)
@ -115,14 +212,10 @@ endif(USE_MPI)
#######################################################################
# propagate cmake variables to Netgen subproject
set_vars( NETGEN_CMAKE_ARGS
CMAKE_CXX_COMPILER
CMAKE_BUILD_TYPE
CMAKE_SHARED_LINKER_FLAGS
CMAKE_SHARED_LINKER_FLAGS_RELEASE
CMAKE_CXX_FLAGS
CMAKE_CXX_FLAGS_RELEASE
CMAKE_OSX_DEPLOYMENT_TARGET
CMAKE_OSX_SYSROOT
USE_GUI
USE_PYTHON
@ -135,16 +228,27 @@ set_vars( NETGEN_CMAKE_ARGS
USE_OCC
USE_MPEG
USE_JPEG
USE_CGNS
USE_INTERNAL_TCL
INSTALL_PROFILES
INTEL_MIC
CMAKE_PREFIX_PATH
CMAKE_INSTALL_PREFIX
ENABLE_UNIT_TESTS
ENABLE_CPP_CORE_GUIDELINES_CHECK
USE_SPDLOG
DEBUG_LOG
CHECK_RANGE
TRACE_MEMORY
BUILD_STUB_FILES
BUILD_FOR_CONDA
NG_COMPILE_FLAGS
OpenCascade_ROOT
ZLIB_INCLUDE_DIRS
ZLIB_LIBRARIES
NGLIB_LIBRARY_TYPE
NGCORE_LIBRARY_TYPE
NGGUI_LIBRARY_TYPE
)
# propagate all variables set on the command line using cmake -DFOO=BAR
@ -152,9 +256,10 @@ set_vars( NETGEN_CMAKE_ARGS
get_cmake_property(CACHE_VARS CACHE_VARIABLES)
foreach(CACHE_VAR ${CACHE_VARS})
get_property(CACHE_VAR_HELPSTRING CACHE ${CACHE_VAR} PROPERTY HELPSTRING)
if(CACHE_VAR_HELPSTRING STREQUAL "No help, variable specified on the command line.")
if(CACHE_VAR_HELPSTRING STREQUAL "No help, variable specified on the command line." AND NOT CACHE_VAR STREQUAL "CMAKE_OSX_ARCHITECTURES")
get_property(CACHE_VAR_TYPE CACHE ${CACHE_VAR} PROPERTY TYPE)
set(NETGEN_CMAKE_ARGS ${NETGEN_CMAKE_ARGS};-D${CACHE_VAR}:${CACHE_VAR_TYPE}=${${CACHE_VAR}} CACHE INTERNAL "")
string(REPLACE ";" "|" varvalue "${${CACHE_VAR}}" )
set(NETGEN_CMAKE_ARGS ${NETGEN_CMAKE_ARGS};-D${CACHE_VAR}:${CACHE_VAR_TYPE}=${varvalue} CACHE INTERNAL "")
endif()
endforeach()
@ -164,10 +269,17 @@ else()
set(NETGEN_BUILD_COMMAND ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/netgen --config ${CMAKE_BUILD_TYPE})
endif()
string(REPLACE ";" "|" NETGEN_CMAKE_PREFIX_PATH_ALT_SEP "${NETGEN_CMAKE_PREFIX_PATH}")
ExternalProject_Add (netgen
${SUBPROJECT_ARGS}
DEPENDS ${NETGEN_DEPENDENCIES}
SOURCE_DIR ${PROJECT_SOURCE_DIR}
CMAKE_ARGS -DUSE_SUPERBUILD=OFF ${NETGEN_CMAKE_ARGS}
CMAKE_ARGS
-DUSE_SUPERBUILD=OFF
${NETGEN_CMAKE_ARGS}
${SUBPROJECT_CMAKE_ARGS}
-DCMAKE_PREFIX_PATH=${NETGEN_CMAKE_PREFIX_PATH_ALT_SEP}
INSTALL_COMMAND ""
BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/netgen
BUILD_COMMAND ${NETGEN_BUILD_COMMAND}
@ -191,7 +303,7 @@ ExternalProject_Add (netgen
)
install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build . --target install --config ${CMAKE_BUILD_TYPE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/netgen)")
install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" --build . --target install --config ${CMAKE_BUILD_TYPE} WORKING_DIRECTORY \"${CMAKE_CURRENT_BINARY_DIR}/netgen\")")
add_custom_target(test_netgen
${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/netgen

View File

@ -1,97 +0,0 @@
# Try to find OCC
# Once done this will define
#
# OCC_FOUND - system has OCC - OpenCASCADE
# OCC_INCLUDE_DIR - where the OCC include directory can be found
# OCC_LIBRARY_DIR - where the OCC library directory can be found
# OCC_LIBRARIES - Link this to use OCC
if(WIN32)
find_path(OCC_INCLUDE_DIR Standard_Version.hxx PATH_SUFFIXES inc ../inc)
find_library(OCC_LIBRARY TKernel)
else(WIN32)
find_path(OCC_INCLUDE_DIR Standard_Version.hxx
/usr/include/opencascade
/usr/local/include/opencascade
/usr/include/oce
/usr/local/include/oce
/opt/opencascade/include
/opt/opencascade/inc
)
find_library(OCC_LIBRARY TKernel
/usr/lib
/usr/local/lib
/opt/opencascade/lib
)
endif(WIN32)
if(OCC_LIBRARY)
get_filename_component(OCC_LIBRARY_DIR ${OCC_LIBRARY} PATH)
endif(OCC_LIBRARY)
if(OCC_INCLUDE_DIR)
file(STRINGS ${OCC_INCLUDE_DIR}/Standard_Version.hxx OCC_MAJOR
REGEX "#define OCC_VERSION_MAJOR.*"
)
string(REGEX MATCH "[0-9]+" OCC_MAJOR ${OCC_MAJOR})
file(STRINGS ${OCC_INCLUDE_DIR}/Standard_Version.hxx OCC_MINOR
REGEX "#define OCC_VERSION_MINOR.*"
)
string(REGEX MATCH "[0-9]+" OCC_MINOR ${OCC_MINOR})
file(STRINGS ${OCC_INCLUDE_DIR}/Standard_Version.hxx OCC_MAINT
REGEX "#define OCC_VERSION_MAINTENANCE.*"
)
string(REGEX MATCH "[0-9]+" OCC_MAINT ${OCC_MAINT})
set(OCC_VERSION_STRING "${OCC_MAJOR}.${OCC_MINOR}.${OCC_MAINT}")
endif(OCC_INCLUDE_DIR)
set(OCC_LIBRARY_NAMES
TKBO
TKBool
TKBRep
TKCAF
TKCDF
TKernel
TKG2d
TKG3d
TKGeomAlgo
TKGeomBase
TKHLR
TKIGES
TKLCAF
TKMath
TKMesh
TKOffset
TKPrim
TKService
TKShHealing
TKSTEP
TKSTEP209
TKSTEPAttr
TKSTEPBase
TKSTL
TKTopAlgo
TKV3d
TKXCAF
TKXDEIGES
TKXDESTEP
TKXSBase
)
foreach( libname ${OCC_LIBRARY_NAMES} )
find_library( ${libname} ${libname} ${OCC_LIBRARY_DIR} )
set(OCC_LIBRARIES ${OCC_LIBRARIES} ${${libname}})
endforeach()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(OCC REQUIRED_VARS OCC_INCLUDE_DIR VERSION_VAR OCC_VERSION_STRING ${OCC_LIBRARIY_NAMES})
if(OCC_FOUND)
message(STATUS "-- Found OpenCASCADE version: ${OCC_VERSION_STRING}")
message(STATUS "-- OpenCASCADE include directory: ${OCC_INCLUDE_DIR}")
message(STATUS "-- OpenCASCADE shared libraries directory: ${OCC_LIBRARY_DIR}")
message(STATUS "-- OpenCASCADE shared libraries :\n ${OCC_LIBRARIES}")
endif(OCC_FOUND)

View File

@ -4,7 +4,7 @@ ExternalProject_Add(
project_catch
PREFIX ${CMAKE_BINARY_DIR}/catch
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v2.0.1
GIT_TAG v2.13.7
TIMEOUT 10
UPDATE_COMMAND "" # ${GIT_EXECUTABLE} pull
CONFIGURE_COMMAND ""

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

@ -3,12 +3,15 @@ set(METIS_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/metis)
ExternalProject_Add(project_metis
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dependencies
URL "http://ftp.mcs.anl.gov/pub/petsc/externalpackages/metis-5.1.0-p3.tar.gz"
URL_MD5 09d2d771c63a2efb3499882688100088
URL https://bitbucket.org/petsc/pkg-metis/get/v5.1.0-p6.tar.gz
URL_MD5 55fc654bb838846b856ba898795143f1
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
CMAKE_ARGS
-DGKLIB_PATH=${METIS_SRC_DIR}/GKlib
-DCMAKE_INSTALL_PREFIX=${METIS_DIR}
-DCMAKE_POSITION_INDEPENDENT_CODE=ON
-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
UPDATE_COMMAND "" # Disable update
BUILD_IN_SOURCE 1
)

View File

@ -1,61 +1,179 @@
if(UNIX AND NOT APPLE)
set (LINUX TRUE)
endif()
if(LINUX)
find_package(TclStub 8.5 REQUIRED)
else(LINUX)
if(SKBUILD)
# we are building a pip package - download the tcl/tk sources matching the tkinter version (for private headers not shipped with python)
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c
"import tkinter;print(tkinter.Tcl().eval('info patchlevel').replace('.','-'))"
OUTPUT_VARIABLE PYTHON_TCL_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE)
set(TCL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tcl)
set(TK_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tk)
ExternalProject_Add(project_tcl
URL "https://github.com/tcltk/tcl/archive/refs/tags/core-${PYTHON_TCL_VERSION}.zip"
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
${SUBPROJECT_ARGS}
DOWNLOAD_DIR download_tcl
)
ExternalProject_Add(project_tk
URL "https://github.com/tcltk/tk/archive/refs/tags/core-${PYTHON_TCL_VERSION}.zip"
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
INSTALL_COMMAND ""
BUILD_COMMAND ${CMAKE_COMMAND} -E copy_directory macosx generic
${SUBPROJECT_ARGS}
DOWNLOAD_DIR download_tk
BUILD_IN_SOURCE 1
)
set(TCL_INCLUDE_PATH ${TCL_DIR}/generic)
set(TK_INCLUDE_PATH ${TK_DIR}/generic)
list(APPEND NETGEN_DEPENDENCIES project_tcl project_tk)
if(APPLE OR WIN32)
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import sys; print(sys.prefix)" OUTPUT_VARIABLE PYTHON_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE)
file(TO_CMAKE_PATH ${PYTHON_PREFIX} PYTHON_PREFIX)
set(tcl_find_args
REQUIRED
NO_DEFAULT_PATH
NO_PACKAGE_ROOT_PATH
NO_CMAKE_PATH
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH
NO_CMAKE_FIND_ROOT_PATH
HINTS ${PYTHON_PREFIX}/lib ${PYTHON_PREFIX}/tcl
)
find_library(TCL_STUB_LIBRARY NAMES tclstub85 tclstub8.5 tclstub86 tclstub8.6 ${tcl_find_args})
find_library(TK_STUB_LIBRARY NAMES tkstub85 tkstub8.5 tkstub86 tkstub8.6 ${tcl_find_args})
find_library(TCL_LIBRARY NAMES tcl85 tcl8.5 tcl86 tcl8.6 tcl86t ${tcl_find_args})
find_library(TK_LIBRARY NAMES tk85 tk8.5 tk86 tk8.6 tk86t ${tcl_find_args})
else()
# use system tcl/tk on linux
find_package(TclStub REQUIRED)
endif()
else(SKBUILD)
if(APPLE)
# use system tcl/tk
if((${PYTHON_VERSION_STRING} VERSION_EQUAL "3.7") OR (${PYTHON_VERSION_STRING} VERSION_GREATER "3.7"))
# fetch tcl/tk sources to match the one used in Python 3.7
ExternalProject_Add(project_tcl
URL "https://prdownloads.sourceforge.net/tcl/tcl8.6.8-src.tar.gz"
URL_MD5 81656d3367af032e0ae6157eff134f89
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
UPDATE_COMMAND "" # Disable update
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
ExternalProject_Add(project_tk
URL "https://prdownloads.sourceforge.net/tcl/tk8.6.8-src.tar.gz"
URL_MD5 5e0faecba458ee1386078fb228d008ba
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
UPDATE_COMMAND "" # Disable update
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
)
get_filename_component(PYTHON_LIB_DIR ${PYTHON_LIBRARY} DIRECTORY)
find_library(TCL_LIBRARY libtcl8.6.dylib PATHS ${PYTHON_LIB_DIR} NO_DEFAULT_PATH)
find_library(TK_LIBRARY libtk8.6.dylib PATHS ${PYTHON_LIB_DIR} NO_DEFAULT_PATH)
set(TCL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tcl)
set(TK_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tk)
set(TCL_INCLUDE_PATH "${TCL_DIR}/generic;${TCL_DIR}/macosx")
set(TK_INCLUDE_PATH "${TK_DIR}/generic;${TK_DIR}/macosx;${TK_DIR}/xlib")
string(REPLACE ";" "$<SEMICOLON>" TCL_INC "${TCL_INCLUDE_PATH}")
string(REPLACE ";" "$<SEMICOLON>" TK_INC "${TK_INCLUDE_PATH}")
ExternalProject_Add(project_tkdnd
URL "http://sourceforge.net/projects/tkdnd/files/TkDND/TkDND%202.8/tkdnd2.8-src.tar.gz"
URL_MD5 a6d47a996ea957416469b12965d4db91
DEPENDS project_tcl project_tk
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
PATCH_COMMAND patch < ${CMAKE_CURRENT_LIST_DIR}/tkdnd_macosx.patch
UPDATE_COMMAND "" # Disable update
BUILD_IN_SOURCE 1
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/Contents/MacOS
-DTCL_INCLUDE_PATH=${TCL_INC}
-DTK_INCLUDE_PATH=${TK_INC}
-DTK_LIBRARY=${TK_LIBRARY}
-DTCL_LIBRARY=${TCL_LIBRARY}
LOG_DOWNLOAD 1
LOG_CONFIGURE 1
LOG_BUILD 1
LOG_INSTALL 1
set(tcl_prefix ${CMAKE_INSTALL_PREFIX})
# URL "http://sourceforge.net/projects/tcl/files/Tcl/8.6.9/tcl8.6.9-src.tar.gz"
# URL_MD5 aa0a121d95a0e7b73a036f26028538d4
ExternalProject_Add(project_tcl
URL "https://github.com/NGSolve/tcl/archive/7769161.zip"
URL_MD5 1131f188dd26944df557913c475d43b4
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
UPDATE_COMMAND ""
CONFIGURE_COMMAND ../project_tcl/macosx/configure --enable-threads --enable-framework --prefix=${tcl_prefix} --libdir=${tcl_prefix}/Contents/Frameworks --bindir=${tcl_prefix}/Contents/Frameworks/Tcl.framework/bin
BUILD_COMMAND make -j4 binaries libraries
INSTALL_COMMAND make install-binaries install-headers install-libraries install-private-headers
${SUBPROJECT_ARGS}
)
list(APPEND NETGEN_DEPENDENCIES project_tkdnd)
else()
find_package(TCL 8.5 REQUIRED)
endif()
# URL "http://sourceforge.net/projects/tcl/files/Tcl/8.6.9/tk8.6.9.1-src.tar.gz"
# URL_MD5 9efe3976468352dc894dae0c4e785a8e
ExternalProject_Add(project_tk
DEPENDS project_tcl
URL "https://github.com/NGSolve/tk/archive/e7c2bc7.zip"
URL_MD5 94044140d4826069c22f1c60cedb6e59
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
UPDATE_COMMAND ""
CONFIGURE_COMMAND ../project_tk/macosx/configure --enable-aqua=yes --enable-threads --enable-framework --prefix=${tcl_prefix} --libdir=${tcl_prefix}/Contents/Frameworks --bindir=${tcl_prefix}/Contents/Frameworks/Tcl.framework/bin --with-tcl=${tcl_prefix}/Contents/Frameworks/Tcl.framework
BUILD_COMMAND make -j4 binaries libraries
INSTALL_COMMAND make install-binaries install-headers install-libraries install-private-headers
${SUBPROJECT_ARGS}
)
ExternalProject_Add(project_tkdnd
URL "http://sourceforge.net/projects/tkdnd/files/TkDND/TkDND%202.8/tkdnd2.8-src.tar.gz"
URL_MD5 a6d47a996ea957416469b12965d4db91
DEPENDS project_tcl project_tk
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
PATCH_COMMAND patch < ${CMAKE_CURRENT_LIST_DIR}/tkdnd_macosx.patch
UPDATE_COMMAND "" # Disable update
BUILD_IN_SOURCE 1
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/Contents/MacOS
-DTCL_INCLUDE_PATH=${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tcl.framework/Headers
-DTK_INCLUDE_PATH=${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tk.framework/Headers
${SUBPROJECT_ARGS}
)
list(APPEND NETGEN_DEPENDENCIES project_tcl project_tk project_tkdnd)
list(APPEND CMAKE_PREFIX_PATH ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks)
set(TCL_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tcl.framework/Headers)
set(TCL_LIBRARY ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tcl.framework)
set(TK_LIBRARY ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tk.framework)
set(TK_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tk.framework/Headers)
set(TCL_STUB_LIBRARY ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tcl.framework/libtclstub8.6.a)
set(TK_STUB_LIBRARY ${CMAKE_INSTALL_PREFIX}/Contents/Frameworks/Tk.framework/libtkstub8.6.a)
# # use system tcl/tk
# if((${PYTHON_VERSION_STRING} VERSION_EQUAL "3.7") OR (${PYTHON_VERSION_STRING} VERSION_GREATER "3.7"))
# # fetch tcl/tk sources to match the one used in Python 3.7
# ExternalProject_Add(project_tcl
# URL "https://prdownloads.sourceforge.net/tcl/tcl8.6.8-src.tar.gz"
# URL_MD5 81656d3367af032e0ae6157eff134f89
# DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
# UPDATE_COMMAND "" # Disable update
# CONFIGURE_COMMAND ""
# BUILD_COMMAND ""
# INSTALL_COMMAND ""
# )
# ExternalProject_Add(project_tk
# URL "https://prdownloads.sourceforge.net/tcl/tk8.6.8-src.tar.gz"
# URL_MD5 5e0faecba458ee1386078fb228d008ba
# DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
# UPDATE_COMMAND "" # Disable update
# CONFIGURE_COMMAND ""
# BUILD_COMMAND ""
# INSTALL_COMMAND ""
# )
#
# get_filename_component(PYTHON_LIB_DIR ${PYTHON_LIBRARY} DIRECTORY)
# find_library(TCL_LIBRARY libtcl8.6.dylib PATHS ${PYTHON_LIB_DIR} NO_DEFAULT_PATH)
# find_library(TK_LIBRARY libtk8.6.dylib PATHS ${PYTHON_LIB_DIR} NO_DEFAULT_PATH)
#
# set(TCL_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tcl)
# set(TK_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/src/project_tk)
# set(TCL_INCLUDE_PATH "${TCL_DIR}/generic;${TCL_DIR}/macosx")
# set(TK_INCLUDE_PATH "${TK_DIR}/generic;${TK_DIR}/macosx;${TK_DIR}/xlib")
# string(REPLACE ";" "$<SEMICOLON>" TCL_INC "${TCL_INCLUDE_PATH}")
# string(REPLACE ";" "$<SEMICOLON>" TK_INC "${TK_INCLUDE_PATH}")
#
# ExternalProject_Add(project_tkdnd
# URL "http://sourceforge.net/projects/tkdnd/files/TkDND/TkDND%202.8/tkdnd2.8-src.tar.gz"
# URL_MD5 a6d47a996ea957416469b12965d4db91
# DEPENDS project_tcl project_tk
# DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies
# PATCH_COMMAND patch < ${CMAKE_CURRENT_LIST_DIR}/tkdnd_macosx.patch
# UPDATE_COMMAND "" # Disable update
# BUILD_IN_SOURCE 1
# CMAKE_ARGS
# -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}/Contents/MacOS
# -DTCL_INCLUDE_PATH=${TCL_INC}
# -DTK_INCLUDE_PATH=${TK_INC}
# -DTK_LIBRARY=${TK_LIBRARY}
# -DTCL_LIBRARY=${TCL_LIBRARY}
# LOG_DOWNLOAD 1
# LOG_CONFIGURE 1
# LOG_BUILD 1
# LOG_INSTALL 1
# )
#
# list(APPEND NETGEN_DEPENDENCIES project_tkdnd)
# else()
# find_package(TCL 8.5 REQUIRED)
# endif()
elseif(WIN32)
@ -66,13 +184,15 @@ elseif(WIN32)
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX}
LOG_DOWNLOAD 1
${SUBPROJECT_ARGS}
)
set (TK_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/include)
set (TCL_INCLUDE_PATH ${CMAKE_INSTALL_PREFIX}/include)
set (TCL_LIBRARY ${CMAKE_INSTALL_PREFIX}/lib/tcl86t.lib)
set (TK_LIBRARY ${CMAKE_INSTALL_PREFIX}/lib/tk86t.lib)
set (TCL_STUB_LIBRARY ${CMAKE_INSTALL_PREFIX}/lib/tclstub86.lib)
set (TK_STUB_LIBRARY ${CMAKE_INSTALL_PREFIX}/lib/tkstub86.lib)
list(APPEND NETGEN_DEPENDENCIES project_win_tcltk)
else(WIN32)
@ -89,6 +209,8 @@ else(WIN32)
# )
# list(APPEND NETGEN_DEPENDENCIES project_tkdnd)
endif(APPLE)
endif(SKBUILD)
endif(LINUX)
# Propagate settings to Netgen subproject
set_vars(NETGEN_CMAKE_ARGS TCL_INCLUDE_PATH TCL_LIBRARY TK_LIBRARY TK_INCLUDE_PATH TCL_TCLSH TK_WISH)
set_vars(NETGEN_CMAKE_ARGS TCL_INCLUDE_PATH TCL_STUB_LIBRARY TCL_LIBRARY TK_STUB_LIBRARY TK_LIBRARY TK_INCLUDE_PATH TCL_TCLSH TK_WISH)

View File

@ -1,6 +1,8 @@
--- CMakeLists.txt 19:24:32.000000000 +0200
+++ CMakeLists.txt 2018-12-05 11:34:59.000000000 +0100
@@ -43,17 +43,18 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4eb497c..cd22a67 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -43,17 +43,18 @@ IF ( WIN32 )
ELSE ( WIN32 )
## Unix and OS X...
IF ( APPLE )
@ -24,7 +26,7 @@
ADD_DEFINITIONS ( -fno-objc-arc )
# ADD_DEFINITIONS ( -fobjc-arc )
LINK_LIBRARIES ( ${COCOA_LIBRARY} )
@@ -125,8 +126,8 @@
@@ -125,8 +126,8 @@ SET ( CP ${CMAKE_COMMAND} -E copy )
## Locate Tcl/Tk
## ===========================================================================
MESSAGE ( STATUS "Searching for Tcl/Tk..." )
@ -35,7 +37,7 @@
## Tcl/Tk info (useful for debug purposes)...
# MESSAGE ( STATUS " TCL_TCLSH: " ${TCL_TCLSH} )
@@ -139,13 +140,13 @@
@@ -139,13 +140,14 @@ FIND_PACKAGE ( TclStub REQUIRED )
# MESSAGE ( STATUS " TK_LIBRARY: " ${TK_LIBRARY} )
## Enable Tcl/Tk stubs globally...
@ -48,8 +50,9 @@
INCLUDE_DIRECTORIES ( ${TK_INCLUDE_PATH} )
-LINK_LIBRARIES ( ${TCL_STUB_LIBRARY} )
-LINK_LIBRARIES ( ${TK_STUB_LIBRARY} )
+LINK_LIBRARIES ( ${TCL_LIBRARY} )
+LINK_LIBRARIES ( ${TK_LIBRARY} )
+#LINK_LIBRARIES ( ${TCL_LIBRARY} )
+#LINK_LIBRARIES ( ${TK_LIBRARY} )
+SET ( CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -undefined dynamic_lookup" )
IF ( WIN32 AND NO_MSVCRT )
STRING ( REPLACE /MD /MT CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} )

View File

@ -0,0 +1,111 @@
if(NOT BDIR)
set(BDIR ${CMAKE_CURRENT_BINARY_DIR})
endif()
if(NETGEN_VERSION_GIT)
set(git_version_string ${NETGEN_VERSION_GIT})
else()
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 OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()
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(STRIP ${git_version_string} git_version_string)
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})
if(NOT NETGEN_VERSION_GIT)
set(NETGEN_VERSION_GIT ${NETGEN_VERSION_LONG})
endif()
if(NOT NETGEN_VERSION_PYTHON)
set(NETGEN_VERSION_PYTHON ${NETGEN_VERSION_TWEAK})
endif()
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___
")

282
doc/element_types.tex Normal file
View File

@ -0,0 +1,282 @@
\documentclass[convert=pdf2svg]{standalone}
% \documentclass{article}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\renewcommand{\familydefault}{\sfdefault}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usetikzlibrary{external}
\tikzset{external/force remake}
\tikzset{external/disable dependency files}
\tikzset{external/aux in dpth={false}}
% uncomment this to generate a figure for each cell type (and change documentclass to article)
% \tikzexternalize
\tikzstyle{vertex} = [circle,draw=black,fill=black,scale = 0.5]
\tdplotsetmaincoords{70}{110}
% cnode(tag,x,y,z,label,label_pos)
\def\cnode(#1,#2,#3,#4,#5,#6){
\node (#1) at (#2,#3,#4) [vertex,label=#6:$\mathsf{#5}$] {};
}
\pagestyle{empty}
\begin{document}
\begin{tabular}{cc}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SEGMENT &
SEGMENT3
\\
\tikzsetnextfilename{line}
\begin{tikzpicture}[scale = 2]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,2,below right);
\draw (n0) -- (n1);
\end{tikzpicture}
&
\tikzsetnextfilename{line3}
\begin{tikzpicture}[scale = 2]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,2,below right);
\cnode(n2,1,0,0,3,below right);
\draw (n0) -- (n2) -- (n1);
\end{tikzpicture}
\\[1 em]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
TRIG &
TRIG6
\\
\tikzsetnextfilename{triangle}
\begin{tikzpicture}[scale = 2]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,2,below right);
\cnode(n2,0,2,0,3,right);
\draw (n0) -- (n1) -- (n2) -- (n0);
\end{tikzpicture}
&
\tikzsetnextfilename{triangle6}
\begin{tikzpicture}[scale = 2]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,2,below right);
\cnode(n2,0,2,0,3,right);
\cnode(n3,1,0,0,6,below right);
\cnode(n4,1,1,0,4,right);
\cnode(n5,0,1,0,5,below right);
\draw (n0) -- (n3) -- (n1) -- (n4) -- (n2) -- (n5) -- (n0);
\end{tikzpicture}
\\[1 em]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
QUAD &
QUAD8
\\
\tikzsetnextfilename{quad}
\begin{tikzpicture}[scale = 2]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,2,below right);
\cnode(n2,2,2,0,3,below right);
\cnode(n3,0,2,0,4,below right);
\draw (n0) -- (n1) -- (n2) -- (n3) -- (n0);
\end{tikzpicture}
&
\tikzsetnextfilename{quad8}
\begin{tikzpicture}[scale = 2]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,2,below right);
\cnode(n2,2,2,0,3,below right);
\cnode(n3,0,2,0,4,below right);
\cnode(n4,1,0,0,5,below right);
\cnode(n5,2,1,0,8,below right);
\cnode(n6,1,2,0,6,below right);
\cnode(n7,0,1,0,7,below right);
\draw (n0) -- (n4) -- (n1) -- (n5) -- (n2) -- (n6) -- (n3) -- (n7) -- (n0);
\end{tikzpicture}
\\[1 em]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
TET &
TET10
\\
\tikzsetnextfilename{tetra}
\begin{tikzpicture}[scale = 2, tdplot_main_coords]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,3,below right);
\cnode(n2,0,2,0,2,below right);
\cnode(n3,0,0,2,4,right);
\draw (n0) -- (n1) -- (n2) -- (n0);
\draw (n0) -- (n3);
\draw (n1) -- (n3);
\draw (n2) -- (n3);
\end{tikzpicture}
&
\tikzsetnextfilename{tetra10} % VTK
\begin{tikzpicture}[scale = 2, tdplot_main_coords]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,3,below right);
\cnode(n2,0,2,0,2,below right);
\cnode(n3,0,0,2,4,right);
\cnode(n4,1,0,0,6,below right);
\cnode(n5,1,1,0,8,below right);
\cnode(n6,0,1,0,5,below right);
\cnode(n7,0,0,1,7,below right);
\cnode(n8,1,0,1,10,below right);
\cnode(n9,0,1,1,9,right);
\draw (n0) -- (n4) -- (n1) -- (n5) -- (n2) -- (n6) -- (n0);
\draw (n0) -- (n7) -- (n3);
\draw (n1) -- (n8) -- (n3);
\draw (n2) -- (n9) -- (n3);
\end{tikzpicture}
\\[1 em]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
PYRAMID &
PYRAMID13
\\
\tikzsetnextfilename{pyramid}
\begin{tikzpicture}[scale = 2, tdplot_main_coords]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,4,below right);
\cnode(n2,2,2,0,3,below right);
\cnode(n3,0,2,0,2,below right);
\cnode(n4,1,1,2,5,right);
\draw (n0) -- (n1) -- (n2) -- (n3) -- (n0);
\draw (n0) -- (n4);
\draw (n1) -- (n4);
\draw (n2) -- (n4);
\draw (n3) -- (n4);
\end{tikzpicture}
&
\tikzsetnextfilename{pyramid13} % VTK != gmsh
\begin{tikzpicture}[scale = 2, tdplot_main_coords]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,4,below right);
\cnode(n2,2,2,0,3,below right);
\cnode(n3,0,2,0,2,below right);
\cnode(n4,1,1,2,5,right);
\cnode(n5,1,0,0,8,below right);
\cnode(n6,2,1,0,7,below right);
\cnode(n7,1,2,0,9,below right);
\cnode(n8,0,1,0,6,below right);
\cnode(n9,0.5,0.5,1,10,below right);
\cnode(n10,1.5,0.5,1,13,below right);
\cnode(n11,1.5,1.5,1,12,below right);
\cnode(n12,0.5,1.5,1,11,right);
\draw (n0) -- (n5) -- (n1) -- (n6) -- (n2) -- (n7) -- (n3) -- (n8) -- (n0);
\draw (n0) -- (n9) -- (n4);
\draw (n1) -- (n10) -- (n4);
\draw (n2) -- (n11) -- (n4);
\draw (n3) -- (n12) -- (n4);
\end{tikzpicture}
\\[1 em]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
PRISM &
PRISM15
\\
\tikzsetnextfilename{wedge} % gmsh != VTK
\begin{tikzpicture}[scale = 2, tdplot_main_coords]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,3,below right);
\cnode(n2,0,2,0,2,below right);
\cnode(n3,0,0,2,4,below right);
\cnode(n4,2,0,2,6,below right);
\cnode(n5,0,2,2,5,below right);
\draw (n0) -- (n1) -- (n2) -- (n0);
\draw (n3) -- (n4) -- (n5) -- (n3);
\draw (n0) -- (n3);
\draw (n1) -- (n4);
\draw (n2) -- (n5);
\end{tikzpicture}
&
\tikzsetnextfilename{wedge15} % VTK != gmsh
\begin{tikzpicture}[scale = 2, tdplot_main_coords]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,3,below right);
\cnode(n2,0,2,0,2,below right);
\cnode(n3,0,0,2,4,below right);
\cnode(n4,2,0,2,6,below right);
\cnode(n5,0,2,2,5,below right);
\cnode(n6,1,0,0,8,below right);
\cnode(n7,1,1,0,9,below right);
\cnode(n8,0,1,0,7,below right);
\cnode(n9,1,0,2,14,below right);
\cnode(n10,1,1,2,15,below right);
\cnode(n11,0,1,2,13,below right);
\cnode(n12,0,0,1,10,below right);
\cnode(n13,2,0,1,12,below right);
\cnode(n14,0,2,1,11,below right);
\draw (n0) -- (n6) -- (n1) -- (n7) -- (n2) -- (n8) -- (n0);
\draw (n3) -- (n9) -- (n4) -- (n10) -- (n5) -- (n11) -- (n3);
\draw (n0) -- (n12) -- (n3);
\draw (n1) -- (n13) -- (n4);
\draw (n2) -- (n14) -- (n5);
\end{tikzpicture}
\\[1 em]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
HEX &
HEX20
\\
\tikzsetnextfilename{hexahedron}
\begin{tikzpicture}[scale = 2, tdplot_main_coords]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,4,below right);
\cnode(n2,2,2,0,3,below right);
\cnode(n3,0,2,0,2,below right);
\cnode(n4,0,0,2,5,below right);
\cnode(n5,2,0,2,8,below right);
\cnode(n6,2,2,2,7,below right);
\cnode(n7,0,2,2,6,below right);
\draw (n0) -- (n1) -- (n2) -- (n3) -- (n0);
\draw (n4) -- (n5) -- (n6) -- (n7) -- (n4);
\draw (n0) -- (n4);
\draw (n1) -- (n5);
\draw (n2) -- (n6);
\draw (n3) -- (n7);
\end{tikzpicture}
&
\tikzsetnextfilename{hexahedron20} % VTK != gmsh
\begin{tikzpicture}[scale = 2, tdplot_main_coords]
\cnode(n0,0,0,0,1,below right);
\cnode(n1,2,0,0,4,below right);
\cnode(n2,2,2,0,3,below right);
\cnode(n3,0,2,0,2,below right);
\cnode(n4,0,0,2,5,below right);
\cnode(n5,2,0,2,8,below right);
\cnode(n6,2,2,2,7,below right);
\cnode(n7,0,2,2,6,below right);
\cnode(n8,1,0,0,11,below right);
\cnode(n9,2,1,0,10,below right);
\cnode(n10,1,2,0,12,below right);
\cnode(n11,0,1,0,9,below right);
\cnode(n12,1,0,2,15,below right);
\cnode(n13,2,1,2,14,below right);
\cnode(n14,1,2,2,16,below right);
\cnode(n15,0,1,2,13,below right);
\cnode(n16,0,0,1,17,below right);
\cnode(n17,2,0,1,20,below right);
\cnode(n18,2,2,1,19,below right);
\cnode(n19,0,2,1,18,below right);
\draw (n0) -- (n8) -- (n1) -- (n9) -- (n2) -- (n10) -- (n3) -- (n11) -- (n0);
\draw (n4) -- (n12) -- (n5) -- (n13) -- (n6) -- (n14) -- (n7) -- (n15) -- (n4);
\draw (n0) -- (n16) -- (n4);
\draw (n1) -- (n17) -- (n5);
\draw (n2) -- (n18) -- (n6);
\draw (n3) -- (n19) -- (n7);
\end{tikzpicture}
\end{tabular}
\end{document}

View File

@ -176,7 +176,7 @@ Lines starting with $\#$ are comment lines. Every CSG file must contain the
keyword {\tt algebraic3d} before any non-comment line.
The keyword {\tt solid} defines a named solid, here the solid {\it cube}
is defined. A solid is defined by the Eulerian operations applied to
primitives. Here, the solid is just the primitve defined by {\tt orthobrick}.
primitives. Here, the solid is just the primitive defined by {\tt orthobrick}.
This is a brick parallel to the axis, specified by the minimal $x$, $y$, and
$z$ coordinates, and the maximal $x$, $y$, and $z$ coordinates. The present
definition gives the cube $[0,1]^3$. Finally, the definition {\tt tlo cube}
@ -260,7 +260,7 @@ amount of red, green and blue (RGB) values. The flag {\tt
-transparent} makes the solid appear transparent.
It is possible to specify bounday condition numbers for individual
It is possible to specify boundary condition numbers for individual
surfaces of a solid. The flag {\tt -bc} assigns the bc to all
surfaces of that solid-tree. If several flags are given the one closest
to the leaves of the tree dominates. The following file defines a
@ -536,7 +536,7 @@ STL is a standardized file format to describe (approximate) geometies
by triangulated surfaces. It is useful to describe complicated parts
which are modeled with some CAD programmes. Also, some users have written
their own (C) programmes to define STL geometries, where was not so easy
to use the CSG format. The syntac of STL files is as follos
to use the CSG format. The syntax of STL files is as follows
\begin{quote}
(not available yet. please figure out the syntax from the examples)
\end{quote}
@ -593,10 +593,10 @@ Finally, the refinement factor along the line follows.
\chapter{Mesh and Solution Formats}
You can export meshes to a couple of file formats. Some are self-defined,
some other are standard formats. The self-defined are the followings:
some other are standard formats. The self-defined are the following:
\section{Mesh Size File}
By means of a mesh size file you can provide a local mesh size density. The file extension must be {\it .msz}. If you want to use the mesh size file, you specify it in the ``Meshing Options'', doalog box, page ``Mesh Size''.
By means of a mesh size file you can provide a local mesh size density. The file extension must be {\it .msz}. If you want to use the mesh size file, you specify it in the ``Meshing Options'', dialog box, page ``Mesh Size''.
The syntay is:
\begin{verbatim}
@ -643,7 +643,7 @@ The Fepp 2D format contains the following sections:
\begin{enumerate}
\item
boundary segmetns \\
boundary segments \\
After the number of boundary segments there follows a list of
segments. Each segment is specified by the spline - patch number,
and the two node indices. Counting starts with 1
@ -749,7 +749,7 @@ the bottom, and the large drawing window. The menu items will be explained in
\item Quit \newline
Terminate Netgen
\item Generate mesh \newline
Performe mesh generation
Perform mesh generation
\item Stop Meshing \newline
Stop mesh generation
\item Geometry/Edges/Mesh/Solution \newline

@ -1 +1 @@
Subproject commit 2a150736601bb3113877bb673fb934bb60d46ec5
Subproject commit 80dc998efced8ceb2be59756668a7e90e8bef917

View File

@ -4,10 +4,21 @@ add_subdirectory(gprim)
add_subdirectory(linalg)
add_subdirectory(include)
add_subdirectory(meshing)
add_subdirectory(visualization)
add_subdirectory(csg)
add_subdirectory(geom2d)
add_subdirectory(occ)
add_subdirectory(stlgeom)
add_subdirectory(interface)
if(USE_OCC)
add_subdirectory(occ)
endif(USE_OCC)
if(USE_STLGEOM)
add_subdirectory(stlgeom)
endif(USE_STLGEOM)
if(USE_GUI)
add_subdirectory(visualization)
endif(USE_GUI)
if(USE_INTERFACE)
add_subdirectory(interface)
endif(USE_INTERFACE)
if(USE_CSG)
add_subdirectory(csg)
endif(USE_CSG)
if(USE_GEOM2D)
add_subdirectory(geom2d)
endif(USE_GEOM2D)

View File

@ -1,5 +1,8 @@
Checks: '*,-clang-analyzer-alpha.*,-*braces-around-statements,-fuchsia-*,-google-runtime-references,-readability-implicit-bool-conversion,-google-explicit-constructor,-hicpp-explicit-conversions,-google-runtime-int,-llvm-header-guard,-modernize-pass-by-value'
Checks: '*,-clang-analyzer-alpha.*,-*braces-around-statements,-fuchsia-*,-google-runtime-references,-readability-implicit-bool-conversion,-google-explicit-constructor,-hicpp-explicit-conversions,-google-runtime-int,-llvm-header-guard,-modernize-pass-by-value,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-readability-magic-numbers,-cppcoreguidelines-avoid-magic-numbers'
CheckOptions:
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
value: 1
- key: cppcoreguidelines-macro-usage.AllowedRegexp
value: NGCORE_*|NETGEN_*|NG_EXCEPTION*
WarningsAsErrors: '*'

View File

@ -1,17 +1,54 @@
add_library(ngcore SHARED archive.cpp logging.cpp paje_trace.cpp utils.cpp profiler.cpp)
add_library(ngcore ${NGCORE_LIBRARY_TYPE}
archive.cpp
bitarray.cpp
exception.cpp
localheap.cpp
logging.cpp
flags.cpp
paje_trace.cpp
profiler.cpp
table.cpp
taskmanager.cpp
utils.cpp
version.cpp
)
string(REPLACE "|" ";" ng_compile_flags_replace_sep "${NG_COMPILE_FLAGS}")
target_compile_options(ngcore PUBLIC ${ng_compile_flags_replace_sep})
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)
target_link_libraries(ngcore PUBLIC stdc++fs)
endif()
if(USE_PYTHON)
target_sources(ngcore PRIVATE python_ngcore.cpp)
target_compile_definitions(ngcore PUBLIC NETGEN_PYTHON NG_PYTHON PYBIND11_SIMPLE_GIL_MANAGEMENT)
endif(USE_PYTHON)
if(WIN32)
target_compile_options(ngcore PUBLIC /bigobj /MP /W1 /wd4068)
get_WIN32_WINNT(ver)
target_compile_definitions(ngcore PUBLIC _WIN32_WINNT=${ver} WNT WNT_WINDOW NOMINMAX MSVC_EXPRESS _CRT_SECURE_NO_WARNINGS HAVE_STRUCT_TIMESPEC WIN32)
target_link_options(ngcore PUBLIC /ignore:4273 /ignore:4217 /ignore:4049)
endif(WIN32)
target_compile_definitions(ngcore PRIVATE NGCORE_EXPORTS)
if(NOT WIN32)
target_compile_options(ngcore PRIVATE -fvisibility=hidden)
endif(NOT WIN32)
target_compile_definitions(ngcore PUBLIC $<$<CONFIG:DEBUG>:NETGEN_ENABLE_CHECK_RANGE>)
target_include_directories(ngcore INTERFACE $<INSTALL_INTERFACE:${NG_INSTALL_DIR_INCLUDE}> $<INSTALL_INTERFACE:${NG_INSTALL_DIR_INCLUDE}/include>)
if(CHECK_RANGE)
target_compile_definitions(ngcore PUBLIC NETGEN_ENABLE_CHECK_RANGE)
endif(CHECK_RANGE)
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG")
target_compile_definitions(ngcore PUBLIC _DEBUG NETGEN_ENABLE_CHECK_RANGE)
endif(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG")
if(TRACE_MEMORY)
target_compile_definitions(ngcore PUBLIC NETGEN_TRACE_MEMORY)
endif(TRACE_MEMORY)
if(USE_SPDLOG)
include_directories(${SPDLOG_INCLUDE_DIR})
install(DIRECTORY ${SPDLOG_INCLUDE_DIR}
@ -24,26 +61,34 @@ 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)
if(USE_PYTHON)
target_compile_definitions(ngcore PUBLIC NETGEN_PYTHON)
target_include_directories(ngcore PUBLIC ${PYTHON_INCLUDE_DIRS})
target_link_libraries(ngcore PUBLIC ${PYTHON_LIBRARIES})
endif(USE_PYTHON)
target_link_libraries(ngcore PUBLIC netgen_mpi PRIVATE "$<BUILD_INTERFACE:netgen_python>" ${CMAKE_THREAD_LIBS_INIT})
install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp
install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp memtracer.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 ranges.hpp ngstream.hpp
simd.hpp simd_avx.hpp simd_avx512.hpp simd_generic.hpp simd_sse.hpp simd_arm64.hpp
register_archive.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.cpp)
target_link_libraries(pyngcore PUBLIC ngcore ${PYTHON_LIBRARIES})
set_target_properties(pyngcore PROPERTIES INSTALL_RPATH "${NG_RPATH_TOKEN}/${NETGEN_PYTHON_RPATH}")
install(TARGETS pyngcore DESTINATION ${NG_INSTALL_DIR_PYTHON} COMPONENT netgen)
pybind11_add_module(pyngcore SHARED python_ngcore_export.cpp)
target_link_libraries(pyngcore PUBLIC ngcore netgen_python)
set_target_properties(pyngcore PROPERTIES INSTALL_RPATH "${NG_RPATH_TOKEN}/../${NETGEN_PYTHON_RPATH}")
install(TARGETS pyngcore DESTINATION ${NG_INSTALL_DIR_PYTHON}/pyngcore COMPONENT netgen)
endif(USE_PYTHON)

View File

@ -1,5 +1,7 @@
#include "archive.hpp"
#include "register_archive.hpp"
#include "version.hpp"
#ifndef WIN32
#include <cxxabi.h>
@ -7,18 +9,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)
@ -39,4 +29,13 @@ namespace ngcore
std::make_unique<std::map<std::string, detail::ClassArchiveInfo>>();
return type_register->count(classname) != 0;
}
#ifdef NETGEN_PYTHON
pybind11::object CastAnyToPy(const std::any& a)
{
auto info = Archive::GetArchiveRegister(Demangle(a.type().name()));
return info.anyToPyCaster(a);
}
#endif // NETGEN_PYTHON
} // namespace ngcore

View File

@ -1,14 +1,19 @@
#ifndef NETGEN_CORE_ARCHIVE_HPP
#define NETGEN_CORE_ARCHIVE_HPP
#include <any>
#include <array> // for array
#include <complex> // for complex
#include <cstring> // for size_t, strlen
#include <filesystem> // for path
#include <fstream> // for ifstream, ofstream
#include <functional> // for function
#include <map> // for map
#include <memory> // for shared_ptr
#include <optional> // for optional
#include <string> // for string
#include <type_traits> // for declval, enable_if_t, false_type, is_co...
#include <cstddef> // for std::byte
#include <typeinfo> // for type_info
#include <utility> // for move, swap, pair
#include <vector> // for vector
@ -21,17 +26,20 @@
#include "version.hpp" // for VersionInfo
#ifdef NETGEN_PYTHON
#include <pybind11/pybind11.h>
namespace pybind11
{
class object;
}
#endif // NETGEN_PYTHON
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);
#ifdef NETGEN_PYTHON
pybind11::object CastAnyToPy(const std::any& a);
#endif // NETGEN_PYTHON
class NGCORE_API Archive;
namespace detail
{
// create new pointer of type T if it is default constructible, else throw
@ -86,12 +94,27 @@ namespace ngcore
// This caster takes a void* pointer to the (base)class type_info and returns void* pointing
// to the type stored in this info
std::function<void*(const std::type_info&, void*)> downcaster;
#ifdef NETGEN_PYTHON
std::function<pybind11::object(const std::any&)> anyToPyCaster;
#endif // NETGEN_PYTHON
};
} // namespace detail
template<typename T>
constexpr bool is_archivable = detail::is_Archivable_struct<T>::value;
template <typename T, typename ... Trest>
constexpr size_t TotSize ()
{
if constexpr (sizeof...(Trest) == 0)
return sizeof(T);
else
return sizeof(T) + TotSize<Trest...> ();
}
// Base Archive class
class NGCORE_API Archive
{
@ -108,6 +131,9 @@ namespace ngcore
std::map<std::string, VersionInfo> version_map = GetLibraryVersions();
std::shared_ptr<Logger> logger = GetLogger("Archive");
public:
template<typename T>
static constexpr bool is_archivable = detail::is_Archivable_struct<T>::value;
Archive() = delete;
Archive(const Archive&) = delete;
Archive(Archive&&) = delete;
@ -120,28 +146,23 @@ namespace ngcore
// once and put them together correctly afterwards. Therefore all objects that may live in
// Python should be archived using this Shallow function. If Shallow is called from C++ code
// it archives the object normally.
#ifdef NETGEN_PYTHON
template<typename T>
Archive& Shallow(T& val); // implemented in python_ngcore.hpp
#else // NETGEN_PYTHON
template<typename T>
Archive& Shallow(T& val)
{
static_assert(detail::is_any_pointer<T>, "ShallowArchive must be given pointer type!");
#ifdef NETGEN_PYTHON
if(shallow_to_python)
{
if(is_output)
ShallowOutPython(pybind11::cast(val));
else
val = pybind11::cast<T>(ShallowInPython());
}
else
#endif // NETGEN_PYTHON
*this & val;
return *this;
}
#endif // NETGEN_PYTHON
#ifdef NETGEN_PYTHON
virtual void ShallowOutPython(const pybind11::object& /*unused*/)
{ throw UnreachableCodeException{}; }
virtual pybind11::object ShallowInPython()
virtual void ShallowInPython(pybind11::object &)
{ throw UnreachableCodeException{}; }
#endif // NETGEN_PYTHON
@ -157,6 +178,8 @@ 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 & (std::byte & d) = 0;
virtual Archive & operator & (float & d) = 0;
virtual Archive & operator & (double & d) = 0;
virtual Archive & operator & (int & i) = 0;
virtual Archive & operator & (long & i) = 0;
@ -208,7 +231,7 @@ namespace ngcore
Do(&v[0], size);
return (*this);
}
// archive implementation for enums
template<typename T>
auto operator & (T& val) -> std::enable_if_t<std::is_enum<T>::value, Archive&>
@ -272,12 +295,33 @@ namespace ngcore
}
return (*this);
}
template<typename T>
Archive& operator& (std::optional<T>& opt)
{
bool has_value = opt.has_value();
(*this) & has_value;
if(has_value)
{
if(Output())
(*this) << *opt;
else
{
T value;
(*this) & value;
opt = value;
}
}
return (*this);
}
// Archive arrays =====================================================
// this functions can be overloaded in Archive implementations for more efficiency
template <typename T, typename = std::enable_if_t<is_archivable<T>>>
Archive & Do (T * data, size_t n)
{ for (size_t j = 0; j < n; j++) { (*this) & data[j]; }; return *this; }; // NOLINT
virtual Archive & Do (std::byte * d, size_t n)
{ for (size_t j = 0; j < n; j++) { (*this) & d[j]; }; return *this; }; // NOLINT
virtual Archive & Do (double * d, size_t n)
{ for (size_t j = 0; j < n; j++) { (*this) & d[j]; }; return *this; }; // NOLINT
@ -306,6 +350,55 @@ namespace ngcore
val.DoArchive(*this); return *this;
}
// pack elements to binary
template <typename ... Types>
Archive & DoPacked (Types & ... args)
{
if (true) // (isbinary)
{
constexpr size_t totsize = TotSize<Types...>(); // (args...);
std::byte mem[totsize];
if (is_output)
{
CopyToBin (&mem[0], args...);
Do(&mem[0], totsize);
}
else
{
Do(&mem[0], totsize);
CopyFromBin (&mem[0], args...);
}
}
// else
// cout << "DoPacked of non-binary called --> individual pickling" << endl;
return *this;
}
template <typename T, typename ... Trest>
constexpr void CopyToBin (std::byte * ptr, T & first, Trest & ...rest) const
{
memcpy (ptr, &first, sizeof(first));
CopyToBin(ptr+sizeof(first), rest...);
}
constexpr void CopyToBin (std::byte * ptr) const { }
template <typename T, typename ... Trest>
constexpr void CopyFromBin (std::byte * ptr, T & first, Trest & ...rest) const
{
memcpy (&first, ptr, sizeof(first));
CopyFromBin(ptr+sizeof(first), rest...);
}
constexpr void CopyFromBin (std::byte * ptr) const { }
// Archive shared_ptrs =================================================
template <typename T>
Archive& operator & (std::shared_ptr<T>& ptr)
@ -376,7 +469,7 @@ namespace ngcore
// -1 restores a new shared ptr by restoring the inner pointer and creating a shared_ptr to it
if (nr == -1)
{
logger->debug("Createing new shared_ptr");
logger->debug("Creating new shared_ptr");
T* p = nullptr;
bool neededDowncast;
(*this) & neededDowncast & p;
@ -571,13 +664,18 @@ 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>
friend class RegisterClassForArchive;
#ifdef NETGEN_PYTHON
friend pybind11::object CastAnyToPy(const std::any&);
#endif // NETGEN_PYTHON
// Returns ClassArchiveInfo of Demangled typeid
static const detail::ClassArchiveInfo& GetArchiveRegister(const std::string& classname);
// Set ClassArchiveInfo for Demangled typeid, this is done by creating an instance of
@ -631,33 +729,11 @@ namespace ngcore
};
};
template<typename T, typename ... Bases>
class RegisterClassForArchive
{
public:
RegisterClassForArchive()
{
static_assert(detail::all_of_tmpl<std::is_base_of<Bases,T>::value...>,
"Variadic template arguments must be base classes of T");
detail::ClassArchiveInfo info {};
info.creator = [this,&info](const std::type_info& ti) -> void*
{ return typeid(T) == ti ? detail::constructIfPossible<T>()
: Archive::Caster<T, Bases...>::tryUpcast(ti, detail::constructIfPossible<T>()); };
info.upcaster = [this](const std::type_info& ti, void* p) -> void*
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases...>::tryUpcast(ti, static_cast<T*>(p)); };
info.downcaster = [this](const std::type_info& ti, void* p) -> void*
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases...>::tryDowncast(ti, p); };
Archive::SetArchiveRegister(std::string(Demangle(typeid(T).name())),info);
}
};
// BinaryOutArchive ======================================================================
class NGCORE_API BinaryOutArchive : public Archive
{
static constexpr size_t BUFFERSIZE = 1024;
char buffer[BUFFERSIZE] = {};
std::array<char,BUFFERSIZE> buffer{};
size_t ptr = 0;
protected:
std::shared_ptr<std::ostream> stream;
@ -668,7 +744,7 @@ namespace ngcore
BinaryOutArchive(std::shared_ptr<std::ostream>&& astream)
: Archive(true), stream(std::move(astream))
{ }
BinaryOutArchive(const std::string& filename)
BinaryOutArchive(const std::filesystem::path& filename)
: BinaryOutArchive(std::make_shared<std::ofstream>(filename)) {}
~BinaryOutArchive () override { FlushBuffer(); }
@ -676,6 +752,10 @@ namespace ngcore
BinaryOutArchive& operator=(BinaryOutArchive&&) = delete;
using Archive::operator&;
Archive & operator & (std::byte & d) override
{ return Write(d); }
Archive & operator & (float & f) override
{ return Write(f); }
Archive & operator & (double & d) override
{ return Write(d); }
Archive & operator & (int & i) override
@ -683,13 +763,18 @@ 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
{ return Write(i); }
Archive & operator & (bool & b) override
{ return Write(b); }
Archive & operator & (std::string & str) override
{
int len = str.length();
@ -701,7 +786,7 @@ namespace ngcore
}
Archive & operator & (char *& str) override
{
long len = str ? strlen (str) : -1;
long len = str ? static_cast<long>(strlen (str)) : -1;
(*this) & len;
FlushBuffer();
if(len > 0)
@ -716,19 +801,23 @@ namespace ngcore
ptr = 0;
}
}
Archive & Do (std::byte * d, size_t n) override
{
FlushBuffer();
stream->write(reinterpret_cast<char*>(d), n*sizeof(std::byte)); return *this;
}
private:
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;
}
@ -743,10 +832,14 @@ namespace ngcore
BinaryInArchive (std::shared_ptr<std::istream>&& astream)
: Archive(false), stream(std::move(astream))
{ }
BinaryInArchive (const std::string& filename)
BinaryInArchive (const std::filesystem::path& filename)
: BinaryInArchive(std::make_shared<std::ifstream>(filename)) { ; }
using Archive::operator&;
Archive & operator & (std::byte & d) override
{ Read(d); return *this; }
Archive & operator & (float & f) override
{ Read(f); return *this; }
Archive & operator & (double & d) override
{ Read(d); return *this; }
Archive & operator & (int & i) override
@ -754,7 +847,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
@ -785,6 +883,8 @@ namespace ngcore
return *this;
}
Archive & Do (std::byte * d, size_t n) override
{ stream->read(reinterpret_cast<char*>(d), n*sizeof(std::byte)); return *this; } // NOLINT
Archive & Do (double * d, size_t n) override
{ stream->read(reinterpret_cast<char*>(d), n*sizeof(double)); return *this; } // NOLINT
Archive & Do (int * i, size_t n) override
@ -807,10 +907,14 @@ namespace ngcore
TextOutArchive (std::shared_ptr<std::ostream>&& astream)
: Archive(true), stream(std::move(astream))
{ }
TextOutArchive (const std::string& filename) :
TextOutArchive (const std::filesystem::path& filename) :
TextOutArchive(std::make_shared<std::ofstream>(filename)) { }
using Archive::operator&;
Archive & operator & (std::byte & d) override
{ *stream << std::hex << int(d) << ' '; return *this; }
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
@ -838,7 +942,7 @@ namespace ngcore
}
Archive & operator & (char *& str) override
{
long len = str ? strlen (str) : -1;
long len = str ? static_cast<long>(strlen (str)) : -1;
*this & len;
if(len > 0)
{
@ -858,10 +962,14 @@ namespace ngcore
TextInArchive (std::shared_ptr<std::istream>&& astream) :
Archive(false), stream(std::move(astream))
{ }
TextInArchive (const std::string& filename)
TextInArchive (const std::filesystem::path& filename)
: TextInArchive(std::make_shared<std::ifstream>(filename)) {}
using Archive::operator&;
Archive & operator & (std::byte & d) override
{ int tmp; *stream >> std::hex >> tmp; d = std::byte(tmp); return *this; }
Archive & operator & (float & f) override
{ *stream >> f; return *this; }
Archive & operator & (double & d) override
{ *stream >> d; return *this; }
Archive & operator & (int & i) override
@ -882,6 +990,8 @@ namespace ngcore
*stream >> len;
char ch;
stream->get(ch); // '\n'
if(ch == '\r') // windows line endings -> read \n as well
stream->get(ch);
str.resize(len);
if(len)
stream->get(&str[0], len+1, '\0');
@ -901,6 +1011,8 @@ namespace ngcore
if(len)
{
stream->get(ch); // \n
if(ch == '\r') // windows line endings, read \n as well
stream->get(ch);
stream->get(&str[0], len+1, '\0'); // NOLINT
}
str[len] = '\0'; // NOLINT
@ -908,105 +1020,56 @@ namespace ngcore
}
};
#ifdef NETGEN_PYTHON
// HashArchive =================================================================
// This class enables to easily create hashes for archivable objects by xoring
// threw its data
template<typename ARCHIVE>
class PyArchive : public ARCHIVE
class NGCORE_API HashArchive : public Archive
{
private:
pybind11::list lst;
size_t index = 0;
std::map<std::string, VersionInfo> version_needed;
protected:
using ARCHIVE::stream;
using ARCHIVE::version_map;
using ARCHIVE::logger;
using ARCHIVE::GetLibraryVersions;
size_t hash_value = 0;
char* h;
int offset = 0;
public:
PyArchive(const pybind11::object& alst = pybind11::none()) :
ARCHIVE(std::make_shared<std::stringstream>()),
lst(alst.is_none() ? pybind11::list() : pybind11::cast<pybind11::list>(alst))
HashArchive() : Archive(true)
{ h = (char*)&hash_value; }
using Archive::operator&;
Archive & operator & (std::byte & d) override { return ApplyHash(d); }
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)
{
ARCHIVE::shallow_to_python = true;
if(Input())
size_t n = sizeof(T);
char* pval = (char*)&val;
for(size_t i = 0; i < n; i++)
{
stream = std::make_shared<std::stringstream>
(pybind11::cast<pybind11::bytes>(lst[pybind11::len(lst)-1]));
*this & version_needed;
logger->debug("versions needed for unpickling = {}", version_needed);
for(auto& libversion : version_needed)
if(libversion.second > GetLibraryVersion(libversion.first))
throw Exception("Error in unpickling data:\nLibrary " + libversion.first +
" must be at least " + libversion.second.to_string());
stream = std::make_shared<std::stringstream>
(pybind11::cast<pybind11::bytes>(lst[pybind11::len(lst)-2]));
*this & version_map;
stream = std::make_shared<std::stringstream>
(pybind11::cast<pybind11::bytes>(lst[pybind11::len(lst)-3]));
h[offset++] ^= pval[i];
offset %= 8;
}
}
void NeedsVersion(const std::string& library, const std::string& version) override
{
if(Output())
{
logger->debug("Need version {} of library {}.", version, library);
version_needed[library] = version_needed[library] > version ? version_needed[library] : version;
}
}
using ARCHIVE::Output;
using ARCHIVE::Input;
using ARCHIVE::FlushBuffer;
using ARCHIVE::operator&;
using ARCHIVE::operator<<;
using ARCHIVE::GetVersion;
void ShallowOutPython(const pybind11::object& val) override { lst.append(val); }
pybind11::object ShallowInPython() override { return lst[index++]; }
pybind11::list WriteOut()
{
FlushBuffer();
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
stream = std::make_shared<std::stringstream>();
*this & GetLibraryVersions();
FlushBuffer();
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
stream = std::make_shared<std::stringstream>();
logger->debug("Writeout version needed = {}", version_needed);
*this & version_needed;
FlushBuffer();
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
return lst;
return *this;
}
};
template<typename T, typename T_ARCHIVE_OUT=BinaryOutArchive, typename T_ARCHIVE_IN=BinaryInArchive>
auto NGSPickle()
{
return pybind11::pickle([](T* self)
{
PyArchive<T_ARCHIVE_OUT> ar;
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;
},
[](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;
});
}
#endif // NETGEN_PYTHON
} // namespace ngcore
#endif // NETGEN_CORE_ARCHIVE_HPP

1693
libsrc/core/array.hpp Normal file

File diff suppressed because it is too large Load Diff

184
libsrc/core/bitarray.cpp Normal file
View File

@ -0,0 +1,184 @@
/**************************************************************************/
/* File: bitarray.cpp */
/* Autho: Joachim Schoeberl */
/* Date: 01. Jun. 95 */
/**************************************************************************/
/*
data type BitArray
*/
#include "bitarray.hpp"
#include "archive.hpp"
namespace ngcore
{
BitArray :: BitArray (size_t asize)
{
size = 0;
data = NULL;
SetSize (asize);
}
BitArray :: BitArray (size_t asize, LocalHeap & lh)
{
size = asize;
data = new (lh) unsigned char [Addr (size)+1];
owns_data = false;
}
BitArray :: BitArray (const BitArray & ba2)
{
size = 0;
data = NULL;
(*this) = ba2;
}
void BitArray :: SetSize (size_t asize)
{
if (size == asize) return;
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()
{
if (!size) return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] = UCHAR_MAX;
return *this;
}
BitArray & BitArray :: Clear () throw()
{
if (!size) return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] = 0;
return *this;
}
BitArray & BitArray :: Invert ()
{
if (!size) return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] ^= 255;
return *this;
}
BitArray & BitArray :: And (const BitArray & ba2)
{
if (!size) return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] &= ba2.data[i];
return *this;
}
BitArray & BitArray :: Or (const BitArray & ba2)
{
if (!size) return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] |= ba2.data[i];
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)
{
SetSize (ba2.Size());
if (!size)
return *this;
for (size_t i = 0; i <= Addr (size); i++)
data[i] = ba2.data[i];
return *this;
}
std::ostream & operator<<(std::ostream & s, const BitArray & ba)
{
size_t n = ba.Size();
for (size_t i = 0; i < n; i++)
{
if (i % 50 == 0) s << i << ": ";
s << int(ba[i]);
if (i % 50 == 49) s << "\n";
}
s << std::flush;
return s;
}
size_t BitArray :: NumSet () const
{
size_t cnt = 0;
for (size_t i = 0; i < Size(); i++)
if (Test(i)) cnt++;
return cnt;
}
void BitArray :: DoArchive(Archive& archive)
{
if(archive.GetVersion("netgen") >= "v6.2.2007-62")
{
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
{
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;
SetSize (size);
Clear();
for (size_t i = 0; i < size; i++)
{
bool b;
archive & b;
if (b) SetBit(i);
}
}
}
}
} // namespace ngcore

210
libsrc/core/bitarray.hpp Normal file
View File

@ -0,0 +1,210 @@
#ifndef NETGEN_CORE_BITARRAY
#define NETGEN_CORE_BITARRAY
/**************************************************************************/
/* File: bitarray.hpp */
/* Author: Joachim Schoeberl */
/* Date: 01. Jun. 95 */
/**************************************************************************/
#include <climits>
#include <cstring>
#include <ostream>
#include "array.hpp"
#include "localheap.hpp"
#include "ngcore_api.hpp"
#include "utils.hpp"
namespace ngcore
{
/**
A compressed array of bools.
Provides bit-operations and whole array operations.
*/
class BitArray
{
protected:
/// number of bits
size_t size;
/// the data
unsigned char * data;
///
bool owns_data = true;
public:
/// empty array
BitArray ()
: size(0), data(nullptr) { ; }
/// array of asize bits
NGCORE_API BitArray (size_t asize);
/// array of asize bits
NGCORE_API BitArray (size_t asize, LocalHeap & lh);
///
NGCORE_API BitArray (const BitArray & ba2);
BitArray (BitArray && ba2)
: size(ba2.size), data(ba2.data), owns_data(ba2.owns_data)
{
ba2.owns_data = false;
ba2.data = nullptr;
}
template <typename T>
NETGEN_INLINE BitArray (std::initializer_list<T> list)
: BitArray (list.size())
{
Clear();
int cnt = 0;
for (auto i = list.begin(); i < list.end(); i++, cnt++)
if (*i) SetBit(cnt);
}
/// delete data
~BitArray ()
{
if (owns_data)
delete [] data;
}
/// Set size, loose values
NGCORE_API void SetSize (size_t asize);
/// the size
size_t Size () const { return size; }
/// set all bits
NGCORE_API BitArray & Set () throw();
/// clear all bits
NGCORE_API BitArray & Clear () throw();
/// set bit i
[[deprecated("Use either SetBit() or SetBitAtomic()")]]
void Set (size_t i) { SetBitAtomic(i); }
/// set bit i ( not thread safe )
void SetBit (size_t i)
{
NETGEN_CHECK_RANGE(i, 0, size);
data[Addr(i)] |= Mask(i);
}
/// set bit i ( thread safe )
void SetBitAtomic (size_t i)
{
NETGEN_CHECK_RANGE(i, 0, size);
unsigned char * p = data+Addr(i);
unsigned char mask = Mask(i);
AsAtomic(*p) |= mask;
}
/// clear bit i
void Clear (size_t i)
{
NETGEN_CHECK_RANGE(i, 0, size);
data[Addr(i)] &= ~Mask(i);
}
/// check bit i
bool Test (size_t i) const
{
NETGEN_CHECK_RANGE(i, 0, size);
return (data[Addr(i)] & Mask(i)) ? true : false;
}
/// set all bits to b
BitArray & operator= (bool b)
{
if (b) Set();
else Clear();
return *this;
}
/// check bit i
bool operator[] (size_t i) const
{
NETGEN_CHECK_RANGE(i, 0, size);
return Test(i);
}
NGCORE_API bool operator==(const BitArray& other) const;
/// invert all bits
NGCORE_API BitArray & Invert ();
/// logical AND with ba2
NGCORE_API BitArray & And (const BitArray & ba2);
/// logical OR with ba2
NGCORE_API BitArray & Or (const BitArray & ba2);
/// copy from ba2
NGCORE_API BitArray & operator= (const BitArray & ba2);
NGCORE_API size_t NumSet () const;
NGCORE_API void DoArchive(class 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
{ return char(1) << (i % CHAR_BIT); }
///
size_t Addr (size_t i) const
{ return (i / CHAR_BIT); }
MemoryTracer mt;
};
inline BitArray & operator|= (BitArray & me, const BitArray & you)
{
me.Or(you);
return me;
}
inline BitArray & operator&= (BitArray & me, const BitArray & you)
{
me.And(you);
return me;
}
inline BitArray operator| (const BitArray & a, const BitArray & b)
{
BitArray res = a;
res |= b;
return res;
}
inline BitArray operator& (const BitArray & a, const BitArray & b)
{
BitArray res = a;
res &= b;
return res;
}
inline BitArray operator~ (const BitArray & a)
{
BitArray res = a;
res.Invert();
return res;
}
NGCORE_API std::ostream & operator<<(std::ostream & s, const BitArray & ba);
} // namespace ngcore
#endif // NETGEN_CORE_BITARRAY

File diff suppressed because it is too large Load Diff

239
libsrc/core/exception.cpp Normal file
View File

@ -0,0 +1,239 @@
#include "exception.hpp"
#include "utils.hpp"
namespace ngcore
{
Exception :: Exception(const std::string& s)
: m_what(s) {}
Exception :: Exception(const char* s)
: m_what(s) {}
void ThrowException(const std::string & s)
{
throw Exception (s);
}
void ThrowException(const char * s)
{
throw Exception (s);
}
} // namespace ngcore
// ********* STUFF FOR GETBACKTRACE ***************************
#ifdef __GNUC__
#include <execinfo.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <iostream>
#include <dlfcn.h>
#include <array>
#include <memory>
#include <cxxabi.h>
#include <signal.h>
#include <vector>
namespace ngcore
{
namespace detail
{
static int exec(std::string cmd, std::string & out) {
std::array<char, 128> buffer;
FILE *pipe = popen(cmd.c_str(), "r");
if (!pipe)
throw std::runtime_error("popen() failed!");
out = "";
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr)
out += buffer.data();
int error_code = pclose(pipe);
return error_code;
}
#ifdef __APPLE__
// Split output line from backtrace_symbols to recover function name and offset
// then use `nm` command line tool to get the address of the function
// then use `add42line` command line tool to map function address + offset to line in source code
static std::string TranslateBacktrace( std::string s, std::string libname )
{
// example line
// 1 libngcore.dylib 0x000000010ddb298c _ZL21ngcore_signal_handleri + 316
constexpr char reset_shell[] = "\033[0m";
constexpr char green[] = "\033[32m";
constexpr char yellow[] = "\033[33m";
std::istringstream in(s);
std::string libname1, funcname, addr, plus_sign;
size_t i,offset;
in >> i >> libname1 >> addr >> funcname >> plus_sign >> std::hex >> offset;
std::stringstream out;
if(!funcname.empty() && !libname.empty())
{
std::string nm_command = "nm " + libname + " | grep \"" + funcname + "$\" | cut -f 1 -d ' '";
std::string output;
auto exit_code = exec(nm_command, output);
auto fptr = std::strtoul(output.c_str(), 0, 16);
if(fptr == 0)
return out.str()+'\n';
std::stringstream offset_s;
offset_s << "0x" << std::hex << fptr+offset - 5;
std::string addr2line_command = std::string("atos -o ") + libname + " --fullPath " + offset_s.str();
exit_code = exec(addr2line_command, output);
if(exit_code==0)
out << " at " << green << output << reset_shell;
else
out << '\n';
}
else
out << s << '\n';
return out.str();
}
#else // __APPLE__
// Split output line from backtrace_symbols to recover function name and offset
// then use `nm` command line tool to get the address of the function
// then use `addr2line` command line tool to map function address + offset to line in source code
static std::string TranslateBacktrace( std::string s, std::string /*dummy*/ )
{
// example line:
// /home/mhochsteger/install/ngs_clang/bin/../lib/libngcore.so(_ZN6ngcore11TaskManager4LoopEi+0x1e0) [0x7f2991fe1030]
constexpr char reset_shell[] = "\033[0m";
constexpr char green[] = "\033[32m";
constexpr char yellow[] = "\033[33m";
auto brace_open_pos = s.find('(');
auto brace_close_pos = s.find(')', brace_open_pos);
auto plus_pos = s.find('+', brace_open_pos);
auto bracket_open_pos = s.find('[');
auto bracket_close_pos = s.find(']');
auto libname = s.substr(0, brace_open_pos);
auto funcname = s.substr(brace_open_pos+1, plus_pos - brace_open_pos - 1);
auto offset = std::strtoul(s.substr(plus_pos+1, brace_close_pos - plus_pos - 1).c_str(), 0, 16);
auto position = std::strtoul(s.substr(bracket_open_pos+1, bracket_close_pos - bracket_open_pos - 1).c_str(), 0, 16);
std::stringstream out;
if(!funcname.empty())
{
std::vector<char> buffer(10240);
int status;
size_t size = buffer.size();
abi::__cxa_demangle(funcname.c_str(), &buffer[0], &size, &status);
out << "in " << yellow << &buffer[0] << reset_shell << '\n';
std::string nm_command = "nm " + libname + " | grep " + funcname + " | cut -f 1 -d ' '";
std::string output;
auto exit_code = exec(nm_command, output);
auto fptr = std::strtoul(output.c_str(), 0, 16);
std::stringstream offset_s;
offset_s << "0x" << std::hex << fptr+offset - 5;
std::string addr2line_command = std::string("addr2line -i -p -e ") + libname + " " + offset_s.str();
exit_code = exec(addr2line_command, output);
if(exit_code==0)
{
std::stringstream soutput(output);
std::string s;
while(soutput)
{
if(getline(soutput, s))
out << "\t at " << green << s << reset_shell << '\n';
}
}
else
out << '\n';
}
else
out << s << '\n';
return out.str();
}
#endif // __APPLE__
} // namespace detail
std::string GetBackTrace()
{
if(!getenv("NG_BACKTRACE"))
return "";
std::cerr << "Collecting backtrace..." << std::endl;
std::stringstream result;
void *bt[100];
int bt_size;
char **bt_syms;
int i;
bt_size = backtrace(bt, 100);
bt_syms = backtrace_symbols(bt, bt_size);
Dl_info info;
for (i = 1; i < bt_size-1; i++)
{
dladdr(bt[i], &info);
size_t len = strlen(bt_syms[i]);
result << '#'<< i << '\t' << detail::TranslateBacktrace( bt_syms[i], info.dli_fname );
}
free(bt_syms);
return result.str();
}
} // namespace ngcore
static void ngcore_signal_handler(int sig)
{
static bool first_call = true;
if(!first_call)
exit(1); // avoid endless recursions if signals are caused by this handler
first_call = false;
switch(sig)
{
case SIGABRT:
std::cerr << "Caught SIGABRT: usually caused by abort() or assert()" << std::endl;
break;
case SIGILL:
std::cerr << "Caught SIGILL: illegal instruction" << std::endl;
break;
case SIGSEGV:
std::cerr << "Caught SIGSEGV: segmentation fault" << std::endl;
break;
}
std::cerr << ngcore::GetBackTrace() << std::endl;
exit(1);
}
// 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;
}();
#else // __GNUC__
namespace ngcore
{
std::string GetBackTrace()
{
return std::string();
}
} // namespace ngcore
#endif // __GNUC__

View File

@ -7,8 +7,12 @@
#include "ngcore_api.hpp" // for NGCORE_API
namespace ngcore
{
NGCORE_API std::string GetBackTrace();
// Exception for code that shouldn't be executed
class NGCORE_API UnreachableCodeException : public std::exception
{
@ -27,8 +31,8 @@ namespace ngcore
Exception() = default;
Exception(const Exception&) = default;
Exception(Exception&&) = default;
Exception(const std::string& s) : m_what(s) {}
Exception(const char* s) : m_what(s) {}
Exception(const std::string& s); // : m_what(s) {}
Exception(const char* s); // : m_what(s) {}
~Exception() override = default;
Exception& operator =(const Exception&) = default;
@ -45,7 +49,10 @@ namespace ngcore
/// implement virtual function of std::exception
const char* what() const noexcept override { return m_what.c_str(); }
};
NGCORE_API void ThrowException(const std::string & s);
NGCORE_API void ThrowException(const char * s);
// Out of Range exception
class NGCORE_API RangeException : public Exception
{
@ -55,8 +62,9 @@ namespace ngcore
int ind, int imin, int imax) : Exception("")
{
std::stringstream str;
str << where << ": index " << ind << " out of range [" << imin << "," << imax << "]\n";
str << where << ": index " << ind << " out of range [" << imin << "," << imax << ")\n";
Append (str.str());
Append (GetBackTrace());
}
template<typename T>
@ -79,12 +87,19 @@ namespace ngcore
// Convenience macro to append file name and line of exception origin to the string
#define NG_EXCEPTION(s) ngcore::Exception(__FILE__ ":" NETGEN_CORE_NGEXEPTION_STR(__LINE__) "\t"+std::string(s))
#ifdef NETGEN_ENABLE_CHECK_RANGE
#define NETGEN_CHECK_RANGE(value, min, max) \
{ if ((value)<(min) || (value)>=(max)) \
throw ngcore::RangeException(__FILE__ ":" NETGEN_CORE_NGEXEPTION_STR(__LINE__) "\t", (value), (min), (max)); }
#else // NETGEN_ENABLE_CHECK_RANGE
#if defined(NETGEN_ENABLE_CHECK_RANGE) && !defined(__CUDA_ARCH__)
#define NETGEN_CHECK_RANGE(value, min, max_plus_one) \
{ if ((value)<(min) || (value)>=(max_plus_one)) \
throw ngcore::RangeException(__FILE__ ":" NETGEN_CORE_NGEXEPTION_STR(__LINE__) "\t", (value), (min), (max_plus_one)); }
#define NETGEN_CHECK_SHAPE(a,b) \
{ if(a.Shape() != b.Shape()) \
throw ngcore::Exception(__FILE__": shape don't match"); }
#else // defined(NETGEN_ENABLE_CHECK_RANGE) && !defined(__CUDA_ARCH__)
#define NETGEN_CHECK_RANGE(value, min, max)
#endif // NETGEN_ENABLE_CHECK_RANGE
#define NETGEN_CHECK_SHAPE(a,b)
#endif // defined(NETGEN_ENABLE_CHECK_RANGE) && !defined(__CUDA_ARCH__)
#endif // NETGEN_CORE_EXCEPTION_HPP

642
libsrc/core/flags.cpp Normal file
View File

@ -0,0 +1,642 @@
/**************************************************************************/
/* File: flags.cpp */
/* Author: Joachim Schoeberl */
/* Date: 10. Oct. 96 */
/**************************************************************************/
#include "archive.hpp"
#include "flags.hpp"
#ifdef WIN32
#include <float.h>
#endif
#include <algorithm>
namespace ngcore
{
using std::string;
using std::endl;
Flags :: Flags () { ; }
Flags :: Flags (const Flags & flags)
{
string name;
for (int i = 0; i < flags.GetNStringFlags(); i++)
{
string str = flags.GetStringFlag (i, name);
SetFlag (name, str);
}
for (int i = 0; i < flags.GetNNumFlags(); i++)
{
double val = flags.GetNumFlag (i, name);
SetFlag (name, val);
}
for (int i = 0; i < flags.GetNDefineFlags(); i++)
{
bool val = flags.GetDefineFlag (i, name);
SetFlag (name, val);
}
for (int i = 0; i < flags.GetNNumListFlags(); i++)
{
auto numa = flags.GetNumListFlag (i, name);
SetFlag (name, *numa);
}
for (int i = 0; i < flags.GetNStringListFlags(); i++)
{
auto stra = flags.GetStringListFlag (i, name);
SetFlag (name, *stra);
}
for (int i = 0; i < flags.GetNFlagsFlags(); i++)
{
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)
: strflags(flags.strflags), numflags(flags.numflags),
defflags(flags.defflags), strlistflags(flags.strlistflags),
numlistflags(flags.numlistflags) { ; }
Flags :: Flags (std::initializer_list<string> list)
{
for (auto i = list.begin(); i < list.end(); i++)
SetCommandLineFlag ((string("-")+*i).c_str());
}
Flags :: Flags (string f1, string f2, string f3, string f4, string f5)
{
SetCommandLineFlag ((string("-")+f1).c_str());
if (f2.length()) SetCommandLineFlag ( (string("-")+f2).c_str() );
if (f3.length()) SetCommandLineFlag ( (string("-")+f3).c_str() );
if (f4.length()) SetCommandLineFlag ( (string("-")+f4).c_str() );
if (f5.length()) SetCommandLineFlag ( (string("-")+f5).c_str() );
}
Flags :: ~Flags ()
{
DeleteFlags ();
}
void Flags :: DeleteFlags ()
{
strflags.DeleteAll();
numflags.DeleteAll();
defflags.DeleteAll();
strlistflags.DeleteAll();
numlistflags.DeleteAll();
}
Flags Flags :: SetFlag (const char * name, bool b) &&
{
this -> SetFlag (name, b);
return std::move(*this);
}
Flags Flags :: SetFlag (const char * name, double val) &&
{
this -> SetFlag (name, val);
return std::move(*this);
}
Flags & Flags :: SetFlag (const char * name, const string & val)
{
strflags.Set (name, val);
return *this;
}
Flags & Flags :: SetFlag (const char * name, double val) &
{
numflags.Set (name, val);
return *this;
}
Flags & Flags :: SetFlag (const char * name, bool b) &
{
defflags.Set (name, b);
return *this;
}
Flags & Flags :: SetFlag (const char * name, Flags & val) &
{
flaglistflags.Set (name, val);
return *this;
}
Flags & Flags :: SetFlag (const string & name, const string & val)
{
// char * hval = new char[strlen (val) + 1];
// strcpy (hval, val);
strflags.Set (name, val);
return *this;
}
Flags & Flags :: SetFlag (const string & name, double val)
{
numflags.Set (name, val);
return *this;
}
Flags & Flags :: SetFlag (const string & name, bool b)
{
defflags.Set (name, b);
return *this;
}
Flags & Flags :: SetFlag (const string & name, Flags & val)
{
flaglistflags.Set (name, val);
return *this;
}
Flags & Flags :: SetFlag (const string & name, const Array<string> & val)
{
auto strarray = std::make_shared<Array<string>>(val);
/*
for (int i = 0; i < val.Size(); i++)
{
strarray->Append (new char[strlen(val[i])+1]);
strcpy (strarray->Last(), val[i]);
}
*/
strlistflags.Set (name, strarray);
return *this;
}
Flags & Flags :: SetFlag (const string & name, const Array<double> & val)
{
// Array<double> * numarray = new Array<double>(val);
auto numarray = std::make_shared<Array<double>> (val);
numlistflags.Set (name, numarray);
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
{
if (strflags.Used (name))
return strflags[name];
else
{
if (!def) return string("");
return def;
}
}
string Flags :: GetStringFlag (const string & name, string def) const
{
if (strflags.Used (name))
return strflags[name];
else
return def;
}
double Flags :: GetNumFlag (const string & name, double def) const
{
if (numflags.Used (name))
return numflags[name];
else
return def;
}
const double * Flags :: GetNumFlagPtr (const string & name) const
{
if (numflags.Used (name))
return & ((SymbolTable<double>&)numflags)[name];
else
return NULL;
}
double * Flags :: GetNumFlagPtr (const string & name)
{
if (numflags.Used (name))
return & ((SymbolTable<double>&)numflags)[name];
else
return NULL;
}
/*
int Flags :: GetDefineFlag (const char * name) const
{
return defflags.Used (name);
}
*/
bool Flags :: GetDefineFlag (const string & name) const throw()
{
if (!defflags.Used (name)) return false;
return defflags[name];
}
xbool Flags :: GetDefineFlagX (const string & name) const throw()
{
if (!defflags.Used (name)) return maybe;
return bool(defflags[name]);
}
const Array<string> &
Flags :: GetStringListFlag (const string & name) const
{
if (strlistflags.Used (name))
return *strlistflags[name];
else
{
static Array<string> hstra(0);
return hstra;
}
}
const Array<double> &
Flags ::GetNumListFlag (const string & name) const
{
if (numlistflags.Used (name))
return *numlistflags[name];
else
{
static Array<double> hnuma(0);
return hnuma;
}
}
const Flags &
Flags ::GetFlagsFlag (const string & name) const
{
if (flaglistflags.Used (name))
return flaglistflags[name];
else
{
static Flags empty;
return empty;
}
}
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);
}
bool Flags :: NumFlagDefined (const string &name) const
{
return numflags.Used (name);
}
bool Flags :: FlagsFlagDefined (const string &name) const
{
return flaglistflags.Used (name);
}
bool Flags :: StringListFlagDefined (const string & name) const
{
return strlistflags.Used (name);
}
bool Flags :: NumListFlagDefined (const string & name) const
{
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++)
str << strflags.GetName(i) << " = " << strflags[i] << endl;
for (int i = 0; i < numflags.Size(); i++)
str << numflags.GetName(i) << " = " << numflags[i] << endl;
for (int i = 0; i < defflags.Size(); i++)
str << defflags.GetName(i) << " = " << (defflags[i] ? "_TRUE" : "_FALSE") << endl;
for (int i = 0; i < flaglistflags.Size(); i++)
str << flaglistflags.GetName(i) << " =*" << flaglistflags[i] << endl;
for (int i = 0; i < numlistflags.Size(); i++)
{
str << numlistflags.GetName(i) << " = [";
int j = 0;
for (j = 0; j + 1 < numlistflags[i]->Size(); ++j)
str << (*numlistflags[i])[j] << ", ";
if (numlistflags[i]->Size())
str << (*numlistflags[i])[j];
str << "]" << endl;
}
}
void Flags :: SaveFlags (const char * filename) const
{
std::ofstream outfile (filename);
SaveFlags(outfile);
}
void Flags :: PrintFlags (ostream & ost) const
{
for (int i = 0; i < strflags.Size(); i++)
ost << strflags.GetName(i) << " = " << strflags[i] << endl;
for (int i = 0; i < numflags.Size(); i++)
ost << numflags.GetName(i) << " = " << numflags[i] << endl;
for (int i = 0; i < defflags.Size(); i++)
ost << defflags.GetName(i) << endl;
for (int i = 0; i < strlistflags.Size(); i++)
ost << strlistflags.GetName(i) << " = " << *strlistflags[i] << endl;
for (int i = 0; i < numlistflags.Size(); i++)
ost << numlistflags.GetName(i) << " = " << *numlistflags[i] << endl;
for (int i = 0; i < flaglistflags.Size(); i++)
ost << flaglistflags.GetName(i) << " = " << flaglistflags[i] << endl;
}
void Flags :: LoadFlags (const char * filename, SymbolTable<Flags> * sf)
{
std::ifstream str(filename);
LoadFlags(str,sf);
}
void Flags :: LoadFlags (std::istream & istr, SymbolTable<Flags> * sf )
{
char str[100];
char ch;
// double val;
while (istr.good())
{
string name;
string content;
string line;
getline(istr, line);
std::istringstream line_stream(line);
getline(line_stream, name, '=');
name.erase(std::remove(name.begin(), name.end(), ' '), name.end());
getline(line_stream, content);
content.erase(std::remove(content.begin(), content.end(), ' '), content.end());
// if (name[0] == '/' && name[1] == '/')
// {
// ch = 0;
// while (ch != '\n' && istr.good())
// {
// ch = istr.get();
// }
// continue;
// }
if (strlen(content.c_str())==0)
{
SetFlag (name);
continue;
}
else
{
std::istringstream content_stream(content);
content_stream >> ch;
if (ch != '*')
{
if (ch == '[')
{
// content_stream.putback (ch);
// content_stream >> ch;
string inner_string;
getline(content_stream, inner_string, ']');
std::istringstream inner_string_stream(inner_string);
Array<double> values;
Array<string> strings;
string cur;
while (getline(inner_string_stream, cur, ','))
{
char* endptr;
double vald = strtod (cur.c_str(), &endptr);
if (endptr != cur.c_str() && strings.Size() == 0)
values.Append(vald);
else
strings.Append(cur);
}
if (strings.Size() > 0)
SetFlag(name, strings);
else
SetFlag(name, values);
}
else
{
if(content == "_TRUE" || content == "_FALSE")
{
SetFlag(name, (content =="_TRUE") ? true : false);
continue;
}
char* endptr;
double vald = strtod (content.c_str(), &endptr);
if (endptr != content.c_str())
SetFlag (name, vald);
else
SetFlag (name, content);
}
}
else
{
content_stream.clear();
content_stream >> str;
if (sf)
SetFlag (name, (*sf)[str]);
else
throw Exception (" no symboltable of flags ");
}
}
}
}
void Flags :: DoArchive(Archive & archive)
{
archive & strflags & numflags & defflags & numlistflags & strlistflags & flaglistflags;
}
void Flags :: Update(const Flags& other)
{
strflags.Update(other.strflags);
numflags.Update(other.numflags);
defflags.Update(other.defflags);
numlistflags.Update(other.numlistflags);
strlistflags.Update(other.strlistflags);
flaglistflags.Update(other.flaglistflags);
}
void Flags :: SetCommandLineFlag (const char * st, SymbolTable<Flags> * sf )
{
//cout << "SetCommandLineFlag: flag = " << st << endl;
std::istringstream inst( (char *)st);
char name[100];
double val;
if (st[0] != '-')
{
std::cerr << "flag must start with '-'" << endl;
return;
}
// flag with double --
if (st[1] == '-') st++;
const char * pos = strchr (st, '=');
const char * posstar = strchr (st, '*');
const char * posbrack = strchr (st, '[');
if (!pos)
{
// (cout) << "Add def flag: " << st+1 << endl;
SetFlag (st+1);
}
else
{
//cout << "pos = " << pos << endl;
strncpy (name, st+1, (pos-st)-1);
name[pos-st-1] = 0;
//cout << "name = " << name << endl;
pos++;
char * endptr = NULL;
val = strtod (pos, &endptr);
/*
cout << "val = " << val << endl;
cout << "isfinite = " << std::isfinite (val) << endl;
cout << "isinf = " << std::isinf (val) << endl;
cout << "pos = " << pos << ", endpos = " << endptr << endl;
*/
if (endptr != pos && !std::isfinite (val))
endptr = const_cast<char *>(pos);
/*
#ifdef WIN32
if(endptr != pos && !_finite(val))
endptr = const_cast<char *>(pos);
#else
#ifdef MACOS
if(endptr != pos && (__isnand(val) || __isinfd(val)))
endptr = const_cast<char *>(pos);
#else
#ifdef SUN
#else
if(endptr != pos && (std::isnan(val) || std::isinf(val)))
endptr = const_cast<char *>(pos);
#endif
#endif
#endif
*/
//cout << "val = " << val << endl;
if (!posbrack)
{
if (posstar)
{
pos++;
if (sf)
SetFlag (name, (*sf)[pos]);
else
throw Exception (" no symboltable of flags ");
}
else if (endptr == pos)
{
// string-flag
//(cout) << "Add String Flag: " << name << " = " << pos << endl;
SetFlag (name, pos);
}
else
{
// num-flag
//(cout) << "Add Num Flag: " << name << " = " << val << endl;
SetFlag (name, val);
}
}
else
{
// list-flag
char hc;
double val;
val = strtod (posbrack+1, &endptr);
if (endptr != posbrack+1)
{
Array<double> values;
std::istringstream ist(posbrack);
ist >> hc; // '['
ist >> val;
while (ist.good())
{
values.Append (val);
ist >> hc; // ','
ist >> val;
}
SetFlag (name, values);
}
else
{
// to be cleaned up ...
Array<char *> strs;
posbrack++;
char * hstr = new char[strlen(posbrack)+1];
strcpy (hstr, posbrack);
char * chp = hstr;
bool start = 1;
while (*chp && *chp != ']')
{
if (start)
strs.Append (chp);
start = 0;
if (*chp == ',')
{
*chp = 0;
start = 1;
}
chp++;
}
*chp = 0;
Array<string> strings;
for (int i = 0; i < strs.Size(); i++)
strings.Append (string (strs[i]));
SetFlag (name, strings);
delete [] hstr;
}
}
}
}
} // namespace ngcore

199
libsrc/core/flags.hpp Normal file
View File

@ -0,0 +1,199 @@
#ifndef NETGEN_CORE_FLAGS_HPP
#define NETGEN_CORE_FLAGS_HPP
/**************************************************************************/
/* File: flags.hpp */
/* Author: Joachim Schoeberl */
/* Date: 10. Oct. 96 */
/**************************************************************************/
#include <iostream>
#include <memory>
#include <string>
#include <any>
#include "array.hpp"
#include "symboltable.hpp"
#include "xbool.hpp"
namespace ngcore
{
/**
A storage for command-line flags.
The flag structure maintains string flags, numerical flags,
define flags, string list flags, num list flags.
*/
class NGCORE_API Flags
{
/// string flags
SymbolTable<std::string> strflags;
/// numerical flags
SymbolTable<double> numflags;
/// define flags
SymbolTable<bool> defflags;
/// string list flags
SymbolTable<std::shared_ptr<Array<std::string>>> strlistflags;
/// numerical list flags
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 ();
/// copy flags
Flags (const Flags & flags);
/// steal flags
Flags (Flags && flags);
///
Flags (std::initializer_list<std::string> list);
///
Flags (std::string f1, std::string f2 = "", std::string f3 = "", std::string f4 = "", std::string f5 = "");
/// delete mem
~Flags ();
Flags & operator= (const Flags & f2) = default;
Flags & operator= (Flags && f2) = default;
void DoArchive(class Archive& ar);
void Update(const Flags& other);
/// Deletes all flags
void DeleteFlags ();
/// Sets string flag, overwrite if exists
Flags & SetFlag (const char * name, const std::string & val);
/// Sets string flag, overwrite if exists
Flags & SetFlag (const char * name, const char * str)
{ return SetFlag (name, std::string(str)); }
/// Sets numerical flag, overwrite if exists
Flags & SetFlag (const char * name, double val) &;
/// Sets numerical flag, overwrite if exists
Flags & SetFlag (const char * name, int val)
{ return SetFlag (name, double(val)); }
/// Sets boolean flag
Flags & SetFlag (const char * name, bool b = true) &;
/// Sets numerical flag, overwrite if exists
Flags & SetFlag (const char * name, Flags & val) &;
/// Sets string flag, overwrite if exists
Flags & SetFlag (const std::string & name, const std::string & val);
Flags & SetFlag (const std::string & name, const char * str)
{ return SetFlag (name, std::string(str)); }
/// Sets numerical flag, overwrite if exists
Flags & SetFlag (const std::string & name, double val);
/// Sets numerical flag, overwrite if exists
Flags & SetFlag (const std::string & name, int val)
{ return SetFlag (name, double(val)); }
/// Sets boolean flag
Flags & SetFlag (const std::string & name, bool b = true);
/// Sets numerical flag, overwrite if exists
Flags & SetFlag (const std::string & name, Flags & val);
/// Sets string array flag
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) &&;
Flags SetFlag (const char * name, double val) &&;
/// Save flags to file
void SaveFlags (const char * filename) const;
void SaveFlags (ostream & str) const;
/// write flags to stream
void PrintFlags (ostream & ost) const;
/// Load flags from file
void LoadFlags (const char * filename, SymbolTable<Flags> * sf = nullptr);
void LoadFlags (std::istream & str, SymbolTable<Flags> * sf = nullptr);
/**
Set command line flag.
Flag must be in form: -name=hello -val=0.5 -defflag
-names=[Joe,Jim] -values=[1,3,4] -solverflags=*abc
*/
void SetCommandLineFlag (const char * st, SymbolTable<Flags> * sf = nullptr);
/// Returns string flag, default value if not exists
std::string GetStringFlag (const std::string & name, const char * def) const;
/// Returns std::string flag, default value if not exists
std::string GetStringFlag (const std::string & name, std::string def = "") const;
/// Returns numerical flag, default value if not exists
double GetNumFlag (const std::string & name, double def) const;
/// Returns address of numerical flag, null if not exists
const double * GetNumFlagPtr (const std::string & name) const;
/// Returns address of numerical flag, null if not exists
double * GetNumFlagPtr (const std::string & name);
/// Returns boolean flag
// int GetDefineFlag (const char * name) const;
bool GetDefineFlag (const std::string & name) const throw();
xbool GetDefineFlagX (const std::string & name) const throw();
/// Returns string list flag, empty array if not exist
const Array<std::string> & GetStringListFlag (const std::string & name) const;
/// Returns num list flag, empty array if not exist
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
bool StringFlagDefined (const std::string & name) const;
/// Test, if num flag is defined
bool NumFlagDefined (const std::string & name) const;
/// Test, if num flag is defined
bool FlagsFlagDefined (const std::string & name) const;
/// Test, if string list flag is defined
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(); }
/// number of num flags
int GetNNumFlags () const { return numflags.Size(); }
/// number of num flags
int GetNFlagsFlags () const { return flaglistflags.Size(); }
/// number of define flags
int GetNDefineFlags () const { return defflags.Size(); }
/// number of string-list flags
int GetNStringListFlags () const { return strlistflags.Size(); }
/// number of num-list flags
int GetNNumListFlags () const { return numlistflags.Size(); }
int GetNAnyFlags() const { return anyflags.Size(); }
///
const std::string & GetStringFlag (int i, std::string & name) const
{ name = strflags.GetName(i); return strflags[i]; }
double GetNumFlag (int i, std::string & name) const
{ name = numflags.GetName(i); return numflags[i]; }
bool GetDefineFlag (int i, std::string & name) const
{ name = defflags.GetName(i); return defflags[i]; }
const std::shared_ptr<Array<double>> GetNumListFlag (int i, std::string & name) const
{ name = numlistflags.GetName(i).c_str(); return numlistflags[i]; }
const std::shared_ptr<Array<std::string>> GetStringListFlag (int i, std::string & name) const
{ name = strlistflags.GetName(i); return strlistflags[i]; }
const Flags & GetFlagsFlag (int i, std::string & name) const
{ name = flaglistflags.GetName(i); return flaglistflags[i]; }
const std::any& GetAnyFlag(int i, std::string& name) const
{ name = anyflags.GetName(i); return anyflags[i]; }
};
/// Print flags
inline std::ostream & operator<< (std::ostream & s, const Flags & flags)
{
flags.PrintFlags (s);
return s;
}
} // namespace ngcore
#endif // NETGEN_CORE_FLAGS_HPP

1106
libsrc/core/hashtable.hpp Normal file

File diff suppressed because it is too large Load Diff

72
libsrc/core/localheap.cpp Normal file
View File

@ -0,0 +1,72 @@
/**************************************************************************/
/* File: localheap.cpp */
/* Author: Joachim Schoeberl */
/* Date: 19. Apr. 2002 */
/**************************************************************************/
#include <exception>
#include <string>
#include "localheap.hpp"
#include "taskmanager.hpp"
namespace ngcore
{
LocalHeap :: LocalHeap (size_t asize, const char * aname, bool mult_by_threads)
{
if (mult_by_threads)
asize *= TaskManager::GetMaxThreads();
totsize = asize;
try
{
data = new char[asize];
}
catch (std::exception & e)
{
throw Exception (ToString ("Could not allocate localheap, heapsize = ") + ToString(asize));
}
next = data + totsize;
p = data;
owner = true;
name = aname;
CleanUp(); // align pointer
}
LocalHeap LocalHeap :: Split() const
{
int pieces = TaskManager::GetNumThreads();
int i = TaskManager::GetThreadId();
size_t freemem = totsize - (p - data);
size_t size_of_piece = freemem / pieces;
return LocalHeap (p + i * size_of_piece, size_of_piece, name);
}
void LocalHeap :: ThrowException() // throw (LocalHeapOverflow)
{
/*
cout << "allocated: " << (p-data) << endl;
cout << "throw LocalHeapOverflow, totsize = "<< totsize << endl;
cout << "heap name = " << name << endl;
*/
throw LocalHeapOverflow(totsize);
}
LocalHeapOverflow :: LocalHeapOverflow (size_t size)
: Exception("Local Heap overflow\n")
{
std::stringstream str;
str << "Current heapsize is " << size << '\n';
Append (str.str());
// Append ("please use 'define constant heapsize = xxx' with larger value\n");
}
LocalHeapOverflow :: ~LocalHeapOverflow ()
{
;
}
}

318
libsrc/core/localheap.hpp Normal file
View File

@ -0,0 +1,318 @@
#ifndef NETGEN_CORE_LOCALHEAP_HPP
#define NETGEN_CORE_LOCALHEAP_HPP
/**************************************************************************/
/* File: localheap.hpp */
/* Author: Joachim Schoeberl */
/* Date: 19. Apr. 2000 */
/**************************************************************************/
#include <cstdlib>
#include "exception.hpp"
#include "ngcore_api.hpp"
#include "utils.hpp"
namespace ngcore
{
class Allocator
{
public:
virtual ~Allocator() {}
virtual void * Alloc (size_t size)
{
return new char[size];
}
virtual void Delete(void* p)
{
delete (char*) p;
}
virtual void ArrayDelete(void* p)
{
delete [] (char*) p;
}
};
static Allocator global_alloc;
/**
Exception on heap overflow.
Thrown by allocation on LocalHeap.
*/
class NGCORE_API LocalHeapOverflow : public Exception
{
public:
LocalHeapOverflow (size_t size);
virtual ~LocalHeapOverflow ();
};
/**
Optimized memory handler.
One block of data is organized as stack memory.
One can allocate memory out of it. This increases the stack pointer.
With \Ref{CleanUp}, the pointer is reset to the beginning or to a
specific position.
*/
class LocalHeap : public Allocator
{
char * data;
char * next;
char * p;
size_t totsize;
public:
bool owner;
const char * name;
#if defined(__MIC__) || defined (__AVX512F__)
enum { ALIGN = 64 };
#else
enum { ALIGN = 32 };
#endif
public:
/// Allocate one block of size asize.
NGCORE_API LocalHeap (size_t asize,
const char * aname = "noname",
bool mult_by_threads = false);
/// Use provided memory for the LocalHeap
NETGEN_INLINE LocalHeap (char * adata, size_t asize,
const char * aname = "noname") throw ()
{
totsize = asize;
data = adata;
next = data + totsize;
owner = 0;
// p = data;
name = aname;
CleanUp();
}
/*
/// Use provided memory for the LocalHeap
NETGEN_INLINE LocalHeap (const LocalHeap & lh2)
: data(lh2.data), p(lh2.p), totsize(lh2.totsize), owner(false),
name(lh2.name)
{
next = data + totsize;
}
*/
NETGEN_INLINE LocalHeap (const LocalHeap & lh2) = delete;
NETGEN_INLINE LocalHeap (LocalHeap && lh2)
: data(lh2.data), p(lh2.p), totsize(lh2.totsize), owner(lh2.owner),
name(lh2.name)
{
next = data + totsize;
lh2.owner = false;
}
NETGEN_INLINE LocalHeap Borrow()
{
return LocalHeap (p, Available());
}
NETGEN_INLINE LocalHeap & operator= (LocalHeap && lh2)
{
if (owner)
delete [] data;
data = lh2.data;
p = lh2.p;
totsize = lh2.totsize;
owner = lh2.owner;
name = lh2.name;
next = data + totsize;
lh2.owner = false;
return *this;
}
NETGEN_INLINE LocalHeap ()
: data(nullptr), next(nullptr), p(nullptr), totsize(0), owner(false) { ; }
/// free memory
virtual ~LocalHeap ()
{
if (owner)
delete [] data;
}
/// delete all memory on local heap
NETGEN_INLINE void CleanUp() throw ()
{
p = data;
// p += (16 - (long(p) & 15) );
p += (ALIGN - (size_t(p) & (ALIGN-1) ) );
}
/// returns heap-pointer
NETGEN_INLINE void * GetPointer () throw ()
{
return p;
}
/// deletes memory back to heap-pointer
NETGEN_INLINE void CleanUp (void * addr) throw ()
{
p = (char*)addr;
}
/// allocates size bytes of memory from local heap
void * Alloc (size_t size) final // throw (LocalHeapOverflow)
{
char * oldp = p;
// 16 byte alignment
size += (ALIGN - size % ALIGN);
p += size;
// if ( size_t(p - data) >= totsize )
#ifndef FULLSPEED
if (likely(p >= next))
ThrowException();
#endif
return oldp;
}
/// allocates size objects of type T on local heap
template <typename T>
T * Alloc (size_t size) // throw (LocalHeapOverflow)
{
char * oldp = p;
size *= sizeof (T);
// 16 byte alignment
size += (ALIGN - size % ALIGN);
p += size;
#ifndef FULLSPEED
if (likely(p >= next))
ThrowException();
#endif
return reinterpret_cast<T*> (oldp);
}
virtual void Delete(void* /* p */) {}
virtual void ArrayDelete(void* /* p */) {}
private:
///
#ifndef __CUDA_ARCH__
[[noreturn]] NGCORE_API void ThrowException();
#else
NETGEN_INLINE void ThrowException() { ; }
#endif
public:
/// free memory (dummy function)
NETGEN_INLINE void Free (void * /* data */) throw ()
{
;
}
/// available memory on LocalHeap
NETGEN_INLINE size_t Available () const throw () { return (totsize - (p-data)); }
/// Split free memory on heap into pieces for each thread
NGCORE_API LocalHeap Split () const;
/// Split free memory on heap into pieces
NETGEN_INLINE LocalHeap Split (int partnr, int nparts) const
{
int pieces = nparts;
int i = partnr;
size_t freemem = totsize - (p - data);
size_t size_of_piece = freemem / pieces;
return LocalHeap (p + i * size_of_piece, size_of_piece, name);
}
NETGEN_INLINE void ClearValues ()
{
for (size_t i = 0; i < totsize; i++) data[i] = 47;
}
NETGEN_INLINE size_t UsedSize ()
{
for (size_t i = totsize-1; i != 0; i--)
if (data[i] != 47) return i;
return 0;
}
};
/**
Optimized memory handler.
Provides static memory for the local heap. The template argument specifies the size in number of chars.
*/
template <int S>
class LocalHeapMem : public LocalHeap
{
char mem[S];
public:
NETGEN_INLINE LocalHeapMem (const char * aname) throw () : LocalHeap (mem, S, aname) { ; }
};
/**
A reset for the heap-pointer of a LocalHeap..
The constructor stores the heap-pointer, the constructor at the end of the regions resets the heap-pointer.
*/
class HeapReset
{
LocalHeap & lh;
void * pointer;
public:
///
NETGEN_INLINE HeapReset (LocalHeap & alh)
: lh(alh), pointer (alh.GetPointer()) { ; }
///
NETGEN_INLINE ~HeapReset ()
{
lh.CleanUp (pointer);
}
};
}
NETGEN_INLINE void * operator new (size_t size, ngcore::Allocator & alloc)
{
return alloc.Alloc(size);
}
NETGEN_INLINE void * operator new [] (size_t size, ngcore::Allocator & alloc)
{
return alloc.Alloc(size);
}
NETGEN_INLINE void operator delete (void * p, ngcore::Allocator & lh)
{
lh.Delete(p);
}
NETGEN_INLINE void operator delete [] (void * p, ngcore::Allocator & lh)
{
lh.ArrayDelete(p);
}
#endif // NETGEN_CORE_LOCALHEAP_HPP

View File

@ -13,13 +13,16 @@
namespace ngcore
{
std::ostream* testout = new std::ostream(nullptr); // NOLINT
level::level_enum Logger::global_level = level::warn;
void Logger::log(level::level_enum level, std::string && s)
{
#ifdef NETGEN_USE_SPDLOG
logger->log(spdlog::level::level_enum(level), s);
#else // NETGEN_USE_SPDLOG
if(level>level::debug)
if(level>=global_level)
std::clog << s << '\n';
#endif // NETGEN_USE_SPDLOG
}
@ -125,7 +128,11 @@ namespace ngcore
return std::make_shared<Logger>(std::make_shared<spdlog::logger>());
}
void SetLoggingLevel(level::level_enum /*unused*/, const std::string& /*unused*/) {}
void SetLoggingLevel(level::level_enum level, const std::string& /*unused*/)
{
Logger::SetGlobalLoggingLevel(level);
}
void AddFileSink(const std::string& /*unused*/, level::level_enum /*unused*/,
const std::string& /*unused*/)
{}

View File

@ -31,6 +31,8 @@ namespace spdlog
namespace ngcore
{
NGCORE_API extern std::ostream* testout; // NOLINT
namespace level
{
enum level_enum
@ -47,7 +49,11 @@ namespace ngcore
class Logger
{
static NGCORE_API level::level_enum global_level;
public:
static void SetGlobalLoggingLevel( level::level_enum level ) { global_level = level; }
std::shared_ptr<spdlog::logger> logger;
Logger(std::shared_ptr<spdlog::logger> l) : logger(std::move(l)) {}

173
libsrc/core/memtracer.hpp Normal file
View File

@ -0,0 +1,173 @@
#ifndef NETGEN_CORE_MEMTRACER_HPP
#define NETGEN_CORE_MEMTRACER_HPP
#include <array>
#include <chrono>
#include <string>
#include "array.hpp"
#include "logging.hpp"
#include "paje_trace.hpp"
#include "utils.hpp"
namespace ngcore
{
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*8*1024)
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
#endif // NETGEN_CORE_MEMTRACER_HPP

View File

@ -6,6 +6,11 @@
#include <mpi.h>
#endif
#include "array.hpp"
#include "table.hpp"
#include "exception.hpp"
#include "profiler.hpp"
#include "ngstream.hpp"
namespace ngcore
{
@ -23,6 +28,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; } };
@ -40,6 +48,27 @@ namespace ngcore
inline MPI_Datatype GetMPIType () {
return MPI_typetrait<T>::MPIType();
}
template <class T>
inline MPI_Datatype GetMPIType (T &) {
return GetMPIType<T>();
}
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);
}
inline int MyMPI_WaitAny (FlatArray<MPI_Request> requests)
{
int nr;
MPI_Waitany (requests.Size(), requests.Data(), &nr, MPI_STATUS_IGNORE);
return nr;
}
class NgMPI_Comm
@ -57,6 +86,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
@ -87,6 +127,11 @@ namespace ngcore
MPI_Comm_free(&comm);
}
bool ValidCommunicator() const
{
return valid_comm;
}
NgMPI_Comm & operator= (const NgMPI_Comm & c)
{
if (refcount)
@ -115,6 +160,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);
}
@ -125,12 +171,48 @@ namespace ngcore
void Send (T & val, int dest, int tag) const {
MPI_Send (&val, 1, GetMPIType<T>(), dest, tag, comm);
}
void Send (const std::string & s, int dest, int tag) const {
MPI_Send( const_cast<char*> (&s[0]), s.length(), MPI_CHAR, dest, tag, comm);
}
template<typename T, typename 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);
}
template<typename T, typename T2 = decltype(GetMPIType<T>())>
void Recv (T & val, int src, int tag) const {
MPI_Recv (&val, 1, GetMPIType<T>(), src, tag, comm, MPI_STATUS_IGNORE);
}
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 TI, typename T2 = decltype(GetMPIType<T>())>
void Recv (Array <T,TI> & s, int src, int tag) const
{
MPI_Status status;
int len;
const MPI_Datatype MPI_T = GetMPIType<T> ();
MPI_Probe (src, tag, comm, &status);
MPI_Get_count (&status, MPI_T, &len);
s.SetSize (len);
MPI_Recv (s.Data(), len, MPI_T, src, tag, comm, MPI_STATUS_IGNORE);
}
/** --- non-blocking P2P --- **/
@ -141,7 +223,15 @@ namespace ngcore
MPI_Isend (&val, 1, GetMPIType<T>(), dest, tag, comm, &request);
return request;
}
template<typename T, typename T2 = decltype(GetMPIType<T>())>
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);
return request;
}
template<typename T, typename T2 = decltype(GetMPIType<T>())>
MPI_Request IRecv (T & val, int dest, int tag) const
{
@ -150,11 +240,21 @@ namespace ngcore
return request;
}
template<typename T, typename T2 = decltype(GetMPIType<T>())>
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);
return request;
}
/** --- collectives --- **/
template <typename T, typename T2 = decltype(GetMPIType<T>())>
T Reduce (T d, const MPI_Op & op, int root = 0)
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;
@ -165,6 +265,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;
@ -172,11 +273,35 @@ namespace ngcore
return global_d;
}
template <typename T, typename T2 = decltype(GetMPIType<T>())>
void AllReduce (FlatArray<T> d, const MPI_Op & op) const
{
static Timer t("MPI - AllReduce Array"); RegionTimer reg(t);
if (size == 1) return;
MPI_Allreduce (MPI_IN_PLACE, d.Data(), d.Size(), GetMPIType<T>(), op, comm);
}
template <typename T, typename T2 = decltype(GetMPIType<T>())>
void Bcast (T & s, int root = 0) const {
if (size == 1) return ;
if (size == 1) return;
static Timer t("MPI - Bcast"); RegionTimer reg(t);
MPI_Bcast (&s, 1, GetMPIType<T>(), root, comm);
}
template <class T>
void Bcast (Array<T> & d, int root = 0)
{
if (size == 1) return;
int ds = d.Size();
Bcast (ds, root);
if (Rank() != root) d.SetSize (ds);
if (ds != 0)
MPI_Bcast (d.Data(), ds, GetMPIType<T>(), root, comm);
}
void Bcast (std::string & s, int root = 0) const
{
@ -187,11 +312,145 @@ 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 GatherRoot (FlatArray<T> recv) const
{
recv[0] = T(0);
if (size == 1) return;
MPI_Gather (MPI_IN_PLACE, 1, GetMPIType<T>(),
recv.Data(), 1, GetMPIType<T>(), 0, comm);
}
template <typename T>
void Gather (T send) const
{
if (size == 1) return;
MPI_Gather (&send, 1, GetMPIType<T>(),
NULL, 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);
}
template <typename T>
void ExchangeTable (DynamicTable<T> & send_data,
DynamicTable<T> & recv_data, int tag)
{
Array<int> send_sizes(size);
Array<int> recv_sizes(size);
for (int i = 0; i < size; i++)
send_sizes[i] = send_data[i].Size();
AllToAll (send_sizes, recv_sizes);
recv_data = DynamicTable<T> (recv_sizes, true);
Array<MPI_Request> requests;
for (int dest = 0; dest < size; dest++)
if (dest != rank && send_data[dest].Size())
requests.Append (ISend (FlatArray<T>(send_data[dest]), dest, tag));
for (int dest = 0; dest < size; dest++)
if (dest != rank && recv_data[dest].Size())
requests.Append (IRecv (FlatArray<T>(recv_data[dest]), dest, tag));
MyMPI_WaitAll (requests);
}
NgMPI_Comm SubCommunicator (FlatArray<int> procs) const
{
MPI_Comm subcomm;
MPI_Group gcomm, gsubcomm;
MPI_Comm_group(comm, &gcomm);
MPI_Group_incl(gcomm, procs.Size(), procs.Data(), &gsubcomm);
MPI_Comm_create_group(comm, gsubcomm, 4242, &subcomm);
return NgMPI_Comm(subcomm, true);
}
}; // class NgMPI_Comm
#else
class MyMPI
{
bool initialized_by_me;
public:
MyMPI(int argc, char ** argv)
{
int is_init = -1;
MPI_Initialized(&is_init);
if (!is_init)
{
MPI_Init (&argc, &argv);
initialized_by_me = true;
}
else
initialized_by_me = false;
NgMPI_Comm comm(MPI_COMM_WORLD);
NGSOStream::SetGlobalActive (comm.Rank() == 0);
if (comm.Size() > 1)
TaskManager::SetNumThreads (1);
}
~MyMPI()
{
if (initialized_by_me)
MPI_Finalize ();
}
};
#else // PARALLEL
class MPI_Comm {
int nr;
public:
@ -202,9 +461,13 @@ 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 };
inline void MPI_Type_contiguous ( int, MPI_Datatype, MPI_Datatype*) { ; }
inline void MPI_Type_commit ( MPI_Datatype * ) { ; }
class NgMPI_Comm
{
@ -215,6 +478,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(); }
@ -222,35 +486,72 @@ namespace ngcore
void Send( T & val, int dest, int tag) const { ; }
template<typename T>
void MyMPI_Recv (T & val, int src, int tag) const { ; }
void Send(FlatArray<T> s, int dest, int tag) const { ; }
template<typename T>
void Recv (T & val, int src, int tag) const { ; }
template <typename T>
void Recv (FlatArray <T> s, int src, int tag) const { ; }
template <typename T>
void Recv (Array <T> & s, int src, int tag) const { ; }
template<typename T>
MPI_Request ISend (T & val, int dest, int tag) const { return 0; }
template<typename T>
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 (FlatArray<T> s, int src, int tag) const { return 0; }
template <typename T>
T Reduce (T d, const MPI_Op & op, int root = 0) { return d; }
T Reduce (T d, const MPI_Op & op, int root = 0) const { return d; }
template <typename T>
T AllReduce (T d, const MPI_Op & op) const { return d; }
template <typename T>
void AllReduce (FlatArray<T> d, const MPI_Op & op) const { ; }
template <typename T>
void Bcast (T & s, int root = 0) const { ; }
template <class T>
void Bcast (Array<T> & d, int root = 0) { ; }
template <typename T>
void AllGather (T val, FlatArray<T> recv) const
{
recv[0] = val;
}
template <typename T>
void ExchangeTable (DynamicTable<T> & send_data,
DynamicTable<T> & recv_data, int tag) { ; }
NgMPI_Comm SubCommunicator (FlatArray<int> procs) const
{ return *this; }
};
#endif
inline void MyMPI_WaitAll (FlatArray<MPI_Request> requests) { ; }
inline int MyMPI_WaitAny (FlatArray<MPI_Request> requests) { return 0; }
class MyMPI
{
public:
MyMPI(int argc, char ** argv) { ; }
};
#endif // PARALLEL
}
} // namespace ngcore
#endif
#endif // NGCORE_MPIWRAPPER_HPP

View File

@ -2,11 +2,23 @@
#define NETGEN_CORE_NGCORE_HPP
#include "archive.hpp"
#include "array.hpp"
#include "bitarray.hpp"
#include "exception.hpp"
#include "flags.hpp"
#include "table.hpp"
#include "hashtable.hpp"
#include "localheap.hpp"
#include "logging.hpp"
#include "profiler.hpp"
#include "symboltable.hpp"
#include "version.hpp"
#include "mpi_wrapper.hpp"
#include "profiler.hpp"
#include "signal.hpp"
#include "simd.hpp"
#include "symboltable.hpp"
#include "taskmanager.hpp"
#include "version.hpp"
#include "xbool.hpp"
#include "ngstream.hpp"
#include "utils.hpp"
#endif // NETGEN_CORE_NGCORE_HPP

View File

@ -1,6 +1,39 @@
#ifndef NETGEN_CORE_NGCORE_API_HPP
#define NETGEN_CORE_NGCORE_API_HPP
#ifdef WIN32
// This function or variable may be unsafe. Consider using _ftime64_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
#pragma warning(disable:4244)
#pragma warning(disable:4996)
// multiple inheritance via dominance
#pragma warning(disable:4250)
// needs to have dll-interface to be used by clients of class
#pragma warning(disable:4251)
// size_t to int conversion:
#pragma warning(disable:4267)
// non dll-interface class 'std::exception' used as base for dll-interface class
#pragma warning(disable:4275)
// C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
#pragma warning(disable:4290)
// no suitable definition provided for explicit template instantiation request
#pragma warning(disable:4661)
// bool-int conversion
#pragma warning(disable:4800)
// '__declspec(dllexport)' and 'extern' are incompatible on an explicit instantiation
#pragma warning(disable:4910)
#endif // WIN32
#ifdef WIN32
#define NGCORE_API_EXPORT __declspec(dllexport)
#define NGCORE_API_IMPORT __declspec(dllimport)
@ -15,23 +48,103 @@
#define NGCORE_API NGCORE_API_IMPORT
#endif
// Set __host__ __device__ for all inline functions
#ifdef __CUDACC__
#define NETGEN_HD __host__ __device__
#else // __CUDACC__
#define NETGEN_HD
#endif // __CUDACC__
#ifdef __INTEL_COMPILER
#define NETGEN_ALWAYS_INLINE __forceinline
#define NETGEN_INLINE __forceinline inline
#ifdef WIN32
#define NETGEN_INLINE __forceinline inline
#define NETGEN_LAMBDA_INLINE
#else
#define NETGEN_INLINE __forceinline inline
#define NETGEN_LAMBDA_INLINE __attribute__ ((__always_inline__))
#endif
#else
#ifdef __GNUC__
#define NETGEN_INLINE __attribute__ ((__always_inline__)) inline
#define NETGEN_LAMBDA_INLINE __attribute__ ((__always_inline__))
#define NETGEN_ALWAYS_INLINE __attribute__ ((__always_inline__))
#define NETGEN_INLINE __attribute__ ((__always_inline__)) inline NETGEN_HD
#define NETGEN_LAMBDA_INLINE __attribute__ ((__always_inline__)) NETGEN_HD
#define NETGEN_VLA
#else
#define NETGEN_ALWAYS_INLINE
#define NETGEN_INLINE inline
#define NETGEN_LAMBDA_INLINE
#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,
// thus implement it here globally
#include <mm_malloc.h>
#ifdef __clang__
#pragma clang diagnostic ignored "-Winline-new-delete"
#endif
inline void * operator new (size_t s, std::align_val_t al)
{
if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
return _mm_malloc(s, int(al));
else
return new char[s];
}
inline void * operator new[] (size_t s, std::align_val_t al)
{
if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
return _mm_malloc(s, int(al));
else
return new char[s];
}
inline void operator delete ( void* ptr, std::align_val_t al ) noexcept
{
if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
_mm_free(ptr);
else
delete (char*)ptr;
}
inline void operator delete[]( void* ptr, std::align_val_t al ) noexcept
{
if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
_mm_free(ptr);
else
delete[] (char*)ptr;
}
inline void operator delete ( void* ptr, std::size_t sz, std::align_val_t al ) noexcept
{
if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
_mm_free(ptr);
else
delete (char*)ptr;
}
inline void operator delete[]( void* ptr, std::size_t sz, std::align_val_t al ) noexcept
{
if (int(al) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)
_mm_free(ptr);
else
delete[] (char*)ptr;
}
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED < 101300
#endif // NETGEN_CORE_NGCORE_API_HPP

115
libsrc/core/ngstream.hpp Normal file
View File

@ -0,0 +1,115 @@
#ifndef FILE_NGSTREAM
#define FILE_NGSTREAM
/**************************************************************************/
/* File: ng(s)stream.hpp */
/* Author: Joachim Schoeberl */
/* Date: 20. Jul. 2011 */
/**************************************************************************/
// #include <ios>
// #include <iostream>
namespace ngcore
{
NGCORE_API extern int printmessage_importance;
// important message
class IM
{
int value;
public:
IM (int val) : value(val) { ; }
int Value () const { return value; }
};
class trunc
{
double eps;
public:
trunc (double aeps) : eps(aeps) { ; }
double Eps() const { return eps; }
};
class NGSOStream
{
std::ostream & ost;
bool active;
NGCORE_API static bool glob_active;
double trunc;
public:
NGSOStream (std::ostream & aost, bool aactive)
: ost(aost), active(aactive), trunc(-1) { ; }
NGSOStream & SetTrunc (double atrunc) { trunc = atrunc; return *this; }
double GetTrunc () const { return trunc; }
bool Active () const { return active && glob_active; }
std::ostream & GetStream () { return ost; }
static void SetGlobalActive (bool b) { glob_active = b; }
};
inline NGSOStream operator<< (std::ostream & ost, const IM & im)
{
return NGSOStream (ost,
(im.Value() <= printmessage_importance));
}
/*
// doesn't work for matrices
inline NGSOStream operator<< (ostream & ost, trunc tr)
{
cout << "set trunc modifier" << endl;
return NGSOStream (ost, true).SetTrunc (tr.Eps());
}
*/
template <typename T>
inline NGSOStream operator<< (NGSOStream ngsost, const T & data)
{
if (ngsost.Active())
ngsost.GetStream() << data;
return ngsost;
}
/*
inline NGSOStream operator<< (NGSOStream ngsost, const double & data)
{
cout << "double out" << endl;
if (ngsost.Active())
{
double hdata = data;
if (fabs (hdata) < ngsost.GetTrunc()) hdata = 0.0;
ngsost.GetStream() << hdata;
}
return ngsost;
}
*/
inline NGSOStream operator<< (NGSOStream ngsost, std::ostream& ( *pf )(std::ostream&))
{
if ( ngsost.Active() )
ngsost.GetStream() << (*pf);
return ngsost;
}
inline NGSOStream operator<< (NGSOStream ngsost, std::ios& ( *pf )(std::ios&))
{
if ( ngsost.Active() )
ngsost.GetStream() << (*pf);
return ngsost;
}
inline NGSOStream operator<< (NGSOStream ngsost, std::ios_base& ( *pf )(std::ios_base&))
{
if ( ngsost.Active() )
ngsost.GetStream() << (*pf);
return ngsost;
}
}
#endif

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,14 +65,73 @@ namespace ngcore
jobs.reserve(reserve_size);
timer_events.reserve(reserve_size);
gpu_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.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 & event : user_events)
{
event.t_start -= start_time;
event.t_end -= start_time;
}
for(auto & event : gpu_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();
for(auto & event : gpu_events)
event.timer_id += NgProfiler::SIZE*comm.Rank();
if(comm.Rank() == MPI_PAJE_WRITER)
Write(tracefile_name);
else
SendData();
}
}
@ -84,13 +161,12 @@ namespace ngcore
else if (x<5*d)
r=6*(x-4*d), g=0,b=1;
else
r=1, g=0,b=1-5*(x-d);
r=1, g=0,b=1-6*(x-5*d);
};
int alias_counter;
FILE * ctrace_stream;
TTimePoint start_time;
std::shared_ptr<Logger> logger = GetLogger("PajeTrace");
@ -98,7 +174,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 (t-start_time) / 2.7e6;
return 1000.0*static_cast<double>(t) * seconds_per_tick;
}
enum PType
@ -122,6 +198,10 @@ namespace ngcore
: time(atime), event_type(aevent_type), type(atype), container(acontainer), value(avalue), id(aid), value_is_alias(avalue_is_alias)
{ }
PajeEvent( int aevent_type, double atime, int atype, int acontainer, std::string as_value, int aid = 0 )
: time(atime), event_type(aevent_type), type(atype), container(acontainer), id(aid), s_value(as_value), value_is_alias(false), value_is_int(false)
{ }
PajeEvent( int aevent_type, double atime, int atype, int acontainer, int avalue, int astart_container, int akey )
: time(atime), event_type(aevent_type), type(atype), container(acontainer), value(avalue), start_container(astart_container), id(akey)
{ }
@ -131,10 +211,12 @@ namespace ngcore
int event_type;
int type;
int container;
std::string s_value = "";
int value = 0;
int start_container = 0;
int id = 0;
bool value_is_alias = true;
bool value_is_int = true;
bool operator < (const PajeEvent & other) const {
// Same start and stop times can occur for very small tasks -> take "starting" events first (eg. PajePushState before PajePopState)
@ -158,8 +240,10 @@ namespace ngcore
case PajePushState:
if(value_is_alias)
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\ta%d\t%d\n", PajePushState, time, type, container, value, id); // NOLINT
else
else if(value_is_int)
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%d\t%d\n", PajePushState, time, type, container, value, id); // NOLINT
else
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t\"%s\"\t%d\n", PajePushState, time, type, container, s_value.c_str(), id); // NOLINT
case PajePopState:
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\n", PajePopState, time, type, container ); // NOLINT
case PajeStartLink:
@ -180,10 +264,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;
}
@ -241,7 +325,9 @@ namespace ngcore
}
int alias = ++alias_counter;
double r,g,b;
double r;
double g;
double b;
Hue2RGB( hue, r, g, b );
fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\t\"%.15g %.15g %.15g\"\n", PajeDefineEntityValue, alias, type, name.c_str(), r,g,b ); // NOLINT
return alias;
@ -282,6 +368,11 @@ namespace ngcore
events.emplace_back( PajeEvent( PajePushState, ConvertTime(time), type, container, value, id, value_is_alias) );
}
void PushState ( TTimePoint time, int type, int container, std::string value, int id = 0)
{
events.emplace_back( PajeEvent( PajePushState, ConvertTime(time), type, container, value, id) );
}
void PopState ( TTimePoint time, int type, int container )
{
events.emplace_back( PajeEvent( PajePopState, ConvertTime(time), type, container ) );
@ -346,7 +437,7 @@ namespace ngcore
void PajeTrace::Write( const std::string & filename )
{
int n_events = jobs.size() + timer_events.size();
auto n_events = jobs.size() + timer_events.size();
for(auto & vtasks : tasks)
n_events += vtasks.size();
@ -363,39 +454,86 @@ 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;
container_nodes.reserve(num_nodes);
for(int i=0; i<num_nodes; i++)
#ifdef PARALLEL
// Hostnames
NgMPI_Comm comm(MPI_COMM_WORLD);
auto rank = comm.Rank();
auto nranks = comm.Size();
if(nranks>1)
{
nthreads = nranks;
thread_aliases.reserve(nthreads);
std::array<char, MPI_MAX_PROCESSOR_NAME+1> ahostname;
int len;
MPI_Get_processor_name(ahostname.data(), &len);
std::string hostname = ahostname.data();
std::map<std::string, int> host_map;
std::string name;
for(auto i : IntRange(0, nranks))
{
if(i!=MPI_PAJE_WRITER)
comm.Recv(name, i, 0);
else
name = hostname;
if(host_map.count(name)==0)
{
host_map[name] = container_nodes.size();
container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, name) );
}
thread_aliases.emplace_back( paje.CreateContainer( container_type_thread, container_nodes[host_map[name]], "Rank " + ToString(i) ) );
}
}
else
#endif // PARALLEL
{
container_nodes.reserve(num_nodes);
for(int i=0; i<num_nodes; i++)
container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, "Node " + ToString(i)) );
std::vector <int> thread_aliases;
thread_aliases.reserve(nthreads);
if(trace_threads)
for (int i=0; i<nthreads; i++)
thread_aliases.reserve(nthreads);
if(trace_threads)
for (int i=0; i<nthreads; i++)
{
auto name = "Timer level " + ToString(i);
thread_aliases.emplace_back( paje.CreateContainer( container_type_thread, container_nodes[i*num_nodes/nthreads], name ) );
auto name = "Thread " + ToString(i);
if(tasks[i].size())
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;
@ -414,20 +552,75 @@ 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_ids.insert(event.timer_id);
for(auto & event : gpu_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 (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;
@ -459,6 +652,54 @@ namespace ngcore
paje.PopState( event.time, state_type_timer, timer_container_aliases[--timerdepth] );
}
if(gpu_events.size())
{
auto gpu_container = paje.CreateContainer( container_type_timer, container_task_manager, "GPU" );
for(auto & event : gpu_events)
{
if(event.is_start)
paje.PushState( event.time, state_type_timer, gpu_container, timer_aliases[event.timer_id] );
else
paje.PopState( event.time, state_type_timer, gpu_container);
}
}
if(user_events.size())
{
std::sort (user_events.begin(), user_events.end());
std::map<int, int> containers;
for(auto i : Range(user_containers.size()))
{
auto & [name, parent] = user_containers[i];
int a_parent = parent == -1 ? container_task_manager : containers[parent];
containers[i] = paje.CreateContainer( container_type_timer, a_parent, name );
}
for(auto ev : user_events)
{
if(containers[ev.container]==0)
{
std::string name = "User " + ToString(ev.container);
containers[ev.container] = paje.CreateContainer( container_type_timer, container_task_manager, name );
}
}
int i_start = 0;
for(auto i : Range(user_events.size()))
{
auto & event = user_events[i];
while(i_start < user_events.size() && user_events[i_start].t_start < event.t_end)
{
auto & ev = user_events[i_start];
paje.PushState( ev.t_start, state_type_timer, containers[ev.container], ev.data, ev.id );
i_start++;
}
paje.PopState( event.t_end, state_type_timer, containers[event.container]);
}
}
for(auto & vtasks : tasks)
{
for (Task & t : vtasks) {
@ -470,28 +711,80 @@ namespace ngcore
value_id = job_task_map[jobs[t.id-1].type];
if(trace_thread_counter)
{
paje.AddVariable( t.start_time, variable_type_active_threads, container_jobs, 1.0 );
paje.SubVariable( t.stop_time, variable_type_active_threads, container_jobs, 1.0 );
if(t.is_start)
paje.AddVariable( t.time, variable_type_active_threads, container_jobs, 1.0 );
else
paje.SubVariable( t.time, variable_type_active_threads, container_jobs, 1.0 );
}
if(trace_threads)
{
paje.PushState( t.start_time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, true );
paje.PopState( t.stop_time, state_type_task, thread_aliases[t.thread_id] );
if(t.is_start)
paje.PushState( t.time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, true );
else
paje.PopState( t.time, state_type_task, thread_aliases[t.thread_id] );
}
break;
case Task::ID_TIMER:
value_id = timer_aliases[t.id];
paje.PushState( t.start_time, state_type_timer, thread_aliases[t.thread_id], value_id, t.additional_value, true );
paje.PopState( t.stop_time, state_type_timer, thread_aliases[t.thread_id] );
if(t.is_start)
paje.PushState( t.time, state_type_timer, thread_aliases[t.thread_id], value_id, t.additional_value, true );
else
paje.PopState( t.time, state_type_timer, thread_aliases[t.thread_id] );
break;
default:
paje.PushState( t.start_time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, false );
paje.PopState( t.stop_time, state_type_task, thread_aliases[t.thread_id] );
if(t.is_start)
paje.PushState( t.time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, false );
else
paje.PopState( t.time, state_type_task, thread_aliases[t.thread_id] );
break;
}
}
}
#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)
@ -550,8 +843,416 @@ namespace ngcore
}
}
}
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 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, std::ofstream & f)
{
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)
{
int i = 0;
f << ", children: [";
for(auto & c : n.children)
{
PrintNode(c.second, f);
if(++i<size)
f << " , ";
}
f << ']';
}
f << '}';
}
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.name="all";
TreeNode *current = &root;
std::vector<TreeNode*> node_stack;
node_stack.push_back(&root);
TTimePoint stop_time = 0;
for(auto & event : timer_events)
{
events.push_back(event);
stop_time = std::max(event.time, stop_time);
}
std::map<std::string, int> jobs_map;
std::vector<std::string> job_names;
for(auto & job : jobs)
{
auto name = Demangle(job.type->name());
int id = job_names.size();
if(jobs_map.count(name)==0)
{
jobs_map[name] = id;
job_names.push_back(name);
}
else
id = jobs_map[name];
events.push_back(TimerEvent{-1, job.start_time, true, id});
events.push_back(TimerEvent{-1, job.stop_time, false, id});
stop_time = std::max(job.stop_time, stop_time);
}
std::sort (events.begin(), events.end());
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)
{
bool is_timer_event = event.timer_id != -1;
int id = is_timer_event ? event.timer_id : event.thread_id;
if(event.is_start)
{
bool need_init = !current->children.count(id);
node_stack.push_back(current);
current = &current->children[id];
if(need_init)
{
current->name = is_timer_event ? GetTimerName(id) : job_names[id];
current->size = 0.0;
current->id = id;
}
current->start_time = event.time;
}
else
{
if(node_stack.size()==0) {
std::cout << "node stack empty!" << std::endl;
break;
}
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->chart_size -= size;
node_stack.pop_back();
}
}
root.chart_size = 0.0;
ngcore::WriteSunburstHTML( root, tracefile_name, true );
}
} // namespace ngcore
const char *header =

View File

@ -1,6 +1,7 @@
#ifndef NETGEN_CORE_PAJE_TRACE_HPP
#define NETGEN_CORE_PAJE_TRACE_HPP
#include <algorithm>
#include <limits>
#include <vector>
@ -23,17 +24,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:
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;
@ -68,8 +80,8 @@ namespace ngcore
int additional_value;
TTimePoint start_time;
TTimePoint stop_time;
TTimePoint time;
bool is_start;
static constexpr int ID_NONE = -1;
static constexpr int ID_JOB = 1;
@ -86,6 +98,16 @@ namespace ngcore
bool operator < (const TimerEvent & other) const { return time < other.time; }
};
struct UserEvent
{
TTimePoint t_start = 0, t_end = 0;
std::string data = "";
int container = 0;
int id = 0;
bool operator < (const UserEvent & other) const { return t_start < other.t_start; }
};
struct ThreadLink
{
int thread_id;
@ -95,10 +117,24 @@ 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<UserEvent> user_events;
std::vector<std::tuple<std::string, int>> user_containers;
std::vector<TimerEvent> gpu_events;
std::vector<std::vector<ThreadLink> > links;
NGCORE_API static std::vector<MemoryEvent> memory_events;
public:
NGCORE_API void StopTracing();
@ -112,6 +148,36 @@ namespace ngcore
void operator=(const PajeTrace &) = delete;
void operator=(PajeTrace &&) = delete;
int AddUserContainer(std::string name, int parent=-1)
{
if(auto pos = std::find(user_containers.begin(), user_containers.end(), std::tuple{name,parent}); pos != user_containers.end())
return pos - user_containers.begin();
int id = user_containers.size();
user_containers.push_back({name, parent});
return id;
}
void AddUserEvent(UserEvent ue)
{
if(!tracing_enabled) return;
user_events.push_back(ue);
}
void StartGPU(int timer_id = 0)
{
if(!tracing_enabled) return;
if(unlikely(gpu_events.size() == max_num_events_per_thread))
StopTracing();
gpu_events.push_back(TimerEvent{timer_id, GetTimeCounter(), true});
}
void StopGPU(int timer_id)
{
if(!tracing_enabled) return;
if(unlikely(gpu_events.size() == max_num_events_per_thread))
StopTracing();
gpu_events.push_back(TimerEvent{timer_id, GetTimeCounter(), false});
}
void StartTimer(int timer_id)
{
if(!tracing_enabled) return;
@ -128,30 +194,44 @@ namespace ngcore
timer_events.push_back(TimerEvent{timer_id, GetTimeCounter(), false});
}
NETGEN_INLINE int StartTask(int thread_id, int id, int id_type = Task::ID_NONE, int additional_value = -1)
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);
}
int StartTask(int thread_id, int id, int id_type = Task::ID_NONE, int additional_value = -1)
{
if(!tracing_enabled) return -1;
if(!trace_threads && !trace_thread_counter) return -1;
if(unlikely(tasks[thread_id].size() == max_num_events_per_thread))
StopTracing();
int task_num = tasks[thread_id].size();
tasks[thread_id].push_back( Task{thread_id, id, id_type, additional_value, GetTimeCounter()} );
tasks[thread_id].push_back( Task{thread_id, id, id_type, additional_value, GetTimeCounter(), true} );
return task_num;
}
void StopTask(int thread_id, int task_num)
void StopTask(int thread_id, int id, int id_type = Task::ID_NONE)
{
if(!trace_threads && !trace_thread_counter) return;
if(task_num>=0)
tasks[thread_id][task_num].stop_time = GetTimeCounter();
tasks[thread_id].push_back( Task{thread_id, id, id_type, 0, GetTimeCounter(), false} );
}
void SetTask(int thread_id, int task_num, int additional_value) {
if(!trace_threads && !trace_thread_counter) return;
if(task_num>=0)
tasks[thread_id][task_num].additional_value = additional_value;
}
void StartJob(int job_id, const std::type_info & type)
{
if(!tracing_enabled) return;
@ -184,6 +264,8 @@ namespace ngcore
void Write( const std::string & filename );
void SendData(); // MPI parallel data reduction
};
} // namespace ngcore

View File

@ -8,10 +8,10 @@ namespace ngcore
std::string NgProfiler::filename;
size_t NgProfiler::dummy_thread_times[NgProfiler::SIZE];
size_t * NgProfiler::thread_times = NgProfiler::dummy_thread_times; // NOLINT
size_t NgProfiler::dummy_thread_flops[NgProfiler::SIZE];
size_t * NgProfiler::thread_flops = NgProfiler::dummy_thread_flops; // NOLINT
std::array<size_t,NgProfiler::SIZE> NgProfiler::dummy_thread_times;
size_t * NgProfiler::thread_times = NgProfiler::dummy_thread_times.data(); // NOLINT
std::array<size_t,NgProfiler::SIZE> NgProfiler::dummy_thread_flops;
size_t * NgProfiler::thread_flops = NgProfiler::dummy_thread_flops.data(); // NOLINT
std::shared_ptr<Logger> NgProfiler::logger = GetLogger("Profiler"); // NOLINT
@ -94,7 +94,7 @@ namespace ngcore
if (first_overflow)
{
first_overflow = false;
NgProfiler::logger->warn("no more timer available, reusing last one");
NgProfiler::logger->warn( ("no more timer available ("+name+"), reusing last one").c_str());
}
return 0;
}
@ -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

@ -1,11 +1,15 @@
#ifndef NETGEN_CORE_PROFILER_HPP
#define NETGEN_CORE_PROFILER_HPP
#include <array>
#include <chrono>
#include <functional>
#include <string>
#include "array.hpp"
#include "logging.hpp"
#include "paje_trace.hpp"
#include "taskmanager.hpp"
#include "utils.hpp"
namespace ngcore
@ -21,7 +25,7 @@ namespace ngcore
TimerVal() = default;
double tottime = 0.0;
double starttime = 0.0;
TTimePoint starttime=0;
double flops = 0.0;
double loads = 0.0;
double stores = 0.0;
@ -35,8 +39,8 @@ namespace ngcore
NGCORE_API static TTimePoint * thread_times;
NGCORE_API static TTimePoint * thread_flops;
NGCORE_API static std::shared_ptr<Logger> logger;
NGCORE_API static size_t dummy_thread_times[NgProfiler::SIZE];
NGCORE_API static size_t dummy_thread_flops[NgProfiler::SIZE];
NGCORE_API static std::array<size_t, NgProfiler::SIZE> dummy_thread_times;
NGCORE_API static std::array<size_t, NgProfiler::SIZE> dummy_thread_flops;
private:
NGCORE_API static std::string filename;
@ -60,13 +64,13 @@ namespace ngcore
/// start timer of index nr
static void StartTimer (int nr)
{
timers[nr].starttime = WallTime(); timers[nr].count++;
timers[nr].starttime = GetTimeCounter(); timers[nr].count++;
}
/// stop timer of index nr
static void StopTimer (int nr)
{
timers[nr].tottime += WallTime()-timers[nr].starttime;
timers[nr].tottime += (GetTimeCounter()-timers[nr].starttime)*seconds_per_tick;
}
static void StartThreadTimer (size_t nr, size_t tid)
@ -143,39 +147,98 @@ namespace ngcore
};
};
struct TNoTracing{ static constexpr bool do_tracing=false; };
struct TTracing{ static constexpr bool do_tracing=true; };
struct TNoTiming{ static constexpr bool do_timing=false; };
struct TTiming{ static constexpr bool do_timing=true; };
class NGCORE_API Timer
namespace detail {
template<typename T>
constexpr bool is_tracing_type_v = std::is_same_v<T, TNoTracing> || std::is_same_v<T, TTracing>;
template<typename T>
constexpr bool is_timing_type_v = std::is_same_v<T, TNoTiming> || std::is_same_v<T, TTiming>;
}
[[maybe_unused]] static TNoTracing NoTracing;
[[maybe_unused]] static TNoTiming NoTiming;
template<typename TTracing=TTracing, typename TTiming=TTiming>
class Timer
{
int timernr;
int priority;
public:
Timer (const std::string & name, int apriority = 1)
: priority(apriority)
int Init( const std::string & name )
{
timernr = NgProfiler::CreateTimer (name);
return NgProfiler::CreateTimer (name);
}
public:
static constexpr bool do_tracing = TTracing::do_tracing;
static constexpr bool do_timing = TTiming::do_timing;
Timer (const std::string & name) : timernr(Init(name)) { }
template<std::enable_if_t< detail::is_tracing_type_v<TTracing>, bool> = false>
Timer( const std::string & name, TTracing ) : timernr(Init(name)) { }
template<std::enable_if_t< detail::is_timing_type_v<TTiming>, bool> = false>
Timer( const std::string & name, TTiming ) : timernr(Init(name)) { }
Timer( const std::string & name, TTracing, TTiming ) : timernr(Init(name)) { }
[[deprecated ("Use Timer(name, NoTracing/NoTiming) instead")]] Timer( const std::string & name, int ) : timernr(Init(name)) {}
void SetName (const std::string & name)
{
NgProfiler::SetName (timernr, name);
}
void Start ()
void Start () const
{
if (priority <= 2)
NgProfiler::StartTimer (timernr);
if (priority <= 1)
if(trace) trace->StartTimer(timernr);
Start(TaskManager::GetThreadId());
}
void Stop ()
void Stop () const
{
if (priority <= 2)
NgProfiler::StopTimer (timernr);
if (priority <= 1)
if(trace) trace->StopTimer(timernr);
Stop(TaskManager::GetThreadId());
}
void Start (int tid) const
{
if(tid==0)
{
if constexpr(do_timing)
NgProfiler::StartTimer (timernr);
if constexpr(do_tracing)
if(trace) trace->StartTimer(timernr);
}
else
{
if constexpr(do_timing)
NgProfiler::StartThreadTimer(timernr, tid);
if constexpr(do_tracing)
if(trace) trace->StartTask (tid, timernr, PajeTrace::Task::ID_TIMER);
}
}
void Stop (int tid) const
{
if(tid==0)
{
if constexpr(do_timing)
NgProfiler::StopTimer (timernr);
if constexpr(do_tracing)
if(trace) trace->StopTimer(timernr);
}
else
{
if constexpr(do_timing)
NgProfiler::StopThreadTimer(timernr, tid);
if constexpr(do_tracing)
if(trace) trace->StopTask (tid, timernr, PajeTrace::Task::ID_TIMER);
}
}
void AddFlops (double aflops)
{
if (priority <= 2)
if constexpr(do_timing)
NgProfiler::AddFlops (timernr, aflops);
}
@ -184,7 +247,7 @@ namespace ngcore
double GetMFlops ()
{ return NgProfiler::GetFlops(timernr)
/ NgProfiler::GetTime(timernr) * 1e-6; }
operator int () { return timernr; }
operator int () const { return timernr; }
};
@ -192,14 +255,21 @@ namespace ngcore
Timer object.
Start / stop timer at constructor / destructor.
*/
template<typename TTimer>
class RegionTimer
{
Timer & timer;
const TTimer & timer;
int tid;
public:
/// start timer
RegionTimer (Timer & atimer) : timer(atimer) { timer.Start(); }
RegionTimer (const TTimer & atimer) : timer(atimer)
{
tid = TaskManager::GetThreadId();
timer.Start(tid);
}
/// stop timer
~RegionTimer () { timer.Stop(); }
~RegionTimer () { timer.Stop(tid); }
RegionTimer() = delete;
RegionTimer(const RegionTimer &) = delete;
@ -208,7 +278,7 @@ namespace ngcore
void operator=(RegionTimer &&) = delete;
};
class ThreadRegionTimer
class [[deprecated("Use RegionTimer instead (now thread safe)")]] ThreadRegionTimer
{
size_t nr;
size_t tid;
@ -231,6 +301,7 @@ namespace ngcore
{
int nr;
int thread_id;
int type;
public:
static constexpr int ID_JOB = PajeTrace::Task::ID_JOB;
static constexpr int ID_NONE = PajeTrace::Task::ID_NONE;
@ -247,28 +318,26 @@ namespace ngcore
: thread_id(athread_id)
{
if (trace)
nr = trace->StartTask (athread_id, region_id, id_type, additional_value);
trace->StartTask (athread_id, region_id, id_type, additional_value);
type = id_type;
nr = region_id;
}
/// start trace with timer
RegionTracer (int athread_id, Timer & timer, int additional_value = -1 )
template<typename TTimer>
RegionTracer (int athread_id, TTimer & timer, int additional_value = -1 )
: thread_id(athread_id)
{
nr = timer;
type = ID_TIMER;
if (trace)
nr = trace->StartTask (athread_id, static_cast<int>(timer), ID_TIMER, additional_value);
trace->StartTask (athread_id, nr, type, additional_value);
}
/// set user defined value
void SetValue( int additional_value )
{
if (trace)
trace->SetTask( thread_id, nr, additional_value );
}
/// stop trace
~RegionTracer ()
{
if (trace)
trace->StopTask (thread_id, nr);
trace->StopTask (thread_id, nr, type);
}
};
@ -300,5 +369,14 @@ namespace ngcore
} // namespace ngcore
// Helper macro to easily add multiple timers in a function for profiling
// Usage: NETGEN_TIMER_FROM_HERE("my_timer_name")
// Effect: define static Timer and RegionTimer with given name and line number
#define NETGEN_TOKEN_CONCAT(x, y) x ## y
#define NETGEN_TOKEN_CONCAT2(x, y) NETGEN_TOKEN_CONCAT(x, y)
#define NETGEN_TIMER_FROM_HERE(name) \
static Timer NETGEN_TOKEN_CONCAT2(timer_, __LINE__)( string(name)+"_"+ToString(__LINE__)); \
RegionTimer NETGEN_TOKEN_CONCAT2(rt_,__LINE__)(NETGEN_TOKEN_CONCAT2(timer_,__LINE__));
#endif // NETGEN_CORE_PROFILER_HPP

View File

@ -1,30 +1,168 @@
#include <pybind11/pybind11.h>
#include "logging.hpp"
#include "python_ngcore.hpp"
namespace py = pybind11;
using namespace ngcore;
using std::string;
PYBIND11_MODULE(pyngcore, m) // NOLINT
namespace ngcore
{
py::enum_<level::level_enum>(m, "LOG_LEVEL", "Logging level")
.value("Trace", level::trace)
.value("Debug", level::debug)
.value("Info", level::info)
.value("Warn", level::warn)
.value("Error", level::err)
.value("Critical", level::critical)
.value("Off", level::off);
bool ngcore_have_numpy = false;
bool parallel_pickling = true;
void SetFlag(Flags &flags, string s, py::object value)
{
if (py::isinstance<py::dict>(value))
{
py::dict vdd(value);
// call recursively to set dictionary
for (auto item : vdd) {
string name = item.first.cast<string>();
py::object val = py::reinterpret_borrow<py::object>(item.second);
SetFlag(flags, name, val);
}
return;
}
m.def("SetLoggingLevel", &SetLoggingLevel, py::arg("level"), py::arg("logger")="",
"Set logging level, if name is given only to the specific logger, else set the global logging level");
m.def("AddFileSink", &AddFileSink, py::arg("filename"), py::arg("level"), py::arg("logger")="",
"Add File sink, either only to logger specified or globally to all loggers");
m.def("AddConsoleSink", &AddConsoleSink, py::arg("level"), py::arg("logger")="",
"Add console output for specific logger or all if none given");
m.def("ClearLoggingSinks", &ClearLoggingSinks, py::arg("logger")="",
"Clear sinks of specific logger, or all if none given");
m.def("FlushOnLoggingLevel", &FlushOnLoggingLevel, py::arg("level"), py::arg("logger")="",
"Flush every message with level at least `level` for specific logger or all loggers if none given.");
}
if (py::isinstance<py::bool_>(value))
flags.SetFlag(s, value.cast<bool>());
if (py::isinstance<py::float_>(value))
flags.SetFlag(s, value.cast<double>());
if (py::isinstance<py::int_>(value))
flags.SetFlag(s, double(value.cast<int>()));
if (py::isinstance<py::str>(value))
flags.SetFlag(s, value.cast<string>());
if (py::isinstance<py::list>(value))
{
auto vdl = py::cast<py::list>(value);
if (py::len(vdl) > 0)
{
if(py::isinstance<py::float_>(vdl[0]) || py::isinstance<py::int_>(vdl[0]))
flags.SetFlag(s, makeCArray<double>(vdl));
if(py::isinstance<py::str>(vdl[0]))
flags.SetFlag(s, makeCArray<string>(vdl));
}
else
{
Array<string> dummystr;
Array<double> dummydbl;
flags.SetFlag(s,dummystr);
flags.SetFlag(s,dummydbl);
}
}
if (py::isinstance<py::tuple>(value))
{
auto vdt = py::cast<py::tuple>(value);
if (py::isinstance<py::float_>(value))
flags.SetFlag(s, makeCArray<double>(vdt));
if (py::isinstance<py::int_>(value))
flags.SetFlag(s, makeCArray<double>(vdt));
if (py::isinstance<py::str>(value))
flags.SetFlag(s, makeCArray<string>(vdt));
}
}
Flags CreateFlagsFromKwArgs(const py::kwargs& kwargs, py::object pyclass, py::list info)
{
static std::shared_ptr<Logger> logger = GetLogger("Flags");
py::dict flags_dict;
if (kwargs.contains("flags"))
{
logger->warn("WARNING: using flags as kwarg is deprecated{}, use the flag arguments as kwargs instead!",
pyclass.is_none() ? "" : std::string(" in ") + std::string(py::str(pyclass)));
auto addflags = py::cast<py::dict>(kwargs["flags"]);
for (auto item : addflags)
flags_dict[item.first.cast<string>().c_str()] = item.second;
}
py::dict special;
if(!pyclass.is_none())
{
auto flags_doc = pyclass.attr("__flags_doc__")();
for (auto item : kwargs)
if (!flags_doc.contains(item.first.cast<string>().c_str()) &&
!(item.first.cast<string>() == "flags"))
logger->warn("WARNING: kwarg '{}' is an undocumented flags option for class {}, maybe there is a typo?",
item.first.cast<string>(), std::string(py::str(pyclass)));
if(py::hasattr(pyclass,"__special_treated_flags__"))
special = pyclass.attr("__special_treated_flags__")();
}
for (auto item : kwargs)
{
auto name = item.first.cast<string>();
if (name != "flags")
{
if(!special.contains(name.c_str()))
flags_dict[name.c_str()] = item.second;
}
}
auto flags = py::cast<Flags>(flags_dict);
for (auto item : kwargs)
{
auto name = item.first.cast<string>();
if (name != "flags")
{
if(special.contains(name.c_str()))
special[name.c_str()](item.second, &flags, info);
}
}
return flags;
}
py::dict CreateDictFromFlags(const Flags& flags)
{
py::dict d;
std::string key;
for(auto i : Range(flags.GetNFlagsFlags()))
{
auto& f = flags.GetFlagsFlag(i, key);
d[key.c_str()] = CreateDictFromFlags(f);
}
for(auto i : Range(flags.GetNStringListFlags()))
{
auto strlistflag = flags.GetStringListFlag(i, key);
py::list lst;
for(auto& val : *strlistflag)
lst.append(val);
d[key.c_str()] = lst;
}
for(auto i : Range(flags.GetNNumListFlags()))
{
auto numlistflag = flags.GetNumListFlag(i, key);
py::list lst;
for(auto& val : *numlistflag)
lst.append(val);
d[key.c_str()] = lst;
}
for(auto i : Range(flags.GetNStringFlags()))
{
auto val = flags.GetStringFlag(i, key);
d[key.c_str()] = val;
}
for(auto i : Range(flags.GetNNumFlags()))
{
auto val = flags.GetNumFlag(i, key);
d[key.c_str()] = val;
}
for(auto i : Range(flags.GetNDefineFlags()))
{
auto val = flags.GetDefineFlag(i, key);
d[key.c_str()] = val;
}
for(auto i : Range(flags.GetNAnyFlags()))
{
auto& a = flags.GetAnyFlag(i, key);
d[key.c_str()] = CastAnyToPy(a);
}
return d;
}
} // namespace ngcore

View File

@ -0,0 +1,436 @@
#ifndef NETGEN_CORE_PYTHON_NGCORE_HPP
#define NETGEN_CORE_PYTHON_NGCORE_HPP
#include "ngcore_api.hpp" // for operator new
#include <pybind11/pybind11.h>
#include <pybind11/operators.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include <pybind11/stl/filesystem.h>
#include "array.hpp"
#include "table.hpp"
#include "archive.hpp"
#include "flags.hpp"
#include "ngcore_api.hpp"
#include "profiler.hpp"
namespace py = pybind11;
namespace ngcore
{
namespace detail
{
template<typename T>
struct HasPyFormat
{
private:
template<typename T2>
static auto check(T2*) -> std::enable_if_t<std::is_same_v<decltype(std::declval<py::format_descriptor<T2>>().format()), std::string>, std::true_type>;
static auto check(...) -> std::false_type;
public:
static constexpr bool value = decltype(check((T*) nullptr))::value;
};
} // namespace detail
} // namespace ngcore
////////////////////////////////////////////////////////////////////////////////
// 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>, enable_if_t<!ngcore::detail::HasPyFormat<Type>::value>>
: ngcore_list_caster<ngcore::Array<Type>, Type> { };
/*
template <typename Type> struct type_caster<std::shared_ptr<ngcore::Table<Type>>>
{
template <typename T>
static handle cast(T &&src, return_value_policy policy, handle parent)
{
std::cout << "handle called with type src = " << typeid(src).name() << std::endl;
return handle(); // what so ever
}
PYBIND11_TYPE_CASTER(Type, _("Table[") + make_caster<Type>::name + _("]"));
};
*/
} // 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>
struct PyNameTraits {
static const std::string & GetName()
{
static const std::string name = typeid(T).name();
return name;
}
};
template <typename T>
std::string GetPyName(const char *prefix = 0) {
std::string s;
if(prefix) s = std::string(prefix);
s+= PyNameTraits<T>::GetName();
return s;
}
template<>
struct PyNameTraits<int> {
static std::string GetName() { return "I"; }
};
template<>
struct PyNameTraits<unsigned> {
static std::string GetName() { return "U"; }
};
template<>
struct PyNameTraits<float> {
static std::string GetName() { return "F"; }
};
template<>
struct PyNameTraits<double> {
static std::string GetName() { return "D"; }
};
template<>
struct PyNameTraits<size_t> {
static std::string GetName() { return "S"; }
};
template<typename T>
struct PyNameTraits<std::shared_ptr<T>> {
static std::string GetName()
{ return std::string("sp_")+GetPyName<T>(); }
};
// *************** Archiving functionality **************
template<typename T>
Archive& Archive :: Shallow(T& val)
{
static_assert(detail::is_any_pointer<T>, "ShallowArchive must be given pointer type!");
#ifdef NETGEN_PYTHON
if(shallow_to_python)
{
if(is_output)
ShallowOutPython(pybind11::cast(val));
else
{
pybind11::object obj;
ShallowInPython(obj);
val = pybind11::cast<T>(obj);
}
}
else
#endif // NETGEN_PYTHON
*this & val;
return *this;
}
template<typename ARCHIVE>
class NGCORE_API_EXPORT PyArchive : public ARCHIVE
{
private:
pybind11::list lst;
size_t index = 0;
std::map<std::string, VersionInfo> version_needed;
protected:
using ARCHIVE::stream;
using ARCHIVE::version_map;
using ARCHIVE::logger;
public:
PyArchive(const pybind11::object& alst = pybind11::none()) :
ARCHIVE(std::make_shared<std::stringstream>()),
lst(alst.is_none() ? pybind11::list() : pybind11::cast<pybind11::list>(alst))
{
ARCHIVE::shallow_to_python = true;
if(Input())
{
stream = std::make_shared<std::stringstream>
(pybind11::cast<pybind11::bytes>(lst[pybind11::len(lst)-1]));
*this & version_needed;
logger->debug("versions needed for unpickling = {}", version_needed);
for(auto& libversion : version_needed)
if(libversion.second > GetLibraryVersion(libversion.first))
throw Exception("Error in unpickling data:\nLibrary " + libversion.first +
" must be at least " + libversion.second.to_string());
stream = std::make_shared<std::stringstream>
(pybind11::cast<pybind11::bytes>(lst[pybind11::len(lst)-2]));
*this & version_map;
stream = std::make_shared<std::stringstream>
(pybind11::cast<pybind11::bytes>(lst[pybind11::len(lst)-3]));
}
}
void NeedsVersion(const std::string& library, const std::string& version) override
{
if(Output())
{
logger->debug("Need version {} of library {}.", version, library);
version_needed[library] = version_needed[library] > version ? version_needed[library] : version;
}
}
using ARCHIVE::Output;
using ARCHIVE::Input;
using ARCHIVE::FlushBuffer;
using ARCHIVE::operator&;
using ARCHIVE::operator<<;
using ARCHIVE::GetVersion;
void ShallowOutPython(const pybind11::object& val) override { lst.append(val); }
void ShallowInPython(pybind11::object& val) override { val = lst[index++]; }
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 & version_runtime;
FlushBuffer();
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
stream = std::make_shared<std::stringstream>();
logger->debug("Writeout version needed = {}", version_needed);
*this & version_needed;
FlushBuffer();
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
return lst;
}
};
template<typename T, typename T_ARCHIVE_OUT=BinaryOutArchive, typename T_ARCHIVE_IN=BinaryInArchive>
auto NGSPickle()
{
return pybind11::pickle([](T* self)
{
PyArchive<T_ARCHIVE_OUT> ar;
ar.SetParallel(parallel_pickling);
ar & self;
auto output = pybind11::make_tuple(ar.WriteOut());
return output;
},
[](const pybind11::tuple & state)
{
T* val = nullptr;
PyArchive<T_ARCHIVE_IN> ar(state[0]);
ar & val;
return val;
});
}
template<typename T>
Array<T> makeCArray(const py::object& obj)
{
Array<T> arr;
if(py::isinstance<py::list>(obj))
for(auto& val : py::cast<py::list>(obj))
arr.Append(py::cast<T>(val));
else if(py::isinstance<py::tuple>(obj))
for(auto& val : py::cast<py::tuple>(obj))
arr.Append(py::cast<T>(val));
else
throw py::type_error("Cannot convert Python object to C Array");
return arr;
}
template <typename T, typename TIND=typename FlatArray<T>::index_type>
void ExportArray (py::module &m)
{
using TFlat = FlatArray<T, TIND>;
using TArray = Array<T, TIND>;
std::string suffix = GetPyName<T>() + "_" +
GetPyName<TIND>();
std::string fname = std::string("FlatArray_") + suffix;
auto flatarray_class = py::class_<TFlat>(m, fname.c_str(),
py::buffer_protocol())
.def ("__len__", [] ( TFlat &self ) { return self.Size(); } )
.def ("__getitem__",
[](TFlat & self, TIND i) -> T&
{
static constexpr int base = IndexBASE<TIND>();
if (i < base || i >= self.Size()+base)
throw py::index_error();
return self[i];
},
py::return_value_policy::reference)
.def ("__setitem__",
[](TFlat & self, TIND i, T val) -> T&
{
static constexpr int base = IndexBASE<TIND>();
if (i < base || i >= self.Size()+base)
throw py::index_error();
self[i] = val;
return self[i];
},
py::return_value_policy::reference)
.def ("__setitem__",
[](TFlat & self, py::slice slice, T val)
{
size_t start, stop, step, slicelength;
if (!slice.compute(self.Size(), &start, &stop, &step, &slicelength))
throw py::error_already_set();
static constexpr int base = IndexBASE<TIND>();
if (start < base || start+(slicelength-1)*step >= self.Size()+base)
throw py::index_error();
for (size_t i = 0; i < slicelength; i++, start+=step)
self[start] = val;
})
.def("__iter__", [] ( TFlat & self) {
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)
{
if(ngcore_have_numpy && !py::detail::npy_format_descriptor<T>::dtype().is_none())
{
flatarray_class
.def_buffer([](TFlat& self)
{
return py::buffer_info(
self.Addr(0),
sizeof(T),
py::format_descriptor<T>::format(),
1,
{ self.Size() },
{ sizeof(T) * (self.Addr(1) - self.Addr(0)) });
})
.def("NumPy", [](py::object self)
{
return py::module::import("numpy")
.attr("frombuffer")(self, py::detail::npy_format_descriptor<T>::dtype());
})
;
}
}
std::string aname = std::string("Array_") + suffix;
auto arr = py::class_<TArray, TFlat> (m, aname.c_str())
.def(py::init([] (size_t n) { return new TArray(n); }),py::arg("n"), "Makes array of given length")
.def(py::init([] (std::vector<T> const & x)
{
size_t s = x.size();
TArray tmp(s);
for (size_t i : Range(tmp))
tmp[TIND(i)] = x[i];
return tmp;
}), py::arg("vec"), "Makes array with given list of elements")
;
if constexpr(is_archivable<TArray>)
arr.def(NGSPickle<TArray>());
py::implicitly_convertible<std::vector<T>, TArray>();
}
template <typename T>
void ExportTable (py::module &m)
{
py::class_<ngcore::Table<T>, std::shared_ptr<ngcore::Table<T>>> (m, ("Table_"+GetPyName<T>()).c_str())
.def(py::init([] (py::list blocks)
{
size_t size = py::len(blocks);
Array<int> cnt(size);
size_t i = 0;
for (auto block : blocks)
cnt[i++] = py::len(block);
i = 0;
Table<T> blocktable(cnt);
for (auto block : blocks)
{
auto row = blocktable[i++];
size_t j = 0;
for (auto val : block)
row[j++] = val.cast<T>();
}
// cout << "blocktable = " << *blocktable << endl;
return blocktable;
}), py::arg("blocks"), "a list of lists")
.def ("__len__", [] (Table<T> &self ) { return self.Size(); } )
.def ("__getitem__",
[](Table<T> & self, size_t i) -> FlatArray<T>
{
if (i >= self.Size())
throw py::index_error();
return self[i];
})
.def("__str__", [](Table<T> & self)
{
return ToString(self);
})
;
}
void NGCORE_API SetFlag(Flags &flags, std::string s, py::object value);
// Parse python kwargs to flags
Flags NGCORE_API CreateFlagsFromKwArgs(const py::kwargs& kwargs, py::object pyclass = py::none(),
py::list info = py::list());
// Create python dict from kwargs
py::dict NGCORE_API CreateDictFromFlags(const Flags& flags);
} // namespace ngcore
#endif // NETGEN_CORE_PYTHON_NGCORE_HPP

View File

@ -0,0 +1,290 @@
#include "python_ngcore.hpp"
#include "bitarray.hpp"
#include "taskmanager.hpp"
using namespace ngcore;
using namespace std;
using namespace pybind11::literals;
PYBIND11_MODULE(pyngcore, m) // NOLINT
{
try
{
auto numpy = py::module::import("numpy");
ngcore_have_numpy = !numpy.is_none();
}
catch(...) {}
ExportArray<int>(m);
ExportArray<unsigned>(m);
ExportArray<size_t>(m);
ExportArray<double>(m);
ExportArray<float>(m);
ExportArray<signed short>(m);
ExportArray<signed char>(m);
ExportArray<unsigned short>(m);
ExportArray<unsigned char>(m);
ExportTable<int>(m);
py::class_<BitArray, shared_ptr<BitArray>> (m, "BitArray")
.def(py::init([] (size_t n) { return make_shared<BitArray>(n); }),py::arg("n"))
.def(py::init([] (const BitArray& a) { return make_shared<BitArray>(a); } ), py::arg("ba"))
.def(py::init([] (const vector<bool> & a)
{
auto ba = make_shared<BitArray>(a.size());
ba->Clear();
for (size_t i = 0; i < a.size(); i++)
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)
{
if (i < 0) i+=self.Size();
if (i < 0 || i >= self.Size())
throw py::index_error();
return self.Test(i);
}, py::arg("pos"), "Returns bit from given position")
.def("__setitem__", [] (BitArray & self, int i, bool b)
{
if (i < 0) i+=self.Size();
if (i < 0 || i >= self.Size())
throw py::index_error();
if (b) self.SetBit(i); else self.Clear(i);
}, py::arg("pos"), py::arg("value"), "Clear/Set bit at given position")
.def("__setitem__", [] (BitArray & self, py::slice inds, bool b)
{
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)
{ // base branch
if (b)
self.Set();
else
self.Clear();
}
else
{
if (b)
for (size_t i=0; i<n; i++, start+=step)
self.SetBit(start);
else
for (size_t i=0; i<n; i++, start+=step)
self.Clear(start);
}
}, 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)
for (size_t i : range)
self.SetBit(i);
else
for (size_t i : range)
self.Clear(i);
}, py::arg("range"), py::arg("value"), "Set value for range of indices" )
.def("NumSet", &BitArray::NumSet)
.def("Set", [] (BitArray & self) { self.Set(); }, "Set all bits")
.def("Set", &BitArray::SetBit, py::arg("i"), "Set bit at given position")
.def("Clear", [] (BitArray & self) { self.Clear(); }, "Clear all bits")
.def("Clear", [] (BitArray & self, int i)
{
self.Clear(i);
}, py::arg("i"), "Clear bit at given position")
.def(py::self | py::self)
.def(py::self & py::self)
.def(py::self |= py::self)
.def(py::self &= py::self)
.def(~py::self)
;
py::class_<Flags>(m, "Flags")
.def(py::init<>())
.def("__str__", &ToString<Flags>)
.def(py::init([](py::object & obj) {
Flags flags;
py::dict d(obj);
SetFlag (flags, "", d);
return flags;
}), py::arg("obj"), "Create Flags by given object")
.def(py::pickle([] (const Flags& self)
{
std::stringstream str;
self.SaveFlags(str);
return py::make_tuple(py::cast(str.str()));
},
[] (py::tuple state)
{
string s = state[0].cast<string>();
std::stringstream str(s);
Flags flags;
flags.LoadFlags(str);
return flags;
}
))
.def("Set",[](Flags & self,const py::dict & aflags)->Flags&
{
SetFlag(self, "", aflags);
return self;
}, py::arg("aflag"), "Set the flags by given dict")
.def("Set",[](Flags & self, const char * akey, const py::object & value)->Flags&
{
SetFlag(self, akey, value);
return self;
}, py::arg("akey"), py::arg("value"), "Set flag by given value.")
.def("__getitem__", [](Flags & self, const string& name) -> py::object {
if(self.NumListFlagDefined(name))
return py::cast(self.GetNumListFlag(name));
if(self.StringListFlagDefined(name))
return py::cast(self.GetStringListFlag(name));
if(self.NumFlagDefined(name))
return py::cast(*self.GetNumFlagPtr(name));
if(self.StringFlagDefined(name))
return py::cast(self.GetStringFlag(name));
if(self.FlagsFlagDefined(name))
return py::cast(self.GetFlagsFlag(name));
return py::cast(self.GetDefineFlag(name));
}, py::arg("name"), "Return flag by given name")
.def("ToDict", [](const Flags& flags)
{
return CreateDictFromFlags(flags);
})
;
py::implicitly_convertible<py::dict, Flags>();
py::enum_<level::level_enum>(m, "LOG_LEVEL", "Logging level")
.value("Trace", level::trace)
.value("Debug", level::debug)
.value("Info", level::info)
.value("Warn", level::warn)
.value("Error", level::err)
.value("Critical", level::critical)
.value("Off", level::off);
m.def("SetLoggingLevel", &SetLoggingLevel, py::arg("level"), py::arg("logger")="",
"Set logging level, if name is given only to the specific logger, else set the global logging level");
m.def("AddFileSink", &AddFileSink, py::arg("filename"), py::arg("level"), py::arg("logger")="",
"Add File sink, either only to logger specified or globally to all loggers");
m.def("AddConsoleSink", &AddConsoleSink, py::arg("level"), py::arg("logger")="",
"Add console output for specific logger or all if none given");
m.def("ClearLoggingSinks", &ClearLoggingSinks, py::arg("logger")="",
"Clear sinks of specific logger, or all if none given");
m.def("FlushOnLoggingLevel", &FlushOnLoggingLevel, py::arg("level"), py::arg("logger")="",
"Flush every message with level at least `level` for specific logger or all loggers if none given.");
m.def("RunWithTaskManager",
[](py::object lam)
{
GetLogger("TaskManager")->info("running Python function with task-manager");
RunWithTaskManager ([&] () { lam(); });
}, py::arg("lam"), R"raw_string(
Parameters:
lam : object
input function
)raw_string")
;
m.def("SetNumThreads", &TaskManager::SetNumThreads, py::arg("threads"), R"raw_string(
Set number of threads
Parameters:
threads : int
input number of threads
)raw_string");
// local TaskManager class to be used as context manager in Python
class ParallelContextManager {
int num_threads;
public:
ParallelContextManager() : num_threads(0) {
TaskManager::SetPajeTrace(0);
PajeTrace::SetMaxTracefileSize(0);
};
ParallelContextManager(size_t pajesize) : num_threads(0) {
TaskManager::SetPajeTrace(pajesize > 0);
PajeTrace::SetMaxTracefileSize(pajesize);
}
void Enter() {num_threads = EnterTaskManager(); }
void Exit(py::object exc_type, py::object exc_value, py::object traceback) {
ExitTaskManager(num_threads);
}
};
py::class_<ParallelContextManager>(m, "TaskManager")
.def(py::init<>())
.def(py::init<size_t>(), "pajetrace"_a, "Run paje-tracer, specify buffersize in bytes")
.def("__enter__", &ParallelContextManager::Enter)
.def("__exit__", &ParallelContextManager::Exit)
.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) { 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)
: iter(aiter), end(aend), f(af)
{
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

View File

@ -0,0 +1,39 @@
#ifndef NETGEN_REGISTER_ARCHIVE_HPP
#define NETGEN_REGISTER_ARCHIVE_HPP
#ifdef NETGEN_PYTHON
#include <pybind11/pybind11.h>
#include <pybind11/cast.h>
#endif // NETGEN_PYTHON
#include "archive.hpp"
namespace ngcore {
template<typename T, typename ... Bases>
class RegisterClassForArchive
{
public:
RegisterClassForArchive()
{
static_assert(detail::all_of_tmpl<std::is_base_of<Bases,T>::value...>,
"Variadic template arguments must be base classes of T");
detail::ClassArchiveInfo info {};
info.creator = [](const std::type_info& ti) -> void*
{ return typeid(T) == ti ? detail::constructIfPossible<T>()
: Archive::Caster<T, Bases...>::tryUpcast(ti, detail::constructIfPossible<T>()); };
info.upcaster = [/*this*/](const std::type_info& ti, void* p) -> void*
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases...>::tryUpcast(ti, static_cast<T*>(p)); };
info.downcaster = [/*this*/](const std::type_info& ti, void* p) -> void*
{ return typeid(T) == ti ? p : Archive::Caster<T, Bases...>::tryDowncast(ti, p); };
#ifdef NETGEN_PYTHON
info.anyToPyCaster = [](const std::any& a)
{
const T* val = std::any_cast<T>(&a);
return pybind11::cast(val); };
#endif // NETGEN_PYTHON
Archive::SetArchiveRegister(std::string(Demangle(typeid(T).name())),info);
}
};
} // namespace ngcore
#endif // NETGEN_REGISTER_ARCHIVE_HPP

48
libsrc/core/signal.hpp Normal file
View File

@ -0,0 +1,48 @@
#ifndef NGCORE_SIGNALS_HPP
#define NGCORE_SIGNALS_HPP
#include <list>
#include <functional>
namespace ngcore
{
template<typename ... ParameterTypes>
class Signal
{
private:
std::list<std::function<bool(ParameterTypes...)>> funcs;
bool is_emitting;
public:
Signal() : is_emitting(true) {}
template<typename Cls, typename FUNC>
void Connect(Cls* self, FUNC f)
{
auto ptr = self->weak_from_this();
auto func = [ptr, f](ParameterTypes... args)
{
if (ptr.expired())
return false;
f(args...);
return true;
};
funcs.push_back(func);
}
inline void Emit(ParameterTypes ...args)
{
if(is_emitting)
funcs.remove_if([&](auto& f){ return !f(args...); });
}
inline bool SetEmitting(bool emitting)
{
bool was_emitting = is_emitting;
is_emitting = emitting;
return was_emitting;
}
inline bool GetEmitting() const { return is_emitting; }
};
} // namespace ngcore
#endif // NGCORE_SIGNALS_HPP

92
libsrc/core/simd.hpp Normal file
View File

@ -0,0 +1,92 @@
#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"
#ifndef __CUDA_ARCH__
#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
#endif // __CUDA_ARCH__
namespace ngcore
{
#ifndef __CUDA_ARCH__
#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
#endif // __CUDA_ARCH__
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)
{
if constexpr (sizeof(a1.Lo()) == 16)
{
auto [h1,h2] = Unpack(a1,a2);
auto [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());
}
else
{
b1 = SIMD<double,4> (a1[0], a2[0], a3[0], a4[0]);
b2 = SIMD<double,4> (a1[1], a2[1], a3[1], a4[1]);
b3 = SIMD<double,4> (a1[2], a2[2], a3[2], a4[2]);
b4 = SIMD<double,4> (a1[3], a2[3], a3[3], a4[3]);
}
}
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));
return SIMD<double,4>(HSum(s1, s2), HSum(s3,s4));
}
}
#endif // NETGEN_CORE_SIMD_HPP

187
libsrc/core/simd_arm64.hpp Normal file
View File

@ -0,0 +1,187 @@
#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} { }
SIMD (int64x2_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 (SIMD<double,1> v0, SIMD<double,1> v1) : data{vcombine_f64(float64x1_t{v0.Data()}, float64x1_t{v1.Data()})} { }
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());
}
NETGEN_INLINE SIMD<double,4> HSum(SIMD<double,2> a, SIMD<double,2> b, SIMD<double,2> c, SIMD<double,2> d)
{
return SIMD<double,4> (HSum(a,b), HSum(c,d));
}
// 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] };
uint64x2_t mask = vreinterpretq_u64_s64(a.Data());
return vbslq_f64(mask, 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)
{
uint64x2_t m1 = vreinterpretq_u64_s64(a.Data());
uint64x2_t m2 = vreinterpretq_u64_s64(b.Data());
uint64x2_t res = vandq_u64 (m1, m2);
return vreinterpretq_s64_u64(res);
}
}

326
libsrc/core/simd_avx.hpp Normal file
View File

@ -0,0 +1,326 @@
#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 elements of SIMD")]]
// NETGEN_INLINE double & operator[] (int i) { 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]); }
template <int I>
double Get() const
{
static_assert(I>=0 && I<4, "Index out of range");
return (*this)[I];
}
};
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
#if defined(__FMA__)
NETGEN_INLINE SIMD<double,4> FMAddSub (SIMD<double,4> a, SIMD<double,4> b, SIMD<double,4> c)
{
return _mm256_fmaddsub_pd(a.Data(), b.Data(), c.Data());
}
#endif
NETGEN_INLINE SIMD<double,4> SwapPairs (SIMD<double,4> a)
{
return _mm256_shuffle_pd (a.Data(), a.Data(), 0b0101);
}
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

274
libsrc/core/simd_avx512.hpp Normal file
View File

@ -0,0 +1,274 @@
#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; }
SIMD (SIMD<double,4> v0, SIMD<double,4> v1)
: data(_mm512_set_pd(v1[3], v1[2], v1[1], v1[0], v0[3], v0[2], v0[1], v0[0]))
{}
SIMD (SIMD<double,6> v0, SIMD<double,2> v1)
: data(_mm512_set_pd(v1[1], v1[0], v0[5], v0[4], v0[3], v0[2], v0[1], v0[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 = _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; }
SIMD<double,4> Lo() const { return _mm512_extractf64x4_pd(data, 0); }
SIMD<double,4> Hi() const { return _mm512_extractf64x4_pd(data, 1); }
template <int I>
double Get() const
{
static_assert(I>=0 && I<8, "Index out of range");
return (*this)[I];
}
};
NETGEN_INLINE SIMD<double,8> operator- (SIMD<double,8> a) { return _mm512_xor_pd(a.Data(), _mm512_set1_pd(-0.0)); } //{ 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());
SIMD<double,4> ab = _mm512_extractf64x4_pd(sum01.Data(),0) + _mm512_extractf64x4_pd(sum01.Data(),1);
SIMD<double,4> cd = _mm512_extractf64x4_pd(sum23.Data(),0) + _mm512_extractf64x4_pd(sum23.Data(),1);
return _mm256_add_pd (_mm256_permute2f128_pd (ab.Data(), cd.Data(), 1 + 2 * 16), _mm256_blend_pd(ab.Data(), cd.Data(), 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());
}
NETGEN_INLINE SIMD<double,8> FMAddSub (SIMD<double,8> a, SIMD<double,8> b, SIMD<double,8> c)
{
return _mm512_fmaddsub_pd(a.Data(), b.Data(), c.Data());
}
NETGEN_INLINE SIMD<double,8> SwapPairs (SIMD<double,8> a)
{
return _mm512_shuffle_pd (a.Data(), a.Data(), 0b01010101);
}
}
#endif // NETGEN_CORE_SIMD_AVX512_HPP

View File

@ -0,0 +1,790 @@
#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 <cmath>
#include "array.hpp"
namespace ngcore
{
#if defined __AVX512F__
#define NETGEN_DEFAULT_SIMD_SIZE 8
#define NETGEN_NATIVE_SIMD_SIZE 8
#elif defined __AVX__
#define NETGEN_DEFAULT_SIMD_SIZE 4
#define NETGEN_NATIVE_SIMD_SIZE 4
#elif defined NETGEN_ARCH_AMD64
#define NETGEN_DEFAULT_SIMD_SIZE 2
#define NETGEN_NATIVE_SIMD_SIZE 2
#else
#define NETGEN_DEFAULT_SIMD_SIZE 2
#define NETGEN_NATIVE_SIMD_SIZE 1
#endif
constexpr int GetDefaultSIMDSize() {
return NETGEN_DEFAULT_SIMD_SIZE;
}
constexpr bool IsNativeSIMDSize(int n) {
if(n==1) return true;
#if defined NETGEN_ARCH_AMD64 || defined __SSE__ || defined __aarch64__
if(n==2) return true;
#endif
#if defined __AVX__
if(n==4) return true;
#endif
#if defined __AVX512F__
if(n==8) return true;
#endif
return false;
}
// split n = k+l such that k is the largest natively supported simd size < n
constexpr int GetLargestNativeSIMDPart(int n) {
int k = n-1;
while(!IsNativeSIMDSize(k))
k--;
return k;
}
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(GetLargestNativeSIMDPart(N)*sizeof(int64_t)) SIMD<mask64,N>
{
static constexpr int N1 = GetLargestNativeSIMDPart(N);
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(GetLargestNativeSIMDPart(N)*sizeof(int64_t)) SIMD<int64_t,N>
{
static constexpr int N1 = GetLargestNativeSIMDPart(N);
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(GetLargestNativeSIMDPart(N)*sizeof(double)) SIMD<double, N>
{
static constexpr int N1 = GetLargestNativeSIMDPart(N);
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());
}
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.template Get<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,N>([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,N>([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,N>([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,N>([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,N>([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::erf;
template <int N>
NETGEN_INLINE ngcore::SIMD<double,N> erf (ngcore::SIMD<double,N> a) {
return ngcore::SIMD<double,N>([a](int i)->double { return erf(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 });
}
}
// TODO: specialize for AVX, ...
template<int N>
NETGEN_INLINE auto SwapPairs (SIMD<double,N> a)
{
if constexpr(N==1) {
// static_assert(false);
return a;
}
else if constexpr(N==2) {
return SIMD<double,N> (a.Hi(), a.Lo());
}
else {
return SIMD<double,N> (SwapPairs(a.Lo()), SwapPairs(a.Hi()));
}
}
template<int N>
NETGEN_INLINE auto HSum128 (SIMD<double,N> a)
{
if constexpr(N==1) {
// static_assert(false);
return a;
}
else if constexpr(N==2) {
return a;
}
else {
return HSum128(a.Lo()) + HSum128(a.Hi());
}
}
// TODO: specialize for AVX, ...
// a*b+-c (even: -, odd: +)
template<int N>
NETGEN_INLINE auto FMAddSub (SIMD<double,N> a, SIMD<double,N> b, SIMD<double,N> c)
{
if constexpr(N==1) {
// static_assert(false);
return a*b-c;
}
else if constexpr(N==2) {
return SIMD<double,N> (a.Lo()*b.Lo()-c.Lo(),
a.Hi()*b.Hi()+c.Hi());
}
else {
return SIMD<double,N> (FMAddSub(a.Lo(), b.Lo(), c.Lo()),
FMAddSub(a.Hi(), b.Hi(), c.Hi()));
}
}
}
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

279
libsrc/core/simd_sse.hpp Normal file
View File

@ -0,0 +1,279 @@
#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 (SIMD<double,1> v0, SIMD<double,1> v1)
: data{_mm_set_pd(v0.Data(), v1.Data())}
{ }
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; }
template <int I>
double Get() const
{
static_assert(I>=0 && I<2, "Index out of range");
return (*this)[I];
}
double Lo() const { return Get<0>(); }
double Hi() const { return Get<1>(); }
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

@ -5,7 +5,6 @@
#include <string>
#include <vector>
#include "archive.hpp"
#include "exception.hpp"
#include "ngcore_api.hpp"
@ -38,8 +37,9 @@ namespace ngcore
SymbolTable& operator=(const SymbolTable<T>&) = default;
SymbolTable& operator=(SymbolTable<T>&&) = default;
template<typename T2=T>
auto DoArchive(Archive& ar) -> typename std::enable_if_t<is_archivable<T2>>
template<typename ARCHIVE>
auto DoArchive(ARCHIVE& ar)
-> typename std::enable_if_t<ARCHIVE::template is_archivable<T>, void>
{
ar & names & data;
}

190
libsrc/core/table.cpp Normal file
View File

@ -0,0 +1,190 @@
/**************************************************************************/
/* File: table.cpp */
/* Author: Joachim Schoeberl */
/* Date: 25. Mar. 2000 */
/**************************************************************************/
/*
Abstract data type Table
*/
#include "table.hpp"
namespace ngcore
{
template <typename TI>
size_t * TablePrefixSum2 (FlatArray<TI> entrysize)
{
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
([&] (TaskInfo ti)
{
IntRange r = IntRange(size).Split(ti.task_nr, ti.ntasks);
size_t mysum = 0;
for (size_t i : r)
mysum += entrysize[i];
partial_sums[ti.task_nr+1] = mysum;
});
for (size_t i = 1; i < partial_sums.Size(); i++)
partial_sums[i] += partial_sums[i-1];
ParallelJob
([&] (TaskInfo ti)
{
IntRange r = IntRange(size).Split(ti.task_nr, ti.ntasks);
size_t mysum = partial_sums[ti.task_nr];
for (size_t i : r)
{
index[i] = mysum;
mysum += entrysize[i];
}
});
index[size] = partial_sums.Last();
return index;
}
NGCORE_API size_t * TablePrefixSum32 (FlatArray<unsigned int> entrysize)
{ return TablePrefixSum2 (entrysize); }
NGCORE_API size_t * TablePrefixSum64 (FlatArray<size_t> entrysize)
{ return TablePrefixSum2 (entrysize); }
/*
BaseDynamicTable :: BaseDynamicTable (int size)
: data(size)
{
for (int i = 0; i < size; i++)
{
data[i].maxsize = 0;
data[i].size = 0;
data[i].col = NULL;
}
oneblock = NULL;
}
BaseDynamicTable :: BaseDynamicTable (const Array<int> & entrysizes, int elemsize)
: data(entrysizes.Size())
{
int cnt = 0;
int n = entrysizes.Size();
for (int i = 0; i < n; i++)
cnt += entrysizes[i];
oneblock = new char[elemsize * cnt];
cnt = 0;
for (int i = 0; i < n; i++)
{
data[i].maxsize = entrysizes[i];
data[i].size = 0;
data[i].col = &oneblock[elemsize * cnt];
cnt += entrysizes[i];
}
}
BaseDynamicTable :: ~BaseDynamicTable ()
{
if (oneblock)
delete [] oneblock;
else
for (int i = 0; i < data.Size(); i++)
delete [] static_cast<char*> (data[i].col);
}
void BaseDynamicTable :: SetSize (int size)
{
for (int i = 0; i < data.Size(); i++)
delete [] static_cast<char*> (data[i].col);
data.SetSize(size);
for (int i = 0; i < size; i++)
{
data[i].maxsize = 0;
data[i].size = 0;
data[i].col = NULL;
}
}
void BaseDynamicTable :: IncSize (IndexType i, int elsize)
{
if (i < 0 || i >= data.Size())
{
std::cerr << "BaseDynamicTable::Inc: Out of range, i = " << i << ", size = " << data.Size() << std::endl;
return;
}
linestruct & line = data[i];
if (line.size == line.maxsize)
{
void * p = new char [(2*line.maxsize+5) * elsize];
memcpy (p, line.col, line.maxsize * elsize);
delete [] static_cast<char*> (line.col);
line.col = p;
line.maxsize = 2*line.maxsize+5;
}
line.size++;
}
void BaseDynamicTable :: DecSize (IndexType i)
{
if (i < 0 || i >= data.Size())
{
std::cerr << "BaseDynamicTable::Dec: Out of range" << std::endl;
return;
}
linestruct & line = data[i];
if (line.size == 0)
{
std::cerr << "BaseDynamicTable::Dec: EntrySize < 0" << std::endl;
return;
}
line.size--;
}
*/
void FilteredTableCreator::Add (size_t blocknr, int data)
{
if (!takedofs||takedofs->Test(data))
TableCreator<int>::Add(blocknr,data);
}
void FilteredTableCreator::Add (size_t blocknr, IntRange range)
{
for (size_t i=range.First(); i<range.Next();i++)
if (!takedofs||takedofs->Test(i))
TableCreator<int>::Add(blocknr,i);
}
void FilteredTableCreator::Add (size_t blocknr, FlatArray<int> dofs)
{
for (size_t i = 0; i < dofs.Size(); i++)
if (!takedofs||takedofs->Test(dofs[i]))
TableCreator<int>::Add(blocknr,dofs[i]);
}
} // namespace ngcore

787
libsrc/core/table.hpp Normal file
View File

@ -0,0 +1,787 @@
#ifndef NETGEN_CORE_TABLE_HPP
#define NETGEN_CORE_TABLE_HPP
/**************************************************************************/
/* File: table.hpp */
/* Author: Joachim Schoeberl */
/* Date: 25. Mar. 2000 */
/**************************************************************************/
#include <atomic>
#include <iostream>
#include <optional>
#include "array.hpp"
#include "bitarray.hpp"
#include "memtracer.hpp"
#include "ngcore_api.hpp"
#include "profiler.hpp"
namespace ngcore
{
template <class T, class IndexType = size_t>
class FlatTable
{
protected:
static constexpr IndexType BASE = IndexBASE<IndexType>();
/// number of rows
size_t size;
/// pointer to first in row
size_t * index;
/// array of data
T * data;
public:
FlatTable() = delete;
FlatTable (const FlatTable &) = default;
NETGEN_INLINE FlatTable(size_t as, size_t * aindex, T * adata)
: size(as), index(aindex), data(adata) { ; }
/// Size of table
NETGEN_INLINE size_t Size() const { return size; }
/// Access entry
NETGEN_INLINE const FlatArray<T> operator[] (IndexType i) const
{
return FlatArray<T> (index[i-BASE+1]-index[i-BASE], data+index[i-BASE]);
}
NETGEN_INLINE T * Data() const { return data; }
NETGEN_INLINE FlatArray<T> AsArray() const
{
return FlatArray<T> (index[size]-index[0], data+index[0]);
}
NETGEN_INLINE FlatArray<size_t> IndexArray() const
{
return FlatArray<size_t, IndexType> (size+1, index);
}
/// takes range starting from position start of end-start elements
NETGEN_INLINE FlatTable<T> Range (size_t start, size_t end) const
{
return FlatTable<T> (end-start, index+start-BASE, data);
}
/// takes range starting from position start of end-start elements
NETGEN_INLINE FlatTable<T> Range (T_Range<size_t> range) const
{
return FlatTable<T> (range.Size(), index+range.First()-BASE, data);
}
NETGEN_INLINE T_Range<IndexType> Range () const
{
return T_Range<IndexType> (BASE, size+BASE);
}
class Iterator
{
const FlatTable & tab;
size_t row;
public:
Iterator (const FlatTable & _tab, size_t _row) : tab(_tab), row(_row) { ; }
Iterator & operator++ () { ++row; return *this; }
FlatArray<T> operator* () const { return tab[row]; }
bool operator!= (const Iterator & it2) { return row != it2.row; }
};
Iterator begin() const { return Iterator(*this, BASE); }
Iterator end() const { return Iterator(*this, BASE+size); }
};
NGCORE_API extern size_t * TablePrefixSum32 (FlatArray<unsigned int> entrysize);
NGCORE_API extern size_t * TablePrefixSum64 (FlatArray<size_t> entrysize);
NETGEN_INLINE size_t * TablePrefixSum (FlatArray<unsigned int> entrysize)
{ return TablePrefixSum32 (entrysize); }
NETGEN_INLINE size_t * TablePrefixSum (FlatArray<int> entrysize)
{ return TablePrefixSum32 (FlatArray<unsigned> (entrysize.Size(), (unsigned int*)(int*)(entrysize.Addr(0)))); }
NETGEN_INLINE size_t * TablePrefixSum (FlatArray<std::atomic<int>> entrysize)
{ return TablePrefixSum32 (FlatArray<unsigned> (entrysize.Size(), (unsigned int*)(std::atomic<int>*)entrysize.Addr(0))); }
NETGEN_INLINE size_t * TablePrefixSum (FlatArray<size_t> entrysize)
{ 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:
using FlatTable<T,IndexType>::size;
using FlatTable<T,IndexType>::index;
using FlatTable<T,IndexType>::data;
public:
///
NETGEN_INLINE Table () : FlatTable<T,IndexType> (0,nullptr,nullptr) { ; }
/// Construct table of uniform entrysize
NETGEN_INLINE Table (size_t asize, size_t entrysize)
: FlatTable<T,IndexType>( asize, new size_t[asize+1], new T[asize*entrysize] )
{
for (size_t i : IntRange(size+1))
index[i] = i*entrysize;
}
/// Construct table of variable entrysize
template <typename TI>
NETGEN_INLINE Table (FlatArray<TI,IndexType> entrysize)
: FlatTable<T,IndexType> (0, nullptr, nullptr)
{
size = entrysize.Size();
index = TablePrefixSum (FlatArray<TI> (entrysize.Size(), entrysize.Data()));
size_t cnt = index[size];
data = new T[cnt];
}
explicit NETGEN_INLINE Table (const FlatTable<T,IndexType> & tab2)
: FlatTable<T,IndexType>(0, nullptr, nullptr)
{
size = tab2.Size();
if (size == 0) return;
index = new size_t[size+1];
this->IndexArray() = tab2.IndexArray();
// for (size_t i = 0; i <= size; i++)
// index[i] = tab2.index[i];
size_t cnt = index[size];
data = new T[cnt];
this->AsArray() = tab2.AsArray();
/*
for (size_t i = 0; i < cnt; i++)
data[i] = tab2.data[i];
*/
}
explicit NETGEN_INLINE Table (const Table & tab2)
: FlatTable<T,IndexType>(0, nullptr, nullptr)
{
size = tab2.Size();
if (size == 0) return;
index = new size_t[size+1];
for (size_t i = 0; i <= size; i++)
index[i] = tab2.index[i];
size_t cnt = index[size];
data = new T[cnt];
for (size_t i = 0; i < cnt; i++)
data[i] = tab2.data[i];
}
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);
}
template<typename ARCHIVE>
auto DoArchive(ARCHIVE& ar)
{
ar & size;
if(size == 0)
return;
if(ar.Input())
{
index = new IndexType[size+1];
mt.Alloc(sizeof(IndexType) * (size+1));
}
ar.Do(index, size+1);
if(ar.Input())
{
data = new T[index[size]];
mt.Alloc(sizeof(T) * index[size]);
}
ar.Do(data, index[size]);
}
NETGEN_INLINE Table & operator= (Table && tab2)
{
mt.Swap(GetMemUsage(), tab2.mt, tab2.GetMemUsage());
Swap (size, tab2.size);
Swap (index, tab2.index);
Swap (data, tab2.data);
return *this;
}
/// Delete data
NETGEN_INLINE ~Table ()
{
mt.Free(GetMemUsage());
delete [] data;
delete [] index;
}
/// Size of table
using FlatTable<T,IndexType>::Size;
/// number of elements in all rows
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
template <class T, typename IndexType>
inline ostream & operator<< (ostream & s, const Table<T,IndexType> & table)
{
for (auto i : table.Range())
{
s << i << ":";
for (auto el : table[i])
s << " " << el;
s << "\n";
}
s << std::flush;
return s;
}
template <class T, typename IndexType=size_t>
class TableCreator
{
protected:
int mode; // 1 .. cnt, 2 .. cnt entries, 3 .. fill table
std::atomic<size_t> nd;
Array<std::atomic<int>,IndexType> cnt;
Table<T,IndexType> table;
public:
TableCreator()
{ nd = 0; mode = 1; }
TableCreator (size_t acnt)
{ nd = acnt; SetMode(2); }
Table<T,IndexType> MoveTable()
{
return std::move(table);
}
bool Done () { return mode > 3; }
void operator++(int) { SetMode (mode+1); }
int GetMode () const { return mode; }
void SetMode (int amode)
{
mode = amode;
if (mode == 2)
{
// cnt.SetSize(nd); // atomic has no copy
cnt = Array<std::atomic<int>,IndexType> (nd);
for (auto & ci : cnt) ci.store (0, std::memory_order_relaxed);
}
if (mode == 3)
{
table = Table<T,IndexType> (cnt);
// for (auto & ci : cnt) ci = 0;
for (auto & ci : cnt) ci.store (0, std::memory_order_relaxed);
// cnt = 0;
}
}
void SetSize (size_t _nd)
{
if (mode == 1)
nd = _nd;
else
{
if (nd != _nd)
throw Exception ("cannot change size of table-creator");
}
}
void Add (IndexType blocknr, const T & data)
{
switch (mode)
{
case 1:
{
size_t oldval = nd;
while (blocknr+1>nd) {
nd.compare_exchange_weak (oldval, blocknr+1);
oldval = nd;
}
break;
}
case 2:
cnt[blocknr]++;
break;
case 3:
int ci = cnt[blocknr]++;
table[blocknr][ci] = data;
break;
}
}
void Add (IndexType blocknr, IntRange range)
{
switch (mode)
{
case 1:
{
size_t oldval = nd;
while (blocknr+1>nd) {
nd.compare_exchange_weak (oldval, blocknr+1);
oldval = nd;
}
break;
}
case 2:
cnt[blocknr] += range.Size();
break;
case 3:
size_t ci = ( cnt[blocknr] += range.Size() ) - range.Size();
for (size_t j = 0; j < range.Size(); j++)
table[blocknr][ci+j] = range.First()+j;
break;
}
}
void Add (IndexType blocknr, const FlatArray<int> & dofs)
{
switch (mode)
{
case 1:
{
size_t oldval = nd;
while (blocknr+1>nd) {
nd.compare_exchange_weak (oldval, blocknr+1);
oldval = nd;
}
break;
}
case 2:
cnt[blocknr] += dofs.Size();
break;
case 3:
size_t ci = ( cnt[blocknr] += dofs.Size() ) - dofs.Size();
for (size_t j = 0; j < dofs.Size(); j++)
table[blocknr][ci+j] = dofs[j];
break;
}
}
};
template <typename TEntry, typename TIndex, typename TRange, typename TFunc>
Table<TEntry, TIndex> CreateTable( const TRange & range, const TFunc & func, std::optional< size_t > cnt )
{
static Timer timer("CreateTable");
RegionTimer rt(timer);
std::unique_ptr<TableCreator<TEntry, TIndex>> pcreator;
if(cnt)
pcreator = std::make_unique<TableCreator<TEntry, TIndex>>(*cnt);
else
pcreator = std::make_unique<TableCreator<TEntry, TIndex>>();
auto & creator = *pcreator;
for ( ; !creator.Done(); creator++)
ParallelForRange
(range, [&] (auto myrange)
{
for (auto i : myrange)
func(creator, i);
}, TasksPerThread(4)
);
return creator.MoveTable();
}
template <typename TEntry, typename TIndex, typename TRange, typename TFunc>
Table<TEntry, TIndex> CreateSortedTable( const TRange & range, const TFunc & func, std::optional< size_t > cnt )
{
static Timer timer("CreateSortedTable");
RegionTimer rt(timer);
Table<TEntry, TIndex> table = CreateTable<TEntry, TIndex>(range, func, cnt);
ParallelForRange
(table.Range(), [&] (auto myrange)
{
for (auto i : myrange)
QuickSort(table[i]);
}, TasksPerThread(4)
);
return table;
}
class NGCORE_API FilteredTableCreator : public TableCreator<int>
{
protected:
const BitArray* takedofs;
public:
FilteredTableCreator(const BitArray* atakedofs)
: TableCreator<int>(), takedofs(atakedofs) { };
FilteredTableCreator(int acnt, const BitArray* atakedofs)
: TableCreator<int>(acnt),takedofs(atakedofs) { };
void Add (size_t blocknr, int data);
void Add (size_t blocknr, IntRange range);
void Add (size_t blocknr, FlatArray<int> dofs);
};
/**
A dynamic table class.
A DynamicTable contains entries of variable size. Entry sizes can
be increased dynamically.
*/
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)
: 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, IndexType> & entrysizes, bool setentrysize=false)
: 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];
if (setentrysize)
data[i].size = entrysizes[i];
else
data[i].size = 0;
data[i].col = &oneblock[cnt];
cnt += entrysizes[i];
}
}
DynamicTable (DynamicTable && tab2)
{
Swap (data, tab2.data);
Swap (oneblock, tab2.oneblock);
}
~DynamicTable ()
{
if (oneblock)
delete [] oneblock;
else
for (auto & d : data)
delete [] d.col;
}
DynamicTable & operator= (DynamicTable && tab2)
{
Swap (data, tab2.data);
Swap (oneblock, tab2.oneblock);
return *this;
}
/// Changes Size of table to size, deletes data
void SetSize (int size)
{
for (auto & d : data)
delete [] d.col;
data.SetSize(size);
for (auto & d : data)
{
d.maxsize = 0;
d.size = 0;
d.col = nullptr;
}
}
void ChangeSize (size_t size)
{
if (oneblock)
throw Exception ("cannot change size of oneblock dynamic table");
size_t oldsize = data.Size();
if (size == oldsize)
return;
if (size < oldsize)
for (int i = size; i < oldsize; i++)
delete [] data[i+BASE].col;
data.SetSize(size);
for (int i = oldsize; i < size; i++)
{
data[i+BASE].maxsize = 0;
data[i+BASE].size = 0;
data[i+BASE].col = nullptr;
}
}
///
void IncSize (IndexType i)
{
NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE);
linestruct & line = data[i];
if (line.size == line.maxsize)
{
T * p;
if constexpr (std::is_default_constructible<T>::value)
p = new T[(2*line.maxsize+5)];
else
p = reinterpret_cast<T*>(new char[(2*line.maxsize+5)*sizeof(T)]);
for (size_t i = 0; i < line.maxsize; i++)
p[i] = std::move(line.col[i]);
// memcpy (p, line.col, line.maxsize * sizeof(T));
delete [] line.col;
line.col = p;
line.maxsize = 2*line.maxsize+5;
}
line.size++;
}
void DecSize (IndexType i)
{
NETGEN_CHECK_RANGE(i,BASE,data.Size()+BASE);
linestruct & line = data[i];
#ifdef NETGEN_ENABLE_CHECK_RANGE
if (line.size == 0)
throw Exception ("BaseDynamicTable::Dec: EntrySize < 0");
#endif
line.size--;
}
/// Inserts element acont into row i. Does not test if already used.
void Add (IndexType i, const T & acont)
{
if (data[i].size == data[i].maxsize)
this->IncSize (i);
else
data[i].size++;
data[i].col[data[i].size-1] = acont;
}
/// Inserts element acont into row i, iff not yet exists.
void AddUnique (IndexType i, const T & cont)
{
int es = EntrySize (i);
T * line = data[i].col;
for (int j = 0; j < es; j++)
if (line[j] == cont)
return;
Add (i, cont);
}
/// Inserts element acont into row i. Does not test if already used.
void AddEmpty (IndexType i)
{
IncSize (i);
}
/** Set the nr-th element in the i-th row to acont.
Does not check for overflow. */
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 (IndexType i, int nr) const
{
return data[i].col[nr];
}
/** Returns pointer to the first element in row i. */
const T * GetLine (IndexType i) const
{
return data[i].col;
}
/// Returns size of the table.
size_t Size () const
{
return data.Size();
}
auto Range () const
{
return data.Range();
}
/// Returns size of the i-th row.
int EntrySize (IndexType i) const
{
return data[i].size;
}
///
void DecEntrySize (IndexType i)
{
DecSize(i);
}
/// Access entry i
FlatArray<T> operator[] (IndexType i)
{
return FlatArray<T> (data[i].size, data[i].col);
}
/*
typedef const FlatArray<T> ConstFlatArray;
/// Access entry i
ConstFlatArray 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 (auto i : Range(table))
{
s << i << ":";
for (int j = 0; j < table[i].Size(); j++)
s << " " << table[i][j];
s << "\n";
}
s << std::flush;
return s;
}
// Helper function to calculate coloring of a set of indices for parallel processing of independent elements/points/etc.
// Assigns a color to each of colors.Size() elements, such that two elements with the same color don't share a common 'dof',
// the mapping from element to dofs is provided by the function getDofs(int) -> iterable<int>
//
// Returns the number of used colors
template <typename Tmask>
int ComputeColoring( FlatArray<int> colors, size_t ndofs, Tmask const & getDofs)
{
static Timer timer("ComputeColoring - "+Demangle(typeid(Tmask).name())); RegionTimer rt(timer);
static_assert(sizeof(unsigned int)==4, "Adapt type of mask array");
size_t n = colors.Size();
Array<unsigned int> mask(ndofs);
size_t colored_blocks = 0;
// We are coloring with 32 colors at once and use each bit to mask conflicts
unsigned int check = 0;
unsigned int checkbit = 0;
int current_color = 0;
colors = -1;
int maxcolor = 0;
while(colored_blocks<n)
{
mask = 0;
for (auto i : Range(n) )
{
if(colors[i]>-1) continue;
check = 0;
const auto & dofs = getDofs(i);
// Check if adjacent dofs are already marked by current color
for (auto dof : dofs)
check|=mask[dof];
// Did we find a free color?
if(check != 0xFFFFFFFF)
{
checkbit = 1;
int color = current_color;
// find the actual color, which is free (out of 32)
while (check & checkbit)
{
color++;
checkbit *= 2;
}
colors[i] = color;
maxcolor = color > maxcolor ? color : maxcolor;
colored_blocks++;
// mask all adjacent dofs with the found color
for (auto dof : dofs)
mask[dof] |= checkbit;
}
}
current_color+=32;
}
return maxcolor+1;
}
typedef DynamicTable<int> IntTable;
} // namespace ngcore
#endif // NETGEN_CORE_TABLE_HPP

831
libsrc/core/taskmanager.cpp Normal file
View File

@ -0,0 +1,831 @@
/********************************************************************/
/* File: taskmanager.cpp */
/* Author: M. Hochsterger, J. Schoeberl */
/* Date: 10. Mar. 2015 */
/********************************************************************/
#include <thread>
#include <atomic>
#include <mutex>
#include <chrono>
#include "concurrentqueue.h"
#include "mpi_wrapper.hpp"
#include "paje_trace.hpp"
#include "profiler.hpp"
#include "taskmanager.hpp"
#ifdef USE_MKL
#include <mkl.h>
#endif
namespace ngcore
{
using std::mutex;
using std::lock_guard;
using std::memory_order_release;
using std::memory_order_relaxed;
using std::make_tuple;
TaskManager * task_manager = nullptr;
bool TaskManager :: use_paje_trace = false;
int TaskManager :: max_threads = getenv("NGS_NUM_THREADS") ? atoi(getenv("NGS_NUM_THREADS")) : std::thread::hardware_concurrency();
int TaskManager :: num_threads = 1;
thread_local int TaskManager :: thread_id = 0;
const function<void(TaskInfo&)> * TaskManager::func;
const function<void()> * TaskManager::startup_function = nullptr;
const function<void()> * TaskManager::cleanup_function = nullptr;
atomic<int> TaskManager::ntasks;
Exception * TaskManager::ex;
atomic<int> TaskManager::jobnr;
atomic<int> TaskManager::complete[8]; // max nodes
atomic<int> TaskManager::done;
atomic<int> TaskManager::active_workers;
atomic<int> TaskManager::workers_on_node[8]; // max nodes
int TaskManager::sleep_usecs = 1000;
bool TaskManager::sleep = false;
TaskManager::NodeData *TaskManager::nodedata[8];
int TaskManager::num_nodes;
static mutex copyex_mutex;
int EnterTaskManager ()
{
if (task_manager)
{
// no task manager started
return 0;
}
task_manager = new TaskManager();
GetLogger("TaskManager")->info("task-based parallelization (C++11 threads) using {} threads", task_manager->GetNumThreads());
#ifdef USE_NUMA
numa_run_on_node (0);
#endif
#ifndef WIN32
// master has maximal priority !
int policy;
struct sched_param param;
pthread_getschedparam(pthread_self(), &policy, &param);
param.sched_priority = sched_get_priority_max(policy);
pthread_setschedparam(pthread_self(), policy, &param);
#endif // WIN32
task_manager->StartWorkers();
ParallelFor (Range(100), [&] (int i) { ; }); // startup
return task_manager->GetNumThreads();
}
void ExitTaskManager (int num_threads)
{
if(num_threads > 0)
{
task_manager->StopWorkers();
delete task_manager;
task_manager = nullptr;
}
}
void RunWithTaskManager (function<void()> alg)
{
int num_threads = EnterTaskManager();
alg();
ExitTaskManager(num_threads);
}
void TaskManager :: SetNumThreads(int amax_threads)
{
if(task_manager && task_manager->active_workers>0)
{
std::cerr << "Warning: can't change number of threads while TaskManager active!" << std::endl;
return;
}
max_threads = amax_threads;
}
TaskManager :: TaskManager()
{
num_threads = GetMaxThreads();
// if (MyMPI_GetNTasks() > 1) num_threads = 1;
#ifdef USE_NUMA
numa_available();
num_nodes = numa_max_node() + 1;
if (num_nodes > num_threads) num_nodes = num_threads;
for (int j = 0; j < num_nodes; j++)
{
void * mem = numa_alloc_onnode (sizeof(NodeData), j);
nodedata[j] = new (mem) NodeData;
complete[j] = -1;
workers_on_node[j] = 0;
}
#else
num_nodes = 1;
nodedata[0] = new NodeData;
complete[0] = -1;
workers_on_node[0] = 0;
#endif
jobnr = 0;
done = 0;
sleep = false;
sleep_usecs = 1000;
active_workers = 0;
static int cnt = 0;
if (use_paje_trace)
trace = new PajeTrace(num_threads, "ng" + ToString(cnt++));
}
TaskManager :: ~TaskManager ()
{
if (use_paje_trace)
{
delete trace;
trace = nullptr;
}
num_threads = 1;
}
#ifdef WIN32
int TaskManager :: GetThreadId()
{
return thread_id;
}
#endif
void TaskManager :: StartWorkers()
{
done = false;
for (int i = 1; i < num_threads; i++)
{
std::thread([this,i]() { this->Loop(i); }).detach();
}
thread_id = 0;
size_t alloc_size = num_threads*NgProfiler::SIZE;
NgProfiler::thread_times = new size_t[alloc_size];
for (size_t i = 0; i < alloc_size; i++)
NgProfiler::thread_times[i] = 0;
NgProfiler::thread_flops = new size_t[alloc_size];
for (size_t i = 0; i < alloc_size; i++)
NgProfiler::thread_flops[i] = 0;
while (active_workers < num_threads-1)
;
}
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 = 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;
// cout << "cpu frequ = " << frequ << endl;
// collect timings
for (size_t i = 0; i < num_threads; i++)
for (size_t j = NgProfiler::SIZE; j-- > 0; )
{
if (!NgProfiler::timers[j].usedcounter) break;
NgProfiler::timers[j].tottime += 1.0/frequ * NgProfiler::thread_times[i*NgProfiler::SIZE+j];
NgProfiler::timers[j].flops += NgProfiler::thread_flops[i*NgProfiler::SIZE+j];
}
delete [] NgProfiler::thread_times;
NgProfiler::thread_times = NgProfiler::dummy_thread_times.data();
delete [] NgProfiler::thread_flops;
NgProfiler::thread_flops = NgProfiler::dummy_thread_flops.data();
while (active_workers)
;
}
/////////////////////// NEW: nested tasks using concurrent queue
struct TNestedTask
{
const function<void(TaskInfo&)> * func;
int mynr;
int total;
int producing_thread;
atomic<int> * endcnt;
TNestedTask () { ; }
TNestedTask (const function<void(TaskInfo&)> & _func,
int _mynr, int _total,
atomic<int> & _endcnt, int prod_tid)
: func(&_func), mynr(_mynr), total(_total), producing_thread(prod_tid), endcnt(&_endcnt)
{
;
}
};
typedef moodycamel::ConcurrentQueue<TNestedTask> TQueue;
typedef moodycamel::ProducerToken TPToken;
typedef moodycamel::ConsumerToken TCToken;
static TQueue taskqueue;
void AddTask (const function<void(TaskInfo&)> & afunc,
atomic<int> & endcnt)
{
TPToken ptoken(taskqueue);
int num = endcnt;
auto tid = TaskManager::GetThreadId();
for (int i = 0; i < num; i++)
taskqueue.enqueue (ptoken, { afunc, i, num, endcnt, tid });
}
bool TaskManager :: ProcessTask()
{
// static Timer t("process task");
TNestedTask task;
TCToken ctoken(taskqueue);
if (taskqueue.try_dequeue(ctoken, task))
{
TaskInfo ti;
ti.task_nr = task.mynr;
ti.ntasks = task.total;
ti.thread_nr = TaskManager::GetThreadId();
ti.nthreads = TaskManager::GetNumThreads();
/*
{
lock_guard<mutex> guard(m);
cout << "process nested, nr = " << ti.task_nr << "/" << ti.ntasks << endl;
}
*/
// if(trace && task.producing_thread != ti.thread_nr)
// trace->StartTask (ti.thread_nr, t, PajeTrace::Task::ID_TIMER, task.producing_thread);
(*task.func)(ti);
--*task.endcnt;
// if(trace && task.producing_thread != ti.thread_nr)
// trace->StopTask (ti.thread_nr, t);
return true;
}
return false;
}
void TaskManager :: CreateJob (const function<void(TaskInfo&)> & afunc,
int antasks)
{
if (num_threads == 1 || !task_manager) // || func)
{
if (startup_function) (*startup_function)();
TaskInfo ti;
ti.ntasks = antasks;
ti.thread_nr = 0; ti.nthreads = 1;
// ti.node_nr = 0; ti.nnodes = 1;
for (ti.task_nr = 0; ti.task_nr < antasks; ti.task_nr++)
afunc(ti);
if (cleanup_function) (*cleanup_function)();
return;
}
if (func)
{ // we are already parallel, use nested tasks
// startup for inner function not supported ...
// if (startup_function) (*startup_function)();
if (antasks == 1)
{
TaskInfo ti;
ti.task_nr = 0;
ti.ntasks = 1;
ti.thread_nr = 0; ti.nthreads = 1;
afunc(ti);
return;
}
atomic<int> endcnt(antasks);
AddTask (afunc, endcnt);
while (endcnt > 0)
{
ProcessTask();
}
// if (cleanup_function) (*cleanup_function)();
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;
ntasks.store (antasks); // , memory_order_relaxed);
ex = nullptr;
nodedata[0]->start_cnt.store (0, memory_order_relaxed);
jobnr++;
for (int j = 0; j < num_nodes; j++)
nodedata[j]->participate |= 1;
if (startup_function) (*startup_function)();
int thd = 0;
int thds = GetNumThreads();
int mynode = num_nodes * thd/thds;
IntRange mytasks = Range(int(ntasks)).Split (mynode, num_nodes);
NodeData & mynode_data = *(nodedata[mynode]);
TaskInfo ti;
ti.nthreads = thds;
ti.thread_nr = thd;
// ti.nnodes = num_nodes;
// ti.node_nr = mynode;
try
{
while (1)
{
int mytask = mynode_data.start_cnt++;
if (mytask >= mytasks.Size()) break;
ti.task_nr = mytasks.First()+mytask;
ti.ntasks = ntasks;
{
RegionTracer t(ti.thread_nr, jobnr, RegionTracer::ID_JOB, ti.task_nr);
(*func)(ti);
}
}
}
catch (Exception e)
{
{
lock_guard<mutex> guard(copyex_mutex);
delete ex;
ex = new Exception (e);
mynode_data.start_cnt = mytasks.Size();
}
}
if (cleanup_function) (*cleanup_function)();
for (int j = 0; j < num_nodes; j++)
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();
}
void TaskManager :: Loop(int thd)
{
/*
static Timer tADD("add entry counter");
static Timer tCASready1("spin-CAS ready tick1");
static Timer tCASready2("spin-CAS ready tick2");
static Timer tCASyield("spin-CAS yield");
static Timer tCAS1("spin-CAS wait");
static Timer texit("exit zone");
static Timer tdec("decrement");
*/
thread_id = thd;
int thds = GetNumThreads();
int mynode = num_nodes * thd/thds;
NodeData & mynode_data = *(nodedata[mynode]);
TaskInfo ti;
ti.nthreads = thds;
ti.thread_nr = thd;
// ti.nnodes = num_nodes;
// ti.node_nr = mynode;
#ifdef USE_NUMA
numa_run_on_node (mynode);
#endif
active_workers++;
workers_on_node[mynode]++;
int jobdone = 0;
#ifdef USE_MKL
auto mkl_max = mkl_get_max_threads();
mkl_set_num_threads_local(1);
#endif
size_t no_job_counter = 0;
while (!done)
{
if (complete[mynode] > jobdone)
jobdone = complete[mynode];
if (jobnr == jobdone)
{
no_job_counter++;
// RegionTracer t(ti.thread_nr, tCASyield, ti.task_nr);
while (ProcessTask()) no_job_counter = 0; // do the nested tasks
if(sleep || no_job_counter > 10000)
std::this_thread::sleep_for(std::chrono::microseconds(10));
else
{
#ifdef WIN32
std::this_thread::yield();
#else // WIN32
sched_yield();
#endif // WIN32
}
continue;
}
{
// RegionTracer t(ti.thread_nr, tADD, ti.task_nr);
// non-atomic fast check ...
if ( (mynode_data.participate & 1) == 0) continue;
int oldval = mynode_data.participate += 2;
if ( (oldval & 1) == 0)
{ // job not active, going out again
mynode_data.participate -= 2;
continue;
}
}
if (startup_function) (*startup_function)();
IntRange mytasks = Range(int(ntasks)).Split (mynode, num_nodes);
try
{
while (1)
{
if (mynode_data.start_cnt >= mytasks.Size()) break;
int mytask = mynode_data.start_cnt.fetch_add(1, memory_order_relaxed);
if (mytask >= mytasks.Size()) break;
ti.task_nr = mytasks.First()+mytask;
ti.ntasks = ntasks;
no_job_counter = 0;
{
RegionTracer t(ti.thread_nr, jobnr, RegionTracer::ID_JOB, ti.task_nr);
(*func)(ti);
}
}
}
catch (Exception e)
{
{
// cout << "got exception in TM" << endl;
lock_guard<mutex> guard(copyex_mutex);
delete ex;
ex = new Exception (e);
mynode_data.start_cnt = mytasks.Size();
}
}
#ifndef __MIC__
atomic_thread_fence (memory_order_release);
#endif // __MIC__
if (cleanup_function) (*cleanup_function)();
jobdone = jobnr;
mynode_data.participate-=2;
{
int oldpart = 1;
if (mynode_data.participate.compare_exchange_strong (oldpart, 0))
{
if (jobdone < jobnr.load())
{ // reopen gate
mynode_data.participate |= 1;
}
else
{
if (mynode != 0)
mynode_data.start_cnt = 0;
complete[mynode] = jobnr.load();
}
}
}
}
#ifdef USE_MKL
mkl_set_num_threads_local(mkl_max);
#endif
workers_on_node[mynode]--;
active_workers--;
}
std::list<std::tuple<std::string,double>> TaskManager :: Timing ()
{
/*
list<tuple<string,double>>timings;
double time =
RunTiming
( [&] ()
{
ParallelJob ( [] (TaskInfo ti) { ; } ,
TasksPerThread(1) );
});
timings.push_back (make_tuple("parallel job with 1 task per thread", time*1e9));
time =
RunTiming
( [&] ()
{
ParallelJob ( [] (TaskInfo ti) { ; } ,
TasksPerThread(10) );
});
timings.push_back (make_tuple("parallel job with 10 tasks per thread", time*1e9));
time =
RunTiming
( [&] ()
{
ParallelJob ( [] (TaskInfo ti) { ; } ,
TasksPerThread(100) );
});
timings.push_back (make_tuple("parallel job with 100 tasks per thread", time*1e9));
return timings;
*/
// this is the old function moved from the py-interface:
std::list<std::tuple<std::string,double>>timings;
double starttime, time;
double maxtime = 0.5;
size_t steps;
starttime = WallTime();
steps = 0;
do
{
for (size_t i = 0; i < 1000; i++)
ParallelJob ( [] (TaskInfo ti) { ; },
TasksPerThread(1));
steps += 1000;
time = WallTime()-starttime;
}
while (time < maxtime);
timings.push_back(make_tuple("ParallelJob 1 task/thread", time/steps*1e9));
starttime = WallTime();
steps = 0;
do
{
for (size_t i = 0; i < 1000; i++)
ParallelJob ( [] (TaskInfo ti) { ; },
TasksPerThread(100));
steps += 1000;
time = WallTime()-starttime;
}
while (time < maxtime);
timings.push_back(make_tuple("ParallelJob 100 task/thread", time/steps*1e9));
starttime = WallTime();
steps = 0;
do
{
for (int k = 0; k < 10000; k++)
{
SharedLoop2 sl(1000);
steps += 1;
}
time = WallTime()-starttime;
}
while (time < maxtime);
timings.push_back(make_tuple("SharedLoop init", time/steps*1e9));
starttime = WallTime();
steps = 0;
do
{
for (int k = 0; k < 1000; k++)
{
SharedLoop sl(5);
ParallelJob ( [&sl] (TaskInfo ti)
{
for (auto i : sl)
(void)i; // silence warning
} );
}
steps += 1000;
time = WallTime()-starttime;
}
while (time < maxtime);
timings.push_back(make_tuple("short SharedLoop", time/steps*1e9));
starttime = WallTime();
steps = 0;
do
{
for (int k = 0; k < 1000; k++)
{
SharedLoop sl1(5), sl2(5), sl3(5), sl4(5), sl5(5);
ParallelJob ( [&sl1, &sl2, &sl3, &sl4, &sl5] (TaskInfo ti)
{
for (auto i : sl1)
(void)i; // silence warning
for (auto i : sl2)
(void)i; // silence warning
for (auto i : sl3)
(void)i; // silence warning
for (auto i : sl4)
(void)i; // silence warning
for (auto i : sl5)
(void)i; // silence warning
} );
}
steps += 1000;
time = WallTime()-starttime;
}
while (time < maxtime);
timings.push_back(make_tuple("5 short SharedLoops", time/steps*1e9));
starttime = WallTime();
steps = 0;
SharedLoop2 sl2(5);
do
{
for (int k = 0; k < 1000; k++)
{
sl2.Reset(5);
ParallelJob ( [&sl2] (TaskInfo ti)
{
for (auto i : sl2)
(void)i; // silence warning
} );
}
steps += 1000;
time = WallTime()-starttime;
}
while (time < maxtime);
timings.push_back(make_tuple("short SharedLoop2", time/steps*1e9));
{
starttime = WallTime();
steps = 0;
SharedLoop2 sl1(5), sl2(5), sl3(5), sl4(5), sl5(5);
do
{
for (int k = 0; k < 1000; k++)
{
sl1.Reset(5);
sl2.Reset(5);
sl3.Reset(5);
sl4.Reset(5);
sl5.Reset(5);
ParallelJob ( [&sl1,&sl2,&sl3,&sl4,&sl5] (TaskInfo ti)
{
for (auto i : sl1)
(void)i; // silence warning
for (auto i : sl2)
(void)i; // silence warning
for (auto i : sl3)
(void)i; // silence warning
for (auto i : sl4)
(void)i; // silence warning
for (auto i : sl5)
(void)i; // silence warning
} );
}
steps += 1000;
time = WallTime()-starttime;
}
while (time < maxtime);
timings.push_back(make_tuple("5 short SharedLoop2", time/steps*1e9));
}
starttime = WallTime();
steps = 0;
{
SharedLoop2 sl(1000);
do
{
for (int k = 0; k < 1000; k++)
{
sl.Reset(1000);
ParallelJob ( [&sl] (TaskInfo ti)
{
for (auto i : sl)
(void)i; // silence warning
} );
steps += 1000;
}
time = WallTime()-starttime;
}
while (time < maxtime);
timings.push_back(make_tuple("SharedLoop2 1000, time per iteration", time/steps*1e9));
}
{
starttime = WallTime();
steps = 0;
SharedLoop2 sl(1000000);
do
{
sl.Reset(1000000);
ParallelJob ( [&sl] (TaskInfo ti)
{
for (auto i : sl)
(void)i; // silence warning
} );
steps += 1000000;
time = WallTime()-starttime;
}
while (time < maxtime);
timings.push_back(make_tuple("SharedLoop2 1000000, time per iteration", time/steps*1e9));
}
return timings;
}
}

1121
libsrc/core/taskmanager.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -28,6 +28,29 @@ namespace ngcore
template<typename T>
constexpr bool is_any_pointer = is_any_pointer_impl<T>::value;
} // namespace detail
// Type trait to check if a class implements a 'range_type Range()' function
namespace detail
{
template<typename T>
struct has_Range
{
private:
template<typename T2>
static constexpr auto check(T2*) ->
std::enable_if_t<!std::is_same_v<decltype(std::declval<T2>().Range()), void>, std::true_type>
{ std::true_type(); }
template<typename>
static constexpr std::false_type check(...);
using type = decltype(check<T>(nullptr)); // NOLINT
public:
NGCORE_API static constexpr bool value = type::value;
};
}
template<typename T>
constexpr bool has_range = detail::has_Range<T>::value;
} // namespace ngcore
#endif // NETGEN_CORE_TYPE_TRAITS_HPP

View File

@ -1,27 +1,90 @@
#include "ngcore_api.hpp"
#include "utils.hpp"
#include "logging.hpp"
#include "simd_generic.hpp"
#ifndef WIN32
#include <cxxabi.h>
#endif
#include <array>
#include <filesystem>
#include <iostream>
#include <regex>
#include "ngstream.hpp"
namespace ngcore
{
namespace detail
{
// see https://github.com/RobotLocomotion/drake/blob/master/common/nice_type_name.cc
static const auto demangle_regexes =
std::array<std::pair<std::regex, std::string>, 8>{
// Remove unwanted keywords and following space. (\b is word boundary.)
std::make_pair(std::regex("\\b(class|struct|enum|union) "), ""),
// Tidy up anonymous namespace.
{std::regex("[`(]anonymous namespace[')]"), "(anonymous)"},
// Replace Microsoft __int64 with long long.
{std::regex("\\b__int64\\b"), "long long"},
// Temporarily replace spaces we want to keep with "!". (\w is
// alphanumeric or underscore.)
{std::regex("(\\w) (\\w)"), "$1!$2"},
{std::regex(" "), ""}, // Delete unwanted spaces.
// Some compilers throw in extra namespaces like "__1" or "__cxx11".
// Delete them.
{std::regex("\\b__[[:alnum:]_]+::"), ""},
{std::regex("!"), " "}, // Restore wanted spaces.
// Recognize std::string's full name and abbreviate.
{std::regex("\\bstd::basic_string<char,std::char_traits<char>,"
"std::allocator<char>>"), "std::string"}
};
std::string CleanupDemangledName( std::string s )
{
for(const auto & [r, sub] : demangle_regexes)
s = std::regex_replace (s,r,sub);
return s;
}
} // namespace detail
// parallel netgen
int id = 0, ntasks = 1;
#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;
return detail::CleanupDemangledName(name);
}
#else
NGCORE_API std::string Demangle(const char* typeinfo) { int status; return abi::__cxa_demangle(typeinfo,
nullptr,
nullptr,
&status); }
NGCORE_API std::string Demangle(const char* typeinfo)
{
int status=0;
try
{
char *s = abi::__cxa_demangle(typeinfo, nullptr, nullptr, &status);
std::string result;
if (s == nullptr)
result = typeinfo;
else
{
result = s;
free(s);
}
result = detail::CleanupDemangledName(result);
return result;
}
catch( const std::exception & e )
{
GetLogger("utils")->warn("{}:{} cannot demangle {}, status: {}, error:{}", __FILE__, __LINE__, typeinfo, status, e.what());
}
std::string name = typeinfo;
return detail::CleanupDemangledName(name);
}
#endif
double ticks_per_second = [] () noexcept
double seconds_per_tick = [] () noexcept
{
auto tick_start = GetTimeCounter();
double tstart = WallTime();
@ -33,10 +96,35 @@ namespace ngcore
auto tick_end = GetTimeCounter();
tend = WallTime();
return (tick_end-tick_start)/(tend-tstart);
return (tend-tstart)/static_cast<double>(tick_end-tick_start);
}();
const std::chrono::time_point<TClock> wall_time_start = TClock::now();
int printmessage_importance = 0;
bool NGSOStream :: glob_active = true;
NGCORE_API int GetCompiledSIMDSize()
{
return GetDefaultSIMDSize();
}
NGCORE_API bool IsRangeCheckEnabled()
{
#ifdef NETGEN_ENABLE_CHECK_RANGE
return true;
#else
return false;
#endif
}
NGCORE_API std::filesystem::path GetTempFilename()
{
static int counter = 0;
auto path = std::filesystem::temp_directory_path();
path += ".temp_netgen_file_"+ToString(counter++)+"_"+ToString(GetTimeCounter());
return path;
}
} // namespace ngcore

View File

@ -1,27 +1,42 @@
#ifndef NETGEN_CORE_UTILS_HPP
#define NETGEN_CORE_UTILS_HPP
#include <atomic>
#include <chrono>
#include <filesystem>
#include <map>
#include <ostream>
#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
{
// MPI rank, nranks TODO: Rename
extern NGCORE_API int id, ntasks;
// [[deprecated("don't use global id/ntasks")]]
extern NGCORE_API int id;
// [[deprecated("don't use global id/ntasks")]]
extern NGCORE_API int ntasks;
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)); }
@ -43,11 +58,23 @@ namespace ngcore
// High precision clock counter register
using TTimePoint = size_t;
extern NGCORE_API double ticks_per_second;
extern NGCORE_API double seconds_per_tick;
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>
@ -58,6 +85,42 @@ namespace ngcore
return ss.str();
}
inline std::string ToLower( const std::string & s )
{
std::string res;
res.reserve(s.size());
for(auto & c : s)
res.push_back(tolower(c));
return res;
}
inline std::string ToLower( const std::filesystem::path & p )
{
return ToLower(p.string());
}
template <class T>
void SaveBin (std::ostream & ost, const T & val)
{
const char * cp = reinterpret_cast<const char*> (&val);
for (unsigned j = 0; j < sizeof(T); j++)
ost.put(cp[j]);
}
template <class T>
void LoadBin (std::istream & ist, T & val)
{
char * cp = reinterpret_cast<char*> (&val);
for (unsigned j = 0; j < sizeof(T); j++)
ist.get(cp[j]);
}
template<typename T1, typename T2>
std::ostream& operator << (std::ostream& ost, const std::map<T1,T2>& map)
{
@ -65,6 +128,202 @@ namespace ngcore
ost << "\n" << val.first << ": " << val.second;
return ost;
}
template <class T>
NETGEN_INLINE void Swap (T & a, T & b)
{
T temp = std::move(a);
a = std::move(b);
b = std::move(temp);
}
/// min of 2 values
template <class T>
NETGEN_INLINE T min2 (T a, T b)
{
return (a < b) ? a : b;
}
/// max of 2 values
template <class T>
NETGEN_INLINE T max2 (T a, T b)
{
return (a > b) ? a : b;
}
/// min of 3 values
template <class T>
NETGEN_INLINE T min3 (T a, T b, T c)
{
return (a < b) ? (a < c) ? a : c
: (b < c) ? b : c;
}
/// max of 3 values
template <class T>
NETGEN_INLINE T max3 (T a, T b, T c)
{
///
return (a > b) ? ((a > c) ? a : c)
: ((b > c) ? b : c);
}
/// sign of value (+1, 0, -1)
template <class T>
NETGEN_INLINE int sgn (T a)
{
return (a > 0) ? 1 : ( ( a < 0) ? -1 : 0 );
}
/// square element
template <class T>
NETGEN_INLINE T sqr (const T a)
{
return a * a;
}
/// element to the third power
template <class T>
NETGEN_INLINE T pow3 (const T a)
{
return a * a * a;
}
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; }
// checks if string starts with sequence
inline bool StartsWith(const std::string& str, const std::string& start)
{
if(start.size() > str.size())
return false;
return std::equal(start.begin(), start.end(), str.begin());
}
// checks if string ends with sequence
inline bool EndsWith(const std::string& str, const std::string& end)
{
if(end.size() > str.size())
return false;
return std::equal(end.rbegin(), end.rend(), str.rbegin());
}
template<typename T>
NETGEN_INLINE std::atomic<T> & AsAtomic (T & d)
{
return reinterpret_cast<std::atomic<T>&> (d);
}
NETGEN_INLINE double AtomicAdd( double & sum, double val )
{
std::atomic<double> & asum = AsAtomic(sum);
double current = asum.load();
while (!asum.compare_exchange_weak(current, current + val))
;
return current;
}
template<typename T>
NETGEN_INLINE T AtomicMin( T & minval, T val )
{
std::atomic<T> & aminval = AsAtomic(minval);
T current = aminval.load();
while (!aminval.compare_exchange_weak(current, std::min(current, val)))
;
return current;
}
template<typename T>
NETGEN_INLINE T AtomicMax( T & maxval, T val )
{
std::atomic<T> & amaxval = AsAtomic(maxval);
T current = amaxval.load();
while (!amaxval.compare_exchange_weak(current, std::max(current, val)))
;
return current;
}
template <int N> using IC = std::integral_constant<int,N>; // needed for Iterate
template <int NUM, typename FUNC>
NETGEN_INLINE void Iterate (FUNC f)
{
if constexpr (NUM > 1) Iterate<NUM-1> (f);
if constexpr (NUM >= 1) f(IC<NUM-1>());
}
template <int NUM, typename FUNC>
NETGEN_INLINE void Switch (size_t nr, FUNC f)
{
if (NUM-1 == nr) f(IC<NUM-1>());
if constexpr (NUM > 1) Switch<NUM-1> (nr, f);
}
namespace detail
{
template<typename T>
struct IndexTypeHelper
{
private:
template<typename T2>
static constexpr auto check(T2* t) -> typename T2::index_type { return *t; }
static constexpr size_t check(...);
public:
using type = decltype(check((T*) nullptr)); // NOLINT
};
} // namespace detail
// Get index type of object. If object has a typedef index_type it is this type, else size_t
template<typename T>
using index_type = typename detail::IndexTypeHelper<T>::type;
class MyMutex
{
std::atomic<bool> m;
public:
MyMutex() { m.store(false, std::memory_order_relaxed); }
void lock()
{
bool should = false;
while (!m.compare_exchange_weak(should, true))
{
should = false;
#ifdef NETGEN_ARCH_AMD64
_mm_pause();
#endif // NETGEN_ARCH_AMD64
}
}
void unlock()
{
m = false;
}
};
class MyLock
{
MyMutex & mutex;
public:
MyLock (MyMutex & amutex) : mutex(amutex) { mutex.lock(); }
~MyLock () { mutex.unlock(); }
};
NGCORE_API int GetCompiledSIMDSize();
NGCORE_API bool IsRangeCheckEnabled();
NGCORE_API std::filesystem::path GetTempFilename();
} // namespace ngcore
#endif // NETGEN_CORE_UTILS_HPP

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

47
libsrc/core/xbool.hpp Normal file
View File

@ -0,0 +1,47 @@
#ifndef NETGEN_CORE_XBOOL_HPP
#define NETGEN_CORE_XBOOL_HPP
/**************************************************************************/
/* File: xbool.hpp */
/* Author: Joachim Schoeberl */
/* Date: 14. Nov. 07 */
/**************************************************************************/
namespace ngcore
{
// an extended bool with values false/maybe/true
enum TMAYBE { maybe };
class xbool
{
uint8_t state;
public:
xbool (bool b) : state(b ? 2 : 0) { ; }
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; }
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

@ -1,30 +1,14 @@
add_definitions(-DNGINTERFACE_EXPORTS)
add_library(csg ${NG_LIB_TYPE}
target_sources(nglib PRIVATE
algprim.cpp brick.cpp
bspline2d.cpp csgeom.cpp csgparser.cpp curve2d.cpp edgeflw.cpp
explicitcurve2d.cpp extrusion.cpp gencyl.cpp genmesh.cpp identify.cpp
manifold.cpp meshsurf.cpp polyhedra.cpp revolution.cpp singularref.cpp
solid.cpp specpoin.cpp spline3d.cpp surface.cpp triapprox.cpp zrefine.cpp
python_csg.cpp splinesurface.cpp
)
if(APPLE)
set_target_properties( csg PROPERTIES SUFFIX ".so")
endif(APPLE)
target_link_libraries(csg PUBLIC mesh ${PYTHON_LIBRARIES})
install( TARGETS csg ${NG_INSTALL_DIR})
target_link_libraries(csg PUBLIC ngcore)
)
if(USE_GUI)
add_library(csgvis ${NG_LIB_TYPE} vscsg.cpp )
if(NOT WIN32)
target_link_libraries(csgvis csg visual)
if(APPLE)
set_target_properties( csgvis PROPERTIES SUFFIX ".so")
endif(APPLE)
install( TARGETS csgvis ${NG_INSTALL_DIR})
endif(NOT WIN32)
target_sources(nggui PRIVATE vscsg.cpp csgpkg.cpp)
endif(USE_GUI)
install(FILES

View File

@ -1,4 +1,5 @@
#include <mystdlib.h>
#include <core/register_archive.hpp>
#include <linalg.hpp>
@ -116,7 +117,7 @@ namespace netgen
void Plane :: GetPrimitiveData (const char *& classname,
Array<double> & coeffs) const
NgArray<double> & coeffs) const
{
classname = "plane";
coeffs.SetSize (6);
@ -128,7 +129,7 @@ namespace netgen
coeffs.Elem(6) = n(2);
}
void Plane :: SetPrimitiveData (Array<double> & coeffs)
void Plane :: SetPrimitiveData (NgArray<double> & coeffs)
{
p(0) = coeffs.Elem(1);
p(1) = coeffs.Elem(2);
@ -367,7 +368,7 @@ namespace netgen
c1 = (c(0) * c(0) + c(1) * c(1) + c(2) * c(2)) / (2 * r) - r / 2;
}
void Sphere :: GetPrimitiveData (const char *& classname, Array<double> & coeffs) const
void Sphere :: GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const
{
classname = "sphere";
coeffs.SetSize (4);
@ -377,7 +378,7 @@ namespace netgen
coeffs.Elem(4) = r;
}
void Sphere :: SetPrimitiveData (Array<double> & coeffs)
void Sphere :: SetPrimitiveData (NgArray<double> & coeffs)
{
c(0) = coeffs.Elem(1);
c(1) = coeffs.Elem(2);
@ -642,6 +643,32 @@ namespace netgen
cz = v(2);
}
void Ellipsoid :: GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const
{
classname = "ellipsoid";
coeffs.SetSize (12);
for(auto i : Range(3))
{
coeffs[i] = a(i);
coeffs[3+i] = v1(i);
coeffs[6+i] = v2(i);
coeffs[9+i] = v3(i);
}
}
void Ellipsoid :: SetPrimitiveData (NgArray<double> & coeffs)
{
for(auto i : Range(3))
{
a(i) = coeffs[i];
v1(i) = coeffs[3+i];
v2(i) = coeffs[6+i];
v3(i) = coeffs[9+i];
}
CalcData();
}
INSOLID_TYPE Ellipsoid :: BoxInSolid (const BoxSphere<3> & box) const
{
@ -731,7 +758,7 @@ namespace netgen
Cylinder :: Cylinder (Array<double> & coeffs)
Cylinder :: Cylinder (NgArray<double> & coeffs)
{
SetPrimitiveData(coeffs);
}
@ -773,7 +800,7 @@ namespace netgen
void Cylinder :: GetPrimitiveData (const char *& classname, Array<double> & coeffs) const
void Cylinder :: GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const
{
classname = "cylinder";
coeffs.SetSize (7);
@ -786,7 +813,7 @@ namespace netgen
coeffs.Elem(7) = r;
}
void Cylinder :: SetPrimitiveData (Array<double> & coeffs)
void Cylinder :: SetPrimitiveData (NgArray<double> & coeffs)
{
a(0) = coeffs.Elem(1);
a(1) = coeffs.Elem(2);
@ -851,9 +878,11 @@ namespace netgen
Vec<3> v1 = b - a;
Vec<3> v2 = cyl2->a - a;
if ( fabs (v1 * v2) < (1-eps) * v1.Length() * v2.Length()) return 0;
// if ( fabs (v1 * v2) < (1-1e-12) * v1.Length() * v2.Length()) return 0;
if ( Cross(v1,v2).Length2() > 1e-20 * v1.Length2() * v2.Length2()) return 0;
v2 = cyl2->b - a;
if ( fabs (v1 * v2) < (1-eps) * v1.Length() * v2.Length()) return 0;
// if ( fabs (v1 * v2) < (1-eps) * v1.Length() * v2.Length()) return 0;
if ( Cross(v1,v2).Length2() > 1e-20 * v1.Length2() * v2.Length2()) return 0;
inv = 0;
return 1;
@ -1127,14 +1156,14 @@ namespace netgen
CalcData();
}
EllipticCylinder :: EllipticCylinder (Array<double> & coeffs)
EllipticCylinder :: EllipticCylinder (NgArray<double> & coeffs)
{
SetPrimitiveData(coeffs);
}
void EllipticCylinder :: GetPrimitiveData (const char *& classname, Array<double> & coeffs) const
void EllipticCylinder :: GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const
{
classname = "ellipticcylinder";
coeffs.SetSize (9);
@ -1149,7 +1178,7 @@ namespace netgen
coeffs[8] = vs(2);
}
void EllipticCylinder :: SetPrimitiveData (Array<double> & coeffs)
void EllipticCylinder :: SetPrimitiveData (NgArray<double> & coeffs)
{
a(0) = coeffs[0];
a(1) = coeffs[1];
@ -1312,7 +1341,7 @@ namespace netgen
void Cone :: GetPrimitiveData (const char *& classname, Array<double> & coeffs) const
void Cone :: GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const
{
classname = "cone";
coeffs.SetSize (8);
@ -1326,7 +1355,7 @@ namespace netgen
coeffs.Elem(8) = rb;
}
void Cone :: SetPrimitiveData (Array<double> & coeffs)
void Cone :: SetPrimitiveData (NgArray<double> & coeffs)
{
a(0) = coeffs.Elem(1);
a(1) = coeffs.Elem(2);
@ -1537,10 +1566,10 @@ Primitive * EllipticCone :: CreateDefault ()
}
void EllipticCone :: GetPrimitiveData (const char *& classname, Array<double> & coeffs) const
void EllipticCone :: GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const
{
classname = "ellipticcone";
coeffs.SetSize (15);
coeffs.SetSize (11);
coeffs.Elem(1) = a(0);
coeffs.Elem(2) = a(1);
coeffs.Elem(3) = a(2);
@ -1556,7 +1585,7 @@ Primitive * EllipticCone :: CreateDefault ()
}
void EllipticCone :: SetPrimitiveData (Array<double> & coeffs)
void EllipticCone :: SetPrimitiveData (NgArray<double> & coeffs)
{
a(0) = coeffs.Elem(1);
@ -1727,7 +1756,7 @@ void EllipticCone :: GetTriangleApproximation
r = ar;
}
void Torus :: GetPrimitiveData (const char *& classname, Array<double> & coeffs) const
void Torus :: GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const
{
classname = "torus";
coeffs.SetSize (8);
@ -1741,7 +1770,7 @@ void EllipticCone :: GetTriangleApproximation
coeffs.Elem(8) = r;
}
void Torus :: SetPrimitiveData (Array<double> & coeffs)
void Torus :: SetPrimitiveData (NgArray<double> & coeffs)
{
c(0) = coeffs.Elem(1);
c(1) = coeffs.Elem(2);

View File

@ -80,8 +80,8 @@ namespace netgen
Point<3> P() const { return p; }
Vec<3> N() const { return n; }
virtual void GetPrimitiveData (const char *& classname,
Array<double> & coeffs) const;
virtual void SetPrimitiveData (Array<double> & coeffs);
NgArray<double> & coeffs) const;
virtual void SetPrimitiveData (NgArray<double> & coeffs);
static Primitive * CreateDefault ();
virtual Primitive * Copy () const;
@ -153,8 +153,8 @@ namespace netgen
}
virtual void GetPrimitiveData (const char *& classname,
Array<double> & coeffs) const;
virtual void SetPrimitiveData (Array<double> & coeffs);
NgArray<double> & coeffs) const;
virtual void SetPrimitiveData (NgArray<double> & coeffs);
static Primitive * CreateDefault ();
virtual Primitive * Copy () const;
@ -208,7 +208,7 @@ namespace netgen
public:
Cylinder (const Point<3> & aa, const Point<3> & ab, double ar);
Cylinder (Array<double> & coeffs);
Cylinder (NgArray<double> & coeffs);
// default constructor for archive
Cylinder() {}
@ -220,8 +220,8 @@ namespace netgen
Point<3> A() const { return a; }
Point<3> B() const { return b; }
double R() const { return r; }
virtual void GetPrimitiveData (const char *& classname, Array<double> & coeffs) const;
virtual void SetPrimitiveData (Array<double> & coeffs);
virtual void GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const;
virtual void SetPrimitiveData (NgArray<double> & coeffs);
static Primitive * CreateDefault ();
virtual Primitive * Copy () const;
@ -278,7 +278,7 @@ namespace netgen
///
EllipticCylinder (const Point<3> & aa,
const Vec<3> & avl, const Vec<3> & avs);
EllipticCylinder (Array<double> & coeffs);
EllipticCylinder (NgArray<double> & coeffs);
// default constructor for archive
EllipticCylinder() {}
@ -289,8 +289,8 @@ namespace netgen
}
// static Primitive * CreateDefault ();
virtual void GetPrimitiveData (const char *& classname, Array<double> & coeffs) const;
virtual void SetPrimitiveData (Array<double> & coeffs);
virtual void GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const;
virtual void SetPrimitiveData (NgArray<double> & coeffs);
///
virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
@ -339,23 +339,26 @@ namespace netgen
// default constructor for archive
Ellipsoid() {}
virtual void DoArchive(Archive& ar)
void DoArchive(Archive& ar) override
{
QuadraticSurface::DoArchive(ar);
ar & a & v1 & v2 & v3 & rmin;
}
///
virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const override;
///
virtual double HesseNorm () const;
double HesseNorm () const override;
///
virtual double MaxCurvature () const;
double MaxCurvature () const override;
///
virtual Point<3> GetSurfacePoint () const;
Point<3> GetSurfacePoint () const override;
virtual void GetTriangleApproximation (TriangleApproximation & tas,
void GetTriangleApproximation (TriangleApproximation & tas,
const Box<3> & bbox,
double facets) const;
double facets) const override;
void GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const override;
void SetPrimitiveData (NgArray<double> & coeffs) override;
private:
void CalcData();
@ -393,8 +396,8 @@ namespace netgen
ar & a & b & ra & rb & minr & vab & t0vec & t1vec & vabl & t0 & t1 & cosphi;
}
static Primitive * CreateDefault ();
virtual void GetPrimitiveData (const char *& classname, Array<double> & coeffs) const;
virtual void SetPrimitiveData (Array<double> & coeffs);
virtual void GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const;
virtual void SetPrimitiveData (NgArray<double> & coeffs);
///
virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
@ -445,8 +448,8 @@ namespace netgen
ar & a & vl & vs & h & vlr;
}
static Primitive * CreateDefault ();
virtual void GetPrimitiveData (const char *& classname, Array<double> & coeffs) const;
virtual void SetPrimitiveData (Array<double> & coeffs);
virtual void GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const;
virtual void SetPrimitiveData (NgArray<double> & coeffs);
///
virtual INSOLID_TYPE BoxInSolid (const BoxSphere<3> & box) const;
@ -513,9 +516,9 @@ namespace netgen
virtual Point<3> GetSurfacePoint () const;
/// OK
virtual void GetPrimitiveData (const char *& classname,
Array<double> & coeffs) const;
NgArray<double> & coeffs) const;
/// OK
virtual void SetPrimitiveData (Array<double> & coeffs);
virtual void SetPrimitiveData (NgArray<double> & coeffs);
/// OK
static Primitive * CreateDefault ();
/// OK

View File

@ -1,4 +1,5 @@
#include <mystdlib.h>
#include <core/register_archive.hpp>
#include <linalg.hpp>
#include <csg.hpp>
@ -343,7 +344,7 @@ INSOLID_TYPE Brick :: VecInSolid4 (const Point<3> & p,
void Brick ::
GetPrimitiveData (const char *& classname, Array<double> & coeffs) const
GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const
{
classname = "brick";
coeffs.SetSize(12);
@ -364,7 +365,7 @@ GetPrimitiveData (const char *& classname, Array<double> & coeffs) const
coeffs.Elem(12) = p4(2);
}
void Brick :: SetPrimitiveData (Array<double> & coeffs)
void Brick :: SetPrimitiveData (NgArray<double> & coeffs)
{
p1(0) = coeffs.Elem(1);
p1(1) = coeffs.Elem(2);
@ -414,7 +415,7 @@ void Brick :: CalcData()
{ 1, 5, 3, 7 },
{ 2, 4, 6, 8 } };
Array<double> data(6);
NgArray<double> data(6);
for (i = 0; i < 6; i++)
{
const Point<3> lp1 = pi[lface[i][0]-1];

View File

@ -63,8 +63,8 @@ namespace netgen
{
Point<3> p1, p2, p3, p4;
Vec<3> v12, v13, v14;
// Array<OneSurfacePrimitive*> faces;
Array<Plane*> faces;
// NgArray<OneSurfacePrimitive*> faces;
NgArray<Plane*> faces;
public:
Brick (Point<3> ap1, Point<3> ap2, Point<3> ap3, Point<3> ap4);
@ -115,8 +115,8 @@ namespace netgen
{ return *faces[i]; }
virtual void GetPrimitiveData (const char *& classname, Array<double> & coeffs) const;
virtual void SetPrimitiveData (Array<double> & coeffs);
virtual void GetPrimitiveData (const char *& classname, NgArray<double> & coeffs) const;
virtual void SetPrimitiveData (NgArray<double> & coeffs);
virtual void Reduce (const BoxSphere<3> & box);
virtual void UnReduce ();

View File

@ -1,5 +1,6 @@
#include <mystdlib.h>
#include <myadt.hpp>
#include <core/register_archive.hpp>
#include <linalg.hpp>
#include <csg.hpp>
@ -72,10 +73,97 @@ namespace netgen
Clean();
}
PointGeomInfo CSGeometry :: ProjectPoint(int surfind, Point<3> & p) const
{
Point<3> hp = p;
GetSurface(surfind)->Project (hp);
p = hp;
return PointGeomInfo();
}
bool CSGeometry :: ProjectPointGI(int surfind, Point<3> & p, PointGeomInfo & gi) const
{
GetSurface(surfind)->Project (p);
return true;
}
void CSGeometry :: ProjectPointEdge(int surfind, INDEX surfind2,
Point<3> & p, EdgePointGeomInfo* /*unused*/) const
{
Point<3> hp = p;
ProjectToEdge (GetSurface(surfind),
GetSurface(surfind2), hp);
p = hp;
}
Vec<3> CSGeometry :: GetNormal(int surfind, const Point<3> & p,
const PointGeomInfo* /*unused*/) const
{
Vec<3> hn;
GetSurface(surfind)->CalcGradient(p, hn);
hn.Normalize();
return hn;
}
void CSGeometry ::
PointBetween(const Point<3> & p1, const Point<3> & p2, double secpoint,
int surfi,
const PointGeomInfo & gi1,
const PointGeomInfo & gi2,
Point<3> & newp, PointGeomInfo & newgi) const
{
Point<3> hnewp;
hnewp = p1+secpoint*(p2-p1);
if (surfi != -1)
{
GetSurface (surfi) -> Project (hnewp);
newgi.trignum = 1;
}
newp = hnewp;
}
void CSGeometry :: PointBetweenEdge(const Point<3> & p1, const Point<3> & p2, double secpoint,
int surfi1, int surfi2,
const EdgePointGeomInfo & ap1,
const EdgePointGeomInfo & ap2,
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)
{
netgen::ProjectToEdge (GetSurface(surfi1),
GetSurface(surfi2),
hnewp);
// (*testout) << "Pointbetween, newp = " << hnewp << endl
// << ", err = " << sqrt (sqr (hnewp(0))+ sqr(hnewp(1)) + sqr (hnewp(2))) - 1 << endl;
newgi.edgenr = 1;
//(*testout) << "hnewp (a1) " << hnewp << endl;
}
else if (surfi1 != -1)
{
GetSurface (surfi1) -> Project (hnewp);
//(*testout) << "hnewp (a2) " << hnewp << endl;
}
newp = hnewp;
};
Vec<3> CSGeometry :: GetTangent(const Point<3> & p, int surfi1, int surfi2,
const EdgePointGeomInfo & ap1) const
{
Vec<3> n1 = GetSurface (surfi1)->GetNormalVector (p);
Vec<3> n2 = GetSurface (surfi2)->GetNormalVector (p);
Vec<3> tau = Cross (n1, n2).Normalize();
return tau;
}
void CSGeometry :: Clean ()
{
Array< Solid* > to_delete;
NgArray< Solid* > to_delete;
for (int i = 0; i < solids.Size(); i++)
if(!to_delete.Contains(solids[i]->S1()))
@ -89,9 +177,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++)
@ -134,18 +221,18 @@ namespace netgen
int CSGeometry :: GenerateMesh (shared_ptr<Mesh> & mesh, MeshingParameters & mparam)
{
return CSGGenerateMesh (*this, mesh, mparam);
if(restricted_h.Size())
{
// copy so that we don't change mparam outside
MeshingParameters mp = mparam;
for(const auto& [pnt, maxh] : restricted_h)
mp.meshsize_points.Append({pnt, maxh});
return CSGGenerateMesh (*this, mesh, mp);
}
else
return CSGGenerateMesh (*this, mesh, mparam);
}
const Refinement & CSGeometry :: GetRefinement () const
{
// cout << "get CSGeometry - Refinement" << endl;
// should become class variables
RefinementSurfaces * ref = new RefinementSurfaces(*this);
ref -> Set2dOptimizer(new MeshOptimize2dSurfaces(*this));
return *ref;
}
class WritePrimitivesIt : public SolidIterator
{
ostream & ost;
@ -162,7 +249,7 @@ namespace netgen
if (prim)
{
const char * classname;
Array<double> coeffs;
NgArray<double> coeffs;
prim -> GetPrimitiveData (classname, coeffs);
@ -177,7 +264,7 @@ namespace netgen
}
void CSGeometry :: Save (string filename) const
void CSGeometry :: Save (const filesystem::path & filename) const
{
ofstream ost (filename.c_str());
Save (ost);
@ -235,9 +322,9 @@ namespace netgen
{
// CSGeometry * geo = new CSGeometry;
char key[100], name[100], classname[100], sname[100];
char key[100], name[100], classname[100], sname[150];
int ncoeff, i, j;
Array<double> coeff;
NgArray<double> coeff;
while (ist.good())
{
@ -262,7 +349,7 @@ namespace netgen
for (j = 0; j < nprim->GetNSurfaces(); j++)
{
sprintf (sname, "%s,%d", name, j);
snprintf (sname, size(sname), "%s,%d", name, j);
AddSurface (sname, &nprim->GetSurface(j));
nprim -> SetSurfaceId (j, GetNSurf());
}
@ -330,7 +417,7 @@ namespace netgen
& identpoints & boundingbox & isidenticto & ideps
& filename & spline_surfaces & splinecurves2d & splinecurves3d & surf2prim;
if(archive.Input())
FindIdenticSurfaces(1e-6);
FindIdenticSurfaces(1e-8 * MaxSize());
}
void CSGeometry :: SaveSurfaces (ostream & out) const
@ -343,7 +430,7 @@ namespace netgen
Array<double> coeffs;
NgArray<double> coeffs;
const char * classname;
out << "csgsurfaces " << GetNSurf() << "\n";
@ -408,7 +495,7 @@ namespace netgen
void CSGeometry :: LoadSurfaces (istream & in)
{
Array<double> coeffs;
NgArray<double> coeffs;
string classname;
int nsurfaces,size;
@ -485,6 +572,15 @@ namespace netgen
delete_them.Append(cone);
}
else if(classname == "ellipsoid")
{
Ellipsoid * ellipsoid = new Ellipsoid(dummypoint,dummyvec,dummyvec,dummyvec);
ellipsoid->SetPrimitiveData(coeffs);
AddSurface(ellipsoid);
delete_them.Append(ellipsoid);
}
else if(classname == "ellipticcone")
{
EllipticCone * ellipticcone = new EllipticCone(dummypoint,dummyvec,dummyvec,dummydouble,dummydouble);
@ -536,8 +632,8 @@ namespace netgen
{
static int cntsurfs = 0;
cntsurfs++;
char name[15];
sprintf (name, "nnsurf%d", cntsurfs);
char name[20];
snprintf (name, size(name), "nnsurf%d", cntsurfs);
AddSurface (name, surf);
}
@ -625,24 +721,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];
@ -722,7 +818,7 @@ namespace netgen
void CSGeometry :: SetFlags (const char * solidname, const Flags & flags)
{
Solid * solid = solids[solidname];
Array<int> surfind;
NgArray<int> surfind;
int i;
double maxh = flags.GetNumFlag ("maxh", -1);
@ -752,7 +848,7 @@ namespace netgen
if (flags.StringListFlagDefined ("bcname"))
{
const Array<char*> & bcname = flags.GetStringListFlag("bcname");
auto& bcname = flags.GetStringListFlag("bcname");
Polyhedra * polyh;
if(solid->S1())
@ -762,7 +858,7 @@ namespace netgen
if(polyh)
{
Array < Array<int> * > polysurfs;
NgArray < NgArray<int> * > polysurfs;
polyh->GetPolySurfs(polysurfs);
if(bcname.Size() != polysurfs.Size())
cerr << "WARNING: solid \"" << solidname << "\" has " << polysurfs.Size()
@ -806,7 +902,7 @@ namespace netgen
if (flags.NumListFlagDefined ("bc"))
{
const Array<double> & bcnum = flags.GetNumListFlag("bc");
const auto& bcnum = flags.GetNumListFlag("bc");
Polyhedra * polyh;
if(solid->S1())
@ -816,7 +912,7 @@ namespace netgen
if(polyh)
{
Array < Array<int> * > polysurfs;
NgArray < NgArray<int> * > polysurfs;
polyh->GetPolySurfs(polysurfs);
if(bcnum.Size() != polysurfs.Size())
cerr << "WARNING: solid \"" << solidname << "\" has " << polysurfs.Size()
@ -853,6 +949,7 @@ namespace netgen
{
int inv;
int nsurf = GetNSurf();
identicsurfaces.DeleteData();
isidenticto.SetSize(nsurf);
@ -880,7 +977,7 @@ namespace netgen
void CSGeometry ::
GetSurfaceIndices (const Solid * sol,
const BoxSphere<3> & box,
Array<int> & locsurf) const
NgArray<int> & locsurf) const
{
ReducePrimitiveIterator rpi(box);
UnReducePrimitiveIterator urpi;
@ -909,7 +1006,7 @@ namespace netgen
void CSGeometry ::
GetIndependentSurfaceIndices (const Solid * sol,
const BoxSphere<3> & box,
Array<int> & locsurf) const
NgArray<int> & locsurf) const
{
ReducePrimitiveIterator rpi(box);
UnReducePrimitiveIterator urpi;
@ -968,7 +1065,7 @@ namespace netgen
void CSGeometry ::
GetIndependentSurfaceIndices (const Solid * sol,
const Point<3> & p, Vec<3> & v,
Array<int> & locsurf) const
NgArray<int> & locsurf) const
{
cout << "very dangerous" << endl;
Point<3> p2 = p + 1e-2 * v;
@ -980,7 +1077,7 @@ namespace netgen
*/
void CSGeometry ::
GetIndependentSurfaceIndices (Array<int> & locsurf) const
GetIndependentSurfaceIndices (NgArray<int> & locsurf) const
{
for (int i = 0; i < locsurf.Size(); i++)
locsurf[i] = isidenticto[locsurf[i]];
@ -1022,7 +1119,7 @@ namespace netgen
delete triapprox[i];
triapprox.SetSize (ntlo);
Array<int> surfind;
NgArray<int> surfind;
IndexSet iset(GetNSurf());
for (int i = 0; i < ntlo; i++)
@ -1148,7 +1245,7 @@ namespace netgen
//return;
int pinds[6];
ArrayMem<int,500> surfused(GetNSurf());
NgArrayMem<int,500> surfused(GetNSurf());
ReducePrimitiveIterator rpi(box);
UnReducePrimitiveIterator urpi;
@ -1159,7 +1256,7 @@ namespace netgen
// IndexSet iset(GetNSurf());
locsol -> GetSurfaceIndices (iset);
const Array<int> & lsurfi = iset.GetArray();
const NgArray<int> & lsurfi = iset.GetArray();
locsol -> IterateSolid (urpi);
@ -1523,21 +1620,21 @@ namespace netgen
class CSGeometryRegister : public GeometryRegister
{
public:
virtual NetgenGeometry * Load (string filename) const;
virtual NetgenGeometry * LoadFromMeshFile (istream & ist) const;
virtual NetgenGeometry * Load (const filesystem::path & filename) const;
virtual NetgenGeometry * LoadFromMeshFile (istream & ist, string token) const;
// virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const;
};
extern CSGeometry * ParseCSG (istream & istr, CSGeometry *instance=nullptr);
NetgenGeometry * CSGeometryRegister :: Load (string filename) const
NetgenGeometry * CSGeometryRegister :: Load (const filesystem::path & filename) const
{
const char * cfilename = filename.c_str();
if (strcmp (&cfilename[strlen(cfilename)-3], "geo") == 0)
string extension = filename.extension().string();
if (extension == ".geo")
{
PrintMessage (1, "Load CSG geometry file ", cfilename);
PrintMessage (1, "Load CSG geometry file ", filename);
ifstream infile(cfilename);
ifstream infile(filename);
CSGeometry * hgeom = ParseCSG (infile);
if (!hgeom)
@ -1547,38 +1644,28 @@ namespace netgen
return hgeom;
}
if (strcmp (&cfilename[strlen(cfilename)-3], "ngg") == 0)
if (extension == ".ngg")
{
PrintMessage (1, "Load new CSG geometry file ", cfilename);
PrintMessage (1, "Load new CSG geometry file ", filename);
ifstream infile(cfilename);
ifstream infile(filename);
CSGeometry * hgeom = new CSGeometry("");
hgeom -> Load (infile);
return hgeom;
}
return NULL;
}
NetgenGeometry * CSGeometryRegister :: LoadFromMeshFile (istream & ist) const
NetgenGeometry * CSGeometryRegister :: LoadFromMeshFile (istream & ist, string token) const
{
string auxstring;
if (ist.good())
{
ist >> auxstring;
if (auxstring == "csgsurfaces")
{
CSGeometry * geometry = new CSGeometry ("");
geometry -> LoadSurfaces(ist);
return geometry;
}
// else
// ist.putback (auxstring);
}
return NULL;
if (token != "csgsurfaces")
return nullptr;
CSGeometry * geometry = new CSGeometry ("");
geometry -> LoadSurfaces(ist);
return geometry;
}

View File

@ -106,47 +106,50 @@ namespace netgen
public:
/// primitive of surface
Array<const Primitive*> surf2prim;
NgArray<const Primitive*> surf2prim;
private:
Array<Surface*> delete_them;
NgArray<Surface*> delete_them;
/// all named solids
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
Array<TopLevelObject*> toplevelobjects;
NgArray<TopLevelObject*> toplevelobjects;
public:
/// additional points specified by user
class UserPoint : public Point<3>
{
int index;
string name;
public:
UserPoint() = default;
UserPoint (Point<3> p, int _index) : Point<3>(p), index(_index) { ; }
UserPoint (Point<3> p, const string & _name) : Point<3>(p), index(-1), name(_name) { ; }
int GetIndex() const { return index; }
const string & GetName() const { return name; }
void DoArchive(Archive& archive)
{
archive & index;
archive & index & name;
Point<3>::DoArchive(archive);
}
};
private:
// Array<Point<3> > userpoints;
Array<UserPoint> userpoints;
Array<double> userpoints_ref_factor;
// NgArray<Point<3> > userpoints;
NgArray<UserPoint> userpoints;
NgArray<double> userpoints_ref_factor;
mutable Array<Point<3> > identpoints;
mutable NgArray<Point<3> > identpoints;
/// triangular approximation of top level objects
Array<TriangleApproximation*> triapprox;
NgArray<TriangleApproximation*> triapprox;
/// increment, if geometry is changed
static int changeval;
@ -159,7 +162,7 @@ namespace netgen
/// identic surfaces are stored by pair of indizes, val = inverse
INDEX_2_HASHTABLE<int> identicsurfaces;
Array<int> isidenticto;
NgArray<int> isidenticto;
/// identification of boundaries (periodic, thin domains, ...)
double ideps;
@ -168,8 +171,10 @@ namespace netgen
string filename;
/// store splinesurfaces, such that added ones do not get deleted before geometry does
Array<shared_ptr<SplineSurface>> spline_surfaces;
NgArray<shared_ptr<SplineSurface>> spline_surfaces;
shared_ptr<BlockAllocator> solid_ball = Solid::ball;
public:
CSGeometry ();
CSGeometry (const string & afilename);
@ -177,7 +182,7 @@ namespace netgen
void Clean ();
virtual void Save (string filename) const override;
virtual void Save (const filesystem::path & filename) const override;
void Save (ostream & ost) const;
void Load (istream & ist);
@ -186,6 +191,27 @@ namespace netgen
virtual void SaveToMeshFile (ostream & ost) const override;
PointGeomInfo ProjectPoint(INDEX surfind, Point<3> & p) const override;
bool ProjectPointGI (int surfind, Point<3> & p, PointGeomInfo & gi) const override;
void ProjectPointEdge(INDEX surfind, INDEX surfind2, Point<3> & p,
EdgePointGeomInfo* gi = nullptr) const override;
Vec<3> GetNormal(int surfind, const Point<3> & p, const PointGeomInfo* gi = nullptr) const override;
void PointBetween(const Point<3> & p1, const Point<3> & p2,
double secpoint, int surfi,
const PointGeomInfo & gi1,
const PointGeomInfo & gi2,
Point<3> & newp, PointGeomInfo & newgi) const override;
void PointBetweenEdge(const Point<3> & p1, const Point<3> & p2, double secpoint,
int surfi1, int surfi2,
const EdgePointGeomInfo & ap1,
const EdgePointGeomInfo & ap2,
Point<3> & newp, EdgePointGeomInfo & newgi) const override;
Vec<3> GetTangent (const Point<3> & p, int surfi1, int surfi2,
const EdgePointGeomInfo & ap1) const override;
int GetChangeVal() { return changeval; }
void Change() { changeval++; }
@ -206,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;
@ -261,10 +287,10 @@ namespace netgen
// quick implementations:
Array<SingularFace*> singfaces;
Array<SingularEdge*> singedges;
Array<SingularPoint*> singpoints;
Array<Identification*> identifications;
NgArray<SingularFace*> singfaces;
NgArray<SingularEdge*> singedges;
NgArray<SingularPoint*> singpoints;
NgArray<Identification*> identifications;
int GetNIdentifications (void) const { return identifications.Size(); }
void AddIdentification (Identification * ident);
@ -278,19 +304,19 @@ namespace netgen
///
void GetSurfaceIndices (const Solid * sol,
const BoxSphere<3> & box,
Array<int> & locsurf) const;
NgArray<int> & locsurf) const;
///
void GetIndependentSurfaceIndices (const Solid * sol,
const BoxSphere<3> & box,
Array<int> & locsurf) const;
NgArray<int> & locsurf) const;
///
/*
void GetIndependentSurfaceIndices (const Solid * sol,
const Point<3> & p, Vec<3> & v,
Array<int> & locsurf) const;
NgArray<int> & locsurf) const;
*/
///
void GetIndependentSurfaceIndices (Array<int> & locsurf) const;
void GetIndependentSurfaceIndices (NgArray<int> & locsurf) const;
///
int GetSurfaceClassRepresentant (int si) const
@ -342,12 +368,15 @@ namespace netgen
string * bcname;
};
Array<BCModification> bcmodifications;
NgArray<BCModification> bcmodifications;
map<tuple<Surface*,Surface*>, string> named_edges;
virtual int GenerateMesh (shared_ptr<Mesh> & mesh, MeshingParameters & mparam) override;
virtual const Refinement & GetRefinement () const override;
void AddSplineSurface (shared_ptr<SplineSurface> ss) { spline_surfaces.Append(ss); }
};

View File

@ -399,7 +399,7 @@ namespace netgen
int inputface = 0;
while (1)
{
Array<int> pnums,cleaned_pnums;
NgArray<int> pnums,cleaned_pnums;
for(int i=0; i<3; i++)
{
pnums.Append((int) (ParseNumber (scan)));
@ -479,7 +479,7 @@ namespace netgen
}
Primitive * nprim = new Revolution(p0,p1,
*(geom->GetSplineCurve2d(spline)));
geom->GetSplineCurve2d(spline));
geom->AddSurfaces (nprim);
return new Solid(nprim);
@ -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);
@ -794,28 +794,22 @@ namespace netgen
vals.Append (ParseNumber(scan));
}
ParseChar (scan, ']');
flags.SetFlag (name.c_str(), vals);
flags.SetFlag (name, vals);
}
else
{ // string list
Array<char*> vals;
string val = scan.GetStringValue();
vals.Append(new char[val.size()+1]);
strcpy(vals.Last(),val.c_str());
Array<string> vals;
vals.Append(scan.GetStringValue());
scan.ReadNext();
while (scan.GetToken() == ',')
{
scan.ReadNext();
val = scan.GetStringValue();
vals.Append(new char[val.size()+1]);
strcpy(vals.Last(),val.c_str());
vals.Append(scan.GetStringValue());
scan.ReadNext();
}
ParseChar (scan, ']');
flags.SetFlag (name.c_str(), vals);
for(int i=0; i<vals.Size(); i++)
delete [] vals[i];
flags.SetFlag (name, vals);
}
}
else if (scan.GetToken() == TOK_NUM)
@ -934,7 +928,7 @@ namespace netgen
ParseChar (scan, ';');
Array<int> si;
NgArray<int> si;
geom->GetSolid(surfname)->GetSurfaceIndices(si);
int tlonr =
geom->SetTopLevelObject ((Solid*)geom->GetSolid(name),
@ -942,8 +936,8 @@ namespace netgen
TopLevelObject * tlo = geom->GetTopLevelObject (tlonr);
if (flags.NumListFlagDefined ("col"))
{
const Array<double> & col = flags.GetNumListFlag ("col");
tlo->SetRGB (col.Get(1), col.Get(2), col.Get(3));
const auto& col = flags.GetNumListFlag ("col");
tlo->SetRGB (col[0], col[1], col[2]);
}
if (flags.GetDefineFlag ("transparent"))
tlo->SetTransparent (1);
@ -980,7 +974,7 @@ namespace netgen
ParseChar (scan, ';');
Array<int> si1, si2;
NgArray<int> si1, si2;
geom->GetSolid(name1)->GetSurfaceIndices(si1);
geom->GetSolid(name2)->GetSurfaceIndices(si2);
@ -1016,7 +1010,7 @@ namespace netgen
ParseChar (scan, ';');
Array<int> si1, si2;
NgArray<int> si1, si2;
geom->GetSolid(name1)->GetSurfaceIndices(si1);
geom->GetSolid(name2)->GetSurfaceIndices(si2);
@ -1192,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);
@ -1218,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);
@ -1246,7 +1240,7 @@ namespace netgen
CSGeometry::BCModification bcm;
bcm.bcname = NULL;
Array<int> si;
NgArray<int> si;
geom->GetSolid(name1)->GetSurfaceIndices(si);
if(si.Size() == 0)
@ -1298,7 +1292,7 @@ namespace netgen
bcm.bcname = NULL;
Array<int> si;
NgArray<int> si;
geom->GetSolid(name1)->GetSurfaceIndices(si);
if(si.Size() == 0)

View File

@ -17,7 +17,6 @@ extern "C" int Ng_CSG_Init (Tcl_Interp * interp);
namespace netgen
{
// extern DLL_HEADER NetgenGeometry * ng_geometry;
extern DLL_HEADER shared_ptr<NetgenGeometry> ng_geometry;
extern DLL_HEADER shared_ptr<Mesh> mesh;
@ -66,18 +65,18 @@ namespace netgen
Point3d pmin = geometry->BoundingBox ().PMin();
Point3d pmax = geometry->BoundingBox ().PMax();
sprintf (buf, "%5.1lf", pmin.X());
snprintf (buf, size(buf), "%5.1lf", pmin.X());
Tcl_SetVar (interp, "::geooptions.minx", buf, 0);
sprintf (buf, "%5.1lf", pmin.Y());
snprintf (buf, size(buf), "%5.1lf", pmin.Y());
Tcl_SetVar (interp, "::geooptions.miny", buf, 0);
sprintf (buf, "%5.1lf", pmin.Z());
snprintf (buf, size(buf), "%5.1lf", pmin.Z());
Tcl_SetVar (interp, "::geooptions.minz", buf, 0);
sprintf (buf, "%5.1lf", pmax.X());
snprintf (buf, size(buf), "%5.1lf", pmax.X());
Tcl_SetVar (interp, "::geooptions.maxx", buf, 0);
sprintf (buf, "%5.1lf", pmax.Y());
snprintf (buf, size(buf), "%5.1lf", pmax.Y());
Tcl_SetVar (interp, "::geooptions.maxy", buf, 0);
sprintf (buf, "%5.1lf", pmax.Z());
snprintf (buf, size(buf), "%5.1lf", pmax.Z());
Tcl_SetVar (interp, "::geooptions.maxz", buf, 0);
}
}
@ -154,7 +153,7 @@ namespace netgen
tcl_const char * name = argv[1];
tcl_const char * value = argv[2];
Array<double> coeffs;
NgArray<double> coeffs;
cout << "Set primitive data, name = " << name
@ -222,7 +221,7 @@ namespace netgen
const char * classname;
Array<double> coeffs;
NgArray<double> coeffs;
geometry->GetSolid (name)->GetPrimitive()->GetPrimitiveData (classname, coeffs);
@ -433,17 +432,17 @@ namespace netgen
if (!tlo) return TCL_OK;
char varname[50];
sprintf (varname, "%s(red)", propvar);
snprintf (varname, size(varname), "%s(red)", propvar);
double red = atof (Tcl_GetVar (interp, varname, 0));
sprintf (varname, "%s(blue)", propvar);
snprintf (varname, size(varname), "%s(blue)", propvar);
double blue = atof (Tcl_GetVar (interp, varname, 0));
sprintf (varname, "%s(green)", propvar);
snprintf (varname, size(varname), "%s(green)", propvar);
double green = atof (Tcl_GetVar (interp, varname, 0));
tlo -> SetRGB (red, green, blue);
sprintf (varname, "%s(visible)", propvar);
snprintf (varname, size(varname), "%s(visible)", propvar);
tlo -> SetVisible (bool(atoi (Tcl_GetVar (interp, varname, 0))));
sprintf (varname, "%s(transp)", propvar);
snprintf (varname, size(varname), "%s(transp)", propvar);
tlo -> SetTransparent (bool(atoi (Tcl_GetVar (interp, varname, 0))));
}
@ -461,24 +460,24 @@ namespace netgen
char varname[50], varval[10];
sprintf (varname, "%s(red)", propvar);
sprintf (varval, "%lf", tlo->GetRed());
snprintf (varname, size(varname), "%s(red)", propvar);
snprintf (varval, size(varval), "%lf", tlo->GetRed());
Tcl_SetVar (interp, varname, varval, 0);
sprintf (varname, "%s(green)", propvar);
sprintf (varval, "%lf", tlo->GetGreen());
snprintf (varname, size(varname), "%s(green)", propvar);
snprintf (varval, size(varval), "%lf", tlo->GetGreen());
Tcl_SetVar (interp, varname, varval, 0);
sprintf (varname, "%s(blue)", propvar);
sprintf (varval, "%lf", tlo->GetBlue());
snprintf (varname, size(varname), "%s(blue)", propvar);
snprintf (varval, size(varval), "%lf", tlo->GetBlue());
Tcl_SetVar (interp, varname, varval, 0);
sprintf (varname, "%s(visible)", propvar);
sprintf (varval, "%d", tlo->GetVisible());
snprintf (varname, size(varname), "%s(visible)", propvar);
snprintf (varval, size(varval), "%d", tlo->GetVisible());
Tcl_SetVar (interp, varname, varval, 0);
sprintf (varname, "%s(transp)", propvar);
sprintf (varval, "%d", tlo->GetTransparent());
snprintf (varname, size(varname), "%s(transp)", propvar);
snprintf (varval, size(varval), "%d", tlo->GetTransparent());
Tcl_SetVar (interp, varname, varval, 0);
}
@ -547,86 +546,10 @@ namespace netgen
}
/*
class CSGeometryRegister : public GeometryRegister
{
public:
virtual NetgenGeometry * Load (string filename) const;
virtual NetgenGeometry * LoadFromMeshFile (istream & ist) const;
virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const;
};
extern CSGeometry * ParseCSG (istream & istr);
NetgenGeometry * CSGeometryRegister :: Load (string filename) const
{
const char * cfilename = filename.c_str();
if (strcmp (&cfilename[strlen(cfilename)-3], "geo") == 0)
{
PrintMessage (1, "Load CSG geometry file ", cfilename);
ifstream infile(cfilename);
CSGeometry * hgeom = ParseCSG (infile);
if (!hgeom)
throw NgException ("geo-file should start with 'algebraic3d'");
hgeom -> FindIdenticSurfaces(1e-8 * hgeom->MaxSize());
return hgeom;
}
if (strcmp (&cfilename[strlen(cfilename)-3], "ngg") == 0)
{
PrintMessage (1, "Load new CSG geometry file ", cfilename);
ifstream infile(cfilename);
CSGeometry * hgeom = new CSGeometry("");
hgeom -> Load (infile);
return hgeom;
}
return NULL;
}
NetgenGeometry * CSGeometryRegister :: LoadFromMeshFile (istream & ist) const
{
string auxstring;
if (ist.good())
{
ist >> auxstring;
if (auxstring == "csgsurfaces")
{
CSGeometry * geometry = new CSGeometry ("");
geometry -> LoadSurfaces(ist);
return geometry;
}
// else
// ist.putback (auxstring);
}
return NULL;
}
VisualScene * CSGeometryRegister :: GetVisualScene (const NetgenGeometry * geom) const
{
CSGeometry * geometry = dynamic_cast<CSGeometry*> (ng_geometry.get());
if (geometry)
{
vsgeom.SetGeometry (geometry);
return &vsgeom;
}
return NULL;
}
*/
class CSGeometryVisRegister : public GeometryRegister
{
public:
virtual NetgenGeometry * Load (string filename) const { return NULL; }
virtual NetgenGeometry * Load (const filesystem::path & filename) const { return NULL; }
virtual VisualScene * GetVisualScene (const NetgenGeometry * geom) const;
};

View File

@ -13,7 +13,7 @@ namespace netgen
/*
2D Curve repesentation
2D Curve representation
*/

View File

@ -10,7 +10,7 @@ namespace netgen
EdgeCalculation ::
EdgeCalculation (const CSGeometry & ageometry,
Array<SpecialPoint> & aspecpoints,
NgArray<SpecialPoint> & aspecpoints,
MeshingParameters & amparam)
: geometry(ageometry), specpoints(aspecpoints), mparam(amparam)
{
@ -48,7 +48,7 @@ namespace netgen
// add all special points before edge points (important for periodic identification)
// JS, Jan 2007
const double di=1e-7*geometry.MaxSize();
Array<int> locsearch;
NgArray<int> locsearch;
for (int i = 0; i < specpoints.Size(); i++)
if (specpoints[i].unconditional)
@ -96,9 +96,9 @@ namespace netgen
void EdgeCalculation :: CalcEdges1 (double h, Mesh & mesh)
{
Array<int> hsp(specpoints.Size());
Array<int> glob2hsp(specpoints.Size());
Array<int> startpoints, endpoints;
NgArray<int> hsp(specpoints.Size());
NgArray<int> glob2hsp(specpoints.Size());
NgArray<int> startpoints, endpoints;
int pos, ep;
@ -107,11 +107,11 @@ namespace netgen
Point<3> p, np;
int pi1, s1, s2, s1_orig, s2_orig;
Array<Point<3> > edgepoints;
Array<double> curvelength;
NgArray<Point<3> > edgepoints;
NgArray<double> curvelength;
int copyedge = 0, copyfromedge = -1, copyedgeidentification = -1;
Array<int> locsurfind, locind;
NgArray<int> locsurfind, locind;
int checkedcopy = 0;
@ -180,7 +180,7 @@ namespace netgen
pi1 = 0;
copyedge = 0;
// identifyable point available ?
// identifiable point available ?
for (int i = 0; i < geometry.identifications.Size() && !pi1; i++)
@ -191,8 +191,8 @@ namespace netgen
<< ", v = " << specpoints[startpoints[j]].v
<< " for copying (i,j = " << i << ", " << j << ")" << endl;
#endif
if (geometry.identifications[i]->IdentifyableCandidate (specpoints[startpoints[j]]) &&
geometry.identifications[i]->IdentifyableCandidate (specpoints[endpoints[j]]))
if (geometry.identifications[i]->IdentifiableCandidate (specpoints[startpoints[j]]) &&
geometry.identifications[i]->IdentifiableCandidate (specpoints[endpoints[j]]))
{
@ -201,7 +201,7 @@ namespace netgen
for (int k = 0; k < hsp.Size() && !pi1; k++)
{
//(*testout) << " ? identifyable with " << specpoints[hsp[k]].p
//(*testout) << " ? identifiable with " << specpoints[hsp[k]].p
//<< ", v = " << specpoints[hsp[k]].v
// << endl;
if (identification_used.Used (INDEX_2(i, startpoints[j])) ||
@ -212,12 +212,12 @@ namespace netgen
}
if (geometry.identifications[i]
->Identifyable(specpoints[startpoints[j]], specpoints[hsp[k]], specpoint2tlo, specpoint2surface) ||
->Identifiable(specpoints[startpoints[j]], specpoints[hsp[k]], specpoint2tlo, specpoint2surface) ||
geometry.identifications[i]
->Identifyable(specpoints[hsp[k]], specpoints[startpoints[j]], specpoint2tlo, specpoint2surface))
->Identifiable(specpoints[hsp[k]], specpoints[startpoints[j]], specpoint2tlo, specpoint2surface))
{
#ifdef DEVELOP
(*testout) << "identifyable: " << specpoints[hsp[k]].p << ", v = " << specpoints[hsp[k]].v
(*testout) << "identifiable: " << specpoints[hsp[k]].p << ", v = " << specpoints[hsp[k]].v
<< " and " << specpoints[startpoints[j]].p << ", v = " << specpoints[startpoints[j]].v
<< " (identification " << i+1 << ")" << endl;
#endif
@ -245,7 +245,7 @@ namespace netgen
}
// cannot copy from other ege ?
// cannot copy from other edge ?
if (!pi1)
checkedcopy = startpoints.Size();
@ -406,8 +406,8 @@ namespace netgen
}
Array<Segment> refedges;
Array<bool> refedgesinv;
NgArray<Segment> refedges;
NgArray<bool> refedgesinv;
AnalyzeEdge (s1_orig, s2_orig, s1, s2, pos, layer,
@ -485,6 +485,29 @@ namespace netgen
layer,
mesh);
}
{
// named edge ?
// cout << "check edge name, size = " << geometry.named_edges.size() << endl;
// for (auto pair : geometry.named_edges)
// cout << "key = " << get<0> (pair.first) << "-" << get<1> (pair.first) << ", val = " << pair.second << endl;
Surface * sp1 = const_cast<Surface*> (geometry.GetSurface(s1));
Surface * sp2 = const_cast<Surface*> (geometry.GetSurface(s2));
// cout << "sp1 = " << sp1 << ", sp2 = " << sp2 << endl;
auto ptr = geometry.named_edges.find(tuple(sp1, sp2));
if (ptr != geometry.named_edges.end())
for (int i = 0; i < refedges.Size(); i++)
mesh.SetCD2Name(refedges[i].edgenr, ptr->second);
ptr = geometry.named_edges.find(tuple(sp2, sp1));
if (ptr != geometry.named_edges.end())
for (int i = 0; i < refedges.Size(); i++)
mesh.SetCD2Name(refedges[i].edgenr, ptr->second);
}
for(int i=0; i<refedges.Size(); i++)
{
auto splinesurface = dynamic_cast<const SplineSurface*>(geometry.GetSurface(refedges[i].surfnr1));
@ -546,7 +569,7 @@ namespace netgen
SegmentIndex si;
PointIndex pi;
Array<int> osedges(cntedge);
NgArray<int> osedges(cntedge);
INDEX_2_HASHTABLE<int> osedgesht (cntedge+1);
osedges = 2;
@ -678,17 +701,17 @@ namespace netgen
void EdgeCalculation ::
FollowEdge (int pi1, int & ep, int & pos,
const Array<int> & hsp,
const NgArray<int> & hsp,
double h, const Mesh & mesh,
Array<Point<3> > & edgepoints,
Array<double> & curvelength)
NgArray<Point<3> > & edgepoints,
NgArray<double> & curvelength)
{
int s1, s2, s1_rep, s2_rep;
double len, steplen, cursteplen, loch;
Point<3> p, np, pnp;
Vec<3> a1, a2, t;
Array<int> locind;
NgArray<int> locind;
double size = geometry.MaxSize();
double epspointdist2 = size * 1e-6;
@ -904,14 +927,14 @@ namespace netgen
void EdgeCalculation ::
AnalyzeEdge (int s1, int s2, int s1_rep, int s2_rep, int pos, int layer,
const Array<Point<3> > & edgepoints,
Array<Segment> & refedges,
Array<bool> & refedgesinv)
const NgArray<Point<3> > & edgepoints,
NgArray<Segment> & refedges,
NgArray<bool> & refedgesinv)
{
Segment seg;
Array<int> locsurfind, locsurfind2;
NgArray<int> locsurfind, locsurfind2;
Array<int> edges_priority;
NgArray<int> edges_priority;
double size = geometry.MaxSize();
bool debug = 0;
@ -947,7 +970,7 @@ namespace netgen
for (int i = 0; i < geometry.GetNTopLevelObjects(); i++)
{
Solid * locsol;
// Solid * locsol;
if (geometry.GetTopLevelObject(i)->GetLayer() != layer)
continue;
@ -955,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;
@ -972,7 +996,8 @@ namespace netgen
ReducePrimitiveIterator rpi(boxp);
UnReducePrimitiveIterator urpi;
((Solid*)locsol) -> IterateSolid (rpi);
// ((Solid*)locsol) -> IterateSolid (rpi);
locsol -> IterateSolid (rpi);
locsol -> CalcSurfaceInverse ();
@ -997,7 +1022,8 @@ namespace netgen
}
}
((Solid*)locsol) -> IterateSolid (urpi);
// ((Solid*)locsol) -> IterateSolid (urpi);
locsol -> IterateSolid (urpi);
if (debug)
@ -1062,23 +1088,33 @@ namespace netgen
//int k;
double eps = 1e-8*size;
Array<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);
@ -1127,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)
@ -1174,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;
@ -1223,7 +1262,7 @@ namespace netgen
m *= -1;
}
}
delete locsol;
// delete locsol;
}
@ -1232,8 +1271,11 @@ namespace netgen
*testout << "Refsegments, before delete: " << endl << refedges << endl;
*testout << "inv: " << endl << refedgesinv << endl;
}
if(refedges.Size() == 0)
throw Exception("No edges found, something wrong.");
BitArray todelete(refedges.Size());
NgBitArray todelete(refedges.Size());
todelete.Clear();
@ -1291,17 +1333,17 @@ namespace netgen
void EdgeCalculation ::
StoreEdge (const Array<Segment> & refedges,
const Array<bool> & refedgesinv,
const Array<Point<3> > & edgepoints,
const Array<double> & curvelength,
StoreEdge (const NgArray<Segment> & refedges,
const NgArray<bool> & refedgesinv,
const NgArray<Point<3> > & edgepoints,
const NgArray<double> & curvelength,
int layer,
Mesh & mesh)
{
// Calculate optimal element-length
int i, j, k;
PointIndex pi;
// PointIndex pi;
int ne;
double len, corr, lam;
@ -1326,7 +1368,7 @@ namespace netgen
// generate initial point
p = edgepoints.Get(1);
lastpi = -1;
lastpi = PointIndex::INVALID;
/*
for (pi = PointIndex::BASE;
@ -1340,7 +1382,7 @@ namespace netgen
const double di=1e-7*geometry.MaxSize();
Array<int> locsearch;
NgArray<int> locsearch;
meshpoint_tree -> GetIntersecting (p-Vec<3> (di,di,di),
p+Vec<3> (di,di,di), locsearch);
if (locsearch.Size())
@ -1348,7 +1390,7 @@ namespace netgen
if (lastpi == -1)
if (!lastpi.IsValid())
{
lastpi = mesh.AddPoint (p, layer, FIXEDPOINT);
meshpoint_tree -> Insert (p, lastpi);
@ -1368,7 +1410,7 @@ namespace netgen
np(1) = (1-lam) * edgepoints.Get(j-1)(1) + lam * edgepoints.Get(j)(1);
np(2) = (1-lam) * edgepoints.Get(j-1)(2) + lam * edgepoints.Get(j)(2);
thispi = -1;
thispi = PointIndex::INVALID;
if (i == ne)
{
/*
@ -1384,7 +1426,7 @@ namespace netgen
thispi = locsearch[0];
}
if (thispi == -1)
if (!thispi.IsValid())
{
ProjectToEdge (surf1, surf2, np);
thispi = mesh.AddPoint (np, layer, (i==ne) ? FIXEDPOINT : EDGEPOINT);
@ -1463,10 +1505,10 @@ namespace netgen
void EdgeCalculation ::
StoreShortEdge (const Array<Segment> & refedges,
const Array<bool> & refedgesinv,
const Array<Point<3> > & edgepoints,
const Array<double> & curvelength,
StoreShortEdge (const NgArray<Segment> & refedges,
const NgArray<bool> & refedgesinv,
const NgArray<Point<3> > & edgepoints,
const NgArray<double> & curvelength,
int layer,
Mesh & mesh)
{
@ -1496,7 +1538,7 @@ namespace netgen
// generate initial point
Point<3> p = edgepoints[0];
PointIndex pi1 = -1;
PointIndex pi1 = PointIndex::INVALID;
for (pi = PointIndex::BASE;
pi < mesh.GetNP()+PointIndex::BASE; pi++)
@ -1506,7 +1548,7 @@ namespace netgen
break;
}
if (pi1 == -1)
if (!pi1.IsValid())
{
pi1 = mesh.AddPoint (p, layer, FIXEDPOINT);
meshpoint_tree -> Insert (p, pi1);
@ -1514,7 +1556,7 @@ namespace netgen
}
p = edgepoints.Last();
PointIndex pi2 = -1;
PointIndex pi2 = PointIndex::INVALID;
for (pi = PointIndex::BASE;
pi < mesh.GetNP()+PointIndex::BASE; pi++)
@ -1523,7 +1565,7 @@ namespace netgen
pi2 = pi;
break;
}
if (pi2==-1)
if (!pi2.IsValid())
{
pi2 = mesh.AddPoint (p, layer, FIXEDPOINT);
meshpoint_tree -> Insert (p, pi2);
@ -1594,8 +1636,8 @@ namespace netgen
void EdgeCalculation ::
CopyEdge (const Array<Segment> & refedges,
const Array<bool> & refedgesinv,
CopyEdge (const NgArray<Segment> & refedges,
const NgArray<bool> & refedgesinv,
int copyfromedge,
const Point<3> & fromstart, const Point<3> & fromend,
const Point<3> & tostart, const Point<3> & toend,
@ -1616,8 +1658,8 @@ namespace netgen
Point<3> top =
(i == 1) ? tostart : toend;
PointIndex frompi = -1;
PointIndex topi = -1;
PointIndex frompi = PointIndex::INVALID;
PointIndex topi = PointIndex::INVALID;
for (pi = PointIndex::BASE;
pi < mesh.GetNP()+PointIndex::BASE; pi++)
{
@ -1628,7 +1670,7 @@ namespace netgen
}
if (topi == -1)
if (!topi.IsValid())
{
topi = mesh.AddPoint (top, layer, FIXEDPOINT);
meshpoint_tree -> Insert (top, topi);
@ -1638,9 +1680,9 @@ namespace netgen
(*geometry.identifications.Get(copyedgeidentification));
if (csi.Identifyable (mesh[frompi], mesh[topi]))
if (csi.Identifiable (mesh[frompi], mesh[topi]))
mesh.GetIdentifications().Add(frompi, topi, copyedgeidentification);
else if (csi.Identifyable (mesh[topi], mesh[frompi]))
else if (csi.Identifiable (mesh[topi], mesh[frompi]))
mesh.GetIdentifications().Add(topi, frompi, copyedgeidentification);
else
{
@ -1741,14 +1783,14 @@ namespace netgen
int nsurf = geometry.GetNSurf();
int layer = 0;
Solid * tansol;
Array<int> tansurfind;
// Solid * tansol;
NgArray<int> tansurfind;
double size = geometry.MaxSize();
int nsol = geometry.GetNTopLevelObjects();
BitArray pointatsurface (nsurf);
NgBitArray pointatsurface (nsurf);
pointatsurface.Clear();
for (int i = 1; i <= mesh.GetNSeg(); i++)
@ -1799,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();
@ -1829,7 +1872,7 @@ namespace netgen
// seg.invs1 = surfaces[i] -> Inverse();
// seg.invs2 = ! (surfaces[i] -> Inverse());
}
delete tansol;
// delete tansol;
}
}

View File

@ -26,7 +26,7 @@ namespace netgen
points have to be given.
*/
extern void CalcEdges (const CSGeometry & geometry,
const Array<SpecialPoint> & specpoints,
const NgArray<SpecialPoint> & specpoints,
double h, Mesh & mesh);
@ -36,7 +36,7 @@ namespace netgen
class EdgeCalculation
{
const CSGeometry & geometry;
Array<SpecialPoint> & specpoints;
NgArray<SpecialPoint> & specpoints;
Point3dTree * searchtree;
Point3dTree * meshpoint_tree;
int cntedge;
@ -46,7 +46,7 @@ namespace netgen
public:
EdgeCalculation (const CSGeometry & ageometry,
Array<SpecialPoint> & aspecpoints,
NgArray<SpecialPoint> & aspecpoints,
MeshingParameters & amparam);
~EdgeCalculation();
@ -61,34 +61,34 @@ namespace netgen
void FollowEdge (int pi1, int & ep, int & pos,
// const Array<SpecialPoint> & hsp,
const Array<int> & hsp,
// const NgArray<SpecialPoint> & hsp,
const NgArray<int> & hsp,
double h, const Mesh & mesh,
Array<Point<3> > & edgepoints,
Array<double> & curvelength);
NgArray<Point<3> > & edgepoints,
NgArray<double> & curvelength);
void AnalyzeEdge (int s1, int s2, int s1_rep, int s2_rep, int pos, int layer,
const Array<Point<3> > & edgepoints,
Array<Segment> & refedges,
Array<bool> & refedgesinv);
const NgArray<Point<3> > & edgepoints,
NgArray<Segment> & refedges,
NgArray<bool> & refedgesinv);
void StoreEdge (const Array<Segment> & refedges,
const Array<bool> & refedgesinv,
const Array<Point<3> > & edgepoints,
const Array<double> & curvelength,
void StoreEdge (const NgArray<Segment> & refedges,
const NgArray<bool> & refedgesinv,
const NgArray<Point<3> > & edgepoints,
const NgArray<double> & curvelength,
int layer,
Mesh & mesh);
void StoreShortEdge (const Array<Segment> & refedges,
const Array<bool> & refedgesinv,
const Array<Point<3> > & edgepoints,
const Array<double> & curvelength,
void StoreShortEdge (const NgArray<Segment> & refedges,
const NgArray<bool> & refedgesinv,
const NgArray<Point<3> > & edgepoints,
const NgArray<double> & curvelength,
int layer,
Mesh & mesh);
void CopyEdge (const Array<Segment> & refedges,
const Array<bool> & refedgesinv,
void CopyEdge (const NgArray<Segment> & refedges,
const NgArray<bool> & refedgesinv,
int copyfromedge,
const Point<3> & fromstart, const Point<3> & fromend,
const Point<3> & tostart, const Point<3> & toend,

View File

@ -13,7 +13,7 @@ namespace netgen
/*
Explicit 2D Curve repesentation
Explicit 2D Curve representation
*/
@ -70,9 +70,9 @@ namespace netgen
class BSplineCurve2d : public ExplicitCurve2d
{
///
Array<Point<2> > points;
NgArray<Point<2> > points;
///
Array<int> intervallused;
NgArray<int> intervallused;
///
int redlevel;

View File

@ -1,4 +1,5 @@
#include <mystdlib.h>
#include <core/register_archive.hpp>
#include <linalg.hpp>
#include <csg.hpp>
@ -7,7 +8,7 @@
namespace netgen
{
Array<Point<3> > project1, project2;
NgArray<Point<3> > project1, project2;
@ -41,6 +42,18 @@ namespace netgen
loc_z_dir[i] = glob_z_direction;
}
}
double cum_angle = 0.;
for(auto i : Range(path->GetSplines()))
{
const auto& sp = path->GetSpline(i);
auto t1 = sp.GetTangent(0.);
t1.Normalize();
auto t2 = sp.GetTangent(1.);
t2.Normalize();
cum_angle += acos(t1 * t2);
angles.Append(cum_angle);
}
profile->GetCoeff(profile_spline_coeff);
latest_point3d = -1.111e30;
@ -57,13 +70,13 @@ namespace netgen
Init();
}
ExtrusionFace :: ExtrusionFace(const Array<double> & raw_data)
ExtrusionFace :: ExtrusionFace(const NgArray<double> & raw_data)
{
deletable = true;
int pos=0;
Array< Point<2> > p(3);
NgArray< Point<2> > p(3);
int ptype = int(raw_data[pos]); pos++;
@ -128,21 +141,26 @@ namespace netgen
void ExtrusionFace :: CalcProj(const Point<3> & point3d, Point<2> & point2d,
int & seg, double & t) const
{
if (Dist2 (point3d, latest_point3d) <
1e-25 * Dist2(path->GetSpline(0).StartPI(), path->GetSpline(0).EndPI()))
static mutex set_latest_point;
auto eps = 1e-25 * Dist2(path->GetSpline(0).StartPI(), path->GetSpline(0).EndPI());
if (Dist2 (point3d, latest_point3d) < eps)
{
point2d = latest_point2d;
seg = latest_seg;
t = latest_t;
return;
std::lock_guard<std::mutex> guard(set_latest_point);
if (Dist2 (point3d, latest_point3d) < eps)
{
point2d = latest_point2d;
seg = latest_seg;
t = latest_t;
return;
}
}
latest_point3d = point3d;
double cutdist = -1;
Array<double> mindist(path->GetNSplines());
NgArray<double> mindist(path->GetNSplines());
for(int i = 0; i < path->GetNSplines(); i++)
{
@ -201,11 +219,13 @@ namespace netgen
point2d = testpoint2d;
t = thist;
seg = i;
latest_seg = i;
latest_t = t;
latest_point2d = point2d;
}
}
std::lock_guard<std::mutex> guard(set_latest_point);
latest_seg = seg;
latest_t = t;
latest_point2d = point2d;
latest_point3d = point3d;
}
double ExtrusionFace :: CalcProj(const Point<3> & point3d, Point<2> & point2d,
@ -415,6 +435,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,
@ -453,7 +481,7 @@ namespace netgen
v2d(1) = v * loc_z_dir[seg];
Vec<2> n(v2d(1),-v2d(0));
Array < Point<2> > ips;
NgArray < Point<2> > ips;
profile->LineIntersections(v2d(1),
@ -593,7 +621,7 @@ namespace netgen
}
void ExtrusionFace :: GetRawData(Array<double> & data) const
void ExtrusionFace :: GetRawData(NgArray<double> & data) const
{
data.DeleteAll();
profile->GetRawData(data);
@ -648,20 +676,35 @@ namespace netgen
dez /= lenz;
dez -= (dez * ez) * ez;
}
Extrusion :: Extrusion(const SplineGeometry<3> & path_in,
const SplineGeometry<2> & profile_in,
void ExtrusionFace :: DefineTangentialPlane(const Point<3>& ap1,
const Point<3>& ap2)
{
Surface::DefineTangentialPlane(ap1, ap2);
tangential_plane_seg = latest_seg;
}
void ExtrusionFace :: ToPlane(const Point<3>& p3d, Point<2>& p2d,
double h, int& zone) const
{
Surface::ToPlane(p3d, p2d, h, zone);
double angle = angles[tangential_plane_seg] - angles[latest_seg];
if(fabs(angle) > 3.14/2.)
zone = -1;
}
Extrusion :: Extrusion(shared_ptr<SplineGeometry<3>> path_in,
shared_ptr<SplineGeometry<2>> profile_in,
const Vec<3> & z_dir) :
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);
@ -695,7 +738,7 @@ namespace netgen
INSOLID_TYPE Extrusion :: PointInSolid (const Point<3> & p,
const double eps,
Array<int> * const facenums) const
NgArray<int> * const facenums) const
{
Vec<3> random_vec(-0.4561,0.7382,0.4970247);
@ -737,11 +780,21 @@ 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
{
Array<int> facenums;
NgArray<int> facenums;
INSOLID_TYPE pInSolid = PointInSolid(p,eps,&facenums);
if(pInSolid != DOES_INTERSECT)
@ -838,7 +891,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,14 +12,16 @@ namespace netgen
const SplineSeg<2> * profile;
const SplineGeometry<3> * path;
Vec<3> glob_z_direction;
Array<double> angles;
bool deletable;
int tangential_plane_seg;
Array< const SplineSeg3<3> * > spline3_path;
Array< const LineSeg<3> * > line_path;
NgArray< const SplineSeg3<3> * > spline3_path;
NgArray< const LineSeg<3> * > line_path;
mutable Array < Vec<3> > x_dir, y_dir, z_dir, loc_z_dir;
mutable Array < Point<3> > p0;
mutable NgArray < Vec<3> > x_dir, y_dir, z_dir, loc_z_dir;
mutable NgArray < Point<3> > p0;
mutable Vec<3> profile_tangent;
mutable double profile_par;
@ -48,13 +50,13 @@ namespace netgen
const SplineGeometry<3> * path_in,
const Vec<3> & z_direction);
ExtrusionFace(const Array<double> & raw_data);
ExtrusionFace(const NgArray<double> & raw_data);
// default constructor for archive
ExtrusionFace() {}
~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;
@ -102,7 +107,7 @@ namespace netgen
const Vec<3> & GetProfileTangent (void) const {return profile_tangent;}
double GetProfilePar(void) const {return profile_par;}
void GetRawData(Array<double> & data) const;
void GetRawData(NgArray<double> & data) const;
void CalcLocalCoordinates (int seg, double t,
Vec<3> & ex, Vec<3> & ey, Vec<3> & ez) 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,53 +128,56 @@ 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;
Array<ExtrusionFace*> faces;
NgArray<ExtrusionFace*> faces;
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,
Array<int> * const facenums) const;
virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
const Vec<3> & v,
double eps) const;
NgArray<int> * const facenums) const;
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 override;
// checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid
virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p,
const Vec<3> & v1,
const Vec<3> & v2,
double eps) const;
INSOLID_TYPE VecInSolid2 (const Point<3> & p,
const Vec<3> & v1,
const Vec<3> & v2,
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

@ -10,15 +10,19 @@
namespace netgen
{
Array<SpecialPoint> specpoints;
static Array<MeshPoint> spoints;
DLL_HEADER NgArray<SpecialPoint> global_specpoints; // for visualization
//static NgArray<MeshPoint> spoints;
#define TCL_OK 0
#define TCL_ERROR 1
static void FindPoints (CSGeometry & geom, Mesh & mesh)
static void FindPoints (CSGeometry & geom,
NgArray<SpecialPoint> & specpoints,
NgArray<MeshPoint> & spoints,
Mesh & mesh)
{
PrintMessage (1, "Start Findpoints");
@ -32,7 +36,11 @@ namespace netgen
auto pnum = mesh.AddPoint(up);
mesh.Points().Last().Singularity (geom.GetUserPointRefFactor(i));
mesh.AddLockedPoint (PointIndex (i+1));
mesh.pointelements.Append (Element0d(pnum, up.GetIndex()));
int index = up.GetIndex();
if (index == -1)
index = mesh.AddCD3Name (up.GetName())+1;
// cout << "adding 0d element, pnum = " << pnum << ", material index = " << index << endl;
mesh.pointelements.Append (Element0d(pnum, index));
}
SpecialPointCalculation spc;
@ -44,7 +52,13 @@ namespace netgen
PrintMessage (2, "Analyze spec points");
spc.AnalyzeSpecialPoints (geom, spoints, specpoints);
{
static mutex mut;
lock_guard<mutex> guard(mut);
global_specpoints = specpoints;
}
PrintMessage (5, "done");
(*testout) << specpoints.Size() << " special points:" << endl;
@ -63,7 +77,10 @@ namespace netgen
static void FindEdges (CSGeometry & geom, Mesh & mesh, MeshingParameters & mparam,
static void FindEdges (CSGeometry & geom, Mesh & mesh,
NgArray<SpecialPoint> & specpoints,
NgArray<MeshPoint> & spoints,
MeshingParameters & mparam,
const bool setmeshsize = false)
{
EdgeCalculation ec (geom, specpoints, mparam);
@ -140,7 +157,7 @@ namespace netgen
}
}
Array<int> loc;
NgArray<int> loc;
if (!ec.point_on_edge_problem)
for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++)
{
@ -234,17 +251,17 @@ namespace netgen
const char * savetask = multithread.task;
multithread.task = "Surface meshing";
Array<Segment> segments;
NgArray<Segment> segments;
int noldp = mesh.GetNP();
double starttime = GetTime();
// find master faces from identified
Array<int> masterface(mesh.GetNFD());
NgArray<int> masterface(mesh.GetNFD());
for (int i = 1; i <= mesh.GetNFD(); i++)
masterface.Elem(i) = i;
Array<INDEX_2> fpairs;
NgArray<INDEX_2> fpairs;
bool changed;
do
{
@ -382,7 +399,7 @@ namespace netgen
for (int j = 0; j < geom.singfaces.Size(); j++)
{
Array<int> surfs;
NgArray<int> surfs;
geom.GetIndependentSurfaceIndices (geom.singfaces[j]->GetSolid(),
geom.BoundingBox(), surfs);
for (int k = 1; k <= mesh.GetNFD(); k++)
@ -422,7 +439,7 @@ namespace netgen
geom.GetSurface((mesh.GetFaceDescriptor(k).SurfNr()));
Meshing2Surfaces meshing(*surf, mparam, geom.BoundingBox());
Meshing2Surfaces meshing(geom, *surf, mparam, geom.BoundingBox());
meshing.SetStartTime (starttime);
double eps = 1e-8 * geom.MaxSize();
@ -500,10 +517,12 @@ namespace netgen
}
if (multithread.terminate) return;
for (SurfaceElementIndex sei = oldnf; sei < mesh.GetNSE(); sei++)
mesh[sei].SetIndex (k);
auto n_illegal_trigs = mesh.FindIllegalTrigs();
PrintMessage (3, n_illegal_trigs, " illegal triangles");
// mesh.CalcSurfacesOfNode();
@ -521,48 +540,48 @@ namespace netgen
if (multithread.terminate) return;
{
MeshOptimize2dSurfaces meshopt(geom);
MeshOptimize2d meshopt(mesh);
meshopt.SetFaceIndex (k);
meshopt.SetImproveEdges (0);
meshopt.SetMetricWeight (mparam.elsizeweight);
meshopt.SetWriteStatus (0);
meshopt.EdgeSwapping (mesh, (i > mparam.optsteps2d/2));
meshopt.EdgeSwapping (i > mparam.optsteps2d/2);
}
if (multithread.terminate) return;
{
// mesh.CalcSurfacesOfNode();
MeshOptimize2dSurfaces meshopt(geom);
MeshOptimize2d meshopt(mesh);
meshopt.SetFaceIndex (k);
meshopt.SetImproveEdges (0);
meshopt.SetMetricWeight (mparam.elsizeweight);
meshopt.SetWriteStatus (0);
meshopt.ImproveMesh (mesh, mparam);
meshopt.ImproveMesh(mparam);
}
{
MeshOptimize2dSurfaces meshopt(geom);
MeshOptimize2d meshopt(mesh);
meshopt.SetFaceIndex (k);
meshopt.SetImproveEdges (0);
meshopt.SetMetricWeight (mparam.elsizeweight);
meshopt.SetWriteStatus (0);
meshopt.CombineImprove (mesh);
meshopt.CombineImprove();
// mesh.CalcSurfacesOfNode();
}
if (multithread.terminate) return;
{
MeshOptimize2dSurfaces meshopt(geom);
MeshOptimize2d meshopt(mesh);
meshopt.SetFaceIndex (k);
meshopt.SetImproveEdges (0);
meshopt.SetMetricWeight (mparam.elsizeweight);
meshopt.SetWriteStatus (0);
meshopt.ImproveMesh (mesh, mparam);
meshopt.ImproveMesh(mparam);
}
}
}
@ -663,6 +682,10 @@ namespace netgen
int CSGGenerateMesh (CSGeometry & geom,
shared_ptr<Mesh> & mesh, MeshingParameters & mparam)
{
NgArray<SpecialPoint> specpoints;
NgArray<MeshPoint> spoints;
if (mesh && mesh->GetNSE() &&
!geom.GetNSolids())
{
@ -680,7 +703,7 @@ namespace netgen
mesh->SetGlobalH (mparam.maxh);
mesh->SetMinimalH (mparam.minh);
Array<double> maxhdom(geom.GetNTopLevelObjects());
NgArray<double> maxhdom(geom.GetNTopLevelObjects());
for (int i = 0; i < maxhdom.Size(); i++)
maxhdom[i] = geom.GetTopLevelObject(i)->GetMaxH();
@ -699,7 +722,7 @@ namespace netgen
}
spoints.SetSize(0);
FindPoints (geom, *mesh);
FindPoints (geom, specpoints, spoints, *mesh);
PrintMessage (5, "find points done");
@ -717,7 +740,7 @@ namespace netgen
if (mparam.perfstepsstart <= MESHCONST_MESHEDGES)
{
FindEdges (geom, *mesh, mparam, true);
FindEdges (geom, *mesh, specpoints, spoints, mparam, true);
if (multithread.terminate) return TCL_OK;
#ifdef LOG_STREAM
(*logout) << "Edges meshed" << endl
@ -734,16 +757,16 @@ namespace netgen
mesh->CalcLocalH(mparam.grading);
mesh->DeleteMesh();
FindPoints (geom, *mesh);
FindPoints (geom, specpoints, spoints, *mesh);
if (multithread.terminate) return TCL_OK;
FindEdges (geom, *mesh, mparam, true);
FindEdges (geom, *mesh, specpoints, spoints, mparam, true);
if (multithread.terminate) return TCL_OK;
mesh->DeleteMesh();
FindPoints (geom, *mesh);
FindPoints (geom, specpoints, spoints, *mesh);
if (multithread.terminate) return TCL_OK;
FindEdges (geom, *mesh, mparam);
FindEdges (geom, *mesh, specpoints, spoints, mparam);
if (multithread.terminate) return TCL_OK;
}
}

View File

@ -28,7 +28,7 @@ ostream & operator<< (ostream & ost, Identification & ident)
/*
void Identification :: IdentifySpecialPoints (Array<class SpecialPoint> & points)
void Identification :: IdentifySpecialPoints (NgArray<class SpecialPoint> & points)
{
;
}
@ -36,24 +36,24 @@ void Identification :: IdentifySpecialPoints (Array<class SpecialPoint> & points
int Identification ::
Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2,
Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2,
const TABLE<int> & specpoint2solid,
const TABLE<int> & specpoint2surface) const
{
cout << "Identification::Identifyable called for base-class" << endl;
cout << "Identification::Identifiable called for base-class" << endl;
return 0;
}
int Identification ::
Identifyable (const Point<3> & p1, const Point<3> & sp2) const
Identifiable (const Point<3> & p1, const Point<3> & sp2) const
{
cout << "Identification::Identifyable called for base-class" << endl;
cout << "Identification::Identifiable called for base-class" << endl;
return 0;
}
int Identification ::
IdentifyableCandidate (const SpecialPoint & sp1) const
IdentifiableCandidate (const SpecialPoint & sp1) const
{
return 1;
}
@ -84,7 +84,7 @@ void Identification :: IdentifyFaces (class Mesh & mesh)
}
void Identification ::
BuildSurfaceElements (Array<Segment> & segs,
BuildSurfaceElements (NgArray<Segment> & segs,
Mesh & mesh, const Surface * surf)
{
cout << "Identification::BuildSurfaceElements called for base-class" << endl;
@ -93,14 +93,14 @@ BuildSurfaceElements (Array<Segment> & segs,
void Identification ::
BuildVolumeElements (Array<class Element2d> & surfels,
BuildVolumeElements (NgArray<class Element2d> & surfels,
class Mesh & mesh)
{
;
}
void Identification ::
GetIdentifiedFaces (Array<INDEX_2> & idfaces) const
GetIdentifiedFaces (NgArray<INDEX_2> & idfaces) const
{
idfaces.SetSize(0);
for (int i = 1; i <= identfaces.GetNBags(); i++)
@ -136,7 +136,7 @@ PeriodicIdentification :: ~PeriodicIdentification ()
/*
void PeriodicIdentification :: IdentifySpecialPoints
(Array<class SpecialPoint> & points)
(NgArray<class SpecialPoint> & points)
{
int i, j;
int bestj;
@ -196,7 +196,7 @@ void PeriodicIdentification :: IdentifySpecialPoints
*/
int PeriodicIdentification ::
Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2,
Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2,
const TABLE<int> & specpoint2solid,
const TABLE<int> & specpoint2surface) const
{
@ -252,7 +252,7 @@ Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2,
}
int PeriodicIdentification ::
Identifyable (const Point<3> & p1, const Point<3> & p2) const
Identifiable (const Point<3> & p1, const Point<3> & p2) const
{
return (s1->PointOnSurface (p1) &&
s2->PointOnSurface (p2));
@ -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);
/*
@ -446,7 +450,7 @@ void PeriodicIdentification :: IdentifyFaces (class Mesh & mesh)
void PeriodicIdentification ::
BuildSurfaceElements (Array<Segment> & segs,
BuildSurfaceElements (NgArray<Segment> & segs,
Mesh & mesh, const Surface * surf)
{
int found = 0;
@ -458,7 +462,7 @@ BuildSurfaceElements (Array<Segment> & segs,
if (geom.GetSurface(surfnr) == s1 ||
geom.GetSurface(surfnr) == s2)
{
Array<int> copy_points;
NgArray<int> copy_points;
for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++)
{
@ -609,7 +613,7 @@ void CloseSurfaceIdentification :: GetData (ostream & ost) const
/*
void CloseSurfaceIdentification :: IdentifySpecialPoints
(Array<class SpecialPoint> & points)
(NgArray<class SpecialPoint> & points)
{
int i, j;
int bestj;
@ -668,7 +672,7 @@ void CloseSurfaceIdentification :: IdentifySpecialPoints
*/
int CloseSurfaceIdentification ::
Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2,
Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2,
const TABLE<int> & specpoint2solid,
const TABLE<int> & specpoint2surface) const
{
@ -677,7 +681,7 @@ Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2,
if (!dom_surf_valid)
{
const_cast<bool&> (dom_surf_valid) = 1;
Array<int> & hsurf = const_cast<Array<int>&> (domain_surfaces);
NgArray<int> & hsurf = const_cast<NgArray<int>&> (domain_surfaces);
if (domain)
{
@ -826,7 +830,7 @@ Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2,
}
int CloseSurfaceIdentification ::
Identifyable (const Point<3> & p1, const Point<3> & p2) const
Identifiable (const Point<3> & p1, const Point<3> & p2) const
{
// if (domain)
// if (!domain->GetSolid()->IsIn (p1) || !domain->GetSolid()->IsIn (p2))
@ -838,7 +842,7 @@ Identifyable (const Point<3> & p1, const Point<3> & p2) const
int CloseSurfaceIdentification ::
IdentifyableCandidate (const SpecialPoint & sp1) const
IdentifiableCandidate (const SpecialPoint & sp1) const
{
if (domain)
if (!domain->GetSolid()->IsIn (sp1.p))
@ -887,7 +891,7 @@ GetIdentifiedPoint (class Mesh & mesh, int pi)
const Surface *snew;
const Point<3> & p = mesh.Point (pi);
Array<int,PointIndex::BASE> identmap(mesh.GetNP());
NgArray<int,PointIndex::BASE> identmap(mesh.GetNP());
mesh.GetIdentifications().GetMap (nr, identmap);
if (identmap.Get(pi))
return identmap.Get(pi);
@ -958,13 +962,13 @@ void CloseSurfaceIdentification :: IdentifyPoints (Mesh & mesh)
{
int np = mesh.GetNP();
Array<int> points_on_surf2;
NgArray<int> points_on_surf2;
for (int i2 = 1; i2 <= np; i2++)
if (s2->PointOnSurface (mesh.Point(i2)))
points_on_surf2.Append (i2);
Array<int> surfs_of_p1;
NgArray<int> surfs_of_p1;
for (int i1 = 1; i1 <= np; i1++)
{
@ -1080,7 +1084,7 @@ void CloseSurfaceIdentification :: IdentifyFaces (class Mesh & mesh)
s2rep = geom.GetSurfaceClassRepresentant(i);
}
Array<int> segs_on_face1, segs_on_face2;
NgArray<int> segs_on_face1, segs_on_face2;
identfaces.DeleteData();
@ -1219,13 +1223,13 @@ void CloseSurfaceIdentification :: IdentifyFaces (class Mesh & mesh)
void CloseSurfaceIdentification ::
BuildSurfaceElements (Array<Segment> & segs,
BuildSurfaceElements (NgArray<Segment> & segs,
Mesh & mesh, const Surface * surf)
{
bool found = 0;
int cntquads = 0;
Array<int,PointIndex::BASE> identmap;
NgArray<int,PointIndex::BASE> identmap;
identmap = 0;
mesh.GetIdentifications().GetMap (nr, identmap);
@ -1240,7 +1244,7 @@ BuildSurfaceElements (Array<Segment> & segs,
//(*testout) << "segs = " << endl << segs << endl;
//(*testout) << "identmap = " << endl << identmap << endl;
//Array<bool> foundseg(segs.Size());
//NgArray<bool> foundseg(segs.Size());
//foundseg = false;
// insert quad layer:
@ -1301,7 +1305,7 @@ BuildSurfaceElements (Array<Segment> & segs,
{
PrintMessage(3, "insert quad layer of ", cntquads,
" elements at face ", segs.Get(1).si);
//Array<Segment> aux;
//NgArray<Segment> aux;
//for(int i=0; i<segs.Size();i++)
// if(!foundseg[i])
// aux.Append(segs[i]);
@ -1319,7 +1323,7 @@ BuildSurfaceElements (Array<Segment> & segs,
void CloseSurfaceIdentification ::
BuildSurfaceElements2 (Array<Segment> & segs,
BuildSurfaceElements2 (NgArray<Segment> & segs,
Mesh & mesh, const Surface * surf)
{
// copy mesh
@ -1420,7 +1424,7 @@ BuildSurfaceElements2 (Array<Segment> & segs,
void CloseSurfaceIdentification ::
BuildVolumeElements (Array<class Element2d> & surfels,
BuildVolumeElements (NgArray<class Element2d> & surfels,
class Mesh & mesh)
{
;
@ -1481,7 +1485,7 @@ void CloseEdgesIdentification :: GetData (ostream & ost) const
/*
void CloseEdgesIdentification :: IdentifySpecialPoints
(Array<class SpecialPoint> & points)
(NgArray<class SpecialPoint> & points)
{
int i, j;
int bestj;
@ -1540,7 +1544,7 @@ void CloseEdgesIdentification :: IdentifySpecialPoints
*/
int CloseEdgesIdentification ::
Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2,
Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2,
const TABLE<int> & specpoint2solid,
const TABLE<int> & specpoint2surface) const
{
@ -1633,7 +1637,7 @@ void CloseEdgesIdentification :: IdentifyPoints (Mesh & mesh)
}
void CloseEdgesIdentification ::
BuildSurfaceElements (Array<Segment> & segs,
BuildSurfaceElements (NgArray<Segment> & segs,
Mesh & mesh, const Surface * surf)
{
int found = 0;

View File

@ -34,17 +34,17 @@ namespace netgen
DLL_HEADER virtual void GetData (ostream & ost) const = 0;
/// obsolete
// virtual void IdentifySpecialPoints (Array<class SpecialPoint> & points);
// virtual void IdentifySpecialPoints (NgArray<class SpecialPoint> & points);
/// can identify both special points (fixed direction)
/// (identified points, same tangent)
virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2,
virtual int Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2,
const TABLE<int> & specpoint2solid,
const TABLE<int> & specpoint2surface) const;
///
virtual int Identifyable (const Point<3> & p1, const Point<3> & sp2) const;
virtual int Identifiable (const Point<3> & p1, const Point<3> & sp2) const;
/// is it possible to identify sp1 with some other ?
virtual int IdentifyableCandidate (const SpecialPoint & sp1) const;
virtual int IdentifiableCandidate (const SpecialPoint & sp1) const;
/// are points (if connected) by a short edge (direction anyhow) ?
virtual int ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const;
@ -59,16 +59,16 @@ namespace netgen
virtual int GetIdentifiedPoint (class Mesh & mesh, int pi1);
/// copy surfaces, or fill rectangles
virtual void BuildSurfaceElements (Array<class Segment> & segs,
virtual void BuildSurfaceElements (NgArray<class Segment> & segs,
class Mesh & mesh,
const Surface * surf);
/// insert volume elements in thin layers
virtual void BuildVolumeElements (Array<class Element2d> & surfels,
virtual void BuildVolumeElements (NgArray<class Element2d> & surfels,
class Mesh & mesh);
/// get list of identified faces
virtual void GetIdentifiedFaces (Array<INDEX_2> & idfaces) const;
virtual void GetIdentifiedFaces (NgArray<INDEX_2> & idfaces) const;
friend ostream & operator<< (ostream & ost, Identification & ident);
};
@ -91,16 +91,16 @@ namespace netgen
virtual void GetData (ostream & ost) const override;
// virtual void IdentifySpecialPoints (Array<class SpecialPoint> & points);
virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2,
// virtual void IdentifySpecialPoints (NgArray<class SpecialPoint> & points);
virtual int Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2,
const TABLE<int> & specpoint2solid,
const TABLE<int> & specpoint2surface) const override;
virtual int Identifyable (const Point<3> & p1, const Point<3> & sp2) const override;
virtual int Identifiable (const Point<3> & p1, const Point<3> & sp2) const override;
virtual int GetIdentifiedPoint (class Mesh & mesh, int pi1) override;
virtual void IdentifyPoints (class Mesh & mesh) override;
virtual void IdentifyFaces (class Mesh & mesh) override;
virtual void BuildSurfaceElements (Array<class Segment> & segs,
virtual void BuildSurfaceElements (NgArray<class Segment> & segs,
class Mesh & mesh,
const Surface * surf) override;
};
@ -125,7 +125,7 @@ namespace netgen
double eps_n;
Array<double> slices;
/// used only for domain-local identification:
Array<int> domain_surfaces;
NgArray<int> domain_surfaces;
///
bool dom_surf_valid;
@ -146,25 +146,25 @@ namespace netgen
virtual void GetData (ostream & ost) const;
// virtual void IdentifySpecialPoints (Array<class SpecialPoint> & points);
virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2,
// virtual void IdentifySpecialPoints (NgArray<class SpecialPoint> & points);
virtual int Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2,
const TABLE<int> & specpoint2solid,
const TABLE<int> & specpoint2surface) const;
virtual int Identifyable (const Point<3> & p1, const Point<3> & sp2) const;
virtual int IdentifyableCandidate (const SpecialPoint & sp1) const;
virtual int Identifiable (const Point<3> & p1, const Point<3> & sp2) const;
virtual int IdentifiableCandidate (const SpecialPoint & sp1) const;
virtual int ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const;
virtual int GetIdentifiedPoint (class Mesh & mesh, int pi1);
const Array<double> & GetSlices () const { return slices; }
virtual void IdentifyPoints (class Mesh & mesh);
virtual void IdentifyFaces (class Mesh & mesh);
virtual void BuildSurfaceElements (Array<class Segment> & segs,
virtual void BuildSurfaceElements (NgArray<class Segment> & segs,
class Mesh & mesh,
const Surface * surf);
void BuildSurfaceElements2 (Array<class Segment> & segs,
void BuildSurfaceElements2 (NgArray<class Segment> & segs,
class Mesh & mesh,
const Surface * surf);
virtual void BuildVolumeElements (Array<class Element2d> & surfels,
virtual void BuildVolumeElements (NgArray<class Element2d> & surfels,
class Mesh & mesh);
int RefLevels () const { return ref_levels; }
@ -196,14 +196,14 @@ namespace netgen
virtual void Print (ostream & ost) const;
virtual void GetData (ostream & ost) const;
// virtual void IdentifySpecialPoints (Array<class SpecialPoint> & points);
virtual int Identifyable (const SpecialPoint & sp1, const SpecialPoint & sp2,
// virtual void IdentifySpecialPoints (NgArray<class SpecialPoint> & points);
virtual int Identifiable (const SpecialPoint & sp1, const SpecialPoint & sp2,
const TABLE<int> & specpoint2solid,
const TABLE<int> & specpoint2surface) const;
virtual void IdentifyPoints (class Mesh & mesh);
virtual void BuildSurfaceElements (Array<class Segment> & segs,
virtual void BuildSurfaceElements (NgArray<class Segment> & segs,
class Mesh & mesh,
const Surface * surf);
};

View File

@ -14,49 +14,44 @@ Meshing2Surfaces :: Meshing2Surfaces (const Surface & asurface)
;
}
*/
Meshing2Surfaces :: Meshing2Surfaces (const Surface & asurf,
const MeshingParameters & mp,
const Box<3> & abb)
: Meshing2(mp, abb), surface(asurf), mparam (mp)
{
;
}
Meshing2Surfaces :: Meshing2Surfaces (const CSGeometry& geo,
const Surface & asurf,
const MeshingParameters & mp,
const Box<3> & abb)
: Meshing2(geo, mp, abb), surface(asurf), mparam (mp)
{
;
}
void Meshing2Surfaces :: DefineTransformation (const Point3d & p1, const Point3d & p2,
void Meshing2Surfaces :: DefineTransformation (const Point<3> & p1, const Point<3> & p2,
const PointGeomInfo * geominfo1,
const PointGeomInfo * geominfo2)
{
((Surface&)surface).DefineTangentialPlane (p1, p2);
}
void Meshing2Surfaces :: TransformToPlain (const Point3d & locpoint,
void Meshing2Surfaces :: TransformToPlain (const Point<3> & locpoint,
const MultiPointGeomInfo & geominfo,
Point2d & planepoint,
Point<2> & planepoint,
double h, int & zone)
{
Point<2> hp;
surface.ToPlane (locpoint, hp, h, zone);
planepoint.X() = hp(0);
planepoint.Y() = hp(1);
surface.ToPlane (locpoint, planepoint, h, zone);
}
int Meshing2Surfaces :: TransformFromPlain (Point2d & planepoint,
Point3d & locpoint,
PointGeomInfo & gi,
double h)
int Meshing2Surfaces :: TransformFromPlain (const Point<2> & planepoint,
Point<3> & locpoint,
PointGeomInfo & gi,
double h)
{
Point<3> hp;
Point<2> hp2 (planepoint.X(), planepoint.Y());
surface.FromPlane (hp2, hp, h);
locpoint = hp;
surface.FromPlane (planepoint, locpoint, h);
gi.trignum = 1;
return 0;
}
double Meshing2Surfaces :: CalcLocalH (const Point3d & p, double gh) const
double Meshing2Surfaces :: CalcLocalH (const Point<3> & p, double gh) const
{
return surface.LocH (p, 3, 1, mparam, gh);
/*
@ -65,147 +60,4 @@ double Meshing2Surfaces :: CalcLocalH (const Point3d & p, double gh) const
return loch;
*/
}
MeshOptimize2dSurfaces :: MeshOptimize2dSurfaces (const CSGeometry & ageometry)
: MeshOptimize2d(), geometry(ageometry)
{
;
}
void MeshOptimize2dSurfaces :: ProjectPoint (INDEX surfind, Point<3> & p) const
{
Point<3> hp = p;
geometry.GetSurface(surfind)->Project (hp);
p = hp;
}
void MeshOptimize2dSurfaces :: ProjectPoint2 (INDEX surfind, INDEX surfind2,
Point<3> & p) const
{
Point<3> hp = p;
ProjectToEdge ( geometry.GetSurface(surfind),
geometry.GetSurface(surfind2), hp);
p = hp;
}
void MeshOptimize2dSurfaces ::
GetNormalVector(INDEX surfind, const Point<3> & p, Vec<3> & n) const
{
Vec<3> hn = n;
geometry.GetSurface(surfind)->CalcGradient (p, hn);
hn.Normalize();
n = hn;
/*
if (geometry.GetSurface(surfind)->Inverse())
n *= -1;
*/
}
RefinementSurfaces :: RefinementSurfaces (const CSGeometry & ageometry)
: Refinement(), geometry(ageometry)
{
if(geometry.GetNSurf() == 0)
*testout << endl
<< "WARNING: Initializing 2D refinement with 0-surface geometry" << endl
<< "==========================================================" << endl
<< endl << endl;
}
RefinementSurfaces :: ~RefinementSurfaces ()
{
;
}
void RefinementSurfaces ::
PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
int surfi,
const PointGeomInfo & gi1,
const PointGeomInfo & gi2,
Point<3> & newp, PointGeomInfo & newgi) const
{
Point<3> hnewp;
hnewp = p1+secpoint*(p2-p1);
if (surfi != -1)
{
geometry.GetSurface (surfi) -> Project (hnewp);
newgi.trignum = 1;
}
newp = hnewp;
}
void RefinementSurfaces ::
PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
int surfi1, int surfi2,
const EdgePointGeomInfo & ap1,
const EdgePointGeomInfo & ap2,
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)
{
netgen::ProjectToEdge (geometry.GetSurface(surfi1),
geometry.GetSurface(surfi2),
hnewp);
// (*testout) << "Pointbetween, newp = " << hnewp << endl
// << ", err = " << sqrt (sqr (hnewp(0))+ sqr(hnewp(1)) + sqr (hnewp(2))) - 1 << endl;
newgi.edgenr = 1;
//(*testout) << "hnewp (a1) " << hnewp << endl;
}
else if (surfi1 != -1)
{
geometry.GetSurface (surfi1) -> Project (hnewp);
//(*testout) << "hnewp (a2) " << hnewp << endl;
}
newp = hnewp;
};
Vec<3> RefinementSurfaces :: GetTangent (const Point<3> & p, int surfi1, int surfi2,
const EdgePointGeomInfo & ap1) const
{
Vec<3> n1 = geometry.GetSurface (surfi1)->GetNormalVector (p);
Vec<3> n2 = geometry.GetSurface (surfi2)->GetNormalVector (p);
Vec<3> tau = Cross (n1, n2).Normalize();
return tau;
}
Vec<3> RefinementSurfaces :: GetNormal (const Point<3> & p, int surfi1,
const PointGeomInfo & gi) const
{
return geometry.GetSurface (surfi1)->GetNormalVector (p);
}
void RefinementSurfaces :: ProjectToSurface (Point<3> & p, int surfi) const
{
if (surfi != -1)
geometry.GetSurface (surfi) -> Project (p);
};
void RefinementSurfaces :: ProjectToEdge (Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & egi) const
{
netgen::ProjectToEdge (geometry.GetSurface(surfi1),
geometry.GetSurface(surfi2),
p);
}
}

View File

@ -16,83 +16,30 @@ namespace netgen
///
// Meshing2Surfaces (const Surface & asurf);
///
Meshing2Surfaces (const Surface & asurf, const MeshingParameters & mp,
Meshing2Surfaces (const CSGeometry& geo,
const Surface & asurf,
const MeshingParameters & mp,
const Box<3> & aboundingbox);
protected:
///
virtual void DefineTransformation (const Point3d & p1, const Point3d & p2,
const PointGeomInfo * geominfo1,
const PointGeomInfo * geominfo2);
void DefineTransformation(const Point<3> & p1,
const Point<3> & p2,
const PointGeomInfo * geominfo1,
const PointGeomInfo * geominfo2) override;
///
virtual void TransformToPlain (const Point3d & locpoint,
const MultiPointGeomInfo & geominfo,
Point2d & plainpoint,
double h, int & zone);
void TransformToPlain(const Point<3> & locpoint,
const MultiPointGeomInfo & geominfo,
Point<2> & plainpoint,
double h, int & zone) override;
///
virtual int TransformFromPlain (Point2d & plainpoint,
Point3d & locpoint,
PointGeomInfo & gi,
double h);
int TransformFromPlain(const Point<2>& plainpoint,
Point<3>& locpoint,
PointGeomInfo & gi,
double h) override;
///
virtual double CalcLocalH (const Point3d & p, double gh) const;
double CalcLocalH(const Point<3> & p, double gh) const override;
};
///
class MeshOptimize2dSurfaces : public MeshOptimize2d
{
///
const CSGeometry & geometry;
public:
///
MeshOptimize2dSurfaces (const CSGeometry & ageometry);
///
virtual void ProjectPoint (INDEX surfind, Point<3> & p) const;
///
virtual void ProjectPoint2 (INDEX surfind, INDEX surfind2, Point<3> & p) const;
///
virtual void GetNormalVector(INDEX surfind, const Point<3> & p, Vec<3> & n) const;
};
class RefinementSurfaces : public Refinement
{
const CSGeometry & geometry;
public:
RefinementSurfaces (const CSGeometry & ageometry);
virtual ~RefinementSurfaces ();
virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
int surfi,
const PointGeomInfo & gi1,
const PointGeomInfo & gi2,
Point<3> & newp, PointGeomInfo & newgi) const;
virtual void PointBetween (const Point<3> & p1, const Point<3> & p2, double secpoint,
int surfi1, int surfi2,
const EdgePointGeomInfo & ap1,
const EdgePointGeomInfo & ap2,
Point<3> & newp, EdgePointGeomInfo & newgi) const;
virtual Vec<3> GetTangent (const Point<3> & p, int surfi1, int surfi2,
const EdgePointGeomInfo & ap1) const;
virtual Vec<3> GetNormal (const Point<3> & p, int surfi1,
const PointGeomInfo & gi) const;
virtual void ProjectToSurface (Point<3> & p, int surfi) const;
virtual void ProjectToEdge (Point<3> & p, int surfi1, int surfi2, const EdgePointGeomInfo & egi) const;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -35,64 +35,81 @@ namespace netgen
Face () { ; }
Face (int pi1, int pi2, int pi3,
const Array<Point<3> > & points,
const NgArray<Point<3> > & points,
int ainputnr);
};
Array<Point<3> > points;
Array<Face> faces;
Array<Plane*> planes;
NgArray<Point<3> > points;
NgArray<Face> faces;
NgArray<Plane*> planes;
Box<3> poly_bbox;
double eps_base1;
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;
virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
const Vec<3> & v,
double eps) const override;
// checks if lim s->0 lim t->0 p + t(v1 + s v2) in solid
virtual INSOLID_TYPE VecInSolid2 (const Point<3> & p,
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,
Array<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,
Array<int> & surfind, double eps) const;
NgArray<int> & surfind, double eps) const override;
virtual void CalcSpecialPoints (Array<Point<3> > & pts) const;
virtual void CalcSpecialPoints (NgArray<Point<3> > & pts) const override;
virtual void AnalyzeSpecialPoint (const Point<3> & pt,
Array<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, Array<double> & coeffs) const;
virtual void SetPrimitiveData (Array<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);
void GetPolySurfs(Array < Array<int> * > & polysurfs);
void GetPolySurfs(NgArray < NgArray<int> * > & polysurfs);
protected:
int FaceBoxIntersection (int fnr, const BoxSphere<3> & box) const;

View File

@ -1,10 +1,14 @@
#ifdef NG_PYTHON
#include <../general/ngpython.hpp>
#include <csg.hpp>
#include "../general/ngpython.hpp"
#include "../core/python_ngcore.hpp"
#include "csg.hpp"
#include "../meshing/python_mesh.hpp"
#include "../general/gzstream.h"
using namespace netgen;
using namespace pybind11::literals;
namespace netgen
{
@ -27,9 +31,11 @@ class SPSolid
double red = 0, green = 0, blue = 1;
bool transp = false;
public:
enum optyp { TERM, SECTION, UNION, SUB };
enum optyp { TERM, SECTION, UNION, SUB, EXISTING };
SPSolid (Solid * as) : solid(as), owner(true), op(TERM) { ; }
SPSolid (Solid * as, int /*dummy*/)
: solid(as), owner(false), op(EXISTING) { ; }
~SPSolid ()
{
; // if (owner) delete solid;
@ -166,7 +172,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)
@ -174,16 +181,16 @@ DLL_HEADER void ExportCSG(py::module &m)
self.geompoints.Append (GeomPoint<2> (Point<2> (x,y)));
return self.geompoints.Size()-1;
}))
.def ("AddSegment", FunctionPointer
([] (SplineGeometry<2> & self, int i1, int i2)
{
self.splines.Append (new LineSeg<2> (self.geompoints[i1], self.geompoints[i2]));
}))
.def ("AddSegment", FunctionPointer
([] (SplineGeometry<2> & self, int i1, int i2, int i3)
{
self.splines.Append (new SplineSeg3<2> (self.geompoints[i1], self.geompoints[i2], self.geompoints[i3]));
}))
.def ("AddSegment", [] (SplineGeometry<2> & self, int i1, int i2,
string bcname, double maxh)
{
self.splines.Append (new LineSeg<2> (self.geompoints[i1], self.geompoints[i2], maxh, bcname));
}, "p1"_a, "p2"_a, "bcname"_a="default", "maxh"_a=1e99)
.def ("AddSegment", [] (SplineGeometry<2> & self, int i1, int i2,
int i3, string bcname, double maxh)
{
self.splines.Append (new SplineSeg3<2> (self.geompoints[i1], self.geompoints[i2], self.geompoints[i3], bcname, maxh));
}, "p1"_a, "p2"_a, "p3"_a, "bcname"_a="default", "maxh"_a=1e99)
;
py::class_<SplineGeometry<3>,shared_ptr<SplineGeometry<3>>> (m,"SplineCurve3d")
@ -208,10 +215,10 @@ DLL_HEADER void ExportCSG(py::module &m)
py::class_<SplineSurface, shared_ptr<SplineSurface>> (m, "SplineSurface",
"A surface for co dim 2 integrals on the splines")
.def("__init__", FunctionPointer ([](SplineSurface* instance, shared_ptr<SPSolid> base, py::list cuts)
.def(py::init([](shared_ptr<SPSolid> base, py::list cuts)
{
auto primitive = dynamic_cast<OneSurfacePrimitive*> (base->GetSolid()->GetPrimitive());
auto acuts = make_shared<Array<shared_ptr<OneSurfacePrimitive>>>();
auto acuts = make_shared<NgArray<shared_ptr<OneSurfacePrimitive>>>();
for(int i = 0; i<py::len(cuts);i++)
{
py::extract<shared_ptr<SPSolid>> sps(cuts[i]);
@ -221,12 +228,11 @@ DLL_HEADER void ExportCSG(py::module &m)
if(sp)
acuts->Append(shared_ptr<OneSurfacePrimitive>(sp));
else
throw NgException("Cut must be SurfacePrimitive in constructor of SplineSurface!");
throw Exception("Cut must be SurfacePrimitive in constructor of SplineSurface!");
}
if(!primitive)
throw NgException("Base is not a SurfacePrimitive in constructor of SplineSurface!");
new (instance) SplineSurface(shared_ptr<OneSurfacePrimitive>(primitive),acuts);
py::object obj = py::cast(instance);
throw Exception("Base is not a SurfacePrimitive in constructor of SplineSurface!");
return make_shared<SplineSurface>(shared_ptr<OneSurfacePrimitive>(primitive),acuts);
}),py::arg("base"), py::arg("cuts")=py::list())
.def("AddPoint", FunctionPointer
([] (SplineSurface & self, double x, double y, double z, bool hpref)
@ -319,21 +325,38 @@ DLL_HEADER void ExportCSG(py::module &m)
Solid * sol = new Solid (torus);
return make_shared<SPSolid> (sol);
}));
m.def ("Revolution", FunctionPointer([](Point<3> p1, Point<3> p2,
const SplineGeometry<2> & spline)
{
Revolution * rev = new Revolution (p1, p2, spline);
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)
{
Extrusion * extr = new Extrusion (path,profile,n);
Solid * sol = new Solid(extr);
return make_shared<SPSolid> (sol);
}));
m.def ("Revolution", [](Point<3> p1, Point<3> p2,
shared_ptr<SplineGeometry<2>> spline)
{
Revolution * rev = new Revolution (p1, p2, spline);
Solid * sol = new Solid(rev);
return make_shared<SPSolid> (sol);
});
m.def ("Extrusion", [](shared_ptr<SplineGeometry<3>> path,
shared_ptr<SplineGeometry<2>> profile,
Vec<3> d)
{
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)
{
@ -351,6 +374,35 @@ When r =1, the truncated elliptic cone becomes an elliptic cylinder.
When r tends to zero, the truncated elliptic cone tends to a full elliptic cone.
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)
{
@ -409,7 +461,7 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails!
if (py::extract<int>(val).check()) mod_nr = py::extract<int> (val)();
if (py::extract<string>(val).check()) bcname = new string ( py::extract<string> (val)());
Array<int> si;
NgArray<int> si;
mod_solid -> GetSolid() -> GetSurfaceIndices (si);
// cout << "change bc on surfaces: " << si << " to " << mod_nr << endl;
@ -459,7 +511,7 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails!
self.GetTopLevelObject(tlonr) -> SetBCProp(surf->GetBase()->GetBCProperty());
self.GetTopLevelObject(tlonr) -> SetBCName(surf->GetBase()->GetBCName());
self.GetTopLevelObject(tlonr) -> SetMaxH(surf->GetBase()->GetMaxH());
Array<Point<3>> non_midpoints;
NgArray<Point<3>> non_midpoints;
for(auto spline : surf->GetSplines())
{
non_midpoints.Append(spline->GetPoint(0));
@ -494,12 +546,9 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails!
.def("CloseSurfaces", FunctionPointer
([] (CSGeometry & self, shared_ptr<SPSolid> s1, shared_ptr<SPSolid> s2, py::list aslices )
{
Array<int> si1, si2;
NgArray<int> si1, si2;
s1->GetSolid()->GetSurfaceIndices (si1);
s2->GetSolid()->GetSurfaceIndices (si2);
cout << "surface ids1 = " << si1 << endl;
cout << "surface ids2 = " << si2 << endl;
Flags flags;
try
@ -531,7 +580,7 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails!
([] (CSGeometry & self, shared_ptr<SPSolid> s1, shared_ptr<SPSolid> s2,
int reflevels, shared_ptr<SPSolid> domain_solid)
{
Array<int> si1, si2;
NgArray<int> si1, si2;
s1->GetSolid()->GetSurfaceIndices (si1);
s2->GetSolid()->GetSurfaceIndices (si2);
cout << "surface ids1 = " << si1 << endl;
@ -556,7 +605,7 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails!
([] (CSGeometry & self, shared_ptr<SPSolid> s1, shared_ptr<SPSolid> s2,
Transformation<3> trafo)
{
Array<int> si1, si2;
NgArray<int> si1, si2;
s1->GetSolid()->GetSurfaceIndices (si1);
s2->GetSolid()->GetSurfaceIndices (si2);
cout << "identify surfaces " << si1[0] << " and " << si2[0] << endl;
@ -569,10 +618,22 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails!
py::arg("solid1"), py::arg("solid2"),
py::arg("trafo")=Transformation<3>(Vec<3>(0,0,0))
)
.def("AddPoint", [] (CSGeometry & self, Point<3> p, int index) -> CSGeometry&
.def("NameEdge", [] (CSGeometry & self, shared_ptr<SPSolid> s1, shared_ptr<SPSolid> s2, string name)
{
self.AddUserPoint(CSGeometry::UserPoint(p, index));
Array<Surface*> surfs1, surfs2;
s1->GetSolid()->ForEachSurface( [&surfs1] (Surface * s, bool inv) { surfs1.Append(s); });
s2->GetSolid()->ForEachSurface( [&surfs2] (Surface * s, bool inv) { surfs2.Append(s); });
for (auto s1 : surfs1)
for (auto s2 : surfs2)
self.named_edges[tuple(s1,s2)] = name;
})
.def("AddPoint", [] (CSGeometry & self, Point<3> p, variant<int,string> index) -> CSGeometry&
{
if (auto pint = std::get_if<int> (&index))
self.AddUserPoint(CSGeometry::UserPoint(p, *pint));
if (auto pstr = std::get_if<string> (&index))
self.AddUserPoint(CSGeometry::UserPoint(p, *pstr));
return self;
})
@ -615,11 +676,18 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails!
.def("Draw", FunctionPointer
([] (shared_ptr<CSGeometry> self)
{
self->FindIdenticSurfaces(1e-6);
self->FindIdenticSurfaces(1e-8 * self->MaxSize());
self->CalcTriangleApproximation(0.01, 20);
ng_geometry = self;
})
)
.def("GetSolids", [](CSGeometry& self)
{
py::list lst;
for(auto i : Range(self.GetSolids().Size()))
lst.append(make_shared<SPSolid>(self.GetSolids()[i], 1234));
return lst;
})
.def_property_readonly ("ntlo", &CSGeometry::GetNTopLevelObjects)
.def("_visualizationData", [](shared_ptr<CSGeometry> csg_geo)
{
@ -638,8 +706,8 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails!
auto surf = csg_geo->GetSurface(i);
surfnames.push_back(surf->GetBCName());
}
csg_geo->FindIdenticSurfaces(1e-6);
csg_geo->CalcTriangleApproximation(0.01,100);
csg_geo->FindIdenticSurfaces(1e-8 * csg_geo->MaxSize());
csg_geo->CalcTriangleApproximation(0.01,20);
auto nto = csg_geo->GetNTopLevelObjects();
size_t np = 0;
size_t ntrig = 0;
@ -683,26 +751,27 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails!
res["max"] = MoveToNumpy(max);
return res;
}, py::call_guard<py::gil_scoped_release>())
;
m.def("GenerateMesh", FunctionPointer
([](shared_ptr<CSGeometry> geo, MeshingParameters & param)
.def("GenerateMesh", [](shared_ptr<CSGeometry> geo,
MeshingParameters* pars, py::kwargs kwargs)
{
auto dummy = make_shared<Mesh>();
SetGlobalMesh (dummy);
dummy->SetGeometry(geo);
MeshingParameters mp;
if(pars) mp = *pars;
{
py::gil_scoped_acquire aq;
CreateMPfromKwargs(mp, kwargs);
}
auto mesh = make_shared<Mesh>();
SetGlobalMesh (mesh);
mesh->SetGeometry(geo);
ng_geometry = geo;
geo->FindIdenticSurfaces(1e-8 * geo->MaxSize());
try
{
geo->GenerateMesh (dummy, param);
}
catch (NgException ex)
{
cout << "Caught NgException: " << ex.What() << endl;
}
return dummy;
}),py::call_guard<py::gil_scoped_release>())
auto result = geo->GenerateMesh (mesh, mp);
if(result != 0)
throw Exception("Meshing failed!");
return mesh;
}, py::arg("mp") = nullptr,
meshingparameter_description.c_str(),
py::call_guard<py::gil_scoped_release>())
;
m.def("Save", FunctionPointer

View File

@ -1,4 +1,5 @@
#include <mystdlib.h>
#include <core/register_archive.hpp>
#include <linalg.hpp>
#include <csg.hpp>
@ -48,17 +49,19 @@ namespace netgen
isfirst(first), islast(last), spline(&spline_in), p0(p), v_axis(vec), id(id_in)
{
deletable = false;
maxh = spline_in.GetMaxh();
bcname = spline_in.GetBCName();
Init();
}
RevolutionFace :: RevolutionFace(const Array<double> & raw_data)
RevolutionFace :: RevolutionFace(const NgArray<double> & raw_data)
{
deletable = true;
int pos = 0;
Array< Point<2> > p(3);
NgArray< Point<2> > p(3);
int stype = int(raw_data[pos]); pos++;
@ -305,6 +308,7 @@ namespace netgen
}
else
{
hesse = 0;
(*testout) << "hesse4: " << hesse <<endl;
}
}
@ -332,7 +336,7 @@ namespace netgen
{
double retval = spline->MaxCurvature();
Array < Point<2> > checkpoints;
NgArray < Point<2> > checkpoints;
const SplineSeg3<2> * ss3 = dynamic_cast<const SplineSeg3<2> *>(spline);
const LineSeg<2> * ls = dynamic_cast<const LineSeg<2> *>(spline);
@ -385,7 +389,7 @@ namespace netgen
// find smallest y value of spline:
Array<double> testt;
NgArray<double> testt;
if(!isfirst)
testt.Append(0);
@ -623,7 +627,7 @@ namespace netgen
void RevolutionFace :: GetRawData(Array<double> & data) const
void RevolutionFace :: GetRawData(NgArray<double> & data) const
{
data.DeleteAll();
spline->GetRawData(data);
@ -639,10 +643,10 @@ namespace netgen
Revolution :: Revolution(const Point<3> & p0_in,
const Point<3> & p1_in,
const SplineGeometry<2> & spline_in) :
p0(p0_in), p1(p1_in)
shared_ptr<SplineGeometry<2>> spline_in) :
p0(p0_in), p1(p1_in), splinegeo(spline_in)
{
auto nsplines = spline_in.GetNSplines();
auto nsplines = spline_in->GetNSplines();
surfaceactive.SetSize(0);
surfaceids.SetSize(0);
@ -650,25 +654,42 @@ namespace netgen
v_axis.Normalize();
if(spline_in.GetSpline(0).StartPI()(1) <= 0. &&
spline_in.GetSpline(nsplines-1).EndPI()(1) <= 0.)
if(spline_in->GetSpline(0).StartPI()(1) <= 0. &&
spline_in->GetSpline(nsplines-1).EndPI()(1) <= 0.)
type = 2;
else if (Dist(spline_in.GetSpline(0).StartPI(),
spline_in.GetSpline(nsplines-1).EndPI()) < 1e-7)
else if (Dist(spline_in->GetSpline(0).StartPI(),
spline_in->GetSpline(nsplines-1).EndPI()) < 1e-7)
type = 1;
else
cerr << "Surface of revolution cannot be constructed" << endl;
for(int i=0; i<spline_in.GetNSplines(); i++)
for(int i=0; i<spline_in->GetNSplines(); i++)
{
RevolutionFace * face = new RevolutionFace(spline_in.GetSpline(i),
p0,v_axis,
type==2 && i==0,
type==2 && i==spline_in.GetNSplines()-1);
faces.Append(face);
surfaceactive.Append(1);
faces.Append(new RevolutionFace
(spline_in->GetSpline(i),
p0,v_axis,
type==2 && i==0,
type==2 && i==spline_in->GetNSplines()-1));
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()
@ -717,7 +738,7 @@ namespace netgen
return DOES_INTERSECT;
else
{
Array < Point<3> > pext(2);
NgArray < Point<3> > pext(2);
Point<3> p;
pext[0] = box.PMin();
@ -763,15 +784,16 @@ 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;
const double b = -randomx;
const double c = -a*p2d(0)-b*p2d(1);
Array < Point<2> > points;
NgArray < Point<2> > points;
//(*testout) << "face intersections at: " << endl;
for(int i=0; i<faces.Size(); i++)
@ -795,14 +817,14 @@ namespace netgen
}
}
if(intersections_before % 2 == 0)
if(intersections_after % 2 == 0)
return IS_OUTSIDE;
else
return IS_INSIDE;
}
void Revolution :: GetTangentialSurfaceIndices (const Point<3> & p,
Array<int> & surfind, double eps) const
NgArray<int> & surfind, double eps) const
{
for (int j = 0; j < faces.Size(); j++)
if (faces[j] -> PointInFace(p, eps))
@ -822,7 +844,7 @@ namespace netgen
return pInSolid;
}
Array<int> intersecting_faces;
NgArray<int> intersecting_faces;
for(int i=0; i<faces.Size(); i++)
if(faces[i]->PointInFace(p,eps)) // == DOES_INTERSECT)
@ -929,6 +951,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
{

View File

@ -23,9 +23,9 @@ namespace netgen
mutable Vector spline_coefficient_shifted;
Array < Vec<2>* > checklines_vec;
Array < Point<2>* > checklines_start;
Array < Vec<2>* > checklines_normal;
NgArray < Vec<2>* > checklines_vec;
NgArray < Point<2>* > checklines_start;
NgArray < Vec<2>* > checklines_normal;
private:
void Init (void);
@ -44,7 +44,7 @@ namespace netgen
bool last = false,
const int id_in = 0);
RevolutionFace(const Array<double> & raw_data);
RevolutionFace(const NgArray<double> & raw_data);
// default constructor for archive
RevolutionFace() {}
@ -67,7 +67,10 @@ namespace netgen
virtual double MaxCurvature () const;
//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;
@ -87,7 +90,7 @@ namespace netgen
/* INSOLID_TYPE */ bool PointInFace (const Point<3> & p, const double eps) const;
void GetRawData(Array<double> & data) const;
void GetRawData(NgArray<double> & data) const;
};
@ -112,13 +115,14 @@ namespace netgen
Array<RevolutionFace*> faces;
shared_ptr<SplineGeometry<2>> splinegeo;
mutable int intersecting_face;
public:
Revolution(const Point<3> & p0_in,
const Point<3> & p1_in,
const SplineGeometry<2> & spline_in);
shared_ptr<SplineGeometry<2>> spline_in);
// default constructor for archive
Revolution() {}
@ -143,7 +147,7 @@ namespace netgen
double eps) const;
virtual void GetTangentialSurfaceIndices (const Point<3> & p,
Array<int> & surfind, double eps) const;
NgArray<int> & surfind, double eps) const;
virtual INSOLID_TYPE VecInSolid (const Point<3> & p,
const Vec<3> & v,
@ -155,7 +159,10 @@ 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);
virtual const Surface & GetSurface (int i = 0) const;

View File

@ -41,7 +41,7 @@ void SingularEdge :: FindPointsOnEdge (class Mesh & mesh)
segms.SetSize(0);
Array<int> si1, si2;
NgArray<int> si1, si2;
sol1->GetSurfaceIndices (si1);
sol2->GetSurfaceIndices (si2);
@ -150,7 +150,7 @@ SingularPoint :: SingularPoint (double abeta,
void SingularPoint :: FindPoints (class Mesh & mesh)
{
points.SetSize(0);
Array<int> surfk, surf;
NgArray<int> surfk, surf;
for (PointIndex pi = PointIndex::BASE;
@ -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

@ -19,7 +19,7 @@ namespace netgen
/**
Singular Face.
Causes a bounday layer mesh refinement.
Causes a boundary layer mesh refinement.
All elements in subdomain domnr will get a boundary layer
on faces sharing the solid sol
*/
@ -29,8 +29,8 @@ namespace netgen
int domnr;
const Solid *sol;
double factor;
// Array<Point<3> > points;
// Array<INDEX_2> segms;
// NgArray<Point<3> > points;
// NgArray<INDEX_2> segms;
public:
SingularFace (int adomnr, const Solid * asol, double sf)
: domnr(adomnr), sol(asol), factor(sf) { ; }
@ -47,8 +47,8 @@ namespace netgen
int domnr;
const CSGeometry& geom;
const Solid *sol1, *sol2;
Array<Point<3> > points;
Array<INDEX_2> segms;
NgArray<Point<3> > points;
NgArray<INDEX_2> segms;
double factor;
double maxhinit;
@ -68,7 +68,7 @@ namespace netgen
public:
double beta;
const Solid *sol1, *sol2, *sol3;
Array<Point<3> > points;
NgArray<Point<3> > points;
double factor;
public:

View File

@ -6,21 +6,6 @@
namespace netgen
{
//using namespace netgen;
/*
SolidIterator :: SolidIterator ()
{
;
}
SolidIterator :: ~SolidIterator ()
{
;
}
*/
// int Solid :: cntnames = 0;
@ -193,9 +178,73 @@ 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);
}
throw Exception("PointInSolid: invalid op");
}
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);
}
throw Exception("VecInSolid: invalid op");
}
// 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);
}
throw Exception("VecInSolid2: invalid op");
}
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 +262,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 +286,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 +312,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 +340,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 +377,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
@ -557,14 +664,14 @@ namespace netgen
void Solid :: Boundaries (const Point<3> & p, Array<int> & bounds) const
void Solid :: Boundaries (const Point<3> & p, NgArray<int> & bounds) const
{
int in, strin;
bounds.SetSize (0);
RecBoundaries (p, bounds, in, strin);
}
void Solid :: RecBoundaries (const Point<3> & p, Array<int> & bounds,
void Solid :: RecBoundaries (const Point<3> & p, NgArray<int> & bounds,
int & in, int & strin) const
{
switch (op)
@ -585,7 +692,7 @@ namespace netgen
case SECTION:
{
int i, in1, in2, strin1, strin2;
Array<int> bounds1, bounds2;
NgArray<int> bounds1, bounds2;
s1 -> RecBoundaries (p, bounds1, in1, strin1);
s2 -> RecBoundaries (p, bounds2, in2, strin2);
@ -604,7 +711,7 @@ namespace netgen
case UNION:
{
int i, in1, in2, strin1, strin2;
Array<int> bounds1, bounds2;
NgArray<int> bounds1, bounds2;
s1 -> RecBoundaries (p, bounds1, in1, strin1);
s2 -> RecBoundaries (p, bounds2, in2, strin2);
@ -638,18 +745,20 @@ namespace netgen
}
void Solid :: TangentialSolid (const Point<3> & p, Solid *& tansol, Array<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, Array<int> & surfids,
int & in, int & strin, double eps) const
void Solid :: RecTangentialSolid (const Point<3> & p, Solid *& tansol, NgArray<int> & surfids,
bool & in, bool & strin, double eps) const
{
tansol = NULL;
@ -671,7 +780,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 +795,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 +821,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 +849,24 @@ namespace netgen
void Solid :: TangentialSolid2 (const Point<3> & p,
const Vec<3> & t,
Solid *& tansol, Array<int> & surfids, double eps) const
unique_ptr<Solid> Solid :: TangentialSolid2 (const Point<3> & p,
const Vec<3> & t,
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, Array<int> & surfids,
int & in, int & strin, double eps) const
Solid *& tansol, NgArray<int> & surfids,
bool & in, bool & strin, double eps) const
{
tansol = NULL;
tansol = nullptr;
switch (op)
{
@ -774,8 +885,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 +897,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 +912,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 +933,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 +965,28 @@ namespace netgen
void Solid :: TangentialSolid3 (const Point<3> & p,
const Vec<3> & t, const Vec<3> & t2,
Solid *& tansol, Array<int> & surfids,
double eps) const
unique_ptr<Solid> Solid :: TangentialSolid3 (const Point<3> & p,
const Vec<3> & t, const Vec<3> & t2,
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, Array<int> & surfids,
int & in, int & strin, double eps) const
Solid *& tansol, NgArray<int> & surfids,
bool & in, bool & strin, double eps) const
{
tansol = NULL;
tansol = nullptr;
switch (op)
{
@ -882,8 +996,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 +1008,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 +1023,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 +1044,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 +1079,13 @@ namespace netgen
void Solid :: TangentialEdgeSolid (const Point<3> & p,
const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m,
Solid *& tansol, Array<int> & surfids,
double eps) const
unique_ptr<Solid> Solid :: TangentialEdgeSolid (const Point<3> & p,
const Vec<3> & t, const Vec<3> & t2, const Vec<3> & m,
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 +1093,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, Array<int> & surfids,
int & in, int & strin, double eps) const
Solid *& tansol, NgArray<int> & surfids,
bool & in, bool & strin, double eps) const
{
tansol = NULL;
@ -1005,8 +1122,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 +1134,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 +1149,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 +1170,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 +1212,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 +1262,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 +1277,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 +1292,7 @@ namespace netgen
}
case SUB:
{
int in1, strin1;
bool in1, strin1;
s1 -> RecEdge (p, v, in1, strin1, faces, eps);
in = !strin1;
strin = !in1;
@ -1450,13 +1571,13 @@ namespace netgen
return 0;
}
void Solid :: GetSurfaceIndices (Array<int> & surfind) const
void Solid :: GetSurfaceIndices (NgArray<int> & surfind) const
{
surfind.SetSize (0);
RecGetSurfaceIndices (surfind);
}
void Solid :: RecGetSurfaceIndices (Array<int> & surfind) const
void Solid :: RecGetSurfaceIndices (NgArray<int> & surfind) const
{
switch (op)
{
@ -1533,13 +1654,13 @@ namespace netgen
}
void Solid :: GetTangentialSurfaceIndices (const Point<3> & p, Array<int> & surfind, double eps) const
void Solid :: GetTangentialSurfaceIndices (const Point<3> & p, NgArray<int> & surfind, double eps) const
{
surfind.SetSize (0);
RecGetTangentialSurfaceIndices (p, surfind, eps);
}
void Solid :: RecGetTangentialSurfaceIndices (const Point<3> & p, Array<int> & surfind, double eps) const
void Solid :: RecGetTangentialSurfaceIndices (const Point<3> & p, NgArray<int> & surfind, double eps) const
{
switch (op)
{
@ -1576,14 +1697,14 @@ namespace netgen
void Solid :: GetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v,
Array<int> & surfind, double eps) const
NgArray<int> & surfind, double eps) const
{
surfind.SetSize (0);
RecGetTangentialSurfaceIndices2 (p, v, surfind, eps);
}
void Solid :: RecGetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v,
Array<int> & surfind, double eps) const
NgArray<int> & surfind, double eps) const
{
switch (op)
{
@ -1628,14 +1749,14 @@ namespace netgen
void Solid :: GetTangentialSurfaceIndices3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2,
Array<int> & surfind, double eps) const
NgArray<int> & surfind, double eps) const
{
surfind.SetSize (0);
RecGetTangentialSurfaceIndices3 (p, v, v2, surfind, eps);
}
void Solid :: RecGetTangentialSurfaceIndices3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2,
Array<int> & surfind, double eps) const
NgArray<int> & surfind, double eps) const
{
switch (op)
{
@ -1697,7 +1818,7 @@ namespace netgen
void Solid :: RecGetTangentialEdgeSurfaceIndices (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, const Vec<3> & m,
Array<int> & surfind, double eps) const
NgArray<int> & surfind, double eps) const
{
switch (op)
{
@ -1801,7 +1922,7 @@ namespace netgen
}
void Solid :: CalcOnePrimitiveSpecialPoints (const Box<3> & box, Array<Point<3> > & pts) const
void Solid :: CalcOnePrimitiveSpecialPoints (const Box<3> & box, NgArray<Point<3> > & pts) const
{
double eps = 1e-8 * box.Diam ();
@ -1814,7 +1935,7 @@ namespace netgen
}
}
void Solid :: RecCalcOnePrimitiveSpecialPoints (Array<Point<3> > & pts) const
void Solid :: RecCalcOnePrimitiveSpecialPoints (NgArray<Point<3> > & pts) const
{
switch (op)
{
@ -1842,5 +1963,6 @@ namespace netgen
BlockAllocator Solid :: ball(sizeof (Solid));
// BlockAllocator Solid :: ball(sizeof (Solid));
shared_ptr<BlockAllocator> Solid :: ball = make_shared<BlockAllocator>(sizeof (Solid));
}

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
{
@ -81,14 +101,14 @@ namespace netgen
void IterateSolid (SolidIterator & it, bool only_once = 0);
void Boundaries (const Point<3> & p, Array<int> & bounds) const;
void Boundaries (const Point<3> & p, NgArray<int> & bounds) const;
int NumPrimitives () const;
void GetSurfaceIndices (Array<int> & surfind) const;
void GetSurfaceIndices (NgArray<int> & surfind) const;
void GetSurfaceIndices (IndexSet & iset) const;
void GetTangentialSurfaceIndices (const Point<3> & p, Array<int> & surfids, double eps) const;
void GetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v, Array<int> & surfids, double eps) const;
void GetTangentialSurfaceIndices3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, Array<int> & surfids, double eps) const;
void GetTangentialSurfaceIndices (const Point<3> & p, NgArray<int> & surfids, double eps) const;
void GetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v, NgArray<int> & surfids, double eps) const;
void GetTangentialSurfaceIndices3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, NgArray<int> & surfids, double eps) const;
void ForEachSurface (const std::function<void(Surface*,bool)> & lambda, bool inv = false) const;
@ -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, Array<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, Array<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, Array<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,12 +164,12 @@ 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,
const Vec<3> & m,
Solid *& tansol, Array<int> & surfids, double eps) const;
unique_ptr<Solid> TangentialEdgeSolid (const Point<3> & p, const Vec<3> & t, const Vec<3> & t2,
const Vec<3> & m,
NgArray<int> & surfids, double eps) const;
void CalcOnePrimitiveSpecialPoints (const Box<3> & box, Array<Point<3> > & pts) const;
void CalcOnePrimitiveSpecialPoints (const Box<3> & box, NgArray<Point<3> > & pts) const;
///
int Edge (const Point<3> & p, const Vec<3> & v, double eps) const;
@ -161,58 +192,58 @@ namespace netgen
static Solid * CreateSolid (istream & ist, const SymbolTable<Solid*> & solids);
static BlockAllocator ball;
static shared_ptr<BlockAllocator> ball;
void * operator new(size_t /* s */)
{
return ball.Alloc();
return ball->Alloc();
}
void operator delete (void * p)
{
ball.Free (p);
ball->Free (p);
}
protected:
///
void RecBoundaries (const Point<3> & p, Array<int> & bounds,
void RecBoundaries (const Point<3> & p, NgArray<int> & bounds,
int & in, int & strin) const;
///
void RecTangentialSolid (const Point<3> & p, Solid *& tansol, Array<int> & surfids,
int & in, int & strin, double eps) const;
void RecTangentialSolid (const Point<3> & p, Solid *& tansol, NgArray<int> & surfids,
bool & in, bool & strin, double eps) const;
void RecTangentialSolid2 (const Point<3> & p, const Vec<3> & vec,
Solid *& tansol, Array<int> & surfids,
int & in, int & strin, double eps) const;
Solid *& tansol, NgArray<int> & surfids,
bool & in, bool & strin, double eps) const;
///
void RecTangentialSolid3 (const Point<3> & p, const Vec<3> & vec,const Vec<3> & vec2,
Solid *& tansol, Array<int> & surfids,
int & in, int & strin, double eps) const;
Solid *& tansol, NgArray<int> & surfids,
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, Array<int> & surfids,
int & in, int & strin, double eps) const;
Solid *& tansol, NgArray<int> & surfids,
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);
///
Solid * RecGetReducedSolid (const BoxSphere<3> & box, INSOLID_TYPE & in) const;
///
void RecGetSurfaceIndices (Array<int> & surfind) const;
void RecGetTangentialSurfaceIndices (const Point<3> & p, Array<int> & surfids, double eps) const;
void RecGetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v, Array<int> & surfids, double eps) const;
void RecGetSurfaceIndices (NgArray<int> & surfind) const;
void RecGetTangentialSurfaceIndices (const Point<3> & p, NgArray<int> & surfids, double eps) const;
void RecGetTangentialSurfaceIndices2 (const Point<3> & p, const Vec<3> & v, NgArray<int> & surfids, double eps) const;
void RecGetTangentialSurfaceIndices3 (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2,
Array<int> & surfids, double eps) const;
NgArray<int> & surfids, double eps) const;
void RecGetTangentialEdgeSurfaceIndices (const Point<3> & p, const Vec<3> & v, const Vec<3> & v2, const Vec<3> & m,
Array<int> & surfids, double eps) const;
NgArray<int> & surfids, double eps) const;
void RecGetSurfaceIndices (IndexSet & iset) const;
void RecCalcOnePrimitiveSpecialPoints (Array<Point<3> > & pts) const;
void RecCalcOnePrimitiveSpecialPoints (NgArray<Point<3> > & pts) const;
friend class SolidIterator;
friend class ClearVisitedIt;
@ -234,7 +265,7 @@ namespace netgen
class ReducePrimitiveIterator : public SolidIterator
{
const BoxSphere<3> & box;
BoxSphere<3> box;
public:
ReducePrimitiveIterator (const BoxSphere<3> & abox)
: SolidIterator(), box(abox) { ; }

View File

@ -21,7 +21,7 @@
namespace netgen
{
Array<Box<3> > boxes;
DLL_HEADER NgArray<Box<3> > boxes; // for visualization
void ProjectToEdge (const Surface * f1, const Surface * f2, Point<3> & hp);
@ -64,7 +64,7 @@ namespace netgen
}
static Array<int> numprim_hist;
// static NgArray<int> numprim_hist;
SpecialPointCalculation :: SpecialPointCalculation ()
{
@ -73,10 +73,10 @@ namespace netgen
void SpecialPointCalculation ::
CalcSpecialPoints (const CSGeometry & ageometry,
Array<MeshPoint> & apoints)
NgArray<MeshPoint> & apoints)
{
static int timer = NgProfiler::CreateTimer ("CSG: find special points");
NgProfiler::RegionTimer reg (timer);
// static int timer = NgProfiler::CreateTimer ("CSG: find special points");
// NgProfiler::RegionTimer reg (timer);
geometry = &ageometry;
@ -100,8 +100,8 @@ namespace netgen
box.CalcDiamCenter();
PrintMessage (3, "main-solids: ", geometry->GetNTopLevelObjects());
numprim_hist.SetSize (geometry->GetNSurf()+1);
numprim_hist = 0;
// numprim_hist.SetSize (geometry->GetNSurf()+1);
// numprim_hist = 0;
for (int i = 0; i < geometry->GetNTopLevelObjects(); i++)
{
@ -112,7 +112,7 @@ namespace netgen
if (tlo->GetSolid())
{
Array<Point<3> > hpts;
NgArray<Point<3> > hpts;
tlo->GetSolid()->CalcOnePrimitiveSpecialPoints (box, hpts);
// if (hpts.Size())
// cout << "oneprimitivespecialpoints = " << hpts << endl;
@ -161,10 +161,12 @@ namespace netgen
PrintMessage (3, "Found points ", apoints.Size());
/*
for (int i = 0; i < boxesinlevel.Size(); i++)
(*testout) << "level " << i << " has "
<< boxesinlevel[i] << " boxes" << endl;
(*testout) << "numprim_histogramm = " << endl << numprim_hist << endl;
*/
}
@ -184,8 +186,8 @@ namespace netgen
if (multithread.terminate)
{
*testout << "boxes = " << boxes << endl;
*testout << "boxesinlevel = " << boxesinlevel << endl;
// *testout << "boxes = " << boxes << endl;
// *testout << "boxesinlevel = " << boxesinlevel << endl;
throw NgException ("Meshing stopped");
}
@ -210,17 +212,18 @@ namespace netgen
bool possiblecrossp, possibleexp; // possible cross or extremalpoint
bool surecrossp = 0, sureexp = 0; // sure ...
// static Array<int> locsurf; // attention: array is static
ArrayMem<int,100> locsurf;
// static NgArray<int> locsurf; // attention: array is static
NgArrayMem<int,100> locsurf;
// static int cntbox = 0;
// cntbox++;
/*
if (level <= boxesinlevel.Size())
boxesinlevel.Elem(level)++;
else
boxesinlevel.Append (1);
*/
/*
numprim = sol -> NumPrimitives();
sol -> GetSurfaceIndices (locsurf);
@ -233,7 +236,7 @@ namespace netgen
(*testout) << "numprim = " << numprim << endl;
#endif
numprim_hist[numprim]++;
// numprim_hist[numprim]++;
Point<3> p = box.Center();
@ -273,8 +276,8 @@ namespace netgen
if (nquad == numprim && nplane >= numprim-1)
{
Array<Point<3> > pts;
Array<int> surfids;
NgArray<Point<3> > pts;
NgArray<int> surfids;
for (int k1 = 0; k1 < numprim - 2; k1++)
for (int k2 = k1 + 1; k2 < numprim - 1; k2++)
@ -286,36 +289,30 @@ 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)
{
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++)
{
int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
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;
}
delete tansol;
}
auto tansol = sol -> TangentialSolid (pnt, surfids, 1e-9*size);
if (tansol)
{
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 (auto surfid : surfids)
{
int actrep = geometry->GetSurfaceClassRepresentant(surfid);
if (actrep == rep1) ok1 = true;
if (actrep == rep2) ok2 = true;
if (actrep == rep3) ok3 = true;
}
if (ok1 && ok2 && ok3)
if (AddPoint (pnt, layer))
(*testout) << "cross point found, 1: " << pnt << endl;
}
}
}
@ -330,39 +327,30 @@ 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)
{
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++)
{
int actrep = geometry->GetSurfaceClassRepresentant(surfids[jj]);
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, 2: " << pts[j] << endl;
}
delete tansol;
auto tansol = sol -> TangentialSolid (pnt, surfids, 1e-9*size);
if (tansol)
{
bool ok1 = false, ok2 = false, ok3 = true;//false;
int rep1 = geometry->GetSurfaceClassRepresentant(locsurf[k1]);
int rep2 = geometry->GetSurfaceClassRepresentant(locsurf[k2]);
for (auto surfid : surfids)
{
int actrep = geometry->GetSurfaceClassRepresentant(surfid);
if (actrep == rep1) ok1 = true;
if (actrep == rep2) ok2 = true;
}
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,15 +360,10 @@ 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;
if (AddPoint (pts[j], layer))
(*testout) << "extremal point found, 1: " << pts[j] << endl;
}
}
}
@ -392,11 +375,9 @@ namespace netgen
if (nsphere == numprim) // && calccp == false)
{
Array<Point<3> > pts;
Array<int> surfids;
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 +390,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,14 +406,9 @@ 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 (AddPoint (pts[j], layer))
(*testout) << "cross point found, 1: " << pts[j] << endl;
}
delete tansol;
if (ok1 && ok2 && ok3)
if (AddPoint (pts[j], layer))
(*testout) << "cross point found, 1: " << pts[j] << endl;
}
}
@ -449,23 +423,37 @@ 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;
if (AddPoint (pts[j], layer))
(*testout) << "extremal point found, spheres: " << pts[j] << endl;
}
}
return;
}
}
if (numprim == 2)
{
auto rev0 = dynamic_cast<const RevolutionFace*> (geometry->GetSurface(locsurf[0]));
auto rev1 = dynamic_cast<const RevolutionFace*> (geometry->GetSurface(locsurf[1]));
if (rev0 && rev1)
{
NgArray<Point<3>> pts;
bool check = ComputeExtremalPoints (rev0, rev1, pts);
if (check)
{
for (auto p : pts)
if (box.IsIn(p))
AddPoint (p, layer);
return;
}
}
}
} // end if (numprim <= check_crosspoint)
possiblecrossp = (numprim >= 3) && calccp;
surecrossp = 0;
@ -494,7 +482,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;
}
@ -541,7 +528,7 @@ namespace netgen
BoxSphere<3> boxp (pp, pp);
boxp.Increase (1e-3*size);
boxp.CalcDiamCenter();
Array<int> locsurf2;
NgArray<int> locsurf2;
geometry -> GetIndependentSurfaceIndices (sol, boxp, locsurf2);
@ -608,9 +595,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,9 +877,18 @@ namespace netgen
f1->CalcGradient (p, g1);
f2->CalcGradient (p, g2);
if ( sqr (g1 * g2) > (1 - 1e-10) * Abs2 (g1) * Abs2 (g2))
return 1;
// 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++)
{
mat(0,j) = g1(j);
@ -1132,7 +1128,7 @@ namespace netgen
ComputeCrossPoints (const Plane * plane1,
const Plane * plane2,
const Plane * plane3,
Array<Point<3> > & pts)
NgArray<Point<3> > & pts)
{
Mat<3> mat;
Vec<3> rhs, sol;
@ -1174,7 +1170,7 @@ namespace netgen
ComputeCrossPoints (const Plane * plane1,
const Plane * plane2,
const QuadraticSurface * quadric,
Array<Point<3> > & pts)
NgArray<Point<3> > & pts)
{
Mat<2,3> mat;
Mat<3,2> inv;
@ -1244,7 +1240,7 @@ namespace netgen
ComputeCrossPoints (const Sphere * sphere1,
const Sphere * sphere2,
const Sphere * sphere3,
Array<Point<3> > & pts)
NgArray<Point<3> > & pts)
{
Mat<2,3> mat;
Mat<3,2> inv;
@ -1327,7 +1323,7 @@ namespace netgen
void SpecialPointCalculation ::
ComputeExtremalPoints (const Plane * plane,
const QuadraticSurface * quadric,
Array<Point<3> > & pts)
NgArray<Point<3> > & pts)
{
// 3 equations:
// surf1 = 0 <===> plane_a + plane_b x = 0;
@ -1416,7 +1412,7 @@ namespace netgen
void SpecialPointCalculation ::
ComputeExtremalPoints (const Sphere * sphere1,
const Sphere * sphere2,
Array<Point<3> > & pts)
NgArray<Point<3> > & pts)
{
// 3 equations:
// surf1 = 0 <===> |x-c1|^2 - r1^2 = 0;
@ -1534,7 +1530,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;
}
@ -1666,19 +1716,19 @@ namespace netgen
void SpecialPointCalculation ::
AnalyzeSpecialPoints (const CSGeometry & ageometry,
Array<MeshPoint> & apoints,
Array<SpecialPoint> & specpoints)
NgArray<MeshPoint> & apoints,
NgArray<SpecialPoint> & specpoints)
{
static int timer = NgProfiler::CreateTimer ("CSG: analyze special points");
NgProfiler::RegionTimer reg (timer);
Array<int> surfind, rep_surfind, surfind2, rep_surfind2, surfind3;
NgArray<int> surfind, rep_surfind, surfind2, rep_surfind2, surfind3;
Array<Vec<3> > normalvecs;
NgArray<Vec<3> > normalvecs;
Vec<3> nsurf = 0.0;
Array<int> specpoint2point;
NgArray<int> specpoint2point;
specpoints.SetSize (0);
geometry = &ageometry;
@ -1698,7 +1748,7 @@ namespace netgen
*/
Vec<3> dir(1.2, 1.7, 0.9);
Array<double> coord(apoints.Size());
NgArray<double> coord(apoints.Size());
for (int i = 0; i < apoints.Size(); i++)
coord[i] = dir * Vec<3> (apoints[i]);
@ -1717,7 +1767,7 @@ namespace netgen
(*testout) << "points = " << apoints << endl;
Point3dTree searchtree (bbox.PMin(), bbox.PMax());
Array<int> locsearch;
NgArray<int> locsearch;
for (int si = 0; si < ageometry.GetNTopLevelObjects(); si++)
{
@ -1739,9 +1789,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 +1817,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 +1866,11 @@ namespace netgen
}
if (Abs2 (t) < 1e-8)
continue;
if (Abs2 (t) < 1e-16)
{
// cerr << "normal vectors degenerated" << endl;
continue;
}
#ifdef DEVELOP
*testout << " tangential vector " << t << endl;
@ -1860,17 +1911,17 @@ namespace netgen
rhs(0) = -t * (hessej * t);
rhs(1) = -t * (hessek * t);
CalcInverse (mat, inv);
t2 = inv * rhs;
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);
@ -1882,7 +1933,7 @@ namespace netgen
#ifdef DEVELOP
(*testout) << "surfind2 = " << endl << surfind2 << endl;
#endif
Array<int> surfind2_aux(surfind2);
NgArray<int> surfind2_aux(surfind2);
ageometry.GetIndependentSurfaceIndices (surfind2_aux);
#ifdef DEVELOP
(*testout) << "surfind2,rep = " << endl << surfind2_aux << endl;
@ -1911,31 +1962,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 +1999,6 @@ namespace netgen
if (cnt_tang_faces < 1)
ok = false;
delete locsol2;
if (!ok) continue;
}
@ -1973,16 +2023,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) &&
@ -1992,10 +2073,8 @@ namespace netgen
!locsol->VectorStrictIn (p, t2b));
*/
if (isface)
{
cnts++;
}
if (isface)
cnts++;
}
if (cnts < 2) isedge = 0;
}
@ -2014,7 +2093,7 @@ namespace netgen
for (int m = 0; m < locsearch.Size(); m++)
{
if (Dist2 (specpoints[locsearch[m]].p, apoints[i]) < 1e-10*geomsize
if (Dist2 (specpoints[locsearch[m]].p, apoints[i]) < sqr(1e-8*geomsize)
&& Abs2(specpoints[locsearch[m]].v - t) < 1e-8)
{
spi = locsearch[m];
@ -2054,42 +2133,11 @@ namespace netgen
}
}
delete locsol;
}
}
/*
BitArray testuncond (specpoints.Size());
testuncond.Clear();
for(int i = 0; i<specpoints.Size(); i++)
{
if(testuncond.Test(i))
continue;
Array<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:
@ -2098,10 +2146,9 @@ namespace netgen
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

@ -79,14 +79,14 @@ namespace netgen
///
const CSGeometry * geometry;
///
Array<MeshPoint> * points;
NgArray<MeshPoint> * points;
///
Array<long int> boxesinlevel;
NgArray<long int> boxesinlevel;
///
double size;
///
double relydegtest; // maximal dimension of bisection intervall for
double relydegtest; // maximal dimension of bisection interval for
/// test of degeneration parameters
double cpeps1, epeps1, epeps2, epspointdist2;
@ -102,11 +102,11 @@ namespace netgen
///
void CalcSpecialPoints (const CSGeometry & ageometry,
Array<MeshPoint> & points);
NgArray<MeshPoint> & points);
///
void AnalyzeSpecialPoints (const CSGeometry & geometry,
Array<MeshPoint> & points,
Array<SpecialPoint> & specpoints);
NgArray<MeshPoint> & points,
NgArray<SpecialPoint> & specpoints);
protected:
///
@ -161,27 +161,30 @@ namespace netgen
void ComputeExtremalPoints (const Plane * plane,
const QuadraticSurface * quadric,
Array<Point<3> > & pts);
NgArray<Point<3> > & pts);
void ComputeExtremalPoints (const Sphere * sphere1,
const Sphere * sphere2,
Array<Point<3> > & pts);
NgArray<Point<3> > & pts);
bool ComputeExtremalPoints (const RevolutionFace * rev1,
const RevolutionFace * rev2,
NgArray<Point<3> > & pts);
void ComputeCrossPoints (const Plane * plane1,
const Plane * plane2,
const Plane * plane3,
Array<Point<3> > & pts);
NgArray<Point<3> > & pts);
void ComputeCrossPoints (const Plane * plane1,
const Plane * plane2,
const QuadraticSurface * quadratic,
Array<Point<3> > & pts);
NgArray<Point<3> > & pts);
void ComputeCrossPoints (const Sphere * sphere1,
const Sphere * sphere2,
const Sphere * sphere3,
Array<Point<3> > & pts);
NgArray<Point<3> > & pts);
};
}

View File

@ -27,7 +27,7 @@ namespace netgen
class spline3d
{
///
Array<splinesegment3d *> segments;
NgArray<splinesegment3d *> segments;
public:
///

View File

@ -1,5 +1,6 @@
#include <csg.hpp>
#include <core/register_archive.hpp>
namespace netgen
{
@ -36,11 +37,11 @@ void SplineSurface :: AppendPoint(const Point<3> & p, const double reffac, const
return "default";
}
const shared_ptr<Array<shared_ptr<OneSurfacePrimitive>>> SplineSurface :: CreateCuttingSurfaces()
const shared_ptr<NgArray<shared_ptr<OneSurfacePrimitive>>> SplineSurface :: CreateCuttingSurfaces()
{
if(all_cuts)
return all_cuts;
auto cuttings = make_shared<Array<shared_ptr<OneSurfacePrimitive>>>();
auto cuttings = make_shared<NgArray<shared_ptr<OneSurfacePrimitive>>>();
for (auto cut : *cuts)
cuttings->Append(cut);
for(int i = 0; i<splines.Size(); i++)

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