mirror of
https://github.com/NGSolve/netgen.git
synced 2025-05-07 19:20:48 +05:00
Merge branch 'master' into feature/extend_nglib_api
This commit is contained in:
commit
a931afa7d0
174
.gitlab-ci.yml
174
.gitlab-ci.yml
@ -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
|
||||
|
345
CMakeLists.txt
345
CMakeLists.txt
@ -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
18
CONTRIBUTING.md
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
# How to Contribute
|
||||
|
||||
## Reporting issues
|
||||
|
||||
If you have a problem using Netgen/NGSolve consider asking a question in our [forum](https://ngsolve.org/forum).
|
||||
|
||||
If you found a bug create an issue in the [Github Issue Tracker](https://github.com/NGSolve/netgen/issues). Please be as specific as possible, issues with a reproducible minimal failing example will get more attention than unspecific one liners :)
|
||||
|
||||
## Contributing patches
|
||||
|
||||
We love and want to encourage community engagement and will review and accept patches and contributions to this project. There are just a few steps to follow:
|
||||
|
||||
On your first contribution, to clear any legal questions, we ask you to sign our [Contributor License Agreement](CLA.pdf). Generally you have to sign this only once for Netgen or NGSolve. Please send the signed agreement to <joachim.schoeberl@tuwien.ac.at>.
|
||||
|
||||
Place a pull request on GitHub. From there we will pull it into our internal testing environment and, if approved, merge it into the main codebase.
|
||||
|
||||
If you have any questions feel free to ask on the [forum](https://ngsolve.org/forum).
|
@ -1,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
|
||||
|
@ -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@")
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 ""
|
||||
|
30
cmake/external_projects/cgns.cmake
Normal file
30
cmake/external_projects/cgns.cmake
Normal file
@ -0,0 +1,30 @@
|
||||
if(WIN32)
|
||||
|
||||
ExternalProject_Add(project_win_cgns
|
||||
URL ${CGNS_DOWNLOAD_URL_WIN}
|
||||
UPDATE_COMMAND "" # Disable update
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX}
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
list(APPEND NETGEN_DEPENDENCIES project_win_cgns)
|
||||
endif(WIN32)
|
||||
|
||||
if(APPLE)
|
||||
ExternalProject_Add(project_mac_cgns
|
||||
URL ${CGNS_DOWNLOAD_URL_MAC}
|
||||
UPDATE_COMMAND "" # Disable update
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX}
|
||||
LOG_DOWNLOAD 1
|
||||
)
|
||||
|
||||
list(APPEND NETGEN_DEPENDENCIES project_mac_cgns)
|
||||
list(APPEND NETGEN_CMAKE_ARGS "-DCGNS_INCLUDE_DIR=${CMAKE_INSTALL_PREFIX}/Contents/Resources/include")
|
||||
list(APPEND NETGEN_CMAKE_ARGS "-DCGNS_LIBRARY=${CMAKE_INSTALL_PREFIX}/Contents/MacOS/libcgns.dylib")
|
||||
endif(APPLE)
|
@ -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
|
||||
)
|
||||
|
@ -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)
|
||||
|
@ -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} )
|
||||
|
111
cmake/generate_version_file.cmake
Normal file
111
cmake/generate_version_file.cmake
Normal 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
282
doc/element_types.tex
Normal 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}
|
14
doc/ng4.tex
14
doc/ng4.tex
@ -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
|
@ -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)
|
||||
|
@ -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: '*'
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
1693
libsrc/core/array.hpp
Normal file
File diff suppressed because it is too large
Load Diff
184
libsrc/core/bitarray.cpp
Normal file
184
libsrc/core/bitarray.cpp
Normal 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
210
libsrc/core/bitarray.hpp
Normal 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
|
3619
libsrc/core/concurrentqueue.h
Normal file
3619
libsrc/core/concurrentqueue.h
Normal file
File diff suppressed because it is too large
Load Diff
239
libsrc/core/exception.cpp
Normal file
239
libsrc/core/exception.cpp
Normal 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__
|
@ -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
642
libsrc/core/flags.cpp
Normal 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
199
libsrc/core/flags.hpp
Normal 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
1106
libsrc/core/hashtable.hpp
Normal file
File diff suppressed because it is too large
Load Diff
72
libsrc/core/localheap.cpp
Normal file
72
libsrc/core/localheap.cpp
Normal 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
318
libsrc/core/localheap.hpp
Normal 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
|
@ -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*/)
|
||||
{}
|
||||
|
@ -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
173
libsrc/core/memtracer.hpp
Normal 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
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
115
libsrc/core/ngstream.hpp
Normal 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
|
@ -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 + " → " + 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 = ¤t->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 =
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
436
libsrc/core/python_ngcore.hpp
Normal file
436
libsrc/core/python_ngcore.hpp
Normal 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
|
290
libsrc/core/python_ngcore_export.cpp
Normal file
290
libsrc/core/python_ngcore_export.cpp
Normal 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
109
libsrc/core/ranges.hpp
Normal file
@ -0,0 +1,109 @@
|
||||
#ifndef NETGEN_CORE_RANGES_HPP
|
||||
#define NETGEN_CORE_RANGES_HPP
|
||||
|
||||
#include <iterator>
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
template<typename Iterator>
|
||||
class AdapterRange
|
||||
{
|
||||
Iterator _begin,_end;
|
||||
public:
|
||||
AdapterRange(Iterator abegin, Iterator aend) : _begin(abegin), _end(aend) { ; }
|
||||
Iterator begin() const { return _begin; }
|
||||
Iterator end() const { return _end; }
|
||||
};
|
||||
|
||||
template<typename FUNC>
|
||||
class FilterAdapter
|
||||
{
|
||||
FUNC f;
|
||||
public:
|
||||
FilterAdapter(FUNC af) : f(af) { ; }
|
||||
FUNC GetFunction() const { return f; }
|
||||
};
|
||||
|
||||
template<typename FUNC, typename Iterator>
|
||||
class FilterIterator
|
||||
{
|
||||
Iterator iter;
|
||||
Iterator end;
|
||||
FUNC f;
|
||||
public:
|
||||
FilterIterator(FUNC af, Iterator aiter, Iterator aend)
|
||||
: 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
|
39
libsrc/core/register_archive.hpp
Normal file
39
libsrc/core/register_archive.hpp
Normal 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
48
libsrc/core/signal.hpp
Normal 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
92
libsrc/core/simd.hpp
Normal 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
187
libsrc/core/simd_arm64.hpp
Normal 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
326
libsrc/core/simd_avx.hpp
Normal 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
274
libsrc/core/simd_avx512.hpp
Normal 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
|
790
libsrc/core/simd_generic.hpp
Normal file
790
libsrc/core/simd_generic.hpp
Normal 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
279
libsrc/core/simd_sse.hpp
Normal 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
|
@ -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
190
libsrc/core/table.cpp
Normal 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
787
libsrc/core/table.hpp
Normal 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
831
libsrc/core/taskmanager.cpp
Normal 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, ¶m);
|
||||
param.sched_priority = sched_get_priority_max(policy);
|
||||
pthread_setschedparam(pthread_self(), policy, ¶m);
|
||||
#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
1121
libsrc/core/taskmanager.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
29
libsrc/core/version.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#include <map>
|
||||
|
||||
#include <netgen_version.hpp>
|
||||
#include "exception.hpp"
|
||||
#include "version.hpp"
|
||||
|
||||
namespace ngcore
|
||||
{
|
||||
// clang-tidy should ignore this static object
|
||||
static std::map<std::string, VersionInfo> library_versions; // NOLINT
|
||||
|
||||
const VersionInfo& GetLibraryVersion(const std::string& library)
|
||||
{ return library_versions[library]; }
|
||||
|
||||
const std::map<std::string, VersionInfo>& GetLibraryVersions()
|
||||
{ return library_versions; }
|
||||
|
||||
void SetLibraryVersion(const std::string& library, const VersionInfo& version)
|
||||
{
|
||||
if(library_versions.count(library) && (library_versions[library] != version))
|
||||
throw Exception("Failed to set library version for " + library + " to " + version.to_string() + ": version already set to " + library_versions[library].to_string());
|
||||
library_versions[library] = version;
|
||||
}
|
||||
|
||||
static bool dummy = [](){
|
||||
SetLibraryVersion("netgen", NETGEN_VERSION);
|
||||
return true;
|
||||
}();
|
||||
} // namespace ngcore
|
@ -80,6 +80,10 @@ namespace ngcore
|
||||
return mayor_ == other.mayor_ && minor_ == other.minor_ && release == other.release
|
||||
&& 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
47
libsrc/core/xbool.hpp
Normal 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
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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 ();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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); }
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -13,7 +13,7 @@ namespace netgen
|
||||
|
||||
/*
|
||||
|
||||
2D Curve repesentation
|
||||
2D Curve representation
|
||||
|
||||
*/
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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) { ; }
|
||||
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ namespace netgen
|
||||
class spline3d
|
||||
{
|
||||
///
|
||||
Array<splinesegment3d *> segments;
|
||||
NgArray<splinesegment3d *> segments;
|
||||
|
||||
public:
|
||||
///
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user