diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..24978543 --- /dev/null +++ b/.clang-format @@ -0,0 +1,64 @@ +Language: Cpp +BasedOnStyle: LLVM +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: true +AllowShortFunctionsOnASingleLine: InlineOnly +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBraces: Custom +BraceWrapping: + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterStruct: true + AfterUnion: true + BeforeCatch: true + BeforeElse: true + IndentBraces: true +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakInheritanceList: AfterColon +ColumnLimit: 0 +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 2 +ContinuationIndentWidth: 2 +Cpp11BracedListStyle: true +EmptyLineBeforeAccessModifier: Never +IndentCaseLabels: false +IndentPPDirectives: None +IndentWidth: 2 +KeepEmptyLinesAtTheStartOfBlocks: false +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +PointerAlignment: Left +ReflowComments: true +SortIncludes: false +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceBeforeParens: Custom +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterFunctionDefinitionName: true + AfterFunctionDeclarationName: true +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInSquareBrackets: false +Standard: Latest +TabWidth: 2 +UseTab: Never + diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..6eb7a9e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.whl +dist +build +*.vol.gz +*.vol +*.ini +__pycache__ +*.json +*.zip +.cache +*.patch diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a3047e0a..67833b7e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -32,13 +32,23 @@ push_github: - "echo off" - 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 CCACHE_BASEDIR=C:\ci\%CI_PIPELINE_ID% - set NETGEN_BUILD_DIR=%CI_DIR%\build - set INSTALL_DIR=%CI_DIR%\install - set SRC_DIR=%CI_DIR%\src - set NETGENDIR=%INSTALL_DIR%\bin - set PYTHONPATH=%INSTALL_DIR%\lib\site-packages - - set PATH=%NETGENDIR%;%PATH% + - echo %PATH% + - set PATH=%INSTALL_DIR%\bin;C:\python312;C:\python312\bin;C:\python312\Scripts;C:\tools\;%PATH% + - echo %PATH% + - set CCACHE_HARDLINK=1 + - set CCACHE_NOHASHDIR=1 + - C:\tools\ccache -s + - C:\tools\ccache -M 20G + - dir C:\python312 + - python.exe --version + - python.exe -m pip install -U netgen-occt netgen-occt-devel + - cmake --version build_win: <<: *win @@ -54,12 +64,14 @@ build_win: - >- cmake %SRC_DIR% -G Ninja + -DCMAKE_PREFIX=C:/python312 + -DPython3_ROOT_DIR=C:/python312 -DCMAKE_INSTALL_PREFIX=%INSTALL_DIR% -DCHECK_RANGE=ON -DUSE_CGNS=ON -DUSE_OCC=ON -DUSE_CCACHE=ON - -DENABLE_UNIT_TESTS=ON + -DENABLE_UNIT_TESTS=OFF -DCMAKE_BUILD_TYPE=Release - cmake --build . --target install --config Release @@ -74,6 +86,21 @@ test_win: - cd .. needs: ["build_win"] +generate_results: + <<: *win + stage: test + script: + - pip install pytest-check + - cd tests\pytest + - python test_tutorials.py new_results.json + needs: ["build_win"] + when: manual + artifacts: + paths: + - tests/pytest/new_results.json + when: always + expire_in: 1 week + cleanup_win: <<: *win stage: cleanup @@ -99,6 +126,7 @@ cleanup_win: - pwd - ls - docker info + - export PYTHONPATH=/opt/netgen/`python3 -c "import os.path, sysconfig;print(os.path.relpath(sysconfig.get_path('platlib'), sysconfig.get_path('data')))"` variables: UBUNTU_VERSION: "22.04" @@ -112,6 +140,7 @@ build_ubuntu_debug: docker run --cidfile netgen_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id -e CCACHE_DIR=/ccache + -e PYTHONPATH=$PYTHONPATH -v /mnt/ccache:/ccache netgen_${CI_PIPELINE_ID}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_debug.sh @@ -128,6 +157,7 @@ build_ubuntu_mpi: docker run>- --cidfile netgen_mpi_${CI_PIPELINE_ID}_${UBUNTU_VERSION}.id>- -e CCACHE_DIR=/ccache + -e PYTHONPATH=$PYTHONPATH -e RUN_SLOW_TESTS=${RUN_SLOW_TESTS} -v /mnt/ccache:/ccache netgen_mpi_${CI_PIPELINE_ID}:${UBUNTU_VERSION} @@ -141,8 +171,7 @@ test_ubuntu_debug: script: - >- docker run - -e NETGENDIR=/opt/netgen/bin - -e PYTHONPATH=/opt/netgen/lib/python3/dist-packages + -e PYTHONPATH=$PYTHONPATH 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"] @@ -154,8 +183,7 @@ test_ubuntu_mpi: - >- docker run -e RUN_SLOW_TESTS=${RUN_SLOW_TESTS} - -e NETGENDIR=/opt/netgen/bin - -e PYTHONPATH=/opt/netgen/lib/python3/dist-packages + -e PYTHONPATH=$PYTHONPATH 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"] @@ -168,7 +196,7 @@ test_build_ngsolve: - >- docker run -e NETGENDIR=/opt/netgen/bin - -e PYTHONPATH=/opt/netgen/lib/python3/dist-packages + -e PYTHONPATH=$PYTHONPATH -e MKLROOT=/opt/intel/mkl -v /opt/intel:/opt/intel -e CCACHE_DIR=/ccache @@ -176,22 +204,6 @@ test_build_ngsolve: 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_PIPELINE_ID}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_nospdlog.sh - cleanup_ubuntu: stage: cleanup tags: @@ -222,7 +234,7 @@ cleanup_ubuntu: - export SRC_DIR=$ROOT_DIR/src - export BUILD_DIR=$ROOT_DIR/build - export CMAKE_INSTALL_PREFIX=/tmp/$CI_PIPELINE_ID/install/Netgen.app - - export PYTHONPATH=$CMAKE_INSTALL_PREFIX/Contents/Resources/`python3 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1,0,''))"`:. + - export PYTHONPATH=$CMAKE_INSTALL_PREFIX/Contents/Resources/`python3 -c "import os.path, sysconfig;print(os.path.relpath(sysconfig.get_path('platlib'), sysconfig.get_path('data')))"`:. - export PATH=$CMAKE_INSTALL_PREFIX/Contents/MacOS:$PATH build_mac: @@ -248,6 +260,7 @@ build_mac: -DCMAKE_OSX_SYSROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -DUSE_CGNS=ON -DUSE_OCC=ON + -DPython3_ROOT_DIR=/Library/Frameworks/Python.framework/Versions/3.8/ - make -j5 install test_mac: @@ -268,7 +281,7 @@ cleanup_mac: needs: ["test_mac"] pip_linux: - image: quay.io/pypa/manylinux2014_x86_64 + image: quay.io/pypa/manylinux_2_28_x86_64 stage: build tags: - pip @@ -284,10 +297,11 @@ pip_windows: - 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:\Python313 + - .\tests\build_pip.ps1 C:\Python312 - .\tests\build_pip.ps1 C:\Python311 + - .\tests\build_pip.ps1 C:\Python310 + - .\tests\build_pip.ps1 C:\Python39 when: manual pip_macos: @@ -297,8 +311,9 @@ pip_macos: - 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.13 + - ./tests/build_pip_mac.sh 3.12 - ./tests/build_pip_mac.sh 3.11 + - ./tests/build_pip_mac.sh 3.10 + - ./tests/build_pip_mac.sh 3.9 when: manual diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a18972a..9c54e30e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,8 +2,12 @@ if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING INTERNAL) endif(NOT CMAKE_BUILD_TYPE) -cmake_minimum_required(VERSION 3.13) -cmake_policy(VERSION 3.13) +cmake_minimum_required(VERSION 3.16) +cmake_policy(VERSION 3.16) + +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.24.0") + cmake_policy(SET CMP0135 NEW) +endif() include (CMakeDependentOption) option( USE_NATIVE_ARCH "build for native cpu architecture" ON) @@ -12,8 +16,8 @@ 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_MPI4PY "enable mpi4py interface" ON ) -option( USE_OCC "build with OpenCascade geometry kernel interface" OFF) +option( USE_MPI_WRAPPER "enable mpi wrapper (run-time dispatch of MPI library calls)" OFF ) +option( USE_OCC "build with OpenCascade geometry kernel interface" ON) option( USE_STLGEOM "build with STL geometry support" ON) option( USE_CSG "build with CSG kernel" ON) option( USE_INTERFACE "build nginterface" ON) @@ -28,7 +32,6 @@ option( USE_CCACHE "use ccache") option( USE_INTERNAL_TCL "Compile tcl files into the code and don't install them" ON) option( ENABLE_UNIT_TESTS "Enable Catch unit tests") option( ENABLE_CPP_CORE_GUIDELINES_CHECK "Enable cpp core guideline checks on ngcore" OFF) -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) @@ -71,19 +74,83 @@ endif(UNIX AND USE_SUPERBUILD) if (USE_SUPERBUILD) project (SUPERBUILD) - if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${INSTALL_DIR_DEFAULT}" CACHE PATH "Install directory" FORCE) +else() + project(Netgen) +endif() + +if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${INSTALL_DIR_DEFAULT}" CACHE PATH "Install directory" FORCE) +endif() + +set(NG_INSTALL_SUFFIX netgen CACHE STRING "Suffix appended to install directories (project name)") + +if(USE_PYTHON) + if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.18) + find_package(Python3 REQUIRED COMPONENTS Development.Module) + if(NOT EMSCRIPTEN) + find_package(Python3 COMPONENTS Interpreter Development.Embed) + endif() + else() + find_package(Python3 REQUIRED COMPONENTS Interpreter Development) endif() + if(NOT CMAKE_CROSSCOMPILING) + find_package(Python3 REQUIRED COMPONENTS Interpreter) + execute_process(COMMAND ${Python3_EXECUTABLE} -c "import os.path, sysconfig;print(os.path.relpath(sysconfig.get_path('platlib'), sysconfig.get_path('data')))" OUTPUT_VARIABLE PYTHON_PACKAGES_INSTALL_DIR OUTPUT_STRIP_TRAILING_WHITESPACE) + file(TO_CMAKE_PATH ${PYTHON_PACKAGES_INSTALL_DIR} PYTHON_PACKAGES_INSTALL_DIR) + endif(NOT CMAKE_CROSSCOMPILING) +endif(USE_PYTHON) + +if(APPLE AND NOT EMSCRIPTEN) + set(NG_INSTALL_DIR_BIN_DEFAULT Contents/MacOS) + set(NG_INSTALL_DIR_LIB_DEFAULT Contents/MacOS) + set(NG_INSTALL_DIR_CMAKE_DEFAULT Contents/Resources/CMake) + set(NG_INSTALL_DIR_PYTHON_DEFAULT Contents/Resources/${PYTHON_PACKAGES_INSTALL_DIR}) + set(NG_INSTALL_DIR_RES_DEFAULT Contents/Resources/share) + set(NG_INSTALL_DIR_INCLUDE_DEFAULT Contents/Resources/include) + + set(NG_RPATH_TOKEN "@loader_path") +else(APPLE AND NOT EMSCRIPTEN) + set(NG_INSTALL_DIR_BIN_DEFAULT bin) + set(NG_INSTALL_DIR_LIB_DEFAULT lib) + if(WIN32) + set(NG_INSTALL_DIR_CMAKE_DEFAULT cmake) + else(WIN32) + set(NG_INSTALL_DIR_CMAKE_DEFAULT lib/cmake/${NG_INSTALL_SUFFIX}) + endif(WIN32) + set(NG_INSTALL_DIR_PYTHON_DEFAULT ${PYTHON_PACKAGES_INSTALL_DIR}) + set(NG_INSTALL_DIR_RES_DEFAULT share) + set(NG_INSTALL_DIR_INCLUDE_DEFAULT include) + + set(NG_RPATH_TOKEN "\$ORIGIN") +endif(APPLE AND NOT EMSCRIPTEN) + +set(NG_INSTALL_DIR_PYTHON ${NG_INSTALL_DIR_PYTHON_DEFAULT} CACHE STRING "Install directory for Python files") +set(NG_INSTALL_DIR_BIN ${NG_INSTALL_DIR_BIN_DEFAULT} CACHE STRING "Install directory for executables") +set(NG_INSTALL_DIR_LIB ${NG_INSTALL_DIR_LIB_DEFAULT} CACHE STRING "Install directory for libraries") +set(NG_INSTALL_DIR_INCLUDE ${NG_INSTALL_DIR_INCLUDE_DEFAULT} CACHE STRING "Install directory for header files") +set(NG_INSTALL_DIR_CMAKE ${NG_INSTALL_DIR_CMAKE_DEFAULT} CACHE STRING "Install directory for CMake files") +set(NG_INSTALL_DIR_RES ${NG_INSTALL_DIR_RES_DEFAULT} CACHE STRING "Install directory for resources") + +get_filename_component(NETGEN_CMAKE_DIR_ABSOLUTE ${NG_INSTALL_DIR_CMAKE} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) +get_filename_component(NETGEN_BINARY_DIR_ABSOLUTE ${NG_INSTALL_DIR_BIN} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) +get_filename_component(NETGEN_LIBRARY_DIR_ABSOLUTE ${NG_INSTALL_DIR_LIB} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) +get_filename_component(NETGEN_INCLUDE_DIR_ABSOLUTE ${NG_INSTALL_DIR_INCLUDE} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) +get_filename_component(NETGEN_RESOURCE_DIR_ABSOLUTE ${NG_INSTALL_DIR_RES} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) + +file(RELATIVE_PATH NETGEN_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${CMAKE_INSTALL_PREFIX}) +file(RELATIVE_PATH NETGEN_BINARY_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_BINARY_DIR_ABSOLUTE}) +file(RELATIVE_PATH NETGEN_LIBRARY_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_LIBRARY_DIR_ABSOLUTE}) +file(RELATIVE_PATH NETGEN_INCLUDE_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_INCLUDE_DIR_ABSOLUTE}) +file(RELATIVE_PATH NETGEN_RESOURCE_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_RESOURCE_DIR_ABSOLUTE}) + +file(RELATIVE_PATH NETGEN_RPATH ${NETGEN_BINARY_DIR_ABSOLUTE} ${NETGEN_LIBRARY_DIR_ABSOLUTE}) + +if (USE_SUPERBUILD) # execute the superbuild (this script will be invoked again without the # USE_SUPERBUILD option this time) include (cmake/SuperBuild.cmake) return() # stop processing this file further -else() - project(Netgen) - if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${INSTALL_DIR_DEFAULT}" CACHE PATH "Install directory" FORCE) - endif() endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -97,6 +164,7 @@ if(USE_CCACHE) find_program(CCACHE_FOUND NAMES ccache ccache.bat) if(CCACHE_FOUND) set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ${CCACHE_FOUND}) + message(STATUS "Using ccache ${CCACHE_FOUND}") endif(CCACHE_FOUND) endif(USE_CCACHE) @@ -125,63 +193,6 @@ include_directories ("${PROJECT_BINARY_DIR}") set(CMAKE_INCLUDE_CURRENT_DIR ON) -if(USE_PYTHON) - find_package(PythonInterp 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) -endif(USE_PYTHON) - -set(NG_INSTALL_SUFFIX netgen CACHE STRING "Suffix appended to install directories (project name)") - -if(APPLE) - set(NG_INSTALL_DIR_BIN_DEFAULT Contents/MacOS) - set(NG_INSTALL_DIR_LIB_DEFAULT Contents/MacOS) - set(NG_INSTALL_DIR_CMAKE_DEFAULT Contents/Resources/CMake) - set(NG_INSTALL_DIR_PYTHON_DEFAULT Contents/Resources/${PYTHON_PACKAGES_INSTALL_DIR}) - set(NG_INSTALL_DIR_RES_DEFAULT Contents/Resources/share) - set(NG_INSTALL_DIR_INCLUDE_DEFAULT Contents/Resources/include) - - set(NG_RPATH_TOKEN "@loader_path") -else(APPLE) - set(NG_INSTALL_DIR_BIN_DEFAULT bin) - set(NG_INSTALL_DIR_LIB_DEFAULT lib) - if(WIN32) - set(NG_INSTALL_DIR_CMAKE_DEFAULT cmake) - else(WIN32) - set(NG_INSTALL_DIR_CMAKE_DEFAULT lib/cmake/${NG_INSTALL_SUFFIX}) - endif(WIN32) - set(NG_INSTALL_DIR_PYTHON_DEFAULT ${PYTHON_PACKAGES_INSTALL_DIR}) - set(NG_INSTALL_DIR_RES_DEFAULT share) - set(NG_INSTALL_DIR_INCLUDE_DEFAULT include) - - set(NG_RPATH_TOKEN "\$ORIGIN") -endif(APPLE) - -set(NG_INSTALL_DIR_PYTHON ${NG_INSTALL_DIR_PYTHON_DEFAULT} CACHE STRING "Install directory for Python files") -set(NG_INSTALL_DIR_BIN ${NG_INSTALL_DIR_BIN_DEFAULT} CACHE STRING "Install directory for executables") -set(NG_INSTALL_DIR_LIB ${NG_INSTALL_DIR_LIB_DEFAULT} CACHE STRING "Install directory for libraries") -set(NG_INSTALL_DIR_INCLUDE ${NG_INSTALL_DIR_INCLUDE_DEFAULT} CACHE STRING "Install directory for header files") -set(NG_INSTALL_DIR_CMAKE ${NG_INSTALL_DIR_CMAKE_DEFAULT} CACHE STRING "Install directory for CMake files") -set(NG_INSTALL_DIR_RES ${NG_INSTALL_DIR_RES_DEFAULT} CACHE STRING "Install directory for resources") - -get_filename_component(NETGEN_CMAKE_DIR_ABSOLUTE ${NG_INSTALL_DIR_CMAKE} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) -get_filename_component(NETGEN_BINARY_DIR_ABSOLUTE ${NG_INSTALL_DIR_BIN} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) -get_filename_component(NETGEN_LIBRARY_DIR_ABSOLUTE ${NG_INSTALL_DIR_LIB} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) -get_filename_component(NETGEN_INCLUDE_DIR_ABSOLUTE ${NG_INSTALL_DIR_INCLUDE} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) -get_filename_component(NETGEN_RESOURCE_DIR_ABSOLUTE ${NG_INSTALL_DIR_RES} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) - -file(RELATIVE_PATH NETGEN_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${CMAKE_INSTALL_PREFIX}) -file(RELATIVE_PATH NETGEN_BINARY_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_BINARY_DIR_ABSOLUTE}) -file(RELATIVE_PATH NETGEN_LIBRARY_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_LIBRARY_DIR_ABSOLUTE}) -file(RELATIVE_PATH NETGEN_INCLUDE_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_INCLUDE_DIR_ABSOLUTE}) -file(RELATIVE_PATH NETGEN_RESOURCE_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_RESOURCE_DIR_ABSOLUTE}) - -file(RELATIVE_PATH NETGEN_RPATH ${NETGEN_BINARY_DIR_ABSOLUTE} ${NETGEN_LIBRARY_DIR_ABSOLUTE}) - if(USE_PYTHON) get_filename_component(NETGEN_PYTHON_DIR_ABSOLUTE ${NG_INSTALL_DIR_PYTHON} ABSOLUTE BASE_DIR ${CMAKE_INSTALL_PREFIX}) file(RELATIVE_PATH NETGEN_PYTHON_DIR ${NETGEN_CMAKE_DIR_ABSOLUTE} ${NETGEN_PYTHON_DIR_ABSOLUTE}) @@ -252,7 +263,6 @@ 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) @@ -313,11 +323,11 @@ if (USE_PYTHON) 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}) + target_compile_definitions(netgen_python INTERFACE NG_PYTHON NETGEN_PYTHON) + target_include_directories(netgen_python INTERFACE ${pybind11_INCLUDE_DIR} ${Python3_INCLUDE_DIRS}) + target_include_directories(nglib PRIVATE ${pybind11_INCLUDE_DIR} ${Python3_INCLUDE_DIRS}) + if(Python3_LIBRARIES AND (WIN32 OR NOT BUILD_FOR_CONDA)) + target_link_libraries(netgen_python INTERFACE ${Python3_LIBRARIES}) endif() if(NG_INSTALL_PYBIND) @@ -327,30 +337,19 @@ if (USE_PYTHON) 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 ) + set(MPI_DETERMINE_LIBRARY_VERSION TRUE) + find_package(MPI) find_package(METIS REQUIRED) 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}) ####################################################################### +add_library(occ_libs INTERFACE IMPORTED) if (USE_OCC) find_package(OpenCascade NAMES OpenCASCADE opencascade REQUIRED CMAKE_FIND_ROOT_PATH_BOTH) add_definitions(-DOCCGEOMETRY) @@ -366,53 +365,66 @@ if (USE_OCC) 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(${OpenCASCADE_MAJOR_VERSION}.${OpenCASCADE_MINOR_VERSION} VERSION_GREATER_EQUAL 7.8) + list(APPEND OCC_LIBRARIES TKDEIGES TKDESTEP TKDESTL) + else() + list(APPEND OCC_LIBRARIES + TKIGES + TKSTEP + TKSTL + TKXDEIGES + TKXDESTEP + TKSTEP209 + TKSTEPAttr + TKSTEPBase + ) + endif() + if(UNIX AND NOT APPLE) + list(PREPEND OCC_LIBRARIES -Wl,--start-group) + list(APPEND OCC_LIBRARIES -Wl,--end-group) + endif() + + target_link_libraries(occ_libs INTERFACE ${OCC_LIBRARIES}) + get_target_property(occ_include_dir TKernel INTERFACE_INCLUDE_DIRECTORIES) + if(NOT occ_include_dir) + set(occ_include_dir ${OpenCASCADE_INCLUDE_DIR}) + endif() + target_include_directories(occ_libs INTERFACE ${occ_include_dir}) + message(STATUS "OpenCasCade include dirs: ${occ_include_dir}") if(NOT OpenCASCADE_BUILD_SHARED_LIBS) if(OpenCASCADE_WITH_FREETYPE) - find_library( FREETYPE NAMES freetype HINTS ${OpenCASCADE_INSTALL_PREFIX}/lib) + find_library( FREETYPE NAMES freetype HINTS ${OpenCASCADE_LIBRARY_DIR}) list(APPEND OCC_LIBRARIES ${FREETYPE}) + target_link_libraries(occ_libs INTERFACE ${FREETYPE}) if(UNIX AND NOT APPLE) find_package(Fontconfig REQUIRED) - list(APPEND OCC_LIBRARIES ${Fontconfig_LIBRARIES}) + target_link_libraries(occ_libs INTERFACE ${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() + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + target_link_libraries(occ_libs INTERFACE Threads::Threads) endif() - message(STATUS "OCC DIRS ${OpenCASCADE_INCLUDE_DIR}") if(WIN32 AND USE_GUI) - target_link_libraries(nggui PRIVATE ${OCC_LIBRARIES}) + target_link_libraries(nggui PRIVATE Ws2_32.lib) endif(WIN32 AND USE_GUI) + if(USE_GUI) + target_link_libraries(nggui PRIVATE occ_libs) + endif(USE_GUI) endif (USE_OCC) ####################################################################### @@ -621,6 +633,16 @@ if(UNIX) endif(temp) endif(UNIX) +if(USE_PYTHON AND NOT SKBUILD) + # install egg file to let python/pip know that Netgen ist installed + file( WRITE "netgen_mesher-py3.egg-info" +"Metadata-Version: 2.1 +Name: netgen-mesher +Version: ${NETGEN_VERSION_MAJOR}.${NETGEN_VERSION_MINOR}.${NETGEN_VERSION_PATCH}.post${NETGEN_VERSION_TWEAK} +") + install(FILES netgen_mesher-py3.egg-info DESTINATION ${NG_INSTALL_DIR_PYTHON} COMPONENT netgen) +endif() + if(APPLE AND NOT SKBUILD) # create some auxiliary files set(mac_startup ${CMAKE_CURRENT_BINARY_DIR}/startup.sh) diff --git a/README.md b/README.md index e7d2e8fd..43cfb3d8 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,4 @@ NETGEN is an automatic 3d tetrahedral mesh generator. It accepts input from cons Find the Open Source Community on https://ngsolve.org Support & Services: https://cerbsim.com + diff --git a/cmake/NetgenConfig.cmake.in b/cmake/NetgenConfig.cmake.in index ddb8850b..477ed214 100644 --- a/cmake/NetgenConfig.cmake.in +++ b/cmake/NetgenConfig.cmake.in @@ -38,9 +38,9 @@ set(NETGEN_OCC_LIBRARIES_BIN "@OpenCASCADE_BINARY_DIR@") set(NETGEN_OCC_LIBRARIES "@OCC_LIBRARIES@") 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_PYTHON_EXECUTABLE "@Python3_EXECUTABLE@") +set(NETGEN_PYTHON_INCLUDE_DIRS "@Python3_INCLUDE_DIRS@") +set(NETGEN_PYTHON_LIBRARIES "@Python3_LIBRARIES@") set(NETGEN_TCL_INCLUDE_PATH "@TCL_INCLUDE_PATH@") set(NETGEN_TCL_LIBRARY "@TCL_STUB_LIBRARY@") set(NETGEN_TK_DND_LIBRARY "@TK_DND_LIBRARY@") diff --git a/cmake/SuperBuild.cmake b/cmake/SuperBuild.cmake index 387f7b29..00a5ed5e 100644 --- a/cmake/SuperBuild.cmake +++ b/cmake/SuperBuild.cmake @@ -14,9 +14,16 @@ set (SUBPROJECT_ARGS PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dependencies ) +if (EMSCRIPTEN) + set (SUBPROJECT_ARGS + ${SUBPROJECT_ARGS} + CMAKE_COMMAND emcmake ${CMAKE_COMMAND}) +endif() + # only show output on failure in ci-builds if(DEFINED ENV{CI}) set (SUBPROJECT_ARGS + ${SUBPROJECT_ARGS} LOG_DOWNLOAD ON LOG_BUILD ON LOG_INSTALL ON @@ -50,7 +57,7 @@ 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 "") +set(SUBPROJECT_CMAKE_ARGS "${SUBPROJECT_CMAKE_ARGS};-DCMAKE_POSITION_INDEPENDENT_CODE=ON;-DCMAKE_POLICY_VERSION_MINIMUM=3.5" CACHE INTERNAL "") if(USE_CCACHE) find_program(CCACHE_FOUND NAMES ccache ccache.bat) @@ -82,8 +89,12 @@ 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 + # URL https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V7_6_3.zip + # URL_MD5 2426e373903faabbd4f96a01a934b66d + # URL https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V7_7_2.zip + # URL_MD5 533eb4f18af0f77ae321b158caeaee79 + URL https://github.com/Open-Cascade-SAS/OCCT/archive/refs/tags/V7_8_1.zip + URL_MD5 bf62952a03696dab9e4272aa8efacb1a DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies ${SUBPROJECT_ARGS} CMAKE_ARGS @@ -97,6 +108,7 @@ if(BUILD_OCC) -DBUILD_MODULE_Visualization:BOOL=OFF -DBUILD_MODULE_ApplicationFramework:BOOL=OFF -DBUILD_MODULE_Draw:BOOL=OFF + -DBUILD_MODULE_DETools:BOOL=OFF -DUSE_FREETYPE:BOOL=OFF -DUSE_OPENGL:BOOL=OFF -DUSE_XLIB:BOOL=OFF @@ -108,44 +120,42 @@ if(BUILD_OCC) 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) + find_package(OpenCascade NAMES OpenCasCade OpenCASCADE opencascade) + if(NOT OpenCascade_FOUND) + message(FATAL_ERROR "Opencascade not found, either\n\ + - install pip packages netgen-occt-devel netgen-occ\n\ + - set OpenCascade_DIR to a directory containting opencascadeConfig.cmake\n\ + - build OpenCascade automatically by passing -DBUILD_OCC=ON\n\ + - disable OpenCascade by passing -DUSE_OCC=OFF\n\ + ") endif() endif(BUILD_OCC) endif(USE_OCC) if(BUILD_ZLIB) - set(ZLIB_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/zlib) + set(ZLIB_ROOT ${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} + -DCMAKE_INSTALL_PREFIX=${ZLIB_ROOT} ${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) + set(ZLIB_INCLUDE_DIRS ${ZLIB_ROOT}/include) + set(ZLIB_LIBRARIES ${ZLIB_ROOT}/lib/zlibstatic.lib) + set(ZLIB_LIBRARY_RELEASE ${ZLIB_ROOT}/lib/zlibstatic.lib) + else(WIN32) + set(ZLIB_INCLUDE_DIRS ${ZLIB_ROOT}/include) + set(ZLIB_LIBRARIES ${ZLIB_ROOT}/lib/libz.a) + set(ZLIB_LIBRARY_RELEASE ${ZLIB_ROOT}/lib/libz.a) endif(WIN32) else() include(cmake/external_projects/zlib.cmake) @@ -165,16 +175,20 @@ if (USE_PYTHON) else( PYBIND_INCLUDE_DIR ) message(FATAL_ERROR "Could NOT find pybind11!") endif( PYBIND_INCLUDE_DIR ) - find_package(PythonInterp 3 REQUIRED) - if(NOT BUILD_FOR_CONDA) - find_package(PythonLibs 3 REQUIRED) + if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.18) + find_package(Python3 COMPONENTS Interpreter Development.Module) + if(NOT EMSCRIPTEN) + find_package(Python3 COMPONENTS Interpreter Development.Embed) + endif() + else() + find_package(Python3 REQUIRED COMPONENTS Interpreter Development) endif() set_vars(NETGEN_CMAKE_ARGS - PYTHON_INCLUDE_DIRS - PYTHON_LIBRARIES - PYTHON_EXECUTABLE - PYTHON_VERSION + Python3_INCLUDE_DIRS + Python3_LIBRARIES + Python3_EXECUTABLE + Python3_VERSION PYBIND_INCLUDE_DIR NG_INSTALL_PYBIND ) @@ -192,7 +206,6 @@ endif(USE_CGNS) ####################################################################### if(USE_MPI) - if(UNIX) if (METIS_DIR) message(STATUS "Using external METIS at: ${METIS_DIR}") else (METIS_DIR) @@ -203,23 +216,24 @@ if(USE_MPI) include(cmake/external_projects/metis.cmake) endif(NOT METIS_FOUND) endif(METIS_DIR) - else(UNIX) - find_package(METIS REQUIRED) - endif(UNIX) endif(USE_MPI) ####################################################################### # propagate cmake variables to Netgen subproject set_vars( NETGEN_CMAKE_ARGS + CMAKE_MODULE_LINKER_FLAGS + CMAKE_MODULE_LINKER_FLAGS_RELEASE CMAKE_SHARED_LINKER_FLAGS CMAKE_SHARED_LINKER_FLAGS_RELEASE CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_RELEASE + CMAKE_STRIP USE_GUI USE_PYTHON USE_MPI + USE_MPI_WRAPPER USE_VT USE_VTUNE USE_NUMA @@ -245,10 +259,20 @@ set_vars( NETGEN_CMAKE_ARGS OpenCascade_ROOT ZLIB_INCLUDE_DIRS ZLIB_LIBRARIES + ZLIB_LIBRARY_RELEASE + ZLIB_ROOT NGLIB_LIBRARY_TYPE NGCORE_LIBRARY_TYPE NGGUI_LIBRARY_TYPE + + NG_INSTALL_DIR_PYTHON + NG_INSTALL_DIR_BIN + NG_INSTALL_DIR_LIB + NG_INSTALL_DIR_INCLUDE + NG_INSTALL_DIR_CMAKE + NG_INSTALL_DIR_RES + NG_INSTALL_SUFFIX ) # propagate all variables set on the command line using cmake -DFOO=BAR diff --git a/cmake/external_projects/metis.cmake b/cmake/external_projects/metis.cmake index 1711b5df..5501a0f5 100644 --- a/cmake/external_projects/metis.cmake +++ b/cmake/external_projects/metis.cmake @@ -3,8 +3,8 @@ set(METIS_DIR ${CMAKE_CURRENT_BINARY_DIR}/dependencies/metis) ExternalProject_Add(project_metis PREFIX ${CMAKE_CURRENT_BINARY_DIR}/dependencies - URL https://bitbucket.org/petsc/pkg-metis/get/v5.1.0-p6.tar.gz - URL_MD5 55fc654bb838846b856ba898795143f1 + URL https://bitbucket.org/petsc/pkg-metis/get/v5.1.0-p12.tar.gz + URL_MD5 6cd66f75f88dfa2cf043de011f85d8bc DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies CMAKE_ARGS -DGKLIB_PATH=${METIS_SRC_DIR}/GKlib diff --git a/cmake/external_projects/tcltk.cmake b/cmake/external_projects/tcltk.cmake index 637c1899..cbbc8388 100644 --- a/cmake/external_projects/tcltk.cmake +++ b/cmake/external_projects/tcltk.cmake @@ -7,7 +7,7 @@ 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 +execute_process(COMMAND ${Python3_EXECUTABLE} -c "import tkinter;print(tkinter.Tcl().eval('info patchlevel').replace('.','-'))" OUTPUT_VARIABLE PYTHON_TCL_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -39,7 +39,7 @@ 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) + execute_process(COMMAND ${Python3_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 @@ -51,12 +51,17 @@ if(APPLE OR WIN32) NO_SYSTEM_ENVIRONMENT_PATH NO_CMAKE_SYSTEM_PATH NO_CMAKE_FIND_ROOT_PATH - HINTS ${PYTHON_PREFIX}/lib ${PYTHON_PREFIX}/tcl + HINTS + ${PYTHON_PREFIX}/lib + ${PYTHON_PREFIX}/tcl + ${PYTHON_PREFIX}/Frameworks + ${PYTHON_PREFIX}/Frameworks/Tcl.framework + ${PYTHON_PREFIX}/Frameworks/Tk.framework ) 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}) + find_library(TCL_LIBRARY NAMES tcl85 tcl8.5 tcl86 tcl8.6 tcl86t Tcl ${tcl_find_args}) + find_library(TK_LIBRARY NAMES tk85 tk8.5 tk86 tk8.6 tk86t Tk ${tcl_find_args}) else() # use system tcl/tk on linux find_package(TclStub REQUIRED) @@ -93,7 +98,7 @@ if(APPLE) ) ExternalProject_Add(project_tkdnd - URL "http://sourceforge.net/projects/tkdnd/files/TkDND/TkDND%202.8/tkdnd2.8-src.tar.gz" + URL "https://src.fedoraproject.org/repo/pkgs/tkdnd/tkdnd2.8-src.tar.gz/a6d47a996ea957416469b12965d4db91/tkdnd2.8-src.tar.gz" URL_MD5 a6d47a996ea957416469b12965d4db91 DEPENDS project_tcl project_tk DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external_dependencies @@ -104,6 +109,7 @@ if(APPLE) -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 + -DCMAKE_POLICY_VERSION_MINIMUM=3.5 ${SUBPROJECT_ARGS} ) @@ -183,7 +189,10 @@ elseif(WIN32) BUILD_IN_SOURCE 1 CONFIGURE_COMMAND "" BUILD_COMMAND "" - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX} + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory lib ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_LIB} + COMMAND ${CMAKE_COMMAND} -E copy_directory bin ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_BIN} + COMMAND ${CMAKE_COMMAND} -E copy_directory include ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_INCLUDE} + ${SUBPROJECT_ARGS} ) diff --git a/cmake/external_projects/zlib.cmake b/cmake/external_projects/zlib.cmake index c655090f..ddda799d 100644 --- a/cmake/external_projects/zlib.cmake +++ b/cmake/external_projects/zlib.cmake @@ -6,7 +6,9 @@ if(WIN32) BUILD_IN_SOURCE 1 CONFIGURE_COMMAND "" BUILD_COMMAND "" - INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory . ${CMAKE_INSTALL_PREFIX} + INSTALL_COMMAND ${CMAKE_COMMAND} -E copy_directory lib ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_LIB} + COMMAND ${CMAKE_COMMAND} -E copy_directory bin ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_BIN} + COMMAND ${CMAKE_COMMAND} -E copy_directory include ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_INCLUDE} LOG_DOWNLOAD 1 ) diff --git a/cmake/generate_version_file.cmake b/cmake/generate_version_file.cmake index c4a579d1..780c287b 100644 --- a/cmake/generate_version_file.cmake +++ b/cmake/generate_version_file.cmake @@ -24,8 +24,8 @@ if(status AND NOT status EQUAL 0) 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") + 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) @@ -106,6 +106,7 @@ file(GENERATE OUTPUT netgen_config.hpp CONTENT #define NETGEN_USE_CHECK_RANGE $ #define NETGEN_BUILD_STUB_FILES $ #define NETGEN_BUILD_FOR_CONDA $ +#define NETGEN_SHARED_LIBRARY_SUFFIX \"${CMAKE_SHARED_LIBRARY_SUFFIX}\" #endif // NETGEN_CONFIG_HPP_INCLUDED___ ") diff --git a/external_dependencies/pybind11 b/external_dependencies/pybind11 index 80dc998e..38bf7b17 160000 --- a/external_dependencies/pybind11 +++ b/external_dependencies/pybind11 @@ -1 +1 @@ -Subproject commit 80dc998efced8ceb2be59756668a7e90e8bef917 +Subproject commit 38bf7b174875c27c1ba98bdf5a9bf13d967f14d4 diff --git a/libsrc/core/.clang-tidy b/libsrc/core/.clang-tidy index 9ceddce8..086e97b8 100644 --- a/libsrc/core/.clang-tidy +++ b/libsrc/core/.clang-tidy @@ -1,4 +1,4 @@ -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' +Checks: '*,-cppcoreguidelines-avoid-non-const-global-variables,-llvmlibc-restrict-system-libc-headers,-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 diff --git a/libsrc/core/CMakeLists.txt b/libsrc/core/CMakeLists.txt index c4f4795e..40cb54d6 100644 --- a/libsrc/core/CMakeLists.txt +++ b/libsrc/core/CMakeLists.txt @@ -12,13 +12,42 @@ add_library(ngcore ${NGCORE_LIBRARY_TYPE} taskmanager.cpp utils.cpp version.cpp + ng_mpi_wrapper.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) +if(EMSCRIPTEN) + set(PYTHON_MODULE_EXTENSION ".so") + target_link_options(ngcore PUBLIC -sALLOW_MEMORY_GROWTH -sENVIRONMENT=web) + target_compile_options(ngcore PUBLIC -sNO_DISABLE_EXCEPTION_CATCHING) +endif() + +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND USE_PYTHON) + # Python packages on Linux are compiled with the old ABI, + # make sure that the same ABI is used in plugins aswell + try_run( + ret_val can_compile + ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/_get_glibcxx_use_cxx11_abi.cpp + RUN_OUTPUT_VARIABLE use_glibcxx_cxx11_abi + ) + target_compile_definitions(ngcore PUBLIC -D_GLIBCXX_USE_CXX11_ABI=${use_glibcxx_cxx11_abi}) + try_run( + ret_val can_compile + ${CMAKE_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/_get_gxx_abi.cpp + RUN_OUTPUT_VARIABLE default_cxx_abi_version + ) + if(${can_compile} AND (${ret_val} EQUAL 0)) + # Different python modules using pybind11 need to use the same C++ ABI version + # for compatibility + set(cxx_abi_version 17) + if(cxx_abi_version LESS default_cxx_abi_version) + set(cxx_abi_version ${default_cxx_abi_version}) + endif() + message(STATUS "GNU C++ ABI version: ${cxx_abi_version}") + target_compile_options(ngcore PUBLIC "-fabi-version=${cxx_abi_version}") + endif() endif() if(USE_PYTHON) @@ -27,10 +56,12 @@ if(USE_PYTHON) endif(USE_PYTHON) if(WIN32) - target_compile_options(ngcore PUBLIC /bigobj /MP /W1 /wd4068) + target_compile_options(ngcore PUBLIC /bigobj $) 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) +else(WIN32) + target_link_libraries(ngcore PUBLIC dl) endif(WIN32) target_compile_definitions(ngcore PRIVATE NGCORE_EXPORTS) @@ -48,19 +79,6 @@ 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} - DESTINATION ${NG_INSTALL_DIR_INCLUDE} - ) - add_dependencies(ngcore project_spdlog) - target_compile_definitions(ngcore PUBLIC NETGEN_USE_SPDLOG) - if(DEBUG_LOG) - target_compile_definitions(ngcore PUBLIC NETGEN_LOG_DEBUG) - endif(DEBUG_LOG) -endif(USE_SPDLOG) - if(USE_NUMA) find_library(NUMA_LIBRARY libnuma.so) target_compile_definitions(ngcore PUBLIC USE_NUMA) @@ -69,14 +87,15 @@ endif(USE_NUMA) install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen) -target_link_libraries(ngcore PUBLIC netgen_mpi PRIVATE "$" ${CMAKE_THREAD_LIBS_INIT}) +target_link_libraries(ngcore PRIVATE "$" ${CMAKE_THREAD_LIBS_INIT}) 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 + register_archive.hpp autodiff.hpp autodiffdiff.hpp + ng_mpi.hpp ng_mpi_generated_declarations.hpp mpi4py_pycapi.h ng_mpi_native.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel) if(ENABLE_CPP_CORE_GUIDELINES_CHECK) @@ -86,9 +105,71 @@ endif(ENABLE_CPP_CORE_GUIDELINES_CHECK) add_dependencies(ngcore ng_generate_version_file) if(USE_PYTHON) - pybind11_add_module(pyngcore SHARED python_ngcore_export.cpp) - target_link_libraries(pyngcore PUBLIC ngcore netgen_python) + pybind11_add_module(pyngcore MODULE python_ngcore_export.cpp) + target_link_libraries(pyngcore PUBLIC ngcore PRIVATE netgen_python) set_target_properties(pyngcore PROPERTIES INSTALL_RPATH "${NG_RPATH_TOKEN}/../${NETGEN_PYTHON_RPATH}") + if(EMSCRIPTEN) + target_compile_definitions(pyngcore PRIVATE NGCORE_EXPORTS) + endif(EMSCRIPTEN) install(TARGETS pyngcore DESTINATION ${NG_INSTALL_DIR_PYTHON}/pyngcore COMPONENT netgen) endif(USE_PYTHON) +function (build_mpi_variant) + set(target ng_${ARGV0}) + set(include_dir ${ARGV1}) + message("1Building MPI variant: ${ARGV0} ${ARGV1}") + add_library(${target} SHARED ng_mpi.cpp) + target_link_libraries(${target} PUBLIC ngcore PRIVATE netgen_python) + target_compile_definitions(${target} PUBLIC PARALLEL NG_MPI_WRAPPER) + target_include_directories(${target} PRIVATE ${include_dir}) + set_target_properties(${target} PROPERTIES PREFIX "") + install(TARGETS ${target} RUNTIME DESTINATION ${NG_INSTALL_DIR_BIN} LIBRARY DESTINATION ${NG_INSTALL_DIR_LIB} COMPONENT netgen) +endfunction() + +if(USE_MPI) + target_compile_definitions(ngcore PUBLIC PARALLEL) + + message(STATUS "Found MPI version\n${MPI_C_LIBRARY_VERSION_STRING}") + + if(USE_MPI_WRAPPER) + target_compile_definitions(ngcore PUBLIC NG_MPI_WRAPPER) + if(MPI_C_LIBRARY_VERSION_STRING MATCHES "Microsoft MPI.*") + set(MICROSOFT_MPI_INCLUDE_DIR ${MPI_C_HEADER_DIR}) + set(MICROSOFT_MPI_LIBRARY ${MPI_msmpi_LIBRARY}) + endif() + + if(MPI_C_LIBRARY_VERSION_STRING MATCHES "Open MPI.*") + set(OPENMPI_INCLUDE_DIR ${MPI_C_INCLUDE_PATH}) + endif() + + if(MPI_C_LIBRARY_VERSION_STRING MATCHES "MPICH.*") + set(MPICH_INCLUDE_DIR ${MPI_C_INCLUDE_PATH}) + endif() + + if(MPI_C_LIBRARY_VERSION_STRING MATCHES "Intel.*") + set(INTEL_MPI_INCLUDE_DIR ${MPI_C_INCLUDE_PATH}) + endif() + + if(OPENMPI_INCLUDE_DIR) + build_mpi_variant(openmpi ${OPENMPI_INCLUDE_DIR}) + endif() + if(MPICH_INCLUDE_DIR) + build_mpi_variant(mpich ${MPICH_INCLUDE_DIR}) + endif() + if(INTEL_MPI_INCLUDE_DIR) + build_mpi_variant(intel_mpi ${INTEL_MPI_INCLUDE_DIR}) + if(WIN32) + target_link_libraries(ng_intel_mpi PUBLIC ${INTEL_MPI_LIBRARY}) + endif() + endif() + if(MICROSOFT_MPI_INCLUDE_DIR) + build_mpi_variant(microsoft_mpi ${MICROSOFT_MPI_INCLUDE_DIR}) + target_link_libraries(ng_microsoft_mpi PUBLIC ${MICROSOFT_MPI_LIBRARY}) + endif() + else() + target_link_libraries(ngcore PUBLIC ${MPI_C_LIBRARIES}) + target_include_directories(ngcore PUBLIC ${MPI_C_INCLUDE_PATH}) + endif(USE_MPI_WRAPPER) + +endif(USE_MPI) + diff --git a/libsrc/core/_get_glibcxx_use_cxx11_abi.cpp b/libsrc/core/_get_glibcxx_use_cxx11_abi.cpp new file mode 100644 index 00000000..63588187 --- /dev/null +++ b/libsrc/core/_get_glibcxx_use_cxx11_abi.cpp @@ -0,0 +1,13 @@ +#include + +int main() { + #ifdef _GLIBCXX_USE_CXX11_ABI + if(_GLIBCXX_USE_CXX11_ABI) + std::cout << 1; + else + std::cout << 0; + #else // _GLIBCXX_USE_CXX11_ABI + std::cout << 0; + #endif // _GLIBCXX_USE_CXX11_ABI + return 0; +} diff --git a/libsrc/core/_get_gxx_abi.cpp b/libsrc/core/_get_gxx_abi.cpp new file mode 100644 index 00000000..ac1579f0 --- /dev/null +++ b/libsrc/core/_get_gxx_abi.cpp @@ -0,0 +1,7 @@ +#include + +int main() { + if (__GXX_ABI_VERSION >= 2000 || __GXX_ABI_VERSION < 1000) return 1; + std::cout << (__GXX_ABI_VERSION % 100); + return 0; +} diff --git a/libsrc/core/archive.cpp b/libsrc/core/archive.cpp index 5454b929..c4731562 100644 --- a/libsrc/core/archive.cpp +++ b/libsrc/core/archive.cpp @@ -10,24 +10,31 @@ namespace ngcore { // clang-tidy should ignore this static object - static std::unique_ptr> type_register; // NOLINT + // static std::map type_register; // NOLINT + + auto& GetTypeRegister() + { + static std::map type_register; + return type_register; + } + const detail::ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname) { - if(type_register == nullptr) type_register = - std::make_unique>(); - return (*type_register)[classname]; + // if(type_register == nullptr) type_register = + // std::make_unique>(); + return GetTypeRegister()[classname]; } void Archive :: SetArchiveRegister(const std::string& classname, const detail::ClassArchiveInfo& info) { - if(type_register == nullptr) type_register = - std::make_unique>(); - (*type_register)[classname] = info; + // if(type_register == nullptr) type_register = + // std::make_unique>(); + GetTypeRegister()[classname] = info; } bool Archive :: IsRegistered(const std::string& classname) { - if(type_register == nullptr) type_register = - std::make_unique>(); - return type_register->count(classname) != 0; + // if(type_register == nullptr) type_register = + // std::make_unique>(); + return GetTypeRegister().count(classname) != 0; } #ifdef NETGEN_PYTHON diff --git a/libsrc/core/archive.hpp b/libsrc/core/archive.hpp index 79c3fedd..8a3d7a32 100644 --- a/libsrc/core/archive.hpp +++ b/libsrc/core/archive.hpp @@ -1,6 +1,7 @@ #ifndef NETGEN_CORE_ARCHIVE_HPP #define NETGEN_CORE_ARCHIVE_HPP +#include #include #include // for array #include // for complex @@ -14,12 +15,12 @@ #include // for string #include // for declval, enable_if_t, false_type, is_co... #include // for std::byte +#include // for set #include // for type_info #include // for move, swap, pair #include // for vector #include "exception.hpp" // for UnreachableCodeException, Exception -#include "logging.hpp" // for logger #include "ngcore_api.hpp" // for NGCORE_API #include "type_traits.hpp" // for all_of_tmpl #include "utils.hpp" // for Demangle, unlikely @@ -34,7 +35,40 @@ namespace pybind11 namespace ngcore { + template + struct Shallow { + T val; + Shallow() = default; + Shallow(T aval) : val(aval) { ; } + operator T&() { return val; } + }; + // Helper to detect shared_from_this + template + class has_shared_from_this2 + { + private: + // typedef T* T_ptr; + template static std::true_type test(decltype(((C*)nullptr)->shared_from_this())); + template static std::false_type test(...); + + public: + // If the test returns true_type, then T has shared_from_this + static constexpr bool value = decltype(test(0))::value; + }; + + + + + template + class has_shallow_archive : public std::false_type {}; + + template + class has_shallow_archive> + : public std::is_same {}; + + + #ifdef NETGEN_PYTHON pybind11::object CastAnyToPy(const std::any& a); #endif // NETGEN_PYTHON @@ -42,16 +76,36 @@ namespace ngcore class NGCORE_API Archive; namespace detail { + template + T* construct_from_tuple(Tuple&& tuple, std::index_sequence ) { + // return new T{std::get(std::forward(tuple))...}; + return new T{std::get(std::move(tuple))...}; + } + + template + T* construct_from_tuple(Tuple&& tuple) { + return construct_from_tuple(std::forward(tuple), + std::make_index_sequence>::value>{} + ); + } + // create new pointer of type T if it is default constructible, else throw - template - T* constructIfPossible_impl(Rest... /*unused*/) - { throw Exception(std::string(Demangle(typeid(T).name())) + " is not default constructible!"); } + template + T* constructIfPossible(std::tuple args) + { + if constexpr(std::is_constructible_v) + return construct_from_tuple(args); + throw Exception(std::string(Demangle(typeid(T).name())) + + " is not constructible!"); + } - template::value>> - T* constructIfPossible_impl(int /*unused*/) { return new T; } // NOLINT - - template - T* constructIfPossible() { return constructIfPossible_impl(int{}); } + template T *constructIfPossible() + { + if constexpr(std::is_constructible_v) + return new T(); + throw Exception(std::string(Demangle(typeid(T).name())) + + " is not default constructible!"); + } //Type trait to check if a class implements a 'void DoArchive(Archive&)' function template @@ -83,20 +137,53 @@ namespace ngcore NGCORE_API static constexpr bool value = type::value; }; + template + struct has_GetCArgs + { + template static std::true_type check( decltype( sizeof(&C::GetCArgs )) ) { return std::true_type(); } + template static std::false_type check(...) { return std::false_type(); } + typedef decltype( check(sizeof(char)) ) type; + static constexpr type value = type(); + }; + template + constexpr bool has_GetCArgs_v = has_GetCArgs::value; + + template>::type* = nullptr> + std::tuple<> GetCArgs(T&val) { return {}; } + + template>::type* = nullptr> + auto GetCArgs(T&val) { + return val.GetCArgs(); + } + + template + using TCargs = decltype(GetCArgs(*static_cast(nullptr))); + + struct ClassArchiveInfo { // create new object of this type and return a void* pointer that is points to the location // of the (base)class given by type_info - std::function creator; + // std::function creator; + void* (*creator)(const std::type_info&, Archive&); // This caster takes a void* pointer to the type stored in this info and casts it to a // void* pointer pointing to the (base)class type_info - std::function upcaster; + // std::function upcaster; + void* (*upcaster) (const std::type_info&, void*); // 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 downcaster; + // std::function downcaster; + void* (*downcaster)(const std::type_info&, void*); + + // Archive constructor arguments + // std::function cargs_archiver; + void (*cargs_archiver)(Archive&, void*); #ifdef NETGEN_PYTHON - std::function anyToPyCaster; + // std::function anyToPyCaster; + pybind11::object (*anyToPyCaster)(const std::any&); #endif // NETGEN_PYTHON }; } // namespace detail @@ -129,7 +216,6 @@ namespace ngcore protected: bool shallow_to_python = false; std::map version_map = GetLibraryVersions(); - std::shared_ptr logger = GetLogger("Archive"); public: template static constexpr bool is_archivable = detail::is_Archivable_struct::value; @@ -250,7 +336,6 @@ namespace ngcore // don't use it that often anyway) Archive& operator& (std::vector& v) { - logger->debug("In special archive for std::vector"); size_t size; if(Output()) size = v.size(); @@ -313,6 +398,26 @@ namespace ngcore } return (*this); } + template + Archive& operator&(std::set &s) + { + auto size = s.size(); + (*this) & size; + if(Output()) + for(const auto & val : s) + (*this) << val; + else + { + for(size_t i=0; i>> @@ -397,30 +502,36 @@ namespace ngcore + template + Archive& operator & (ngcore::Shallow& shallow) + { + this->Shallow(shallow.val); + return *this; + } // Archive shared_ptrs ================================================= template Archive& operator & (std::shared_ptr& ptr) { + if constexpr(has_shallow_archive::value) + if (shallow_to_python) + { + Shallow (ptr); + return *this; + } + if(Output()) { - logger->debug("Store shared ptr of type {}", Demangle(typeid(T).name())); // save -2 for nullptr if(!ptr) - { - logger->debug("Storing nullptr"); - return (*this) << -2; - } + return (*this) << -2; void* reg_ptr = ptr.get(); bool neededDowncast = false; // Downcasting is only possible for our registered classes if(typeid(T) != typeid(*ptr)) { - logger->debug("Typids are different: {} vs {}", - Demangle(typeid(T).name()), - Demangle(typeid(*ptr).name())); if(!IsRegistered(Demangle(typeid(*ptr).name()))) throw Exception(std::string("Archive error: Polymorphic type ") + Demangle(typeid(*ptr).name()) @@ -428,17 +539,12 @@ namespace ngcore reg_ptr = GetArchiveRegister(Demangle(typeid(*ptr).name())).downcaster(typeid(T), ptr.get()); // if there was a true downcast we have to store more information if(reg_ptr != static_cast(ptr.get())) - { - logger->debug("Multiple/Virtual inheritance involved, need to cast pointer"); - neededDowncast = true; - } + neededDowncast = true; } auto pos = shared_ptr2nr.find(reg_ptr); // if not found store -1 and the pointer if(pos == shared_ptr2nr.end()) { - logger->debug("Didn't find the shared_ptr, create new registry entry at {}", - shared_ptr_count); auto p = ptr.get(); (*this) << -1; (*this) & neededDowncast & p; @@ -449,27 +555,23 @@ namespace ngcore return *this; } // if found store the position and if it has to be downcasted and how - logger->debug("Found shared_ptr at position {}", pos->second); (*this) << pos->second << neededDowncast; if(neededDowncast) (*this) << Demangle(typeid(*ptr).name()); } else // Input { - logger->debug("Reading shared_ptr of type {}", Demangle(typeid(T).name())); int nr; (*this) & nr; // -2 restores a nullptr if(nr == -2) { - logger->debug("Reading a nullptr"); ptr = nullptr; return *this; } // -1 restores a new shared ptr by restoring the inner pointer and creating a shared_ptr to it if (nr == -1) { - logger->debug("Creating new shared_ptr"); T* p = nullptr; bool neededDowncast; (*this) & neededDowncast & p; @@ -477,7 +579,6 @@ namespace ngcore // if we did downcast we need to store a shared_ptr to the true object if(neededDowncast) { - logger->debug("Shared pointer needed downcasting"); std::string name; (*this) & name; auto info = GetArchiveRegister(name); @@ -488,20 +589,15 @@ namespace ngcore ptr.get()))); } else - { - logger->debug("Shared pointer didn't need downcasting"); nr2shared_ptr.push_back(ptr); - } } else { - logger->debug("Reading already existing pointer at entry {}", nr); auto other = nr2shared_ptr[nr]; bool neededDowncast; (*this) & neededDowncast; if(neededDowncast) { - logger->debug("Shared pointer needed pointer downcast"); // if there was a downcast we can expect the class to be registered (since archiving // wouldn't have worked else) std::string name; @@ -515,7 +611,6 @@ namespace ngcore } else { - logger->debug("Shared pointer didn't need pointer casts"); ptr = std::static_pointer_cast(other); } } @@ -529,45 +624,39 @@ namespace ngcore { if (Output()) { - logger->debug("Store pointer of type {}",Demangle(typeid(T).name())); // if the pointer is null store -2 if (!p) - { - logger->debug("Storing nullptr"); return (*this) << -2; - } auto reg_ptr = static_cast(p); if(typeid(T) != typeid(*p)) { - logger->debug("Typeids are different: {} vs {}", - Demangle(typeid(T).name()), - Demangle(typeid(*p).name())); if(!IsRegistered(Demangle(typeid(*p).name()))) throw Exception(std::string("Archive error: Polymorphic type ") + Demangle(typeid(*p).name()) + " not registered for archive"); reg_ptr = GetArchiveRegister(Demangle(typeid(*p).name())).downcaster(typeid(T), static_cast(p)); - if(reg_ptr != static_cast(p)) - { - logger->debug("Multiple/Virtual inheritance involved, need to cast pointer"); - } } auto pos = ptr2nr.find(reg_ptr); // if the pointer is not found in the map create a new entry if (pos == ptr2nr.end()) { - logger->debug("Didn't find pointer, create new registry entry at {}", - ptr_count); ptr2nr[reg_ptr] = ptr_count++; if(typeid(*p) == typeid(T)) if (std::is_constructible::value) - { - logger->debug("Store standard class pointer (no virt. inh,...)"); - return (*this) << -1 & (*p); - } + return (*this) << -1 & (*p); else - throw Exception(std::string("Archive error: Class ") + - Demangle(typeid(*p).name()) + " does not provide a default constructor!"); + { + if (IsRegistered(Demangle(typeid(*p).name()))) + { + (*this) << -3 << Demangle(typeid(*p).name()); + GetArchiveRegister(Demangle(typeid(*p).name())). + cargs_archiver(*this, p); + return (*this) & (*p); + } + else + throw Exception(std::string("Archive error: Class ") + + Demangle(typeid(*p).name()) + " does not provide a default constructor!"); + } else { // if a pointer to a base class is archived, the class hierarchy must be registered @@ -578,49 +667,41 @@ namespace ngcore throw Exception(std::string("Archive error: Polymorphic type ") + Demangle(typeid(*p).name()) + " not registered for archive"); - logger->debug("Store a possibly more complicated pointer"); - return (*this) << -3 << Demangle(typeid(*p).name()) & (*p); + (*this) << -3 << Demangle(typeid(*p).name()); + GetArchiveRegister(Demangle(typeid(*p).name())). + cargs_archiver(*this, p); + return (*this) & (*p); } } else { (*this) & pos->second; bool downcasted = !(reg_ptr == static_cast(p) ); - logger->debug("Store a the existing position in registry at {}", pos->second); - logger->debug("Pointer {} downcasting", downcasted ? "needs" : "doesn't need"); // store if the class has been downcasted and the name (*this) << downcasted << Demangle(typeid(*p).name()); } } else { - logger->debug("Reading pointer of type {}", Demangle(typeid(T).name())); int nr; (*this) & nr; if (nr == -2) // restore a nullptr - { - logger->debug("Loading a nullptr"); p = nullptr; - } else if (nr == -1) // create a new pointer of standard type (no virtual or multiple inheritance,...) { - logger->debug("Load a new pointer to a simple class"); p = detail::constructIfPossible(); nr2ptr.push_back(p); (*this) & *p; } else if(nr == -3) // restore one of our registered classes that can have multiple inheritance,... { - logger->debug("Load a new pointer to a potentially more complicated class " - "(allows for multiple/virtual inheritance,...)"); // As stated above, we want this special behaviour only for our classes that implement DoArchive std::string name; (*this) & name; - logger->debug("Name = {}", name); auto info = GetArchiveRegister(name); // the creator creates a new object of type name, and returns a void* pointing // to T (which may have an offset) - p = static_cast(info.creator(typeid(T))); + p = static_cast(info.creator(typeid(T), *this)); // we store the downcasted pointer (to be able to find it again from // another class in a multiple inheritance tree) nr2ptr.push_back(info.downcaster(typeid(T),p)); @@ -628,11 +709,9 @@ namespace ngcore } else { - logger->debug("Restoring pointer to already existing object at registry position {}", nr); bool downcasted; std::string name; (*this) & downcasted & name; - logger->debug("{} object of type {}", downcasted ? "Downcasted" : "Not downcasted", name); if(downcasted) { // if the class has been downcasted we can assume it is in the register @@ -646,6 +725,16 @@ namespace ngcore return *this; } + Archive& operator&(std::tuple<>&) { return *this; } + + template + Archive& operator&(std::tuple &t) + { + // call operator& for each element of the tuple + std::apply([this](auto&... arg) { std::make_tuple(((*this) & arg).IsParallel()...);}, t); + return *this; + } + // const ptr template Archive& operator &(const T*& t) @@ -669,7 +758,7 @@ namespace ngcore void SetParallel (bool _parallel) { parallel = _parallel; } private: - template + template friend class RegisterClassForArchive; #ifdef NETGEN_PYTHON @@ -688,7 +777,7 @@ namespace ngcore struct Caster{}; template - struct Caster + struct Caster> { static void* tryUpcast (const std::type_info& /*unused*/, T* /*unused*/) { @@ -700,8 +789,37 @@ namespace ngcore } }; + template + struct Caster + { + static void* tryUpcast(const std::type_info& ti, T* p) + { + try { + return GetArchiveRegister(Demangle(typeid(B1).name())) + .upcaster(ti, static_cast(dynamic_cast(p))); + } catch (const Exception &) { + throw Exception("Upcast not successful, some classes are not " + "registered properly for archiving!"); + } + } + + static void* tryDowncast(const std::type_info& ti, void* p) + { + if(typeid(B1) == ti) + return dynamic_cast(static_cast(p)); + try + { + return dynamic_cast(static_cast(GetArchiveRegister(Demangle(typeid(B1).name())). + downcaster(ti, p))); + } catch (const Exception &) { + throw Exception("Downcast not successful, some classes are not " + "registered properly for archiving!"); + } + } + }; + template - struct Caster + struct Caster> { static void* tryUpcast(const std::type_info& ti, T* p) { @@ -709,7 +827,7 @@ namespace ngcore { return GetArchiveRegister(Demangle(typeid(B1).name())). upcaster(ti, static_cast(dynamic_cast(p))); } catch(const Exception&) - { return Caster::tryUpcast(ti, p); } + { return Caster>::tryUpcast(ti, p); } } static void* tryDowncast(const std::type_info& ti, void* p) @@ -723,7 +841,7 @@ namespace ngcore } catch(const Exception&) { - return Caster::tryDowncast(ti, p); + return Caster>::tryDowncast(ti, p); } } }; @@ -765,11 +883,19 @@ namespace ngcore Archive & operator & (long & i) override { // for platform independence - int64_t tmp = i; - return Write(tmp); + if constexpr (sizeof(long) == 8) + return Write(i); + else + return Write(static_cast(i)); } Archive & operator & (size_t & i) override - { return Write(i); } + { + // for platform independence + if constexpr (sizeof(size_t) == 8) + return Write(i); + else + return Write(static_cast(i)); + } Archive & operator & (unsigned char & i) override { return Write(i); } Archive & operator & (bool & b) override @@ -848,13 +974,30 @@ namespace ngcore { Read(i); return *this; } Archive & operator & (long & i) override { - int64_t tmp; - Read(tmp); - i = tmp; + // for platform independence + if constexpr (sizeof(long) == 8) + Read(i); + else + { + int64_t tmp = 0; + Read(tmp); + i = tmp; + } return *this; } Archive & operator & (size_t & i) override - { Read(i); return *this; } + { + // for platform independence + if constexpr (sizeof(long) == 8) + Read(i); + else + { + uint64_t tmp = 0; + Read(tmp); + i = tmp; + } + return *this; + } Archive & operator & (unsigned char & i) override { Read(i); return *this; } Archive & operator & (bool & b) override @@ -890,7 +1033,15 @@ namespace ngcore Archive & Do (int * i, size_t n) override { stream->read(reinterpret_cast(i), n*sizeof(int)); return *this; } // NOLINT Archive & Do (size_t * i, size_t n) override - { stream->read(reinterpret_cast(i), n*sizeof(size_t)); return *this; } // NOLINT + { + // for platform independence + if constexpr (sizeof(long) == 8) + stream->read(reinterpret_cast(i), n*sizeof(size_t)); // NOLINT + else + for(size_t j = 0; j < n; j++) + (*this) & i[j]; + return *this; + } private: template @@ -912,7 +1063,7 @@ namespace ngcore using Archive::operator&; Archive & operator & (std::byte & d) override - { *stream << std::hex << int(d) << ' '; return *this; } + { *stream << int(d) << ' '; return *this; } Archive & operator & (float & f) override { *stream << f << '\n'; return *this; } Archive & operator & (double & d) override @@ -967,7 +1118,7 @@ namespace ngcore using Archive::operator&; Archive & operator & (std::byte & d) override - { int tmp; *stream >> std::hex >> tmp; d = std::byte(tmp); return *this; } + { int tmp; *stream >> tmp; d = std::byte(tmp); return *this; } Archive & operator & (float & f) override { *stream >> f; return *this; } Archive & operator & (double & d) override @@ -986,15 +1137,32 @@ namespace ngcore { char c; *stream >> c; b = (c=='t'); return *this; } Archive & operator & (std::string & str) override { + // Ignore \r (carriage return) characters when reading strings + // this is necessary for instance when a file was written on Windows and is read on Unix + int len; *stream >> len; char ch; - stream->get(ch); // '\n' + stream->get(ch); // read newline character 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'); + + // remove all \r characters from the string, check if size changed + // if so, read the remaining characters + str.erase(std::remove(str.begin(), str.end(), '\r'), str.cend()); + size_t chars_to_read = len-str.size(); + while (chars_to_read>0) + { + auto old_size = str.size(); + str.resize(len); + + stream->get(&str[old_size], chars_to_read+1, '\0'); + str.erase(std::remove(str.begin()+old_size, str.end(), '\r'), str.cend()); + chars_to_read = len - str.size(); + } return *this; } Archive & operator & (char *& str) override diff --git a/libsrc/core/array.hpp b/libsrc/core/array.hpp index 170f51b8..94ce84a5 100644 --- a/libsrc/core/array.hpp +++ b/libsrc/core/array.hpp @@ -216,6 +216,10 @@ namespace ngcore template constexpr T IndexBASE () { return T(0); } + template + constexpr T IndexBASE (T ind) { return IndexBASE(); } + + class IndexFromEnd { @@ -278,7 +282,8 @@ namespace ngcore T first, next; public: NETGEN_INLINE T_Range () { ; } - NETGEN_INLINE T_Range (T n) : first(0), next(n) {;} + // NETGEN_INLINE T_Range (T n) : first(0), next(n) {;} + NETGEN_INLINE explicit T_Range (size_t n) : first(IndexBASE()), next(IndexBASE()+n) {;} NETGEN_INLINE T_Range (T f, T n) : first(f), next(n) {;} template NETGEN_INLINE T_Range(T_Range r2) : first(r2.First()), next(r2.Next()) { ; } @@ -296,7 +301,7 @@ namespace ngcore NETGEN_INLINE T_Range Split (size_t nr, int tot) const { - T diff = next-first; + auto diff = next-first; return T_Range (first + nr * diff / tot, first + (nr+1) * diff / tot); } @@ -554,6 +559,13 @@ namespace ngcore // { return CArray (data+pos); } NETGEN_INLINE T * operator+ (size_t pos) const { return data+pos; } + /// access first element. check by macro NETGEN_CHECK_RANGE + T & First () const + { + NETGEN_CHECK_RANGE(0,0,size); + return data[0]; + } + /// access last element. check by macro NETGEN_CHECK_RANGE T & Last () const { @@ -687,6 +699,7 @@ namespace ngcore size_t allocsize; /// that's the data we have to delete, nullptr for not owning the memory T * mem_to_delete; + MemoryTracer mt; using FlatArray::size; @@ -708,6 +721,7 @@ namespace ngcore { allocsize = asize; mem_to_delete = data; + mt.Alloc(sizeof(T)*asize); } @@ -717,7 +731,10 @@ namespace ngcore { allocsize = asize; if(ownMemory) + { mem_to_delete = adata; + mt.Alloc(sizeof(T)*asize); + } else mem_to_delete = nullptr; } @@ -733,8 +750,7 @@ namespace ngcore NETGEN_INLINE Array (Array && a2) { - mt.Swap(sizeof(T) * allocsize, a2.mt, sizeof(T) * a2.allocsize); - + mt = std::move(a2.mt); size = a2.size; data = a2.data; allocsize = a2.allocsize; @@ -753,6 +769,7 @@ namespace ngcore { allocsize = size; mem_to_delete = data; + mt.Alloc(sizeof(T)*size); for (size_t i = 0; i < size; i++) data[i] = a2.data[i]; } @@ -772,6 +789,7 @@ namespace ngcore { allocsize = size; mem_to_delete = data; + mt.Alloc(sizeof(T)*size); /* for (size_t i = 0; i < size; i++) data[i] = a2[i]; @@ -788,6 +806,7 @@ namespace ngcore { allocsize = size; mem_to_delete = data; + mt.Alloc(sizeof(T)*size); size_t cnt = 0; for (auto val : list) data[cnt++] = val; @@ -800,6 +819,7 @@ namespace ngcore { allocsize = size; mem_to_delete = data; + mt.Alloc(sizeof(T)*size); for(size_t i = 0; i < a2.Size(); i++) data[i] = a2[i]; for (size_t i = a2.Size(), j=0; i < size; i++,j++) @@ -834,6 +854,9 @@ namespace ngcore NETGEN_INLINE void NothingToDelete () { mem_to_delete = nullptr; + + // this memory is not managed by the Array anymore, so set the memory usage to 0 + mt.Free(sizeof(T)*allocsize); } /// Change logical size. If necessary, do reallocation. Keeps contents. @@ -947,7 +970,7 @@ namespace ngcore /// Delete element i. Move last element to position i. - NETGEN_INLINE void DeleteElement (size_t i) + NETGEN_INLINE void DeleteElement (IndexType i) { NETGEN_CHECK_RANGE(i,BASE,BASE+size); data[i-BASE] = std::move(data[size-1]); @@ -956,10 +979,10 @@ namespace ngcore /// Delete element i. Move all remaining elements forward - NETGEN_INLINE void RemoveElement (size_t i) + NETGEN_INLINE void RemoveElement (IndexType i) { NETGEN_CHECK_RANGE(i, BASE, BASE+size); - for(size_t j = i; j < this->size-1; j++) + for(size_t j = i-BASE; j+1 < this->size; j++) this->data[j] = this->data[j+1]; this->size--; } @@ -1001,16 +1024,17 @@ namespace ngcore data[i] = a2.data[i]; return *this; } +#ifndef __CUDA_ARCH__ else throw Exception(std::string("cannot copy Array of type ") + typeid(T).name()); +#endif } /// steal array NETGEN_INLINE Array & operator= (Array && a2) { - mt.Swap(sizeof(T)*allocsize, a2.mt, sizeof(T)*a2.allocsize); - + mt = std::move(a2.mt); ngcore::Swap (size, a2.size); ngcore::Swap (data, a2.data); ngcore::Swap (allocsize, a2.allocsize); @@ -1084,8 +1108,7 @@ namespace ngcore NETGEN_INLINE void Swap (Array & b) { - mt.Swap(sizeof(T) * allocsize, b.mt, sizeof(T) * b.allocsize); - + mt = std::move(b.mt); ngcore::Swap (size, b.size); ngcore::Swap (data, b.data); ngcore::Swap (allocsize, b.allocsize); @@ -1094,7 +1117,8 @@ namespace ngcore NETGEN_INLINE void StartMemoryTracing () const { - mt.Alloc(sizeof(T) * allocsize); + if(mem_to_delete) + mt.Alloc(sizeof(T) * allocsize); } const MemoryTracer& GetMemoryTracer() const { return mt; } @@ -1103,7 +1127,6 @@ namespace ngcore /// resize array, at least to size minsize. copy contents NETGEN_INLINE void ReSize (size_t minsize); - MemoryTracer mt; }; @@ -1156,6 +1179,7 @@ namespace ngcore using Array::allocsize; using Array::data; using Array::mem_to_delete; + using Array::mt; // using Array::ownmem; public: @@ -1169,6 +1193,7 @@ namespace ngcore data = new T[asize]; allocsize = size; mem_to_delete = data; + mt.Alloc(sizeof(T)*asize); } } @@ -1189,6 +1214,7 @@ namespace ngcore ArrayMem(ArrayMem && a2) : Array (a2.Size(), (T*)mem) { + mt = std::move(a2.mt); if (a2.mem_to_delete) { mem_to_delete = a2.mem_to_delete; @@ -1231,6 +1257,7 @@ namespace ngcore ArrayMem & operator= (ArrayMem && a2) { + mt = std::move(a2.mt); ngcore::Swap (mem_to_delete, a2.mem_to_delete); ngcore::Swap (allocsize, a2.allocsize); ngcore::Swap (size, a2.size); @@ -1526,6 +1553,8 @@ namespace ngcore } + struct HTAHelp { }; + // head-tail array template class HTArray @@ -1533,10 +1562,22 @@ namespace ngcore HTArray tail; T head; public: - HTArray () = default; - HTArray (const HTArray &) = default; + constexpr HTArray () = default; + constexpr HTArray (const HTArray &) = default; template - HTArray (const HTArray & a2) : tail(a2.Tail()), head(a2.Head()) { ; } + constexpr HTArray (const HTArray & a2) : tail(a2.Tail()), head(a2.Head()) { ; } + + constexpr HTArray (T v) : tail(v), head(v) { } // all the same + + template = true> + constexpr HTArray (const T &v, T2... rest) + : tail{HTAHelp(), v,rest...}, head(std::get(std::tuple(rest...))) { } + + template + constexpr HTArray (HTAHelp h, const T &v, T2... rest) + : tail{h, v,rest...}, head(std::get(std::tuple(rest...))) { } + HTArray & operator= (const HTArray &) = default; @@ -1557,10 +1598,15 @@ namespace ngcore { T head; public: - HTArray () = default; - HTArray (const HTArray &) = default; + constexpr HTArray () = default; + constexpr HTArray (const HTArray &) = default; template - HTArray (const HTArray<1,T2> & a2) : head(a2.Head()) { ; } + constexpr HTArray (const HTArray<1,T2> & a2) : head(a2.Head()) { ; } + constexpr HTArray (T v) : head(v) { } // all the same + template + constexpr HTArray (HTAHelp h, const T &v, T2... rest) + : head(v) { } + HTArray & operator= (const HTArray &) = default; @@ -1588,7 +1634,7 @@ namespace ngcore HTArray (const HTArray &) = default; template HTArray (const HTArray<0,T2> & a2) { ; } - + constexpr HTArray (T v) { } // all the same HTArray & operator= (const HTArray &) = default; /* diff --git a/libsrc/core/autodiff.hpp b/libsrc/core/autodiff.hpp new file mode 100644 index 00000000..dda8fc78 --- /dev/null +++ b/libsrc/core/autodiff.hpp @@ -0,0 +1,1131 @@ +#ifndef FILE_AUTODIFF +#define FILE_AUTODIFF + +/**************************************************************************/ +/* File: autodiff.hpp */ +/* Author: Joachim Schoeberl */ +/* Date: 24. Oct. 02 */ +/**************************************************************************/ + +namespace ngcore +{ + using ngcore::IfPos; + +// Automatic differentiation datatype + + template class AutoDiffRec; + + +/** + Datatype for automatic differentiation. + Contains function value and D derivatives. Algebraic + operations are overloaded by using product-rule etc. etc. +**/ +template +class AutoDiffVec +{ + SCAL val; + SCAL dval[D?D:1]; +public: + + typedef AutoDiffVec TELEM; + typedef SCAL TSCAL; + + + /// elements are undefined + // NETGEN_INLINE AutoDiffVec () throw() { }; + AutoDiffVec() = default; + // { val = 0; for (int i = 0; i < D; i++) dval[i] = 0; } // ! + + /// copy constructor + AutoDiffVec (const AutoDiffVec & ad2) = default; + /* + NETGEN_INLINE AutoDiffVec (const AutoDiffVec & ad2) throw() + { + val = ad2.val; + for (int i = 0; i < D; i++) + dval[i] = ad2.dval[i]; + } + */ + /// initial object with constant value + NETGEN_INLINE AutoDiffVec (SCAL aval) throw() + { + val = aval; + for (int i = 0; i < D; i++) + dval[i] = 0; + } + + /// init object with (val, e_diffindex) + NETGEN_INLINE AutoDiffVec (SCAL aval, int diffindex) throw() + { + val = aval; + for (int i = 0; i < D; i++) + dval[i] = 0; + dval[diffindex] = 1; + } + + NETGEN_INLINE AutoDiffVec (SCAL aval, const SCAL * grad) + { + val = aval; + LoadGradient (grad); + } + + /// assign constant value + NETGEN_INLINE AutoDiffVec & operator= (SCAL aval) throw() + { + val = aval; + for (int i = 0; i < D; i++) + dval[i] = 0; + return *this; + } + + AutoDiffVec & operator= (const AutoDiffVec & ad2) = default; + + /// returns value + NETGEN_INLINE SCAL Value() const throw() { return val; } + + /// returns partial derivative + NETGEN_INLINE SCAL DValue (int i) const throw() { return dval[i]; } + + /// + NETGEN_INLINE void StoreGradient (SCAL * p) const + { + for (int i = 0; i < D; i++) + p[i] = dval[i]; + } + + NETGEN_INLINE void LoadGradient (const SCAL * p) + { + for (int i = 0; i < D; i++) + dval[i] = p[i]; + } + + /// access value + NETGEN_INLINE SCAL & Value() throw() { return val; } + + /// accesses partial derivative + NETGEN_INLINE SCAL & DValue (int i) throw() { return dval[i]; } +}; + + +//@{ AutoDiffVec helper functions. + +/// prints AutoDiffVec +template +inline ostream & operator<< (ostream & ost, const AutoDiffVec & x) +{ + ost << x.Value() << ", D = "; + for (int i = 0; i < D; i++) + ost << x.DValue(i) << " "; + return ost; +} + +/// AutoDiffVec plus AutoDiffVec +template +NETGEN_INLINE AutoDiffVec operator+ (const AutoDiffVec & x, const AutoDiffVec & y) throw() +{ + AutoDiffVec res; + res.Value () = x.Value()+y.Value(); + // AutoDiffVec res(x.Value()+y.Value()); + for (int i = 0; i < D; i++) + res.DValue(i) = x.DValue(i) + y.DValue(i); + return res; +} + + +/// AutoDiffVec minus AutoDiffVec +template +NETGEN_INLINE AutoDiffVec operator- (const AutoDiffVec & x, const AutoDiffVec & y) throw() +{ + AutoDiffVec res; + res.Value() = x.Value()-y.Value(); + // AutoDiffVec res (x.Value()-y.Value()); + for (int i = 0; i < D; i++) + res.DValue(i) = x.DValue(i) - y.DValue(i); + return res; +} + +/// double plus AutoDiffVec + template::value, int>::type = 0> +NETGEN_INLINE AutoDiffVec operator+ (SCAL2 x, const AutoDiffVec & y) throw() +{ + AutoDiffVec res; + res.Value() = x+y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = y.DValue(i); + return res; +} + +/// AutoDiffVec plus double + template::value, int>::type = 0> +NETGEN_INLINE AutoDiffVec operator+ (const AutoDiffVec & y, SCAL2 x) throw() +{ + AutoDiffVec res; + res.Value() = x+y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = y.DValue(i); + return res; +} + + +/// minus AutoDiffVec +template +NETGEN_INLINE AutoDiffVec operator- (const AutoDiffVec & x) throw() +{ + AutoDiffVec res; + res.Value() = -x.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = -x.DValue(i); + return res; +} + +/// AutoDiffVec minus double + template::value, int>::type = 0> +NETGEN_INLINE AutoDiffVec operator- (const AutoDiffVec & x, SCAL2 y) throw() +{ + AutoDiffVec res; + res.Value() = x.Value()-y; + for (int i = 0; i < D; i++) + res.DValue(i) = x.DValue(i); + return res; +} + +/// + template::value, int>::type = 0> +NETGEN_INLINE AutoDiffVec operator- (SCAL2 x, const AutoDiffVec & y) throw() +{ + AutoDiffVec res; + res.Value() = x-y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = -y.DValue(i); + return res; +} + + +/// double times AutoDiffVec + template::value, int>::type = 0> +NETGEN_INLINE AutoDiffVec operator* (SCAL2 x, const AutoDiffVec & y) throw() +{ + AutoDiffVec res; + res.Value() = x*y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = x*y.DValue(i); + return res; +} + +/// AutoDiffVec times double + template::value, int>::type = 0> + + NETGEN_INLINE AutoDiffVec operator* (const AutoDiffVec & y, SCAL2 x) throw() +{ + AutoDiffVec res; + res.Value() = x*y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = x*y.DValue(i); + return res; +} + +/// AutoDiffVec times AutoDiffVec +template +NETGEN_INLINE AutoDiffVec operator* (const AutoDiffVec & x, const AutoDiffVec & y) throw() +{ + AutoDiffVec res; + SCAL hx = x.Value(); + SCAL hy = y.Value(); + + res.Value() = hx*hy; + for (int i = 0; i < D; i++) + res.DValue(i) = hx*y.DValue(i) + hy*x.DValue(i); + + return res; +} + +/// AutoDiffVec times AutoDiffVec +using ngcore::sqr; +template +NETGEN_INLINE AutoDiffVec sqr (const AutoDiffVec & x) throw() +{ + AutoDiffVec res; + SCAL hx = x.Value(); + res.Value() = hx*hx; + hx *= 2; + for (int i = 0; i < D; i++) + res.DValue(i) = hx*x.DValue(i); + return res; +} + +/// Inverse of AutoDiffVec +template +NETGEN_INLINE AutoDiffVec Inv (const AutoDiffVec & x) +{ + AutoDiffVec res(1.0 / x.Value()); + for (int i = 0; i < D; i++) + res.DValue(i) = -x.DValue(i) / (x.Value() * x.Value()); + return res; +} + + +/// AutoDiffVec div AutoDiffVec +template +NETGEN_INLINE AutoDiffVec operator/ (const AutoDiffVec & x, const AutoDiffVec & y) +{ + return x * Inv (y); +} + +/// AutoDiffVec div double +template::value, int>::type = 0> +NETGEN_INLINE AutoDiffVec operator/ (const AutoDiffVec & x, SCAL2 y) +{ + return (1.0/y) * x; +} + + /// double div AutoDiffVec +template::value, int>::type = 0> + NETGEN_INLINE AutoDiffVec operator/ (SCAL2 x, const AutoDiffVec & y) + { + return x * Inv(y); + } + + + + + template + NETGEN_INLINE AutoDiffVec & operator+= (AutoDiffVec & x, SCAL2 y) throw() + { + x.Value() += y; + return x; + } + + + /// + template + NETGEN_INLINE AutoDiffVec & operator+= (AutoDiffVec & x, AutoDiffVec y) + { + x.Value() += y.Value(); + for (int i = 0; i < D; i++) + x.DValue(i) += y.DValue(i); + return x; + } + + /// + template + NETGEN_INLINE AutoDiffVec & operator-= (AutoDiffVec & x, AutoDiffVec y) + { + x.Value() -= y.Value(); + for (int i = 0; i < D; i++) + x.DValue(i) -= y.DValue(i); + return x; + + } + + template + NETGEN_INLINE AutoDiffVec & operator-= (AutoDiffVec & x, SCAL2 y) + { + x.Value() -= y; + return x; + } + + /// + template + NETGEN_INLINE AutoDiffVec & operator*= (AutoDiffVec & x, AutoDiffVec y) + { + for (int i = 0; i < D; i++) + x.DValue(i) = x.DValue(i)*y.Value() + x.Value() * y.DValue(i); + x.Value() *= y.Value(); + return x; + } + + /// + template + NETGEN_INLINE AutoDiffVec & operator*= (AutoDiffVec & x, SCAL2 y) + { + x.Value() *= y; + for (int i = 0; i < D; i++) + x.DValue(i) *= y; + return x; + } + + /// + template + NETGEN_INLINE AutoDiffVec & operator/= (AutoDiffVec & x, SCAL y) + { + SCAL iy = 1.0 / y; + x.Value() *= iy; + for (int i = 0; i < D; i++) + x.DValue(i) *= iy; + return x; + } + + + + + /// + template + NETGEN_INLINE bool operator== (AutoDiffVec x, SCAL val2) + { + return x.Value() == val2; + } + + /// + template + NETGEN_INLINE bool operator!= (AutoDiffVec x, SCAL val2) throw() + { + return x.Value() != val2; + } + + /// + template + NETGEN_INLINE bool operator< (AutoDiffVec x, SCAL val2) throw() + { + return x.Value() < val2; + } + + /// + template + NETGEN_INLINE bool operator> (AutoDiffVec x, SCAL val2) throw() + { + return x.Value() > val2; + } + + + + +template +NETGEN_INLINE AutoDiffVec fabs (const AutoDiffVec & x) +{ + double abs = fabs (x.Value()); + AutoDiffVec res( abs ); + if (abs != 0.0) + for (int i = 0; i < D; i++) + res.DValue(i) = x.Value()*x.DValue(i) / abs; + else + for (int i = 0; i < D; i++) + res.DValue(i) = 0.0; + return res; +} + +using std::sqrt; +template +NETGEN_INLINE AutoDiffVec sqrt (const AutoDiffVec & x) +{ + AutoDiffVec res; + res.Value() = sqrt(x.Value()); + for (int j = 0; j < D; j++) + res.DValue(j) = 0.5 / res.Value() * x.DValue(j); + return res; +} + +using std::log; +template +AutoDiffVec log (AutoDiffVec x) +{ + AutoDiffVec res; + res.Value() = log(x.Value()); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k) / x.Value(); + return res; +} + +using std::exp; +template +NETGEN_INLINE AutoDiffVec exp (AutoDiffVec x) +{ + AutoDiffVec res; + res.Value() = exp(x.Value()); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k) * res.Value(); + return res; +} + +using std::pow; +template +NETGEN_INLINE AutoDiffVec pow (AutoDiffVec x, AutoDiffVec y ) +{ + return exp(log(x)*y); +} + +using std::sin; +/* +template +NETGEN_INLINE AutoDiffVec sin (AutoDiffVec x) +{ + AutoDiffVec res; + res.Value() = sin(x.Value()); + SCAL c = cos(x.Value()); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k) * c; + return res; +} +*/ + +template +NETGEN_INLINE AutoDiffVec sin (AutoDiffVec x) +{ + return sin(AutoDiffRec(x)); +} + +using std::cos; +/* +template +NETGEN_INLINE AutoDiffVec cos (AutoDiffVec x) +{ + AutoDiffVec res; + res.Value() = cos(x.Value()); + SCAL ms = -sin(x.Value()); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k) * ms; + return res; +} +*/ +template +NETGEN_INLINE AutoDiffVec cos (AutoDiffVec x) +{ + return cos(AutoDiffRec(x)); +} + +using std::tan; +template +NETGEN_INLINE AutoDiffVec tan (AutoDiffVec x) +{ return sin(x) / cos(x); } + +using std::sinh; +template +NETGEN_INLINE AutoDiffVec sinh (AutoDiffVec x) +{ + AutoDiffVec res; + res.Value() = sinh(x.Value()); + SCAL ch = cosh(x.Value()); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k) * ch; + return res; +} + +using std::cosh; +template +NETGEN_INLINE AutoDiffVec cosh (AutoDiffVec x) +{ + AutoDiffVec res; + res.Value() = cosh(x.Value()); + SCAL sh = sinh(x.Value()); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k) * sh; + return res; +} + +using std::erf; +template +NETGEN_INLINE AutoDiffVec erf (AutoDiffVec x) +{ + return erf(AutoDiffRec(x)); +} + +using std::floor; +template +NETGEN_INLINE AutoDiffVec floor (const AutoDiffVec & x) +{ + AutoDiffVec res; + res.Value() = floor(x.Value()); + for (int j = 0; j < D; j++) + res.DValue(j) = 0.0; + return res; +} + +using std::ceil; +template +NETGEN_INLINE AutoDiffVec ceil (const AutoDiffVec & x) +{ + AutoDiffVec res; + res.Value() = ceil(x.Value()); + for (int j = 0; j < D; j++) + res.DValue(j) = 0.0; + return res; +} + + +using std::atan; +/* +template +NETGEN_INLINE AutoDiffVec atan (AutoDiffVec x) +{ + AutoDiffVec res; + SCAL a = atan(x.Value()); + res.Value() = a; + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k)/(1+x.Value()*x.Value()) ; + return res; +} +*/ +template +AutoDiffVec atan (AutoDiffVec x) +{ + return atan (AutoDiffRec (x)); +} + +using std::atan2; +template +NETGEN_INLINE AutoDiffVec atan2 (AutoDiffVec x, AutoDiffVec y) +{ + AutoDiffVec res; + SCAL a = atan2(x.Value(), y.Value()); + res.Value() = a; + for (int k = 0; k < D; k++) + res.DValue(k) = (x.Value()*y.DValue(k)-y.Value()*x.DValue(k))/(y.Value()*y.Value()+x.Value()*x.Value()); + return res; +} + + +using std::acos; +template +NETGEN_INLINE AutoDiffVec acos (AutoDiffVec x) +{ + AutoDiffVec res; + SCAL a = acos(x.Value()); + res.Value() = a; + SCAL da = -1 / sqrt(1-x.Value()*x.Value()); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k)*da; + return res; +} + + +using std::asin; +template +NETGEN_INLINE AutoDiffVec asin (AutoDiffVec x) +{ + AutoDiffVec res; + SCAL a = asin(x.Value()); + res.Value() = a; + SCAL da = 1 / sqrt(1-x.Value()*x.Value()); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k)*da; + return res; +} + + + + + template + auto IfPos (AutoDiffVec a, TB b, TC c) // -> decltype(IfPos (a.Value(), b, c)) + { + return IfPos (a.Value(), b, c); + } + + template + NETGEN_INLINE AutoDiffVec IfPos (SCAL /* SIMD */ a, AutoDiffVec b, AutoDiffVec c) + { + AutoDiffVec res; + res.Value() = IfPos (a, b.Value(), c.Value()); + for (int j = 0; j < D; j++) + res.DValue(j) = IfPos (a, b.DValue(j), c.DValue(j)); + return res; + } + + template + NETGEN_INLINE AutoDiffVec IfPos (SCAL /* SIMD */ a, AutoDiffVec b, TC c) + { + return IfPos (a, b, AutoDiffVec (c)); + } + +//@} + + + + template + class AutoDiffRec + { + AutoDiffRec rec; + SCAL last; + + public: + NETGEN_INLINE AutoDiffRec () = default; + NETGEN_INLINE AutoDiffRec (const AutoDiffRec &) = default; + NETGEN_INLINE AutoDiffRec (AutoDiffRec _rec, SCAL _last) : rec(_rec), last(_last) { ; } + NETGEN_INLINE AutoDiffRec & operator= (const AutoDiffRec &) = default; + + NETGEN_INLINE AutoDiffRec (SCAL aval) : rec(aval), last(0.0) { ; } + NETGEN_INLINE AutoDiffRec (SCAL aval, int diffindex) : rec(aval, diffindex), last((diffindex==D-1) ? 1.0 : 0.0) { ; } + NETGEN_INLINE AutoDiffRec (SCAL aval, const SCAL * grad) + : rec(aval, grad), last(grad[D-1]) { } + + NETGEN_INLINE AutoDiffRec (const AutoDiffVec & ad) + { + Value() = ad.Value(); + for (int i = 0; i < D; i++) + DValue(i) = ad.DValue(i); + } + + NETGEN_INLINE AutoDiffRec & operator= (SCAL aval) { rec = aval; last = 0.0; return *this; } + NETGEN_INLINE SCAL Value() const { return rec.Value(); } + NETGEN_INLINE SCAL DValue(int i) const { return (i == D-1) ? last : rec.DValue(i); } + NETGEN_INLINE SCAL & Value() { return rec.Value(); } + NETGEN_INLINE SCAL & DValue(int i) { return (i == D-1) ? last : rec.DValue(i); } + NETGEN_INLINE auto Rec() const { return rec; } + NETGEN_INLINE auto Last() const { return last; } + NETGEN_INLINE auto & Rec() { return rec; } + NETGEN_INLINE auto & Last() { return last; } + NETGEN_INLINE operator AutoDiffVec () const + { + AutoDiffVec res(Value()); + for (int i = 0; i < D; i++) + res.DValue(i) = DValue(i); + return res; + } + }; + + template + ostream & operator<< (ostream & ost, AutoDiffRec ad) + { + return ost << AutoDiffVec (ad); + } + + template + class AutoDiffRec<0,SCAL> + { + SCAL val; + public: + NETGEN_INLINE AutoDiffRec () = default; + NETGEN_INLINE AutoDiffRec (const AutoDiffRec &) = default; + NETGEN_INLINE AutoDiffRec (SCAL _val) : val(_val) { ; } + NETGEN_INLINE AutoDiffRec (SCAL _val, SCAL /* _dummylast */) : val(_val) { ; } + NETGEN_INLINE AutoDiffRec (SCAL aval, const SCAL * /* grad */) + : val(aval) { } + + NETGEN_INLINE AutoDiffRec & operator= (const AutoDiffRec &) = default; + NETGEN_INLINE AutoDiffRec & operator= (SCAL aval) { val = aval; return *this; } + + NETGEN_INLINE SCAL Value() const { return val; } + NETGEN_INLINE SCAL DValue(int /* i */) const { return SCAL(0); } + NETGEN_INLINE SCAL & Value() { return val; } + // SCAL & DValue(int i) { return val; } + NETGEN_INLINE auto Rec() const { return val; } + NETGEN_INLINE auto Last() const { return SCAL(0); } + NETGEN_INLINE auto & Rec() { return val; } + NETGEN_INLINE auto & Last() { return val; } + NETGEN_INLINE operator AutoDiffVec<0,SCAL> () const { return AutoDiffVec<0,SCAL>(); } + }; + + + template + class AutoDiffRec<1,SCAL> + { + SCAL val; + SCAL last; + public: + NETGEN_INLINE AutoDiffRec () = default; + NETGEN_INLINE AutoDiffRec (const AutoDiffRec &) = default; + NETGEN_INLINE AutoDiffRec (SCAL _val) : val(_val), last(0.0) { ; } + NETGEN_INLINE AutoDiffRec (SCAL _val, SCAL _last) : val(_val), last(_last) { ; } + NETGEN_INLINE AutoDiffRec (SCAL aval, int diffindex) : val(aval), last((diffindex==0) ? 1.0 : 0.0) { ; } + NETGEN_INLINE AutoDiffRec (SCAL aval, const SCAL * grad) + : val(aval), last(grad[0]) { } + + NETGEN_INLINE AutoDiffRec (const AutoDiffVec<1,SCAL> & ad) + { + Value() = ad.Value(); + DValue(0) = ad.DValue(0); + } + + NETGEN_INLINE AutoDiffRec & operator= (const AutoDiffRec &) = default; + NETGEN_INLINE AutoDiffRec & operator= (SCAL aval) { val = aval; last = 0.0; return *this; } + + NETGEN_INLINE SCAL Value() const { return val; } + NETGEN_INLINE SCAL DValue(int /* i */) const { return last; } + NETGEN_INLINE SCAL & Value() { return val; } + NETGEN_INLINE SCAL & DValue(int /* i */) { return last; } + NETGEN_INLINE auto Rec() const { return val; } + NETGEN_INLINE auto Last() const { return last; } + NETGEN_INLINE auto & Rec() { return val; } + NETGEN_INLINE auto & Last() { return last; } + + NETGEN_INLINE operator AutoDiffVec<1,SCAL> () const + { + AutoDiffVec<1,SCAL> res(Value()); + res.DValue(0) = DValue(0); + return res; + } + }; + + template ::value, int>::type = 0> + NETGEN_INLINE AutoDiffRec operator+ (SCAL2 a, AutoDiffRec b) + { + return AutoDiffRec (a+b.Rec(), b.Last()); + } + + template ::value, int>::type = 0> + NETGEN_INLINE AutoDiffRec operator+ (AutoDiffRec a, SCAL2 b) + { + return AutoDiffRec (a.Rec()+b, a.Last()); + } + + template + NETGEN_INLINE AutoDiffRec operator+ (AutoDiffRec a, AutoDiffRec b) + { + return AutoDiffRec (a.Rec()+b.Rec(), a.Last()+b.Last()); + } + + template ::value, int>::type = 0> + NETGEN_INLINE AutoDiffRec operator- (SCAL2 b, AutoDiffRec a) + { + return AutoDiffRec (b-a.Rec(), -a.Last()); + } + + template ::value, int>::type = 0> + NETGEN_INLINE AutoDiffRec operator- (AutoDiffRec a, SCAL2 b) + { + return AutoDiffRec (a.Rec()-b, a.Last()); + } + + template + NETGEN_INLINE AutoDiffRec operator- (AutoDiffRec a, AutoDiffRec b) + { + return AutoDiffRec (a.Rec()-b.Rec(), a.Last()-b.Last()); + } + + /// minus AutoDiff + template + NETGEN_INLINE AutoDiffRec operator- (AutoDiffRec a) + { + return AutoDiffRec (-a.Rec(), -a.Last()); + } + + template + NETGEN_INLINE AutoDiffRec operator* (AutoDiffRec a, AutoDiffRec b) + { + return AutoDiffRec (a.Rec()*b.Rec(), a.Value()*b.Last()+b.Value()*a.Last()); + } + + template ::value, int>::type = 0> + NETGEN_INLINE AutoDiffRec operator* (AutoDiffRec b, SCAL1 a) + { + return AutoDiffRec (a*b.Rec(), a*b.Last()); + } + + template ::value, int>::type = 0> + NETGEN_INLINE AutoDiffRec operator* (SCAL1 a, AutoDiffRec b) + { + return AutoDiffRec (a*b.Rec(), a*b.Last()); + } + + template + NETGEN_INLINE AutoDiffRec & operator+= (AutoDiffRec & a, AutoDiffRec b) + { + a.Rec() += b.Rec(); + a.Last() += b.Last(); + return a; + } + + template + NETGEN_INLINE AutoDiffRec & operator-= (AutoDiffRec & a, double b) + { + a.Rec() -= b; + return a; + } + + template + NETGEN_INLINE AutoDiffRec & operator-= (AutoDiffRec & a, AutoDiffRec b) + { + a.Rec() -= b.Rec(); + a.Last() -= b.Last(); + return a; + } + + + template + NETGEN_INLINE AutoDiffRec & operator*= (AutoDiffRec & a, AutoDiffRec b) + { + a = a*b; + return a; + } + + + template + NETGEN_INLINE AutoDiffRec & operator*= (AutoDiffRec & b, SCAL2 a) + { + b.Rec() *= a; + b.Last() *= a; + return b; + } + + /// Inverse of AutoDiffRec + + template + auto Inv1 (SCAL x) { return 1.0/x; } + + template + NETGEN_INLINE AutoDiffRec Inv1 (AutoDiffRec x) + { + return AutoDiffRec (Inv1(x.Rec()), (-sqr(1.0/x.Value())) * x.Last()); + } + + /// AutoDiffRec div AutoDiffRec + template + NETGEN_INLINE AutoDiffRec operator/ (const AutoDiffRec & x, const AutoDiffRec & y) + { + return x * Inv1 (y); + } + + + /// AutoDiffVec div double + template::value, int>::type = 0> + NETGEN_INLINE AutoDiffRec operator/ (const AutoDiffRec & x, SCAL2 y) + { + return (1.0/y) * x; + } + + + /// double div AutoDiffVec + template::value, int>::type = 0> + NETGEN_INLINE AutoDiffRec operator/ (SCAL2 x, const AutoDiffRec & y) + { + return x * Inv1(y); + } + + + + + + + + /// + template + NETGEN_INLINE bool operator== (AutoDiffRec x, SCAL val2) + { + return x.Value() == val2; + } + + /// + template + NETGEN_INLINE bool operator!= (AutoDiffRec x, SCAL val2) throw() + { + return x.Value() != val2; + } + + /// + template + NETGEN_INLINE bool operator< (AutoDiffRec x, SCAL val2) throw() + { + return x.Value() < val2; + } + + /// + template + NETGEN_INLINE bool operator> (AutoDiffRec x, SCAL val2) throw() + { + return x.Value() > val2; + } + + using std::fabs; + template + NETGEN_INLINE AutoDiffRec fabs (const AutoDiffRec & x) + { + auto sign = IfPos(x.Value(), SCAL(1.0), IfPos(-x.Value(), SCAL(-1.0), SCAL(0.0))); + return AutoDiffRec (fabs(x.Rec()), sign*x.Last()); + // return fabs (AutoDiffVec(x)); + /* + double abs = fabs (x.Value()); + AutoDiffVec res( abs ); + if (abs != 0.0) + for (int i = 0; i < D; i++) + res.DValue(i) = x.Value()*x.DValue(i) / abs; + else + for (int i = 0; i < D; i++) + res.DValue(i) = 0.0; + return res; + */ + } + + + template + NETGEN_INLINE auto sqrt (const AutoDiffRec & x) + { + return AutoDiffRec (sqrt(x.Rec()), (0.5/sqrt(x.Value()))*x.Last()); + } + + + + template + auto log (AutoDiffRec x) + { + return AutoDiffRec (log(x.Rec()), (1.0/x.Value())*x.Last()); + } + + template + auto exp (AutoDiffRec x) + { + return AutoDiffRec (exp(x.Rec()), exp(x.Value())*x.Last()); + } + + template + NETGEN_INLINE AutoDiffRec pow (AutoDiffRec x, AutoDiffRec y ) + { + return exp(log(x)*y); + } + + + template + auto sin (AutoDiffRec x) + { + return AutoDiffRec (sin(x.Rec()), cos(x.Value())*x.Last()); + } + + template + auto cos (AutoDiffRec x) + { + return AutoDiffRec (cos(x.Rec()), -sin(x.Value())*x.Last()); + } + + template + auto tan (AutoDiffRec x) + { + return sin(x) / cos(x); + } + + template + auto sinh (AutoDiffRec x) + { + return AutoDiffRec (sinh(x.Rec()), cosh(x.Value())*x.Last()); + } + + template + auto cosh (AutoDiffRec x) + { + return AutoDiffRec (cosh(x.Rec()), sinh(x.Value())*x.Last()); + } + + template + auto erf (AutoDiffRec x) + { + return AutoDiffRec (erf(x.Rec()), 2. / sqrt(M_PI) * exp(- x.Value() * x.Value())*x.Last()); + } + + template + auto floor (AutoDiffRec x) + { + return AutoDiffRec (floor(x.Rec()), 0.0); + } + + template + auto ceil (AutoDiffRec x) + { + return AutoDiffRec (ceil(x.Rec()), 0.0); + } + + + + template + auto atan (AutoDiffRec x) + { + return AutoDiffRec (atan(x.Rec()), (1./(1.+x.Value()*x.Value()))*x.Last()); + } + + template + auto atan2 (AutoDiffRec x, AutoDiffRec y) + { + return AutoDiffRec (atan2(x.Rec(), y.Rec()), + (1./(x.Value()*x.Value()+y.Value()*y.Value()))*(x.Value()*y.Last()-y.Value()*x.Last())); + } + + template + auto acos (AutoDiffRec x) + { + return AutoDiffRec (acos(x.Rec()), (-1./sqrt(1.-x.Value()*x.Value()))*x.Last()); + } + + template + auto asin (AutoDiffRec x) + { + return AutoDiffRec (asin(x.Rec()), (1./sqrt(1.-x.Value()*x.Value()))*x.Last()); + } + + + template + auto IfPos (AutoDiffRec a, TB b, TC c) // -> decltype(IfPos (a.Value(), b, c)) + { + return IfPos (a.Value(), b, c); + } + + template + NETGEN_INLINE AutoDiffRec IfPos (SCAL /* SIMD */ a, AutoDiffRec b, AutoDiffRec c) + { + /* + AutoDiffRec res; + res.Value() = IfPos (a, b.Value(), c.Value()); + for (int j = 0; j < D; j++) + res.DValue(j) = IfPos (a, b.DValue(j), c.DValue(j)); + return res; + */ + return AutoDiffRec (IfPos(a, b.Rec(), c.Rec()), IfPos(a, b.Last(), c.Last())); + } + + template + NETGEN_INLINE AutoDiffRec IfPos (SCAL /* SIMD */ a, AutoDiffRec b, TC c) + { + return IfPos (a, b, AutoDiffRec (c)); + } + + + +template +using AutoDiff = AutoDiffRec; + +} + + + +namespace ngbla +{ + template struct is_scalar_type; + template + struct is_scalar_type> { static constexpr bool value = true; }; + + // not meaningful for AutoDiff, since this is + // not (complex) differentiable anyway + template + inline auto L2Norm2 (const ngcore::AutoDiff & x) + { + return x*x; + } + + template + inline auto L2Norm (const ngcore::AutoDiff & x) throw() + { + return IfPos(x.Value(), x, -x); + } + + + + template + NETGEN_INLINE auto Conj (const ngcore::AutoDiff & a) + { + ngcore::AutoDiff b; + b.Value() = conj(a.Value()); + + for(int i=0;i +class AutoDiffDiff +{ + SCAL val; + SCAL dval[D?D:1]; + SCAL ddval[D?D*D:1]; +public: + + typedef AutoDiffDiff TELEM; + + + /// elements are undefined + AutoDiffDiff () throw() { ; } + + /// copy constructor + AutoDiffDiff (const AutoDiffDiff & ad2) throw() + { + val = ad2.val; + for (int i = 0; i < D; i++) + dval[i] = ad2.dval[i]; + for (int i = 0; i < D*D; i++) + ddval[i] = ad2.ddval[i]; + } + + /// initial object with constant value + AutoDiffDiff (SCAL aval) throw() + { + val = aval; + for (int i = 0; i < D; i++) + dval[i] = 0; + for (int i = 0; i < D*D; i++) + ddval[i] = 0; + } + + /// initial object with value and derivative + AutoDiffDiff (const AutoDiff & ad2) throw() + { + val = ad2.Value(); + for (int i = 0; i < D; i++) + dval[i] = ad2.DValue(i); + for (int i = 0; i < D*D; i++) + ddval[i] = 0; + } + + /// init object with (val, e_diffindex) + AutoDiffDiff (SCAL aval, int diffindex) throw() + { + val = aval; + for (int i = 0; i < D; i++) + dval[i] = 0; + for (int i = 0; i < D*D; i++) + ddval[i] = 0; + dval[diffindex] = 1; + } + + NETGEN_INLINE AutoDiffDiff (SCAL aval, const SCAL * grad) + { + val = aval; + LoadGradient (grad); + for (int i = 0; i < D*D; i++) + ddval[i] = 0; + } + + NETGEN_INLINE AutoDiffDiff (SCAL aval, const SCAL * grad, const SCAL * hesse) + { + val = aval; + LoadGradient (grad); + LoadHessian (hesse); + } + + /// assign constant value + AutoDiffDiff & operator= (SCAL aval) throw() + { + val = aval; + for (int i = 0; i < D; i++) + dval[i] = 0; + for (int i = 0; i < D*D; i++) + ddval[i] = 0; + return *this; + } + + NETGEN_INLINE void StoreGradient (SCAL * p) const + { + for (int i = 0; i < D; i++) + p[i] = dval[i]; + } + + NETGEN_INLINE void LoadGradient (const SCAL * p) + { + for (int i = 0; i < D; i++) + dval[i] = p[i]; + } + + NETGEN_INLINE void StoreHessian (SCAL * p) const + { + for (int i = 0; i < D*D; i++) + p[i] = ddval[i]; + } + + NETGEN_INLINE void LoadHessian (const SCAL * p) + { + for (int i = 0; i < D*D; i++) + ddval[i] = p[i]; + } + + /// returns value + SCAL Value() const throw() { return val; } + + /// returns partial derivative + SCAL DValue (int i) const throw() { return dval[i]; } + + AutoDiff DValueAD (int i) const + { + AutoDiff r(dval[i]); + for (int j = 0; j < D; j++) + r.DValue(j) = ddval[i*D+j]; + return r; + } + + /// returns partial derivative + SCAL DDValue (int i) const throw() { return ddval[i]; } + + /// returns partial derivative + SCAL DDValue (int i, int j) const throw() { return ddval[i*D+j]; } + + /// access value + SCAL & Value() throw() { return val; } + + /// accesses partial derivative + SCAL & DValue (int i) throw() { return dval[i]; } + + /// accesses partial derivative + SCAL & DDValue (int i) throw() { return ddval[i]; } + + /// accesses partial derivative + SCAL & DDValue (int i, int j) throw() { return ddval[i*D+j]; } + + explicit operator AutoDiff () const + { return AutoDiff (val, &dval[0]); } + + /// add autodiffdiff object + AutoDiffDiff & operator+= (const AutoDiffDiff & y) throw() + { + val += y.val; + for (int i = 0; i < D; i++) + dval[i] += y.dval[i]; + for (int i = 0; i < D*D; i++) + ddval[i] += y.ddval[i]; + return *this; + } + + /// subtract autodiffdiff object + AutoDiffDiff & operator-= (const AutoDiffDiff & y) throw() + { + val -= y.val; + for (int i = 0; i < D; i++) + dval[i] -= y.dval[i]; + for (int i = 0; i < D*D; i++) + ddval[i] -= y.ddval[i]; + return *this; + } + + /// multiply with autodiffdiff object + AutoDiffDiff & operator*= (const AutoDiffDiff & y) throw() + { + for (int i = 0; i < D*D; i++) + ddval[i] = val * y.ddval[i] + y.val * ddval[i]; + + for (int i = 0; i < D; i++) + for (int j = 0; j < D; j++) + ddval[i*D+j] += dval[i] * y.dval[j] + dval[j] * y.dval[i]; + + for (int i = 0; i < D; i++) + { + dval[i] *= y.val; + dval[i] += val * y.dval[i]; + } + val *= y.val; + return *this; + } + + /// multiply with scalar + AutoDiffDiff & operator*= (const SCAL & y) throw() + { + for ( int i = 0; i < D*D; i++ ) + ddval[i] *= y; + for (int i = 0; i < D; i++) + dval[i] *= y; + val *= y; + return *this; + } + + /// divide by scalar + AutoDiffDiff & operator/= (const SCAL & y) throw() + { + SCAL iy = 1.0 / y; + for ( int i = 0; i < D*D; i++ ) + ddval[i] *= iy; + for (int i = 0; i < D; i++) + dval[i] *= iy; + val *= iy; + return *this; + } + + /// same value + bool operator== (SCAL val2) throw() + { + return val == val2; + } + + /// different values + bool operator!= (SCAL val2) throw() + { + return val != val2; + } + + /// less + bool operator< (SCAL val2) throw() + { + return val < val2; + } + + /// greater + bool operator> (SCAL val2) throw() + { + return val > val2; + } +}; + + +//@{ AutoDiff helper functions. + +/// Prints AudoDiffDiff +template +inline ostream & operator<< (ostream & ost, const AutoDiffDiff & x) +{ + ost << x.Value() << ", D = "; + for (int i = 0; i < D; i++) + ost << x.DValue(i) << " "; + ost << ", DD = "; + for (int i = 0; i < D*D; i++) + ost << x.DDValue(i) << " "; + return ost; +} + +/// +template +inline AutoDiffDiff operator+ (const AutoDiffDiff & x, const AutoDiffDiff & y) throw() +{ + AutoDiffDiff res; + res.Value () = x.Value()+y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = x.DValue(i) + y.DValue(i); + for (int i = 0; i < D*D; i++) + res.DDValue(i) = x.DDValue(i) + y.DDValue(i); + return res; +} + + +/// +template +inline AutoDiffDiff operator- (const AutoDiffDiff & x, const AutoDiffDiff & y) throw() +{ + AutoDiffDiff res; + res.Value() = x.Value()-y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = x.DValue(i) - y.DValue(i); + for (int i = 0; i < D*D; i++) + res.DDValue(i) = x.DDValue(i) - y.DDValue(i); + return res; +} + + +/// +template::value, int>::type = 0> +inline AutoDiffDiff operator+ (SCAL2 x, const AutoDiffDiff & y) throw() +{ + AutoDiffDiff res; + res.Value() = x+y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = y.DValue(i); + for (int i = 0; i < D*D; i++) + res.DDValue(i) = y.DDValue(i); + return res; +} + +/// +template::value, int>::type = 0> +inline AutoDiffDiff operator+ (const AutoDiffDiff & y, SCAL2 x) throw() +{ + AutoDiffDiff res; + res.Value() = x+y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = y.DValue(i); + for (int i = 0; i < D*D; i++) + res.DDValue(i) = y.DDValue(i); + return res; +} + + +/// +template +inline AutoDiffDiff operator- (const AutoDiffDiff & x) throw() +{ + AutoDiffDiff res; + res.Value() = -x.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = -x.DValue(i); + for (int i = 0; i < D*D; i++) + res.DDValue(i) = -x.DDValue(i); + return res; +} + +/// +template::value, int>::type = 0> +inline AutoDiffDiff operator- (const AutoDiffDiff & x, SCAL2 y) throw() +{ + AutoDiffDiff res; + res.Value() = x.Value()-y; + for (int i = 0; i < D; i++) + res.DValue(i) = x.DValue(i); + for (int i = 0; i < D*D; i++) + res.DDValue(i) = x.DDValue(i); + return res; +} + +/// +template::value, int>::type = 0> +inline AutoDiffDiff operator- (SCAL2 x, const AutoDiffDiff & y) throw() +{ + AutoDiffDiff res; + res.Value() = x-y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = -y.DValue(i); + for (int i = 0; i < D*D; i++) + res.DDValue(i) = -y.DDValue(i); + return res; +} + + +/// +template::value, int>::type = 0> +inline AutoDiffDiff operator* (SCAL2 x, const AutoDiffDiff & y) throw() +{ + AutoDiffDiff res; + res.Value() = x*y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = x*y.DValue(i); + for (int i = 0; i < D*D; i++) + res.DDValue(i) = x*y.DDValue(i); + return res; +} + +/// +template::value, int>::type = 0> +inline AutoDiffDiff operator* (const AutoDiffDiff & y, SCAL2 x) throw() +{ + AutoDiffDiff res; + res.Value() = x*y.Value(); + for (int i = 0; i < D; i++) + res.DValue(i) = x*y.DValue(i); + for (int i = 0; i < D*D; i++) + res.DDValue(i) = x*y.DDValue(i); + return res; +} + +/// +template +inline AutoDiffDiff operator* (const AutoDiffDiff & x, const AutoDiffDiff & y) throw() +{ + AutoDiffDiff res; + SCAL hx = x.Value(); + SCAL hy = y.Value(); + + res.Value() = hx*hy; + for (int i = 0; i < D; i++) + res.DValue(i) = hx*y.DValue(i) + hy*x.DValue(i); + + for (int i = 0; i < D; i++) + for (int j = 0; j < D; j++) + res.DDValue(i,j) = hx * y.DDValue(i,j) + hy * x.DDValue(i,j) + + x.DValue(i) * y.DValue(j) + x.DValue(j) * y.DValue(i); + + return res; +} + + + +template +inline AutoDiffDiff Inv (const AutoDiffDiff & x) +{ + AutoDiffDiff res(1.0 / x.Value()); + for (int i = 0; i < D; i++) + res.DValue(i) = -x.DValue(i) / (x.Value() * x.Value()); + + SCAL fac1 = 2/(x.Value()*x.Value()*x.Value()); + SCAL fac2 = 1/sqr(x.Value()); + for (int i = 0; i < D; i++) + for (int j = 0; j < D; j++) + res.DDValue(i,j) = fac1*x.DValue(i)*x.DValue(j) - fac2*x.DDValue(i,j); + return res; +} + + +template +inline AutoDiffDiff operator/ (const AutoDiffDiff & x, const AutoDiffDiff & y) +{ + return x * Inv (y); +} + +template::value, int>::type = 0> +inline AutoDiffDiff operator/ (const AutoDiffDiff & x, SCAL2 y) +{ + return (1/y) * x; +} + +template::value, int>::type = 0> +inline AutoDiffDiff operator/ (SCAL2 x, const AutoDiffDiff & y) +{ + return x * Inv(y); +} + + +template +inline AutoDiffDiff sqrt (const AutoDiffDiff & x) +{ + AutoDiffDiff res; + res.Value() = sqrt(x.Value()); + for (int j = 0; j < D; j++) + res.DValue(j) = IfZero(x.DValue(j),SCAL{0.},0.5 / res.Value() * x.DValue(j)); + + + for (int i = 0; i < D; i++) + for (int j = 0; j < D; j++) + res.DDValue(i,j) = IfZero(x.DDValue(i,j)+x.DValue(i) * x.DValue(j),SCAL{0.},0.5/res.Value() * x.DDValue(i,j) - 0.25 / (x.Value()*res.Value()) * x.DValue(i) * x.DValue(j)); + + return res; +} + +// df(u)/dx = exp(x) * du/dx +// d^2 f(u) / dx^2 = exp(x) * (du/dx)^2 + exp(x) * d^2u /dx^2 +template +NETGEN_INLINE AutoDiffDiff exp (AutoDiffDiff x) +{ + AutoDiffDiff res; + res.Value() = exp(x.Value()); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k) * res.Value(); + for (int k = 0; k < D; k++) + for (int l = 0; l < D; l++) + res.DDValue(k,l) = (x.DValue(k) * x.DValue(l)+x.DDValue(k,l)) * res.Value(); + return res; +} + +using std::pow; +template +NETGEN_INLINE AutoDiffDiff pow (AutoDiffDiff x, AutoDiffDiff y ) +{ + return exp(log(x)*y); +} + +template +NETGEN_INLINE AutoDiffDiff log (AutoDiffDiff x) +{ + AutoDiffDiff res; + res.Value() = log(x.Value()); + SCAL xinv = 1.0/x.Value(); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k) * xinv; + for (int k = 0; k < D; k++) + for (int l = 0; l < D; l++) + res.DDValue(k,l) = -xinv*xinv*x.DValue(k) * x.DValue(l) + xinv * x.DDValue(k,l); + return res; +} + + + +template +NETGEN_INLINE AutoDiffDiff sin (AutoDiffDiff x) +{ + AutoDiffDiff res; + SCAL s = sin(x.Value()); + SCAL c = cos(x.Value()); + + res.Value() = s; + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k) * c; + for (int k = 0; k < D; k++) + for (int l = 0; l < D; l++) + res.DDValue(k,l) = -s * x.DValue(k) * x.DValue(l) + c * x.DDValue(k,l); + return res; +} + + +template +NETGEN_INLINE AutoDiffDiff cos (AutoDiffDiff x) +{ + AutoDiffDiff res; + SCAL s = sin(x.Value()); + SCAL c = cos(x.Value()); + + res.Value() = c; + for (int k = 0; k < D; k++) + res.DValue(k) = -s * x.DValue(k); + for (int k = 0; k < D; k++) + for (int l = 0; l < D; l++) + res.DDValue(k,l) = -c * x.DValue(k) * x.DValue(l) - s * x.DDValue(k,l); + return res; +} + +template +NETGEN_INLINE AutoDiffDiff tan (AutoDiffDiff x) +{ return sin(x) / cos(x); } + + +template +NETGEN_INLINE AutoDiffDiff atan (AutoDiffDiff x) +{ + AutoDiffDiff res; + SCAL a = atan(x.Value()); + res.Value() = a; + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k)/(1+x.Value()*x.Value()) ; + for (int k = 0; k < D; k++) + for (int l = 0; l < D; l++) + res.DDValue(k,l) = -2*x.Value()/((1+x.Value()*x.Value())*(1+x.Value()*x.Value())) * x.DValue(k) * x.DValue(l) + x.DDValue(k,l)/(1+x.Value()*x.Value()); + return res; +} + +template +NETGEN_INLINE AutoDiffDiff atan2 (AutoDiffDiff x,AutoDiffDiff y) +{ + AutoDiffDiff res; + SCAL a = atan2(x.Value(), y.Value()); + res.Value() = a; + for (int k = 0; k < D; k++) + res.DValue(k) = (x.Value()*y.DValue(k)-y.Value()*x.DValue(k))/(y.Value()*y.Value()+x.Value()*x.Value()); + + for (int k = 0; k < D; k++) + for (int l = 0; l < D; l++) + res.DDValue(k,l) = (x.DValue(k)*y.DValue(l)+x.Value()*y.DDValue(l,k) - y.DValue(k)*x.DValue(l) - y.Value()*x.DDValue(l,k))/(y.Value()*y.Value()+x.Value()*x.Value()) - 2 * (x.Value()*y.DValue(k)-y.Value()*x.DValue(k)) * (x.Value()*x.DValue(k) + y.Value()*y.DValue(k))/( (y.Value()*y.Value()+x.Value()*x.Value()) * (y.Value()*y.Value()+x.Value()*x.Value()) ); + return res; +} + + + +using std::acos; +template +NETGEN_INLINE AutoDiffDiff acos (AutoDiffDiff x) +{ + AutoDiffDiff res; + SCAL a = acos(x.Value()); + res.Value() = a; + auto omaa = 1-x.Value()*x.Value(); + auto s = sqrt(omaa); + SCAL da = -1 / s; + SCAL dda = -x.Value() / (s*omaa); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k)*da; + for (int k = 0; k < D; k++) + for (int l = 0; l < D; l++) + res.DDValue(k,l) = dda * x.DValue(k) * x.DValue(l) + da * x.DDValue(k,l); + + return res; +} + + +using std::acos; +template +NETGEN_INLINE AutoDiffDiff asin (AutoDiffDiff x) +{ + AutoDiffDiff res; + SCAL a = asin(x.Value()); + res.Value() = a; + auto omaa = 1-x.Value()*x.Value(); + auto s = sqrt(omaa); + SCAL da = 1 / s; + SCAL dda = x.Value() / (s*omaa); + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k)*da; + for (int k = 0; k < D; k++) + for (int l = 0; l < D; l++) + res.DDValue(k,l) = dda * x.DValue(k) * x.DValue(l) + da * x.DDValue(k,l); + + return res; +} + + +template +NETGEN_INLINE AutoDiffDiff sinh (AutoDiffDiff x) +{ + AutoDiffDiff res; + SCAL sh = sinh(x.Value()); + SCAL ch = cosh(x.Value()); + + res.Value() = sh; + for (int k = 0; k < D; k++) + res.DValue(k) = x.DValue(k) * ch; + for (int k = 0; k < D; k++) + for (int l = 0; l < D; l++) + res.DDValue(k,l) = sh * x.DValue(k) * x.DValue(l) + ch * x.DDValue(k,l); + return res; +} + + +template +NETGEN_INLINE AutoDiffDiff cosh (AutoDiffDiff x) +{ + AutoDiffDiff res; + SCAL sh = sinh(x.Value()); + SCAL ch = cosh(x.Value()); + + res.Value() = ch; + for (int k = 0; k < D; k++) + res.DValue(k) = sh * x.DValue(k); + for (int k = 0; k < D; k++) + for (int l = 0; l < D; l++) + res.DDValue(k,l) = ch * x.DValue(k) * x.DValue(l) + sh * x.DDValue(k,l); + return res; +} + +template +NETGEN_INLINE AutoDiffDiff erf (AutoDiffDiff x) +{ + AutoDiffDiff res; + SCAL derf = 2. / sqrt(M_PI) * exp(- x.Value() * x.Value()); + + res.Value() = erf(x.Value()); + for (int k = 0; k < D; k++) + res.DValue(k) = - derf * x.DValue(k); + for (int k = 0; k < D; k++) + for (int l = 0; l < D; l++) + res.DDValue(k,l) = derf * (x.DDValue(k, l) - 2 * x.Value() * x.DValue(k) * x.DValue(l)); + return res; +} + +using std::floor; +template +NETGEN_INLINE AutoDiffDiff floor (const AutoDiffDiff & x) +{ + return floor(x.Value()); +} + +using std::ceil; +template +NETGEN_INLINE AutoDiffDiff ceil (const AutoDiffDiff & x) +{ + return ceil(x.Value()); +} + + +template +auto IfPos (AutoDiffDiff a, TB b, TC c) -> decltype(IfPos (a.Value(), b, c)) +{ + return IfPos (a.Value(), b, c); +} + +template +NETGEN_INLINE AutoDiffDiff IfPos (SCAL /* SIMD */ a, AutoDiffDiff b, AutoDiffDiff c) +{ + AutoDiffDiff res; + res.Value() = IfPos (a, b.Value(), c.Value()); + for (int j = 0; j < D; j++) + { + res.DValue(j) = IfPos (a, b.DValue(j), c.DValue(j)); + res.DDValue(j) = IfPos (a, b.DDValue(j), c.DDValue(j)); + } + return res; +} + +template +NETGEN_INLINE AutoDiffDiff IfPos (SCAL /* SIMD */ a, AutoDiffDiff b, TC c) +{ + return IfPos (a, b, AutoDiffDiff (c)); +} + + + + +//@} + +} + + +namespace ngbla +{ + template struct is_scalar_type; + template + struct is_scalar_type> { static constexpr bool value = true; }; + + + // not meaningful for AutoDiff, since this is + // not (complex) differentiable anyway + template + inline auto L2Norm2 (const ngcore::AutoDiffDiff & x) + { + return x*x; + } + +} + + + +#endif diff --git a/libsrc/core/bitarray.cpp b/libsrc/core/bitarray.cpp index 8c76ba90..1c6f6ec4 100644 --- a/libsrc/core/bitarray.cpp +++ b/libsrc/core/bitarray.cpp @@ -40,12 +40,13 @@ namespace ngcore if (owns_data) { delete [] data; - mt.Free(Addr(size)+1); + mt.Free(GetMemoryUsage()); } size = asize; data = new unsigned char [Addr (size)+1]; - mt.Alloc(Addr(size)+1); + owns_data = true; + mt.Alloc(GetMemoryUsage()); } BitArray & BitArray :: Set () throw() diff --git a/libsrc/core/bitarray.hpp b/libsrc/core/bitarray.hpp index 8ae32e3c..caa8345c 100644 --- a/libsrc/core/bitarray.hpp +++ b/libsrc/core/bitarray.hpp @@ -49,6 +49,7 @@ public: { ba2.owns_data = false; ba2.data = nullptr; + mt = std::move(ba2.mt); } template @@ -59,13 +60,17 @@ public: int cnt = 0; for (auto i = list.begin(); i < list.end(); i++, cnt++) if (*i) SetBit(cnt); + StartMemoryTracing(); } /// delete data ~BitArray () { if (owns_data) + { delete [] data; + mt.Free(GetMemoryUsage()); + } } /// Set size, loose values @@ -150,11 +155,11 @@ public: NGCORE_API auto * Data() const { return data; } + const size_t GetMemoryUsage() const { return owns_data ? (size+CHAR_BIT-1)/CHAR_BIT : 0; } const MemoryTracer& GetMemoryTracer() const { return mt; } void StartMemoryTracing() const { - if(owns_data) - mt.Alloc(Addr(size)+1); + mt.Alloc(GetMemoryUsage()); } private: @@ -205,6 +210,31 @@ private: NGCORE_API std::ostream & operator<<(std::ostream & s, const BitArray & ba); + + + template + class TBitArray : public BitArray + { + public: + using BitArray::BitArray; + + void SetBit (IndexType i) { BitArray::SetBit(i-IndexBASE()); } + void Clear () { BitArray::Clear(); } + void Clear (IndexType i) { BitArray::Clear(i-IndexBASE()); } + void SetBitAtomic (IndexType i) { BitArray::SetBitAtomic(i-IndexBASE()); } + bool Test (IndexType i) const { return BitArray::Test(i-IndexBASE()); } + + bool operator[] (IndexType i) const { return Test(i); } + T_Range Range() const { return { IndexBASE(), IndexBASE()+Size() }; } + NGCORE_API TBitArray & Or (const TBitArray & ba2) + { + BitArray::Or(ba2); + return *this; + } + + }; + } // namespace ngcore + #endif // NETGEN_CORE_BITARRAY diff --git a/libsrc/core/exception.cpp b/libsrc/core/exception.cpp index b89d721e..1411b25e 100644 --- a/libsrc/core/exception.cpp +++ b/libsrc/core/exception.cpp @@ -1,15 +1,69 @@ #include "exception.hpp" #include "utils.hpp" +#ifdef EMSCRIPTEN +#include +#endif // EMSCRIPTEN + namespace ngcore { Exception :: Exception(const std::string& s) - : m_what(s) {} + : m_what(s) { + #ifdef EMSCRIPTEN + std::cout << "THROW Exception " << s << std::endl; + #endif +} Exception :: Exception(const char* s) - : m_what(s) {} + : m_what(s) { + #ifdef EMSCRIPTEN + std::cout << "THROW Exception " << s << std::endl; + #endif + +} + Exception :: Exception(std::string_view s1, std::string_view s2) + : Exception(std::string(s1)+std::string(s2)) + { } + + Exception :: Exception(std::string_view s1, std::string_view s2, std::string_view s3) + : Exception(std::string(s1)+std::string(s2)+std::string(s3)) + { } + + + void Exception :: Throw (std::string_view s1) + { + throw Exception(std::string(s1)); + } + + void Exception :: Throw (std::string_view s1, std::string_view s2) + { + throw Exception(std::string(s1)+std::string(s2)); + } + + void Exception :: Throw (std::string_view s1, std::string_view s2, std::string_view s3) + { + throw Exception(std::string(s1)+std::string(s2)+std::string(s3)); + } + + + RangeException :: RangeException (// const std::string & where, + const char * where, + ptrdiff_t ind, ptrdiff_t imin, ptrdiff_t imax) : Exception("") + { + std::stringstream str; + str << where << ": index " << ind << " out of range [" << imin << "," << imax << ")\n"; + Append (str.str()); + Append (GetBackTrace()); + } + + + void ThrowRangeException(const char * s, ptrdiff_t ind, ptrdiff_t imin, ptrdiff_t imax) + { + throw RangeException(s, ind, imin, imax); + } + void ThrowException(const std::string & s) { throw Exception (s); @@ -19,11 +73,18 @@ namespace ngcore { throw Exception (s); } + + + void ThrowNotTheSameException(const char * s, ptrdiff_t a, ptrdiff_t b) + { + throw ngcore::Exception(std::string(s) + ", a="+ToString(a) + ", b="+ToString(b) + GetBackTrace()); + } + } // namespace ngcore // ********* STUFF FOR GETBACKTRACE *************************** -#ifdef __GNUC__ +#if defined __GNUC__ && !defined __EMSCRIPTEN__ #include #include @@ -67,7 +128,7 @@ namespace ngcore // 1 libngcore.dylib 0x000000010ddb298c _ZL21ngcore_signal_handleri + 316 constexpr char reset_shell[] = "\033[0m"; constexpr char green[] = "\033[32m"; - constexpr char yellow[] = "\033[33m"; + [[maybe_unused]] constexpr char yellow[] = "\033[33m"; std::istringstream in(s); @@ -122,7 +183,7 @@ namespace ngcore 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); + // 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()) @@ -181,7 +242,7 @@ namespace ngcore for (i = 1; i < bt_size-1; i++) { dladdr(bt[i], &info); - size_t len = strlen(bt_syms[i]); + // size_t len = strlen(bt_syms[i]); result << '#'<< i << '\t' << detail::TranslateBacktrace( bt_syms[i], info.dli_fname ); } free(bt_syms); @@ -226,7 +287,7 @@ static bool dummy = []() return true; }(); -#else // __GNUC__ +#else // __GNUC__ and not __EMSCRIPTEN__ namespace ngcore { diff --git a/libsrc/core/exception.hpp b/libsrc/core/exception.hpp index 32b02cb2..d095384b 100644 --- a/libsrc/core/exception.hpp +++ b/libsrc/core/exception.hpp @@ -1,16 +1,17 @@ #ifndef NETGEN_CORE_EXCEPTION_HPP #define NETGEN_CORE_EXCEPTION_HPP +#include #include // for stringstream #include // for exception #include // for string #include "ngcore_api.hpp" // for NGCORE_API +#include "utils.hpp" // for ToString namespace ngcore { - NGCORE_API std::string GetBackTrace(); // Exception for code that shouldn't be executed @@ -33,8 +34,14 @@ namespace ngcore Exception(Exception&&) = default; Exception(const std::string& s); // : m_what(s) {} Exception(const char* s); // : m_what(s) {} + Exception(std::string_view s1, std::string_view s2); + Exception(std::string_view s1, std::string_view s2, std::string_view s3); ~Exception() override = default; + [[noreturn]] static void Throw (std::string_view s1); + [[noreturn]] static void Throw (std::string_view s1, std::string_view s2); + [[noreturn]] static void Throw (std::string_view s1, std::string_view s2, std::string_view s3); + Exception& operator =(const Exception&) = default; Exception& operator =(Exception&&) noexcept = default; @@ -50,23 +57,26 @@ namespace ngcore 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); + [[noreturn]] NGCORE_API void ThrowException(const std::string & s); + [[noreturn]] NGCORE_API void ThrowException(const char * s); // Out of Range exception class NGCORE_API RangeException : public Exception { public: /// where it occurs, index, minimal and maximal indices - RangeException (const std::string & where, - int ind, int imin, int imax) : Exception("") + RangeException (// const std::string & where, + const char * where, + ptrdiff_t ind, ptrdiff_t imin, ptrdiff_t imax); + /* + : Exception("") { std::stringstream str; str << where << ": index " << ind << " out of range [" << imin << "," << imax << ")\n"; Append (str.str()); Append (GetBackTrace()); } - + */ template RangeException(const std::string& where, const T& value) { @@ -76,9 +86,40 @@ namespace ngcore } }; + [[noreturn]] NGCORE_API void ThrowRangeException(const char * s, ptrdiff_t ind, ptrdiff_t imin, ptrdiff_t imax); + [[noreturn]] NGCORE_API void ThrowNotTheSameException(const char * s, ptrdiff_t a, ptrdiff_t b); + + // Exception used if no simd implementation is available to fall back to standard evaluation class NGCORE_API ExceptionNOSIMD : public Exception { public: using Exception::Exception; }; + + template + struct IsSafe { + constexpr operator bool() const { return false; } }; + + namespace detail { + template + inline static constexpr void CheckRange(const char * s, const T& n, Tmin first, Tmax next) + { + if constexpr (!IsSafe()) + if (n=next) + ThrowRangeException(s, ptrdiff_t(n), ptrdiff_t(first), ptrdiff_t(next)); + } + + template + inline static constexpr void CheckSame(const char * s, const Ta& a, const Tb& b) + { + if constexpr (!IsSafe() || !IsSafe()) + if(a != b) + { + if constexpr(std::is_integral_v && std::is_same_v) + ThrowNotTheSameException(s, long(a), long(b)); \ + else + throw Exception(std::string(s) + "\t: not the same, a="+ToString(a) + ", b="+ngcore::ToString(b) + GetBackTrace()); + } + } + } // namespace detail } // namespace ngcore #define NETGEN_CORE_NGEXEPTION_STR_HELPER(x) #x @@ -88,16 +129,15 @@ namespace ngcore #define NG_EXCEPTION(s) ngcore::Exception(__FILE__ ":" NETGEN_CORE_NGEXEPTION_STR(__LINE__) "\t"+std::string(s)) #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"); } +#define NETGEN_CHECK_RANGE(value, min, max_plus_one) ngcore::detail::CheckRange(__FILE__ ":" NETGEN_CORE_NGEXEPTION_STR(__LINE__) "\t", value, min, max_plus_one); +#define NETGEN_CHECK_SAME(a,b) ngcore::detail::CheckSame(__FILE__ ":" NETGEN_CORE_NGEXEPTION_STR(__LINE__) "\t", a, b); + +#define NETGEN_NOEXCEPT #else // defined(NETGEN_ENABLE_CHECK_RANGE) && !defined(__CUDA_ARCH__) #define NETGEN_CHECK_RANGE(value, min, max) -#define NETGEN_CHECK_SHAPE(a,b) - +#define NETGEN_CHECK_SAME(a,b) +// #define NETGEN_CHECK_SHAPE(a,b) +#define NETGEN_NOEXCEPT noexcept #endif // defined(NETGEN_ENABLE_CHECK_RANGE) && !defined(__CUDA_ARCH__) diff --git a/libsrc/core/flags.cpp b/libsrc/core/flags.cpp index e968ce9c..dc311124 100644 --- a/libsrc/core/flags.cpp +++ b/libsrc/core/flags.cpp @@ -16,6 +16,7 @@ namespace ngcore { using std::string; + using std::string_view; using std::endl; Flags :: Flags () { ; } @@ -209,18 +210,18 @@ namespace ngcore } - double Flags :: GetNumFlag (const string & name, double def) const + double Flags :: GetNumFlag (string_view name, double def) const { if (numflags.Used (name)) - return numflags[name]; + return numflags[string(name)]; else return def; } - const double * Flags :: GetNumFlagPtr (const string & name) const + const double * Flags :: GetNumFlagPtr (string_view name) const { if (numflags.Used (name)) - return & ((SymbolTable&)numflags)[name]; + return & ((SymbolTable&)numflags)[string(name)]; else return NULL; } @@ -239,16 +240,16 @@ namespace ngcore return defflags.Used (name); } */ - bool Flags :: GetDefineFlag (const string & name) const throw() + bool Flags :: GetDefineFlag (string_view name) const throw() { - if (!defflags.Used (name)) return false; - return defflags[name]; + if (!defflags.Used (string(name))) return false; + return defflags[string(name)]; } - xbool Flags :: GetDefineFlagX (const string & name) const throw() + xbool Flags :: GetDefineFlagX (string_view name) const throw() { - if (!defflags.Used (name)) return maybe; - return bool(defflags[name]); + if (!defflags.Used (string(name))) return maybe; + return bool(defflags[string(name)]); } @@ -296,32 +297,32 @@ namespace ngcore return empty; } - bool Flags :: StringFlagDefined (const string & name) const + bool Flags :: StringFlagDefined (string_view name) const noexcept { return strflags.Used (name); } - bool Flags :: NumFlagDefined (const string &name) const + bool Flags :: NumFlagDefined (string_view name) const noexcept { return numflags.Used (name); } - bool Flags :: FlagsFlagDefined (const string &name) const + bool Flags :: FlagsFlagDefined (string_view name) const noexcept { return flaglistflags.Used (name); } - bool Flags :: StringListFlagDefined (const string & name) const + bool Flags :: StringListFlagDefined (string_view name) const noexcept { return strlistflags.Used (name); } - bool Flags :: NumListFlagDefined (const string & name) const + bool Flags :: NumListFlagDefined (string_view name) const noexcept { return numlistflags.Used (name); } - bool Flags :: AnyFlagDefined (const string& name) const + bool Flags :: AnyFlagDefined (string_view name) const noexcept { return anyflags.Used(name); } diff --git a/libsrc/core/flags.hpp b/libsrc/core/flags.hpp index 938fb789..2d3d52ac 100644 --- a/libsrc/core/flags.hpp +++ b/libsrc/core/flags.hpp @@ -125,15 +125,15 @@ namespace ngcore /// 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; + double GetNumFlag (std::string_view name, double def) const; /// Returns address of numerical flag, null if not exists - const double * GetNumFlagPtr (const std::string & name) const; + const double * GetNumFlagPtr (std::string_view 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(); + bool GetDefineFlag (std::string_view name) const noexcept; + xbool GetDefineFlagX (std::string_view name) const noexcept; /// Returns string list flag, empty array if not exist const Array & GetStringListFlag (const std::string & name) const; /// Returns num list flag, empty array if not exist @@ -144,16 +144,16 @@ namespace ngcore /// Test, if string flag is defined - bool StringFlagDefined (const std::string & name) const; + bool StringFlagDefined (std::string_view name) const noexcept; /// Test, if num flag is defined - bool NumFlagDefined (const std::string & name) const; + bool NumFlagDefined (std::string_view name) const noexcept; /// Test, if num flag is defined - bool FlagsFlagDefined (const std::string & name) const; + bool FlagsFlagDefined (std::string_view name) const noexcept; /// Test, if string list flag is defined - bool StringListFlagDefined (const std::string & name) const; + bool StringListFlagDefined (std::string_view name) const noexcept; /// Test, if num list flag is defined - bool NumListFlagDefined (const std::string & name) const; - bool AnyFlagDefined (const std::string& name) const; + bool NumListFlagDefined (std::string_view name) const noexcept; + bool AnyFlagDefined (std::string_view name) const noexcept; /// number of string flags int GetNStringFlags () const { return strflags.Size(); } diff --git a/libsrc/core/generate_mpi_sources.py b/libsrc/core/generate_mpi_sources.py new file mode 100644 index 00000000..5d96d8b0 --- /dev/null +++ b/libsrc/core/generate_mpi_sources.py @@ -0,0 +1,174 @@ +functions = [ + ("double", "MPI_Wtime"), + ("int", "MPI_Allgather", "void*", "int", "MPI_Datatype", "void*", "int", "MPI_Datatype", "MPI_Comm"), + ("int", "MPI_Allreduce", "void*", "void*", "int", "MPI_Datatype", "MPI_Op", "MPI_Comm"), + ("int", "MPI_Alltoall", "void*", "int", "MPI_Datatype", "void*", "int", "MPI_Datatype", "MPI_Comm"), + ("int", "MPI_Barrier", "MPI_Comm"), + ("int", "MPI_Bcast", "void*", "int", "MPI_Datatype", "int", "MPI_Comm"), + ("int", "MPI_Ibcast", "void*", "int", "MPI_Datatype", "int", "MPI_Comm", "MPI_Request*"), + ("int", "MPI_Comm_c2f", "MPI_Comm"), + ("int", "MPI_Comm_create", "MPI_Comm", "MPI_Group", "MPI_Comm*"), + ("int", "MPI_Comm_create_group", "MPI_Comm", "MPI_Group", "int", "MPI_Comm*"), + ("int", "MPI_Comm_free", "MPI_Comm*"), + ("int", "MPI_Comm_group", "MPI_Comm", "MPI_Group*"), + ("int", "MPI_Comm_rank", "MPI_Comm", "int*"), + ("int", "MPI_Comm_size", "MPI_Comm", "int*"), + ("int", "MPI_Finalize"), + ("int", "MPI_Gather", "void*", "int", "MPI_Datatype", "void*", "int", "MPI_Datatype", "int", "MPI_Comm"), + ("int", "MPI_Gatherv", "void*", "int", "MPI_Datatype", "void*", "int*", "int*", "MPI_Datatype", "int", "MPI_Comm"), + ("int", "MPI_Get_count", "MPI_Status*", "MPI_Datatype", "int*"), + ("int", "MPI_Get_processor_name", "char*", "int*"), + ("int", "MPI_Group_incl", "MPI_Group", "int", "int*", "MPI_Group*"), + ("int", "MPI_Init", "int*", "char***"), + ("int", "MPI_Init_thread", "int*", "char***", "int", "int*"), + ("int", "MPI_Initialized", "int*"), + ("int", "MPI_Iprobe", "int", "int", "MPI_Comm", "int*", "MPI_Status*"), + ("int", "MPI_Irecv", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm", "MPI_Request*"), + ("int", "MPI_Isend", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm", "MPI_Request*"), + ("int", "MPI_Probe", "int", "int", "MPI_Comm", "MPI_Status*"), + ("int", "MPI_Query_thread", "int*"), + ("int", "MPI_Recv", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm", "MPI_Status*"), + ("int", "MPI_Recv_init", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm", "MPI_Request*"), + ("int", "MPI_Reduce", "void*", "void*", "int", "MPI_Datatype", "MPI_Op", "int", "MPI_Comm"), + ("int", "MPI_Reduce_local", "void*", "void*", "int", "MPI_Datatype", "MPI_Op"), + ("int", "MPI_Request_free", "MPI_Request*"), + ("int", "MPI_Scatter", "void*", "int", "MPI_Datatype", "void*", "int", "MPI_Datatype", "int", "MPI_Comm"), + ("int", "MPI_Send", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm"), + ("int", "MPI_Send_init", "void*", "int", "MPI_Datatype", "int", "int", "MPI_Comm", "MPI_Request*"), + ("int", "MPI_Startall", "int", "MPI_Request*:0"), + ("int", "MPI_Type_commit", "MPI_Datatype*"), + ("int", "MPI_Type_contiguous", "int", "MPI_Datatype", "MPI_Datatype*"), + ("int", "MPI_Type_create_resized", "MPI_Datatype", "MPI_Aint", "MPI_Aint", "MPI_Datatype*"), + ("int", "MPI_Type_create_struct", "int", "int*:0", "MPI_Aint*:0", "MPI_Datatype*:0", "MPI_Datatype*"), + ("int", "MPI_Type_free", "MPI_Datatype*"), + ("int", "MPI_Type_get_extent", "MPI_Datatype", "MPI_Aint*", "MPI_Aint*"), + ("int", "MPI_Type_indexed", "int", "int*:0", "int*:0", "MPI_Datatype", "MPI_Datatype*"), + ("int", "MPI_Type_size", "MPI_Datatype", "int*"), + ("int", "MPI_Wait", "MPI_Request*", "MPI_Status*"), + ("int", "MPI_Waitall", "int", "MPI_Request*:0", "MPI_Status*"), + ("int", "MPI_Waitany", "int", "MPI_Request*:0", "int*", "MPI_Status*"), + ] + +constants = [ + ("MPI_Comm", "MPI_COMM_NULL"), + ("MPI_Comm", "MPI_COMM_WORLD"), + ("MPI_Datatype", "MPI_CHAR"), + ("MPI_Datatype", "MPI_CXX_DOUBLE_COMPLEX"), + ("MPI_Datatype", "MPI_C_BOOL"), + ("MPI_Datatype", "MPI_DATATYPE_NULL"), + ("MPI_Datatype", "MPI_DOUBLE"), + ("MPI_Datatype", "MPI_FLOAT"), + ("MPI_Datatype", "MPI_INT"), + ("MPI_Datatype", "MPI_SHORT"), + ("MPI_Datatype", "MPI_UINT64_T"), + ("MPI_Op", "MPI_LOR"), + ("MPI_Op", "MPI_MAX"), + ("MPI_Op", "MPI_MIN"), + ("MPI_Op", "MPI_SUM"), + ("MPI_Request", "MPI_REQUEST_NULL"), + ("MPI_Status*", "MPI_STATUSES_IGNORE"), + ("MPI_Status*", "MPI_STATUS_IGNORE"), + ("int", "MPI_ANY_SOURCE"), + ("int", "MPI_ANY_TAG"), + ("int", "MPI_MAX_PROCESSOR_NAME"), + ("int", "MPI_PROC_NULL"), + ("int", "MPI_ROOT"), + ("int", "MPI_SUBVERSION"), + ("int", "MPI_THREAD_MULTIPLE"), + ("int", "MPI_THREAD_SINGLE"), + ("int", "MPI_VERSION"), + ("void*", "MPI_IN_PLACE"), +] + +def get_args(f, counts=False): + args = [] + for arg in f[2:]: + has_count = ':' in arg + if has_count: + s, count = arg.split(':') + count = int(count) + else: + s = arg + count = None + if s.startswith("MPI_"): + s = "NG_" + s + if counts: + args.append((s, count)) + else: + args.append(s) + return args + +def generate_declarations(): + code = "" + nowrapper_code = "" + for f in functions: + ret = f[0] + name = f[1] + args = ", ".join(get_args(f)) + code += f"NGCORE_API extern {ret} (*NG_{name})({args});\n" + nowrapper_code += f"#define NG_{name} {name}\n" + + for typ, name in constants: + if typ.startswith("MPI_"): + typ = "NG_" + typ + code += f"NGCORE_API extern {typ} NG_{name};\n" + nowrapper_code += f"#define NG_{name} {name}\n" + + with open("ng_mpi_generated_declarations.hpp", "w") as f: + f.write("#ifdef NG_MPI_WRAPPER\n") + f.write(code) + f.write("#else // NG_MPI_WRAPPER\n") + f.write(nowrapper_code) + f.write("#endif // NG_MPI_WRAPPER\n") + +def generate_dummy_init(): + code = "" + for f in functions: + ret = f[0] + name = f[1] + args = ", ".join(get_args(f)) + code += f"decltype(NG_{name}) NG_{name} = []({args})->{ret} {{ throw no_mpi(); }};\n" + + for typ, name in constants: + if typ.startswith("MPI_"): + typ = "NG_" + typ + code += f"{typ} NG_{name} = 0;\n" + + with open("ng_mpi_generated_dummy_init.hpp", "w") as f: + f.write(code) + +def generate_init(): + code = "" + for f in functions: + ret = f[0] + name = f[1] + args = get_args(f, counts=True) + in_args ='' + call_args = '' + for i in range(len(args)): + arg, count = args[i] + if i > 0: + in_args += ', ' + call_args += ', ' + in_args += arg + f" arg{i}" + if not arg.startswith("NG_"): + # plain type (like int, int *, etc.), just pass the argument along + call_args += f" arg{i}" + elif count is None: + # MPI type (by value or pointer), but just one object, no arrays + call_args += f" ng2mpi(arg{i})" + else: + # arrays of MPI types, we need to copy them due to incompatible size + call_args += f" ng2mpi(arg{i}, arg{count})" + code += f"NG_{name} = []({in_args})->{ret} {{ return {name}({call_args}); }};\n" + + for _, name in constants: + code += f"NG_{name} = mpi2ng({name});\n" + + with open("ng_mpi_generated_init.hpp", "w") as f: + f.write(code) + +if __name__ == "__main__": + generate_declarations() + generate_dummy_init() + generate_init() diff --git a/libsrc/core/hashtable.hpp b/libsrc/core/hashtable.hpp index a1c603cf..336b5071 100644 --- a/libsrc/core/hashtable.hpp +++ b/libsrc/core/hashtable.hpp @@ -9,8 +9,9 @@ #include #include +#include -#include "mpi_wrapper.hpp" +// #include "mpi_wrapper.hpp" #include "ngcore_api.hpp" #include "table.hpp" #include "utils.hpp" @@ -37,53 +38,68 @@ namespace ngcore }; - + // feature check macro for transition from INT to IVec +#define NGCORE_HAS_IVEC + /// N integers template - class INT + class IVec { /// data - T i[(N>0)?N:1]; + // T i[(N>0)?N:1]; + HTArray i; + public: /// - NETGEN_INLINE INT () { } + constexpr NETGEN_INLINE IVec () = default; + constexpr NETGEN_INLINE IVec (const IVec & i1) : i(i1.i) { } + constexpr NETGEN_INLINE IVec (T ai1) : i(ai1) { } + + template = true> + constexpr IVec (const T &v, T2... rest) + : i{v,rest...} { } + + /* /// init all - NETGEN_INLINE INT (T ai1) + NETGEN_INLINE IVec (T ai1) { - for (int j = 0; j < N; j++) { i[j] = ai1; } + for (int j = 0; j < N; j++) { i[j] = ai1; } } /// init i[0], i[1] - constexpr NETGEN_INLINE INT (T ai1, T ai2) + constexpr NETGEN_INLINE IVec (T ai1, T ai2) : i{ai1, ai2} { ; } /// init i[0], i[1], i[2] - constexpr NETGEN_INLINE INT (T ai1, T ai2, T ai3) + constexpr NETGEN_INLINE IVec (T ai1, T ai2, T ai3) : i{ai1, ai2, ai3} { ; } /// init i[0], i[1], i[2] - constexpr NETGEN_INLINE INT (T ai1, T ai2, T ai3, T ai4) + constexpr NETGEN_INLINE IVec (T ai1, T ai2, T ai3, T ai4) : i{ai1, ai2, ai3, ai4} { ; } /// init i[0], i[1], i[2] - constexpr NETGEN_INLINE INT (T ai1, T ai2, T ai3, T ai4, T ai5) + constexpr NETGEN_INLINE IVec (T ai1, T ai2, T ai3, T ai4, T ai5) : i{ai1, ai2, ai3, ai4, ai5} { ; } /// init i[0], i[1], i[2] - NETGEN_INLINE INT (T ai1, T ai2, T ai3, T ai4, T ai5, T ai6, T ai7, T ai8, T ai9) + NETGEN_INLINE IVec (T ai1, T ai2, T ai3, T ai4, T ai5, T ai6, T ai7, T ai8, T ai9) : i{ai1, ai2, ai3, ai4, ai5, ai6, ai7, ai8, ai9 } { ; } - + */ + template void DoArchive(ARCHIVE& ar) { - ar.Do(i, N); + // ar.Do(i.begin(), N); + ar.Do(i.Ptr(), N); } template - NETGEN_INLINE INT (const INT & in2) + NETGEN_INLINE IVec (const IVec & in2) { if (N2 <= N) { @@ -100,7 +116,7 @@ namespace ngcore } template - NETGEN_INLINE INT (const BaseArrayObject & ao) + NETGEN_INLINE IVec (const BaseArrayObject & ao) { for (int j = 0; j < N; j++) i[j] = ao.Spec()[j]; @@ -108,7 +124,7 @@ namespace ngcore NETGEN_INLINE size_t Size() const { return N; } /// all ints equal ? - NETGEN_INLINE bool operator== (const INT & in2) const + NETGEN_INLINE bool operator== (const IVec & in2) const { for (int j = 0; j < N; j++) if (i[j] != in2.i[j]) return 0; @@ -116,7 +132,7 @@ namespace ngcore } /// any ints unequal ? - NETGEN_INLINE bool operator!= (const INT & in2) const + NETGEN_INLINE bool operator!= (const IVec & in2) const { for (int j = 0; j < N; j++) if (i[j] != in2.i[j]) return 1; @@ -124,7 +140,7 @@ namespace ngcore } /// sort integers - NETGEN_INLINE INT & Sort () & + NETGEN_INLINE IVec & Sort () & { for (int k = 0; k < N; k++) for (int l = k+1; l < N; l++) @@ -133,7 +149,7 @@ namespace ngcore return *this; } - NETGEN_INLINE INT Sort () && + NETGEN_INLINE IVec Sort () && { for (int k = 0; k < N; k++) for (int l = k+1; l < N; l++) @@ -155,7 +171,7 @@ namespace ngcore operator FlatArray () { return FlatArray (N, &i[0]); } - NETGEN_INLINE INT & operator= (T value) + NETGEN_INLINE IVec & operator= (T value) { for (int j = 0; j < N; j++) i[j] = value; @@ -163,7 +179,7 @@ namespace ngcore } template - NETGEN_INLINE INT & operator= (INT v2) + NETGEN_INLINE IVec & operator= (IVec v2) { for (int j = 0; j < N; j++) i[j] = v2[j]; @@ -186,14 +202,14 @@ namespace ngcore /// sort 2 integers template <> - NETGEN_INLINE INT<2> & INT<2>::Sort () & + NETGEN_INLINE IVec<2> & IVec<2>::Sort () & { if (i[0] > i[1]) Swap (i[0], i[1]); return *this; } template <> - NETGEN_INLINE INT<2> INT<2>::Sort () && + NETGEN_INLINE IVec<2> IVec<2>::Sort () && { if (i[0] > i[1]) Swap (i[0], i[1]); return *this; @@ -201,7 +217,7 @@ namespace ngcore /// sort 3 integers template <> - NETGEN_INLINE INT<3> INT<3>::Sort () && + NETGEN_INLINE IVec<3> IVec<3>::Sort () && { if (i[0] > i[1]) Swap (i[0], i[1]); if (i[1] > i[2]) Swap (i[1], i[2]); @@ -211,7 +227,7 @@ namespace ngcore /// Print integers template - inline ostream & operator<<(ostream & s, const INT & i2) + inline ostream & operator<<(ostream & s, const IVec & i2) { for (int j = 0; j < N; j++) s << (int) i2[j] << " "; @@ -219,15 +235,15 @@ namespace ngcore } template - auto begin(const INT & ind) + auto begin(const IVec & ind) { - return AOWrapperIterator> (ind, 0); + return AOWrapperIterator> (ind, 0); } template - auto end(const INT & ind) + auto end(const IVec & ind) { - return AOWrapperIterator> (ind, N); + return AOWrapperIterator> (ind, N); } @@ -236,9 +252,9 @@ namespace ngcore template - NETGEN_INLINE size_t HashValue (const INT & ind, size_t size) + NETGEN_INLINE size_t HashValue (const IVec & ind, size_t size) { - INT lind = ind; + IVec lind = ind; size_t sum = 0; for (int i = 0; i < N; i++) sum += lind[i]; @@ -247,24 +263,24 @@ namespace ngcore /// hash value of 1 int template - NETGEN_INLINE size_t HashValue (const INT<1,TI> & ind, size_t size) + NETGEN_INLINE size_t HashValue (const IVec<1,TI> & ind, size_t size) { return ind[0] % size; } /// hash value of 2 int template - NETGEN_INLINE size_t HashValue (const INT<2,TI> & ind, size_t size) + NETGEN_INLINE size_t HashValue (const IVec<2,TI> & ind, size_t size) { - INT<2,size_t> lind = ind; + IVec<2,size_t> lind = ind; return (113*lind[0]+lind[1]) % size; } /// hash value of 3 int template - NETGEN_INLINE size_t HashValue (const INT<3,TI> & ind, size_t size) + NETGEN_INLINE size_t HashValue (const IVec<3,TI> & ind, size_t size) { - INT<3,size_t> lind = ind; + IVec<3,size_t> lind = ind; return (113*lind[0]+59*lind[1]+lind[2]) % size; } @@ -284,9 +300,9 @@ namespace ngcore template - NETGEN_INLINE size_t HashValue2 (const INT & ind, size_t mask) + NETGEN_INLINE constexpr size_t HashValue2 (const IVec & ind, size_t mask) { - INT lind = ind; + IVec lind = ind; size_t sum = 0; for (int i = 0; i < N; i++) sum += lind[i]; @@ -295,32 +311,32 @@ namespace ngcore /// hash value of 1 int template - NETGEN_INLINE size_t HashValue2 (const INT<1,TI> & ind, size_t mask) + NETGEN_INLINE constexpr size_t HashValue2 (const IVec<1,TI> & ind, size_t mask) { return ind[0] & mask; } /// hash value of 2 int template - NETGEN_INLINE size_t HashValue2 (const INT<2,TI> & ind, size_t mask) + NETGEN_INLINE constexpr size_t HashValue2 (const IVec<2,TI> & ind, size_t mask) { - INT<2,size_t> lind = ind; + IVec<2,size_t> lind = ind; return (113*lind[0]+lind[1]) & mask; } /// hash value of 3 int template - NETGEN_INLINE size_t HashValue2 (const INT<3,TI> & ind, size_t mask) + NETGEN_INLINE constexpr size_t HashValue2 (const IVec<3,TI> & ind, size_t mask) { - INT<3,size_t> lind = ind; + IVec<3,size_t> lind = ind; return (113*lind[0]+59*lind[1]+lind[2]) & mask; } - NETGEN_INLINE size_t HashValue2 (size_t ind, size_t mask) + NETGEN_INLINE constexpr size_t HashValue2 (size_t ind, size_t mask) { return ind & mask; } - NETGEN_INLINE size_t HashValue2 (int ind, size_t mask) + NETGEN_INLINE constexpr size_t HashValue2 (int ind, size_t mask) { return size_t(ind) & mask; } @@ -332,7 +348,7 @@ namespace ngcore // using ngstd::max; template - NETGEN_INLINE T Max (const INT & i) + NETGEN_INLINE T Max (const IVec & i) { if (D == 0) return 0; T m = i[0]; @@ -342,7 +358,7 @@ namespace ngcore } template - NETGEN_INLINE T Min (const INT & i) + NETGEN_INLINE T Min (const IVec & i) { if (D == 0) return 0; T m = i[0]; @@ -352,18 +368,18 @@ namespace ngcore } template - NETGEN_INLINE INT Max (INT i1, INT i2) + NETGEN_INLINE IVec Max (IVec i1, IVec i2) { - INT tmp; + IVec tmp; for (int i = 0; i < D; i++) tmp[i] = std::max(i1[i], i2[i]); return tmp; } template - NETGEN_INLINE INT operator+ (INT i1, INT i2) + NETGEN_INLINE IVec operator+ (IVec i1, IVec i2) { - INT tmp; + IVec tmp; for (int i = 0; i < D; i++) tmp[i] = i1[i]+i2[i]; return tmp; @@ -575,7 +591,27 @@ namespace ngcore return res; } + template + constexpr inline T InvalidHash() { return T(-1); } + template + struct CHT_trait + { + constexpr static inline T_HASH Invalid() { return InvalidHash(); } + constexpr static inline size_t HashValue (const T_HASH & hash, size_t mask) { return HashValue2(hash, mask); } + }; + + template + struct CHT_trait> + { + constexpr static inline std::tuple Invalid() { return { CHT_trait::Invalid(), CHT_trait::Invalid() } ; } + constexpr static inline size_t HashValue (const std::tuple & hash, size_t mask) + { + return (CHT_trait::HashValue(std::get<0>(hash), mask) + CHT_trait::HashValue(std::get<1>(hash),mask)) & mask; + } + }; + + /** A closed hash-table. @@ -596,14 +632,18 @@ namespace ngcore /// Array cont; /// - T_HASH invalid = -1; + // T_HASH invalid = -1; + // static constexpr T_HASH invalid = InvalidHash(); + static constexpr T_HASH invalid = CHT_trait::Invalid(); public: /// ClosedHashTable (size_t asize = 128) : size(RoundUp2(asize)), hash(size), cont(size) { mask = size-1; - hash = T_HASH(invalid); + // hash = T_HASH(invalid); + // hash = InvalidHash(); + hash = CHT_trait::Invalid(); } ClosedHashTable (ClosedHashTable && ht2) = default; @@ -612,7 +652,8 @@ namespace ngcore ClosedHashTable (size_t asize, LocalHeap & lh) : size(RoundUp2(asize)), mask(size-1), hash(size, lh), cont(size, lh) { - hash = T_HASH(invalid); + // hash = T_HASH(invalid); + hash = InvalidHash(); } ClosedHashTable & operator= (ClosedHashTable && ht2) = default; @@ -637,7 +678,8 @@ namespace ngcore size_t Position (const T_HASH ind) const { - size_t i = HashValue2(ind, mask); + // size_t i = HashValue2(ind, mask); + size_t i = CHT_trait::HashValue(ind, mask); while (true) { if (hash[i] == ind) return i; @@ -659,7 +701,8 @@ namespace ngcore { if (UsedElements()*2 > Size()) DoubleSize(); - size_t i = HashValue2 (ind, mask); + // size_t i = HashValue2 (ind, mask); + size_t i = CHT_trait::HashValue (ind, mask); while (true) { @@ -704,6 +747,16 @@ namespace ngcore return (Position (ahash) != size_t(-1)); } + inline std::optional GetIfUsed (const T_HASH & ahash) const + { + size_t pos = Position (ahash); + if (pos != size_t(-1)) + return cont[pos]; + else + return std::nullopt; + } + + void SetData (size_t pos, const T_HASH & ahash, const T & acont) { hash[pos] = ahash; @@ -781,6 +834,15 @@ namespace ngcore hash = T_HASH(invalid); used = 0; } + + template + void DoArchive (ARCHIVE& ar) + { + ar & hash & cont; + ar & size & mask & used; + } + + struct EndIterator { }; class Iterator { @@ -798,24 +860,21 @@ namespace ngcore while (nr < tab.Size() && !tab.UsedPos(nr)) nr++; return *this; } - bool operator!= (const Iterator & it2) { return nr != it2.nr; } - auto operator* () const - { - T_HASH hash; - T val; - tab.GetData(nr, hash,val); - return std::make_pair(hash,val); - } + + bool operator!= (EndIterator it2) { return nr != tab.Size(); } + + auto operator* () const { return tab.GetBoth(nr); } }; Iterator begin() const { return Iterator(*this, 0); } - Iterator end() const { return Iterator(*this, Size()); } + EndIterator end() const { return EndIterator(); } }; template ostream & operator<< (ostream & ost, const ClosedHashTable & tab) { + /* for (size_t i = 0; i < tab.Size(); i++) if (tab.UsedPos(i)) { @@ -824,25 +883,28 @@ namespace ngcore tab.GetData (i, key, val); ost << key << ": " << val << ", "; } + */ + for (auto [key,val] : tab) + ost << key << ": " << val << ", "; return ost; } template - NETGEN_INLINE size_t HashValue (const INT<3,TI> ind) + NETGEN_INLINE size_t HashValue (const IVec<3,TI> ind) { - INT<3,size_t> lind = ind; + IVec<3,size_t> lind = ind; return 113*lind[0]+59*lind[1]+lind[2]; } template - NETGEN_INLINE size_t HashValue (const INT<2,TI> ind) + NETGEN_INLINE size_t HashValue (const IVec<2,TI> ind) { - INT<2,size_t> lind = ind; + IVec<2,size_t> lind = ind; return 113*lind[0]+lind[1]; } template - NETGEN_INLINE size_t HashValue (const INT<1,TI> ind) + NETGEN_INLINE size_t HashValue (const IVec<1,TI> ind) { return ind[0]; } @@ -1068,14 +1130,114 @@ namespace ngcore return ost; } + + + + + + + + + template + class CompressedTable + { + Table table; + ClosedHashTable idmap; + + public: + CompressedTable (Table && atable, ClosedHashTable && aidmap) + : table(std::move(atable)), idmap(std::move(aidmap)) { } + + FlatArray operator[](IndexType id) const + { + if (auto nr = idmap.GetIfUsed(id)) + return table[*nr]; + else + return { 0, nullptr }; + } + auto & GetTable() { return table; } + }; + + + template + class CompressedTableCreator + { + protected: + int mode; // 1 .. cnt, 2 .. cnt entries, 3 .. fill table + size_t nd; // number of entries; + ClosedHashTable idmap; + Array cnt; + Table table; + public: + CompressedTableCreator() + { nd = 0; mode = 1; } + + CompressedTable MoveTable() + { + return { std::move(table), std::move(idmap) }; + } + + 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); + cnt = 0; + } + if (mode == 3) + { + table = Table (cnt); + cnt = 0; + } + } + + void Add (IndexType blocknr, const T & data) + { + switch (mode) + { + case 1: + { + if (!idmap.Used (blocknr)) + idmap[blocknr] = nd++; + break; + } + case 2: + cnt[idmap.Get(blocknr)]++; + break; + case 3: + size_t cblock = idmap.Get(blocknr); + int ci = cnt[cblock]++; + table[cblock][ci] = data; + break; + } + } + }; + + + + + + + + + + + + + } // namespace ngcore - +/* #ifdef PARALLEL namespace ngcore { template - class MPI_typetrait > + class MPI_typetrait > { public: /// gets the MPI datatype @@ -1092,6 +1254,19 @@ namespace ngcore { }; } #endif +*/ + +namespace ngcore +{ + template struct MPI_typetrait; + + template + struct MPI_typetrait > { + static auto MPIType () { + return MPI_typetrait>::MPIType(); + } + }; +} @@ -1099,8 +1274,8 @@ namespace std { // structured binding support template - struct tuple_size> : std::integral_constant {}; - template struct tuple_element> { using type = T; }; + struct tuple_size> : std::integral_constant {}; + template struct tuple_element> { using type = T; }; } #endif diff --git a/libsrc/core/logging.cpp b/libsrc/core/logging.cpp index b5056406..105515bd 100644 --- a/libsrc/core/logging.cpp +++ b/libsrc/core/logging.cpp @@ -1,15 +1,6 @@ #include "logging.hpp" -#ifdef NETGEN_USE_SPDLOG - -#include -#include -#include - -#else // NETGEN_USE_SPDLOG #include -#endif // NETGEN_USE_SPDLOG - namespace ngcore { @@ -19,94 +10,10 @@ namespace ngcore 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>=global_level) std::clog << s << '\n'; -#endif // NETGEN_USE_SPDLOG } -#ifdef NETGEN_USE_SPDLOG - namespace detail - { - std::vector>& GetDefaultSinks() - { - static std::vector> sinks = - { std::make_shared() }; - return sinks; - } - std::shared_ptr CreateDefaultLogger(const std::string& name) - { - auto& default_sinks = GetDefaultSinks(); - auto logger = std::make_shared(name, default_sinks.begin(), default_sinks.end()); - spdlog::details::registry::instance().register_and_init(logger); - return logger; - } - } // namespace detail - - std::shared_ptr GetLogger(const std::string& name) - { - auto logger = spdlog::get(name); - if(!logger) - logger = detail::CreateDefaultLogger(name); - return std::make_shared(logger); - } - - void SetLoggingLevel(spdlog::level::level_enum level, const std::string& name) - { - if(!name.empty()) - spdlog::get(name)->set_level(level); - else - spdlog::set_level(level); - } - - void AddFileSink(const std::string& filename, spdlog::level::level_enum level, const std::string& logger) - { - auto sink = std::make_shared(filename); - sink->set_level(level); - if(!logger.empty()) - GetLogger(logger)->logger->sinks().push_back(sink); - else - { - detail::GetDefaultSinks().push_back(sink); - spdlog::details::registry::instance().apply_all([sink](auto logger) { logger->sinks().push_back(sink); }); - } - } - - void AddConsoleSink(spdlog::level::level_enum level, const std::string& logger) - { - auto sink = std::make_shared(); - sink->set_level(level); - if(!logger.empty()) - GetLogger(logger)->logger->sinks().push_back(sink); - else - { - detail::GetDefaultSinks().push_back(sink); - spdlog::details::registry::instance().apply_all([sink](auto logger) { logger->sinks().push_back(sink); }); - } - } - - void ClearLoggingSinks(const std::string& logger) - { - if(!logger.empty()) - GetLogger(logger)->logger->sinks().clear(); - else - { - detail::GetDefaultSinks().clear(); - spdlog::details::registry::instance().apply_all([](auto logger) { logger->sinks().clear(); }); - } - } - - void FlushOnLoggingLevel(spdlog::level::level_enum level, const std::string& logger) - { - if(!logger.empty()) - GetLogger(logger)->logger->flush_on(level); - else - spdlog::flush_on(level); - } - -#else // NETGEN_USE_SPDLOG } //namespace ngcore namespace spdlog @@ -140,5 +47,3 @@ namespace ngcore void ClearLoggingSinks(const std::string& /*unused*/) {} void FlushOnLoggingLevel(level::level_enum /*unused*/, const std::string& /*unused*/) {} } //namespace ngcore - -#endif // NETGEN_USE_SPDLOG diff --git a/libsrc/core/logging.hpp b/libsrc/core/logging.hpp index adfed7ed..0e010b1a 100644 --- a/libsrc/core/logging.hpp +++ b/libsrc/core/logging.hpp @@ -1,7 +1,6 @@ #ifndef NETGEN_CORE_LOGGING_HPP #define NETGEN_CORE_LOGGING_HPP -#undef NETGEN_USE_SPDLOG #include #include #include @@ -11,15 +10,6 @@ #include "ngcore_api.hpp" #include "utils.hpp" -#ifdef NETGEN_USE_SPDLOG -#include -#include // to be able to parse anything to logger that implements operator << ostream -#ifdef NETGEN_LOG_DEBUG -#define SPDLOG_DEBUG_ON -#define NETGEN_DEBUG_LOG(logger, ...) SPDLOG_DEBUG(logger, __VA_ARGS__) -#endif // NETGEN_LOG_DEBUG -#endif // NETGEN_USE_SPDLOG - #ifndef NETGEN_DEBUG_LOG #define NETGEN_DEBUG_LOG(logger, ...) #endif // NETGEN_DEBUG_LOG @@ -52,7 +42,12 @@ namespace ngcore static NGCORE_API level::level_enum global_level; public: - static void SetGlobalLoggingLevel( level::level_enum level ) { global_level = level; } + static auto SetGlobalLoggingLevel( level::level_enum level ) + { + auto oldval = global_level; + global_level = level; + return oldval; + } std::shared_ptr logger; @@ -60,13 +55,6 @@ namespace ngcore void NGCORE_API log( level::level_enum level, std::string && s); -#ifdef NETGEN_USE_SPDLOG - template - void log( level::level_enum level, const char* str, Args ... args) - { - log(level, fmt::format(str, args...)); - } -#else // NETGEN_USE_SPDLOG template std::string replace(std::string s, const T & t) { @@ -100,7 +88,6 @@ namespace ngcore { log(level, log_helper(std::string(str), args...)); } -#endif // NETGEN_USE_SPDLOG template void trace( const char* str, Args ... args) { log(level::level_enum::trace, str, args...); } diff --git a/libsrc/core/memtracer.hpp b/libsrc/core/memtracer.hpp index 15b05ebf..757e6405 100644 --- a/libsrc/core/memtracer.hpp +++ b/libsrc/core/memtracer.hpp @@ -35,11 +35,16 @@ namespace ngcore class MemoryTracer { - #ifdef NETGEN_TRACE_MEMORY +#if defined(NETGEN_TRACE_MEMORY) && !defined(__CUDA_ARCH__) NGCORE_API static std::vector names; NGCORE_API static std::vector parents; - static int CreateId(const std::string& name) + #if defined(NETGEN_CHECK_RANGE) + NGCORE_API static std::atomic total_memory; + mutable size_t allocated_memory = 0; + #endif // NETGEN_CHECK_RANGE + + static int CreateId(const std::string& name = "") { int id = names.size(); names.push_back(name); @@ -48,7 +53,7 @@ namespace ngcore std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl; return id; } - int id; + mutable int id = 0; public: @@ -57,8 +62,33 @@ namespace ngcore id = CreateId(name); } - // not tracing - MemoryTracer() : id(0) {} + MemoryTracer() { } + + MemoryTracer(const MemoryTracer & tracer) + { + (*this) = tracer; + } + + MemoryTracer(MemoryTracer && tracer) + { + (*this) = std::move(tracer); + } + + MemoryTracer & operator=(const MemoryTracer & tracer) { + if(tracer.id) + id = CreateId(names[tracer.id]); + return *this; + } + + MemoryTracer & operator=(MemoryTracer && tracer) { + ngcore::Swap(id, tracer.id); + + #if defined(NETGEN_CHECK_RANGE) + ngcore::Swap(allocated_memory, tracer.allocated_memory); + #endif // NETGEN_CHECK_RANGE + + return *this; + } template MemoryTracer( std::string name, TRest & ... rest ) @@ -67,38 +97,48 @@ namespace ngcore Track(rest...); } + #if defined(NETGEN_CHECK_RANGE) + // check if all memory was freed when object is destroyed + ~MemoryTracer() + { + NETGEN_CHECK_SAME(allocated_memory, 0); + } + #endif // NETGEN_CHECK_RANGE + NETGEN_INLINE void Alloc(size_t size) const { + #if defined(NETGEN_CHECK_RANGE) + // Trace also nameless Memtracer objects if range checks are active + if(!id && size) + id = CreateId(); + #endif // NETGEN_CHECK_RANGE + if(id && trace) trace->AllocMemory(id, size); + + #if defined(NETGEN_CHECK_RANGE) + if(id) + { + allocated_memory += size; + total_memory += size; + } + #endif // NETGEN_CHECK_RANGE } 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(mysizeChangeMemory(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); - } + #if defined(NETGEN_CHECK_RANGE) + if(id) + { + // check if we have at least size bytes of memory currently allocated (such that allocated_memory doesn't get negative) + NETGEN_CHECK_RANGE(allocated_memory, static_cast(size), std::numeric_limits::max()); + allocated_memory -= size; + total_memory -= size; + #endif // NETGEN_CHECK_RANGE + } } int GetId() const { return id; } @@ -148,7 +188,15 @@ namespace ngcore static const std::vector & GetNames() { return names; } static const std::vector & GetParents() { return parents; } -#else // NETGEN_TRACE_MEMORY + static size_t GetTotalMemory() + { + #if defined(NETGEN_CHECK_RANGE) + return total_memory; + #else + return 0; + #endif // NETGEN_CHECK_RANGE + } +#else // defined(NETGEN_TRACE_MEMORY) && !defined(__CUDA_ARCH__) public: MemoryTracer() {} MemoryTracer( std::string /* name */ ) {} @@ -157,7 +205,6 @@ namespace ngcore void Alloc(size_t /* size */) const {} void Free(size_t /* size */) const {} - void Swap(...) const {} int GetId() const { return 0; } template @@ -166,6 +213,7 @@ namespace ngcore static std::string GetName(int /* id */) { return ""; } std::string GetName() const { return ""; } void SetName(std::string /* name */) const {} + static size_t GetTotalMemory() { return 0; } #endif // NETGEN_TRACE_MEMORY }; } // namespace ngcore diff --git a/libsrc/core/mpi4py_pycapi.h b/libsrc/core/mpi4py_pycapi.h new file mode 100644 index 00000000..87d0c69e --- /dev/null +++ b/libsrc/core/mpi4py_pycapi.h @@ -0,0 +1,245 @@ +/* Author: Lisandro Dalcin */ +/* Contact: dalcinl@gmail.com */ + +#ifndef MPI4PY_PYCAPI_H +#define MPI4PY_PYCAPI_H + +#include +#include + +#define _mpi4py_declare_pycapi(Type, star) \ +static PyTypeObject *_mpi4py_PyMPI##Type = NULL; \ +static PyObject *(*_mpi4py_PyMPI##Type##_New)(MPI_##Type star) = NULL; \ +static MPI_##Type *(*_mpi4py_PyMPI##Type##_Get)(PyObject *) = NULL; + +#ifndef MPI4PY_LIMITED_API_SKIP_DATATYPE +_mpi4py_declare_pycapi(Datatype,) +#define PyMPIDatatype_Type (*_mpi4py_PyMPIDatatype) +#define PyMPIDatatype_New _mpi4py_PyMPIDatatype_New +#define PyMPIDatatype_Get _mpi4py_PyMPIDatatype_Get +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_STATUS +_mpi4py_declare_pycapi(Status,*) +#define PyMPIStatus_Type (*_mpi4py_PyMPIStatus) +#define PyMPIStatus_New _mpi4py_PyMPIStatus_New +#define PyMPIStatus_Get _mpi4py_PyMPIStatus_Get +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_REQUEST +_mpi4py_declare_pycapi(Request,) +#define PyMPIRequest_Type (*_mpi4py_PyMPIRequest) +#define PyMPIRequest_New _mpi4py_PyMPIRequest_New +#define PyMPIRequest_Get _mpi4py_PyMPIRequest_Get +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_MESSAGE +_mpi4py_declare_pycapi(Message,) +#define PyMPIMessage_Type (*_mpi4py_PyMPIMessage) +#define PyMPIMessage_New _mpi4py_PyMPIMessage_New +#define PyMPIMessage_Get _mpi4py_PyMPIMessage_Get +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_OP +_mpi4py_declare_pycapi(Op,) +#define PyMPIOp_Type (*_mpi4py_PyMPIOp) +#define PyMPIOp_New _mpi4py_PyMPIOp_New +#define PyMPIOp_Get _mpi4py_PyMPIOp_Get +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_GROUP +_mpi4py_declare_pycapi(Group,) +#define PyMPIGroup_Type (*_mpi4py_PyMPIGroup) +#define PyMPIGroup_New _mpi4py_PyMPIGroup_New +#define PyMPIGroup_Get _mpi4py_PyMPIGroup_Get +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_INFO +_mpi4py_declare_pycapi(Info,) +#define PyMPIInfo_Type (*_mpi4py_PyMPIInfo) +#define PyMPIInfo_New _mpi4py_PyMPIInfo_New +#define PyMPIInfo_Get _mpi4py_PyMPIInfo_Get +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_ERRHANDLER +_mpi4py_declare_pycapi(Errhandler,) +#define PyMPIErrhandler_Type (*_mpi4py_PyMPIErrhandler) +#define PyMPIErrhandler_New _mpi4py_PyMPIErrhandler_New +#define PyMPIErrhandler_Get _mpi4py_PyMPIErrhandler_Get +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_SESSION +_mpi4py_declare_pycapi(Session,) +#define PyMPISession_Type (*_mpi4py_PyMPISession) +#define PyMPISession_New _mpi4py_PyMPISession_New +#define PyMPISession_Get _mpi4py_PyMPISession_Get +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_COMM +_mpi4py_declare_pycapi(Comm,) +#define PyMPIComm_Type (*_mpi4py_PyMPIComm) +#define PyMPIComm_New _mpi4py_PyMPIComm_New +#define PyMPIComm_Get _mpi4py_PyMPIComm_Get +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_WIN +_mpi4py_declare_pycapi(Win,) +#define PyMPIWin_Type (*_mpi4py_PyMPIWin) +#define PyMPIWin_New _mpi4py_PyMPIWin_New +#define PyMPIWin_Get _mpi4py_PyMPIWin_Get +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_FILE +_mpi4py_declare_pycapi(File,) +#define PyMPIFile_Type (*_mpi4py_PyMPIFile) +#define PyMPIFile_New _mpi4py_PyMPIFile_New +#define PyMPIFile_Get _mpi4py_PyMPIFile_Get +#endif + +#undef _mpi4py_define_pycapi + +static int _mpi4py_ImportType(PyObject *module, + const char *type_name, + PyTypeObject **type) +{ + PyObject *attr = NULL; + attr = PyObject_GetAttrString(module, type_name); + if (!attr) + goto fn_fail; + if (!PyType_Check(attr)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s is not a type object", + PyModule_GetName(module), type_name); + goto fn_fail; + } + *type = (PyTypeObject *)attr; + return 0; + fn_fail: + Py_DecRef(attr); + return -1; +} + +static int _mpi4py_ImportFunc(PyObject *module, + const char *func_name, + const char *signature, + void (**func)(void)) +{ + PyObject *pyxcapi = NULL; + PyObject *capsule = NULL; + union { void *obj; void (*fcn)(void); } ptr; + pyxcapi = PyObject_GetAttrString(module, (char *)"__pyx_capi__"); + if (!pyxcapi) + goto fn_fail; + + capsule = PyDict_GetItemString(pyxcapi, func_name); + if (!capsule) { + PyErr_Format(PyExc_ImportError, + "%.200s does not export expected C function %.200s", + PyModule_GetName(module), func_name); + goto fn_fail; + } + if (!PyCapsule_CheckExact(capsule)) { + PyErr_Format(PyExc_TypeError, + "%.200s.%.200s is not a capsule", + PyModule_GetName(module), func_name); + } + if (!signature) { + signature = PyCapsule_GetName(capsule); + } + if (!PyCapsule_IsValid(capsule, signature)) { + PyErr_Format(PyExc_TypeError, + "C function %.200s.%.200s has wrong signature " + "(expected %.500s, got %.500s)", + PyModule_GetName(module), func_name, + signature, PyCapsule_GetName(capsule)); + goto fn_fail; + } + ptr.obj = PyCapsule_GetPointer(capsule, signature); + if (!ptr.obj) + goto fn_fail; + *func = ptr.fcn; + Py_DecRef(pyxcapi); + return 0; + fn_fail: + Py_DecRef(pyxcapi); + return -1; +} + +static int import_mpi4py_MPI(void) +{ + PyObject *module = PyImport_ImportModule("mpi4py.MPI"); + if (!module) + goto fn_fail; + +#define _mpi4py_import_pycapi(Type) do { \ + if (_mpi4py_ImportType(module, #Type, &_mpi4py_PyMPI##Type) < 0) \ + goto fn_fail; \ + if (_mpi4py_ImportFunc(module, "PyMPI" #Type "_New", NULL, \ + (void (**)(void))&_mpi4py_PyMPI##Type##_New) < 0) \ + goto fn_fail; \ + if (_mpi4py_ImportFunc(module, "PyMPI" #Type "_Get", NULL, \ + (void (**)(void))&_mpi4py_PyMPI##Type##_Get) < 0) \ + goto fn_fail; \ + } while (0) + +#ifndef MPI4PY_LIMITED_API_SKIP_DATATYPE + _mpi4py_import_pycapi(Datatype); +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_STATUS + _mpi4py_import_pycapi(Status); +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_REQUEST + _mpi4py_import_pycapi(Request); +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_MESSAGE + _mpi4py_import_pycapi(Message); +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_OP + _mpi4py_import_pycapi(Op); +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_GROUP + _mpi4py_import_pycapi(Group); +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_INFO + _mpi4py_import_pycapi(Info); +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_ERRHANDLER + _mpi4py_import_pycapi(Errhandler); +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_SESSION + _mpi4py_import_pycapi(Session); +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_COMM + _mpi4py_import_pycapi(Comm); +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_WIN + _mpi4py_import_pycapi(Win); +#endif + +#ifndef MPI4PY_LIMITED_API_SKIP_FILE + _mpi4py_import_pycapi(File); +#endif + +#undef _mpi4py_import_pycapi + + Py_DecRef(module); + return 0; + fn_fail: + Py_DecRef(module); + return -1; +} + +#define __PYX_HAVE_API__mpi4py__MPI +#define import_mpi4py__MPI import_mpi4py_MPI + +#endif /* MPI4PY_PYCAPI_H */ diff --git a/libsrc/core/mpi_wrapper.hpp b/libsrc/core/mpi_wrapper.hpp index 9a007a80..434e2ce5 100644 --- a/libsrc/core/mpi_wrapper.hpp +++ b/libsrc/core/mpi_wrapper.hpp @@ -1,16 +1,16 @@ #ifndef NGCORE_MPIWRAPPER_HPP #define NGCORE_MPIWRAPPER_HPP -#ifdef PARALLEL -#define OMPI_SKIP_MPICXX -#include -#endif +#include + +#include #include "array.hpp" #include "table.hpp" #include "exception.hpp" #include "profiler.hpp" #include "ngstream.hpp" +#include "ng_mpi.hpp" namespace ngcore { @@ -20,52 +20,124 @@ namespace ngcore template struct MPI_typetrait { }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_INT; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_INT; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_SHORT; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_SHORT; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_CHAR; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_CHAR; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_CHAR; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_CHAR; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_CHAR; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_CHAR; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_UINT64_T; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_UINT64_T; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_DOUBLE; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_DOUBLE; } }; + + template <> struct MPI_typetrait> { + static NG_MPI_Datatype MPIType () { return NG_MPI_CXX_DOUBLE_COMPLEX; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_C_BOOL; } }; + static NG_MPI_Datatype MPIType () { return NG_MPI_C_BOOL; } }; + + template + struct MPI_typetrait> + { + static NG_MPI_Datatype MPIType () + { + static NG_MPI_Datatype NG_MPI_T = 0; + if (!NG_MPI_T) + { + NG_MPI_Type_contiguous ( S, MPI_typetrait::MPIType(), &NG_MPI_T); + NG_MPI_Type_commit ( &NG_MPI_T ); + } + return NG_MPI_T; + } + }; template ::MPIType())> - inline MPI_Datatype GetMPIType () { + inline NG_MPI_Datatype GetMPIType () { return MPI_typetrait::MPIType(); } template - inline MPI_Datatype GetMPIType (T &) { + inline NG_MPI_Datatype GetMPIType (T &) { return GetMPIType(); } + class NgMPI_Request + { + NG_MPI_Request request; + public: + NgMPI_Request (NG_MPI_Request requ) : request{requ} { } + NgMPI_Request (const NgMPI_Request&) = delete; + NgMPI_Request (NgMPI_Request&&) = default; + ~NgMPI_Request () { NG_MPI_Wait (&request, NG_MPI_STATUS_IGNORE); } + void Wait() { NG_MPI_Wait (&request, NG_MPI_STATUS_IGNORE); } + operator NG_MPI_Request() && + { + auto tmp = request; + request = NG_MPI_REQUEST_NULL; + return tmp; + } + }; - inline void MyMPI_WaitAll (FlatArray requests) + class NgMPI_Requests + { + Array requests; + public: + NgMPI_Requests() = default; + ~NgMPI_Requests() { WaitAll(); } + + void Reset() { requests.SetSize0(); } + + NgMPI_Requests & operator+= (NgMPI_Request && r) + { + requests += NG_MPI_Request(std::move(r)); + return *this; + } + + NgMPI_Requests & operator+= (NG_MPI_Request r) + { + requests += r; + return *this; + } + + void WaitAll() + { + static Timer t("NgMPI - WaitAll"); RegionTimer reg(t); + if (!requests.Size()) return; + NG_MPI_Waitall (requests.Size(), requests.Data(), NG_MPI_STATUSES_IGNORE); + } + + int WaitAny () + { + int nr; + NG_MPI_Waitany (requests.Size(), requests.Data(), &nr, NG_MPI_STATUS_IGNORE); + return nr; + } + }; + + [[deprecated("use requests.WaitAll instread")]] + inline void MyMPI_WaitAll (FlatArray requests) { static Timer t("MPI - WaitAll"); RegionTimer reg(t); if (!requests.Size()) return; - MPI_Waitall (requests.Size(), requests.Data(), MPI_STATUSES_IGNORE); + NG_MPI_Waitall (requests.Size(), requests.Data(), NG_MPI_STATUSES_IGNORE); } - - inline int MyMPI_WaitAny (FlatArray requests) + + [[deprecated("use requests.WaitAny instread")]] + inline int MyMPI_WaitAny (FlatArray requests) { int nr; - MPI_Waitany (requests.Size(), requests.Data(), &nr, MPI_STATUS_IGNORE); + NG_MPI_Waitany (requests.Size(), requests.Data(), &nr, NG_MPI_STATUS_IGNORE); return nr; } @@ -74,7 +146,7 @@ namespace ngcore class NgMPI_Comm { protected: - MPI_Comm comm; + NG_MPI_Comm comm; bool valid_comm; int * refcount; int rank, size; @@ -83,11 +155,11 @@ namespace ngcore : valid_comm(false), refcount(nullptr), rank(0), size(1) { ; } - NgMPI_Comm (MPI_Comm _comm, bool owns = false) + NgMPI_Comm (NG_MPI_Comm _comm, bool owns = false) : comm(_comm), valid_comm(true) { int flag; - MPI_Initialized (&flag); + NG_MPI_Initialized (&flag); if (!flag) { valid_comm = false; @@ -102,8 +174,8 @@ namespace ngcore else refcount = new int{1}; - MPI_Comm_rank(comm, &rank); - MPI_Comm_size(comm, &size); + NG_MPI_Comm_rank(comm, &rank); + NG_MPI_Comm_size(comm, &size); } NgMPI_Comm (const NgMPI_Comm & c) @@ -124,7 +196,7 @@ namespace ngcore { if (refcount) if (--(*refcount) == 0) - MPI_Comm_free(&comm); + NG_MPI_Comm_free(&comm); } bool ValidCommunicator() const @@ -136,7 +208,7 @@ namespace ngcore { if (refcount) if (--(*refcount) == 0) - MPI_Comm_free(&comm); + NG_MPI_Comm_free(&comm); refcount = c.refcount; if (refcount) (*refcount)++; @@ -152,7 +224,7 @@ namespace ngcore InvalidCommException() : Exception("Do not have a valid communicator") { ; } }; - operator MPI_Comm() const { + operator NG_MPI_Comm() const { if (!valid_comm) throw InvalidCommException(); return comm; } @@ -161,7 +233,7 @@ namespace ngcore int Size() const { return size; } void Barrier() const { static Timer t("MPI - Barrier"); RegionTimer reg(t); - if (size > 1) MPI_Barrier (comm); + if (size > 1) NG_MPI_Barrier (comm); } @@ -169,82 +241,82 @@ namespace ngcore template())> void Send (T & val, int dest, int tag) const { - MPI_Send (&val, 1, GetMPIType(), dest, tag, comm); + NG_MPI_Send (&val, 1, GetMPIType(), dest, tag, comm); } void Send (const std::string & s, int dest, int tag) const { - MPI_Send( const_cast (&s[0]), s.length(), MPI_CHAR, dest, tag, comm); + NG_MPI_Send( const_cast (&s[0]), s.length(), NG_MPI_CHAR, dest, tag, comm); } template())> void Send(FlatArray s, int dest, int tag) const { - MPI_Send (s.Data(), s.Size(), GetMPIType(), dest, tag, comm); + NG_MPI_Send (s.Data(), s.Size(), GetMPIType(), dest, tag, comm); } template())> void Recv (T & val, int src, int tag) const { - MPI_Recv (&val, 1, GetMPIType(), src, tag, comm, MPI_STATUS_IGNORE); + NG_MPI_Recv (&val, 1, GetMPIType(), src, tag, comm, NG_MPI_STATUS_IGNORE); } void Recv (std::string & s, int src, int tag) const { - MPI_Status status; + NG_MPI_Status status; int len; - MPI_Probe (src, tag, comm, &status); - MPI_Get_count (&status, MPI_CHAR, &len); + NG_MPI_Probe (src, tag, comm, &status); + NG_MPI_Get_count (&status, NG_MPI_CHAR, &len); // s.assign (len, ' '); s.resize (len); - MPI_Recv( &s[0], len, MPI_CHAR, src, tag, comm, MPI_STATUS_IGNORE); + NG_MPI_Recv( &s[0], len, NG_MPI_CHAR, src, tag, comm, NG_MPI_STATUS_IGNORE); } template ())> void Recv (FlatArray s, int src, int tag) const { - MPI_Recv (s.Data(), s.Size(), GetMPIType (), src, tag, comm, MPI_STATUS_IGNORE); + NG_MPI_Recv (s.Data(), s.Size(), GetMPIType (), src, tag, comm, NG_MPI_STATUS_IGNORE); } template ())> void Recv (Array & s, int src, int tag) const { - MPI_Status status; + NG_MPI_Status status; int len; - const MPI_Datatype MPI_T = GetMPIType (); - MPI_Probe (src, tag, comm, &status); - MPI_Get_count (&status, MPI_T, &len); + const NG_MPI_Datatype NG_MPI_T = GetMPIType (); + NG_MPI_Probe (src, tag, comm, &status); + NG_MPI_Get_count (&status, NG_MPI_T, &len); s.SetSize (len); - MPI_Recv (s.Data(), len, MPI_T, src, tag, comm, MPI_STATUS_IGNORE); + NG_MPI_Recv (s.Data(), len, NG_MPI_T, src, tag, comm, NG_MPI_STATUS_IGNORE); } /** --- non-blocking P2P --- **/ - - template())> - MPI_Request ISend (T & val, int dest, int tag) const - { - MPI_Request request; - MPI_Isend (&val, 1, GetMPIType(), dest, tag, comm, &request); - return request; - } - - template())> - MPI_Request ISend (FlatArray s, int dest, int tag) const - { - MPI_Request request; - MPI_Isend (s.Data(), s.Size(), GetMPIType(), dest, tag, comm, &request); - return request; - } template())> - MPI_Request IRecv (T & val, int dest, int tag) const + [[nodiscard]] NG_MPI_Request ISend (T & val, int dest, int tag) const { - MPI_Request request; - MPI_Irecv (&val, 1, GetMPIType(), dest, tag, comm, &request); + NG_MPI_Request request; + NG_MPI_Isend (&val, 1, GetMPIType(), dest, tag, comm, &request); return request; } template())> - MPI_Request IRecv (FlatArray s, int src, int tag) const + [[nodiscard]] NG_MPI_Request ISend (FlatArray s, int dest, int tag) const + { + NG_MPI_Request request; + NG_MPI_Isend (s.Data(), s.Size(), GetMPIType(), dest, tag, comm, &request); + return request; + } + + template())> + [[nodiscard]] NG_MPI_Request IRecv (T & val, int dest, int tag) const + { + NG_MPI_Request request; + NG_MPI_Irecv (&val, 1, GetMPIType(), dest, tag, comm, &request); + return request; + } + + template())> + [[nodiscard]] NG_MPI_Request IRecv (FlatArray s, int src, int tag) const { - MPI_Request request; - MPI_Irecv (s.Data(), s.Size(), GetMPIType(), src, tag, comm, &request); + NG_MPI_Request request; + NG_MPI_Irecv (s.Data(), s.Size(), GetMPIType(), src, tag, comm, &request); return request; } @@ -252,46 +324,55 @@ namespace ngcore /** --- collectives --- **/ template ())> - T Reduce (T d, const MPI_Op & op, int root = 0) const + T Reduce (T d, const NG_MPI_Op & op, int root = 0) const { static Timer t("MPI - Reduce"); RegionTimer reg(t); if (size == 1) return d; T global_d; - MPI_Reduce (&d, &global_d, 1, GetMPIType(), op, root, comm); + NG_MPI_Reduce (&d, &global_d, 1, GetMPIType(), op, root, comm); return global_d; } template ())> - T AllReduce (T d, const MPI_Op & op) const + T AllReduce (T d, const NG_MPI_Op & op) const { static Timer t("MPI - AllReduce"); RegionTimer reg(t); if (size == 1) return d; T global_d; - MPI_Allreduce ( &d, &global_d, 1, GetMPIType(), op, comm); + NG_MPI_Allreduce ( &d, &global_d, 1, GetMPIType(), op, comm); return global_d; } template ())> - void AllReduce (FlatArray d, const MPI_Op & op) const + void AllReduce (FlatArray d, const NG_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(), op, comm); + NG_MPI_Allreduce (NG_MPI_IN_PLACE, d.Data(), d.Size(), GetMPIType(), op, comm); } template ())> void Bcast (T & s, int root = 0) const { if (size == 1) return; static Timer t("MPI - Bcast"); RegionTimer reg(t); - MPI_Bcast (&s, 1, GetMPIType(), root, comm); + NG_MPI_Bcast (&s, 1, GetMPIType(), root, comm); } + + template + void Bcast (std::array & d, int root = 0) const + { + if (size == 1) return; + if (S != 0) + NG_MPI_Bcast (&d[0], S, GetMPIType(), root, comm); + } + template - void Bcast (Array & d, int root = 0) + void Bcast (Array & d, int root = 0) const { if (size == 1) return; @@ -299,7 +380,7 @@ namespace ngcore Bcast (ds, root); if (Rank() != root) d.SetSize (ds); if (ds != 0) - MPI_Bcast (d.Data(), ds, GetMPIType(), root, comm); + NG_MPI_Bcast (d.Data(), ds, GetMPIType(), root, comm); } @@ -309,14 +390,34 @@ namespace ngcore int len = s.length(); Bcast (len, root); if (rank != 0) s.resize (len); - MPI_Bcast (&s[0], len, MPI_CHAR, root, comm); + NG_MPI_Bcast (&s[0], len, NG_MPI_CHAR, root, comm); } + + + template + [[nodiscard]] NgMPI_Request IBcast (std::array & d, int root = 0) const + { + NG_MPI_Request request; + NG_MPI_Ibcast (&d[0], S, GetMPIType(), root, comm, &request); + return request; + } + + template + [[nodiscard]] NgMPI_Request IBcast (FlatArray d, int root = 0) const + { + NG_MPI_Request request; + int ds = d.Size(); + NG_MPI_Ibcast (d.Data(), ds, GetMPIType(), root, comm, &request); + return request; + } + + template void AllToAll (FlatArray send, FlatArray recv) const { - MPI_Alltoall (send.Data(), 1, GetMPIType(), - recv.Data(), 1, GetMPIType(), comm); + NG_MPI_Alltoall (send.Data(), 1, GetMPIType(), + recv.Data(), 1, GetMPIType(), comm); } @@ -324,16 +425,16 @@ namespace ngcore void ScatterRoot (FlatArray send) const { if (size == 1) return; - MPI_Scatter (send.Data(), 1, GetMPIType(), - MPI_IN_PLACE, -1, GetMPIType(), 0, comm); + NG_MPI_Scatter (send.Data(), 1, GetMPIType(), + NG_MPI_IN_PLACE, -1, GetMPIType(), 0, comm); } template void Scatter (T & recv) const { if (size == 1) return; - MPI_Scatter (NULL, 0, GetMPIType(), - &recv, 1, GetMPIType(), 0, comm); + NG_MPI_Scatter (NULL, 0, GetMPIType(), + &recv, 1, GetMPIType(), 0, comm); } template @@ -341,15 +442,15 @@ namespace ngcore { recv[0] = T(0); if (size == 1) return; - MPI_Gather (MPI_IN_PLACE, 1, GetMPIType(), - recv.Data(), 1, GetMPIType(), 0, comm); + NG_MPI_Gather (NG_MPI_IN_PLACE, 1, GetMPIType(), + recv.Data(), 1, GetMPIType(), 0, comm); } template void Gather (T send) const { if (size == 1) return; - MPI_Gather (&send, 1, GetMPIType(), + NG_MPI_Gather (&send, 1, GetMPIType(), NULL, 1, GetMPIType(), 0, comm); } @@ -362,7 +463,7 @@ namespace ngcore recv[0] = val; return; } - MPI_Allgather (&val, 1, GetMPIType(), + NG_MPI_Allgather (&val, 1, GetMPIType(), recv.Data(), 1, GetMPIType(), comm); } @@ -383,16 +484,16 @@ namespace ngcore recv_data = DynamicTable (recv_sizes, true); - Array requests; + NgMPI_Requests requests; for (int dest = 0; dest < size; dest++) if (dest != rank && send_data[dest].Size()) - requests.Append (ISend (FlatArray(send_data[dest]), dest, tag)); + requests += ISend (FlatArray(send_data[dest]), dest, tag); for (int dest = 0; dest < size; dest++) if (dest != rank && recv_data[dest].Size()) - requests.Append (IRecv (FlatArray(recv_data[dest]), dest, tag)); + requests += IRecv (FlatArray(recv_data[dest]), dest, tag); - MyMPI_WaitAll (requests); + requests.WaitAll(); } @@ -401,86 +502,69 @@ namespace ngcore NgMPI_Comm SubCommunicator (FlatArray 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); + NG_MPI_Comm subcomm; + NG_MPI_Group gcomm, gsubcomm; + NG_MPI_Comm_group(comm, &gcomm); + NG_MPI_Group_incl(gcomm, procs.Size(), procs.Data(), &gsubcomm); + NG_MPI_Comm_create_group(comm, gsubcomm, 4242, &subcomm); return NgMPI_Comm(subcomm, true); } }; // class NgMPI_Comm - - - - - - 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 { + class NG_MPI_Comm { int nr; public: - MPI_Comm (int _nr = 0) : nr(_nr) { ; } + NG_MPI_Comm (int _nr = 0) : nr(_nr) { ; } operator int() const { return nr; } - bool operator== (MPI_Comm c2) const { return nr == c2.nr; } + bool operator== (NG_MPI_Comm c2) const { return nr == c2.nr; } }; - static MPI_Comm MPI_COMM_WORLD = 12345, MPI_COMM_NULL = 10000; + static NG_MPI_Comm NG_MPI_COMM_WORLD = 12345, NG_MPI_COMM_NULL = 10000; - typedef int MPI_Op; - typedef int MPI_Datatype; - typedef int MPI_Request; + typedef int NG_MPI_Op; + typedef int NG_MPI_Datatype; + typedef int NG_MPI_Request; - enum { MPI_SUM = 0, MPI_MIN = 1, MPI_MAX = 2, MPI_LOR = 4711 }; + enum { NG_MPI_SUM = 0, NG_MPI_MIN = 1, NG_MPI_MAX = 2, NG_MPI_LOR = 4711 }; - inline void MPI_Type_contiguous ( int, MPI_Datatype, MPI_Datatype*) { ; } - inline void MPI_Type_commit ( MPI_Datatype * ) { ; } + inline void NG_MPI_Type_contiguous ( int, NG_MPI_Datatype, NG_MPI_Datatype*) { ; } + inline void NG_MPI_Type_commit ( NG_MPI_Datatype * ) { ; } + + template struct MPI_typetrait { + static NG_MPI_Datatype MPIType () { return -1; } + }; + template + inline NG_MPI_Datatype GetMPIType () { return -1; } + + class NgMPI_Request { + public: + NgMPI_Request() = default; + NgMPI_Request(NgMPI_Request &&) { ; } + NgMPI_Request(NG_MPI_Request &&) { ; } + }; + class NgMPI_Requests + { + public: + NgMPI_Requests & operator+= (NgMPI_Request &&) { return *this; } + NgMPI_Requests & operator+= (NG_MPI_Request r) { return *this; } + void Reset() { ; } + void WaitAll() { ; } + int WaitAny() { return 0; } + }; class NgMPI_Comm { public: NgMPI_Comm () { ; } - NgMPI_Comm (MPI_Comm _comm, bool owns = false) { ; } + NgMPI_Comm (NG_MPI_Comm _comm, bool owns = false) { ; } 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(); } + operator NG_MPI_Comm() const { return NG_MPI_Comm(); } template void Send( T & val, int dest, int tag) const { ; } @@ -498,32 +582,41 @@ namespace ngcore void Recv (Array & s, int src, int tag) const { ; } template - MPI_Request ISend (T & val, int dest, int tag) const { return 0; } + NG_MPI_Request ISend (T & val, int dest, int tag) const { return 0; } template - MPI_Request ISend (FlatArray s, int dest, int tag) const { return 0; } + NG_MPI_Request ISend (FlatArray s, int dest, int tag) const { return 0; } template - MPI_Request IRecv (T & val, int dest, int tag) const { return 0; } + NG_MPI_Request IRecv (T & val, int dest, int tag) const { return 0; } template - MPI_Request IRecv (FlatArray s, int src, int tag) const { return 0; } + NG_MPI_Request IRecv (FlatArray s, int src, int tag) const { return 0; } template - T Reduce (T d, const MPI_Op & op, int root = 0) const { return d; } + T Reduce (T d, const NG_MPI_Op & op, int root = 0) const { return d; } template - T AllReduce (T d, const MPI_Op & op) const { return d; } + T AllReduce (T d, const NG_MPI_Op & op) const { return d; } template - void AllReduce (FlatArray d, const MPI_Op & op) const { ; } + void AllReduce (FlatArray d, const NG_MPI_Op & op) const { ; } template void Bcast (T & s, int root = 0) const { ; } + template + void Bcast (std::array & d, int root = 0) const {} + template - void Bcast (Array & d, int root = 0) { ; } + void Bcast (Array & d, int root = 0) const { ; } + template + NG_MPI_Request IBcast (std::array & d, int root = 0) const { return 0; } + + template + NG_MPI_Request IBcast (FlatArray d, int root = 0) const { return 0; } + template void AllGather (T val, FlatArray recv) const { @@ -539,16 +632,9 @@ namespace ngcore { return *this; } }; - inline void MyMPI_WaitAll (FlatArray requests) { ; } - inline int MyMPI_WaitAny (FlatArray requests) { return 0; } + inline void MyMPI_WaitAll (FlatArray requests) { ; } + inline int MyMPI_WaitAny (FlatArray requests) { return 0; } - class MyMPI - { - public: - MyMPI(int argc, char ** argv) { ; } - }; - - #endif // PARALLEL } // namespace ngcore diff --git a/libsrc/core/ng_mpi.cpp b/libsrc/core/ng_mpi.cpp new file mode 100644 index 00000000..bc0470ef --- /dev/null +++ b/libsrc/core/ng_mpi.cpp @@ -0,0 +1,184 @@ +#define OMPI_SKIP_MPICXX +#include + +#include "ng_mpi.hpp" + +#include + +#include "array.hpp" +#include "ngcore_api.hpp" + +#ifdef NG_PYTHON +#include "pybind11/pytypes.h" +#include "python_ngcore.hpp" + +#define MPI4PY_LIMITED_API 1 +#define MPI4PY_LIMITED_API_SKIP_MESSAGE 1 +#define MPI4PY_LIMITED_API_SKIP_SESSION 1 +#include "mpi4py_pycapi.h" // mpi4py < 4.0.0 +#endif + +#ifdef MSMPI_VER +int MPI_Comm_create_group(MPI_Comm arg0, MPI_Group arg1, int arg2, + MPI_Comm* arg3) { + throw std::runtime_error( + "MPI_Comm_create_group not supported on Microsoft MPI"); +} +static MPI_Datatype MPI_CXX_DOUBLE_COMPLEX; +#endif // MSMPI_VER + +namespace ngcore { + +static_assert(sizeof(MPI_Status) <= sizeof(NG_MPI_Status), "Size mismatch"); +static_assert(alignof(MPI_Status) <= alignof(NG_MPI_Status), "Size mismatch"); + +int mpi2ng(int value) { return value; } +void* mpi2ng(void* ptr) { return ptr; } + +NG_MPI_Status* mpi2ng(MPI_Status* status) { + return reinterpret_cast(status); +} + +#if !defined(MPICH) && !defined(MSMPI_VER) +NG_MPI_Comm mpi2ng(MPI_Comm comm) { return reinterpret_cast(comm); } +#endif + +template +void gather_strided_array(size_t count, char* data) { + static_assert(size <= stride, "Size must be less than or equal to stride"); + if constexpr (size < stride) { + char* dst = data; + char* src = data; + for ( [[maybe_unused]] auto i : Range(count)) { + memcpy(dst, src, size); + dst += size; + src += stride; + } + } +} + +template +T cast_ng2mpi(uintptr_t obj) { + if constexpr (std::is_pointer_v) + return reinterpret_cast(obj); + else + return static_cast(obj); +} + +template +T cast_ng2mpi(uintptr_t* ptr) { + if constexpr (std::is_pointer_v) + return reinterpret_cast(ptr); + else + return static_cast(ptr); +} + +template +T* cast_ng2mpi(TSrc* ptr, int count) { + gather_strided_array(count, + reinterpret_cast(ptr)); + return reinterpret_cast(ptr); +} + +MPI_Comm ng2mpi(NG_MPI_Comm comm) { + static_assert(sizeof(MPI_Comm) <= sizeof(comm.value), "Size mismatch"); + static_assert(alignof(MPI_Comm) <= alignof(NG_MPI_Comm), "Size mismatch"); + return cast_ng2mpi(comm.value); +} + +MPI_Group ng2mpi(NG_MPI_Group group) { + static_assert(sizeof(MPI_Group) <= sizeof(group.value), "Size mismatch"); + static_assert(alignof(MPI_Group) <= alignof(NG_MPI_Group), "Size mismatch"); + return cast_ng2mpi(group.value); +} + +MPI_Comm* ng2mpi(NG_MPI_Comm* comm) { + return cast_ng2mpi(&comm->value); +} +MPI_Group* ng2mpi(NG_MPI_Group* group) { + return cast_ng2mpi(&group->value); +} +MPI_Datatype* ng2mpi(NG_MPI_Datatype* type) { + return cast_ng2mpi(&type->value); +} +MPI_Datatype* ng2mpi(NG_MPI_Datatype* type, int count) { + return cast_ng2mpi(&type->value, count); +} +MPI_Request* ng2mpi(NG_MPI_Request* request) { + return cast_ng2mpi(&request->value); +} +MPI_Request* ng2mpi(NG_MPI_Request* request, int count) { + return cast_ng2mpi(&request->value, count); +} +MPI_Status* ng2mpi(NG_MPI_Status* status) { + return reinterpret_cast(status); +} +MPI_Aint* ng2mpi(NG_MPI_Aint* aint) { + return reinterpret_cast(aint); +} +MPI_Aint* ng2mpi(NG_MPI_Aint* aint, int count) { + return cast_ng2mpi(aint, count); +} + +MPI_Datatype ng2mpi(NG_MPI_Datatype type) { + static_assert(sizeof(MPI_Datatype) <= sizeof(type.value), "Size mismatch"); + return cast_ng2mpi(type.value); +} + +MPI_Request ng2mpi(NG_MPI_Request request) { + static_assert(sizeof(MPI_Request) <= sizeof(request.value), "Size mismatch"); + return cast_ng2mpi(request.value); +} + +MPI_Op ng2mpi(NG_MPI_Op op) { + static_assert(sizeof(MPI_Op) <= sizeof(op.value), "Size mismatch"); + return cast_ng2mpi(op.value); +} + +MPI_Aint ng2mpi(NG_MPI_Aint aint) { + static_assert(sizeof(MPI_Aint) <= sizeof(aint.value), "Size mismatch"); + return cast_ng2mpi(aint.value); +} + +void* ng2mpi(void* ptr) { return ptr; } +char* ng2mpi(char* ptr) { return ptr; } +char*** ng2mpi(char*** ptr) { return ptr; } +int* ng2mpi(int* ptr) { return ptr; } +int ng2mpi(int value) { return value; } + +} // namespace ngcore + +using namespace ngcore; + +extern "C" { +NGCORE_API_EXPORT void ng_init_mpi(); +} + +static bool imported_mpi4py = false; + +void ng_init_mpi() { +#ifdef NG_PYTHON + NG_MPI_CommFromMPI4Py = [](py::handle src, NG_MPI_Comm& dst) -> bool { + if (!imported_mpi4py) { + import_mpi4py__MPI(); + imported_mpi4py = true; + } + PyObject* py_src = src.ptr(); + [[maybe_unused]] auto type = Py_TYPE(py_src); + if (PyObject_TypeCheck(py_src, &PyMPIComm_Type)) { + dst = mpi2ng(*PyMPIComm_Get(py_src)); + return !PyErr_Occurred(); + } + return false; + }; + NG_MPI_CommToMPI4Py = [](NG_MPI_Comm src) -> py::handle { + if (!imported_mpi4py) { + import_mpi4py__MPI(); + imported_mpi4py = true; + } + return py::handle(PyMPIComm_New(ng2mpi(src))); + }; +#endif // NG_PYTHON + +#include "ng_mpi_generated_init.hpp" +} diff --git a/libsrc/core/ng_mpi.hpp b/libsrc/core/ng_mpi.hpp new file mode 100644 index 00000000..3afc0369 --- /dev/null +++ b/libsrc/core/ng_mpi.hpp @@ -0,0 +1,94 @@ +#ifndef NG_MPI_HPP_INCLUDED +#define NG_MPI_HPP_INCLUDED + +#ifdef PARALLEL + +#include +#include +#include + +#include "ngcore_api.hpp" + +#ifndef NG_MPI_WRAPPER +#define OMPI_SKIP_MPICXX +#include +#endif // NG_MPI_WRAPPER + +namespace ngcore { + +NGCORE_API bool MPI_Loaded(); +NGCORE_API void InitMPI( + std::optional mpi_lib_path = std::nullopt); + +#ifdef NG_MPI_WRAPPER +inline void not_implemented() { throw std::runtime_error("Not implemented"); } + +struct NG_MPI_Status { + uintptr_t data[4]; +}; + +struct NG_MPI_Comm { + uintptr_t value; + NG_MPI_Comm() { value = 0; } + NG_MPI_Comm(uintptr_t value_) : value(value_) {} + NG_MPI_Comm(const NG_MPI_Comm &comm) : value(comm.value) {} + + void operator=(int value_) { value = value_; } + void operator=(uintptr_t value_) { value = value_; } + bool operator==(const NG_MPI_Comm &comm) const { return value == comm.value; } + bool operator!=(const NG_MPI_Comm &comm) const { return value != comm.value; } +}; + +struct NG_MPI_Datatype { + uintptr_t value = 0; + NG_MPI_Datatype() = default; + NG_MPI_Datatype(uintptr_t value_) : value(value_) {} + operator bool() const { return value != 0; } + void operator=(NG_MPI_Datatype type) { value = type.value; } + void operator=(uintptr_t value_) { value = value_; } + void operator=(void *value_) { value = reinterpret_cast(value_); } +}; + +struct NG_MPI_Request { + uintptr_t value = 0; + NG_MPI_Request() = default; + NG_MPI_Request(uintptr_t value_) : value(value_) {} + void operator=(uintptr_t value_) { value = value_; } + void operator=(void *value_) { value = reinterpret_cast(value_); } +}; + +struct NG_MPI_Op { + uintptr_t value; + NG_MPI_Op(uintptr_t value_) : value(value_) {} + void operator=(uintptr_t value_) { value = value_; } + void operator=(void *value_) { value = reinterpret_cast(value_); } +}; + +struct NG_MPI_Group { + uintptr_t value = 0; + NG_MPI_Group(uintptr_t value_) : value(value_) {} + NG_MPI_Group() = default; +}; + +struct NG_MPI_Aint { + intptr_t value = 0; + NG_MPI_Aint(intptr_t value_) : value(value_) {} + NG_MPI_Aint() = default; +}; + +#else // NG_MPI_WRAPPER +using NG_MPI_Comm = MPI_Comm; +using NG_MPI_Status = MPI_Status; +using NG_MPI_Datatype = MPI_Datatype; +using NG_MPI_Request = MPI_Request; +using NG_MPI_Op = MPI_Op; +using NG_MPI_Group = MPI_Group; +using NG_MPI_Aint = MPI_Aint; +#endif // NG_MPI_WRAPPER + +#include "ng_mpi_generated_declarations.hpp" + +} // namespace ngcore + +#endif // PARALLEL +#endif // NG_MPI_HPP_INCLUDED diff --git a/libsrc/core/ng_mpi_generated_declarations.hpp b/libsrc/core/ng_mpi_generated_declarations.hpp new file mode 100644 index 00000000..4e19b9ed --- /dev/null +++ b/libsrc/core/ng_mpi_generated_declarations.hpp @@ -0,0 +1,155 @@ +#ifdef NG_MPI_WRAPPER +NGCORE_API extern double (*NG_MPI_Wtime)(); +NGCORE_API extern int (*NG_MPI_Allgather)(void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Allreduce)(void*, void*, int, NG_MPI_Datatype, NG_MPI_Op, NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Alltoall)(void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Barrier)(NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Bcast)(void*, int, NG_MPI_Datatype, int, NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Ibcast)(void*, int, NG_MPI_Datatype, int, NG_MPI_Comm, NG_MPI_Request*); +NGCORE_API extern int (*NG_MPI_Comm_c2f)(NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Comm_create)(NG_MPI_Comm, NG_MPI_Group, NG_MPI_Comm*); +NGCORE_API extern int (*NG_MPI_Comm_create_group)(NG_MPI_Comm, NG_MPI_Group, int, NG_MPI_Comm*); +NGCORE_API extern int (*NG_MPI_Comm_free)(NG_MPI_Comm*); +NGCORE_API extern int (*NG_MPI_Comm_group)(NG_MPI_Comm, NG_MPI_Group*); +NGCORE_API extern int (*NG_MPI_Comm_rank)(NG_MPI_Comm, int*); +NGCORE_API extern int (*NG_MPI_Comm_size)(NG_MPI_Comm, int*); +NGCORE_API extern int (*NG_MPI_Finalize)(); +NGCORE_API extern int (*NG_MPI_Gather)(void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, int, NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Gatherv)(void*, int, NG_MPI_Datatype, void*, int*, int*, NG_MPI_Datatype, int, NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Get_count)(NG_MPI_Status*, NG_MPI_Datatype, int*); +NGCORE_API extern int (*NG_MPI_Get_processor_name)(char*, int*); +NGCORE_API extern int (*NG_MPI_Group_incl)(NG_MPI_Group, int, int*, NG_MPI_Group*); +NGCORE_API extern int (*NG_MPI_Init)(int*, char***); +NGCORE_API extern int (*NG_MPI_Init_thread)(int*, char***, int, int*); +NGCORE_API extern int (*NG_MPI_Initialized)(int*); +NGCORE_API extern int (*NG_MPI_Iprobe)(int, int, NG_MPI_Comm, int*, NG_MPI_Status*); +NGCORE_API extern int (*NG_MPI_Irecv)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*); +NGCORE_API extern int (*NG_MPI_Isend)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*); +NGCORE_API extern int (*NG_MPI_Probe)(int, int, NG_MPI_Comm, NG_MPI_Status*); +NGCORE_API extern int (*NG_MPI_Query_thread)(int*); +NGCORE_API extern int (*NG_MPI_Recv)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Status*); +NGCORE_API extern int (*NG_MPI_Recv_init)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*); +NGCORE_API extern int (*NG_MPI_Reduce)(void*, void*, int, NG_MPI_Datatype, NG_MPI_Op, int, NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Reduce_local)(void*, void*, int, NG_MPI_Datatype, NG_MPI_Op); +NGCORE_API extern int (*NG_MPI_Request_free)(NG_MPI_Request*); +NGCORE_API extern int (*NG_MPI_Scatter)(void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, int, NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Send)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm); +NGCORE_API extern int (*NG_MPI_Send_init)(void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*); +NGCORE_API extern int (*NG_MPI_Startall)(int, NG_MPI_Request*); +NGCORE_API extern int (*NG_MPI_Type_commit)(NG_MPI_Datatype*); +NGCORE_API extern int (*NG_MPI_Type_contiguous)(int, NG_MPI_Datatype, NG_MPI_Datatype*); +NGCORE_API extern int (*NG_MPI_Type_create_resized)(NG_MPI_Datatype, NG_MPI_Aint, NG_MPI_Aint, NG_MPI_Datatype*); +NGCORE_API extern int (*NG_MPI_Type_create_struct)(int, int*, NG_MPI_Aint*, NG_MPI_Datatype*, NG_MPI_Datatype*); +NGCORE_API extern int (*NG_MPI_Type_free)(NG_MPI_Datatype*); +NGCORE_API extern int (*NG_MPI_Type_get_extent)(NG_MPI_Datatype, NG_MPI_Aint*, NG_MPI_Aint*); +NGCORE_API extern int (*NG_MPI_Type_indexed)(int, int*, int*, NG_MPI_Datatype, NG_MPI_Datatype*); +NGCORE_API extern int (*NG_MPI_Type_size)(NG_MPI_Datatype, int*); +NGCORE_API extern int (*NG_MPI_Wait)(NG_MPI_Request*, NG_MPI_Status*); +NGCORE_API extern int (*NG_MPI_Waitall)(int, NG_MPI_Request*, NG_MPI_Status*); +NGCORE_API extern int (*NG_MPI_Waitany)(int, NG_MPI_Request*, int*, NG_MPI_Status*); +NGCORE_API extern NG_MPI_Comm NG_MPI_COMM_NULL; +NGCORE_API extern NG_MPI_Comm NG_MPI_COMM_WORLD; +NGCORE_API extern NG_MPI_Datatype NG_MPI_CHAR; +NGCORE_API extern NG_MPI_Datatype NG_MPI_CXX_DOUBLE_COMPLEX; +NGCORE_API extern NG_MPI_Datatype NG_MPI_C_BOOL; +NGCORE_API extern NG_MPI_Datatype NG_MPI_DATATYPE_NULL; +NGCORE_API extern NG_MPI_Datatype NG_MPI_DOUBLE; +NGCORE_API extern NG_MPI_Datatype NG_MPI_FLOAT; +NGCORE_API extern NG_MPI_Datatype NG_MPI_INT; +NGCORE_API extern NG_MPI_Datatype NG_MPI_SHORT; +NGCORE_API extern NG_MPI_Datatype NG_MPI_UINT64_T; +NGCORE_API extern NG_MPI_Op NG_MPI_LOR; +NGCORE_API extern NG_MPI_Op NG_MPI_MAX; +NGCORE_API extern NG_MPI_Op NG_MPI_MIN; +NGCORE_API extern NG_MPI_Op NG_MPI_SUM; +NGCORE_API extern NG_MPI_Request NG_MPI_REQUEST_NULL; +NGCORE_API extern NG_MPI_Status* NG_MPI_STATUSES_IGNORE; +NGCORE_API extern NG_MPI_Status* NG_MPI_STATUS_IGNORE; +NGCORE_API extern int NG_MPI_ANY_SOURCE; +NGCORE_API extern int NG_MPI_ANY_TAG; +NGCORE_API extern int NG_MPI_MAX_PROCESSOR_NAME; +NGCORE_API extern int NG_MPI_PROC_NULL; +NGCORE_API extern int NG_MPI_ROOT; +NGCORE_API extern int NG_MPI_SUBVERSION; +NGCORE_API extern int NG_MPI_THREAD_MULTIPLE; +NGCORE_API extern int NG_MPI_THREAD_SINGLE; +NGCORE_API extern int NG_MPI_VERSION; +NGCORE_API extern void* NG_MPI_IN_PLACE; +#else // NG_MPI_WRAPPER +#define NG_MPI_Wtime MPI_Wtime +#define NG_MPI_Allgather MPI_Allgather +#define NG_MPI_Allreduce MPI_Allreduce +#define NG_MPI_Alltoall MPI_Alltoall +#define NG_MPI_Barrier MPI_Barrier +#define NG_MPI_Bcast MPI_Bcast +#define NG_MPI_Ibcast MPI_Ibcast +#define NG_MPI_Comm_c2f MPI_Comm_c2f +#define NG_MPI_Comm_create MPI_Comm_create +#define NG_MPI_Comm_create_group MPI_Comm_create_group +#define NG_MPI_Comm_free MPI_Comm_free +#define NG_MPI_Comm_group MPI_Comm_group +#define NG_MPI_Comm_rank MPI_Comm_rank +#define NG_MPI_Comm_size MPI_Comm_size +#define NG_MPI_Finalize MPI_Finalize +#define NG_MPI_Gather MPI_Gather +#define NG_MPI_Gatherv MPI_Gatherv +#define NG_MPI_Get_count MPI_Get_count +#define NG_MPI_Get_processor_name MPI_Get_processor_name +#define NG_MPI_Group_incl MPI_Group_incl +#define NG_MPI_Init MPI_Init +#define NG_MPI_Init_thread MPI_Init_thread +#define NG_MPI_Initialized MPI_Initialized +#define NG_MPI_Iprobe MPI_Iprobe +#define NG_MPI_Irecv MPI_Irecv +#define NG_MPI_Isend MPI_Isend +#define NG_MPI_Probe MPI_Probe +#define NG_MPI_Query_thread MPI_Query_thread +#define NG_MPI_Recv MPI_Recv +#define NG_MPI_Recv_init MPI_Recv_init +#define NG_MPI_Reduce MPI_Reduce +#define NG_MPI_Reduce_local MPI_Reduce_local +#define NG_MPI_Request_free MPI_Request_free +#define NG_MPI_Scatter MPI_Scatter +#define NG_MPI_Send MPI_Send +#define NG_MPI_Send_init MPI_Send_init +#define NG_MPI_Startall MPI_Startall +#define NG_MPI_Type_commit MPI_Type_commit +#define NG_MPI_Type_contiguous MPI_Type_contiguous +#define NG_MPI_Type_create_resized MPI_Type_create_resized +#define NG_MPI_Type_create_struct MPI_Type_create_struct +#define NG_MPI_Type_free MPI_Type_free +#define NG_MPI_Type_get_extent MPI_Type_get_extent +#define NG_MPI_Type_indexed MPI_Type_indexed +#define NG_MPI_Type_size MPI_Type_size +#define NG_MPI_Wait MPI_Wait +#define NG_MPI_Waitall MPI_Waitall +#define NG_MPI_Waitany MPI_Waitany +#define NG_MPI_COMM_NULL MPI_COMM_NULL +#define NG_MPI_COMM_WORLD MPI_COMM_WORLD +#define NG_MPI_CHAR MPI_CHAR +#define NG_MPI_CXX_DOUBLE_COMPLEX MPI_CXX_DOUBLE_COMPLEX +#define NG_MPI_C_BOOL MPI_C_BOOL +#define NG_MPI_DATATYPE_NULL MPI_DATATYPE_NULL +#define NG_MPI_DOUBLE MPI_DOUBLE +#define NG_MPI_FLOAT MPI_FLOAT +#define NG_MPI_INT MPI_INT +#define NG_MPI_SHORT MPI_SHORT +#define NG_MPI_UINT64_T MPI_UINT64_T +#define NG_MPI_LOR MPI_LOR +#define NG_MPI_MAX MPI_MAX +#define NG_MPI_MIN MPI_MIN +#define NG_MPI_SUM MPI_SUM +#define NG_MPI_REQUEST_NULL MPI_REQUEST_NULL +#define NG_MPI_STATUSES_IGNORE MPI_STATUSES_IGNORE +#define NG_MPI_STATUS_IGNORE MPI_STATUS_IGNORE +#define NG_MPI_ANY_SOURCE MPI_ANY_SOURCE +#define NG_MPI_ANY_TAG MPI_ANY_TAG +#define NG_MPI_MAX_PROCESSOR_NAME MPI_MAX_PROCESSOR_NAME +#define NG_MPI_PROC_NULL MPI_PROC_NULL +#define NG_MPI_ROOT MPI_ROOT +#define NG_MPI_SUBVERSION MPI_SUBVERSION +#define NG_MPI_THREAD_MULTIPLE MPI_THREAD_MULTIPLE +#define NG_MPI_THREAD_SINGLE MPI_THREAD_SINGLE +#define NG_MPI_VERSION MPI_VERSION +#define NG_MPI_IN_PLACE MPI_IN_PLACE +#endif // NG_MPI_WRAPPER diff --git a/libsrc/core/ng_mpi_generated_dummy_init.hpp b/libsrc/core/ng_mpi_generated_dummy_init.hpp new file mode 100644 index 00000000..2719e9da --- /dev/null +++ b/libsrc/core/ng_mpi_generated_dummy_init.hpp @@ -0,0 +1,76 @@ +decltype(NG_MPI_Wtime) NG_MPI_Wtime = []()->double { throw no_mpi(); }; +decltype(NG_MPI_Allgather) NG_MPI_Allgather = [](void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Allreduce) NG_MPI_Allreduce = [](void*, void*, int, NG_MPI_Datatype, NG_MPI_Op, NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Alltoall) NG_MPI_Alltoall = [](void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Barrier) NG_MPI_Barrier = [](NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Bcast) NG_MPI_Bcast = [](void*, int, NG_MPI_Datatype, int, NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Ibcast) NG_MPI_Ibcast = [](void*, int, NG_MPI_Datatype, int, NG_MPI_Comm, NG_MPI_Request*)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_c2f) NG_MPI_Comm_c2f = [](NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_create) NG_MPI_Comm_create = [](NG_MPI_Comm, NG_MPI_Group, NG_MPI_Comm*)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_create_group) NG_MPI_Comm_create_group = [](NG_MPI_Comm, NG_MPI_Group, int, NG_MPI_Comm*)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_free) NG_MPI_Comm_free = [](NG_MPI_Comm*)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_group) NG_MPI_Comm_group = [](NG_MPI_Comm, NG_MPI_Group*)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_rank) NG_MPI_Comm_rank = [](NG_MPI_Comm, int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Comm_size) NG_MPI_Comm_size = [](NG_MPI_Comm, int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Finalize) NG_MPI_Finalize = []()->int { throw no_mpi(); }; +decltype(NG_MPI_Gather) NG_MPI_Gather = [](void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, int, NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Gatherv) NG_MPI_Gatherv = [](void*, int, NG_MPI_Datatype, void*, int*, int*, NG_MPI_Datatype, int, NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Get_count) NG_MPI_Get_count = [](NG_MPI_Status*, NG_MPI_Datatype, int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Get_processor_name) NG_MPI_Get_processor_name = [](char*, int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Group_incl) NG_MPI_Group_incl = [](NG_MPI_Group, int, int*, NG_MPI_Group*)->int { throw no_mpi(); }; +decltype(NG_MPI_Init) NG_MPI_Init = [](int*, char***)->int { throw no_mpi(); }; +decltype(NG_MPI_Init_thread) NG_MPI_Init_thread = [](int*, char***, int, int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Initialized) NG_MPI_Initialized = [](int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Iprobe) NG_MPI_Iprobe = [](int, int, NG_MPI_Comm, int*, NG_MPI_Status*)->int { throw no_mpi(); }; +decltype(NG_MPI_Irecv) NG_MPI_Irecv = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*)->int { throw no_mpi(); }; +decltype(NG_MPI_Isend) NG_MPI_Isend = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*)->int { throw no_mpi(); }; +decltype(NG_MPI_Probe) NG_MPI_Probe = [](int, int, NG_MPI_Comm, NG_MPI_Status*)->int { throw no_mpi(); }; +decltype(NG_MPI_Query_thread) NG_MPI_Query_thread = [](int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Recv) NG_MPI_Recv = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Status*)->int { throw no_mpi(); }; +decltype(NG_MPI_Recv_init) NG_MPI_Recv_init = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*)->int { throw no_mpi(); }; +decltype(NG_MPI_Reduce) NG_MPI_Reduce = [](void*, void*, int, NG_MPI_Datatype, NG_MPI_Op, int, NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Reduce_local) NG_MPI_Reduce_local = [](void*, void*, int, NG_MPI_Datatype, NG_MPI_Op)->int { throw no_mpi(); }; +decltype(NG_MPI_Request_free) NG_MPI_Request_free = [](NG_MPI_Request*)->int { throw no_mpi(); }; +decltype(NG_MPI_Scatter) NG_MPI_Scatter = [](void*, int, NG_MPI_Datatype, void*, int, NG_MPI_Datatype, int, NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Send) NG_MPI_Send = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm)->int { throw no_mpi(); }; +decltype(NG_MPI_Send_init) NG_MPI_Send_init = [](void*, int, NG_MPI_Datatype, int, int, NG_MPI_Comm, NG_MPI_Request*)->int { throw no_mpi(); }; +decltype(NG_MPI_Startall) NG_MPI_Startall = [](int, NG_MPI_Request*)->int { throw no_mpi(); }; +decltype(NG_MPI_Type_commit) NG_MPI_Type_commit = [](NG_MPI_Datatype*)->int { throw no_mpi(); }; +decltype(NG_MPI_Type_contiguous) NG_MPI_Type_contiguous = [](int, NG_MPI_Datatype, NG_MPI_Datatype*)->int { throw no_mpi(); }; +decltype(NG_MPI_Type_create_resized) NG_MPI_Type_create_resized = [](NG_MPI_Datatype, NG_MPI_Aint, NG_MPI_Aint, NG_MPI_Datatype*)->int { throw no_mpi(); }; +decltype(NG_MPI_Type_create_struct) NG_MPI_Type_create_struct = [](int, int*, NG_MPI_Aint*, NG_MPI_Datatype*, NG_MPI_Datatype*)->int { throw no_mpi(); }; +decltype(NG_MPI_Type_free) NG_MPI_Type_free = [](NG_MPI_Datatype*)->int { throw no_mpi(); }; +decltype(NG_MPI_Type_get_extent) NG_MPI_Type_get_extent = [](NG_MPI_Datatype, NG_MPI_Aint*, NG_MPI_Aint*)->int { throw no_mpi(); }; +decltype(NG_MPI_Type_indexed) NG_MPI_Type_indexed = [](int, int*, int*, NG_MPI_Datatype, NG_MPI_Datatype*)->int { throw no_mpi(); }; +decltype(NG_MPI_Type_size) NG_MPI_Type_size = [](NG_MPI_Datatype, int*)->int { throw no_mpi(); }; +decltype(NG_MPI_Wait) NG_MPI_Wait = [](NG_MPI_Request*, NG_MPI_Status*)->int { throw no_mpi(); }; +decltype(NG_MPI_Waitall) NG_MPI_Waitall = [](int, NG_MPI_Request*, NG_MPI_Status*)->int { throw no_mpi(); }; +decltype(NG_MPI_Waitany) NG_MPI_Waitany = [](int, NG_MPI_Request*, int*, NG_MPI_Status*)->int { throw no_mpi(); }; +NG_MPI_Comm NG_MPI_COMM_NULL = 0; +NG_MPI_Comm NG_MPI_COMM_WORLD = 0; +NG_MPI_Datatype NG_MPI_CHAR = 0; +NG_MPI_Datatype NG_MPI_CXX_DOUBLE_COMPLEX = 0; +NG_MPI_Datatype NG_MPI_C_BOOL = 0; +NG_MPI_Datatype NG_MPI_DATATYPE_NULL = 0; +NG_MPI_Datatype NG_MPI_DOUBLE = 0; +NG_MPI_Datatype NG_MPI_FLOAT = 0; +NG_MPI_Datatype NG_MPI_INT = 0; +NG_MPI_Datatype NG_MPI_SHORT = 0; +NG_MPI_Datatype NG_MPI_UINT64_T = 0; +NG_MPI_Op NG_MPI_LOR = 0; +NG_MPI_Op NG_MPI_MAX = 0; +NG_MPI_Op NG_MPI_MIN = 0; +NG_MPI_Op NG_MPI_SUM = 0; +NG_MPI_Request NG_MPI_REQUEST_NULL = 0; +NG_MPI_Status* NG_MPI_STATUSES_IGNORE = 0; +NG_MPI_Status* NG_MPI_STATUS_IGNORE = 0; +int NG_MPI_ANY_SOURCE = 0; +int NG_MPI_ANY_TAG = 0; +int NG_MPI_MAX_PROCESSOR_NAME = 0; +int NG_MPI_PROC_NULL = 0; +int NG_MPI_ROOT = 0; +int NG_MPI_SUBVERSION = 0; +int NG_MPI_THREAD_MULTIPLE = 0; +int NG_MPI_THREAD_SINGLE = 0; +int NG_MPI_VERSION = 0; +void* NG_MPI_IN_PLACE = 0; diff --git a/libsrc/core/ng_mpi_generated_init.hpp b/libsrc/core/ng_mpi_generated_init.hpp new file mode 100644 index 00000000..3340124e --- /dev/null +++ b/libsrc/core/ng_mpi_generated_init.hpp @@ -0,0 +1,76 @@ +NG_MPI_Wtime = []()->double { return MPI_Wtime(); }; +NG_MPI_Allgather = [](void* arg0, int arg1, NG_MPI_Datatype arg2, void* arg3, int arg4, NG_MPI_Datatype arg5, NG_MPI_Comm arg6)->int { return MPI_Allgather( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; +NG_MPI_Allreduce = [](void* arg0, void* arg1, int arg2, NG_MPI_Datatype arg3, NG_MPI_Op arg4, NG_MPI_Comm arg5)->int { return MPI_Allreduce( arg0, arg1, arg2, ng2mpi(arg3), ng2mpi(arg4), ng2mpi(arg5)); }; +NG_MPI_Alltoall = [](void* arg0, int arg1, NG_MPI_Datatype arg2, void* arg3, int arg4, NG_MPI_Datatype arg5, NG_MPI_Comm arg6)->int { return MPI_Alltoall( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; +NG_MPI_Barrier = [](NG_MPI_Comm arg0)->int { return MPI_Barrier( ng2mpi(arg0)); }; +NG_MPI_Bcast = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, NG_MPI_Comm arg4)->int { return MPI_Bcast( arg0, arg1, ng2mpi(arg2), arg3, ng2mpi(arg4)); }; +NG_MPI_Ibcast = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, NG_MPI_Comm arg4, NG_MPI_Request* arg5)->int { return MPI_Ibcast( arg0, arg1, ng2mpi(arg2), arg3, ng2mpi(arg4), ng2mpi(arg5)); }; +NG_MPI_Comm_c2f = [](NG_MPI_Comm arg0)->int { return MPI_Comm_c2f( ng2mpi(arg0)); }; +NG_MPI_Comm_create = [](NG_MPI_Comm arg0, NG_MPI_Group arg1, NG_MPI_Comm* arg2)->int { return MPI_Comm_create( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2)); }; +NG_MPI_Comm_create_group = [](NG_MPI_Comm arg0, NG_MPI_Group arg1, int arg2, NG_MPI_Comm* arg3)->int { return MPI_Comm_create_group( ng2mpi(arg0), ng2mpi(arg1), arg2, ng2mpi(arg3)); }; +NG_MPI_Comm_free = [](NG_MPI_Comm* arg0)->int { return MPI_Comm_free( ng2mpi(arg0)); }; +NG_MPI_Comm_group = [](NG_MPI_Comm arg0, NG_MPI_Group* arg1)->int { return MPI_Comm_group( ng2mpi(arg0), ng2mpi(arg1)); }; +NG_MPI_Comm_rank = [](NG_MPI_Comm arg0, int* arg1)->int { return MPI_Comm_rank( ng2mpi(arg0), arg1); }; +NG_MPI_Comm_size = [](NG_MPI_Comm arg0, int* arg1)->int { return MPI_Comm_size( ng2mpi(arg0), arg1); }; +NG_MPI_Finalize = []()->int { return MPI_Finalize(); }; +NG_MPI_Gather = [](void* arg0, int arg1, NG_MPI_Datatype arg2, void* arg3, int arg4, NG_MPI_Datatype arg5, int arg6, NG_MPI_Comm arg7)->int { return MPI_Gather( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), arg6, ng2mpi(arg7)); }; +NG_MPI_Gatherv = [](void* arg0, int arg1, NG_MPI_Datatype arg2, void* arg3, int* arg4, int* arg5, NG_MPI_Datatype arg6, int arg7, NG_MPI_Comm arg8)->int { return MPI_Gatherv( arg0, arg1, ng2mpi(arg2), arg3, arg4, arg5, ng2mpi(arg6), arg7, ng2mpi(arg8)); }; +NG_MPI_Get_count = [](NG_MPI_Status* arg0, NG_MPI_Datatype arg1, int* arg2)->int { return MPI_Get_count( ng2mpi(arg0), ng2mpi(arg1), arg2); }; +NG_MPI_Get_processor_name = [](char* arg0, int* arg1)->int { return MPI_Get_processor_name( arg0, arg1); }; +NG_MPI_Group_incl = [](NG_MPI_Group arg0, int arg1, int* arg2, NG_MPI_Group* arg3)->int { return MPI_Group_incl( ng2mpi(arg0), arg1, arg2, ng2mpi(arg3)); }; +NG_MPI_Init = [](int* arg0, char*** arg1)->int { return MPI_Init( arg0, arg1); }; +NG_MPI_Init_thread = [](int* arg0, char*** arg1, int arg2, int* arg3)->int { return MPI_Init_thread( arg0, arg1, arg2, arg3); }; +NG_MPI_Initialized = [](int* arg0)->int { return MPI_Initialized( arg0); }; +NG_MPI_Iprobe = [](int arg0, int arg1, NG_MPI_Comm arg2, int* arg3, NG_MPI_Status* arg4)->int { return MPI_Iprobe( arg0, arg1, ng2mpi(arg2), arg3, ng2mpi(arg4)); }; +NG_MPI_Irecv = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5, NG_MPI_Request* arg6)->int { return MPI_Irecv( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; +NG_MPI_Isend = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5, NG_MPI_Request* arg6)->int { return MPI_Isend( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; +NG_MPI_Probe = [](int arg0, int arg1, NG_MPI_Comm arg2, NG_MPI_Status* arg3)->int { return MPI_Probe( arg0, arg1, ng2mpi(arg2), ng2mpi(arg3)); }; +NG_MPI_Query_thread = [](int* arg0)->int { return MPI_Query_thread( arg0); }; +NG_MPI_Recv = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5, NG_MPI_Status* arg6)->int { return MPI_Recv( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; +NG_MPI_Recv_init = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5, NG_MPI_Request* arg6)->int { return MPI_Recv_init( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; +NG_MPI_Reduce = [](void* arg0, void* arg1, int arg2, NG_MPI_Datatype arg3, NG_MPI_Op arg4, int arg5, NG_MPI_Comm arg6)->int { return MPI_Reduce( arg0, arg1, arg2, ng2mpi(arg3), ng2mpi(arg4), arg5, ng2mpi(arg6)); }; +NG_MPI_Reduce_local = [](void* arg0, void* arg1, int arg2, NG_MPI_Datatype arg3, NG_MPI_Op arg4)->int { return MPI_Reduce_local( arg0, arg1, arg2, ng2mpi(arg3), ng2mpi(arg4)); }; +NG_MPI_Request_free = [](NG_MPI_Request* arg0)->int { return MPI_Request_free( ng2mpi(arg0)); }; +NG_MPI_Scatter = [](void* arg0, int arg1, NG_MPI_Datatype arg2, void* arg3, int arg4, NG_MPI_Datatype arg5, int arg6, NG_MPI_Comm arg7)->int { return MPI_Scatter( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), arg6, ng2mpi(arg7)); }; +NG_MPI_Send = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5)->int { return MPI_Send( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5)); }; +NG_MPI_Send_init = [](void* arg0, int arg1, NG_MPI_Datatype arg2, int arg3, int arg4, NG_MPI_Comm arg5, NG_MPI_Request* arg6)->int { return MPI_Send_init( arg0, arg1, ng2mpi(arg2), arg3, arg4, ng2mpi(arg5), ng2mpi(arg6)); }; +NG_MPI_Startall = [](int arg0, NG_MPI_Request* arg1)->int { return MPI_Startall( arg0, ng2mpi(arg1, arg0)); }; +NG_MPI_Type_commit = [](NG_MPI_Datatype* arg0)->int { return MPI_Type_commit( ng2mpi(arg0)); }; +NG_MPI_Type_contiguous = [](int arg0, NG_MPI_Datatype arg1, NG_MPI_Datatype* arg2)->int { return MPI_Type_contiguous( arg0, ng2mpi(arg1), ng2mpi(arg2)); }; +NG_MPI_Type_create_resized = [](NG_MPI_Datatype arg0, NG_MPI_Aint arg1, NG_MPI_Aint arg2, NG_MPI_Datatype* arg3)->int { return MPI_Type_create_resized( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2), ng2mpi(arg3)); }; +NG_MPI_Type_create_struct = [](int arg0, int* arg1, NG_MPI_Aint* arg2, NG_MPI_Datatype* arg3, NG_MPI_Datatype* arg4)->int { return MPI_Type_create_struct( arg0, arg1, ng2mpi(arg2, arg0), ng2mpi(arg3, arg0), ng2mpi(arg4)); }; +NG_MPI_Type_free = [](NG_MPI_Datatype* arg0)->int { return MPI_Type_free( ng2mpi(arg0)); }; +NG_MPI_Type_get_extent = [](NG_MPI_Datatype arg0, NG_MPI_Aint* arg1, NG_MPI_Aint* arg2)->int { return MPI_Type_get_extent( ng2mpi(arg0), ng2mpi(arg1), ng2mpi(arg2)); }; +NG_MPI_Type_indexed = [](int arg0, int* arg1, int* arg2, NG_MPI_Datatype arg3, NG_MPI_Datatype* arg4)->int { return MPI_Type_indexed( arg0, arg1, arg2, ng2mpi(arg3), ng2mpi(arg4)); }; +NG_MPI_Type_size = [](NG_MPI_Datatype arg0, int* arg1)->int { return MPI_Type_size( ng2mpi(arg0), arg1); }; +NG_MPI_Wait = [](NG_MPI_Request* arg0, NG_MPI_Status* arg1)->int { return MPI_Wait( ng2mpi(arg0), ng2mpi(arg1)); }; +NG_MPI_Waitall = [](int arg0, NG_MPI_Request* arg1, NG_MPI_Status* arg2)->int { return MPI_Waitall( arg0, ng2mpi(arg1, arg0), ng2mpi(arg2)); }; +NG_MPI_Waitany = [](int arg0, NG_MPI_Request* arg1, int* arg2, NG_MPI_Status* arg3)->int { return MPI_Waitany( arg0, ng2mpi(arg1, arg0), arg2, ng2mpi(arg3)); }; +NG_MPI_COMM_NULL = mpi2ng(MPI_COMM_NULL); +NG_MPI_COMM_WORLD = mpi2ng(MPI_COMM_WORLD); +NG_MPI_CHAR = mpi2ng(MPI_CHAR); +NG_MPI_CXX_DOUBLE_COMPLEX = mpi2ng(MPI_CXX_DOUBLE_COMPLEX); +NG_MPI_C_BOOL = mpi2ng(MPI_C_BOOL); +NG_MPI_DATATYPE_NULL = mpi2ng(MPI_DATATYPE_NULL); +NG_MPI_DOUBLE = mpi2ng(MPI_DOUBLE); +NG_MPI_FLOAT = mpi2ng(MPI_FLOAT); +NG_MPI_INT = mpi2ng(MPI_INT); +NG_MPI_SHORT = mpi2ng(MPI_SHORT); +NG_MPI_UINT64_T = mpi2ng(MPI_UINT64_T); +NG_MPI_LOR = mpi2ng(MPI_LOR); +NG_MPI_MAX = mpi2ng(MPI_MAX); +NG_MPI_MIN = mpi2ng(MPI_MIN); +NG_MPI_SUM = mpi2ng(MPI_SUM); +NG_MPI_REQUEST_NULL = mpi2ng(MPI_REQUEST_NULL); +NG_MPI_STATUSES_IGNORE = mpi2ng(MPI_STATUSES_IGNORE); +NG_MPI_STATUS_IGNORE = mpi2ng(MPI_STATUS_IGNORE); +NG_MPI_ANY_SOURCE = mpi2ng(MPI_ANY_SOURCE); +NG_MPI_ANY_TAG = mpi2ng(MPI_ANY_TAG); +NG_MPI_MAX_PROCESSOR_NAME = mpi2ng(MPI_MAX_PROCESSOR_NAME); +NG_MPI_PROC_NULL = mpi2ng(MPI_PROC_NULL); +NG_MPI_ROOT = mpi2ng(MPI_ROOT); +NG_MPI_SUBVERSION = mpi2ng(MPI_SUBVERSION); +NG_MPI_THREAD_MULTIPLE = mpi2ng(MPI_THREAD_MULTIPLE); +NG_MPI_THREAD_SINGLE = mpi2ng(MPI_THREAD_SINGLE); +NG_MPI_VERSION = mpi2ng(MPI_VERSION); +NG_MPI_IN_PLACE = mpi2ng(MPI_IN_PLACE); diff --git a/libsrc/core/ng_mpi_native.hpp b/libsrc/core/ng_mpi_native.hpp new file mode 100644 index 00000000..6c8f40ce --- /dev/null +++ b/libsrc/core/ng_mpi_native.hpp @@ -0,0 +1,21 @@ +#ifndef NG_MPI_NATIVE_HPP +#define NG_MPI_NATIVE_HPP + +#include + +#include "mpi_wrapper.hpp" +#include "ng_mpi.hpp" + +namespace ngcore { + +MPI_Comm NG_MPI_Native(NG_MPI_Comm comm) { + return reinterpret_cast(comm.value); +} + +MPI_Comm NG_MPI_Native(NgMPI_Comm comm) { + return reinterpret_cast(static_cast(comm).value); +} + +} // namespace ngcore + +#endif // NG_MPI_NATIVE_HPP diff --git a/libsrc/core/ng_mpi_wrapper.cpp b/libsrc/core/ng_mpi_wrapper.cpp new file mode 100644 index 00000000..4ddf0816 --- /dev/null +++ b/libsrc/core/ng_mpi_wrapper.cpp @@ -0,0 +1,206 @@ +#ifdef PARALLEL + +#include +#include +#include + +#include "ng_mpi.hpp" +#include "ngstream.hpp" +#ifdef NG_PYTHON +#include "python_ngcore.hpp" +#endif // NG_PYTHON +#include "utils.hpp" + +using std::cerr; +using std::cout; +using std::endl; + +#ifndef NG_MPI_WRAPPER +#ifdef NG_PYTHON +#define MPI4PY_LIMITED_API 1 +#define MPI4PY_LIMITED_API_SKIP_MESSAGE 1 +#define MPI4PY_LIMITED_API_SKIP_SESSION 1 +#include "mpi4py_pycapi.h" // mpi4py < 4.0.0 +#endif // NG_PYTHON +#endif // NG_MPI_WRAPPER + +namespace ngcore { + +#ifdef NG_MPI_WRAPPER +static std::unique_ptr mpi_lib, ng_mpi_lib; +static bool need_mpi_finalize = false; + +struct MPIFinalizer { + ~MPIFinalizer() { + if (need_mpi_finalize) { + cout << IM(5) << "Calling MPI_Finalize" << endl; + NG_MPI_Finalize(); + } + } +} mpi_finalizer; + +bool MPI_Loaded() { return ng_mpi_lib != nullptr; } + +void InitMPI(std::optional mpi_lib_path) { + if (ng_mpi_lib) return; + + cout << IM(3) << "InitMPI" << endl; + + std::string vendor = ""; + std::string mpi4py_lib_file = ""; + + if (mpi_lib_path) { + // Dynamic load of given shared MPI library + // Then call MPI_Init, read the library version and set the vender name + try { + typedef int (*init_handle)(int *, char ***); + typedef int (*mpi_initialized_handle)(int *); + mpi_lib = + std::make_unique(*mpi_lib_path, std::nullopt, true); + auto mpi_init = mpi_lib->GetSymbol("MPI_Init"); + auto mpi_initialized = + mpi_lib->GetSymbol("MPI_Initialized"); + + int flag = 0; + mpi_initialized(&flag); + if (!flag) { + typedef const char *pchar; + int argc = 1; + pchar args[] = {"netgen", nullptr}; + pchar *argv = &args[0]; + cout << IM(5) << "Calling MPI_Init" << endl; + mpi_init(&argc, (char ***)argv); + need_mpi_finalize = true; + } + + char c_version_string[65536]; + c_version_string[0] = '\0'; + int result_len = 0; + typedef void (*get_version_handle)(char *, int *); + auto get_version = + mpi_lib->GetSymbol("MPI_Get_library_version"); + get_version(c_version_string, &result_len); + std::string version = c_version_string; + + if (version.substr(0, 8) == "Open MPI") + vendor = "Open MPI"; + else if (version.substr(0, 5) == "MPICH") + vendor = "MPICH"; + else if (version.substr(0, 13) == "Microsoft MPI") + vendor = "Microsoft MPI"; + else if (version.substr(0, 12) == "Intel(R) MPI") + vendor = "Intel MPI"; + else + throw std::runtime_error( + std::string("Unknown MPI version: " + version)); + } catch (std::runtime_error &e) { + cerr << "Could not load MPI: " << e.what() << endl; + throw e; + } + } else { +#ifdef NG_PYTHON + // Use mpi4py to init MPI library and get the vendor name + auto mpi4py = py::module::import("mpi4py.MPI"); + vendor = mpi4py.attr("get_vendor")()[py::int_(0)].cast(); + +#ifndef WIN32 + // Load mpi4py library (it exports all MPI symbols) to have all MPI symbols + // available before the ng_mpi wrapper is loaded This is not necessary on + // windows as the matching mpi dll is linked to the ng_mpi wrapper directly + mpi4py_lib_file = mpi4py.attr("__file__").cast(); + mpi_lib = + std::make_unique(mpi4py_lib_file, std::nullopt, true); +#endif // WIN32 +#endif // NG_PYTHON + } + + std::string ng_lib_name = ""; + if (vendor == "Open MPI") + ng_lib_name = "ng_openmpi"; + else if (vendor == "MPICH") + ng_lib_name = "ng_mpich"; + else if (vendor == "Microsoft MPI") + ng_lib_name = "ng_microsoft_mpi"; + else if (vendor == "Intel MPI") + ng_lib_name = "ng_intel_mpi"; + else + throw std::runtime_error("Unknown MPI vendor: " + vendor); + + ng_lib_name += NETGEN_SHARED_LIBRARY_SUFFIX; + + // Load the ng_mpi wrapper and call ng_init_mpi to set all function pointers + typedef void (*ng_init_handle)(); + ng_mpi_lib = std::make_unique(ng_lib_name); + ng_mpi_lib->GetSymbol("ng_init_mpi")(); + std::cout << IM(3) << "MPI wrapper loaded, vendor: " << vendor << endl; +} + +static std::runtime_error no_mpi() { + return std::runtime_error("MPI not enabled"); +} + +#ifdef NG_PYTHON +decltype(NG_MPI_CommFromMPI4Py) NG_MPI_CommFromMPI4Py = + [](py::handle py_obj, NG_MPI_Comm &ng_comm) -> bool { + // If this gets called, it means that we want to convert an mpi4py + // communicator to a Netgen MPI communicator, but the Netgen MPI wrapper + // runtime was not yet initialized. + + // store the current address of this function + auto old_converter_address = NG_MPI_CommFromMPI4Py; + + // initialize the MPI wrapper runtime, this sets all the function pointers + InitMPI(); + + // if the initialization was successful, the function pointer should have + // changed + // -> call the actual conversion function + if (NG_MPI_CommFromMPI4Py != old_converter_address) + return NG_MPI_CommFromMPI4Py(py_obj, ng_comm); + + // otherwise, something strange happened + throw no_mpi(); +}; +decltype(NG_MPI_CommToMPI4Py) NG_MPI_CommToMPI4Py = + [](NG_MPI_Comm) -> py::handle { throw no_mpi(); }; +#endif // NG_PYTHON + +#include "ng_mpi_generated_dummy_init.hpp" +#else // NG_MPI_WRAPPER + +static bool imported_mpi4py = false; +#ifdef NG_PYTHON +decltype(NG_MPI_CommFromMPI4Py) NG_MPI_CommFromMPI4Py = + [](py::handle src, NG_MPI_Comm &dst) -> bool { + if (!imported_mpi4py) { + import_mpi4py__MPI(); + imported_mpi4py = true; + } + PyObject *py_src = src.ptr(); + auto type = Py_TYPE(py_src); + if (PyObject_TypeCheck(py_src, &PyMPIComm_Type)) { + dst = *PyMPIComm_Get(py_src); + return !PyErr_Occurred(); + } + return false; +}; + +decltype(NG_MPI_CommToMPI4Py) NG_MPI_CommToMPI4Py = + [](NG_MPI_Comm src) -> py::handle { + if (!imported_mpi4py) { + import_mpi4py__MPI(); + imported_mpi4py = true; + } + return py::handle(PyMPIComm_New(src)); +}; + +#endif // NG_PYTHON + +bool MPI_Loaded() { return true; } +void InitMPI(std::optional) {} + +#endif // NG_MPI_WRAPPER + +} // namespace ngcore + +#endif // PARALLEL diff --git a/libsrc/core/ngcore.hpp b/libsrc/core/ngcore.hpp index 84c7f0c1..55b26d8e 100644 --- a/libsrc/core/ngcore.hpp +++ b/libsrc/core/ngcore.hpp @@ -10,15 +10,18 @@ #include "hashtable.hpp" #include "localheap.hpp" #include "logging.hpp" -#include "mpi_wrapper.hpp" +// #include "mpi_wrapper.hpp" #include "profiler.hpp" #include "signal.hpp" #include "simd.hpp" +#include "autodiff.hpp" +#include "autodiffdiff.hpp" #include "symboltable.hpp" #include "taskmanager.hpp" #include "version.hpp" #include "xbool.hpp" #include "ngstream.hpp" #include "utils.hpp" +#include "ranges.hpp" #endif // NETGEN_CORE_NGCORE_HPP diff --git a/libsrc/core/ngcore_api.hpp b/libsrc/core/ngcore_api.hpp index e66e9b87..35f222d4 100644 --- a/libsrc/core/ngcore_api.hpp +++ b/libsrc/core/ngcore_api.hpp @@ -1,6 +1,8 @@ #ifndef NETGEN_CORE_NGCORE_API_HPP #define NETGEN_CORE_NGCORE_API_HPP +#include "netgen_config.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. diff --git a/libsrc/core/paje_trace.cpp b/libsrc/core/paje_trace.cpp index 818a92c8..244c1cf8 100644 --- a/libsrc/core/paje_trace.cpp +++ b/libsrc/core/paje_trace.cpp @@ -7,12 +7,14 @@ #include "archive.hpp" // for Demangle #include "paje_trace.hpp" +#include "ng_mpi.hpp" #include "profiler.hpp" #include "mpi_wrapper.hpp" extern const char *header; constexpr int MPI_PAJE_WRITER = 1; +constexpr int ASSUMED_MPI_MAX_PROCESSOR_NAME = 256; namespace ngcore { @@ -24,7 +26,7 @@ namespace ngcore if(id thread_aliases; std::vector container_nodes; -#ifdef PARALLEL - // Hostnames - NgMPI_Comm comm(MPI_COMM_WORLD); - auto rank = comm.Rank(); - auto nranks = comm.Size(); - if(nranks>1) + NgMPI_Comm comm; + #ifdef PARALLEL + if(MPI_Loaded()) + comm = NgMPI_Comm(NG_MPI_COMM_WORLD); + if(comm.Size()>1) { - nthreads = nranks; + auto comm = NgMPI_Comm(NG_MPI_COMM_WORLD); + nthreads = comm.Size(); thread_aliases.reserve(nthreads); - std::array ahostname; + std::array ahostname; int len; - MPI_Get_processor_name(ahostname.data(), &len); + NG_MPI_Get_processor_name(ahostname.data(), &len); std::string hostname = ahostname.data(); std::map host_map; std::string name; - for(auto i : IntRange(0, nranks)) + for(auto i : IntRange(0, comm.Size())) { if(i!=MPI_PAJE_WRITER) comm.Recv(name, i, 0); @@ -519,7 +537,7 @@ namespace ngcore } } else -#endif // PARALLEL + #endif { container_nodes.reserve(num_nodes); for(int i=0; i1) + if(comm.Size()>1) { - for(auto src : IntRange(0, nranks)) + for(auto src : IntRange(0, comm.Size())) { if(src==MPI_PAJE_WRITER) continue; @@ -608,7 +625,7 @@ namespace ngcore int id; std::string name; - for(auto i : IntRange(n_timers)) + for([[maybe_unused]]auto i : IntRange(n_timers)) { comm.Recv (id, src, 0); comm.Recv (name, src, 0); @@ -617,7 +634,6 @@ namespace ngcore } } } -#endif // PARALLEL for(auto id : timer_ids) timer_aliases[id] = paje.DefineEntityValue( state_type_timer, timer_names[id], -1 ); @@ -742,7 +758,7 @@ namespace ngcore } #ifdef PARALLEL - if(nranks>1) + if(comm.Size()>1) { for(auto & event : timer_events) { @@ -758,7 +774,7 @@ namespace ngcore Array is_start; Array thread_id; - for(auto src : IntRange(0, nranks)) + for(auto src : IntRange(0, comm.Size())) { if(src==MPI_PAJE_WRITER) continue; @@ -843,10 +859,6 @@ namespace ngcore } } } - WriteTimingChart(); -#ifdef NETGEN_TRACE_MEMORY - WriteMemoryChart(""); -#endif // NETGEN_TRACE_MEMORY paje.WriteEvents(); } @@ -854,15 +866,15 @@ namespace ngcore { #ifdef PARALLEL // Hostname - NgMPI_Comm comm(MPI_COMM_WORLD); - auto rank = comm.Rank(); - auto nranks = comm.Size(); + NgMPI_Comm comm(NG_MPI_COMM_WORLD); + // auto rank = comm.Rank(); + // auto nranks = comm.Size(); std::string hostname; { - std::array ahostname; + std::array ahostname; int len; - MPI_Get_processor_name(ahostname.data(), &len); + NG_MPI_Get_processor_name(ahostname.data(), &len); hostname = ahostname.data(); } @@ -955,10 +967,18 @@ namespace ngcore f.precision(4); f << R"CODE_( - + - + )CODE_"; if(!time_or_memory) f << "Maximum Memory Consumption\n"; diff --git a/libsrc/core/paje_trace.hpp b/libsrc/core/paje_trace.hpp index 7adc6c58..7154feb2 100644 --- a/libsrc/core/paje_trace.hpp +++ b/libsrc/core/paje_trace.hpp @@ -25,6 +25,7 @@ namespace ngcore NGCORE_API static bool trace_thread_counter; NGCORE_API static bool trace_threads; NGCORE_API static bool mem_tracing_enabled; + NGCORE_API static bool write_paje_file; bool tracing_enabled; TTimePoint start_time; @@ -32,6 +33,8 @@ namespace ngcore size_t n_memory_events_at_start; public: + NGCORE_API void Write(); + NGCORE_API void WritePajeFile( const std::string & filename ); NGCORE_API void WriteTimingChart(); #ifdef NETGEN_TRACE_MEMORY NGCORE_API void WriteMemoryChart( std::string fname ); @@ -61,6 +64,11 @@ namespace ngcore max_tracefile_size = max_size; } + static void SetWritePajeFile( bool write ) + { + write_paje_file = write; + } + std::string tracefile_name; struct Job @@ -262,8 +270,6 @@ namespace ngcore links[thread_id].push_back( ThreadLink{thread_id, key, GetTimeCounter(), false} ); } - void Write( const std::string & filename ); - void SendData(); // MPI parallel data reduction }; diff --git a/libsrc/core/profiler.cpp b/libsrc/core/profiler.cpp index cf49654b..6f257cfb 100644 --- a/libsrc/core/profiler.cpp +++ b/libsrc/core/profiler.cpp @@ -116,6 +116,7 @@ namespace ngcore #ifdef NETGEN_TRACE_MEMORY std::vector MemoryTracer::names{"all"}; std::vector MemoryTracer::parents{-1}; + std::atomic MemoryTracer::total_memory{0}; #endif // NETGEN_TRACE_MEMORY } // namespace ngcore diff --git a/libsrc/core/python_ngcore.cpp b/libsrc/core/python_ngcore.cpp index 651db906..c5b90e24 100644 --- a/libsrc/core/python_ngcore.cpp +++ b/libsrc/core/python_ngcore.cpp @@ -14,13 +14,11 @@ namespace ngcore { if (py::isinstance(value)) { - py::dict vdd(value); - // call recursively to set dictionary - for (auto item : vdd) { - string name = item.first.cast(); - py::object val = py::reinterpret_borrow(item.second); - SetFlag(flags, name, val); - } + Flags nested_flags; + for(auto item : value.cast()) + SetFlag(nested_flags, item.first.cast(), + item.second.cast()); + flags.SetFlag(s, nested_flags); return; } @@ -103,7 +101,9 @@ namespace ngcore } } - auto flags = py::cast(flags_dict); + Flags flags; + for(auto item : flags_dict) + SetFlag(flags, item.first.cast(), item.second.cast()); for (auto item : kwargs) { diff --git a/libsrc/core/python_ngcore.hpp b/libsrc/core/python_ngcore.hpp index 79c91885..2ce84481 100644 --- a/libsrc/core/python_ngcore.hpp +++ b/libsrc/core/python_ngcore.hpp @@ -13,11 +13,17 @@ #include "archive.hpp" #include "flags.hpp" #include "ngcore_api.hpp" -#include "profiler.hpp" +#include "ng_mpi.hpp" + namespace py = pybind11; namespace ngcore { +#ifdef PARALLEL + NGCORE_API extern bool (*NG_MPI_CommFromMPI4Py)(py::handle, NG_MPI_Comm &); + NGCORE_API extern py::handle (*NG_MPI_CommToMPI4Py)(NG_MPI_Comm); +#endif // PARALLEL + namespace detail { template @@ -31,6 +37,16 @@ namespace ngcore static constexpr bool value = decltype(check((T*) nullptr))::value; }; } // namespace detail + +#ifdef PARALLEL + struct mpi4py_comm { + mpi4py_comm() = default; + mpi4py_comm(NG_MPI_Comm value) : value(value) {} + operator NG_MPI_Comm () { return value; } + + NG_MPI_Comm value; + }; +#endif // PARALLEL } // namespace ngcore @@ -39,6 +55,27 @@ namespace ngcore namespace pybind11 { namespace detail { +#ifdef PARALLEL +template <> struct type_caster { + public: + PYBIND11_TYPE_CASTER(ngcore::mpi4py_comm, _("mpi4py_comm")); + + // Python -> C++ + bool load(handle src, bool) { + return ngcore::NG_MPI_CommFromMPI4Py(src, value.value); + } + + // C++ -> Python + static handle cast(ngcore::mpi4py_comm src, + return_value_policy /* policy */, + handle /* parent */) + { + // Create an mpi4py handle + return ngcore::NG_MPI_CommToMPI4Py(src.value); + } +}; +#endif // PARALLEL + template struct ngcore_list_caster { using value_conv = make_caster; @@ -156,30 +193,6 @@ namespace ngcore { return std::string("sp_")+GetPyName(); } }; - // *************** Archiving functionality ************** - - template - Archive& Archive :: Shallow(T& val) - { - static_assert(detail::is_any_pointer, "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(obj); - } - } - else -#endif // NETGEN_PYTHON - *this & val; - return *this; - } - template class NGCORE_API_EXPORT PyArchive : public ARCHIVE { @@ -190,7 +203,6 @@ namespace ngcore protected: using ARCHIVE::stream; using ARCHIVE::version_map; - using ARCHIVE::logger; public: PyArchive(const pybind11::object& alst = pybind11::none()) : ARCHIVE(std::make_shared()), @@ -202,7 +214,6 @@ namespace ngcore stream = std::make_shared (pybind11::cast(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 + @@ -219,7 +230,6 @@ namespace ngcore { if(Output()) { - logger->debug("Need version {} of library {}.", version, library); version_needed[library] = version_needed[library] > version ? version_needed[library] : version; } } @@ -243,7 +253,6 @@ namespace ngcore FlushBuffer(); lst.append(pybind11::bytes(std::static_pointer_cast(stream)->str())); stream = std::make_shared(); - logger->debug("Writeout version needed = {}", version_needed); *this & version_needed; FlushBuffer(); lst.append(pybind11::bytes(std::static_pointer_cast(stream)->str())); @@ -286,6 +295,16 @@ namespace ngcore return arr; } + template + // py::object makePyTuple (FlatArray ar) + py::object makePyTuple (const BaseArrayObject & ar) + { + py::tuple res(ar.Size()); + for (auto i : Range(ar)) + res[i] = py::cast(ar[i]); + return res; + } + template ::index_type> void ExportArray (py::module &m) { @@ -300,8 +319,9 @@ namespace ngcore .def ("__getitem__", [](TFlat & self, TIND i) -> T& { - static constexpr int base = IndexBASE(); - if (i < base || i >= self.Size()+base) + // static constexpr int base = IndexBASE(); + auto reli = i - IndexBASE(); + if (reli < 0 || reli >= self.Size()) throw py::index_error(); return self[i]; }, @@ -309,8 +329,9 @@ namespace ngcore .def ("__setitem__", [](TFlat & self, TIND i, T val) -> T& { - static constexpr int base = IndexBASE(); - if (i < base || i >= self.Size()+base) + // static constexpr int base = IndexBASE(); + auto reli = i - IndexBASE(); + if (reli < 0 || reli >= self.Size()) throw py::index_error(); self[i] = val; return self[i]; diff --git a/libsrc/core/python_ngcore_export.cpp b/libsrc/core/python_ngcore_export.cpp index facbcda7..cc9f5a70 100644 --- a/libsrc/core/python_ngcore_export.cpp +++ b/libsrc/core/python_ngcore_export.cpp @@ -1,11 +1,18 @@ #include "python_ngcore.hpp" #include "bitarray.hpp" #include "taskmanager.hpp" +#include "mpi_wrapper.hpp" using namespace ngcore; using namespace std; using namespace pybind11::literals; +namespace pybind11 { namespace detail { +}} // namespace pybind11::detail + + + + PYBIND11_MODULE(pyngcore, m) // NOLINT { try @@ -24,8 +31,18 @@ PYBIND11_MODULE(pyngcore, m) // NOLINT ExportArray(m); ExportArray(m); + // Compiler dependent implementation of size_t + if constexpr(!is_same_v) + ExportArray(m); + ExportTable(m); - + + #ifdef PARALLEL + py::class_ (m, "_NG_MPI_Comm") + ; + m.def("InitMPI", &InitMPI, py::arg("mpi_library_path")=nullopt); + #endif // PARALLEL + py::class_> (m, "BitArray") .def(py::init([] (size_t n) { return make_shared(n); }),py::arg("n")) .def(py::init([] (const BitArray& a) { return make_shared(a); } ), py::arg("ba")) @@ -124,20 +141,34 @@ PYBIND11_MODULE(pyngcore, m) // NOLINT .def(py::self | py::self) .def(py::self & py::self) + #ifdef __clang__ + // see https://github.com/pybind/pybind11/issues/1893 + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wself-assign-overloaded" + #endif .def(py::self |= py::self) .def(py::self &= py::self) + #ifdef __clang__ + #pragma GCC diagnostic pop + #endif .def(~py::self) ; py::class_(m, "Flags") .def(py::init<>()) .def("__str__", &ToString) - .def(py::init([](py::object & obj) { + .def(py::init([](py::dict kwargs) { Flags flags; - py::dict d(obj); - SetFlag (flags, "", d); + for (auto d : kwargs) + SetFlag(flags, d.first.cast(), d.second.cast()); return flags; - }), py::arg("obj"), "Create Flags by given object") + }), "Create flags from dict") + .def(py::init([](py::kwargs kwargs) { + Flags flags; + for (auto d : kwargs) + SetFlag(flags, d.first.cast(), d.second.cast()); + return flags; + }), "Create flags from kwargs") .def(py::pickle([] (const Flags& self) { std::stringstream str; @@ -165,6 +196,9 @@ PYBIND11_MODULE(pyngcore, m) // NOLINT return self; }, py::arg("akey"), py::arg("value"), "Set flag by given value.") + .def("keys", [](Flags & self) -> py::list { + return CreateDictFromFlags(self).attr("keys")(); + }) .def("__getitem__", [](Flags & self, const string& name) -> py::object { if(self.NumListFlagDefined(name)) @@ -188,6 +222,10 @@ PYBIND11_MODULE(pyngcore, m) // NOLINT { return CreateDictFromFlags(flags); }) + .def("items", [](const Flags& flags) + { + return CreateDictFromFlags(flags).attr("items")(); + }) ; py::implicitly_convertible(); @@ -286,5 +324,70 @@ threads : int #endif // NETGEN_TRACE_MEMORY ; + m.def("GetTotalMemory", MemoryTracer::GetTotalMemory); + py::class_> (m, "Timer") + .def(py::init()) + .def("Start", static_cast::*)()const>(&Timer<>::Start), "start timer") + .def("Stop", static_cast::*)()const>(&Timer<>::Stop), "stop timer") + .def_property_readonly("time", &Timer<>::GetTime, "returns time") + .def("__enter__", static_cast::*)()const>(&Timer<>::Start)) + .def("__exit__", [](Timer<>& t, py::object, py::object, py::object) + { + t.Stop(); + }) + ; + + m.def("Timers", + []() + { + py::list timers; + for (int i = 0; i < NgProfiler::SIZE; i++) + if (!NgProfiler::timers[i].name.empty()) + { + py::dict timer; + timer["name"] = py::str(NgProfiler::timers[i].name); + timer["time"] = py::float_(NgProfiler::GetTime(i)); + timer["counts"] = py::int_(NgProfiler::GetCounts(i)); + timer["flops"] = py::float_(NgProfiler::GetFlops(i)); + timer["Gflop/s"] = py::float_(NgProfiler::GetFlops(i)/NgProfiler::GetTime(i)*1e-9); + timers.append(timer); + } + return timers; + }, "Returns list of timers" + ); + m.def("ResetTimers", &NgProfiler::Reset); + + py::class_ (m, "MPI_Comm") +#ifdef PARALLEL + .def(py::init([] (mpi4py_comm comm) { return NgMPI_Comm(comm); })) + .def("WTime", [](NgMPI_Comm & c) { return NG_MPI_Wtime(); }) + .def_property_readonly ("mpi4py", [](NgMPI_Comm & self) { return NG_MPI_CommToMPI4Py(self); }) +#endif // PARALLEL + .def_property_readonly ("rank", &NgMPI_Comm::Rank) + .def_property_readonly ("size", &NgMPI_Comm::Size) + .def("Barrier", &NgMPI_Comm::Barrier) + .def("Sum", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, NG_MPI_SUM); }) + .def("Min", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, NG_MPI_MIN); }) + .def("Max", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, NG_MPI_MAX); }) + .def("Sum", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, NG_MPI_SUM); }) + .def("Min", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, NG_MPI_MIN); }) + .def("Max", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, NG_MPI_MAX); }) + .def("Sum", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, NG_MPI_SUM); }) + .def("Min", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, NG_MPI_MIN); }) + .def("Max", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, NG_MPI_MAX); }) + .def("SubComm", [](NgMPI_Comm & c, std::vector proc_list) { + Array procs(proc_list.size()); + for (int i = 0; i < procs.Size(); i++) + { procs[i] = proc_list[i]; } + if (!procs.Contains(c.Rank())) + { throw Exception("rank "+ToString(c.Rank())+" not in subcomm"); } + return c.SubCommunicator(procs); + }, py::arg("procs")); + ; + + +#ifdef PARALLEL + py::implicitly_convertible(); +#endif // PARALLEL } diff --git a/libsrc/core/register_archive.hpp b/libsrc/core/register_archive.hpp index 93221cd6..8005a196 100644 --- a/libsrc/core/register_archive.hpp +++ b/libsrc/core/register_archive.hpp @@ -2,38 +2,91 @@ #define NETGEN_REGISTER_ARCHIVE_HPP #ifdef NETGEN_PYTHON +#include #include #include #endif // NETGEN_PYTHON +#include #include "archive.hpp" namespace ngcore { + // *************** Archiving functionality ************** - template +#ifdef NETGEN_PYTHON + template + Archive& Archive :: Shallow(T& val) + { + static_assert(detail::is_any_pointer, "ShallowArchive must be given pointer type!"); + if(shallow_to_python) + { + if(is_output) + ShallowOutPython(pybind11::cast(val)); + else + { + pybind11::object obj; + ShallowInPython(obj); + val = pybind11::cast(obj); + } + } + else + *this & val; + return *this; + } + + /* + // now using has_shared_from_this2 in archive.hpp + template + struct has_shared_from_this + { + template static std::true_type check( decltype( sizeof(&C::shared_from_this )) ) { return std::true_type(); } + template static std::false_type check(...) { return std::false_type(); } + typedef decltype( check(sizeof(char)) ) type; + static constexpr type value = type(); + }; + */ +#endif // NETGEN_PYTHON + + + template> class RegisterClassForArchive { public: RegisterClassForArchive() { - static_assert(detail::all_of_tmpl::value...>, - "Variadic template arguments must be base classes of T"); + static_assert(std::is_base_of::value || + detail::is_base_of_tuple, + "Second argument must be base class or tuple of base classes of T"); detail::ClassArchiveInfo info {}; - info.creator = [](const std::type_info& ti) -> void* - { return typeid(T) == ti ? detail::constructIfPossible() - : Archive::Caster::tryUpcast(ti, detail::constructIfPossible()); }; - info.upcaster = [/*this*/](const std::type_info& ti, void* p) -> void* - { return typeid(T) == ti ? p : Archive::Caster::tryUpcast(ti, static_cast(p)); }; - info.downcaster = [/*this*/](const std::type_info& ti, void* p) -> void* - { return typeid(T) == ti ? p : Archive::Caster::tryDowncast(ti, p); }; -#ifdef NETGEN_PYTHON - info.anyToPyCaster = [](const std::any& a) + info.creator = [](const std::type_info& ti, Archive& ar) -> void* { + detail::TCargs args; + ar &args; + auto nT = detail::constructIfPossible(std::move(args)); + return typeid(T) == ti ? nT + : Archive::Caster::tryUpcast(ti, nT); + }; + info.upcaster = [](const std::type_info& ti, void* p) -> void* + { return typeid(T) == ti ? p : Archive::Caster::tryUpcast(ti, static_cast(p)); }; + info.downcaster = [](const std::type_info& ti, void* p) -> void* + { return typeid(T) == ti ? p : Archive::Caster::tryDowncast(ti, p); }; + info.cargs_archiver = [](Archive &ar, void* p) { + if constexpr(detail::has_GetCArgs_v) + ar << static_cast(p)->GetCArgs(); + }; +#ifdef NETGEN_PYTHON + info.anyToPyCaster = [](const std::any &a) { + if constexpr(has_shared_from_this2::value) { + std::shared_ptr val = std::any_cast>(a); + return pybind11::cast(val); + } else { const T* val = std::any_cast(&a); - return pybind11::cast(val); }; + return pybind11::cast(val); + } + }; #endif // NETGEN_PYTHON - Archive::SetArchiveRegister(std::string(Demangle(typeid(T).name())),info); - } - }; + Archive::SetArchiveRegister(std::string(Demangle(typeid(T).name())),info); + } +}; } // namespace ngcore #endif // NETGEN_REGISTER_ARCHIVE_HPP diff --git a/libsrc/core/signal.hpp b/libsrc/core/signal.hpp index 082dd32b..a994f48c 100644 --- a/libsrc/core/signal.hpp +++ b/libsrc/core/signal.hpp @@ -2,6 +2,7 @@ #define NGCORE_SIGNALS_HPP #include +#include #include namespace ngcore @@ -43,6 +44,39 @@ namespace ngcore } inline bool GetEmitting() const { return is_emitting; } }; + + + + + class SimpleSignal + { + private: + // std::map> funcs; + std::list>> funcs; + public: + SimpleSignal() = default; + + template + void Connect(void* var, FUNC f) + { + // funcs[var] = f; + funcs.push_back ( { var, f } ); + } + + void Remove(void* var) + { + // funcs.erase(var); + funcs.remove_if([&] (auto var_f) { return var_f.first==var; }); + } + + inline void Emit() + { + for (auto [key,f] : funcs) + f(); + } + }; + + } // namespace ngcore #endif // NGCORE_SIGNALS_HPP diff --git a/libsrc/core/simd_arm64.hpp b/libsrc/core/simd_arm64.hpp index 9b22c36a..9e0bcce4 100644 --- a/libsrc/core/simd_arm64.hpp +++ b/libsrc/core/simd_arm64.hpp @@ -126,8 +126,14 @@ namespace ngcore return SIMD (HSum(a,b), HSum(c,d)); } + + NETGEN_INLINE SIMD SwapPairs (SIMD a) + { + return __builtin_shufflevector(a.Data(), a.Data(), 1, 0); + } + // a*b+c NETGEN_INLINE SIMD FMA (SIMD a, SIMD b, SIMD c) { @@ -148,6 +154,16 @@ namespace ngcore return FNMA(SIMD (a), b, c); } + // ARM complex mult: + // https://arxiv.org/pdf/1901.07294.pdf + // c += a*b (a0re, a0im, a1re, a1im, ...), + NETGEN_INLINE void FMAComplex (SIMD a, SIMD b, SIMD & c) + { + auto tmp = vcmlaq_f64(c.Data(), a.Data(), b.Data()); // are * b + c = vcmlaq_rot90_f64(tmp, a.Data(), b.Data()); // += i*aim * b + } + + NETGEN_INLINE SIMD operator+ (SIMD a, SIMD b) { return a.Data()+b.Data(); } diff --git a/libsrc/core/simd_avx512.hpp b/libsrc/core/simd_avx512.hpp index b1f74a21..e0ae97b5 100644 --- a/libsrc/core/simd_avx512.hpp +++ b/libsrc/core/simd_avx512.hpp @@ -61,6 +61,7 @@ namespace ngcore NETGEN_INLINE auto operator[] (int i) const { return ((int64_t*)(&data))[i]; } + NETGEN_INLINE auto & operator[] (int i) { 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 }; } @@ -111,7 +112,7 @@ namespace ngcore template void SIMD_function (const Function & func, std::true_type) { - data = (__m512){ func(7), func(6), func(5), func(4), + data = (__m512d){ func(7), func(6), func(5), func(4), func(3), func(2), func(1), func(0) }; } @@ -132,6 +133,7 @@ namespace ngcore } NETGEN_INLINE double operator[] (int i) const { return ((double*)(&data))[i]; } + NETGEN_INLINE double & operator[] (int i) { return ((double*)(&data))[i]; } NETGEN_INLINE __m512d Data() const { return data; } NETGEN_INLINE __m512d & Data() { return data; } diff --git a/libsrc/core/simd_generic.hpp b/libsrc/core/simd_generic.hpp index a54aa4e9..4512ba06 100644 --- a/libsrc/core/simd_generic.hpp +++ b/libsrc/core/simd_generic.hpp @@ -18,16 +18,10 @@ 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() { @@ -36,9 +30,7 @@ namespace ngcore 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 @@ -567,6 +559,15 @@ namespace ngcore sum = FNMA(a,b,sum); } + // c += a*b (a0re, a0im, a1re, a1im, ...), + template + void FMAComplex (SIMD a, SIMD b, SIMD & c) + { + auto [are, aim] = Unpack(a, a); + SIMD bswap = SwapPairs(b); + SIMD aim_bswap = aim*bswap; + c += FMAddSub (are, b, aim_bswap); + } template T get(SIMD a) { return a.template Get(); } diff --git a/libsrc/core/symboltable.hpp b/libsrc/core/symboltable.hpp index 62a943e9..d384d70f 100644 --- a/libsrc/core/symboltable.hpp +++ b/libsrc/core/symboltable.hpp @@ -45,7 +45,7 @@ namespace ngcore } /// INDEX of symbol name, throws exception if unused - size_t Index (const std::string & name) const + size_t Index (std::string_view name) const { for (size_t i = 0; i < names.size(); i++) if (names[i] == name) return i; @@ -53,7 +53,7 @@ namespace ngcore } /// Index of symbol name, returns -1 if unused - int CheckIndex (const std::string & name) const + int CheckIndex (std::string_view name) const { for (int i = 0; i < names.size(); i++) if (names[i] == name) return i; @@ -67,12 +67,12 @@ namespace ngcore } /// Returns reference to element. exception for unused identifier - reference operator[] (const std::string & name) + reference operator[] (std::string_view name) { return data[Index (name)]; } - const_reference operator[] (const std::string & name) const + const_reference operator[] (std::string_view name) const { return data[Index (name)]; } @@ -99,7 +99,7 @@ namespace ngcore } /// Associates el to the string name, overrides if name is used - void Set (const std::string & name, const T & el) + void Set (std::string_view name, const T & el) { int i = CheckIndex (name); if (i >= 0) @@ -107,15 +107,24 @@ namespace ngcore else { data.push_back(el); - names.push_back(name); + names.push_back(std::string(name)); } } + + + /* bool Used (const std::string & name) const { return CheckIndex(name) >= 0; } - + */ + + bool Used (std::string_view name) const + { + return CheckIndex(name) >= 0; + } + /// Deletes symboltable inline void DeleteAll () { diff --git a/libsrc/core/table.cpp b/libsrc/core/table.cpp index 1fbcda75..b71cb615 100644 --- a/libsrc/core/table.cpp +++ b/libsrc/core/table.cpp @@ -62,9 +62,9 @@ namespace ngcore return index; } - NGCORE_API size_t * TablePrefixSum32 (FlatArray entrysize) + NGCORE_API size_t * TablePrefixSum32 (FlatArray entrysize) { return TablePrefixSum2 (entrysize); } - NGCORE_API size_t * TablePrefixSum64 (FlatArray entrysize) + NGCORE_API size_t * TablePrefixSum64 (FlatArray entrysize) { return TablePrefixSum2 (entrysize); } /* diff --git a/libsrc/core/table.hpp b/libsrc/core/table.hpp index 47893ed5..f7ba47ea 100644 --- a/libsrc/core/table.hpp +++ b/libsrc/core/table.hpp @@ -17,6 +17,7 @@ #include "ngcore_api.hpp" #include "profiler.hpp" + namespace ngcore { @@ -93,6 +94,7 @@ namespace ngcore Iterator end() const { return Iterator(*this, BASE+size); } }; + /* NGCORE_API extern size_t * TablePrefixSum32 (FlatArray entrysize); NGCORE_API extern size_t * TablePrefixSum64 (FlatArray entrysize); @@ -105,7 +107,20 @@ namespace ngcore { return TablePrefixSum32 (FlatArray (entrysize.Size(), (unsigned int*)(std::atomic*)entrysize.Addr(0))); } NETGEN_INLINE size_t * TablePrefixSum (FlatArray entrysize) { return TablePrefixSum64 (entrysize); } + */ + NGCORE_API extern size_t * TablePrefixSum32 (FlatArray entrysize); + NGCORE_API extern size_t * TablePrefixSum64 (FlatArray entrysize); + + template // TODO: enable_if T is integral + NETGEN_INLINE size_t * TablePrefixSum (FlatArray entrysize) + { + if constexpr (sizeof(T) == 4) + return TablePrefixSum32 ( { entrysize.Size(), (uint32_t*)(void*)entrysize.Addr(0) }); + else + return TablePrefixSum64 ( { entrysize.Size(), (uint64_t*)(void*)entrysize.Addr(0) }); + } + /** A compact Table container. @@ -130,6 +145,7 @@ namespace ngcore { for (size_t i : IntRange(size+1)) index[i] = i*entrysize; + mt.Alloc(GetMemUsage()); } /// Construct table of variable entrysize @@ -141,6 +157,7 @@ namespace ngcore index = TablePrefixSum (FlatArray (entrysize.Size(), entrysize.Data())); size_t cnt = index[size]; data = new T[cnt]; + mt.Alloc(GetMemUsage()); } explicit NETGEN_INLINE Table (const FlatTable & tab2) @@ -157,6 +174,7 @@ namespace ngcore size_t cnt = index[size]; data = new T[cnt]; this->AsArray() = tab2.AsArray(); + mt.Alloc(GetMemUsage()); /* for (size_t i = 0; i < cnt; i++) data[i] = tab2.data[i]; @@ -177,12 +195,14 @@ namespace ngcore data = new T[cnt]; for (size_t i = 0; i < cnt; i++) data[i] = tab2.data[i]; + + mt.Alloc(GetMemUsage()); } NETGEN_INLINE Table (Table && tab2) : FlatTable(0, nullptr, nullptr) { - tab2.mt.Free(tab2.GetMemUsage()); + mt = std::move(tab2.mt); Swap (size, tab2.size); Swap (index, tab2.index); Swap (data, tab2.data); @@ -210,7 +230,7 @@ namespace ngcore NETGEN_INLINE Table & operator= (Table && tab2) { - mt.Swap(GetMemUsage(), tab2.mt, tab2.GetMemUsage()); + mt = std::move(tab2.mt); Swap (size, tab2.size); Swap (index, tab2.index); Swap (data, tab2.data); @@ -324,8 +344,8 @@ namespace ngcore case 1: { size_t oldval = nd; - while (blocknr+1>nd) { - nd.compare_exchange_weak (oldval, blocknr+1); + while (blocknr-IndexBASE()+1>nd) { + nd.compare_exchange_weak (oldval, blocknr-IndexBASE()+1); oldval = nd; } break; @@ -401,7 +421,7 @@ namespace ngcore pcreator = std::make_unique>(*cnt); else pcreator = std::make_unique>(); - + auto & creator = *pcreator; for ( ; !creator.Done(); creator++) @@ -447,7 +467,9 @@ namespace ngcore void Add (size_t blocknr, FlatArray dofs); }; + + /** A dynamic table class. diff --git a/libsrc/core/taskmanager.cpp b/libsrc/core/taskmanager.cpp index f57be4db..31e160d3 100644 --- a/libsrc/core/taskmanager.cpp +++ b/libsrc/core/taskmanager.cpp @@ -76,14 +76,14 @@ namespace ngcore numa_run_on_node (0); #endif -#ifndef WIN32 +#if !defined(WIN32) && !defined(EMSCRIPTEN) // 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 +#endif // !defined(WIN32) && !defined(EMSCRIPTEN) task_manager->StartWorkers(); @@ -168,6 +168,12 @@ namespace ngcore trace = nullptr; } num_threads = 1; +#ifdef USE_NUMA + for (int j = 0; j < num_nodes; j++) + numa_free (nodedata[j], sizeof(NodeData)); +#else + delete nodedata[0]; +#endif } #ifdef WIN32 @@ -412,7 +418,7 @@ namespace ngcore } } - catch (Exception e) + catch (Exception & e) { { lock_guard guard(copyex_mutex); @@ -548,7 +554,7 @@ namespace ngcore } } - catch (Exception e) + catch (Exception & e) { { // cout << "got exception in TM" << endl; diff --git a/libsrc/core/taskmanager.hpp b/libsrc/core/taskmanager.hpp index 53cf21b4..9a37a247 100644 --- a/libsrc/core/taskmanager.hpp +++ b/libsrc/core/taskmanager.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -316,6 +317,7 @@ namespace ngcore public: SharedLoop (IntRange ar) : r(ar) { cnt = r.begin(); } + SharedLoop (size_t s) : SharedLoop (IntRange{s}) { ; } SharedIterator begin() { return SharedIterator (cnt, r.end(), true); } SharedIterator end() { return SharedIterator (cnt, r.end(), false); } }; @@ -622,6 +624,8 @@ public: Reset (r); } + SharedLoop2 (size_t s) : SharedLoop2 (IntRange{s}) { } + void Reset (IntRange r) { for (size_t i = 0; i < ranges.Size(); i++) @@ -631,6 +635,9 @@ public: participants.store(0, std::memory_order_relaxed); processed.store(0, std::memory_order_release); } + + void Reset (size_t s) { Reset(IntRange{s}); } + SharedIterator begin() { @@ -1010,7 +1017,7 @@ public: int num_nodes = numa_num_configured_nodes(); size_t pagesize = numa_pagesize(); - int npages = ceil ( double(s)*sizeof(T) / pagesize ); + int npages = std::ceil ( double(s)*sizeof(T) / pagesize ); // cout << "size = " << numa_size << endl; // cout << "npages = " << npages << endl; diff --git a/libsrc/core/type_traits.hpp b/libsrc/core/type_traits.hpp index 17da6253..361a31e9 100644 --- a/libsrc/core/type_traits.hpp +++ b/libsrc/core/type_traits.hpp @@ -16,6 +16,15 @@ namespace ngcore template struct is_any_pointer_impl : std::false_type {}; + // check if second template argument is tuple of base classes to first + // template argument, return constexpr bool + template + constexpr bool is_base_of_tuple = false; + + template + constexpr bool is_base_of_tuple> = + all_of_tmpl::value...>; + template struct is_any_pointer_impl : std::true_type {}; diff --git a/libsrc/core/utils.cpp b/libsrc/core/utils.cpp index 7eda05f5..8a792ea9 100644 --- a/libsrc/core/utils.cpp +++ b/libsrc/core/utils.cpp @@ -3,16 +3,25 @@ #include "logging.hpp" #include "simd_generic.hpp" -#ifndef WIN32 +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#undef WIN32_LEAN_AND_MEAN +#else // WIN32 #include -#endif +#include +#endif //WIN32 +// #include #include #include #include +#include +#include #include "ngstream.hpp" + namespace ngcore { namespace detail @@ -43,8 +52,16 @@ namespace ngcore */ std::string CleanupDemangledName( std::string s ) { - //for(const auto & [r, sub] : demangle_regexes) - // s = std::regex_replace (s,r,sub); + for(const auto & [r, sub] : demangle_regexes) + s = std::regex_replace (s,r,sub); +#ifdef EMSCRIPTEN + // for some reason regex_replace is not working at all + std::string temp = s; + s = ""; + for(auto c : temp) + if(c!=' ') + s+=c; +#endif // EMSCRIPTEN return s; } @@ -103,7 +120,7 @@ namespace ngcore const std::chrono::time_point wall_time_start = TClock::now(); - int printmessage_importance = 0; + int printmessage_importance = getenv("NG_MESSAGE_LEVEL") ? atoi(getenv("NG_MESSAGE_LEVEL")) : 0; bool NGSOStream :: glob_active = true; NGCORE_API int GetCompiledSIMDSize() @@ -128,5 +145,91 @@ namespace ngcore return path; } + + SharedLibrary :: SharedLibrary(const std::filesystem::path & lib_name_, std::optional directory_to_delete_, bool global ) + : lib_name(lib_name_),directory_to_delete(directory_to_delete_) + { + Load(lib_name, global); + } + + SharedLibrary :: ~SharedLibrary() + { + Unload(); + if(directory_to_delete) + for([[maybe_unused]] auto i : Range(5)) + { + // on Windows, a (detached?) child process of the compiler/linker might still block the directory + // wait for it to finish (up to a second) + try + { + std::filesystem::remove_all(*directory_to_delete); + directory_to_delete = std::nullopt; + break; + } + catch(const std::exception &e) + { + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + } + } + if(directory_to_delete) + std::cerr << "Could not delete " << directory_to_delete->string() << std::endl; + } + + void SharedLibrary :: Load( const std::filesystem::path & lib_name_, bool global ) + { + Unload(); + lib_name = lib_name_; +#ifdef WIN32 + lib = LoadLibraryW(lib_name.wstring().c_str()); + if (!lib) throw std::runtime_error(std::string("Could not load library ") + lib_name.string()); +#else // WIN32 + auto flags = RTLD_NOW; + if (global) flags |= RTLD_GLOBAL; + lib = dlopen(lib_name.c_str(), flags); + if(lib == nullptr) throw std::runtime_error(dlerror()); +#endif // WIN32 + } + + void SharedLibrary :: Unload() { + if(lib) + { +#ifdef WIN32 + FreeLibrary((HMODULE)lib); +#else // WIN32 + int rc = dlclose(lib); + if(rc != 0) std::cerr << "Failed to close library " << lib_name << std::endl; +#endif // WIN32 + } + } + + void* SharedLibrary :: GetRawSymbol( std::string func_name ) + { +#ifdef WIN32 + void* func = GetProcAddress((HMODULE)lib, func_name.c_str()); + if(func == nullptr) + throw std::runtime_error(std::string("Could not find function ") + func_name + " in library " + lib_name.string()); +#else // WIN32 + void* func = dlsym(lib, func_name.c_str()); + if(func == nullptr) + throw std::runtime_error(dlerror()); +#endif // WIN32 + + return func; + } + + void* GetRawSymbol( std::string func_name ) + { + void * func = nullptr; +#ifdef WIN32 + throw std::runtime_error("GetRawSymbol not implemented on WIN32"); +#else // WIN32 + func = dlsym(RTLD_DEFAULT, func_name.c_str()); + if(func == nullptr) + throw std::runtime_error(dlerror()); +#endif // WIN32 + return func; + } + + } // namespace ngcore diff --git a/libsrc/core/utils.hpp b/libsrc/core/utils.hpp index 4f37795c..a503d53c 100644 --- a/libsrc/core/utils.hpp +++ b/libsrc/core/utils.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -71,6 +72,8 @@ namespace ngcore unsigned long long tics; __asm __volatile("mrs %0, CNTVCT_EL0" : "=&r" (tics)); return tics; +#elif defined(__EMSCRIPTEN__) + return std::chrono::high_resolution_clock::now().time_since_epoch().count(); #else #warning "Unsupported CPU architecture" return 0; @@ -179,7 +182,7 @@ namespace ngcore /// square element template - NETGEN_INLINE T sqr (const T a) + NETGEN_INLINE constexpr T sqr (const T a) { return a * a; } @@ -251,6 +254,27 @@ namespace ngcore template using IC = std::integral_constant; // needed for Iterate + + + namespace detail { + template + struct IsIC_trait { + static constexpr auto check() { return false; } + }; + + template + struct IsIC_trait> == true, int> > { + static constexpr auto check() { return true; } + }; + } + + template + constexpr bool is_IC() { + return detail::IsIC_trait::check(); + } + + + template NETGEN_INLINE void Iterate (FUNC f) @@ -324,6 +348,41 @@ namespace ngcore NGCORE_API std::filesystem::path GetTempFilename(); + NGCORE_API void* GetRawSymbol( std::string func_name ); + + template + TFunc GetSymbol( std::string func_name ) + { + return reinterpret_cast(GetRawSymbol(func_name)); + } + + // Class to handle/load shared libraries + class NGCORE_API SharedLibrary + { + std::filesystem::path lib_name; + std::optional directory_to_delete = std::nullopt; + void *lib = nullptr; + + public: + SharedLibrary() = default; + SharedLibrary(const std::filesystem::path & lib_name_, std::optional directory_to_delete_ = std::nullopt, bool global = false ); + + SharedLibrary(const SharedLibrary &) = delete; + SharedLibrary & operator =(const SharedLibrary &) = delete; + + ~SharedLibrary(); + + template + TFunc GetSymbol( std::string func_name ) + { + return reinterpret_cast(GetRawSymbol(func_name)); + } + + void Load( const std::filesystem::path & lib_name_, bool global = true); + void Unload(); + void* GetRawSymbol( std::string func_name ); + }; + } // namespace ngcore #endif // NETGEN_CORE_UTILS_HPP diff --git a/libsrc/csg/csgeom.cpp b/libsrc/csg/csgeom.cpp index 2d5dcfef..dcc6c666 100644 --- a/libsrc/csg/csgeom.cpp +++ b/libsrc/csg/csgeom.cpp @@ -1211,7 +1211,7 @@ namespace netgen PrintMessage (2, "Object ", i, " has ", tams->GetNT(), " triangles"); } } - catch (exception) + catch (const std::exception &) { cerr << "*************************************************************" << endl << "**** out of memory problem in CSG visualization ****" << endl diff --git a/libsrc/csg/csgeom.hpp b/libsrc/csg/csgeom.hpp index 63de9443..7fc1cac3 100644 --- a/libsrc/csg/csgeom.hpp +++ b/libsrc/csg/csgeom.hpp @@ -18,7 +18,6 @@ namespace netgen class TriangleApproximation; class TATriangle; - /** A top level object is an entity to be meshed. I can be either a solid, or one surface patch of a solid. diff --git a/libsrc/csg/edgeflw.cpp b/libsrc/csg/edgeflw.cpp index 26d5172d..afa8184f 100644 --- a/libsrc/csg/edgeflw.cpp +++ b/libsrc/csg/edgeflw.cpp @@ -567,7 +567,7 @@ namespace netgen { // int i, j; SegmentIndex si; - PointIndex pi; + // PointIndex pi; NgArray osedges(cntedge); INDEX_2_HASHTABLE osedgesht (cntedge+1); @@ -610,7 +610,7 @@ namespace netgen for (int i = 1; i <= osedgesht.GetNBags(); i++) for (int j = 1; j <= osedgesht.GetBagSize(i); j++) { - INDEX_2 i2; + PointIndices<2> i2; int val; osedgesht.GetData (i, j, i2, val); @@ -619,8 +619,8 @@ namespace netgen Vec<3> v = p2 - p1; double vlen = v.Length(); v /= vlen; - for (pi = PointIndex::BASE; - pi < mesh.GetNP()+PointIndex::BASE; pi++) + for (PointIndex pi = IndexBASE(); + pi < mesh.GetNP()+IndexBASE(); pi++) if (pi != i2.I1() && pi != i2.I2()) { @@ -1371,8 +1371,8 @@ namespace netgen lastpi = PointIndex::INVALID; /* - for (pi = PointIndex::BASE; - pi < mesh.GetNP()+PointIndex::BASE; pi++) + for (pi = IndexBASE(); + pi < mesh.GetNP()+IndexBASE(); pi++) if (Dist (mesh[pi], p) < 1e-6) { lastpi = pi; @@ -1414,8 +1414,8 @@ namespace netgen if (i == ne) { /* - for (pi = PointIndex::BASE; - pi < mesh.GetNP()+PointIndex::BASE; pi++) + for (pi = IndexBASE(); + pi < mesh.GetNP()+IndexBASE(); pi++) if (Dist(mesh[pi], np) < 1e-6) thispi = pi; */ @@ -1539,8 +1539,8 @@ namespace netgen // generate initial point Point<3> p = edgepoints[0]; PointIndex pi1 = PointIndex::INVALID; - for (pi = PointIndex::BASE; - pi < mesh.GetNP()+PointIndex::BASE; pi++) + for (PointIndex pi = IndexBASE(); + pi < mesh.GetNP()+IndexBASE(); pi++) if (Dist (mesh[pi], p) < 1e-6*geometry.MaxSize()) { @@ -1557,8 +1557,8 @@ namespace netgen p = edgepoints.Last(); PointIndex pi2 = PointIndex::INVALID; - for (pi = PointIndex::BASE; - pi < mesh.GetNP()+PointIndex::BASE; pi++) + for (pi = IndexBASE(); + pi < mesh.GetNP()+IndexBASE(); pi++) if (Dist (mesh[pi], p) < 1e-6*geometry.MaxSize()) { @@ -1646,7 +1646,7 @@ namespace netgen Mesh & mesh) { int k; - PointIndex pi; + // PointIndex pi; double size = geometry.MaxSize(); @@ -1660,8 +1660,8 @@ namespace netgen PointIndex frompi = PointIndex::INVALID; PointIndex topi = PointIndex::INVALID; - for (pi = PointIndex::BASE; - pi < mesh.GetNP()+PointIndex::BASE; pi++) + for (PointIndex pi = IndexBASE(); + pi < mesh.GetNP()+IndexBASE(); pi++) { if (Dist2 (mesh[pi], fromp) <= 1e-16*size) frompi = pi; @@ -1714,12 +1714,12 @@ namespace netgen if (oldseg.seginfo == 0) continue; - int pi1 = oldseg[0]; - int pi2 = oldseg[1]; + PointIndex pi1 = oldseg[0]; + PointIndex pi2 = oldseg[1]; - int npi1 = geometry.identifications.Get(copyedgeidentification) + PointIndex npi1 = geometry.identifications.Get(copyedgeidentification) -> GetIdentifiedPoint (mesh, pi1); - int npi2 = geometry.identifications.Get(copyedgeidentification) + PointIndex npi2 = geometry.identifications.Get(copyedgeidentification) -> GetIdentifiedPoint (mesh, pi2); //(*testout) << "copy edge, pts = " << npi1 << " - " << npi2 << endl; @@ -1885,12 +1885,10 @@ namespace netgen if (seg1.domin != -1 || seg1.domout != -1) { - mesh.AddPoint (p1, layer, EDGEPOINT); - mesh.AddPoint (p2, layer, EDGEPOINT); - seg1[0] = mesh.GetNP()-1; - seg1[1] = mesh.GetNP(); - seg2[1] = mesh.GetNP()-1; - seg2[0] = mesh.GetNP(); + seg1[0] = mesh.AddPoint (p1, layer, EDGEPOINT); + seg1[1] = mesh.AddPoint (p2, layer, EDGEPOINT); + seg2[0] = seg1[1]; + seg2[1] = seg1[0]; seg1.geominfo[0].trignum = 1; seg1.geominfo[1].trignum = 1; seg2.geominfo[0].trignum = 1; diff --git a/libsrc/csg/genmesh.cpp b/libsrc/csg/genmesh.cpp index da790fc4..f613db25 100644 --- a/libsrc/csg/genmesh.cpp +++ b/libsrc/csg/genmesh.cpp @@ -35,7 +35,7 @@ namespace netgen auto up = geom.GetUserPoint(i); auto pnum = mesh.AddPoint(up); mesh.Points().Last().Singularity (geom.GetUserPointRefFactor(i)); - mesh.AddLockedPoint (PointIndex (i+1)); + mesh.AddLockedPoint (pnum); int index = up.GetIndex(); if (index == -1) index = mesh.AddCD3Name (up.GetName())+1; @@ -443,7 +443,7 @@ namespace netgen meshing.SetStartTime (starttime); double eps = 1e-8 * geom.MaxSize(); - for (PointIndex pi = PointIndex::BASE; pi < noldp+PointIndex::BASE; pi++) + for (PointIndex pi = IndexBASE(); pi < noldp+IndexBASE(); pi++) { // if(surf->PointOnSurface(mesh[pi])) meshing.AddPoint (mesh[pi], pi, NULL, @@ -473,8 +473,8 @@ namespace netgen { PointGeomInfo gi; gi.trignum = k; - meshing.AddBoundaryElement (segments[si][0] + 1 - PointIndex::BASE, - segments[si][1] + 1 - PointIndex::BASE, + meshing.AddBoundaryElement (segments[si][0] + 1 - IndexBASE(), + segments[si][1] + 1 - IndexBASE(), gi, gi); } @@ -718,7 +718,7 @@ namespace netgen mesh -> LoadLocalMeshSize (mparam.meshsizefilename); for (auto mspnt : mparam.meshsize_points) - mesh -> RestrictLocalH (mspnt.pnt, mspnt.h); + mesh -> RestrictLocalH (mspnt.pnt, mspnt.h, mspnt.layer); } spoints.SetSize(0); @@ -826,6 +826,9 @@ namespace netgen { multithread.task = "Volume meshing"; + for (int i = 0; i < geom.GetNTopLevelObjects(); i++) + mesh->SetMaterial (i+1, geom.GetTopLevelObject(i)->GetMaterial().c_str()); + MESHING3_RESULT res = MeshVolume (mparam, *mesh); @@ -838,10 +841,6 @@ namespace netgen MeshQuality3d (*mesh); - for (int i = 0; i < geom.GetNTopLevelObjects(); i++) - mesh->SetMaterial (i+1, geom.GetTopLevelObject(i)->GetMaterial().c_str()); - - #ifdef STAT_STREAM (*statout) << GetTime() << " & "; #endif diff --git a/libsrc/csg/identify.cpp b/libsrc/csg/identify.cpp index 08e7c027..e87a6679 100644 --- a/libsrc/csg/identify.cpp +++ b/libsrc/csg/identify.cpp @@ -65,10 +65,10 @@ ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const return 0; } -int Identification :: GetIdentifiedPoint (class Mesh & mesh, int pi) +PointIndex Identification :: GetIdentifiedPoint (class Mesh & mesh, PointIndex pi) { cout << "Identification::GetIdentifiedPoint called for base-class" << endl; - return -1; + return PointIndex::INVALID; } void Identification :: IdentifyPoints (Mesh & mesh) @@ -261,8 +261,8 @@ Identifiable (const Point<3> & p1, const Point<3> & p2) const -int PeriodicIdentification :: -GetIdentifiedPoint (class Mesh & mesh, int pi) +PointIndex PeriodicIdentification :: +GetIdentifiedPoint (class Mesh & mesh, PointIndex pi) { const Surface *snew; const Point<3> & p = mesh.Point (pi); @@ -289,14 +289,14 @@ GetIdentifiedPoint (class Mesh & mesh, int pi) // project to other surface snew->Project (hp); - int newpi = 0; - for (int i = 1; i <= mesh.GetNP(); i++) - if (Dist2 (mesh.Point(i), hp) < 1e-12) + PointIndex newpi(PointIndex::INVALID); + for (PointIndex pi : Range(mesh.Points())) + if (Dist2 (mesh.Point(pi), hp) < 1e-12) { - newpi = i; + newpi = pi; break; } - if (!newpi) + if (!newpi.IsValid()) newpi = mesh.AddPoint (hp); if (snew == s2) @@ -322,6 +322,7 @@ void PeriodicIdentification :: IdentifyPoints (class Mesh & mesh) 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); @@ -334,13 +335,24 @@ void PeriodicIdentification :: IdentifyPoints (class Mesh & mesh) if (Dist2(mesh.Point(j), pp) < eps) { mesh.GetIdentifications().Add (i, j, nr); - /* - (*testout) << "Identify points(periodic:), nr = " << nr << ": " - << mesh.Point(i) << " - " << mesh.Point(j) << endl; - */ } } } + */ + + for (auto pi : Range(mesh.Points())) + { + Point<3> p = mesh[pi]; + if (s1->PointOnSurface (p)) + { + Point<3> pp = p; + pp = trafo(pp); + s2->Project (pp); + for (PointIndex pj : Range(mesh.Points())) + if (Dist2(mesh[pj], pp) < eps) + mesh.GetIdentifications().Add (pi, pj, nr); + } + } mesh.GetIdentifications().SetType(nr,Identifications::PERIODIC); } @@ -396,15 +408,15 @@ void PeriodicIdentification :: IdentifyFaces (class Mesh & mesh) if (side == 1) { - if (mesh.GetIdentifications().Get (seg1[0], seg2[0]) && - mesh.GetIdentifications().Get (seg1[1], seg2[1])) + if (mesh.GetIdentifications().Used (seg1[0], seg2[0]) && + mesh.GetIdentifications().Used (seg1[1], seg2[1])) { foundother = 1; break; } - if (mesh.GetIdentifications().Get (seg1[0], seg2[1]) && - mesh.GetIdentifications().Get (seg1[1], seg2[0])) + if (mesh.GetIdentifications().Used (seg1[0], seg2[1]) && + mesh.GetIdentifications().Used (seg1[1], seg2[0])) { foundother = 1; break; @@ -412,15 +424,15 @@ void PeriodicIdentification :: IdentifyFaces (class Mesh & mesh) } else { - if (mesh.GetIdentifications().Get (seg2[0], seg1[0]) && - mesh.GetIdentifications().Get (seg2[1], seg1[1])) + if (mesh.GetIdentifications().Used (seg2[0], seg1[0]) && + mesh.GetIdentifications().Used (seg2[1], seg1[1])) { foundother = 1; break; } - if (mesh.GetIdentifications().Get (seg2[0], seg1[1]) && - mesh.GetIdentifications().Get (seg2[1], seg1[0])) + if (mesh.GetIdentifications().Used (seg2[0], seg1[1]) && + mesh.GetIdentifications().Used (seg2[1], seg1[0])) { foundother = 1; break; @@ -885,17 +897,21 @@ ShortEdge (const SpecialPoint & sp1, const SpecialPoint & sp2) const -int CloseSurfaceIdentification :: -GetIdentifiedPoint (class Mesh & mesh, int pi) +PointIndex CloseSurfaceIdentification :: +GetIdentifiedPoint (class Mesh & mesh, PointIndex pi) { const Surface *snew; const Point<3> & p = mesh.Point (pi); - NgArray identmap(mesh.GetNP()); + idmap_type identmap(mesh.GetNP()); mesh.GetIdentifications().GetMap (nr, identmap); + /* if (identmap.Get(pi)) return identmap.Get(pi); - + */ + if (identmap[pi].IsValid()) + return identmap[pi]; + if (s1->PointOnSurface (p)) snew = s2; @@ -1168,15 +1184,15 @@ void CloseSurfaceIdentification :: IdentifyFaces (class Mesh & mesh) if (side == 1) { - if (mesh.GetIdentifications().Get (seg1[0], seg2[0]) && - mesh.GetIdentifications().Get (seg1[1], seg2[1])) + if (mesh.GetIdentifications().Used (seg1[0], seg2[0]) && + mesh.GetIdentifications().Used (seg1[1], seg2[1])) { foundother = 1; break; } - if (mesh.GetIdentifications().Get (seg1[0], seg2[1]) && - mesh.GetIdentifications().Get (seg1[1], seg2[0])) + if (mesh.GetIdentifications().Used (seg1[0], seg2[1]) && + mesh.GetIdentifications().Used (seg1[1], seg2[0])) { foundother = 1; break; @@ -1184,15 +1200,15 @@ void CloseSurfaceIdentification :: IdentifyFaces (class Mesh & mesh) } else { - if (mesh.GetIdentifications().Get (seg2[0], seg1[0]) && - mesh.GetIdentifications().Get (seg2[1], seg1[1])) + if (mesh.GetIdentifications().Used (seg2[0], seg1[0]) && + mesh.GetIdentifications().Used (seg2[1], seg1[1])) { foundother = 1; break; } - if (mesh.GetIdentifications().Get (seg2[0], seg1[1]) && - mesh.GetIdentifications().Get (seg2[1], seg1[0])) + if (mesh.GetIdentifications().Used (seg2[0], seg1[1]) && + mesh.GetIdentifications().Used (seg2[1], seg1[0])) { foundother = 1; break; @@ -1229,7 +1245,7 @@ BuildSurfaceElements (NgArray & segs, bool found = 0; int cntquads = 0; - NgArray identmap; + idmap_type identmap; identmap = 0; mesh.GetIdentifications().GetMap (nr, identmap); @@ -1650,8 +1666,8 @@ BuildSurfaceElements (NgArray & segs, { const Segment & s1 = segs.Get(i1); const Segment & s2 = segs.Get(i2); - if (mesh.GetIdentifications().Get (s1[0], s2[1]) && - mesh.GetIdentifications().Get (s1[1], s2[0])) + if (mesh.GetIdentifications().Used (s1[0], s2[1]) && + mesh.GetIdentifications().Used (s1[1], s2[0])) { Element2d el(QUAD); el.PNum(1) = s1[0]; diff --git a/libsrc/csg/identify.hpp b/libsrc/csg/identify.hpp index 90e5f4b0..c8570238 100644 --- a/libsrc/csg/identify.hpp +++ b/libsrc/csg/identify.hpp @@ -56,7 +56,7 @@ namespace netgen virtual void IdentifyFaces (class Mesh & mesh); /// get point on other surface, add entry in mesh identifications - virtual int GetIdentifiedPoint (class Mesh & mesh, int pi1); + virtual PointIndex GetIdentifiedPoint (class Mesh & mesh, PointIndex pi1); /// copy surfaces, or fill rectangles virtual void BuildSurfaceElements (NgArray & segs, @@ -97,7 +97,7 @@ namespace netgen const TABLE & specpoint2surface) 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 PointIndex GetIdentifiedPoint (class Mesh & mesh, PointIndex pi1) override; virtual void IdentifyPoints (class Mesh & mesh) override; virtual void IdentifyFaces (class Mesh & mesh) override; virtual void BuildSurfaceElements (NgArray & segs, @@ -153,7 +153,7 @@ namespace netgen 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); + virtual PointIndex GetIdentifiedPoint (class Mesh & mesh, PointIndex pi1); const Array & GetSlices () const { return slices; } virtual void IdentifyPoints (class Mesh & mesh); virtual void IdentifyFaces (class Mesh & mesh); diff --git a/libsrc/csg/python_csg.cpp b/libsrc/csg/python_csg.cpp index f66f61c6..6376abd4 100644 --- a/libsrc/csg/python_csg.cpp +++ b/libsrc/csg/python_csg.cpp @@ -583,8 +583,8 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails! NgArray si1, si2; s1->GetSolid()->GetSurfaceIndices (si1); s2->GetSolid()->GetSurfaceIndices (si2); - cout << "surface ids1 = " << si1 << endl; - cout << "surface ids2 = " << si2 << endl; + cout << IM(3) << "surface ids1 = " << si1 << endl; + cout << IM(3) << "surface ids2 = " << si2 << endl; Flags flags; const TopLevelObject * domain = nullptr; @@ -756,10 +756,8 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails! { MeshingParameters mp; if(pars) mp = *pars; - { - py::gil_scoped_acquire aq; - CreateMPfromKwargs(mp, kwargs); - } + CreateMPfromKwargs(mp, kwargs); + py::gil_scoped_release gil_rel; auto mesh = make_shared(); SetGlobalMesh (mesh); mesh->SetGeometry(geo); @@ -770,8 +768,7 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails! throw Exception("Meshing failed!"); return mesh; }, py::arg("mp") = nullptr, - meshingparameter_description.c_str(), - py::call_guard()) + meshingparameter_description.c_str()) ; m.def("Save", FunctionPointer diff --git a/libsrc/csg/revolution.cpp b/libsrc/csg/revolution.cpp index cc872cec..10ea2141 100644 --- a/libsrc/csg/revolution.cpp +++ b/libsrc/csg/revolution.cpp @@ -781,7 +781,7 @@ namespace netgen Point<2> p2d; faces[0]->CalcProj(p,p2d); - int intersections_before(0), intersections_after(0); + [[maybe_unused]] int intersections_before(0), intersections_after(0); double randomx = 7.42357; double randomy = 1.814756; double randomlen = sqrt(randomx*randomx+randomy*randomy); diff --git a/libsrc/csg/singularref.cpp b/libsrc/csg/singularref.cpp index 8dc1b7e5..dea9c1cc 100644 --- a/libsrc/csg/singularref.cpp +++ b/libsrc/csg/singularref.cpp @@ -53,7 +53,7 @@ void SingularEdge :: FindPointsOnEdge (class Mesh & mesh) for (SegmentIndex si = 0; si < mesh.GetNSeg(); si++) { - INDEX_2 i2 (mesh[si][0], mesh[si][1]); + PointIndices<2> i2 (mesh[si][0], mesh[si][1]); /* bool onedge = 1; @@ -93,8 +93,8 @@ void SingularEdge :: FindPointsOnEdge (class Mesh & mesh) { segms.Append (i2); // PrintMessage (5, "sing segment ", i2.I1(), " - ", i2.I2()); - points.Append (mesh[ PointIndex (i2.I1())]); - points.Append (mesh[ PointIndex (i2.I2())]); + points.Append (mesh[i2.I1()]); + points.Append (mesh[i2.I2()]); mesh[si].singedge_left = factor; mesh[si].singedge_right = factor; } @@ -153,8 +153,8 @@ void SingularPoint :: FindPoints (class Mesh & mesh) NgArray surfk, surf; - for (PointIndex pi = PointIndex::BASE; - pi < mesh.GetNP()+PointIndex::BASE; pi++) + for (PointIndex pi = IndexBASE(); + pi < mesh.GetNP()+IndexBASE(); pi++) { if (mesh[pi].Type() != FIXEDPOINT) continue; const Point<3> p = mesh[pi]; diff --git a/libsrc/csg/surface.cpp b/libsrc/csg/surface.cpp index e31e9fce..76ed14d5 100644 --- a/libsrc/csg/surface.cpp +++ b/libsrc/csg/surface.cpp @@ -580,5 +580,5 @@ void ProjectToEdge (const Surface * f1, const Surface * f2, Point<3> & hp) RegisterClassForArchive regsurf; RegisterClassForArchive regprim; -RegisterClassForArchive regosf; +RegisterClassForArchive> regosf; } diff --git a/libsrc/csg/vscsg.cpp b/libsrc/csg/vscsg.cpp index ed511e79..2e764b57 100644 --- a/libsrc/csg/vscsg.cpp +++ b/libsrc/csg/vscsg.cpp @@ -343,7 +343,7 @@ namespace netgen const Point3d p = Center (p1, p2); glRasterPos3d (p.X(), p.Y(), p.Z()); - sprintf (buf, "%d", seg.edgenr); + snprintf (buf, sizeof(buf), "%d", seg.edgenr); // glCallLists (GLsizei(strlen (buf)), GL_UNSIGNED_BYTE, buf); MyOpenGLText (buf); } @@ -393,9 +393,9 @@ namespace netgen glBitmap (7, 7, 3, 3, 0, 0, &knoedel[0]); } */ - for (const Point3d & p : mesh->Points()) + for (Point<3> p : mesh->Points()) { - glRasterPos3d (p.X(), p.Y(), p.Z()); + glRasterPos3d (p(0), p(1), p(2)); glBitmap (7, 7, 3, 3, 0, 0, &knoedel[0]); } } @@ -418,7 +418,7 @@ namespace netgen const Point3d & p = mesh->Point(i); glRasterPos3d (p.X(), p.Y(), p.Z()); - sprintf (buf, "%d", int(i)); + snprintf (buf, sizeof(buf), "%d", int(i)); // glCallLists (GLsizei(strlen (buf)), GL_UNSIGNED_BYTE, buf); MyOpenGLText (buf); } @@ -472,7 +472,8 @@ namespace netgen box = Box3d (Point3d (0,0,0), Point3d (1,1,1)); } - if (zoomall == 2 && ((vispar.centerpoint >= 1 && vispar.centerpoint <= mesh->GetNP()) || + if (zoomall == 2 && ((vispar.centerpoint-IndexBASE() >= 0 && + vispar.centerpoint-IndexBASE() < mesh->GetNP()) || vispar.use_center_coords)) { if (vispar.use_center_coords) diff --git a/libsrc/csg/zrefine.cpp b/libsrc/csg/zrefine.cpp index 30594d5b..6e154bcb 100644 --- a/libsrc/csg/zrefine.cpp +++ b/libsrc/csg/zrefine.cpp @@ -45,9 +45,10 @@ namespace netgen void MakePrismsSingEdge (Mesh & mesh, INDEX_2_HASHTABLE & singedges) { // volume elements - for (int i = 1; i <= mesh.GetNE(); i++) + // for (int i = 1; i <= mesh.GetNE(); i++) + for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) { - Element & el = mesh.VolumeElement(i); + Element & el = mesh.VolumeElement(ei); if (el.GetType() != TET) continue; for (int j = 1; j <= 3; j++) @@ -76,9 +77,9 @@ namespace netgen } // surface elements - for (int i = 1; i <= mesh.GetNSE(); i++) + for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) { - Element2d & el = mesh.SurfaceElement(i); + Element2d & el = mesh.SurfaceElement(sei); if (el.GetType() != TRIG) continue; for (int j = 1; j <= 3; j++) @@ -110,18 +111,18 @@ namespace netgen */ void MakePrismsClosePoints (Mesh & mesh) { - int i, j, k; - for (i = 1; i <= mesh.GetNE(); i++) + // int i, j, k; + for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) { - Element & el = mesh.VolumeElement(i); + Element & el = mesh.VolumeElement(ei); if (el.GetType() == TET) { - for (j = 1; j <= 3; j++) - for (k = j+1; k <= 4; k++) + for (int j = 1; j <= 3; j++) + for (int k = j+1; k <= 4; k++) { INDEX_2 edge(el.PNum(j), el.PNum(k)); edge.Sort(); - if (mesh.GetIdentifications().GetSymmetric (el.PNum(j), el.PNum(k))) + if (mesh.GetIdentifications().UsedSymmetric (el.PNum(j), el.PNum(k))) { int pi3 = 1, pi4 = 1; while (pi3 == j || pi3 == k) pi3++; @@ -145,7 +146,7 @@ namespace netgen { // pyramid, base face = 1,2,3,4 - for (j = 0; j <= 1; j++) + for (int j = 0; j <= 1; j++) { PointIndex pi1 = el.PNum( (j+0) % 4 + 1); PointIndex pi2 = el.PNum( (j+1) % 4 + 1); @@ -157,8 +158,8 @@ namespace netgen INDEX_2 edge2(pi2, pi3); edge1.Sort(); edge2.Sort(); - if (mesh.GetIdentifications().GetSymmetric (pi1, pi4) && - mesh.GetIdentifications().GetSymmetric (pi2, pi3)) + if (mesh.GetIdentifications().UsedSymmetric (pi1, pi4) && + mesh.GetIdentifications().UsedSymmetric (pi2, pi3)) { //int p3 = el.PNum(pi3); //int p4 = el.PNum(pi4); @@ -175,18 +176,18 @@ namespace netgen } } - for (i = 1; i <= mesh.GetNSE(); i++) + for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) { - Element2d & el = mesh.SurfaceElement(i); + Element2d & el = mesh.SurfaceElement(sei); if (el.GetType() != TRIG) continue; - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) { - k = (j % 3) + 1; + int k = (j % 3) + 1; INDEX_2 edge(el.PNum(j), el.PNum(k)); edge.Sort(); - if (mesh.GetIdentifications().GetSymmetric (el.PNum(j), el.PNum(k))) + if (mesh.GetIdentifications().UsedSymmetric (el.PNum(j), el.PNum(k))) { int pi3 = 6-j-k; int p3 = el.PNum(pi3); @@ -244,7 +245,7 @@ namespace netgen void RefinePrisms (Mesh & mesh, const CSGeometry * geom, ZRefinementOptions & opt) { - int i, j; + // int i, j; bool found, change; int cnt = 0; @@ -261,15 +262,23 @@ namespace netgen // if (mesh.GetIdentifications().HasIdentifiedPoints()) { - INDEX_2_HASHTABLE & identpts = + auto & identpts = mesh.GetIdentifications().GetIdentifiedPoints (); - - for (i = 1; i <= identpts.GetNBags(); i++) - for (j = 1; j <= identpts.GetBagSize(i); j++) + + /* + for (int i = 1; i <= identpts.GetNBags(); i++) + for (int j = 1; j <= identpts.GetBagSize(i); j++) { - INDEX_2 pair; - int idnr; - identpts.GetData(i, j, pair, idnr); + INDEX_3 pair; + int dummy; + identpts.GetData(i, j, pair, dummy); + */ + for (auto [hash, val] : identpts)\ + { + auto [hash_pts, idnr] = hash; + auto [pi1, pi2] = hash_pts; + // auto idnr = pair[2]; + const CloseSurfaceIdentification * csid = dynamic_cast (geom->identifications.Get(idnr)); @@ -280,17 +289,25 @@ namespace netgen if (first_id.Test (idnr)) { first_id.Clear(idnr); + /* ref_uniform.Append (INDEX_3 (pair.I1(), pair.I2(), csid->RefLevels())); ref_singular.Append (INDEX_3 (pair.I1(), pair.I2(), csid->RefLevels1())); ref_singular.Append (INDEX_3 (pair.I2(), pair.I1(), csid->RefLevels2())); + */ + ref_uniform.Append (INDEX_3 (pi1, pi2, csid->RefLevels())); + ref_singular.Append (INDEX_3 (pi1, pi2, csid->RefLevels1())); + ref_singular.Append (INDEX_3 (pi2, pi1, csid->RefLevels2())); + } } else { //const NgArray & slices = csid->GetSlices(); INDEX_4 i4; - i4[0] = pair.I1(); - i4[1] = pair.I2(); + // i4[0] = pair.I1(); + // i4[1] = pair.I2(); + i4[0] = pi1; + i4[1] = pi2; i4[2] = idnr; i4[3] = csid->GetSlices().Size(); ref_slices.Append (i4); @@ -313,7 +330,7 @@ namespace netgen found = 0; // mark prisms due to close surface flags: int oldsize = ref_uniform.Size(); - for (i = 1; i <= oldsize; i++) + for (int i = 1; i <= oldsize; i++) { int pi1 = ref_uniform.Get(i).I1(); int pi2 = ref_uniform.Get(i).I2(); @@ -339,7 +356,7 @@ namespace netgen ref_uniform.Append (INDEX_3(pi2, npi, levels-1)); } } - for (i = 1; i <= ref_singular.Size(); i++) + for (int i = 1; i <= ref_singular.Size(); i++) { int pi1 = ref_singular.Get(i).I1(); int pi2 = ref_singular.Get(i).I2(); @@ -367,7 +384,7 @@ namespace netgen } } - for (i = 1; i <= ref_slices.Size(); i++) + for (int i = 1; i <= ref_slices.Size(); i++) { int pi1 = ref_slices.Get(i)[0]; int pi2 = ref_slices.Get(i)[1]; @@ -413,13 +430,13 @@ namespace netgen - for (i = 1; i <= mesh.GetNE(); i++) + for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) { - Element & el = mesh.VolumeElement (i); + Element & el = mesh.VolumeElement (ei); if (el.GetType() != PRISM) continue; - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) { int pi1 = el.PNum(j); int pi2 = el.PNum(j+3); @@ -465,14 +482,14 @@ namespace netgen { PrintMessage (5, "start loop"); change = 0; - for (i = 1; i <= mesh.GetNE(); i++) + for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) { - Element & el = mesh.VolumeElement (i); + Element & el = mesh.VolumeElement (ei); if (el.GetType() != PRISM) continue; bool hasref = 0, hasnonref = 0; - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) { int pi1 = el.PNum(j); int pi2 = el.PNum(j+3); @@ -491,7 +508,7 @@ namespace netgen { // cout << "el " << i << " in closure" << endl; change = 1; - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) { int pi1 = el.PNum(j); int pi2 = el.PNum(j+3); @@ -518,7 +535,7 @@ namespace netgen int oldns = mesh.GetNSeg(); - for (i = 1; i <= oldns; i++) + for (int i = 1; i <= oldns; i++) { const Segment & el = mesh.LineSegment(i); @@ -572,14 +589,14 @@ namespace netgen // do refinement int oldne = mesh.GetNE(); - for (i = 1; i <= oldne; i++) + for (ElementIndex ei = 0; ei < oldne; ei++) { - Element & el = mesh.VolumeElement (i); + Element & el = mesh.VolumeElement (ei); if (el.GetNP() != 6) continue; int npi[3]; - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) { int pi1 = el.PNum(j); int pi2 = el.PNum(j+3); @@ -607,7 +624,7 @@ namespace netgen if (npi[0]) { Element nel1(6), nel2(6); - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) { nel1.PNum(j) = el.PNum(j); nel1.PNum(j+3) = npi[j-1]; @@ -616,7 +633,7 @@ namespace netgen } nel1.SetIndex (el.GetIndex()); nel2.SetIndex (el.GetIndex()); - mesh.VolumeElement (i) = nel1; + mesh.VolumeElement (ei) = nel1; mesh.AddVolumeElement (nel2); } } @@ -628,15 +645,15 @@ namespace netgen // do surface elements int oldnse = mesh.GetNSE(); // cout << "oldnse = " << oldnse << endl; - for (i = 1; i <= oldnse; i++) + for (SurfaceElementIndex sei = 0; sei < oldnse; sei++) { - Element2d & el = mesh.SurfaceElement (i); + Element2d & el = mesh.SurfaceElement (sei); if (el.GetType() != QUAD) continue; int index = el.GetIndex(); int npi[2]; - for (j = 1; j <= 2; j++) + for (int j = 1; j <= 2; j++) { int pi1, pi2; @@ -669,7 +686,7 @@ namespace netgen if (npi[0]) { Element2d nel1(QUAD), nel2(QUAD); - for (j = 1; j <= 4; j++) + for (int j = 1; j <= 4; j++) { nel1.PNum(j) = el.PNum(j); nel2.PNum(j) = el.PNum(j); @@ -690,7 +707,7 @@ namespace netgen nel1.SetIndex (el.GetIndex()); nel2.SetIndex (el.GetIndex()); - mesh.SurfaceElement (i) = nel1; + mesh.SurfaceElement (sei) = nel1; mesh.AddSurfaceElement (nel2); int si = mesh.GetFaceDescriptor (index).SurfNr(); @@ -716,9 +733,9 @@ namespace netgen void CombineSingularPrisms(Mesh& mesh) { - for(int i = 1; i<=mesh.GetNE(); i++) + for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++) { - Element& el = mesh.VolumeElement(i); + Element& el = mesh.VolumeElement(ei); if(el.GetType() != PRISM) continue; if(el.PNum(3) == el.PNum(6)) diff --git a/libsrc/general/CMakeLists.txt b/libsrc/general/CMakeLists.txt index eb97a1c0..2b0562a6 100644 --- a/libsrc/general/CMakeLists.txt +++ b/libsrc/general/CMakeLists.txt @@ -1,9 +1,7 @@ target_sources(nglib PRIVATE - dynamicmem.cpp gzstream.cpp hashtabl.cpp mystring.cpp - ngarray.cpp ngbitarray.cpp optmem.cpp parthreads.cpp @@ -13,12 +11,15 @@ target_sources(nglib PRIVATE table.cpp ) +# dynamicmem.cpp + install(FILES ngarray.hpp autodiff.hpp autoptr.hpp ngbitarray.hpp - dynamicmem.hpp hashtabl.hpp myadt.hpp + hashtabl.hpp myadt.hpp mystring.hpp netgenout.hpp ngpython.hpp optmem.hpp parthreads.hpp seti.hpp sort.hpp spbita2d.hpp stack.hpp table.hpp template.hpp gzstream.h DESTINATION ${NG_INSTALL_DIR_INCLUDE}/general COMPONENT netgen_devel ) +# dynamicmem.hpp diff --git a/libsrc/general/autodiff.hpp b/libsrc/general/autodiff.hpp index e2ba63d0..c7f0e269 100644 --- a/libsrc/general/autodiff.hpp +++ b/libsrc/general/autodiff.hpp @@ -9,6 +9,8 @@ // Automatic differentiation datatype +namespace netgen +{ /** Datatype for automatic differentiation. @@ -284,18 +286,6 @@ inline AutoDiff operator* (const AutoDiff & x, const AutoDiff -inline AutoDiff sqr (const AutoDiff & x) throw() -{ - AutoDiff res; - SCAL hx = x.Value(); - res.Value() = hx*hx; - hx *= 2; - for (int i = 0; i < D; i++) - res.DValue(i) = hx*x.DValue(i); - return res; -} /// Inverse of AutoDiff template @@ -329,14 +319,31 @@ inline AutoDiff operator/ (double x, const AutoDiff & y) return x * Inv(y); } +} // namespace netgen - - +namespace ngcore +{ +/// AutoDiff times AutoDiff template -inline AutoDiff fabs (const AutoDiff & x) +inline netgen::AutoDiff sqr (const netgen::AutoDiff & x) throw() +{ + netgen::AutoDiff res; + SCAL hx = x.Value(); + res.Value() = hx*hx; + hx *= 2; + for (int i = 0; i < D; i++) + res.DValue(i) = hx*x.DValue(i); + return res; +} +} // namespace ngcore + +namespace std +{ +template +inline netgen::AutoDiff fabs (const netgen::AutoDiff & x) { double abs = fabs (x.Value()); - AutoDiff res( abs ); + netgen::AutoDiff res( abs ); if (abs != 0.0) for (int i = 0; i < D; i++) res.DValue(i) = x.DValue(i) / abs; @@ -345,7 +352,5 @@ inline AutoDiff fabs (const AutoDiff & x) res.DValue(i) = 0.0; return res; } - -//@} - +} // namespace std #endif diff --git a/libsrc/general/dynamicmem.hpp b/libsrc/general/dynamicmem.hpp index 089a124d..612aae5b 100644 --- a/libsrc/general/dynamicmem.hpp +++ b/libsrc/general/dynamicmem.hpp @@ -1,3 +1,6 @@ +not needed anymore ? + + #ifndef FILE_DYNAMICMEM #define FILE_DYNAMICMEM diff --git a/libsrc/general/gzstream.cpp b/libsrc/general/gzstream.cpp index 49003377..968c07f9 100644 --- a/libsrc/general/gzstream.cpp +++ b/libsrc/general/gzstream.cpp @@ -44,7 +44,7 @@ namespace GZSTREAM_NAMESPACE { // class gzstreambuf: // -------------------------------------- -gzstreambuf* gzstreambuf::open( const filesystem::path & name, int open_mode) { + gzstreambuf* gzstreambuf::open( const std::filesystem::path & name, int open_mode) { if ( is_open()) return (gzstreambuf*)0; mode = open_mode; @@ -143,7 +143,7 @@ int gzstreambuf::sync() { // class gzstreambase: // -------------------------------------- -gzstreambase::gzstreambase( const filesystem::path & name, int mode) { + gzstreambase::gzstreambase( const std::filesystem::path & name, int mode) { init( &buf); open( name.c_str(), mode); } @@ -152,7 +152,7 @@ gzstreambase::~gzstreambase() { buf.close(); } -void gzstreambase::open( const filesystem::path & name, int open_mode) { + void gzstreambase::open( const std::filesystem::path & name, int open_mode) { if ( ! buf.open( name.c_str(), open_mode)) clear( rdstate() | std::ios::badbit); } diff --git a/libsrc/general/gzstream.h b/libsrc/general/gzstream.h index 7528b5f0..20a77795 100644 --- a/libsrc/general/gzstream.h +++ b/libsrc/general/gzstream.h @@ -62,7 +62,7 @@ public: // ASSERT: both input & output capabilities will not be used together } int is_open() { return opened; } - gzstreambuf* open( const filesystem::path & name, int open_mode); + gzstreambuf* open( const std::filesystem::path & name, int open_mode); gzstreambuf* close(); ~gzstreambuf() { close(); } @@ -76,9 +76,9 @@ protected: gzstreambuf buf; public: gzstreambase() { init(&buf); } - gzstreambase( const filesystem::path & name, int open_mode); + gzstreambase( const std::filesystem::path & name, int open_mode); ~gzstreambase(); - void open( const filesystem::path & name, int open_mode); + void open( const std::filesystem::path & name, int open_mode); void close(); gzstreambuf* rdbuf() { return &buf; } }; @@ -92,10 +92,10 @@ public: class DLL_HEADER igzstream : public gzstreambase, public std::istream { public: igzstream() : std::istream( &buf) {} - igzstream( const filesystem::path & name, int open_mode = std::ios::in) + igzstream( const std::filesystem::path & name, int open_mode = std::ios::in) : gzstreambase( name, open_mode), std::istream( &buf) {} gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); } - void open( const filesystem::path & name, int open_mode = std::ios::in) { + void open( const std::filesystem::path & name, int open_mode = std::ios::in) { gzstreambase::open( name, open_mode); } }; @@ -103,10 +103,10 @@ public: class DLL_HEADER ogzstream : public gzstreambase, public std::ostream { public: ogzstream() : std::ostream( &buf) {} - ogzstream( const filesystem::path & name, int mode = std::ios::out) + ogzstream( const std::filesystem::path & name, int mode = std::ios::out) : gzstreambase( name, mode), std::ostream( &buf) {} gzstreambuf* rdbuf() { return gzstreambase::rdbuf(); } - void open( const filesystem::path & name, int open_mode = std::ios::out) { + void open( const std::filesystem::path & name, int open_mode = std::ios::out) { gzstreambase::open( name, open_mode); } }; diff --git a/libsrc/general/hashtabl.cpp b/libsrc/general/hashtabl.cpp index 30f6ed1f..c0be3c1c 100644 --- a/libsrc/general/hashtabl.cpp +++ b/libsrc/general/hashtabl.cpp @@ -292,7 +292,19 @@ namespace netgen - + BASE_INDEX_3_CLOSED_HASHTABLE :: + BASE_INDEX_3_CLOSED_HASHTABLE (size_t size) + : hash(RoundUp2(size)) + { + // cout << "orig size = " << size + // << ", roundup size = " << hash.Size(); + size = hash.Size(); + mask = size-1; + // cout << "mask = " << mask << endl; + invalid = -1; + for (size_t i = 0; i < size; i++) + hash[i].I1() = invalid; + } void BASE_INDEX_3_CLOSED_HASHTABLE :: diff --git a/libsrc/general/hashtabl.hpp b/libsrc/general/hashtabl.hpp index 34c3f641..07c0c7b2 100644 --- a/libsrc/general/hashtabl.hpp +++ b/libsrc/general/hashtabl.hpp @@ -7,6 +7,8 @@ /* Date: 01. Jun. 95 */ /**************************************************************************/ +#include "table.hpp" + namespace netgen { @@ -412,9 +414,14 @@ public: int BagNr() const { return bagnr; } int Pos() const { return pos; } - void operator++ (int) + Iterator operator++ (int) + { + Iterator it(ht, bagnr, pos); + ++(*this); + return it; + } + Iterator& operator++() { - // cout << "begin Operator ++: bagnr = " << bagnr << " - pos = " << pos << endl; pos++; while (bagnr < ht.GetNBags() && pos == ht.GetBagSize(bagnr+1)) @@ -422,7 +429,12 @@ public: pos = 0; bagnr++; } - // cout << "end Operator ++: bagnr = " << bagnr << " - pos = " << pos << endl; + return *this; + } + + std::pair operator*() + { + return std::make_pair(ht.hash[bagnr][pos], ht.cont[bagnr][pos]); } bool operator != (int i) const @@ -444,6 +456,18 @@ public: return GetNBags(); } + Iterator begin () const + { + Iterator it(*this, 0, -1); + it++; + return it; + } + + int end() const + { + return GetNBags(); + } + void GetData (const Iterator & it, INDEX_3 & ahash, T & acont) const { @@ -837,9 +861,10 @@ inline ostream & operator<< (ostream & ost, const INDEX_2_CLOSED_HASHTABLE & for (int i = 0; i < ht.Size(); i++) if (ht.UsedPos(i)) { - INDEX_2 hash; - T data; - ht.GetData0 (i, hash, data); + // INDEX_2 hash; + // T data; + // ht.GetData0 (i, hash, data); + auto [hash,data] = ht.GetBoth(i); ost << "hash = " << hash << ", data = " << data << endl; } return ost; @@ -856,7 +881,8 @@ protected: size_t mask; protected: - BASE_INDEX_3_CLOSED_HASHTABLE (size_t size) + BASE_INDEX_3_CLOSED_HASHTABLE (size_t size); + /* : hash(RoundUp2(size)) { // cout << "orig size = " << size @@ -868,6 +894,7 @@ protected: for (size_t i = 0; i < size; i++) hash[i].I1() = invalid; } + */ public: int Size() const @@ -1049,9 +1076,12 @@ inline ostream & operator<< (ostream & ost, const INDEX_3_CLOSED_HASHTABLE & for (int i = 0; i < ht.Size(); i++) if (ht.UsedPos(i)) { + /* INDEX_3 hash; T data; - ht.GetData (i, hash, data); + ht.GetData (i, hash, data); + */ + auto [hash, data] = ht.GetBoth(); ost << "hash = " << hash << ", data = " << data << endl; } return ost; @@ -1410,7 +1440,7 @@ inline size_t HashValue (INDEX_3 i3, size_t size) { return (i3[0]+15*size_t(i3[1 The array should be allocated with the double size of the expected number of entries. */ template - class ClosedHashTable + class NgClosedHashTable { protected: /// @@ -1423,16 +1453,16 @@ inline size_t HashValue (INDEX_3 i3, size_t size) { return (i3[0]+15*size_t(i3[1 NgArray cont; public: /// - ClosedHashTable (size_t asize = 128) + NgClosedHashTable (size_t asize = 128) : size(asize), used(0), hash(asize), cont(asize) { for (auto & v : hash) SetInvalid(v); } - ClosedHashTable (ClosedHashTable && ht2) = default; + NgClosedHashTable (NgClosedHashTable && ht2) = default; - ClosedHashTable (NgFlatArray _hash, NgFlatArray _cont) + NgClosedHashTable (NgFlatArray _hash, NgFlatArray _cont) : size(_hash.Size()), used(0), hash(_hash.Size(), _hash.Addr(0)), cont(_cont.Size(), _cont.Addr(0)) { for (auto & v : hash) @@ -1440,7 +1470,7 @@ inline size_t HashValue (INDEX_3 i3, size_t size) { return (i3[0]+15*size_t(i3[1 } - ClosedHashTable & operator= (ClosedHashTable && ht2) = default; + NgClosedHashTable & operator= (NgClosedHashTable && ht2) = default; /// size_t Size() const @@ -1474,7 +1504,7 @@ inline size_t HashValue (INDEX_3 i3, size_t size) { return (i3[0]+15*size_t(i3[1 void DoubleSize() { - ClosedHashTable tmp(2*Size()); + NgClosedHashTable tmp(2*Size()); for (auto both : *this) tmp[both.first] = both.second; *this = std::move(tmp); @@ -1609,10 +1639,10 @@ inline size_t HashValue (INDEX_3 i3, size_t size) { return (i3[0]+15*size_t(i3[1 class Iterator { - const ClosedHashTable & tab; + const NgClosedHashTable & tab; size_t nr; public: - Iterator (const ClosedHashTable & _tab, size_t _nr) + Iterator (const NgClosedHashTable & _tab, size_t _nr) : tab(_tab), nr(_nr) { while (nr < tab.Size() && !tab.UsedPos(nr)) nr++; @@ -1639,7 +1669,7 @@ inline size_t HashValue (INDEX_3 i3, size_t size) { return (i3[0]+15*size_t(i3[1 template ostream & operator<< (ostream & ost, - const ClosedHashTable & tab) + const NgClosedHashTable & tab) { for (size_t i = 0; i < tab.Size(); i++) if (tab.UsedPos(i)) diff --git a/libsrc/general/mpi_interface.cpp b/libsrc/general/mpi_interface.cpp deleted file mode 100644 index 8fd6fb96..00000000 --- a/libsrc/general/mpi_interface.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/**************************************************************************/ -/* File: mpi_interface.cpp */ -/* Author: Joachim Schoeberl */ -/* Date: 04. Apr. 97 */ -/**************************************************************************/ - -#ifdef OLD -#include -#include - - -namespace netgen -{ - - -#ifdef PARALLEL - - void MyMPI_SendCmd (const char * cmd) - { - int ntasks; - MPI_Comm_size(MPI_COMM_WORLD, &ntasks); - - if(ntasks==1) - return; - - for (int dest = 1; dest < ntasks; dest++) - MPI_Send( (void*)cmd, (strlen(cmd)+1), MPI_CHAR, dest, MPI_TAG_CMD, MPI_COMM_WORLD); - } - - string MyMPI_RecvCmd () - { - MPI_Status status; - int flag; - int size_of_msg = -1; - - MPI_Probe(0, MPI_TAG_CMD, MPI_COMM_WORLD, &status); - MPI_Get_count(&status, MPI_CHAR, &size_of_msg); - - //char* buf = (char*)malloc(size_of_msg*sizeof(char)); - char buf[100000]; //1MB should be enough... - - MPI_Recv( &buf, size_of_msg, MPI_CHAR, 0, MPI_TAG_CMD, MPI_COMM_WORLD, &status); - - return string(buf); - } - - // #else - // MPI_Comm MPI_COMM_WORLD, MPI_COMM_NULL; -#endif -} - - - -#endif diff --git a/libsrc/general/mpi_interface.hpp b/libsrc/general/mpi_interface.hpp deleted file mode 100644 index edc9c5f1..00000000 --- a/libsrc/general/mpi_interface.hpp +++ /dev/null @@ -1,336 +0,0 @@ -braucht keiner mehr - - -#ifdef XXXXXX - -#ifndef FILE_PARALLEL -#define FILE_PARALLEL - - -#ifdef VTRACE -#include "vt_user.h" -#else - #define VT_USER_START(n) - #define VT_USER_END(n) - #define VT_TRACER(n) -#endif - - -namespace netgen -{ - -#ifdef OLD -#ifdef PARALLEL - template - inline MPI_Datatype MyGetMPIType ( ) - { cerr << "ERROR in GetMPIType() -- no type found" << endl;return 0; } - template <> - inline MPI_Datatype MyGetMPIType ( ) - { return MPI_INT; } - template <> - inline MPI_Datatype MyGetMPIType ( ) - { return MPI_DOUBLE; } - template <> - inline MPI_Datatype MyGetMPIType ( ) - { return MPI_CHAR; } - template<> - inline MPI_Datatype MyGetMPIType ( ) - { return MPI_UINT64_T; } -#else - typedef int MPI_Datatype; - template inline MPI_Datatype MyGetMPIType ( ) { return 0; } -#endif -#endif - - - enum { MPI_TAG_CMD = 110 }; - enum { MPI_TAG_MESH = 210 }; - enum { MPI_TAG_VIS = 310 }; - -#ifdef PARALLEL - - [[deprecated("mympi_send int, use comm.Send instead")]] - inline void MyMPI_Send (int i, int dest, int tag, MPI_Comm comm) - { - int hi = i; - MPI_Send( &hi, 1, MPI_INT, dest, tag, comm); - } - - [[deprecated("mympi_revc int, use comm.Recv instead")]] - inline void MyMPI_Recv (int & i, int src, int tag, MPI_Comm comm) - { - MPI_Status status; - MPI_Recv( &i, 1, MPI_INT, src, tag, comm, &status); - } - - [[deprecated("mympi_send string, use comm.Send instead")]] - inline void MyMPI_Send (const string & s, int dest, int tag, MPI_Comm comm) - { - MPI_Send( const_cast (s.c_str()), s.length(), MPI_CHAR, dest, tag, comm); - } - - [[deprecated("mympi_revc string, use comm.Recv instead")]] - inline void MyMPI_Recv (string & s, int src, int tag, MPI_Comm comm) - { - MPI_Status status; - int len; - MPI_Probe (src, tag, MPI_COMM_WORLD, &status); - MPI_Get_count (&status, MPI_CHAR, &len); - s.assign (len, ' '); - MPI_Recv( &s[0], len, MPI_CHAR, src, tag, comm, &status); - } - - - - template - [[deprecated("mympi_send ngflatarray, use comm.send instead")]] - inline void MyMPI_Send (NgFlatArray s, int dest, int tag, MPI_Comm comm) - { - MPI_Send( &s.First(), s.Size(), GetMPIType(), dest, tag, comm); - } - - template - [[deprecated("mympi_recv ngflatarray, use comm.Recv instead")]] - inline void MyMPI_Recv ( NgFlatArray s, int src, int tag, MPI_Comm comm) - { - MPI_Status status; - MPI_Recv( &s.First(), s.Size(), GetMPIType(), src, tag, comm, &status); - } - - template - [[deprecated("use ngcore - Array instead")]] - inline void MyMPI_Recv ( NgArray & s, int src, int tag, MPI_Comm comm) - { - MPI_Status status; - int len; - MPI_Probe (src, tag, comm, &status); - MPI_Get_count (&status, GetMPIType(), &len); - - s.SetSize (len); - MPI_Recv( &s.First(), len, GetMPIType(), src, tag, comm, &status); - } - - template - [[deprecated("use ngcore - Array instead")]] - inline int MyMPI_Recv ( NgArray & s, int tag, MPI_Comm comm) - { - MPI_Status status; - int len; - MPI_Probe (MPI_ANY_SOURCE, tag, comm, &status); - - int src = status.MPI_SOURCE; - - MPI_Get_count (&status, GetMPIType(), &len); - - s.SetSize (len); - MPI_Recv( &s.First(), len, GetMPIType(), src, tag, comm, &status); - - return src; - } - - - /* - template - inline void MyMPI_ISend (NgFlatArray s, int dest, int tag, MPI_Request & request) - { - MPI_Isend( &s.First(), s.Size(), MyGetMPIType(), dest, tag, MPI_COMM_WORLD, & request); - } - - - template - inline void MyMPI_IRecv (NgFlatArray s, int dest, int tag, MPI_Request & request) - { - MPI_Irecv( &s.First(), s.Size(), MyGetMPIType(), dest, tag, MPI_COMM_WORLD, & request); - } - */ - - template - [[deprecated("mympi_isend ngflatarray, use comm.send instead")]] - [[deprecated("use ngcore - Array instead")]] - inline MPI_Request MyMPI_ISend (NgFlatArray s, int dest, int tag, MPI_Comm comm) - { - MPI_Request request; - MPI_Isend( &s.First(), s.Size(), GetMPIType(), dest, tag, comm, &request); - return request; - } - - template - [[deprecated("mympi_irecv ngflatarray, use comm.recv instead")]] - inline MPI_Request MyMPI_IRecv (NgFlatArray s, int dest, int tag, MPI_Comm comm) - { - MPI_Request request; - MPI_Irecv( &s.First(), s.Size(), GetMPIType(), dest, tag, comm, &request); - return request; - } - - /* - template - inline void MyMPI_ISend (NgFlatArray s, int dest, int tag) - { - MPI_Request request; - MPI_Isend( &s.First(), s.Size(), MyGetMPIType(), dest, tag, MPI_COMM_WORLD, &request); - MPI_Request_free (&request); - } - - - template - inline void MyMPI_IRecv (NgFlatArray s, int dest, int tag) - { - MPI_Request request; - MPI_Irecv( &s.First(), s.Size(), MyGetMPIType(), dest, tag, MPI_COMM_WORLD, &request); - MPI_Request_free (&request); - } - */ - - - - /* - send a table entry to each of the processes in the group ... - receive-table entries will be set - */ - - template - [[deprecated("do we need that ? ")]] - inline void MyMPI_ExchangeTable (TABLE & send_data, - TABLE & recv_data, int tag, - const NgMPI_Comm & comm) - { - int rank = comm.Rank(); - int ntasks = comm.Size(); - - Array send_sizes(ntasks); - Array recv_sizes(ntasks); - for (int i = 0; i < ntasks; i++) - send_sizes[i] = send_data[i].Size(); - - comm.AllToAll (send_sizes, recv_sizes); - - for (int i = 0; i < ntasks; i++) - recv_data.SetEntrySize (i, recv_sizes[i], sizeof(T)); - - Array requests; - for (int dest = 0; dest < ntasks; dest++) - if (dest != rank && send_data[dest].Size()) - requests.Append (comm.ISend (FlatArray(send_data[dest]), dest, tag)); - - for (int dest = 0; dest < ntasks; dest++) - if (dest != rank && recv_data[dest].Size()) - requests.Append (comm.IRecv (FlatArray(recv_data[dest]), dest, tag)); - - MyMPI_WaitAll (requests); - } - - - template - [[deprecated("do we need that ? ")]] - inline void MyMPI_ExchangeTable (DynamicTable & send_data, - DynamicTable & recv_data, int tag, - const NgMPI_Comm & comm) - { - int rank = comm.Rank(); - int ntasks = comm.Size(); - - Array send_sizes(ntasks); - Array recv_sizes(ntasks); - for (int i = 0; i < ntasks; i++) - send_sizes[i] = send_data[i].Size(); - - comm.AllToAll (send_sizes, recv_sizes); - - // for (int i = 0; i < ntasks; i++) - // recv_data.SetEntrySize (i, recv_sizes[i], sizeof(T)); - recv_data = DynamicTable (recv_sizes, true); - - Array requests; - for (int dest = 0; dest < ntasks; dest++) - if (dest != rank && send_data[dest].Size()) - requests.Append (comm.ISend (FlatArray(send_data[dest]), dest, tag)); - - for (int dest = 0; dest < ntasks; dest++) - if (dest != rank && recv_data[dest].Size()) - requests.Append (comm.IRecv (FlatArray(recv_data[dest]), dest, tag)); - - MyMPI_WaitAll (requests); - } - - - - - [[deprecated("do we still send commands?")]] - DLL_HEADER void MyMPI_SendCmd (const char * cmd); - [[deprecated("do we still send commands?")]] - extern string MyMPI_RecvCmd (); - - - template - [[deprecated("use comm.BCast instead")]] - inline void MyMPI_Bcast (T & s, MPI_Comm comm) - { - MPI_Bcast (&s, 1, GetMPIType(), 0, comm); - } - - template - [[deprecated("use comm.BCast instead")]] - inline void MyMPI_Bcast (NgArray & s, NgMPI_Comm comm) - { - int size = s.Size(); - // MyMPI_Bcast (size, comm); - comm.Bcast(size); - // if (MyMPI_GetId(comm) != 0) s.SetSize (size); - if (comm.Rank() != 0) s.SetSize (size); - MPI_Bcast (&s[0], size, GetMPIType(), 0, comm); - } - - template - [[deprecated("use comm.BCast instead")]] - inline void MyMPI_Bcast (NgArray & s, int root, MPI_Comm comm) - { - int id; - MPI_Comm_rank(comm, &id); - - int size = s.Size(); - MPI_Bcast (&size, 1, MPI_INT, root, comm); - if (id != root) s.SetSize (size); - if ( !size ) return; - MPI_Bcast (&s[0], size, GetMPIType(), root, comm); - } - - template - [[deprecated("mympi_allgather deprecated, use comm.allgather")]] - inline void MyMPI_Allgather (const T & send, NgFlatArray recv, MPI_Comm comm) - { - MPI_Allgather( const_cast (&send), 1, GetMPIType(), &recv[0], 1, GetMPIType(), comm); - } - - template - [[deprecated("mympi_alltoall deprecated, use comm.alltoall")]] - inline void MyMPI_Alltoall (NgFlatArray send, NgFlatArray recv, MPI_Comm comm) - { - MPI_Alltoall( &send[0], 1, GetMPIType(), &recv[0], 1, GetMPIType(), comm); - } - - -#else - template - [[deprecated("do we need that ? ")]] - inline void MyMPI_ExchangeTable (TABLE & send_data, - TABLE & recv_data, int tag, - const NgMPI_Comm & comm) - { - ; - } - - template - [[deprecated("do we need that ? ")]] - inline void MyMPI_ExchangeTable (DynamicTable & send_data, - DynamicTable & recv_data, int tag, - const NgMPI_Comm & comm) - { ; } -#endif // PARALLEL - -} - -#endif - - -#endif diff --git a/libsrc/general/myadt.hpp b/libsrc/general/myadt.hpp index 871de4f1..1c26d02b 100644 --- a/libsrc/general/myadt.hpp +++ b/libsrc/general/myadt.hpp @@ -12,7 +12,6 @@ */ - #include "../include/mystdlib.h" #include "../include/mydefs.hpp" @@ -25,7 +24,7 @@ namespace netgen } #include "parthreads.hpp" // #include "moveablemem.hpp" -#include "dynamicmem.hpp" +// #include "dynamicmem.hpp" #include "template.hpp" #include "ngarray.hpp" @@ -46,5 +45,4 @@ namespace netgen // #include "mpi_interface.hpp" #include "netgenout.hpp" - #endif diff --git a/libsrc/general/mystring.cpp b/libsrc/general/mystring.cpp index 7d7dcd01..c88cfab3 100644 --- a/libsrc/general/mystring.cpp +++ b/libsrc/general/mystring.cpp @@ -155,7 +155,7 @@ MyStr::MyStr(long l) MyStr::MyStr(size_t l) { char buffer[32]; - snprintf(buffer, 32, "%ld", l); + snprintf(buffer, 32, "%zu", l); length = unsigned(strlen(buffer)); if (length > SHORTLEN) str = new char[length + 1]; @@ -223,6 +223,16 @@ MyStr::MyStr(const string & st) strcpy (str, st.c_str()); } +MyStr::MyStr(string_view sv) +{ + length = unsigned(sv.length()); + if (length > SHORTLEN) + str = new char[length + 1]; + else + str = shortstr; + strcpy (str, sv.data()); +} + MyStr::MyStr(const filesystem::path & path) : MyStr(path.string()) { } diff --git a/libsrc/general/mystring.hpp b/libsrc/general/mystring.hpp index ee364d77..4f2167ec 100644 --- a/libsrc/general/mystring.hpp +++ b/libsrc/general/mystring.hpp @@ -60,6 +60,7 @@ public: MyStr(const Point3d& p); MyStr(const Vec3d& p); MyStr(const string & st); + MyStr(string_view sv); MyStr(const filesystem::path & st); ~MyStr(); diff --git a/libsrc/general/ngarray.cpp b/libsrc/general/ngarray.cpp deleted file mode 100644 index 37a8e118..00000000 --- a/libsrc/general/ngarray.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef FILE_NGSTD_NgArrayCPP -#define FILE_NGSTD_NgArrayCPP -// necessary for SGI ???? - -/**************************************************************************/ -/* File: array.cpp */ -/* Author: Joachim Schoeberl */ -/* Date: 01. Jun. 95 */ -/**************************************************************************/ - -/* - Abstract data type NgArray -*/ - -#include -#include -#include - - -namespace netgen -{ - //using namespace netgen; - -#ifdef NONE - void BASE_Array :: ReSize (int minsize, int elementsize) - { - cout << "resize, minsize = " << minsize << endl; - - if (inc == -1) - throw Exception ("Try to resize fixed size array"); - - - void * p; - int nsize = (inc) ? allocsize + inc : 2 * allocsize; - if (nsize < minsize) nsize = minsize; - - if (data) - { - p = new char [nsize * elementsize]; - - int mins = (nsize < actsize) ? nsize : actsize; - memcpy (p, data, mins * elementsize); - - delete [] static_cast (data); - data = p; - } - else - { - data = new char[nsize * elementsize]; - } - - allocsize = nsize; - cout << "resize done" << endl; - } - - - - void BASE_Array :: RangeCheck (int i) const - { - if (i < 0 || i >= actsize) - throw ArrayRangeException (); - } - - void BASE_Array :: CheckNonEmpty () const - { - if (!actsize) - { - throw Exception ("NgArray should not be empty"); - // cerr << "NgArray shouldn't be empty"; - } - } -#endif -} -#endif // FILE_NGSTD_NgArrayCPP - diff --git a/libsrc/general/ngarray.hpp b/libsrc/general/ngarray.hpp index 6e244ec8..ca5bbdd7 100644 --- a/libsrc/general/ngarray.hpp +++ b/libsrc/general/ngarray.hpp @@ -7,12 +7,14 @@ /* Date: 01. Jun. 95 */ /**************************************************************************/ +#include namespace netgen { + using namespace ngcore; // template class IndirectArray; - template class IndirectArray; + template class NgIndirectArray; @@ -110,18 +112,14 @@ namespace netgen /// Access array. BASE-based T & operator[] (TIND i) const { -#ifdef DEBUG - if (i-BASE < 0 || i-BASE >= size) - cout << "array<" << typeid(T).name() << "> out of range, i = " << i << ", s = " << size << endl; -#endif - + NETGEN_CHECK_RANGE(i,BASE,size+BASE); return data[i-BASE]; } template - IndirectArray > operator[] (const NgFlatArray & ia) const + NgIndirectArray > operator[] (const NgFlatArray & ia) const { - return IndirectArray > (*this, ia); + return NgIndirectArray > (*this, ia); } @@ -129,13 +127,7 @@ namespace netgen /// Access array, one-based (old fashioned) T & Elem (int i) { -#ifdef DEBUG - if (i < 1 || i > size) - cout << "NgArray<" << typeid(T).name() - << ">::Elem out of range, i = " << i - << ", s = " << size << endl; -#endif - + NETGEN_CHECK_RANGE(i,1,size+1); return ((T*)data)[i-1]; } @@ -143,30 +135,21 @@ namespace netgen // [[deprecated("Use operator[] instead")]] const T & Get (int i) const { -#ifdef DEBUG - if (i < 1 || i > size) - cout << "NgArray<" << typeid(T).name() << ">::Get out of range, i = " << i - << ", s = " << size << endl; -#endif - + NETGEN_CHECK_RANGE(i,1,size+1); return ((const T*)data)[i-1]; } /// Access array, one-based (old fashioned) void Set (int i, const T & el) { -#ifdef DEBUG - if (i < 1 || i > size) - cout << "NgArray<" << typeid(T).name() << ">::Set out of range, i = " << i - << ", s = " << size << endl; -#endif - + NETGEN_CHECK_RANGE(i,1,size+1); ((T*)data)[i-1] = el; } /// access first element T & First () const { + NETGEN_CHECK_RANGE(0,0,size); return data[0]; } @@ -174,6 +157,7 @@ namespace netgen /// access last element. check by macro CHECK_RANGE T & Last () const { + NETGEN_CHECK_RANGE(size-1,0,size); return data[size-1]; } @@ -206,10 +190,10 @@ namespace netgen return ( Pos(elem) >= 0 ); } - operator FlatArray () const + operator ngcore::FlatArray () const { static_assert (BASE==0); - return FlatArray(size, data); + return ngcore::FlatArray(size, data); } }; @@ -344,10 +328,7 @@ namespace netgen /// Delete element i (0-based). Move last element to position i. void Delete (TIND i) { -#ifdef CHECK_Array_RANGE - RangeCheck (i+1); -#endif - + NETGEN_CHECK_RANGE(i,0,size); data[i] = std::move(data[size-1]); size--; // DeleteElement (i+1); @@ -357,10 +338,7 @@ namespace netgen /// Delete element i (1-based). Move last element to position i. void DeleteElement (TIND i) { -#ifdef CHECK_Array_RANGE - RangeCheck (i); -#endif - + NETGEN_CHECK_RANGE(i,1,size+1); data[i-1] = std::move(data[size-1]); size--; } @@ -421,8 +399,9 @@ namespace netgen } // Only provide this function if T is archivable - template - auto DoArchive(Archive& archive) -> typename std::enable_if, void>::type + template + auto DoArchive(ARCHIVE& archive) + -> typename std::enable_if_t, void> { if(archive.Output()) archive << size; @@ -531,13 +510,13 @@ namespace netgen */ template - class IndirectArray + class NgIndirectArray { const TA1 & array; const TA2 & ia; public: - IndirectArray (const TA1 & aa, const TA2 & aia) + NgIndirectArray (const TA1 & aa, const TA2 & aia) : array(aa), ia(aia) { ; } int Size() const { return ia.Size(); } [[deprecated("Use *Range().begin() instead")]] @@ -553,7 +532,7 @@ namespace netgen template - inline ostream & operator<< (ostream & s, const IndirectArray & ia) + inline ostream & operator<< (ostream & s, const NgIndirectArray & ia) { for (int i = ia.Begin(); i < ia.End(); i++) s << i << ": " << ia[i] << endl; diff --git a/libsrc/general/ngbitarray.hpp b/libsrc/general/ngbitarray.hpp index 637d1814..15295593 100644 --- a/libsrc/general/ngbitarray.hpp +++ b/libsrc/general/ngbitarray.hpp @@ -12,7 +12,6 @@ namespace netgen { - /** data type NgBitArray @@ -29,8 +28,11 @@ class NgBitArray unsigned char * data; public: + + // [[ deprecated ("use BitArray instead")]] DLL_HEADER NgBitArray (); /// + // [[ deprecated ("use BitArray instead")]] DLL_HEADER NgBitArray (INDEX asize); /// DLL_HEADER ~NgBitArray (); diff --git a/libsrc/general/ngpython.hpp b/libsrc/general/ngpython.hpp index ef02d19f..d455f2df 100644 --- a/libsrc/general/ngpython.hpp +++ b/libsrc/general/ngpython.hpp @@ -8,7 +8,7 @@ #include #include -using namespace ngcore; +// using namespace ngcore; template py::array MoveToNumpy(std::vector& vec) diff --git a/libsrc/general/optmem.hpp b/libsrc/general/optmem.hpp index b2be31d3..f566ca14 100644 --- a/libsrc/general/optmem.hpp +++ b/libsrc/general/optmem.hpp @@ -7,6 +7,10 @@ /* Date: 04. Apr. 97 */ /**************************************************************************/ +#include + +#include "ngarray.hpp" + namespace netgen { diff --git a/libsrc/general/parthreads.hpp b/libsrc/general/parthreads.hpp index d7f42a4a..52b3208d 100644 --- a/libsrc/general/parthreads.hpp +++ b/libsrc/general/parthreads.hpp @@ -77,8 +77,8 @@ public: template void ParallelFor( int first, int next, const TFunc & f ) { - int nthreads = thread::hardware_concurrency(); - thread * threads = new thread[nthreads]; + int nthreads = std::thread::hardware_concurrency(); + std::thread * threads = new std::thread[nthreads]; for (int i=0; i); - typedef void (*NgTracer)(string, bool); // false .. start, true .. stop + typedef void (*NgTracer)(std::string, bool); // false .. start, true .. stop inline void DummyTaskManager (std::function func) { @@ -105,7 +105,7 @@ void ParallelFor( int first, int next, const TFunc & f ) func(1,2); } - inline void DummyTracer (string, bool) { ; } + inline void DummyTracer (std::string, bool) { ; } template inline void ParallelFor (NgTaskManager tm, size_t n, FUNC func) diff --git a/libsrc/general/table.cpp b/libsrc/general/table.cpp index 732d63c3..dad727ac 100644 --- a/libsrc/general/table.cpp +++ b/libsrc/general/table.cpp @@ -108,8 +108,9 @@ namespace netgen if (line.size == line.maxsize) { void * p = new char [(line.maxsize+5) * elsize]; - - memcpy (p, line.col, line.maxsize * elsize); + + if (line.maxsize && elsize) + memcpy (p, line.col, line.maxsize * elsize); delete [] (char*)line.col; line.col = p; diff --git a/libsrc/general/table.hpp b/libsrc/general/table.hpp index a62277fa..3c25c2b0 100644 --- a/libsrc/general/table.hpp +++ b/libsrc/general/table.hpp @@ -120,7 +120,7 @@ public: /// Creates fixed maximal element size table inline TABLE (const NgFlatArray & entrysizes) - : BASE_TABLE (NgFlatArray (entrysizes.Size(), const_cast(&entrysizes[BASE])), + : BASE_TABLE (NgFlatArray (entrysizes.Size(), entrysizes.Size() ? const_cast(&entrysizes[BASE]) : nullptr), sizeof(T)) { ; } @@ -169,6 +169,7 @@ public: /// Inserts element acont into row i. BASE-based. Does not test if already used, assumes to have enough memory inline void AddSave (int i, const T & acont) { + NETGEN_CHECK_RANGE(i, BASE, data.Size()+BASE); ((T*)data[i-BASE].col)[data[i-BASE].size] = acont; data[i-BASE].size++; } diff --git a/libsrc/general/template.hpp b/libsrc/general/template.hpp index 61166f54..a3b9457d 100644 --- a/libsrc/general/template.hpp +++ b/libsrc/general/template.hpp @@ -7,14 +7,16 @@ /* Date: 01. Jun. 95 */ /**************************************************************************/ +#include + namespace netgen { - + using namespace ngcore; /* templates, global types, defines and variables */ -DLL_HEADER extern const string netgen_version; + DLL_HEADER extern const std::string netgen_version; /// The following value may be adapted to the hardware ! #ifndef CLOCKS_PER_SEC @@ -112,14 +114,24 @@ class INDEX_2 public: /// + // protected: INDEX_2 () { } + INDEX_2 (const INDEX_2&) = default; +public: + INDEX_2 (INDEX_2&&) = default; + + INDEX_2 & operator= (const INDEX_2&) = default; + INDEX_2 & operator= (INDEX_2&&) = default; /// - INDEX_2 (INDEX ai1, INDEX ai2) - { i[0] = ai1; i[1] = ai2; } + constexpr INDEX_2 (INDEX ai1, INDEX ai2) + : i{ai1, ai2} { } + // { i[0] = ai1; i[1] = ai2; } /// - INDEX_2 (const INDEX_2 & in2) - { i[0] = in2.i[0]; i[1] = in2.i[1]; } + // constexpr INDEX_2 (const INDEX_2 & in2) + // : i{in2.i[0], in2.i[1]} { } + + // { i[0] = in2.i[0]; i[1] = in2.i[1]; } /// int operator== (const INDEX_2 & in2) const @@ -128,7 +140,7 @@ public: /// - INDEX_2 Sort () + constexpr INDEX_2 Sort () { if (i[0] > i[1]) { @@ -147,7 +159,7 @@ public: return INDEX_2 (i1,i2); } - + operator std::array() { return { i[0], i[1] }; } /// INDEX & I1 () { return i[0]; } /// @@ -163,7 +175,7 @@ public: /// int & operator[] (int j) { return i[j]; } /// - const int & operator[] (int j) const { return i[j]; } + constexpr const int & operator[] (int j) const { return i[j]; } /// friend ostream & operator<<(ostream & s, const INDEX_2 & i2); }; @@ -201,13 +213,12 @@ public: /// INDEX_3 () { } /// - INDEX_3 (INDEX ai1, INDEX ai2, INDEX ai3) - { i[0] = ai1; i[1] = ai2; i[2] = ai3; } - - /// - INDEX_3 (const INDEX_3 & in2) - { i[0] = in2.i[0]; i[1] = in2.i[1]; i[2] = in2.i[2]; } + constexpr INDEX_3 (INDEX ai1, INDEX ai2, INDEX ai3) + : i{ai1, ai2, ai3} { } + /// + constexpr INDEX_3 (const INDEX_3 & in2) + : i{in2.i[0], in2.i[1], in2.i[2]} { } static INDEX_3 Sort (INDEX_3 i3) { @@ -462,4 +473,37 @@ void MergeSort (int size, T * data, T * help); } +namespace ngcore +{ + // template <> + // constexpr inline netgen::INDEX_2 InvalidHash () { return netgen::INDEX_2{-1,-1}; } + + + template <> + struct CHT_trait + { + constexpr static inline netgen::INDEX_2 Invalid() { return { -1, -1 } ; } + constexpr static inline size_t HashValue (const netgen::INDEX_2 & hash, size_t mask) + { return HashValue2(IVec<2,netgen::INDEX>(hash[0], hash[1]), mask); } + }; + + +} + +namespace netgen +{ + /* + inline size_t HashValue2 (const netgen::INDEX_2 & ind, size_t mask) + { + return HashValue2(IVec<2,netgen::INDEX>(ind[0], ind[1]), mask); + } + */ + + inline size_t HashValue2 (const netgen::INDEX_3 & ind, size_t mask) + { + return HashValue2(IVec<3,netgen::INDEX>(ind[0], ind[1], ind[2]), mask); + } + + +} #endif diff --git a/libsrc/geom2d/csg2d.cpp b/libsrc/geom2d/csg2d.cpp index fdefb59c..667c7514 100644 --- a/libsrc/geom2d/csg2d.cpp +++ b/libsrc/geom2d/csg2d.cpp @@ -12,8 +12,6 @@ namespace netgen { -using ngcore::INT; - constexpr static double EPSILON=0.000000001; void ComputeWeight( Spline & s, Point<2> p ) @@ -670,7 +668,7 @@ IntersectionType Intersect( Spline p, Spline s, double &alpha, double &beta) if(have_intersection) { - for(auto i : IntRange(10)) + for([[maybe_unused]] auto i : IntRange(10)) NewtonIntersect(p, s, alpha, beta); return ClassifyNonOverlappingIntersection( alpha, beta ); } @@ -1733,7 +1731,7 @@ Solid2d ClipSolids ( Solid2d && s1, Solid2d && s2, char op) res.polys.Append(std::move(res_polys)); - return std::move(res); + return res; } Vertex* Loop :: getNonIntersectionVertex() @@ -2037,13 +2035,13 @@ shared_ptr CSG2d :: GenerateSplineGeometry() } netgen::BoxTree <2> solid_tree(box); - Array> loop_list; + Array> loop_list; for(auto i : Range(solids)) for(auto li : Range(solids[i].polys)) { solid_tree.Insert(solids[i].polys[li].GetBoundingBox(), loop_list.Size()); - loop_list.Append(INT<2>(i, li)); + loop_list.Append(IVec<2>(i, li)); } for(auto i1 : Range(solids)) diff --git a/libsrc/geom2d/csg2d.hpp b/libsrc/geom2d/csg2d.hpp index dcc06132..63acefee 100644 --- a/libsrc/geom2d/csg2d.hpp +++ b/libsrc/geom2d/csg2d.hpp @@ -7,7 +7,7 @@ namespace netgen { - +using namespace std; using namespace ngcore; using netgen::Point; using netgen::Vec; @@ -602,7 +602,7 @@ struct Loop size_t cnt = 0; - for(auto v : Vertices(ALL)) + for([[maybe_unused]] auto v : Vertices(ALL)) cnt++; return cnt; diff --git a/libsrc/geom2d/genmesh2d.cpp b/libsrc/geom2d/genmesh2d.cpp index b2ed2dc3..747c6b39 100644 --- a/libsrc/geom2d/genmesh2d.cpp +++ b/libsrc/geom2d/genmesh2d.cpp @@ -5,7 +5,7 @@ namespace netgen { // extern DLL_HEADER MeshingParameters mparam; - extern void Optimize2d (Mesh & mesh, MeshingParameters & mp); + extern void Optimize2d (Mesh & mesh, MeshingParameters & mp, int faceindex=0); @@ -81,7 +81,7 @@ namespace netgen for (int j = 1; j <= n && i < nel; j++) { - double t = (j-0.5)*dt; + // double t = (j-0.5)*dt; double fun = hi[j-1]; f = oldf + dt / fun; @@ -92,7 +92,7 @@ namespace netgen i++; } oldf = f; - t += dt; + // t += dt; } points.Append (len); } @@ -139,7 +139,9 @@ namespace netgen mark = spline.GetPoint (edgelength); { - PointIndex pi1 = -1, pi2 = -1; + PointIndex pi1{PointIndex::INVALID}; + PointIndex pi2{PointIndex::INVALID}; + Point3d mark3(mark(0), mark(1), 0); Point3d oldmark3(oldmark(0), oldmark(1), 0); @@ -157,12 +159,12 @@ namespace netgen if ( mesh[PointIndex(locsearch[k])].GetLayer() == spline.layer) pi2 = locsearch[k]; - if (pi1 == -1) + if (!pi1.IsValid()) { pi1 = mesh.AddPoint(oldmark3, spline.layer); searchtree.Insert (oldmark3, pi1); } - if (pi2 == -1) + if (!pi2.IsValid()) { pi2 = mesh.AddPoint(mark3, spline.layer); searchtree.Insert (mark3, pi2); @@ -278,7 +280,7 @@ namespace netgen mesh2d.AddLockedPoint(npi); Element0d el(npi, npi); el.name = point.name; - mesh2d.SetCD2Name(npi, point.name); + mesh2d.SetCD2Name(npi-IndexBASE()+1, point.name); mesh2d.pointelements.Append (el); searchtree.Insert (newp, npi); } @@ -292,20 +294,20 @@ namespace netgen Point<2> hnewp = (j == 1) ? splines[i]->StartPI() : splines[i]->EndPI(); Point<3> newp(hnewp(0), hnewp(1), 0); int layer = GetSpline(i).layer; - int npi = -1; - for (PointIndex pi = PointIndex::BASE; - pi < mesh2d.GetNP()+PointIndex::BASE; pi++) + PointIndex npi(PointIndex::INVALID); + for (PointIndex pi = IndexBASE(); + pi < mesh2d.GetNP()+IndexBASE(); pi++) if (Dist2 (mesh2d.Point(pi), newp) < 1e-12 * diam2 && mesh2d.Point(pi).GetLayer() == layer) npi = pi; - if (npi == -1) + if (!npi.IsValid()) { npi = mesh2d.AddPoint (newp, layer); searchtree.Insert (newp, npi); mesh2d.AddLockedPoint(npi); - Element0d el(npi, npi); + Element0d el(npi, npi-IndexBASE()+1); el.name = ""; - mesh2d.SetCD2Name(npi, ""); + mesh2d.SetCD2Name(npi-IndexBASE()+1, ""); mesh2d.pointelements.Append (el); } } @@ -463,8 +465,8 @@ namespace netgen PointIndex mpi(0); Point<2> gp = geometry.GetPoint(i); Point<3> gp3(gp(0), gp(1), 0); - for (PointIndex pi = PointIndex::BASE; - pi < mesh->GetNP()+PointIndex::BASE; pi++) + for (PointIndex pi = IndexBASE(); + pi < mesh->GetNP()+IndexBASE(); pi++) if (Dist2(gp3, (*mesh)[pi]) < mindist) { mpi = pi; @@ -511,7 +513,7 @@ namespace netgen t_h.Stop(); int bnp = mesh->GetNP(); // boundary points - auto BndPntRange = mesh->Points().Range(); + // auto BndPntRange = mesh->Points().Range(); int hquad = mp.quad; @@ -521,8 +523,8 @@ namespace netgen { // tensor product mesh RegionTimer rt(t_tensor); - NgArray nextpi(bnp); - NgArray si1(bnp), si2(bnp); + Array nextpi(bnp); + Array si1(bnp), si2(bnp); // PointIndex firstpi; nextpi = -1; @@ -551,7 +553,8 @@ namespace netgen PointIndex c1(0), c2, c3, c4; // 4 corner points int nex = 1, ney = 1; - for (PointIndex pi = 1; pi <= si2.Size(); pi++) + // for (PointIndex pi = 1; pi <= si2.Size(); pi++) + for (PointIndex pi : si2.Range()) if (si2[pi] != -1) { c1 = pi; break; } @@ -564,13 +567,17 @@ namespace netgen NgArray pts ( (nex+1) * (ney+1) ); // x ... inner loop pts = -1; - for (PointIndex pi = c1, i = 0; pi != c2; pi = nextpi[pi], i++) + int i = 0; + for (PointIndex pi = c1; pi != c2; pi = nextpi[pi], i++) pts[i] = pi; - for (PointIndex pi = c2, i = 0; pi != c3; pi = nextpi[pi], i++) + i = 0; + for (PointIndex pi = c2; pi != c3; pi = nextpi[pi], i++) pts[(nex+1)*i+nex] = pi; - for (PointIndex pi = c3, i = 0; pi != c4; pi = nextpi[pi], i++) + i = 0; + for (PointIndex pi = c3; pi != c4; pi = nextpi[pi], i++) pts[(nex+1)*(ney+1)-i-1] = pi; - for (PointIndex pi = c4, i = 0; pi != c1; pi = nextpi[pi], i++) + i = 0; + for (PointIndex pi = c4; pi != c1; pi = nextpi[pi], i++) pts[(nex+1)*(ney-i)] = pi; diff --git a/libsrc/geom2d/geometry2d.cpp b/libsrc/geom2d/geometry2d.cpp index f3332258..014be264 100644 --- a/libsrc/geom2d/geometry2d.cpp +++ b/libsrc/geom2d/geometry2d.cpp @@ -1105,6 +1105,6 @@ namespace netgen }; SplineGeoInit sginit; - static RegisterClassForArchive, NetgenGeometry> regspg2; + static RegisterClassForArchive, NetgenGeometry>> regspg2; static RegisterClassForArchive> regssext; } diff --git a/libsrc/geom2d/python_geom2d.cpp b/libsrc/geom2d/python_geom2d.cpp index ab232f13..99ab617c 100644 --- a/libsrc/geom2d/python_geom2d.cpp +++ b/libsrc/geom2d/python_geom2d.cpp @@ -401,10 +401,8 @@ NGCORE_API_EXPORT void ExportGeom2d(py::module &m) { MeshingParameters mp; if(pars) mp = *pars; - { - py::gil_scoped_acquire aq; - CreateMPfromKwargs(mp, kwargs); - } + CreateMPfromKwargs(mp, kwargs); + py::gil_scoped_release gil_release; auto mesh = make_shared(); mesh->SetGeometry(self); SetGlobalMesh (mesh); @@ -414,7 +412,6 @@ NGCORE_API_EXPORT void ExportGeom2d(py::module &m) throw Exception("Meshing failed!"); return mesh; }, py::arg("mp") = nullopt, - py::call_guard(), meshingparameter_description.c_str()) .def("_SetDomainTensorMeshing", &SplineGeometry2d::SetDomainTensorMeshing) ; @@ -427,7 +424,8 @@ NGCORE_API_EXPORT void ExportGeom2d(py::module &m) .def(py::self-py::self) .def(py::self*py::self) .def(py::self+=py::self) - .def(py::self-=py::self) + // .def(py::self-=py::self) // false clange warning, see https://github.com/pybind/pybind11/issues/1893 + .def("__isub__", [](Solid2d& lhs, const Solid2d& rhs) { return lhs -= rhs; }, py::is_operator()) .def(py::self*=py::self) .def("Mat", &Solid2d::Mat) @@ -466,10 +464,8 @@ NGCORE_API_EXPORT void ExportGeom2d(py::module &m) { MeshingParameters mp; if(pars) mp = *pars; - { - py::gil_scoped_acquire aq; CreateMPfromKwargs(mp, kwargs); - } + py::gil_scoped_release gil_release; auto mesh = make_shared(); auto geo = self.GenerateSplineGeometry(); mesh->SetGeometry(geo); @@ -480,7 +476,6 @@ NGCORE_API_EXPORT void ExportGeom2d(py::module &m) throw Exception("Meshing failed!"); return mesh; }, py::arg("mp") = nullopt, - py::call_guard(), meshingparameter_description.c_str()) ; diff --git a/libsrc/gprim/CMakeLists.txt b/libsrc/gprim/CMakeLists.txt index b23480a4..2cd38884 100644 --- a/libsrc/gprim/CMakeLists.txt +++ b/libsrc/gprim/CMakeLists.txt @@ -11,7 +11,7 @@ target_sources(nglib PRIVATE install(FILES adtree.hpp geom2d.hpp geom3d.hpp geomfuncs.hpp - geomobjects.hpp geomops2.hpp geomops.hpp geomtest3d.hpp gprim.hpp + geomobjects.hpp geomops.hpp geomtest3d.hpp gprim.hpp splinegeometry.hpp spline.hpp transform3d.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/gprim COMPONENT netgen_devel ) diff --git a/libsrc/gprim/adtree.hpp b/libsrc/gprim/adtree.hpp index 594cf76d..21108630 100644 --- a/libsrc/gprim/adtree.hpp +++ b/libsrc/gprim/adtree.hpp @@ -8,6 +8,11 @@ /* Redesigned by Wolfram Muehlhuber, May 1998 */ /* *************************************************************************/ +#include +#include +#include + +#include "geomfuncs.hpp" namespace netgen { @@ -430,7 +435,7 @@ public: // float cmin[dim], cmax[dim]; Point cmin, cmax; // NgArray*> ela; - ClosedHashTable*> ela; + NgClosedHashTable*> ela; BlockAllocator ball{sizeof(T_ADTreeNode)}; public: @@ -759,7 +764,7 @@ public: Leaf() : n_elements(0) { } - void Add( ClosedHashTable &leaf_index, const Point<2*dim> &ap, T aindex ) + void Add( NgClosedHashTable &leaf_index, const Point<2*dim> &ap, T aindex ) { p[n_elements] = ap; index[n_elements] = aindex; @@ -794,7 +799,7 @@ public: private: Node root; - ClosedHashTable leaf_index; + NgClosedHashTable leaf_index; Point global_min, global_max; double tol; @@ -965,7 +970,7 @@ public: Leaf *leaf1 = (Leaf*) ball_leaves.Alloc(); new (leaf1) Leaf(); Leaf *leaf2 = (Leaf*) ball_leaves.Alloc(); new (leaf2) Leaf(); - for (auto i : order.Range(isplit)) + for (auto i : order.Range(0, isplit)) leaf1->Add(leaf_index, leaf->p[i], leaf->index[i] ); for (auto i : order.Range(isplit, N)) leaf2->Add(leaf_index, leaf->p[i], leaf->index[i] ); @@ -1329,7 +1334,7 @@ public: leaves.Append(leaf2); leaves[leaf1->nr] = leaf1; - for (auto i : order.Range(isplit)) + for (auto i : order.Range(0,isplit)) leaf1->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] ); for (auto i : order.Range(isplit, N)) leaf2->Add(leaves, leaf_index, leaf->p[i], leaf->index[i] ); diff --git a/libsrc/gprim/geom2d.cpp b/libsrc/gprim/geom2d.cpp index f50131aa..a6744979 100644 --- a/libsrc/gprim/geom2d.cpp +++ b/libsrc/gprim/geom2d.cpp @@ -128,7 +128,7 @@ Point2d CrossPoint (const Line2d & l1, const Line2d & l2) int CrossPointBarycentric (const Line2d & l1, const Line2d & l2, - double & lam1, double & lam2) + double & lam1, double & lam2, double eps) { // p = l1.1 + lam1 (l1.2-l1.1) = l2.1 + lam2 (l2.2-l2.1) double a11 = l1.p2.X() - l1.p1.X(); @@ -140,8 +140,11 @@ int CrossPointBarycentric (const Line2d & l1, const Line2d & l2, double b2 = l2.p1.Y() - l1.p1.Y(); double det = a11*a22 - a12 * a21; + /* if (det == 0) return 1; + */ + if (fabs (det) < eps * (fabs(a11*a22)+fabs(a12*a21))) return 1; lam1 = (a22 * b1 - a12 * b2) / det; lam2 = (a11 * b2 - a21 * b1) / det; diff --git a/libsrc/gprim/geom2d.hpp b/libsrc/gprim/geom2d.hpp index 890a456b..2c79ca4c 100644 --- a/libsrc/gprim/geom2d.hpp +++ b/libsrc/gprim/geom2d.hpp @@ -7,6 +7,12 @@ /* Date: 5. Aug. 95 */ /* *************************************************************************/ +#include + +#include +#include "geomobjects.hpp" +#include + namespace netgen { @@ -15,7 +21,7 @@ namespace netgen #define EPSGEOM 1E-5 - // extern void MyError (const char * ch); + DLL_HEADER void MyError (const char * ch); class Point2d; class Vec2d; @@ -359,7 +365,7 @@ namespace netgen friend DLL_HEADER Point2d CrossPoint (const Line2d & l1, const Line2d & l2); /// returns 1 iff parallel friend int CrossPointBarycentric (const Line2d & l1, const Line2d & l2, - double & lam1, double & lam2); + double & lam1, double & lam2, double eps); /// friend int Parallel (const Line2d & l1, const Line2d & l2, double peps); diff --git a/libsrc/gprim/geom3d.hpp b/libsrc/gprim/geom3d.hpp index 068848d5..ca3c26f6 100644 --- a/libsrc/gprim/geom3d.hpp +++ b/libsrc/gprim/geom3d.hpp @@ -7,6 +7,9 @@ /* Date: 5. Aug. 95 */ /* *************************************************************************/ +#include +#include "geom2d.hpp" + namespace netgen { diff --git a/libsrc/gprim/geomfuncs.hpp b/libsrc/gprim/geomfuncs.hpp index 2a647b25..34301312 100644 --- a/libsrc/gprim/geomfuncs.hpp +++ b/libsrc/gprim/geomfuncs.hpp @@ -7,6 +7,8 @@ /* Date: 20. Jul. 02 */ /* *************************************************************************/ +#include "geomobjects.hpp" +#include "geomops.hpp" namespace netgen { diff --git a/libsrc/gprim/geomobjects.hpp b/libsrc/gprim/geomobjects.hpp index 32a22318..f5336b33 100644 --- a/libsrc/gprim/geomobjects.hpp +++ b/libsrc/gprim/geomobjects.hpp @@ -7,10 +7,13 @@ /* Date: 20. Jul. 02 */ /* *************************************************************************/ +#include + +#include namespace netgen { - + using namespace ngcore; template class Vec; template class Point; @@ -68,7 +71,8 @@ namespace netgen operator const T* () const { return x; } - void DoArchive(Archive& archive) + template + void DoArchive(ARCHIVE& archive) { for(int i=0; i + void DoArchive(ARCHIVE& archive) { for(int i=0; i GetNormal () const; }; + template + inline ostream & operator<< (ostream & ost, const Vec & a) + { + ost << "("; + for (int i = 0; i < D-1; i++) + ost << a(i) << ", "; + ost << a(D-1) << ")"; + return ost; + } + + template + inline ostream & operator<< (ostream & ost, const Point & a) + { + ost << "("; + for (int i = 0; i < D-1; i++) + ost << a(i) << ", "; + ost << a(D-1) << ")"; + return ost; + } + template inline Vec operator-(const Point& p1, const Point& p2) { @@ -270,7 +295,8 @@ namespace netgen sol = inv * rhs; } - void DoArchive(Archive & ar) + template + void DoArchive(ARCHIVE & ar) { ar.Do(x, H*W); } @@ -317,8 +343,6 @@ namespace netgen pmin(i) = 1e99; pmax(i) = -1e99; } - // pmin = Point (1e99, 1e99, 1e99); - // pmax = Point (-1e99, -1e99, -1e99); } const Point & PMin () const { return pmin; } @@ -338,7 +362,7 @@ namespace netgen } template - void Set (const IndirectArray & points) + void Set (const NgIndirectArray & points) { // Set (points[points.Begin()]); Set (points[*points.Range().begin()]); @@ -348,7 +372,7 @@ namespace netgen } template - void Add (const IndirectArray & points) + void Add (const NgIndirectArray & points) { // for (int i = points.Begin(); i < points.End(); i++) for (int i : points.Range()) @@ -418,7 +442,8 @@ namespace netgen pmax = center + factor*(pmax-center); } - void DoArchive(Archive& archive) + template + void DoArchive(ARCHIVE & archive) { archive & pmin & pmax; } }; diff --git a/libsrc/gprim/geomops2.hpp b/libsrc/gprim/geomops2.hpp deleted file mode 100644 index c615da14..00000000 --- a/libsrc/gprim/geomops2.hpp +++ /dev/null @@ -1,428 +0,0 @@ -#ifndef FILE_GEOMOPS -#define FILE_GEOMOPS - -/* *************************************************************************/ -/* File: geomops.hpp */ -/* Author: Joachim Schoeberl */ -/* Date: 20. Jul. 02 */ -/* *************************************************************************/ - - -/* - -Point - Vector operations - - */ - - - - -template -class SumExpr : public VecExpr > -{ - const TA a; - const TB b; -public: - SumExpr (const TA aa, const TB ab) : a(aa), b(ab) { ; } - double operator() (int i) const { return a(i) + b(i); } -}; - -template -inline SumExpr -operator+ (const VecExpr & a, const VecExpr & b) -{ - return SumExpr (static_cast (a), static_cast (b)); -} - -/* -template -inline SumExpr&, const Vec&> -operator+ (const Vec & a, const Vec & b) -{ - return SumExpr&, const Vec&> (a, b); -} -*/ - - - - - -/* -template -inline Vec operator+ (const Vec & a, const Vec & b) -{ - Vec res; - for (int i = 0; i < D; i++) - res(i) = a(i) + b(i); - return res; -} -*/ - -template -inline Point operator+ (const Point & a, const Vec & b) -{ - Point res; - for (int i = 0; i < D; i++) - res(i) = a(i) + b(i); - return res; -} - - -template -inline Vec operator- (const Point & a, const Point & b) -{ - Vec res; - for (int i = 0; i < D; i++) - res(i) = a(i) - b(i); - return res; -} - -template -inline Point operator- (const Point & a, const Vec & b) -{ - Point res; - for (int i = 0; i < D; i++) - res(i) = a(i) - b(i); - return res; -} - -template -inline Vec operator- (const Vec & a, const Vec & b) -{ - Vec res; - for (int i = 0; i < D; i++) - res(i) = a(i) - b(i); - return res; -} - - -template -inline Vec operator* (double s, const Vec & b) -{ - Vec res; - for (int i = 0; i < D; i++) - res(i) = s * b(i); - return res; -} - - -template -inline double operator* (const Vec & a, const Vec & b) -{ - double sum = 0; - for (int i = 0; i < D; i++) - sum += a(i) * b(i); - return sum; -} - - - -template -inline Vec operator- (const Vec & b) -{ - Vec res; - for (int i = 0; i < D; i++) - res(i) = -b(i); - return res; -} - - -template -inline Point & operator+= (Point & a, const Vec & b) -{ - for (int i = 0; i < D; i++) - a(i) += b(i); - return a; -} - - -template -inline Point & operator+= (Point & a, const VecExpr & b) -{ - for (int i = 0; i < D; i++) - a(i) += b(i); - return a; -} - -template -inline Vec & operator+= (Vec & a, const Vec & b) -{ - for (int i = 0; i < D; i++) - a(i) += b(i); - return a; -} - - - - - -template -inline Point & operator-= (Point & a, const Vec & b) -{ - for (int i = 0; i < D; i++) - a(i) -= b(i); - return a; -} - -template -inline Point & operator-= (Point & a, const VecExpr & b) -{ - for (int i = 0; i < D; i++) - a(i) -= b(i); - return a; -} - - - - - -template -inline Vec & operator-= (Vec & a, const Vec & b) -{ - for (int i = 0; i < D; i++) - a(i) -= b(i); - return a; -} - - - -template -inline Vec & operator*= (Vec & a, double s) -{ - for (int i = 0; i < D; i++) - a(i) *= s; - return a; -} - - -template -inline Vec & operator/= (Vec & a, double s) -{ - for (int i = 0; i < D; i++) - a(i) /= s; - return a; -} - - - - -// Matrix - Vector operations - -/* -template -inline Vec operator* (const Mat & m, const Vec & v) -{ - Vec res; - for (int i = 0; i < H; i++) - { - res(i) = 0; - for (int j = 0; j < W; j++) - res(i) += m(i,j) * v(j); - } - return res; -} -*/ - -// thanks to VC60 partial template specialization features !!! - -inline Vec<2> operator* (const Mat<2,2> & m, const Vec<2> & v) -{ - Vec<2> res; - for (int i = 0; i < 2; i++) - { - res(i) = 0; - for (int j = 0; j < 2; j++) - res(i) += m(i,j) * v(j); - } - return res; -} - -inline Vec<2> operator* (const Mat<2,3> & m, const Vec<3> & v) -{ - Vec<2> res; - for (int i = 0; i < 2; i++) - { - res(i) = 0; - for (int j = 0; j < 3; j++) - res(i) += m(i,j) * v(j); - } - return res; -} - - -inline Vec<3> operator* (const Mat<3,2> & m, const Vec<2> & v) -{ - Vec<3> res; - for (int i = 0; i < 3; i++) - { - res(i) = 0; - for (int j = 0; j < 2; j++) - res(i) += m(i,j) * v(j); - } - return res; -} - - -inline Vec<3> operator* (const Mat<3,3> & m, const Vec<3> & v) -{ - Vec<3> res; - for (int i = 0; i < 3; i++) - { - res(i) = 0; - for (int j = 0; j < 3; j++) - res(i) += m(i,j) * v(j); - } - return res; -} - - - - - - - -/* -template -inline Mat operator* (const Mat & a, const Mat & b) -{ - Mat m; - for (int i = 0; i < H1; i++) - for (int j = 0; j < W2; j++) - { - double sum = 0; - for (int k = 0; k < W1; k++) - sum += a(i,k) * b(k, j); - m(i,j) = sum; - } - return m; -} -*/ - -inline Mat<2,2> operator* (const Mat<2,2> & a, const Mat<2,2> & b) -{ - Mat<2,2> m; - for (int i = 0; i < 2; i++) - for (int j = 0; j < 2; j++) - { - double sum = 0; - for (int k = 0; k < 2; k++) - sum += a(i,k) * b(k, j); - m(i,j) = sum; - } - return m; -} - -inline Mat<2,2> operator* (const Mat<2,3> & a, const Mat<3,2> & b) -{ - Mat<2,2> m; - for (int i = 0; i < 2; i++) - for (int j = 0; j < 2; j++) - { - double sum = 0; - for (int k = 0; k < 3; k++) - sum += a(i,k) * b(k, j); - m(i,j) = sum; - } - return m; -} - - -inline Mat<3,2> operator* (const Mat<3,2> & a, const Mat<2,2> & b) -{ - Mat<3,2> m; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 2; j++) - { - double sum = 0; - for (int k = 0; k < 2; k++) - sum += a(i,k) * b(k, j); - m(i,j) = sum; - } - return m; -} - -inline Mat<3,3> operator* (const Mat<3,3> & a, const Mat<3,3> & b) -{ - Mat<3,3> m; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - { - double sum = 0; - for (int k = 0; k < 3; k++) - sum += a(i,k) * b(k, j); - m(i,j) = sum; - } - return m; -} - - - - - - - - -template -inline Mat Trans (const Mat & m) -{ - Mat res; - for (int i = 0; i < H; i++) - for (int j = 0; j < W; j++) - res(j,i) = m(i,j); - return res; -} - - - - - - - - - - - -template -inline ostream & operator<< (ostream & ost, const Vec & a) -{ - ost << "("; - for (int i = 0; i < D-1; i++) - ost << a(i) << ", "; - ost << a(D-1) << ")"; - return ost; -} - -template -inline ostream & operator<< (ostream & ost, const Point & a) -{ - ost << "("; - for (int i = 0; i < D-1; i++) - ost << a(i) << ", "; - ost << a(D-1) << ")"; - return ost; -} - -template -inline ostream & operator<< (ostream & ost, const Box & b) -{ - ost << b.PMin() << " - " << b.PMax(); - return ost; -} - -template -inline ostream & operator<< (ostream & ost, const Mat & m) -{ - ost << "("; - for (int i = 0; i < H; i++) - { - for (int j = 0; j < W; j++) - ost << m(i,j) << " "; - ost << endl; - } - return ost; -} - - - - -#endif diff --git a/libsrc/gprim/geomtest3d.hpp b/libsrc/gprim/geomtest3d.hpp index 954d32e7..837c402b 100644 --- a/libsrc/gprim/geomtest3d.hpp +++ b/libsrc/gprim/geomtest3d.hpp @@ -7,6 +7,8 @@ /* Date: 13. Feb. 98 */ /* *************************************************************************/ +#include "geom3d.hpp" +#include "geomobjects.hpp" namespace netgen { diff --git a/libsrc/gprim/transform3d.hpp b/libsrc/gprim/transform3d.hpp index b5886d29..0e8a6610 100644 --- a/libsrc/gprim/transform3d.hpp +++ b/libsrc/gprim/transform3d.hpp @@ -11,6 +11,9 @@ Affine - Linear mapping in 3D space */ +#include "geom3d.hpp" +#include "geomfuncs.hpp" + namespace netgen { diff --git a/libsrc/include/incopengl.hpp b/libsrc/include/incopengl.hpp index 1f42f12f..35b1c48b 100644 --- a/libsrc/include/incopengl.hpp +++ b/libsrc/include/incopengl.hpp @@ -5,6 +5,11 @@ #include #include +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + # ifdef __APPLE__ #define GL_SILENCE_DEPRECATION #define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED diff --git a/libsrc/include/inctcl.hpp b/libsrc/include/inctcl.hpp index 8191a44a..4a15a885 100644 --- a/libsrc/include/inctcl.hpp +++ b/libsrc/include/inctcl.hpp @@ -1,3 +1,8 @@ +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + #include #include diff --git a/libsrc/include/mystdlib.h b/libsrc/include/mystdlib.h index f79e0ad2..b23a06ab 100644 --- a/libsrc/include/mystdlib.h +++ b/libsrc/include/mystdlib.h @@ -20,57 +20,40 @@ #include #include #include +#include #include #include #include -#ifdef PARALLEL -// #undef SEEK_SET -// #undef SEEK_CUR -// #undef SEEK_END -#include -#include // for usleep (only for parallel) -#endif - - - -/* -#ifdef METIS -namespace metis { extern "C" { -#include -} } -#endif -*/ - - #ifndef M_PI #define M_PI 3.14159265358979323846 #endif - /*** Windows headers ***/ #ifdef _MSC_VER # define WIN32_LEAN_AND_MEAN # ifndef NO_PARALLEL_THREADS # ifdef MSVC_EXPRESS # else -# include -# include +// # include +// # include # endif // MSVC_EXPRESS # endif -# include +// # include # undef WIN32_LEAN_AND_MEAN -# include - +// # include #else // Not using MC VC++ +#endif + + +// using namespace std; +namespace netgen +{ + using namespace std; +} #endif - -using namespace std; - -#endif - diff --git a/libsrc/include/nginterface.h b/libsrc/include/nginterface.h index b4459087..7c5545a9 100644 --- a/libsrc/include/nginterface.h +++ b/libsrc/include/nginterface.h @@ -38,7 +38,7 @@ enum NG_ELEMENT_TYPE { NG_TRIG = 10, NG_QUAD=11, NG_TRIG6 = 12, NG_QUAD6 = 13, NG_QUAD8 = 14, NG_TET = 20, NG_TET10 = 21, NG_PYRAMID = 22, NG_PRISM = 23, NG_PRISM12 = 24, NG_PRISM15 = 27, NG_PYRAMID13 = 28, - NG_HEX = 25, NG_HEX20 = 26 + NG_HEX = 25, NG_HEX20 = 26, NG_HEX7 = 29 }; typedef double NG_POINT[3]; // coordinates @@ -316,6 +316,7 @@ extern "C" { int iscomplex; // complex vector ? bool draw_surface; bool draw_volume; + std::shared_ptr draw_surfaces, draw_volumes; int order; // order of elements, only partially supported Ng_SolutionType soltype; // type of solution function netgen::SolutionData * solclass; diff --git a/libsrc/include/nginterface_v2.hpp b/libsrc/include/nginterface_v2.hpp index 6c70a9ef..716e01a8 100644 --- a/libsrc/include/nginterface_v2.hpp +++ b/libsrc/include/nginterface_v2.hpp @@ -9,6 +9,7 @@ /**************************************************************************/ #include "mydefs.hpp" +#include /* C++ interface to Netgen @@ -22,7 +23,7 @@ enum NG_ELEMENT_TYPE { NG_TRIG = 10, NG_QUAD=11, NG_TRIG6 = 12, NG_QUAD6 = 13, NG_QUAD8 = 14, NG_TET = 20, NG_TET10 = 21, NG_PYRAMID = 22, NG_PRISM = 23, NG_PRISM12 = 24, NG_PRISM15 = 27, NG_PYRAMID13 = 28, - NG_HEX = 25, NG_HEX20 = 26 + NG_HEX = 25, NG_HEX20 = 26, NG_HEX7 = 29 }; enum NG_REFINEMENT_TYPE { NG_REFINE_H = 0, NG_REFINE_P = 1, NG_REFINE_HP = 2 }; @@ -38,24 +39,9 @@ namespace netgen using namespace std; using namespace ngcore; - // extern DLL_HEADER NgMPI_Comm ng_comm; static constexpr int POINTINDEX_BASE = 1; - /* - struct T_EDGE2 - { - // int orient:1; - // int nr:31; // 0-based - int nr; // 0-based - }; - struct T_FACE2 - { - // int orient:3; - // int nr:29; // 0-based - int nr; // 0-based - }; - */ typedef int T_EDGE2; typedef int T_FACE2; @@ -111,26 +97,6 @@ namespace netgen int operator[] (size_t i) const { return ptr[i]-POINTINDEX_BASE; } }; - class Ng_Edges - { - public: - size_t num; - const T_EDGE2 * ptr; - - size_t Size() const { return num; } - int operator[] (size_t i) const { return ptr[i]; } - }; - - class Ng_Faces - { - public: - size_t num; - const T_FACE2 * ptr; - - size_t Size() const { return num; } - int operator[] (size_t i) const { return ptr[i]; } - }; - class Ng_Facets { public: @@ -146,15 +112,16 @@ namespace netgen public: NG_ELEMENT_TYPE type; int index; // material / boundary condition - const string * mat; // material / boundary label + string_view mat; // material / boundary label NG_ELEMENT_TYPE GetType() const { return type; } int GetIndex() const { return index-1; } Ng_Points points; // all points Ng_Vertices vertices; - Ng_Edges edges; - Ng_Faces faces; + FlatArray edges; + FlatArray faces; Ng_Facets facets; bool is_curved; + int8_t newest_vertex; }; @@ -303,7 +270,7 @@ namespace netgen /// material/boundary label of region, template argument is co-dimension template - const string & GetMaterialCD (int region_nr) const; + string_view GetMaterialCD (int region_nr) const; /// Curved Elements: /// elnr .. element nr @@ -389,6 +356,8 @@ namespace netgen // also added from nginterface.h, still 1-based, need redesign void HPRefinement (int levels, double parameter = 0.125, bool setorders = true,bool ref_level = false); + void SplitAlfeld (); + size_t GetNP() const; int GetSurfaceElementSurfaceNumber (size_t ei) const; int GetSurfaceElementFDNumber (size_t ei) const; @@ -405,6 +374,10 @@ namespace netgen int GetClusterRepEdge (int edi) const; int GetClusterRepFace (int fai) const; int GetClusterRepElement (int eli) const; + + // just copied from nginterface, now 0-based + int GetElement_Faces (int elnr, int * faces, int * orient = 0) const; + int GetSurfaceElement_Face (int selnr, int * orient = 0) const; }; diff --git a/libsrc/include/nginterface_v2_impl.hpp b/libsrc/include/nginterface_v2_impl.hpp index a0c1cf01..7000080f 100644 --- a/libsrc/include/nginterface_v2_impl.hpp +++ b/libsrc/include/nginterface_v2_impl.hpp @@ -49,31 +49,40 @@ NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<0> (size_t nr) const Ng_Element ret; ret.type = NG_PNT; ret.index = el.index; - ret.mat = &el.name; + ret.mat = el.name; ret.points.num = 1; ret.points.ptr = (int*)&el.pnum; ret.vertices.num = 1; ret.vertices.ptr = (int*)&el.pnum; - + + /* ret.edges.num = 0; ret.edges.ptr = NULL; - + */ + ret.edges.Assign ( FlatArray (0, nullptr) ); + /* ret.faces.num = 0; ret.faces.ptr = NULL; - + */ + ret.faces.Assign ( { 0, nullptr } ); + ret.facets.num = 1; - ret.facets.base = 1; + ret.facets.base = POINTINDEX_BASE; ret.facets.ptr = (int*)&el.pnum; + /* if (mesh->GetDimension() == 1) - ret.mat = mesh->GetBCNamePtr(el.index-1); + ret.mat = *(mesh->GetBCNamePtr(el.index-1)); else if (mesh->GetDimension() == 2) - ret.mat = mesh->GetCD2NamePtr(el.index-1); + ret.mat = *(mesh->GetCD2NamePtr(el.index-1)); else - ret.mat = mesh->GetCD3NamePtr(el.index-1); - + ret.mat = *(mesh->GetCD3NamePtr(el.index-1)); + */ + ret.mat = mesh->GetRegionName(0, el.index); + + ret.is_curved = false; return ret; } @@ -91,15 +100,19 @@ NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<1> (size_t nr) const ret.index = el.edgenr; else ret.index = el.si; + + /* if (mesh->GetDimension() == 2) - ret.mat = mesh->GetBCNamePtr(el.si-1); + ret.mat = *(mesh->GetBCNamePtr(el.si-1)); else { if (mesh->GetDimension() == 3) - ret.mat = mesh->GetCD2NamePtr(el.edgenr-1); + ret.mat = *(mesh->GetCD2NamePtr(el.edgenr-1)); else - ret.mat = mesh->GetMaterialPtr(el.si); + ret.mat = *(mesh->GetMaterialPtr(el.si)); } + */ + ret.mat = mesh->GetRegionName(1, ret.index); ret.points.num = el.GetNP(); ret.points.ptr = (int*)&(el[0]); @@ -107,12 +120,18 @@ NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<1> (size_t nr) const ret.vertices.num = 2; ret.vertices.ptr = (int*)&(el[0]); + /* ret.edges.num = 1; ret.edges.ptr = mesh->GetTopology().GetSegmentElementEdgesPtr (nr); + */ + ret.edges.Assign ( FlatArray (1, const_cast((const int*) mesh->GetTopology().GetSegmentElementEdgesPtr (nr)))); + /* ret.faces.num = 0; ret.faces.ptr = NULL; - + */ + ret.faces.Assign ( { 0, nullptr }); + if (mesh->GetDimension() == 3) { ret.facets.num = 0; @@ -123,12 +142,12 @@ NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<1> (size_t nr) const { ret.facets.num = 1; ret.facets.base = 0; - ret.facets.ptr = ret.edges.ptr; + ret.facets.ptr = ret.edges.Data(); } else { ret.facets.num = 2; - ret.facets.base = 1; + ret.facets.base = POINTINDEX_BASE; ret.facets.ptr = (int*)&(el[0]); } @@ -148,34 +167,46 @@ NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<2> (size_t nr) const const FaceDescriptor & fd = mesh->GetFaceDescriptor(el); // .GetIndex()); ret.index = fd.BCProperty(); if (mesh->GetDimension() == 3) - ret.mat = &fd.GetBCName(); + ret.mat = fd.GetBCName(); else - ret.mat = mesh -> GetMaterialPtr(ret.index); + ret.mat = *(mesh -> GetMaterialPtr(ret.index)); ret.points.num = el.GetNP(); ret.points.ptr = (int*)&el[0]; ret.vertices.num = el.GetNV(); ret.vertices.ptr = (int*)&(el[0]); + /* ret.edges.num = MeshTopology::GetNEdges (el.GetType()); ret.edges.ptr = mesh->GetTopology().GetSurfaceElementEdgesPtr (nr); + */ + // ret.edges.Assign (mesh->GetTopology().GetEdges (SurfaceElementIndex(nr))); + auto hedges = mesh->GetTopology().GetEdges (SurfaceElementIndex(nr)); + ret.edges.Assign ( { hedges.Size(), (int*)hedges.Data() } ); + + /* ret.faces.num = MeshTopology::GetNFaces (el.GetType()); ret.faces.ptr = mesh->GetTopology().GetSurfaceElementFacesPtr (nr); + */ + // ret.faces.Assign ( { 1, const_cast(mesh->GetTopology().GetSurfaceElementFacesPtr (nr)) }); + ret.faces.Assign ( { 1, (int*)(mesh->GetTopology().GetSurfaceElementFacesPtr (nr)) }); + if (mesh->GetDimension() == 3) { - ret.facets.num = ret.faces.num; + ret.facets.num = ret.faces.Size(); ret.facets.base = 0; - ret.facets.ptr = ret.faces.ptr; + ret.facets.ptr = ret.faces.Data(); } else { - ret.facets.num = ret.edges.num; + ret.facets.num = ret.edges.Size(); ret.facets.base = 0; - ret.facets.ptr = ret.edges.ptr; + ret.facets.ptr = ret.edges.Data(); } ret.is_curved = el.IsCurved(); + ret.newest_vertex = el.NewestVertex(); return ret; } @@ -187,49 +218,61 @@ NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<3> (size_t nr) const Ng_Element ret; ret.type = NG_ELEMENT_TYPE(el.GetType()); ret.index = el.GetIndex(); - ret.mat = mesh -> GetMaterialPtr(ret.index); + ret.mat = *(mesh -> GetMaterialPtr(ret.index)); ret.points.num = el.GetNP(); ret.points.ptr = (int*)&el[0]; ret.vertices.num = el.GetNV(); ret.vertices.ptr = (int*)&(el[0]); + /* ret.edges.num = MeshTopology::GetNEdges (el.GetType()); ret.edges.ptr = mesh->GetTopology().GetElementEdgesPtr (nr); + */ + // ret.edges.Assign (mesh->GetTopology().GetEdges (ElementIndex(nr))); + auto hedges = mesh->GetTopology().GetEdges (ElementIndex(nr)); + ret.edges.Assign ( { hedges.Size(), (int*)hedges.Data() } ); + + /* ret.faces.num = MeshTopology::GetNFaces (el.GetType()); ret.faces.ptr = mesh->GetTopology().GetElementFacesPtr (nr); - - ret.facets.num = ret.faces.num; + */ + // ret.faces.Assign (mesh->GetTopology().GetFaces (ElementIndex(nr))); + auto hfaces = mesh->GetTopology().GetFaces (ElementIndex(nr)); + ret.faces.Assign ( { hfaces.Size(), (int*)hfaces.Data() } ); + + ret.facets.num = ret.faces.Size(); ret.facets.base = 0; - ret.facets.ptr = ret.faces.ptr; + ret.facets.ptr = ret.faces.Data(); ret.is_curved = el.IsCurved(); + ret.newest_vertex = el.NewestVertex(); return ret; } template <> NGX_INLINE DLL_HEADER -const string & Ngx_Mesh :: GetMaterialCD<0> (int region_nr) const +string_view Ngx_Mesh :: GetMaterialCD<0> (int region_nr) const { return mesh->GetMaterial(region_nr+1); } template <> NGX_INLINE DLL_HEADER -const string & Ngx_Mesh :: GetMaterialCD<1> (int region_nr) const +string_view Ngx_Mesh :: GetMaterialCD<1> (int region_nr) const { return mesh->GetBCName(region_nr); } template <> NGX_INLINE DLL_HEADER -const string & Ngx_Mesh :: GetMaterialCD<2> (int region_nr) const +string_view Ngx_Mesh :: GetMaterialCD<2> (int region_nr) const { return mesh->GetCD2Name(region_nr); } template <> NGX_INLINE DLL_HEADER -const string & Ngx_Mesh :: GetMaterialCD<3> (int region_nr) const +string_view Ngx_Mesh :: GetMaterialCD<3> (int region_nr) const { return mesh->GetCD3Name(region_nr); } @@ -248,10 +291,10 @@ template <> NGX_INLINE DLL_HEADER int Ngx_Mesh :: GetNNodes<2> () return mesh->GetTopology().GetNFaces(); } -template <> NGX_INLINE DLL_HEADER const Ng_Node<0> Ngx_Mesh :: GetNode<0> (int vnr) const +template <> NGX_INLINE DLL_HEADER const Ng_Node<0> Ngx_Mesh :: GetNode<0> (int vnr_) const { Ng_Node<0> node; - vnr++; + PointIndex vnr = IndexBASE() + vnr_; switch (mesh->GetDimension()) { case 3: @@ -304,8 +347,8 @@ template <> NGX_INLINE DLL_HEADER const Ng_Node<2> Ngx_Mesh :: GetNode<2> (int n { Ng_Node<2> node; node.vertices.ptr = (const int*)mesh->GetTopology().GetFaceVerticesPtr(nr); - node.vertices.nv = (node.vertices.ptr[3] == 0) ? 3 : 4; - node.surface_el = mesh->GetTopology().GetFace2SurfaceElement (nr+1)-1; + node.vertices.nv = (node.vertices.ptr[3]+1 == PointIndex::BASE) ? 3 : 4; + node.surface_el = mesh->GetTopology().GetFace2SurfaceElement (nr); return node; } @@ -316,8 +359,8 @@ NGX_INLINE DLL_HEADER Ng_Buffer Ngx_Mesh :: GetPeriodicVertices(int idnr mesh->GetIdentifications().GetPairs (idnr+1, apairs); for(auto& ind : apairs) { - ind.I1()--; - ind.I2()--; + ind.I1() -= IndexBASE(); + ind.I2() -= IndexBASE(); } typedef int ti2[2]; return { apairs.Size(), (ti2*)(void*)apairs.Release() }; @@ -326,12 +369,9 @@ NGX_INLINE DLL_HEADER Ng_Buffer Ngx_Mesh :: GetPeriodicVertices(int idnr NGX_INLINE void Ngx_Mesh :: GetParentNodes (int ni, int * parents) const { - ni++; - if (ni <= mesh->mlbetweennodes.Size()) - { - parents[0] = mesh->mlbetweennodes.Get(ni).I1()-1; - parents[1] = mesh->mlbetweennodes.Get(ni).I2()-1; - } + if (ni < mesh->mlbetweennodes.Size()) + for (int j = 0; j < 2; j++) + parents[j] = mesh->mlbetweennodes[IndexBASE()+ni][j] - IndexBASE(); else parents[0] = parents[1] = -1; } diff --git a/libsrc/interface/CMakeLists.txt b/libsrc/interface/CMakeLists.txt index 9126484f..cf48a84a 100644 --- a/libsrc/interface/CMakeLists.txt +++ b/libsrc/interface/CMakeLists.txt @@ -1,12 +1,12 @@ -target_sources(nglib PRIVATE +target_sources(nglib PRIVATE writeuser.cpp nginterface.cpp nginterface_v2.cpp read_fnf_mesh.cpp readtetmesh.cpp readuser.cpp writeabaqus.cpp writediffpack.cpp writedolfin.cpp writeelmer.cpp writefeap.cpp writefluent.cpp writegmsh.cpp writejcm.cpp - writepermas.cpp writetecplot.cpp writetet.cpp writetochnog.cpp writeuser.cpp writevtk.cpp - wuchemnitz.cpp writegmsh2.cpp writeOpenFOAM15x.cpp rw_cgns.cpp + writepermas.cpp writetecplot.cpp writetet.cpp writetochnog.cpp + wuchemnitz.cpp writegmsh2.cpp writeOpenFOAM15x.cpp rw_cgns.cpp rw_medit.cpp ) install(FILES - writeuser.hpp + writeuser.hpp rw_medit.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/interface COMPONENT netgen_devel ) diff --git a/libsrc/interface/nginterface.cpp b/libsrc/interface/nginterface.cpp index 4da0eed9..9186a5ef 100644 --- a/libsrc/interface/nginterface.cpp +++ b/libsrc/interface/nginterface.cpp @@ -27,17 +27,7 @@ namespace netgen static std::thread meshingthread; void RunParallel ( void * (*fun)(void *), void * in) { - bool parthread = netgen::mparam.parthread; - -#ifdef PARALLEL - int provided; - MPI_Query_thread(&provided); - if (provided < 3) - if (netgen::ntasks > 1) parthread = false; - // cout << "runparallel = " << parthread << endl; -#endif - - if (parthread) + if (netgen::mparam.parthread) { meshingthread = std::thread(fun, in); meshingthread.detach(); @@ -517,7 +507,7 @@ NG_ELEMENT_TYPE Ng_GetSurfaceElement (int ei, int * epi, int * np) { const Segment & seg = mesh->LineSegment (ei); - if (seg[2] < 0) + if (!seg[2].IsValid()) { epi[0] = seg[0]; epi[1] = seg[1]; @@ -661,14 +651,14 @@ int Ng_FindElementOfPoint (double * p, double * lami, int build_searchtree, { Point3d p3d(p[0], p[1], p[2]); ind = - mesh->GetElementOfPoint(p3d, lami, dummy, build_searchtree != 0); + mesh->GetElementOfPoint(p3d, lami, dummy, build_searchtree != 0) + 1; } else { double lam3[3]; Point3d p2d(p[0], p[1], 0); ind = - mesh->GetElementOfPoint(p2d, lam3, dummy, build_searchtree != 0); + mesh->GetSurfaceElementOfPoint(p2d, lam3, dummy, build_searchtree != 0) + 1; if (ind > 0) { @@ -707,7 +697,7 @@ int Ng_FindSurfaceElementOfPoint (double * p, double * lami, int build_searchtre { Point3d p3d(p[0], p[1], p[2]); ind = - mesh->GetSurfaceElementOfPoint(p3d, lami, dummy, build_searchtree != 0); + mesh->GetSurfaceElementOfPoint(p3d, lami, dummy, build_searchtree != 0) + 1; } else { @@ -876,7 +866,7 @@ NG_ELEMENT_TYPE Ng_GetSegment (int ei, int * epi, int * np) epi[0] = seg[0]; epi[1] = seg[1]; - if (seg[2] < 0) + if (!seg[2].IsValid()) { if (np) *np = 2; return NG_SEGM; @@ -1122,7 +1112,7 @@ void Ng_HPRefinement (int levels, double parameter, bool setorders, { NgLock meshlock (mesh->MajorMutex(), true); Refinement & ref = const_cast (mesh->GetGeometry()->GetRefinement()); - HPRefinement (*mesh, &ref, levels, parameter, setorders, ref_level); + HPRefinement (*mesh, &ref, SPLIT_HP, levels, parameter, setorders, ref_level); /* Refinement * ref; @@ -1581,10 +1571,11 @@ int Ng_GetSurfaceElement_Face (int selnr, int * orient) { if (mesh->GetDimension() == 3) { + SurfaceElementIndex sei = selnr-1; const MeshTopology & topology = mesh->GetTopology(); if (orient) *orient = topology.GetSurfaceElementFaceOrientation (selnr); - return topology.GetSurfaceElementFace (selnr); + return topology.GetFace(sei); } return -1; } @@ -1614,7 +1605,11 @@ int Ng_GetFace_Edges (int fnr, int * edge) void Ng_GetEdge_Vertices (int ednr, int * vert) { const MeshTopology & topology = mesh->GetTopology(); - topology.GetEdgeVertices (ednr, vert[0], vert[1]); + // topology.GetEdgeVertices (ednr, vert[0], vert[1]); + // tie(vert[0], vert[1]) = topology.GetEdgeVertices(ednr-1); + auto [v1,v2] = topology.GetEdgeVertices(ednr-1); + vert[0] = v1-IndexBASE()+1; + vert[1] = v2-IndexBASE()+1; } @@ -1745,8 +1740,8 @@ void Ng_GetParentNodes (int ni, int * parents) { if (ni <= mesh->mlbetweennodes.Size()) { - parents[0] = mesh->mlbetweennodes.Get(ni).I1(); - parents[1] = mesh->mlbetweennodes.Get(ni).I2(); + parents[0] = mesh->mlbetweennodes[ni].I1(); + parents[1] = mesh->mlbetweennodes[ni].I2(); } else parents[0] = parents[1] = 0; @@ -1758,12 +1753,12 @@ int Ng_GetParentElement (int ei) if (mesh->GetDimension() == 3) { if (ei <= mesh->mlparentelement.Size()) - return mesh->mlparentelement.Get(ei); + return mesh->mlparentelement[ei-1]+1; } else { if (ei <= mesh->mlparentsurfaceelement.Size()) - return mesh->mlparentsurfaceelement.Get(ei); + return mesh->mlparentsurfaceelement[ei-1]+1; } return 0; } @@ -1774,7 +1769,7 @@ int Ng_GetParentSElement (int ei) if (mesh->GetDimension() == 3) { if (ei <= mesh->mlparentsurfaceelement.Size()) - return mesh->mlparentsurfaceelement.Get(ei); + return mesh->mlparentsurfaceelement[ei-1]+1; } else { @@ -1836,7 +1831,7 @@ void Ng_GetPeriodicVertices (int idnr, int * pairs) int Ng_GetNPeriodicEdges (int idnr) { - NgArray map; + idmap_type map; //const MeshTopology & top = mesh->GetTopology(); int nse = mesh->GetNSeg(); @@ -1863,7 +1858,7 @@ int Ng_GetNPeriodicEdges (int idnr) void Ng_GetPeriodicEdges (int idnr, int * pairs) { - NgArray map; + idmap_type map; const MeshTopology & top = mesh->GetTopology(); int nse = mesh->GetNSeg(); @@ -1954,8 +1949,10 @@ int Ng_GetVertex_Elements( int vnr, int* elems ) } ///// Added by Roman Stainko .... -int Ng_GetVertex_SurfaceElements( int vnr, int* elems ) +int Ng_GetVertex_SurfaceElements( int vnr_, int* elems ) { + PointIndex vnr = vnr_ + IndexBASE()-1; + switch (mesh->GetDimension()) { case 3: @@ -2003,8 +2000,9 @@ int Ng_GetVertex_NElements( int vnr ) } ///// Added by Roman Stainko .... -int Ng_GetVertex_NSurfaceElements( int vnr ) +int Ng_GetVertex_NSurfaceElements( int vnr_ ) { + PointIndex vnr = vnr_ + IndexBASE()-1; switch (mesh->GetDimension()) { case 3: @@ -2249,17 +2247,14 @@ int Ng_GetClosureNodes (int nt, int nodenr, int nodeset, int * nodes) for (int i = 0; i < el.GetNP(); i++) { nodes[cnt++] = 0; - nodes[cnt++] = el[i] - PointIndex::BASE; + nodes[cnt++] = el[i] - IndexBASE(); } } if (nodeset & 2) // Edges { - int edges[12]; - // int ned; - // ned = mesh->GetTopology().GetElementEdges (nodenr+1, edges, 0); - int ned = mesh->GetTopology().GetEdges (ElementIndex(nodenr)).Size(); - for (int i = 0; i < ned; i++) + auto edges = mesh->GetTopology().GetEdges (ElementIndex(nodenr)); + for (int i = 0; i < edges.Size(); i++) { nodes[cnt++] = 1; nodes[cnt++] = edges[i]-1; @@ -2334,7 +2329,7 @@ int Ng_GetElementClosureNodes (int dim, int elementnr, int nodeset, int * nodes) for (int i = 0; i < el.GetNP(); i++) { nodes[cnt++] = 0; - nodes[cnt++] = el[i] - PointIndex::BASE; + nodes[cnt++] = el[i] - IndexBASE(); } } @@ -2352,7 +2347,7 @@ int Ng_GetElementClosureNodes (int dim, int elementnr, int nodeset, int * nodes) if (nodeset & 4) // Faces { - int face = mesh->GetTopology().GetSurfaceElementFace (elementnr+1); + int face = mesh->GetTopology().GetFace (SurfaceElementIndex(elementnr))+1; nodes[cnt++] = 2; nodes[cnt++] = face-1; } diff --git a/libsrc/interface/nginterface_v2.cpp b/libsrc/interface/nginterface_v2.cpp index a953dce0..2c95505f 100644 --- a/libsrc/interface/nginterface_v2.cpp +++ b/libsrc/interface/nginterface_v2.cpp @@ -725,34 +725,32 @@ namespace netgen int Ngx_Mesh :: GetParentElement (int ei) const { - ei++; - if (mesh->GetDimension() == 3) + if (mesh->GetDimension() == 3) { - if (ei <= mesh->mlparentelement.Size()) - return mesh->mlparentelement.Get(ei)-1; + if (ei < mesh->mlparentelement.Size()) + return mesh->mlparentelement[ei]; } - else + else { - if (ei <= mesh->mlparentsurfaceelement.Size()) - return mesh->mlparentsurfaceelement.Get(ei)-1; + if (ei < mesh->mlparentsurfaceelement.Size()) + return mesh->mlparentsurfaceelement[ei]; } - return -1; + return -1; } int Ngx_Mesh :: GetParentSElement (int ei) const { - ei++; - if (mesh->GetDimension() == 3) + if (mesh->GetDimension() == 3) { - if (ei <= mesh->mlparentsurfaceelement.Size()) - return mesh->mlparentsurfaceelement.Get(ei)-1; + if (ei < mesh->mlparentsurfaceelement.Size()) + return mesh->mlparentsurfaceelement[ei]; } - else + else { - return -1; + return -1; } - return -1; + return -1; } int Ngx_Mesh :: GetNIdentifications () const @@ -1013,68 +1011,28 @@ namespace netgen int * const indices, int numind) const { - switch (mesh->GetDimension()) + Point<3> p(hp[0], 0., 0.); + if(mesh->GetDimension() > 1) + p[1] = hp[1]; + if(mesh->GetDimension() == 3) + p[2] = hp[2]; + + for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) { - case 1: - { - Point<3> p(hp[0], 0,0); - for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) - { - auto & seg = (*mesh)[si]; - Point<3> p1 = (*mesh)[seg[0]]; - Point<3> p2 = (*mesh)[seg[1]]; - double lam = (p(0)-p1(0)) / (p2(0)-p1(0)); - if (lam >= -1e-10 && lam <= 1+1e-10) - { - lami[0] = 1-lam; - return si; - } - } - } - break; - case 2: - { - Point<3> p(hp[0], hp[1],0); - try - { - auto ind = mesh->GetSurfaceElementOfPoint(p, lami, nullptr, - build_searchtree); - return ind - 1; - } - catch(NgException e) // quads not implemented curved yet - { - for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) - { - auto & seg = (*mesh)[si]; - Point<3> p1 = (*mesh)[seg[0]]; - Point<3> p2 = (*mesh)[seg[1]]; - double lam; - double r; - if (fabs(p2[0]-p1[0]) >= fabs(p2[1]-p1[1])) - { - lam = (p[0]-p1[0])/(p2[0]-p1[0]); - r = p[1] - p1[1] - lam*(p2[1]-p1[1]); - } - else - { - lam = (p[1]-p1[1])/(p2[1]-p1[1]); - r = p[0] - p1[0] - lam*(p2[0]-p1[0]); - } - if ( lam >= -1e-10 && lam <= 1+1e-10 && fabs(r) <= 1e-10 ) - { - lami[0] = 1-lam; - return si; - } - } - } - } - break; - case 3: - default: - throw Exception("FindElementOfPoint<1> only implemented for mesh-dimension 1 and 2!"); - break; + auto & seg = (*mesh)[si]; + Point<3> p1 = (*mesh)[seg[0]]; + Point<3> p2 = (*mesh)[seg[1]]; + Vec<3> v1 = p2-p1; + Vec<3> v2 = p-p1; + double lam = v1*v2 / v1.Length2(); + double lam2 = (v2 - lam * v1).Length() / v1.Length(); + + if (lam >= -1e-10 && lam <= 1+1e-10 && lam2 < 1e-10) + { + lami[0] = 1-lam; + return si; + } } - return -1; } @@ -1085,37 +1043,26 @@ namespace netgen int * const indices, int numind) const { - NgArray dummy(numind); - for (int i = 0; i < numind; i++) dummy[i] = indices[i]+1; - + Point<3> pp(p[0], p[1], 0.); + if(mesh->GetDimension() == 3) + pp[2] = p[2]; + FlatArray ind(numind, indices); double lam3[3]; - int ind; - - if (mesh->GetDimension() == 2) + auto elnr = mesh->GetSurfaceElementOfPoint(pp, lam3, ind, build_searchtree); + if(elnr.IsValid()) { - Point<3> p2d(p[0], p[1], 0); - ind = mesh->GetElementOfPoint(p2d, lam3, &dummy, build_searchtree); - } - else - { - Point3d p3d(p[0], p[1], p[2]); - ind = mesh->GetSurfaceElementOfPoint(p3d, lam3, &dummy, build_searchtree); - } - - if (ind > 0) - { - if(mesh->SurfaceElement(ind).GetType()==QUAD || mesh->SurfaceElement(ind).GetType()==TRIG6) + if((*mesh)[elnr].GetType() == QUAD || (*mesh)[elnr].GetType() == TRIG6) { lami[0] = lam3[0]; lami[1] = lam3[1]; } - else + else { lami[0] = 1-lam3[0]-lam3[1]; lami[1] = lam3[0]; } } - return ind-1; + return elnr; } @@ -1126,13 +1073,9 @@ namespace netgen int * const indices, int numind) const { - NgArray dummy(numind); - for (int i = 0; i < numind; i++) dummy[i] = indices[i]+1; - - Point<3> p3d(p[0], p[1], p[2]); - int ind = - mesh->GetElementOfPoint(p3d, lami, &dummy, build_searchtree); - return ind-1; + Point<3> pp(p[0], p[1], p[2]); + FlatArray ind(numind, indices); + return mesh->GetElementOfPoint(pp, lami, ind, build_searchtree); } void Ngx_Mesh :: Curve (int order) @@ -1149,6 +1092,7 @@ namespace netgen void Ngx_Mesh :: EnableTable (string name, bool set) { mesh->GetTopology().EnableTable (name, set); + mesh->SetNextTimeStamp(); // update topology will do work } @@ -1226,8 +1170,16 @@ namespace netgen { NgLock meshlock (mesh->MajorMutex(), true); Refinement & ref = const_cast (mesh->GetGeometry()->GetRefinement()); - ::netgen::HPRefinement (*mesh, &ref, levels, parameter, setorders, ref_level); + ::netgen::HPRefinement (*mesh, &ref, SPLIT_HP, levels, parameter, setorders, ref_level); } + + void Ngx_Mesh::SplitAlfeld () + { + NgLock meshlock (mesh->MajorMutex(), true); + Refinement & ref = const_cast (mesh->GetGeometry()->GetRefinement()); + ::netgen::HPRefinement (*mesh, &ref, SPLIT_ALFELD, 1, 1.0/3.0, true, true); + } + int Ngx_Mesh::GetElementOrder (int enr) const { @@ -1240,9 +1192,15 @@ int Ngx_Mesh::GetElementOrder (int enr) const void Ngx_Mesh::GetElementOrders (int enr, int * ox, int * oy, int * oz) const { if (mesh->GetDimension() == 3) - mesh->VolumeElement(enr).GetOrder(*ox, *oy, *oz); + { + ElementIndex ei = IndexBASE() + enr-1; + mesh->VolumeElement(ei).GetOrder(*ox, *oy, *oz); + } else - mesh->SurfaceElement(enr).GetOrder(*ox, *oy, *oz); + { + SurfaceElementIndex sei = IndexBASE() + enr-1; + mesh->SurfaceElement(sei).GetOrder(*ox, *oy, *oz); + } } void Ngx_Mesh::SetElementOrder (int enr, int order) @@ -1288,6 +1246,36 @@ int Ngx_Mesh::GetClusterRepElement (int pi) const } +int Ngx_Mesh::GetElement_Faces (int elnr, int * faces, int * orient) const +{ + const MeshTopology & topology = mesh->GetTopology(); + if (mesh->GetDimension() == 3) + { + int num = topology.GetElementFaces (elnr+1, faces, orient); + for (int i = 0; i < num; i++) + faces[i]--; + return num; + } + else + { + faces[0] = elnr; + if (orient) orient[0] = 0; + return 1; + } +} + +int Ngx_Mesh::GetSurfaceElement_Face (int selnr, int * orient) const +{ + if (mesh->GetDimension() == 3) + { + const MeshTopology & topology = mesh->GetTopology(); + if (orient) + *orient = topology.GetSurfaceElementFaceOrientation (selnr+1); + return topology.GetFace (SurfaceElementIndex(selnr)); + } + return -1; +} + //HERBERT: falsche Anzahl von Argumenten diff --git a/libsrc/interface/read_fnf_mesh.cpp b/libsrc/interface/read_fnf_mesh.cpp index 39ad99ea..92c3978d 100644 --- a/libsrc/interface/read_fnf_mesh.cpp +++ b/libsrc/interface/read_fnf_mesh.cpp @@ -11,10 +11,10 @@ #include #include +#include "writeuser.hpp" namespace netgen { -#include "writeuser.hpp" bool ReadLine (istream & in, string & buf) { @@ -471,4 +471,5 @@ namespace netgen } mesh.ComputeNVertices(); } +static RegisterUserFormat reg_fnf ("Pro/ENGINEER Format", {".fnf"}, ReadFNFFormat, nullopt); } diff --git a/libsrc/interface/readuser.cpp b/libsrc/interface/readuser.cpp index c3aac4ae..f74f55a4 100644 --- a/libsrc/interface/readuser.cpp +++ b/libsrc/interface/readuser.cpp @@ -15,6 +15,12 @@ namespace netgen { + extern void ReadTETFormat (Mesh & mesh, const filesystem::path & filename); + extern void ReadFNFFormat (Mesh & mesh, const filesystem::path & filename); +#ifdef NG_CGNS + extern void ReadCGNSMesh (Mesh & mesh, const filesystem::path & filename); +#endif // NG_CGNS + void ReadFile (Mesh & mesh, const filesystem::path & filename) { @@ -295,7 +301,7 @@ namespace netgen in >> name; cout << IM(3) << len << " element are in group " << name << endl; int hi, index; - int fdnr, ednr; + int fdnr=-1, ednr=-1; in >> hi >> index >> hi >> hi; int codim = get<1>(element_map[index]); @@ -665,9 +671,11 @@ namespace netgen if ( ext == ".fnf" ) ReadFNFFormat (mesh, filename); +#ifdef NG_CGNS // .cgns file - CFD General Notation System if ( ext == ".cgns" ) ReadCGNSMesh (mesh, filename); +#endif // NG_CGNS if ( ext == ".stl" || ext == ".stlb" ) { @@ -695,6 +703,24 @@ namespace netgen } } } + + void ReadUserFormat(Mesh & mesh, const filesystem::path & filename, const string & format) + { + if(format == "") + return ReadFile(mesh, filename); + + if(!UserFormatRegister::HaveFormat(format)) + throw Exception("Unknown format: " + format); + + const auto entry = UserFormatRegister::Get(format); + if(!entry.read) + throw Exception("Reading format " + format + " is not implemented"); + + (*entry.read)(mesh, filename); + } + +static RegisterUserFormat reg_uni ("Universial Format", {".unv"}, ReadFile, nullopt); +static RegisterUserFormat reg_olaf ("Olaf Format", {".emt"}, ReadFile, nullopt); } diff --git a/libsrc/interface/rw_cgns.cpp b/libsrc/interface/rw_cgns.cpp index ad0869a7..458036e9 100644 --- a/libsrc/interface/rw_cgns.cpp +++ b/libsrc/interface/rw_cgns.cpp @@ -8,7 +8,7 @@ namespace netgen::cg { - typedef ngcore::ClosedHashTable, size_t> PointTable; + typedef ngcore::ClosedHashTable, size_t> PointTable; int getDim(ElementType_t type) { @@ -416,7 +416,7 @@ namespace netgen::cg for(auto i : Range(nv)) { - ngcore::INT<3,size_t> hash = {*reinterpret_cast(&x[i]), *reinterpret_cast(&y[i]), *reinterpret_cast(&z[i])}; + ngcore::IVec<3,size_t> hash = {*reinterpret_cast(&x[i]), *reinterpret_cast(&y[i]), *reinterpret_cast(&z[i])}; size_t pi_ng; size_t pos; // check if this point is new @@ -808,32 +808,9 @@ namespace netgen cg_close(fn); } -} - -#else // NG_CGNS - -namespace netgen -{ - void ReadCGNSMesh (Mesh & mesh, const filesystem::path & filename) - { - PrintMessage(1, "Could not import CGNS mesh: Netgen was built without CGNS support"); - } - - tuple, vector, vector>, vector> ReadCGNSFile(const filesystem::path & filename, int base) - { - throw Exception("Netgen was built without CGNS support"); - } - - void WriteCGNSMesh (const Mesh & mesh, const filesystem::path & filename) - { - PrintMessage(1, "Could not write CGNS mesh: Netgen was built without CGNS support"); - } - - void WriteCGNSFile(shared_ptr mesh, const filesystem::path & filename, vector fields, vector> values, vector locations) - { - throw Exception("Netgen was built without CGNS support"); - } - + static RegisterUserFormat reg_cgns ("CGNS Format", {".cgns"}, + static_cast(&ReadCGNSMesh), + static_cast(&WriteCGNSMesh)); } #endif // NG_CGNS diff --git a/libsrc/interface/rw_medit.cpp b/libsrc/interface/rw_medit.cpp new file mode 100644 index 00000000..d952d344 --- /dev/null +++ b/libsrc/interface/rw_medit.cpp @@ -0,0 +1,231 @@ +#include + +#include +#include "rw_medit.hpp" + +namespace netgen +{ +void ReadMeditFormat (Mesh & mesh, const filesystem::path & filename, map, int> & index_map) +{ + static Timer tall("ReadMeditMesh"); RegionTimer rtall(tall); + if(!filesystem::exists(filename)) + throw Exception("File does not exist: " + filename.string()); + auto fin = ifstream(filename); + string token; + int version, dim; + mesh.ClearFaceDescriptors(); + + int index_cnt[4] = {0,0,0,0}; + auto getIndex = [&](int eldim, int index) { + if(index_map.count({eldim,index})==0) { + auto n = ++index_cnt[eldim]; + index_map[{eldim, index}] = n; + if(eldim==2) { + auto fd = FaceDescriptor(n-1,1,0,0); + fd.SetBCProperty(n); + mesh.AddFaceDescriptor (fd); + } + } + return index_map[{eldim, index}]; + }; + + while(true) { + fin >> token; + int index; + // cout << "token: " << token << endl; + if(token == "End") { + break; + } + else if(token == "" || std::regex_match(token, std::regex("^[\\s]*$"))) { + continue; + } + else if(token == "MeshVersionFormatted") { + fin >> version; + } + else if(token == "Dimension") { + fin >> dim; + mesh.SetDimension(dim); + } + else if(token == "Vertices") { + int nvert; + fin >> nvert; + Point<3> p{0.,0.,0.}; + for([[maybe_unused]] auto k : Range(nvert)) { + for(auto i : Range(dim)) + fin >> p[i]; + fin >> index; + mesh.AddPoint(p); + } + } + else if(token == "Edges") { + int nedge; + fin >> nedge; + Segment seg; + for([[maybe_unused]] auto k : Range(nedge)) { + for(auto i : Range(2)) + fin >> seg[i]; + fin >> seg.edgenr; + seg.edgenr = getIndex(1, seg.edgenr); + seg.si = seg.edgenr; + mesh.AddSegment(seg); + } + } + else if(token == "Triangles") { + int ntrig, index; + fin >> ntrig; + Element2d sel; + for([[maybe_unused]] auto k : Range(ntrig)) { + for(auto i : Range(3)) + fin >> sel[i]; + fin >> index; + sel.SetIndex(getIndex(2, index)); + mesh.AddSurfaceElement(sel); + } + } + else if(token == "Tetrahedra") { + int ntet; + fin >> ntet; + Element el(4); + for([[maybe_unused]] auto k : Range(ntet)) { + for(auto i : Range(4)) + fin >> el[i]; + fin >> index; + el.SetIndex(getIndex(3, index)); + el.Invert(); + mesh.AddVolumeElement(el); + } + } + else if(token == "Corners") { + int ncorners; + fin >> ncorners; + Element0d el; + for([[maybe_unused]] auto k : Range(ncorners)) { + fin >> el.pnum; + } + } + else if(token == "RequiredVertices") { + int nverts; + fin >> nverts; + int vert; + for([[maybe_unused]] auto k : Range(nverts)) { + fin >> vert; + } + } + else if(token == "Normals") { + int nnormals; + fin >> nnormals; + Vec<3> normal; + for([[maybe_unused]] auto k : Range(nnormals)) { + fin >> normal[0]; + fin >> normal[1]; + fin >> normal[2]; + } + } + else if(token == "NormalAtVertices") { + int nnormals; + fin >> nnormals; + int vert; + int normal; + for([[maybe_unused]] auto k : Range(nnormals)) { + fin >> normal; + fin >> vert; + } + } + else if(token == "Tangents") { + int ntangents; + fin >> ntangents; + Vec<3> tangent; + for([[maybe_unused]] auto k : Range(ntangents)) { + fin >> tangent[0]; + fin >> tangent[1]; + fin >> tangent[2]; + } + } + else if(token == "TangentAtVertices") { + int ntangents; + fin >> ntangents; + int vert; + int tangent; + for([[maybe_unused]] auto k : Range(ntangents)) { + fin >> tangent; + fin >> vert; + } + } + else if(token == "Ridges") { + int nridges; + fin >> nridges; + int ridge; + for([[maybe_unused]] auto k : Range(nridges)) { + fin >> ridge; + } + } + else { + cout << "unknown token " << token << endl; + int nitems; + fin >> nitems; + string s; + for([[maybe_unused]] auto i : Range(nitems)) + fin >> s; // read one line + } + } +} + +void ReadMeditFormat (Mesh & mesh, const filesystem::path & filename) +{ + map, int> index_map; + ReadMeditFormat(mesh, filename, index_map); +} + + +void WriteMeditFormat (const Mesh & mesh, const filesystem::path & filename, map, int> & index_map) +{ + static Timer tall("WriteMeditFormat"); RegionTimer rtall(tall); + auto fout = ofstream(filename); + fout << "MeshVersionFormatted 2\n"; + fout << "Dimension\n" << mesh.GetDimension() << endl; + fout << "Vertices\n" << mesh.GetNP() << endl; + int base_index = 0; + int max_index = 0; + auto getIndex = [&](int i, int dim) { + max_index = max(max_index, i+base_index); + auto index = base_index+i; + index_map[{dim,i}] = index; + return index; + }; + fout << setprecision(16); + + for(const auto & p : mesh.Points()) + { + for(auto i : Range(mesh.GetDimension())) + fout << p[i] << ' '; + fout << getIndex(1, 0) << endl; + } + + base_index = max_index; + fout << "Edges\n" << mesh.GetNSeg() << endl; + for(const auto & seg : mesh.LineSegments()) + fout << seg[0] << ' ' << seg[1] << ' ' << getIndex(seg.edgenr, 1) << endl; + + base_index = max_index; + fout << "Triangles\n" << mesh.GetNSE() << endl; + for(const auto & sel : mesh.SurfaceElements()) + fout << sel[0] << ' ' << sel[1] << ' ' << sel[2] << ' ' << getIndex(sel.GetIndex(), 2) << endl; + + base_index = max_index; + fout << "Tetrahedra\n" << mesh.GetNE() << endl; + for(const auto & el : mesh.VolumeElements()) + fout << el[0] << ' ' << el[1] << ' ' << el[2] << ' ' << el[3] << '\t' << getIndex(el.GetIndex(), 3) << endl; + + fout << "End" << endl; +} + +void WriteMeditFormat (const Mesh & mesh, const filesystem::path & filename) +{ + map, int> index_map; + WriteMeditFormat(mesh, filename, index_map); +} + +static RegisterUserFormat reg_medit ("Medit Format", {".mesh"}, + static_cast(ReadMeditFormat), + static_cast(WriteMeditFormat)); +} // namespace netgen diff --git a/libsrc/interface/rw_medit.hpp b/libsrc/interface/rw_medit.hpp new file mode 100644 index 00000000..a38b794c --- /dev/null +++ b/libsrc/interface/rw_medit.hpp @@ -0,0 +1,11 @@ +#include +#include "writeuser.hpp" + +namespace netgen +{ +DLL_HEADER void ReadMeditFormat (Mesh & mesh, const filesystem::path & filename, map, int> & index_map); +DLL_HEADER void ReadMeditFormat (Mesh & mesh, const filesystem::path & filename); + +DLL_HEADER void WriteMeditFormat (const Mesh & mesh, const filesystem::path & filename, map, int> & index_map); +DLL_HEADER void WriteMeditFormat (const Mesh & mesh, const filesystem::path & filename); +} // namespace netgen diff --git a/libsrc/interface/writeOpenFOAM15x.cpp b/libsrc/interface/writeOpenFOAM15x.cpp index 8b185d75..fcfacdae 100644 --- a/libsrc/interface/writeOpenFOAM15x.cpp +++ b/libsrc/interface/writeOpenFOAM15x.cpp @@ -31,10 +31,10 @@ #include #include "../general/gzstream.h" +#include "writeuser.hpp" namespace netgen { -#include "writeuser.hpp" extern MeshingParameters mparam; @@ -215,7 +215,8 @@ namespace netgen // Check if the face is a surface element (boundary face) // if not, add the current volume element and the corresponding face into // the owner list - int surfelem = meshtopo.GetFace2SurfaceElement(absfacenr); + // int surfelem = meshtopo.GetFace2SurfaceElement1(absfacenr); + int surfelem = meshtopo.GetFace2SurfaceElement(absfacenr-1)+1; if(!surfelem) { // If it is a new face which has not been listed before, @@ -600,13 +601,13 @@ namespace netgen void WriteOpenFOAM15xFormat (const Mesh & mesh, const filesystem::path & dirname, const bool compressed) { bool error = false; - char casefiles[256]; + // char casefiles[256]; // Make sure that the mesh data has been updated const_cast (mesh).Compress(); const_cast (mesh).CalcSurfacesOfNode(); const_cast (mesh).RebuildSurfaceElementLists(); - const_cast (mesh).BuildElementSearchTree(); + const_cast (mesh).BuildElementSearchTree(3); int np = mesh.GetNP(); @@ -757,5 +758,11 @@ namespace netgen cout << "Error in OpenFOAM 1.5+ Export.... Aborted!\n"; } } + +void WriteOpenFOAM15xFormatCompressed (const Mesh & mesh, const filesystem::path & dirname) { WriteOpenFOAM15xFormat(mesh, dirname, true); } +void WriteOpenFOAM15xFormatUncompressed (const Mesh & mesh, const filesystem::path & dirname) { WriteOpenFOAM15xFormat(mesh, dirname, false); } + +static RegisterUserFormat reg_openfoam ("OpenFOAM 1.5+ Format", {"*"}, nullopt, WriteOpenFOAM15xFormatUncompressed); +static RegisterUserFormat reg_openfoam_compressed ("OpenFOAM 1.5+ Compressed", {"*"}, nullopt, WriteOpenFOAM15xFormatCompressed); } diff --git a/libsrc/interface/writeabaqus.cpp b/libsrc/interface/writeabaqus.cpp index 8d698b0b..34535a63 100644 --- a/libsrc/interface/writeabaqus.cpp +++ b/libsrc/interface/writeabaqus.cpp @@ -10,19 +10,108 @@ #include #include -namespace netgen -{ #include "writeuser.hpp" +namespace netgen +{ +using std::vector; +struct AbaqusElementType +{ + const char * name; + const vector permutation; + + AbaqusElementType(const char * name, const vector & permutation) + : name(name), permutation(permutation) + {} +}; + +static inline const AbaqusElementType & GetAbaqusType(int dim, int num_nodes) +{ + // maps num_nodes to AbaqusElementType for each dimension + typedef std::map AbaqusElementTypes; + static const std::map abaqus_eltypes[3] = + { + // 1D + AbaqusElementTypes{ + {2, AbaqusElementType{"T2D2", vector{0,1}}}, + }, + // 2D + AbaqusElementTypes{ + {3, AbaqusElementType{"CPS3", vector{0,1,2}}}, + }, + // 3D + AbaqusElementTypes{ + {4, AbaqusElementType{"C3D4", vector{0,1,3,2}}}, + {10, AbaqusElementType{"C3D10", vector{0,1,3,2,4,8,6,5,7,9}}}, + } + }; + + const auto & eltypes = abaqus_eltypes[dim-1]; + if (eltypes.count(num_nodes) > 0) + return eltypes.at(num_nodes); + else + throw Exception("unsupported " + ToString(dim)+"d Element type with " + ToString(num_nodes) + " nodes"); +} + +static void WritePoints ( const Mesh & mesh, ostream & out ) +{ + out << "*Node" << endl; + for(auto pi : mesh.Points().Range() ) + { + out << pi+1-IndexBASE() << ", "; + auto p = mesh[pi]; + out << p[0] << ", " << p[1] << ", " << p[2] << '\n'; + } +} + +template +static void WriteElement(ostream & out, const Mesh& mesh, ElIndex ei, const vector & permutation, int & el_counter) +{ + el_counter++; + auto el = mesh[ei]; + out << el_counter; + for(auto i : Range(el.PNums())) + out << ", " << el[permutation[i]]+1-IndexBASE(); + out << '\n'; +} + +template +static void WriteElements ( ostream & out, const Mesh & mesh, int dim, const Elements & el_range, int & el_counter) +{ + // map index, num_nodes to elements + std::map, Array> elset_map; + + for(auto ei : el_range) + { + const auto & el = mesh[ei]; + int index = 0; + if constexpr(std::is_same_v) + index = el.edgenr; + else + index = el.GetIndex(); + elset_map[{index, el.GetNP()}].Append(ei); + } + + for(auto & [key, elems] : elset_map) + { + auto [index, num_nodes] = key; + auto name = mesh.GetRegionName(elems[0]); + if (name == "") name = "default"; + PrintMessage (5, index, ": ", name); + const auto & eltype = GetAbaqusType(dim, num_nodes) ; + out << "*Element, type=" << eltype.name << ", ELSET=" << name << endl; + for(auto ei : elems) + WriteElement(out, mesh, ei, eltype.permutation, el_counter); + } +} void WriteAbaqusFormat (const Mesh & mesh, const filesystem::path & filename) { - - cout << "\nWrite Abaqus Volume Mesh" << endl; + PrintMessage (1, "Write Abaqus Mesh"); ofstream outfile (filename); @@ -31,96 +120,17 @@ void WriteAbaqusFormat (const Mesh & mesh, outfile.precision(8); - outfile << "*Node" << endl; - - int np = mesh.GetNP(); - int ne = mesh.GetNE(); - int i, j, k; - - for (i = 1; i <= np; i++) - { - outfile << i << ", "; - outfile << mesh.Point(i)(0) << ", "; - outfile << mesh.Point(i)(1) << ", "; - outfile << mesh.Point(i)(2) << "\n"; - } - - int elemcnt = 0; //element counter - int finished = 0; - int indcnt = 1; //index counter - - while (!finished) - { - int actcnt = 0; - const Element & el1 = mesh.VolumeElement(1); - int non = el1.GetNP(); - if (non == 4) - { - outfile << "*Element, type=C3D4, ELSET=PART" << indcnt << endl; - } - else if (non == 10) - { - outfile << "*Element, type=C3D10, ELSET=PART" << indcnt << endl; - } - else - { - cout << "unsupported Element type!!!" << endl; - } - - for (i = 1; i <= ne; i++) - { - const Element & el = mesh.VolumeElement(i); - - if (el.GetIndex() == indcnt) - { - actcnt++; - if (el.GetNP() != non) - { - cout << "different element-types in a subdomain are not possible!!!" << endl; - continue; - } - - elemcnt++; - outfile << elemcnt << ", "; - if (non == 4) - { - outfile << el.PNum(1) << ", "; - outfile << el.PNum(2) << ", "; - outfile << el.PNum(4) << ", "; - outfile << el.PNum(3) << "\n"; - } - else if (non == 10) - { - outfile << el.PNum(1) << ", "; - outfile << el.PNum(2) << ", "; - outfile << el.PNum(4) << ", "; - outfile << el.PNum(3) << ", "; - outfile << el.PNum(5) << ", "; - outfile << el.PNum(9) << ", "; - outfile << el.PNum(7) << ", " << "\n"; - outfile << el.PNum(6) << ", "; - outfile << el.PNum(8) << ", "; - outfile << el.PNum(10) << "\n"; - } - else - { - cout << "unsupported Element type!!!" << endl; - for (j = 1; j <= el.GetNP(); j++) - { - outfile << el.PNum(j); - if (j != el.GetNP()) outfile << ", "; - } - outfile << "\n"; - } - } - } - indcnt++; - if (elemcnt == ne) {finished = 1; cout << "all elements found by Index!" << endl;} - if (actcnt == 0) {finished = 1;} - } + int element_counter = 0; + WritePoints(mesh, outfile); + if(mesh.GetDimension() < 3) + WriteElements(outfile, mesh, 1, mesh.LineSegments().Range(), element_counter); + WriteElements(outfile, mesh, 2, mesh.SurfaceElements().Range(), element_counter); + WriteElements(outfile, mesh, 3, mesh.VolumeElements().Range(), element_counter); + // Write identifications (untested!) if (mesh.GetIdentifications().GetMaxNr()) { + const auto np = mesh.GetNP(); // periodic identification, implementation for // Helmut J. Boehm, TU Vienna @@ -137,27 +147,27 @@ void WriteAbaqusFormat (const Mesh & mesh, NgArray pairs; NgBitArray master(np), help(np); master.Set(); - for (i = 1; i <= 3; i++) + for (int i = 1; i <= 3; i++) { mesh.GetIdentifications().GetPairs (i, pairs); help.Clear(); - for (j = 1; j <= pairs.Size(); j++) + for (int j = 1; j <= pairs.Size(); j++) { help.Set (pairs.Get(j).I1()); } master.And (help); } - for (i = 1; i <= np; i++) + for (int i = 1; i <= np; i++) if (master.Test(i)) masternode = i; cout << "masternode = " << masternode << " = " << mesh.Point(masternode) << endl; NgArray minions(3); - for (i = 1; i <= 3; i++) + for (int i = 1; i <= 3; i++) { mesh.GetIdentifications().GetPairs (i, pairs); - for (j = 1; j <= pairs.Size(); j++) + for (int j = 1; j <= pairs.Size(); j++) { if (pairs.Get(j).I1() == masternode) minions.Elem(i) = pairs.Get(j).I2(); @@ -178,12 +188,12 @@ void WriteAbaqusFormat (const Mesh & mesh, << "**POINT_fixed\n" << "**\n" << "*BOUNDARY, OP=NEW\n"; - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) outfile << masternode << ", " << j << ",, 0.\n"; outfile << "**\n" << "*BOUNDARY, OP=NEW\n"; - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) { Vec3d v(mesh.Point(masternode), mesh.Point(minions.Get(j))); double vlen = v.Length(); @@ -202,18 +212,18 @@ void WriteAbaqusFormat (const Mesh & mesh, NgBitArray eliminated(np); eliminated.Clear(); - for (i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++) + for (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++) { mesh.GetIdentifications().GetPairs (i, pairs); if (!pairs.Size()) continue; - for (j = 1; j <= pairs.Size(); j++) + for (int j = 1; j <= pairs.Size(); j++) if (pairs.Get(j).I1() != masternode && !eliminated.Test(pairs.Get(j).I2())) { eliminated.Set (pairs.Get(j).I2()); - for (k = 1; k <= 3; k++) + for (int k = 1; k <= 3; k++) { mpc << "4" << "\n"; mpc << pairs.Get(j).I2() << "," << k << ", -1.0, "; @@ -226,7 +236,8 @@ void WriteAbaqusFormat (const Mesh & mesh, } - cout << "done" << endl; + PrintMessage(1, "done"); } +static RegisterUserFormat reg_abaqus ("Abaqus Format", {".mesh"}, nullopt, WriteAbaqusFormat); } diff --git a/libsrc/interface/writediffpack.cpp b/libsrc/interface/writediffpack.cpp index 1c6ba159..9c481ba9 100644 --- a/libsrc/interface/writediffpack.cpp +++ b/libsrc/interface/writediffpack.cpp @@ -13,14 +13,13 @@ #include #include +#include "writeuser.hpp" namespace netgen { -#include "writeuser.hpp" void WriteDiffPackFormat (const Mesh & mesh, - const NetgenGeometry & geom, const filesystem::path & filename) { // double scale = globflags.GetNumFlag ("scale", 1); @@ -41,7 +40,7 @@ void WriteDiffPackFormat (const Mesh & mesh, int nse = mesh.GetNSE(); NgArray BIname; NgArray BCsinpoint; - int i, j, k, l; + // int i, j, k, l; outfile.precision(6); @@ -59,18 +58,18 @@ void WriteDiffPackFormat (const Mesh & mesh, " Only one subdomain : dpFALSE\n" " Lattice data ? 0\n\n\n\n"; - for (i = 1; i <= nse; i++) + for (int i = 1; i <= nse; i++) { int BI=mesh.GetFaceDescriptor(mesh.SurfaceElement(i).GetIndex()).BCProperty(); int nbi=BIname.Size(); int found=0; - for (j = 1; j <= nbi; j++) + for (int j = 1; j <= nbi; j++) if(BI == BIname.Get(j)) found = 1; if( ! found ) BIname.Append(BI); } outfile << " " << BIname.Size() << " Boundary indicators: "; - for (i =1 ; i <= BIname.Size(); i++) + for (int i =1 ; i <= BIname.Size(); i++) outfile << BIname.Get(i) << " "; outfile << "\n\n\n"; @@ -93,7 +92,8 @@ void WriteDiffPackFormat (const Mesh & mesh, } - for (i = 1; i <= np; i++) + // for (int i = 1; i <= np; i++) + for (PointIndex i : mesh.Points().Range()) { const Point3d & p = mesh.Point(i); @@ -115,14 +115,14 @@ void WriteDiffPackFormat (const Mesh & mesh, NgFlatArray sels = point2sel[i]; for (int jj = 0; jj < sels.Size(); jj++) { - for (k = 1; k <= mesh[sels[jj]].GetNP(); k++) + for (int k = 1; k <= mesh[sels[jj]].GetNP(); k++) { if(mesh[sels[jj]].PNum(k)==i) { int BC=mesh.GetFaceDescriptor(mesh[sels[jj]].GetIndex()).BCProperty(); int nbcsp=BCsinpoint.Size(); int found = 0; - for (l = 1; l <= nbcsp; l++) + for (int l = 1; l <= nbcsp; l++) if(BC == BCsinpoint.Get(l)) found = 1; if( ! found ) BCsinpoint.Append(BC); } @@ -130,7 +130,7 @@ void WriteDiffPackFormat (const Mesh & mesh, } int nbcsp = BCsinpoint.Size(); outfile << "[" << nbcsp << "] "; - for (j = 1; j <= nbcsp; j++) + for (int j = 1; j <= nbcsp; j++) outfile << BCsinpoint.Get(j) << " "; outfile << "\n"; } @@ -147,7 +147,7 @@ void WriteDiffPackFormat (const Mesh & mesh, " - the global node numbers of the nodes in the element.\n" "#\n"; - for (i = 1; i <= ne; i++) + for (int i = 1; i <= ne; i++) { const Element & el = mesh.VolumeElement(i); outfile.width(5); @@ -245,7 +245,8 @@ void WriteDiffPackFormat (const Mesh & mesh, " - the boundary indicators that are set (ON) if any.\n" "#\n"; - for (i = 1; i <= np; i++) + // for (i = 1; i <= np; i++) + for (PointIndex i : mesh.Points().Range()) { const Point3d & p = mesh.Point(i); @@ -322,4 +323,5 @@ void WriteDiffPackFormat (const Mesh & mesh, } } } +static RegisterUserFormat reg_surface("DIFFPACK Format", {".mesh"}, nullopt, WriteDiffPackFormat); } diff --git a/libsrc/interface/writeelmer.cpp b/libsrc/interface/writeelmer.cpp index ebaa97f7..75cec877 100644 --- a/libsrc/interface/writeelmer.cpp +++ b/libsrc/interface/writeelmer.cpp @@ -57,7 +57,7 @@ void WriteElmerFormat (const Mesh &mesh, int ne = mesh.GetNE(); int nse = mesh.GetNSE(); int i, j; - char str[200]; + // char str[200]; int inverttets = mparam.inverttets; int invertsurf = mparam.inverttrigs; @@ -197,4 +197,6 @@ void WriteElmerFormat (const Mesh &mesh, outfile_h << tmap[eltype] << " " << count << "\n"; } +static RegisterUserFormat reg_elmer ("Elmer Format", {"*"}, nullopt, WriteElmerFormat); + } diff --git a/libsrc/interface/writefeap.cpp b/libsrc/interface/writefeap.cpp index 0b5aad61..bdacdd7e 100644 --- a/libsrc/interface/writefeap.cpp +++ b/libsrc/interface/writefeap.cpp @@ -13,12 +13,13 @@ #include #include +#include "writeuser.hpp" + namespace netgen { extern MeshingParameters mparam; -#include "writeuser.hpp" void WriteFEAPFormat (const Mesh & mesh, @@ -219,4 +220,5 @@ void WriteFEAPFormat (const Mesh & mesh, cout << "done" << endl; } +static RegisterUserFormat reg_feap ("FEAP Format", {".mesh"}, nullopt, WriteFEAPFormat); } diff --git a/libsrc/interface/writefluent.cpp b/libsrc/interface/writefluent.cpp index 43cb5fe3..6cf64b72 100644 --- a/libsrc/interface/writefluent.cpp +++ b/libsrc/interface/writefluent.cpp @@ -10,11 +10,10 @@ #include #include -namespace netgen -{ - #include "writeuser.hpp" +namespace netgen +{ void WriteFluentFormat (const Mesh & mesh, @@ -67,7 +66,7 @@ void WriteFluentFormat (const Mesh & mesh, int i2, j2; NgArray surfaceelp; NgArray surfaceeli; - NgArray locels; + Array locels; //no cells=no tets //no faces=2*tets @@ -80,7 +79,7 @@ void WriteFluentFormat (const Mesh & mesh, snprintf (str, size(str), "(13 (4 1 %x 2 3)(",noverbface); //hexadecimal!!! outfile << str << endl; - const_cast (mesh).BuildElementSearchTree(); + const_cast (mesh).BuildElementSearchTree(3); for (i = 1; i <= ne; i++) { @@ -118,12 +117,9 @@ void WriteFluentFormat (const Mesh & mesh, int eli2 = 0; int stopsig = 0; - for (i2 = 1; i2 <= nel; i2++) + for (auto locind : locels) { - locind = locels.Get(i2); - //cout << " locind=" << locind << endl; - - Element el2 = mesh.VolumeElement(locind); + Element el2 = mesh[locind]; //if (inverttets) // el2.Invert(); @@ -131,7 +127,7 @@ void WriteFluentFormat (const Mesh & mesh, { el2.GetFace(j2, face2); - if (face2.HasFace(face)) {eli2 = locind; stopsig = 1; break;} + if (face2.HasFace(face)) {eli2 = locind+1; stopsig = 1; break;} } if (stopsig) break; } @@ -190,4 +186,5 @@ void WriteFluentFormat (const Mesh & mesh, cout << "done" << endl; } +static RegisterUserFormat reg_fluent ("Fluent Format", {".mesh"}, nullopt, WriteFluentFormat); } diff --git a/libsrc/interface/writegmsh.cpp b/libsrc/interface/writegmsh.cpp index 1048f582..58e7f8e6 100644 --- a/libsrc/interface/writegmsh.cpp +++ b/libsrc/interface/writegmsh.cpp @@ -17,10 +17,10 @@ #include #include #include +#include "writeuser.hpp" namespace netgen { -#include "writeuser.hpp" extern MeshingParameters mparam; @@ -31,7 +31,6 @@ namespace netgen */ void WriteGmshFormat (const Mesh & mesh, - const NetgenGeometry & geom, const filesystem::path & filename) { ofstream outfile (filename); @@ -196,6 +195,7 @@ void WriteGmshFormat (const Mesh & mesh, } +static RegisterUserFormat reg_gmsh ("Gmsh Format", {".gmsh"}, nullopt, WriteGmshFormat); } diff --git a/libsrc/interface/writegmsh2.cpp b/libsrc/interface/writegmsh2.cpp index c80208c4..74843195 100644 --- a/libsrc/interface/writegmsh2.cpp +++ b/libsrc/interface/writegmsh2.cpp @@ -20,10 +20,10 @@ #include #include #include +#include "writeuser.hpp" namespace netgen { -#include "writeuser.hpp" extern MeshingParameters mparam; @@ -48,7 +48,6 @@ namespace netgen * */ void WriteGmsh2Format (const Mesh & mesh, - const NetgenGeometry & geom, const filesystem::path & filename) { ofstream outfile (filename); @@ -59,7 +58,7 @@ namespace netgen int np = mesh.GetNP(); /// number of points in mesh int ne = mesh.GetNE(); /// number of 3D elements in mesh int nse = mesh.GetNSE(); /// number of surface elements (BC) - int i, j, k, l; + // int i, j, k, l; /* @@ -67,8 +66,8 @@ namespace netgen */ if ((ne > 0) - && (mesh.VolumeElement(1).GetNP() <= 10) - && (mesh.SurfaceElement(1).GetNP() <= 6)) + && (mesh.VolumeElements().First().GetNP() <= 10) + && (mesh.SurfaceElements().First().GetNP() <= 6)) { cout << "Write GMSH v2.xx Format \n"; cout << "The GMSH v2.xx export is currently available for elements upto 2nd Order\n" << endl; @@ -87,7 +86,7 @@ namespace netgen outfile << "$Nodes\n"; outfile << np << "\n"; - for (i = 1; i <= np; i++) + for (int i = 1; i <= np; i++) { const Point3d & p = mesh.Point(i); outfile << i << " "; /// node number @@ -102,13 +101,13 @@ namespace netgen outfile << "$Elements\n"; outfile << ne + nse << "\n"; //// number of elements + number of surfaces BC - for (i = 1; i <= nse; i++) + for (auto sei : Range(mesh.SurfaceElements())) { int elType = 0; - Element2d el = mesh.SurfaceElement(i); + Element2d el = mesh[sei]; // .SurfaceElement(i); if(invertsurf) el.Invert(); - + if(el.GetNP() == 3) elType = GMSH_TRIG; //// GMSH Type for a 3 node triangle if(el.GetNP() == 6) elType = GMSH_TRIG6; //// GMSH Type for a 6 node triangle if(elType == 0) @@ -117,7 +116,7 @@ namespace netgen return; } - outfile << i; + outfile << sei-IndexBASE(sei)+1; outfile << " "; outfile << elType; outfile << " "; @@ -126,7 +125,7 @@ namespace netgen outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; /// that means that physical entity = elementary entity (arbitrary approach) outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; - for (j = 1; j <= el.GetNP(); j++) + for (int j = 1; j <= el.GetNP(); j++) { outfile << " "; outfile << el.PNum(triGmsh[j]); @@ -134,12 +133,12 @@ namespace netgen outfile << "\n"; } - - for (i = 1; i <= ne; i++) + for (ElementIndex ei : Range(mesh.VolumeElements())) { + int i = ei-IndexBASE(ei)+1; int elType = 0; - Element el = mesh.VolumeElement(i); + Element el = mesh[ei]; if (inverttets) el.Invert(); if(el.GetNP() == 4) elType = GMSH_TET; //// GMSH Element type for 4 node tetrahedron @@ -161,7 +160,7 @@ namespace netgen outfile << " "; outfile << 100000 + el.GetIndex(); /// volume number outfile << " "; - for (j = 1; j <= el.GetNP(); j++) + for (int j = 1; j <= el.GetNP(); j++) { outfile << " "; outfile << el.PNum(tetGmsh[j]); @@ -194,7 +193,7 @@ namespace netgen outfile << "$Nodes\n"; outfile << np << "\n"; - for (i = 1; i <= np; i++) + for (int i = 1; i <= np; i++) { const Point3d & p = mesh.Point(i); outfile << i << " "; /// node number @@ -208,7 +207,7 @@ namespace netgen outfile << "$Elements\n"; outfile << nse << "\n"; - for (k = 1; k <= nse; k++) + for (int k = 1; k <= nse; k++) { int elType = 0; @@ -233,7 +232,7 @@ namespace netgen outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; /// that means that physical entity = elementary entity (arbitrary approach) outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; - for (l = 1; l <= el.GetNP(); l++) + for (int l = 1; l <= el.GetNP(); l++) { outfile << " "; if((elType == GMSH_TRIG) || (elType == GMSH_TRIG6)) @@ -258,6 +257,7 @@ namespace netgen cout << " Invalid element type for Gmsh v2.xx Export Format !\n"; } } // End: WriteGmsh2Format +static RegisterUserFormat reg_gmsh2 ("Gmsh2 Format", {".gmsh2"}, nullopt, WriteGmsh2Format); } // End: namespace netgen diff --git a/libsrc/interface/writejcm.cpp b/libsrc/interface/writejcm.cpp index 7732b413..1c21f322 100644 --- a/libsrc/interface/writejcm.cpp +++ b/libsrc/interface/writejcm.cpp @@ -11,12 +11,12 @@ #include #include -namespace netgen -{ #include "writeuser.hpp" +namespace netgen +{ + void WriteJCMFormat (const Mesh & mesh, - const NetgenGeometry & geom, const filesystem::path & filename) { if (mesh.GetDimension() != 3) @@ -33,7 +33,7 @@ void WriteJCMFormat (const Mesh & mesh, int np = mesh.GetNP(); // Identic points - NgArray identmap1, identmap2, identmap3; + idmap_type identmap1, identmap2, identmap3; mesh.GetIdentifications().GetMap(1, identmap1); mesh.GetIdentifications().GetMap(2, identmap2); mesh.GetIdentifications().GetMap(3, identmap3); @@ -52,19 +52,21 @@ void WriteJCMFormat (const Mesh & mesh, for (j = 1; j <= 4; j++) for (jj = 1; jj <=4; jj++) { - if (identmap1.Elem(el.PNum(j)) == el.PNum(jj)) + // if (identmap1.Elem(el.PNum(j)) == el.PNum(jj)) + if (identmap1[el.PNum(j)] == el.PNum(jj)) { cout << "\n Error: two points on a tetrahedron identified (1) with each other" << "\n REFINE MESH !" << endl; return; } - if (identmap2.Elem(el.PNum(j)) == el.PNum(jj)) + // if (identmap2.Elem(el.PNum(j)) == el.PNum(jj)) + if (identmap2[el.PNum(j)] == el.PNum(jj)) { cout << "\n Error: two points on a tetrahedron identified (2) with each other" << "\n REFINE MESH !" << endl; return; } - if (identmap3.Elem(el.PNum(j)) == el.PNum(jj)) + if (identmap3[el.PNum(j)] == el.PNum(jj)) { cout << "\n Error: two points on a tetrahedron identified (3) with each other" << "\n REFINE MESH !" << endl; @@ -271,6 +273,7 @@ void WriteJCMFormat (const Mesh & mesh, int npid1 = 0; int npid2 = 0; int npid3 = 0; + /* for (i=1; i<=np; i++) { if (identmap1.Elem(i)) @@ -280,6 +283,10 @@ void WriteJCMFormat (const Mesh & mesh, if (identmap3.Elem(i)) npid3++; } + */ + for (auto pi : identmap1) if (pi.IsValid()) npid1++; + for (auto pi : identmap2) if (pi.IsValid()) npid1++; + for (auto pi : identmap3) if (pi.IsValid()) npid1++; outfile << "\n"; outfile << "# Boundary triangles\n"; @@ -302,31 +309,31 @@ void WriteJCMFormat (const Mesh & mesh, outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << "\n"; if (mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() == bc_at_infinity) outfile << "-2\n\n"; - else if (identmap1.Elem(el.PNum(1)) - &&identmap1.Elem(el.PNum(2)) - &&identmap1.Elem(el.PNum(3))) + else if (identmap1[el.PNum(1)].IsValid() + &&identmap1[el.PNum(2)].IsValid() + &&identmap1[el.PNum(3)].IsValid()) { outfile << "-1\n"; for (j = 1; j <= 3; j++) - outfile << identmap1.Elem(el.PNum(j))<<"\n"; + outfile << identmap1[el.PNum(j)]<<"\n"; outfile << "\n"; } - else if (identmap2.Elem(el.PNum(1)) - &&identmap2.Elem(el.PNum(2)) - &&identmap2.Elem(el.PNum(3))) + else if (identmap2[el.PNum(1)].IsValid() + &&identmap2[el.PNum(2)].IsValid() + &&identmap2[el.PNum(3)].IsValid()) { outfile << "-1\n"; for (j = 1; j <= 3; j++) - outfile << identmap2.Elem(el.PNum(j))<<"\n"; + outfile << identmap2[el.PNum(j)]<<"\n"; outfile << "\n"; } - else if (identmap3.Elem(el.PNum(1)) - &&identmap3.Elem(el.PNum(2)) - &&identmap3.Elem(el.PNum(3))) + else if (identmap3[el.PNum(1)].IsValid() + &&identmap3[el.PNum(2)].IsValid() + &&identmap3[el.PNum(3)].IsValid()) { outfile << "-1\n"; for (j = 1; j <= 3; j++) - outfile << identmap3.Elem(el.PNum(j))<<"\n"; + outfile << identmap3[el.PNum(j)]<<"\n"; outfile << "\n"; } else @@ -373,10 +380,10 @@ void WriteJCMFormat (const Mesh & mesh, outfile << "-2\n\n"; cout << "\nWarning: Quadrilateral at infinity found (this should not occur)!"<= 5 ) jj = jj - 4; - outfile << identmap1.Elem(el.PNum(jj))<<"\n"; + outfile << identmap1[el.PNum(jj)]<<"\n"; } outfile << "\n"; } - else if ( identmap2.Elem(el.PNum(1)) && - identmap2.Elem(el.PNum(2)) && - identmap2.Elem(el.PNum(3)) && - identmap2.Elem(el.PNum(4)) ) + else if ( identmap2[el.PNum(1)].IsValid() && + identmap2[el.PNum(2)].IsValid() && + identmap2[el.PNum(3)].IsValid() && + identmap2[el.PNum(4)].IsValid() ) { outfile << "-1\n"; for (j = 1; j <= 4; j++) @@ -399,14 +406,14 @@ void WriteJCMFormat (const Mesh & mesh, jj = j + ct; if ( jj >= 5 ) jj = jj - 4; - outfile << identmap2.Elem(el.PNum(jj))<<"\n"; + outfile << identmap2[el.PNum(jj)] <<"\n"; } outfile << "\n"; } - else if ( identmap3.Elem(el.PNum(1)) && - identmap3.Elem(el.PNum(2)) && - identmap3.Elem(el.PNum(3)) && - identmap3.Elem(el.PNum(4)) ) + else if ( identmap3[el.PNum(1)].IsValid() && + identmap3[el.PNum(2)].IsValid() && + identmap3[el.PNum(3)].IsValid() && + identmap3[el.PNum(4)].IsValid() ) { outfile << "-1\n"; for (j = 1; j <= 4; j++) @@ -414,7 +421,7 @@ void WriteJCMFormat (const Mesh & mesh, jj = j + ct; if ( jj >= 5 ) jj = jj - 4; - outfile << identmap3.Elem(el.PNum(jj))<<"\n"; + outfile << identmap3[el.PNum(jj)]<<"\n"; } outfile << "\n"; } @@ -426,5 +433,6 @@ void WriteJCMFormat (const Mesh & mesh, cout << " JCMwave grid file written." << endl; } +static RegisterUserFormat reg_jcmwave ("JCMwave Format", {".jcm"}, nullopt, WriteJCMFormat); } diff --git a/libsrc/interface/writepermas.cpp b/libsrc/interface/writepermas.cpp index 3fbd5845..28885e67 100644 --- a/libsrc/interface/writepermas.cpp +++ b/libsrc/interface/writepermas.cpp @@ -12,14 +12,15 @@ #include -using namespace std; #include "writeuser.hpp" +using namespace std; namespace netgen { // Forward declarations (don't know, where to define them, sorry) int addComponent(string &strComp, string &strSitu, ofstream &out); + void WritePermasFormat (const Mesh &mesh, const filesystem::path &filename); // This should be the new function to export a PERMAS file void WritePermasFormat (const Mesh &mesh, const filesystem::path &filename, @@ -205,4 +206,5 @@ namespace netgen return 0; } +static RegisterUserFormat reg_permas ("Permas Format", {".mesh"}, nullopt, static_cast(&WritePermasFormat)); } diff --git a/libsrc/interface/writetecplot.cpp b/libsrc/interface/writetecplot.cpp index 2c130efb..53203503 100644 --- a/libsrc/interface/writetecplot.cpp +++ b/libsrc/interface/writetecplot.cpp @@ -9,16 +9,19 @@ #include #include +#include "writeuser.hpp" namespace netgen { -#include "writeuser.hpp" void WriteTecPlotFormat (const Mesh & mesh, - const CSGeometry & geom, - const string & filename) + const filesystem::path & filename) { + auto geom = dynamic_pointer_cast(mesh.GetGeometry()); + if(geom == nullptr) + throw Exception("TecPlot format requires a CSGeometry"); + INDEX i; int j, k, e, z; Vec<3> n; @@ -30,7 +33,7 @@ void WriteTecPlotFormat (const Mesh & mesh, NgArray sn(np); ofstream outfile(filename); - outfile << "TITLE=\" " << filename << "\"" << endl; + outfile << "TITLE=\" " << filename.string() << "\"" << endl; // fill hashtable @@ -56,7 +59,7 @@ void WriteTecPlotFormat (const Mesh & mesh, } - for (j = 1; j <= geom.GetNSurf(); j++) /* Flaeche Nummer j */ + for (j = 1; j <= geom->GetNSurf(); j++) /* Flaeche Nummer j */ { for (i = 1; i <= np; i++) sn.Elem(i) = 0; @@ -85,7 +88,7 @@ void WriteTecPlotFormat (const Mesh & mesh, for (i = 1; i <= np; i++) if (sn.Elem(i) != 0) { - n = geom.GetSurface(j) -> GetNormalVector ( mesh.Point(i) ); + n = geom->GetSurface(j) -> GetNormalVector ( mesh.Point(i) ); outfile << mesh.Point(i)(0) << " " /* Knoten Koordinaten */ << mesh.Point(i)(1) << " " @@ -123,5 +126,6 @@ void WriteTecPlotFormat (const Mesh & mesh, } } +static RegisterUserFormat reg_tecplot ("TecPlot Format", {".mesh"}, nullopt, WriteTecPlotFormat); } diff --git a/libsrc/interface/writetet.cpp b/libsrc/interface/writetet.cpp index 8e952ae9..ab1726bf 100644 --- a/libsrc/interface/writetet.cpp +++ b/libsrc/interface/writetet.cpp @@ -6,21 +6,20 @@ #include #include #include +#include "writeuser.hpp" namespace netgen { - -#include "writeuser.hpp" - + extern void ReadTETFormat (Mesh & mesh, const filesystem::path & filename); void WriteTETFormat (const Mesh & mesh, - const string & filename)//, const string& problemType ) + const filesystem::path & filename)//, const string& problemType ) { string problemType = ""; if(!mesh.PureTetMesh()) throw NgException("Can only export pure tet mesh in this format"); - cout << "starting .tet export to file " << filename << endl; + cout << "starting .tet export to file " << filename.string() << endl; NgArray point_ids,edge_ids,face_ids; @@ -367,12 +366,12 @@ namespace netgen uidpid = "UID"; - NgArray< NgArray* > idmaps; + NgArray< idmap_type* > idmaps; for(int i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++) { if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC) { - idmaps.Append(new NgArray); + idmaps.Append(new idmap_type); mesh.GetIdentifications().GetMap(i,*idmaps.Last(),true); } } @@ -503,7 +502,7 @@ namespace netgen << mesh[i](0) << " " << mesh[i](1) << " " << mesh[i](2) << " " << id_type[i] << " "; - if(i-PointIndex::BASE < point_ids.Size()) + if(i-IndexBASE() < point_ids.Size()) outfile << point_ids[i]; else outfile << "0"; @@ -1067,13 +1066,13 @@ namespace netgen // for(PointIndex i = mesh.Points().Begin(); i < mesh.Points().End(); i++) for(PointIndex i : mesh.Points().Range()) { - if(i-PointIndex::BASE < point_ids.Size()) + if(i-IndexBASE() < point_ids.Size()) { if(uid_to_group_0D[point_ids[i]] >= 0) - groups[uid_to_group_0D[point_ids[i]]]->Append(i+1-PointIndex::BASE); + groups[uid_to_group_0D[point_ids[i]]]->Append(i+1-IndexBASE()); } else - groups[uid_to_group_0D[0]]->Append(i+1-PointIndex::BASE); + groups[uid_to_group_0D[0]]->Append(i+1-IndexBASE()); } @@ -1095,4 +1094,5 @@ namespace netgen cout << ".tet export done" << endl; } +static RegisterUserFormat reg_tet ("TET Format", {".tet"}, ReadTETFormat, WriteTETFormat); } diff --git a/libsrc/interface/writetochnog.cpp b/libsrc/interface/writetochnog.cpp index 3068a385..168f6b6a 100644 --- a/libsrc/interface/writetochnog.cpp +++ b/libsrc/interface/writetochnog.cpp @@ -13,10 +13,10 @@ #include #include +#include "writeuser.hpp" namespace netgen { -#include "writeuser.hpp" void WriteTochnogFormat (const Mesh & mesh, @@ -105,4 +105,5 @@ void WriteTochnogFormat (const Mesh & mesh, cout << "done" << endl; } +static RegisterUserFormat reg_tochnog ("Tochnog Format", {".mesh"}, nullopt, WriteTochnogFormat); } diff --git a/libsrc/interface/writeuser.cpp b/libsrc/interface/writeuser.cpp index 55c91e90..5c85ef90 100644 --- a/libsrc/interface/writeuser.cpp +++ b/libsrc/interface/writeuser.cpp @@ -18,159 +18,43 @@ namespace netgen { extern MeshingParameters mparam; + Array UserFormatRegister::entries; + std::map UserFormatRegister::format_to_entry_index; void RegisterUserFormats (NgArray & names, NgArray & extensions) { - const char *types[] = + for (const auto & entry : UserFormatRegister::entries) { - "Neutral Format", ".mesh", - "Surface Mesh Format", ".mesh" , - "DIFFPACK Format", ".mesh", - "TecPlot Format", ".mesh", - "Tochnog Format", ".mesh", - "Abaqus Format", ".mesh", - "Fluent Format", ".mesh", - "Permas Format", ".mesh", - "FEAP Format", ".mesh", - "Elmer Format", "*", - "STL Format", ".stl", - "STL Extended Format", ".stl", - "VRML Format", ".*", - "Gmsh Format", ".gmsh", - "Gmsh2 Format", ".gmsh2", - "VTK Format", ".vtk", - "OpenFOAM 1.5+ Format", "*", - "OpenFOAM 1.5+ Compressed", "*", - "JCMwave Format", ".jcm", - "TET Format", ".tet", - "CGNS Format", ".cgns", - // { "Chemnitz Format" }, - 0 - }; - - for (int i = 0; types[2*i]; i++) - { - names.Append (types[2*i]); - extensions.Append (types[2*i+1]); + names.Append (entry.format.c_str()); + extensions.Append (entry.extensions[0].c_str()); } } - - -bool WriteUserFormat (const filesystem::path & format, +bool WriteUserFormat (const string & format, const Mesh & mesh, const filesystem::path & filename) { - // cout << "write user &hgeom = " << &hgeom << endl; - // const CSGeometry & geom = *dynamic_cast (&hgeom); - const CSGeometry & geom = *dynamic_pointer_cast (mesh.GetGeometry()); + if(!UserFormatRegister::HaveFormat(format)) + return true; - PrintMessage (1, "Export mesh to file ", filename, - ", format is ", format); + const auto entry = UserFormatRegister::Get(format); + if(!entry.write) + return true; - if (format == "Neutral Format") - WriteNeutralFormat (mesh, geom, filename); - - else if (format == "Surface Mesh Format") - WriteSurfaceFormat (mesh, filename); - - else if (format == "DIFFPACK Format") - WriteDiffPackFormat (mesh, geom, filename); - - else if (format == "Tochnog Format") - WriteTochnogFormat (mesh, filename); - - else if (format == "TecPlot Format") - cerr << "ERROR: TecPlot format currently out of order" << endl; - // WriteTecPlotFormat (mesh, geom, filename); - - else if (format == "Abaqus Format") - WriteAbaqusFormat (mesh, filename); - - else if (format == "Fluent Format") - WriteFluentFormat (mesh, filename); - - else if (format == "Permas Format") - WritePermasFormat (mesh, filename); - - else if (format == "FEAP Format") - WriteFEAPFormat (mesh, filename); - - else if (format == "Elmer Format") - WriteElmerFormat (mesh, filename); - - else if (format == "STL Format") - WriteSTLFormat (mesh, filename); - - // Philippose - 16 August 2010 - // Added additional STL Export in which - // each face of the geometry is treated - // as a separate "solid" entity - else if (format == "STL Extended Format") - WriteSTLExtFormat (mesh, filename); - - else if (format == "VRML Format") - WriteVRMLFormat (mesh, 1, filename); - - else if (format == "Fepp Format") - WriteFEPPFormat (mesh, geom, filename); - - else if (format == "EdgeElement Format") - WriteEdgeElementFormat (mesh, geom, filename); - - else if (format == "Chemnitz Format") - WriteUserChemnitz (mesh, filename); - - else if (format == "Gmsh Format") - WriteGmshFormat (mesh, geom, filename); - - // Philippose - 29/01/2009 - // Added Gmsh v2.xx Mesh export capability - else if (format == "Gmsh2 Format") - WriteGmsh2Format (mesh, geom, filename); - - else if (format == "VTK Format") - WriteVtkFormat (mesh, filename); - - // Philippose - 25/10/2009 - // Added OpenFOAM 1.5+ Mesh export capability - else if (format == "OpenFOAM 1.5+ Format") - WriteOpenFOAM15xFormat (mesh, filename, false); - - else if (format == "OpenFOAM 1.5+ Compressed") - WriteOpenFOAM15xFormat (mesh, filename, true); - - else if (format == "JCMwave Format") - WriteJCMFormat (mesh, geom, filename); - -#ifdef OLIVER - else if (format == "TET Format") - WriteTETFormat( mesh, filename);//, "High Frequency" ); -#endif - - else if (format == "CGNS Format") - WriteCGNSMesh( mesh, filename); - - else - { - return 1; - } - - return 0; + (*entry.write)(mesh, filename); + return false; } - /* * Neutral mesh format * points, elements, surface elements */ void WriteNeutralFormat (const Mesh & mesh, - const NetgenGeometry & geom, const filesystem::path & filename) { cout << "write neutral, new" << endl; @@ -178,7 +62,7 @@ void WriteNeutralFormat (const Mesh & mesh, int ne = mesh.GetNE(); int nse = mesh.GetNSE(); int nseg = mesh.GetNSeg(); - int i, j; + // int i, j; int inverttets = mparam.inverttets; int invertsurf = mparam.inverttrigs; @@ -191,7 +75,7 @@ void WriteNeutralFormat (const Mesh & mesh, outfile << np << "\n"; - for (i = 1; i <= np; i++) + for (int i = 1; i <= np; i++) { const Point3d & p = mesh.Point(i); @@ -210,14 +94,18 @@ void WriteNeutralFormat (const Mesh & mesh, if (mesh.GetDimension() == 3) { outfile << ne << "\n"; - for (i = 1; i <= ne; i++) + /* + for (int i = 1; i <= ne; i++) { Element el = mesh.VolumeElement(i); + */ + for (Element el : mesh.VolumeElements()) + { if (inverttets) el.Invert(); outfile.width(4); outfile << el.GetIndex() << " "; - for (j = 1; j <= el.GetNP(); j++) + for (int j = 1; j <= el.GetNP(); j++) { outfile << " "; outfile.width(8); @@ -228,14 +116,18 @@ void WriteNeutralFormat (const Mesh & mesh, } outfile << nse << "\n"; - for (i = 1; i <= nse; i++) + /* + for (int i = 1; i <= nse; i++) { Element2d el = mesh.SurfaceElement(i); + */ + for (Element2d el : mesh.SurfaceElements()) + { if (invertsurf) el.Invert(); outfile.width(4); outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; - for (j = 1; j <= el.GetNP(); j++) + for (int j = 1; j <= el.GetNP(); j++) { outfile << " "; outfile.width(8); @@ -635,6 +527,16 @@ void WriteVRMLFormat (const Mesh & mesh, } +void WriteVRMLFormatLineset (const Mesh & mesh, const filesystem::path & filename) +{ + WriteVRMLFormat(mesh, false, filename); +} + +void WriteVRMLFormatFaceset (const Mesh & mesh, const filesystem::path & filename) +{ + WriteVRMLFormat(mesh, true, filename); +} + @@ -644,7 +546,6 @@ void WriteVRMLFormat (const Mesh & mesh, * FEPP .. a finite element package developed at University Linz, Austria */ void WriteFEPPFormat (const Mesh & mesh, - const NetgenGeometry & geom, const filesystem::path & filename) { @@ -690,9 +591,13 @@ void WriteFEPPFormat (const Mesh & mesh, outfile << ne << "\n"; + /* for (i = 1; i <= ne; i++) { const Element & el = mesh.VolumeElement(i); + */ + for (const Element & el : mesh.VolumeElements()) + { outfile.width(4); outfile << el.GetIndex() << " "; outfile.width(4); @@ -775,7 +680,6 @@ void WriteFEPPFormat (const Mesh & mesh, */ void WriteEdgeElementFormat (const Mesh & mesh, - const NetgenGeometry & geom, const filesystem::path & filename) { cout << "write edge element format" << endl; @@ -785,7 +689,6 @@ void WriteEdgeElementFormat (const Mesh & mesh, int nelements = mesh.GetNE(); int nsurfelem = mesh.GetNSE(); int nedges = top->GetNEdges(); - int i, j; int inverttets = mparam.inverttets; int invertsurf = mparam.inverttrigs; @@ -800,7 +703,7 @@ void WriteEdgeElementFormat (const Mesh & mesh, // vertices with coordinates outfile << npoints << "\n"; - for (i = 1; i <= npoints; i++) + for (int i = 1; i <= npoints; i++) { const Point3d & p = mesh.Point(i); @@ -814,38 +717,47 @@ void WriteEdgeElementFormat (const Mesh & mesh, // element - edge - list outfile << nelements << " " << nedges << "\n"; + /* for (i = 1; i <= nelements; i++) { Element el = mesh.VolumeElement(i); + */ + for (ElementIndex ei : Range(mesh.VolumeElements())) + { + int i = ei-IndexBASE(ei)+1; + + Element el = mesh.VolumeElement(ei); + if (inverttets) el.Invert(); outfile.width(4); outfile << el.GetIndex() << " "; outfile.width(8); outfile << el.GetNP(); - for (j = 1; j <= el.GetNP(); j++) + for (int j = 1; j <= el.GetNP(); j++) { outfile << " "; outfile.width(8); outfile << el.PNum(j); } - top->GetElementEdges(i,edges); + // top->GetElementEdges(i,edges); + auto eledges = top->GetEdges(ei); outfile << endl << " "; outfile.width(8); - outfile << edges.Size(); - for (j=1; j <= edges.Size(); j++) + outfile << eledges.Size(); + for (int j=1; j <= eledges.Size(); j++) { outfile << " "; outfile.width(8); - outfile << edges[j-1]; + outfile << eledges[j-1]+1; } outfile << "\n"; // orientation: top->GetElementEdgeOrientations(i,edges); outfile << " "; - for (j=1; j <= edges.Size(); j++) + for (int j=1; j <= edges.Size(); j++) { outfile << " "; outfile.width(8); @@ -856,42 +768,45 @@ void WriteEdgeElementFormat (const Mesh & mesh, // surface element - edge - list (with boundary conditions) outfile << nsurfelem << "\n"; - for (i = 1; i <= nsurfelem; i++) + for (int i = 1; i <= nsurfelem; i++) { - Element2d el = mesh.SurfaceElement(i); + SurfaceElementIndex sei(i-1); + Element2d el = mesh[sei]; if (invertsurf) el.Invert(); outfile.width(4); outfile << mesh.GetFaceDescriptor (el.GetIndex()).BCProperty() << " "; outfile.width(8); outfile << el.GetNP(); - for (j = 1; j <= el.GetNP(); j++) + for (int j = 1; j <= el.GetNP(); j++) { outfile << " "; outfile.width(8); outfile << el.PNum(j); } - top->GetSurfaceElementEdges(i,edges); + // top->GetSurfaceElementEdges(i,edges); + auto edges = top->GetEdges(sei); outfile << endl << " "; outfile.width(8); outfile << edges.Size(); - for (j=1; j <= edges.Size(); j++) + for (int j=0; j < edges.Size(); j++) { outfile << " "; outfile.width(8); - outfile << edges[j-1]; + outfile << edges[j]+1; } outfile << "\n"; } - int v1, v2; + // int v1, v2; // edge - vertex - list outfile << nedges << "\n"; - for (i=1; i <= nedges; i++) + for (int i=1; i <= nedges; i++) { - top->GetEdgeVertices(i,v1,v2); + // top->GetEdgeVertices(i,v1,v2); + auto [v1,v2] = top->GetEdgeVertices(i-1); outfile.width(4); outfile << v1; outfile << " "; @@ -900,169 +815,14 @@ void WriteEdgeElementFormat (const Mesh & mesh, } } - - - - - - - - -#ifdef OLDSTYLE_WRITE - - -void WriteFile (int typ, - const Mesh & mesh, - const CSGeometry & geom, - const filesystem::path & filename, - const filesystem::path & geomfile, - double h) -{ - - - int inverttets = mparam.inverttets; - int invertsurf = mparam.inverttrigs; - - - - - - - - - if (typ == WRITE_EDGEELEMENT) - { - // write edge element file - // Peter Harscher, ETHZ - - cout << "Write Edge-Element Format" << endl; - - ofstream outfile (filename); - - int i, j; - int ned; - - // hash table representing edges; - INDEX_2_HASHTABLE edgeht(mesh.GetNP()); - - // list of edges - NgArray edgelist; - - // edge (point) on boundary ? - NgBitArray bedge, bpoint(mesh.GetNP()); - - static int eledges[6][2] = { { 1, 2 } , { 1, 3 } , { 1, 4 }, - { 2, 3 } , { 2, 4 } , { 3, 4 } }; - - // fill hashtable (point1, point2) ----> edgenr - for (i = 1; i <= mesh.GetNE(); i++) - { - const Element & el = mesh.VolumeElement (i); - INDEX_2 edge; - for (j = 1; j <= 6; j++) - { - edge.I1() = el.PNum (eledges[j-1][0]); - edge.I2() = el.PNum (eledges[j-1][1]); - edge.Sort(); - - if (!edgeht.Used (edge)) - { - edgelist.Append (edge); - edgeht.Set (edge, edgelist.Size()); - } - } - } - - - // set bedges, bpoints - bedge.SetSize (edgelist.Size()); - bedge.Clear(); - bpoint.Clear(); - - for (i = 1; i <= mesh.GetNSE(); i++) - { - const Element2d & sel = mesh.SurfaceElement(i); - for (j = 1; j <= 3; j++) - { - bpoint.Set (sel.PNum(j)); - - INDEX_2 edge; - edge.I1() = sel.PNum(j); - edge.I2() = sel.PNum(j%3+1); - edge.Sort(); - - bedge.Set (edgeht.Get (edge)); - } - } - - - - outfile << mesh.GetNE() << endl; - // write element ---> point - for (i = 1; i <= mesh.GetNE(); i++) - { - const Element & el = mesh.VolumeElement(i); - - outfile.width(8); - outfile << i; - for (j = 1; j <= 4; j++) - { - outfile.width(8); - outfile << el.PNum(j); - } - outfile << endl; - } - - // write element ---> edge - for (i = 1; i <= mesh.GetNE(); i++) - { - const Element & el = mesh.VolumeElement (i); - INDEX_2 edge; - for (j = 1; j <= 6; j++) - { - edge.I1() = el.PNum (eledges[j-1][0]); - edge.I2() = el.PNum (eledges[j-1][1]); - edge.Sort(); - - outfile.width(8); - outfile << edgeht.Get (edge); - } - outfile << endl; - } - - // write points - outfile << mesh.GetNP() << endl; - outfile.precision (6); - for (i = 1; i <= mesh.GetNP(); i++) - { - const Point3d & p = mesh.Point(i); - - for (j = 1; j <= 3; j++) - { - outfile.width(8); - outfile << p.X(j); - } - outfile << " " - << (bpoint.Test(i) ? "1" : 0) << endl; - } - - // write edges - outfile << edgelist.Size() << endl; - for (i = 1; i <= edgelist.Size(); i++) - { - outfile.width(8); - outfile << edgelist.Get(i).I1(); - outfile.width(8); - outfile << edgelist.Get(i).I2(); - outfile << " " - << (bedge.Test(i) ? "1" : "0") << endl; - } - } - - - +static RegisterUserFormat reg_neutral("Neutral Format", {".mesh"}, ReadFile, WriteNeutralFormat); +static RegisterUserFormat reg_surface("Surface Mesh Format", {".mesh", ".surf"} ,ReadFile, WriteSurfaceFormat); +static RegisterUserFormat reg_stl ("STL Format", {".stl", ".stlb"}, ReadFile, WriteSTLFormat); +static RegisterUserFormat reg_stlx ("STL Extended Format", {".stl", ".stlb"}, nullopt, WriteSTLExtFormat); +static RegisterUserFormat reg_vrml ("VRML Format", {".*"}, nullopt, WriteVRMLFormatLineset); +static RegisterUserFormat reg_vrml_faces ("VRML Format Faces", {".*"}, nullopt, WriteVRMLFormatFaceset); +static RegisterUserFormat reg_fepp ("Fepp Format", {"*"}, nullopt, WriteFEPPFormat); +static RegisterUserFormat reg_edgeelement ("EdgeElement Format", {"*"}, nullopt, WriteEdgeElementFormat); -} -#endif } diff --git a/libsrc/interface/writeuser.hpp b/libsrc/interface/writeuser.hpp index 037a84ac..99dc21e0 100644 --- a/libsrc/interface/writeuser.hpp +++ b/libsrc/interface/writeuser.hpp @@ -7,179 +7,73 @@ /* Date: 10. Dec. 97 */ /**************************************************************************/ +#include +#include +#include + +#include + namespace netgen { -DLL_HEADER extern -void WriteFile (int typ, - const Mesh & mesh, - const NetgenGeometry & geom, - const filesystem::path & filename, - const filesystem::path & geomfile = "", - double h = 0); +using namespace std::filesystem; + +typedef std::function FWrite; +typedef std::function FRead; +typedef std::function FTest; + +struct UserFormatRegister { + struct UserFormatEntry { + string format; + Array extensions; + optional read; + optional write; + }; + DLL_HEADER static Array entries; + DLL_HEADER static std::map format_to_entry_index; + + static void Register(UserFormatEntry && entry) { + format_to_entry_index[entry.format] = entries.Size(); + entries.Append( std::move(entry) ); + } + + static const bool HaveFormat(string format) { + return format_to_entry_index.count(format) > 0; + } + static const UserFormatEntry & Get(string format) { + return entries[format_to_entry_index[format]]; + } + + template + static void IterateFormats(TFunc func, bool need_read=false, bool need_write=false) { + Array import_formats; + for(const auto & e: entries) + if((!need_read || e.read) && (!need_write || e.write)) + import_formats.Append(e.format); + QuickSort(import_formats); + for(auto format : import_formats) + func(entries[format_to_entry_index[format]]); + } + +}; + +struct RegisterUserFormat { + RegisterUserFormat(string format, Array extensions, optional read, optional write, FTest ftest = [](const filesystem::path & ){return true;}) + { + UserFormatRegister::Register({format, std::move(extensions), std::move(read), std::move(write)}); + } +}; + +DLL_HEADER void ReadFile(Mesh & mesh, const filesystem::path & filename); +DLL_HEADER void ReadUserFormat(Mesh & mesh, const filesystem::path & filename, const string & format = ""); - -DLL_HEADER extern -void ReadFile (Mesh & mesh, - const filesystem::path & filename); - - - - - - -extern -void WriteNeutralFormat (const Mesh & mesh, - const NetgenGeometry & geom, - const filesystem::path & filename); - -extern -void WriteSurfaceFormat (const Mesh & mesh, - const filesystem::path & filename); - -extern -void WriteSTLFormat (const Mesh & mesh, - const filesystem::path & filename); - - -// Philippose - 16 August 2010 -// Added the STL Extended format in which -// each face of the geometry is treated as -// a separate "solid" entity in the STL file -extern -void WriteSTLExtFormat (const Mesh & mesh, - const filesystem::path & filename); - - -extern -void WriteVRMLFormat (const Mesh & mesh, - bool faces, - const filesystem::path & filename); - -extern -void WriteFEPPFormat (const Mesh & mesh, - const NetgenGeometry & geom, - const filesystem::path & filename); - -extern -void WriteGmshFormat (const Mesh & mesh, - const NetgenGeometry & geom, - const filesystem::path & filename); - - -// Philippose - 29/01/2009 -// Added GMSH v2.xx Mesh Export support -void WriteGmsh2Format (const Mesh & mesh, - const NetgenGeometry & geom, - const filesystem::path & filename); - -extern -void WriteVtkFormat (const Mesh & mesh, - const string & filename); - -// Philippose - 25/10/2009 -// Added OpenFOAM 1.5+ Mesh Export support -extern -void WriteOpenFOAM15xFormat (const Mesh & mesh, - const filesystem::path & casename, - const bool compressed); - - -extern -void WriteUserChemnitz (const Mesh & mesh, - const filesystem::path & filename); - -extern -void WriteJCMFormat (const Mesh & mesh, - const NetgenGeometry & geom, - const filesystem::path & filename); - - -extern -void WriteDiffPackFormat (const Mesh & mesh, - const NetgenGeometry & geom, - const filesystem::path & filename); - -extern -void WriteTochnogFormat (const Mesh & mesh, - const filesystem::path & filename); - -extern -void WriteTecPlotFormat (const Mesh & mesh, - const NetgenGeometry & geom, - const filesystem::path & filename); - -extern -void WriteAbaqusFormat (const Mesh & mesh, - const filesystem::path & filename); - -extern -void WriteFluentFormat (const Mesh & mesh, - const filesystem::path & filename); - -extern -void WritePermasFormat (const Mesh & mesh, - const filesystem::path & filename); - -extern -void WriteFEAPFormat (const Mesh & mesh, - const filesystem::path & filename); - -extern -void WriteElmerFormat (const Mesh & mesh, - const filesystem::path & filename); - - -extern -void WriteEdgeElementFormat (const Mesh & mesh, - const NetgenGeometry & geom, - const filesystem::path & filename); - - - -#ifdef OLIVER -extern -void WriteTETFormat (const Mesh & mesh, - const filesystem::path & filename); - -#endif - -extern void ReadTETFormat (Mesh & mesh, - const filesystem::path & filename); - - -extern void ReadFNFFormat (Mesh & mesh, - const filesystem::path & filename); - - - -extern void DLL_HEADER ReadCGNSMesh (Mesh & mesh, - const filesystem::path & filename); - -extern void DLL_HEADER WriteCGNSMesh (const Mesh & mesh, - const filesystem::path & filename); - -// read/write mesh and solutions from CGNS file -extern tuple, vector, vector>, vector> -DLL_HEADER ReadCGNSFile(const filesystem::path & filename, int base); - -extern void DLL_HEADER WriteCGNSFile(shared_ptr mesh, const filesystem::path & filename, vector fields, - vector> values, vector locations); - - -void WriteDolfinFormat (const Mesh & mesh, - const filesystem::path & filename); - +extern bool DLL_HEADER WriteUserFormat (const string & format, + const Mesh & mesh, + const filesystem::path & filename); extern void DLL_HEADER RegisterUserFormats (NgArray & names, NgArray & extensions); - -extern bool DLL_HEADER WriteUserFormat (const filesystem::path & format, - const Mesh & mesh, - // const NetgenGeometry & geom, - const filesystem::path & filename); - } #endif diff --git a/libsrc/interface/wuchemnitz.cpp b/libsrc/interface/wuchemnitz.cpp index 6798993f..ffc0b864 100644 --- a/libsrc/interface/wuchemnitz.cpp +++ b/libsrc/interface/wuchemnitz.cpp @@ -9,6 +9,8 @@ #include #include +#include "writeuser.hpp" + namespace netgen { @@ -316,4 +318,5 @@ namespace netgen WriteFile (outfile); cout << "Wrote Chemnitz standard file" << endl; } +static RegisterUserFormat reg_chemnitz ("Chemnitz Format", {"*"}, nullopt, WriteUserChemnitz ); } diff --git a/libsrc/linalg/densemat.cpp b/libsrc/linalg/densemat.cpp index f2cc2fa5..4dd316e0 100644 --- a/libsrc/linalg/densemat.cpp +++ b/libsrc/linalg/densemat.cpp @@ -49,7 +49,8 @@ namespace netgen { data = NULL; height = width = 0; SetSize (m2.Height(), m2.Width()); - memcpy (data, m2.data, sizeof(double) * Height() * Width()); + if (Height() && Width()) + memcpy (data, m2.data, sizeof(double) * (Height() * Width())); } DenseMatrix :: ~DenseMatrix () @@ -69,7 +70,7 @@ namespace netgen delete[] data; - if (h*w) + if (h && w) data = new double[h*w]; else data = NULL; diff --git a/libsrc/linalg/densemat.hpp b/libsrc/linalg/densemat.hpp index 5b3bb6a5..73b5ee93 100644 --- a/libsrc/linalg/densemat.hpp +++ b/libsrc/linalg/densemat.hpp @@ -11,7 +11,11 @@ Data type dense matrix */ +#include +#include "vector.hpp" +namespace netgen +{ class DenseMatrix { protected: @@ -406,5 +410,5 @@ extern ostream & operator<< (ostream & ost, const MatrixFixWidth & m) extern DLL_HEADER void CalcAtA (const DenseMatrix & a, DenseMatrix & m2); extern DLL_HEADER void CalcInverse (const DenseMatrix & m1, DenseMatrix & m2); - +} // namespace netgen #endif diff --git a/libsrc/linalg/linalg.hpp b/libsrc/linalg/linalg.hpp index 95d0c823..10bc6c50 100644 --- a/libsrc/linalg/linalg.hpp +++ b/libsrc/linalg/linalg.hpp @@ -21,12 +21,9 @@ #include "../include/myadt.hpp" -namespace netgen -{ #include "vector.hpp" #include "densemat.hpp" #include "polynomial.hpp" -} #endif diff --git a/libsrc/linalg/polynomial.hpp b/libsrc/linalg/polynomial.hpp index 3108d4dd..a97db58e 100644 --- a/libsrc/linalg/polynomial.hpp +++ b/libsrc/linalg/polynomial.hpp @@ -7,6 +7,8 @@ /* Date: 25. Nov. 99 */ /* *************************************************************************/ +namespace netgen +{ class QuadraticPolynomial1V { @@ -41,5 +43,5 @@ public: double MaxUnitSquare (); double MaxUnitTriangle (); }; - +} // namespace netgen #endif diff --git a/libsrc/linalg/vector.hpp b/libsrc/linalg/vector.hpp index 97ad05ed..670c4660 100644 --- a/libsrc/linalg/vector.hpp +++ b/libsrc/linalg/vector.hpp @@ -7,8 +7,8 @@ /* Date: 01. Oct. 94 */ /* *************************************************************************/ - - +namespace netgen +{ template class TFlatVector @@ -139,7 +139,8 @@ public: ~Vector () { if (ownmem) delete [] data; } - virtual void DoArchive(Archive& ar) + template + void DoArchive(ARCHIVE& ar) { auto size = s; ar & ownmem & size; @@ -209,7 +210,7 @@ inline ostream & operator<< (ostream & ost, const FlatVector & v) return ost; } - +} //namespace netgen #endif diff --git a/libsrc/meshing/CMakeLists.txt b/libsrc/meshing/CMakeLists.txt index 7fff8d26..ade62d59 100644 --- a/libsrc/meshing/CMakeLists.txt +++ b/libsrc/meshing/CMakeLists.txt @@ -12,10 +12,10 @@ target_sources(nglib PRIVATE parallelmesh.cpp paralleltop.cpp basegeom.cpp python_mesh.cpp surfacegeom.cpp debugging.cpp fieldlines.cpp visual_interface.cpp - boundarylayer2d.cpp + boundarylayer2d.cpp boundarylayer_interpolate.cpp ) -target_link_libraries( nglib PRIVATE netgen_metis "$" ${ZLIB_LIBRARIES} ) +target_link_libraries( nglib PRIVATE $ $ ) install(FILES adfront2.hpp adfront3.hpp basegeom.hpp bcfunctions.hpp bisect.hpp diff --git a/libsrc/meshing/adfront2.cpp b/libsrc/meshing/adfront2.cpp index ab27334b..a915d71f 100644 --- a/libsrc/meshing/adfront2.cpp +++ b/libsrc/meshing/adfront2.cpp @@ -3,8 +3,9 @@ */ #include -#include "meshing.hpp" - +#include +#include +#include "adfront2.hpp" namespace netgen { @@ -151,15 +152,15 @@ namespace netgen if (allflines) { - if (allflines->Used (INDEX_2 (GetGlobalIndex (pi1), - GetGlobalIndex (pi2)))) + if (allflines->Used (PointIndices<2>(GetGlobalIndex (pi1), + GetGlobalIndex (pi2)))) { cerr << "ERROR Adfront2::AddLine: line exists" << endl; (*testout) << "ERROR Adfront2::AddLine: line exists" << endl; } - allflines->Set (INDEX_2 (GetGlobalIndex (pi1), - GetGlobalIndex (pi2)), 1); + allflines->Set (PointIndices<2>(GetGlobalIndex (pi1), + GetGlobalIndex (pi2)), 1); } return li; @@ -193,8 +194,8 @@ namespace netgen if (allflines) { - allflines->Set (INDEX_2 (GetGlobalIndex (lines[li].L().I1()), - GetGlobalIndex (lines[li].L().I2())), 2); + allflines->Set (PointIndices<2>(GetGlobalIndex (lines[li].L().I1()), + GetGlobalIndex (lines[li].L().I2())), 2); } lines[li].Invalidate(); @@ -281,7 +282,7 @@ namespace netgen NgArray & lindex, double xh) { - static Timer timer("adfront2::GetLocals"); RegionTimer reg (timer); + // static Timer timer("adfront2::GetLocals"); RegionTimer reg (timer); int pstind; Point<3> midp, p0; diff --git a/libsrc/meshing/adfront2.hpp b/libsrc/meshing/adfront2.hpp index 95914535..d1d03472 100644 --- a/libsrc/meshing/adfront2.hpp +++ b/libsrc/meshing/adfront2.hpp @@ -1,5 +1,5 @@ -#ifndef FILE_ADFRONT2 -#define FILE_ADFRONT2 +#ifndef NETGEN_ADFRONT2_HPP +#define NETGEN_ADFRONT2_HPP /**************************************************************************/ /* File: adfront2.hpp */ @@ -14,6 +14,12 @@ */ +#include +#include +#include "meshtype.hpp" + +namespace netgen +{ /// class FrontPoint2 { @@ -89,7 +95,7 @@ { private: /// Point Indizes - INDEX_2 l; + INDEX_2 l; // want to replace by std::array l; /// quality class int lineclass; /// geometry specific data @@ -103,23 +109,12 @@ /// FrontLine (const INDEX_2 & al) - { - l = al; - lineclass = 1; - } - + : l(al), lineclass(1) { } /// - const INDEX_2 & L () const - { - return l; - } - + const auto & L () const { return l; } /// - int LineClass() const - { - return lineclass; - } + int LineClass() const { return lineclass; } /// void IncrementClass () @@ -135,13 +130,13 @@ /// bool Valid () const { - return l.I1() != -1; + return l[0] != -1; } /// void Invalidate () { - l.I1() = -1; - l.I2() = -1; + l[0] = -1; + l[1] = -1; lineclass = 1000; } @@ -165,21 +160,21 @@ class AdFront2 { /// - NgArray points; /// front points - NgArray lines; /// front lines + Array points; /// front points + Array lines; /// front lines Box3d boundingbox; BoxTree<3> linesearchtree; /// search tree for lines Point3dTree pointsearchtree; /// search tree for points Point3dTree cpointsearchtree; /// search tree for cone points (not used ???) - NgArray delpointl; /// list of deleted front points - NgArray dellinel; /// list of deleted front lines + Array delpointl; /// list of deleted front points + Array dellinel; /// list of deleted front lines int nfl; /// number of front lines; INDEX_2_HASHTABLE * allflines; /// all front lines ever have been - NgArray invpindex; + Array invpindex; int minval; int starti; @@ -204,8 +199,8 @@ public: /// int GetNFL () const { return nfl; } - const FrontLine & GetLine (int nr) { return lines[nr]; } - const FrontPoint2 & GetPoint (int nr) { return points[nr]; } + const FrontLine & GetLine (int nr) const { return lines[nr]; } + const FrontPoint2 & GetPoint (int nr) const { return points[nr]; } const auto & GetLines () const { return lines; } /// @@ -275,9 +270,5 @@ public: void PrintOpenSegments (ostream & ost) const; }; - - -#endif - - - +} // namespace netgen +#endif // NETGEN_ADFRONT2_HPP diff --git a/libsrc/meshing/adfront3.cpp b/libsrc/meshing/adfront3.cpp index 588f1d23..9f2925ef 100644 --- a/libsrc/meshing/adfront3.cpp +++ b/libsrc/meshing/adfront3.cpp @@ -1,6 +1,7 @@ #include -#include "meshing.hpp" +#include +#include "adfront3.hpp" /* ********************** FrontPoint ********************** */ @@ -12,7 +13,7 @@ FrontPoint3 :: FrontPoint3 () globalindex.Invalidate(); // = -1; nfacetopoint = 0; frontnr = 1000; - cluster = 0; + cluster = PointIndex::INVALID; } @@ -22,7 +23,7 @@ FrontPoint3 :: FrontPoint3 (const Point<3> & ap, PointIndex agi) globalindex = agi; nfacetopoint = 0; frontnr = 1000; - cluster = 0; + cluster = PointIndex::INVALID; } @@ -34,7 +35,7 @@ FrontFace :: FrontFace () qualclass = 1; oldfront = 0; hashvalue = 0; - cluster = 0; + cluster = PointIndex::INVALID; } FrontFace :: FrontFace (const MiniElement2d & af) @@ -70,7 +71,7 @@ AdFront3 :: AdFront3 () hashtable.Init(&points, &faces); facetree = NULL; - connectedpairs = NULL; + // connectedpairs = NULL; rebuildcounter = -1; lasti = 0; @@ -81,7 +82,7 @@ AdFront3 :: AdFront3 () AdFront3 :: ~AdFront3 () { delete facetree; - delete connectedpairs; + // delete connectedpairs; } void AdFront3 :: GetPoints (NgArray > & apoints) const @@ -152,10 +153,10 @@ INDEX AdFront3 :: AddFace (const MiniElement2d & aface) } - int cluster = 0; + PointIndex cluster = PointIndex::INVALID; for (i = 1; i <= aface.GetNP(); i++) { - if (points[aface.PNum(i)].cluster) + if (points[aface.PNum(i)].cluster.IsValid()) cluster = points[aface.PNum(i)].cluster; } for (i = 1; i <= aface.GetNP(); i++) @@ -181,9 +182,13 @@ void AdFront3 :: DeleteFace (INDEX fi) { nff--; + /* for (int i = 1; i <= faces.Get(fi).Face().GetNP(); i++) { PointIndex pi = faces.Get(fi).Face().PNum(i); + */ + for (PointIndex pi : faces.Get(fi).Face().PNums()) + { points[pi].RemoveFace(); if (!points[pi].Valid()) delpointl.Append (pi); @@ -212,13 +217,13 @@ void AdFront3 :: DeleteFace (INDEX fi) } -INDEX AdFront3 :: AddConnectedPair (const INDEX_2 & apair) +INDEX AdFront3 :: AddConnectedPair (PointIndices<2> apair) { if (!connectedpairs) - connectedpairs = new TABLE (GetNP()); + connectedpairs = make_unique> (GetNP()); - connectedpairs->Add (apair.I1(), apair.I2()); - connectedpairs->Add (apair.I2(), apair.I1()); + connectedpairs->Add (apair[0], apair[1]); + connectedpairs->Add (apair[1], apair[0]); return 0; } @@ -230,11 +235,11 @@ void AdFront3 :: CreateTrees () PointIndex pi; Point3d pmin, pmax; - for (pi = PointIndex::BASE; - pi < GetNP()+PointIndex::BASE; pi++) + for (pi = IndexBASE(); + pi < GetNP()+IndexBASE(); pi++) { const Point<3> & p = GetPoint(pi); - if (pi == PointIndex::BASE) + if (pi == IndexBASE()) { pmin = p; pmax = p; @@ -322,12 +327,12 @@ void AdFront3 :: RebuildInternalTables () { const MiniElement2d & el = faces.Get(i).Face(); - int mini = points[el.PNum(1)].cluster; - int maxi = mini; + PointIndex mini = points[el.PNum(1)].cluster; + PointIndex maxi = mini; for (int j = 2; j <= 3; j++) { - int ci = points[el.PNum(j)].cluster; + PointIndex ci = points[el.PNum(j)].cluster; if (ci < mini) mini = ci; if (ci > maxi) maxi = ci; } @@ -357,13 +362,15 @@ void AdFront3 :: RebuildInternalTables () faces.Elem(i).cluster = points[faces.Get(i).Face().PNum(1)].cluster; } + /* int cntcl = 0; for (int i = PointIndex::BASE; i < np+PointIndex::BASE; i++) if (usecl[i]) cntcl++; - - NgArray clvol (np); + */ + + Array clvol (np); clvol = 0.0; for (int i = 1; i <= faces.Size(); i++) @@ -394,21 +401,18 @@ void AdFront3 :: RebuildInternalTables () - int negvol = 0; - for (int i = PointIndex::BASE; - i < clvol.Size()+PointIndex::BASE; i++) - { - if (clvol[i] < 0) - negvol = 1; - } + bool negvol = false; + for (auto i : clvol.Range()) + if (clvol[i] < 0) + negvol = true; if (negvol) { for (int i = 1; i <= faces.Size(); i++) - faces.Elem(i).cluster = 1; + faces.Elem(i).cluster = IndexBASE(); // for (PointIndex pi = points.Begin(); pi < points.End(); pi++) for (PointIndex pi : points.Range()) - points[pi].cluster = 1; + points[pi].cluster = IndexBASE(); } if (hashon) @@ -421,8 +425,6 @@ void AdFront3 :: RebuildInternalTables () int AdFront3 :: SelectBaseElement () { - int i, hi, fstind; - /* static int minval = -1; static int lasti = 0; @@ -447,12 +449,12 @@ int AdFront3 :: SelectBaseElement () } */ - fstind = 0; + int fstind = 0; - for (i = lasti+1; i <= faces.Size() && !fstind; i++) + for (int i = lasti+1; i <= faces.Size() && !fstind; i++) if (faces.Elem(i).Valid()) { - hi = faces.Get(i).QualClass() + + int hi = faces.Get(i).QualClass() + points[faces.Get(i).Face().PNum(1)].FrontNr() + points[faces.Get(i).Face().PNum(2)].FrontNr() + points[faces.Get(i).Face().PNum(3)].FrontNr(); @@ -468,10 +470,10 @@ int AdFront3 :: SelectBaseElement () if (!fstind) { minval = INT_MAX; - for (i = 1; i <= faces.Size(); i++) + for (int i = 1; i <= faces.Size(); i++) if (faces.Elem(i).Valid()) { - hi = faces.Get(i).QualClass() + + int hi = faces.Get(i).QualClass() + points[faces.Get(i).Face().PNum(1)].FrontNr() + points[faces.Get(i).Face().PNum(2)].FrontNr() + points[faces.Get(i).Face().PNum(3)].FrontNr(); @@ -492,10 +494,10 @@ int AdFront3 :: SelectBaseElement () int AdFront3 :: GetLocals (int fstind, - NgArray & locpoints, - NgArray & locfaces, // local index - NgArray & pindex, - NgArray & findex, + Array & locpoints, + Array & locfaces, // local index + Array & pindex, + Array & findex, INDEX_2_HASHTABLE & getconnectedpairs, float xh, float relh, @@ -512,7 +514,7 @@ int AdFront3 :: GetLocals (int fstind, hashcreated=1; } - INDEX i, j; + INDEX i; PointIndex pstind; Point3d midp, p0; @@ -526,7 +528,7 @@ int AdFront3 :: GetLocals (int fstind, locfaces3.SetSize(0); findex2.SetSize(0); - int cluster = faces.Get(fstind).cluster; + PointIndex cluster = faces.Get(fstind).cluster; pstind = faces.Get(fstind).Face().PNum(1); p0 = points[pstind].P(); @@ -593,28 +595,37 @@ int AdFront3 :: GetLocals (int fstind, invpindex.SetSize (points.Size()); + /* for (i = 1; i <= locfaces.Size(); i++) for (j = 1; j <= locfaces.Get(i).GetNP(); j++) { PointIndex pi = locfaces.Get(i).PNum(j); invpindex[pi] = PointIndex::INVALID; } + */ + for (auto & f : locfaces) + for (int j = 1; j <= f.GetNP(); j++) + { + PointIndex pi = f.PNum(j); + invpindex[pi] = PointIndex::INVALID; + } - for (i = 1; i <= locfaces.Size(); i++) + // for (i = 1; i <= locfaces.Size(); i++) + for (auto & f : locfaces) { - for (j = 1; j <= locfaces.Get(i).GetNP(); j++) + // for (j = 1; j <= locfaces.Get(i).GetNP(); j++) + for (int j = 1; j <= f.GetNP(); j++) { - PointIndex pi = locfaces.Get(i).PNum(j); + // PointIndex pi = locfaces.Get(i).PNum(j); + PointIndex pi = f.PNum(j); if (!invpindex[pi].IsValid()) { pindex.Append (pi); locpoints.Append (points[pi].P()); - invpindex[pi] = pindex.Size()-1+PointIndex::BASE; + invpindex[pi] = pindex.Size()-1+IndexBASE(); } - // locfaces.Elem(i).PNum(j) = locpoints.Append (points[pi].P()); - // } - // else - locfaces.Elem(i).PNum(j) = invpindex[pi]; + // locfaces.Elem(i).PNum(j) = invpindex[pi]; + f.PNum(j) = invpindex[pi]; } } @@ -622,22 +633,27 @@ int AdFront3 :: GetLocals (int fstind, if (connectedpairs) { - for (i = 1; i <= locpoints.Size(); i++) + // for (i = 1; i <= locpoints.Size(); i++) + for (auto i : locpoints.Range()) { - int pind = pindex.Get(i); - if (pind >= 1 && pind <= connectedpairs->Size ()) + PointIndex pind = pindex[i]; // .Get(i); + // if (pind.IsValid() && pind <= connectedpairs->Size ()) + if (connectedpairs->Range().Contains(pind)) { - for (j = 1; j <= connectedpairs->EntrySize(pind); j++) + // for (int j = 1; j <= connectedpairs->EntrySize(pind); j++) + for (auto j : (*connectedpairs)[pind].Range()) { - int oi = connectedpairs->Get(pind, j); - int other = invpindex.Get(oi); - if (other >= 1 && other <= pindex.Size() && - pindex.Get(other) == oi) + //PointIndex oi = connectedpairs->Get(pind, j); + PointIndex oi = (*connectedpairs)[pind][j]; + PointIndex other = invpindex[oi]; + // if (other >= 1 && other <= pindex.Size() && + if (pindex.Range().Contains(other) && + pindex[other] == oi) { // INDEX_2 coned(i, other); // coned.Sort(); // (*testout) << "connected: " << locpoints.Get(i) << "-" << locpoints.Get(other) << endl; - getconnectedpairs.Set (INDEX_2::Sort (i, other), 1); + getconnectedpairs.Set (PointIndices<2>::Sort (i, other), 1); } } } @@ -664,10 +680,10 @@ int AdFront3 :: GetLocals (int fstind, // returns all points connected with fi void AdFront3 :: GetGroup (int fi, - NgArray & grouppoints, - NgArray & groupelements, - NgArray & pindex, - NgArray & findex) + Array & grouppoints, + Array & groupelements, + Array & pindex, + Array & findex) { // static NgArray pingroup; int changed; @@ -731,8 +747,9 @@ void AdFront3 :: GetGroup (int fi, if (points[pi].Valid()) { grouppoints.Append (points[pi].P()); - pindex.Append (pi); - invpindex[pi] = pindex.Size(); + pindex.Append (pi); + // invpindex[pi] = pindex.Size(); + invpindex[pi] = pindex.Size()-1 + IndexBASE(); } for (int i = 1; i <= faces.Size(); i++) @@ -784,6 +801,54 @@ void AdFront3 :: SetStartFront (int /* baseelnp */) */ } +bool AdFront3 :: PointInsideGroup(const Array &grouppindex, + const Array &groupfaces) const +{ + for(auto pi : Range(points)) + { + const auto& p = points[pi].P(); + bool found = false; + for(const auto& f : groupfaces) + { + for(auto i : Range(3)) + if(grouppindex[f.PNum(i+1)] == pi) + { + found = true; + break; + } + } + if(found) + continue; + + // "random" direction + Vec<3> dir = { 0.123871, 0.15432,-0.43989 }; + DenseMatrix a(3), ainv(3); + Vector b(3), u(3); + + int count = 0; + for(const auto& f : groupfaces) + { + const auto& p1 = points[grouppindex[f.PNum(1)]].P(); + auto v1 = points[grouppindex[f.PNum(2)]].P() - p1; + auto v2 = points[grouppindex[f.PNum(3)]].P() - p1; + for(auto i : Range(3)) + { + a(i,0) = v1[i]; + a(i,1) = v2[i]; + a(i,2) = -dir[i]; + b(i) = p[i] - p1[i]; + } + CalcInverse (a, ainv); + ainv.Mult (b, u); + if (u(0) >= 0 && u(1) >= 0 && u(0)+u(1) <= 1 && + u(2) > 0) + count++; + } + if (count % 2 == 1) + return true; + } + return false; +} bool AdFront3 :: Inside (const Point<3> & p) const { diff --git a/libsrc/meshing/adfront3.hpp b/libsrc/meshing/adfront3.hpp index 5960ca5c..021c364f 100644 --- a/libsrc/meshing/adfront3.hpp +++ b/libsrc/meshing/adfront3.hpp @@ -11,7 +11,13 @@ Advancing front class for volume meshing */ +#include +#include +#include "meshtype.hpp" +#include "geomsearch.hpp" +namespace netgen +{ /// Point in advancing front class FrontPoint3 @@ -25,7 +31,7 @@ class FrontPoint3 /// distance to original boundary int frontnr; /// - int cluster; + PointIndex cluster; public: /// FrontPoint3 (); @@ -89,7 +95,8 @@ public: const PointIndex PNum (int i) const { return pnum[i-1]; } PointIndex & PNum (int i) { return pnum[i-1]; } const PointIndex PNumMod (int i) const { return pnum[(i-1)%np]; } - auto PNums() const { return NgFlatArray (np, &pnum[0]); } + auto PNums() { return FlatArray (np, &pnum[0]); } + auto PNums() const { return FlatArray (np, &pnum[0]); } void Delete () { deleted = true; for (PointIndex & p : pnum) p.Invalidate(); } bool IsDeleted () const { return deleted; } }; @@ -119,7 +126,7 @@ private: /// int hashvalue; /// - int cluster; + PointIndex cluster; public: /// @@ -166,7 +173,7 @@ public: /// friend class AdFront3; - int Cluster () const { return cluster; } + PointIndex Cluster () const { return cluster; } }; @@ -176,14 +183,17 @@ public: class AdFront3 { /// - NgArray points; + // NgArray points; + Array points +; /// NgArray faces; /// - NgArray delpointl; + Array delpointl; /// which points are connected to pi ? - TABLE * connectedpairs; + // TABLE * connectedpairs; + unique_ptr> connectedpairs; /// number of total front faces; int nff; @@ -208,8 +218,8 @@ class AdFront3 int lasti; /// minimal selection-value of baseelements int minval; - NgArray invpindex; - NgArray pingroup; + Array invpindex; + Array pingroup; /// class BoxTree<3> * facetree; @@ -230,9 +240,9 @@ public: /// int GetNF() const { return nff; } - /// + /// 1-based const MiniElement2d & GetFace (int i) const - { return faces.Get(i).Face(); } + { return faces[i-1].Face(); } const auto & Faces() const { return faces; } /// void Print () const; @@ -256,15 +266,18 @@ public: void GetIntersectingFaces (const Point<3> & pmin, const Point<3> & pmax, NgArray & ifaces) const; + bool PointInsideGroup(const Array &grouppindex, + const Array& groupfaces) const; + /// void GetFaceBoundingBox (int i, Box3d & box) const; /// int GetLocals (int baseelement, - NgArray & locpoints, - NgArray & locfaces, // local index - NgArray & pindex, - NgArray & findex, + Array & locpoints, + Array & locfaces, // local index + Array & pindex, + Array & findex, INDEX_2_HASHTABLE & connectedpairs, float xh, float relh, @@ -272,10 +285,10 @@ public: /// void GetGroup (int fi, - NgArray & grouppoints, - NgArray & groupelements, - NgArray & pindex, - NgArray & findex); + Array & grouppoints, + Array & groupelements, + Array & pindex, + Array & findex); /// void DeleteFace (INDEX fi); @@ -284,14 +297,14 @@ public: /// INDEX AddFace (const MiniElement2d & e); /// - INDEX AddConnectedPair (const INDEX_2 & pair); + INDEX AddConnectedPair (PointIndices<2> pair); /// void IncrementClass (INDEX fi) - { faces.Elem(fi).IncrementQualClass(); } + { faces[fi-1].IncrementQualClass(); } /// void ResetClass (INDEX fi) - { faces.Elem(fi).ResetQualClass(); } + { faces[fi-1].ResetQualClass(); } /// void SetStartFront (int baseelnp = 0); @@ -315,7 +328,5 @@ private: void RebuildInternalTables(); }; - - - +} // namespace netgen #endif diff --git a/libsrc/meshing/basegeom.cpp b/libsrc/meshing/basegeom.cpp index f6818eba..099a56ef 100644 --- a/libsrc/meshing/basegeom.cpp +++ b/libsrc/meshing/basegeom.cpp @@ -8,25 +8,26 @@ namespace netgen { struct PointTree { - BoxTree<3> tree; + std::map> tree; + Box<3> bounding_box; - PointTree( Box<3> bb ) : tree(bb) {} + PointTree( Box<3> bb ) : bounding_box(bb) {} - void Insert(Point<3> p, PointIndex n) + void Insert(Point<3> p, PointIndex n, int index) { - tree.Insert(p, p, n); + if(tree.count(index) == 0) + tree.emplace(index, bounding_box); + tree.at(index).Insert(p, p, n); } - PointIndex Find(Point<3> p) const + PointIndex Find(Point<3> p, int index) const { ArrayMem points; - tree.GetIntersecting(p, p, points); + tree.at(index).GetIntersecting(p, p, points); if(points.Size()==0) - throw Exception("cannot find mapped point"); + throw Exception("cannot find mapped point " + ToString(p)); return points[0]; } - - double GetTolerance() { return tree.GetTolerance(); } }; DLL_HEADER GeometryRegisterArray geometryregister; @@ -213,22 +214,24 @@ namespace netgen } } - struct Line - { - Point<3> p0, p1; - inline double Length() const { return (p1-p0).Length(); } - inline double Dist(const Line& other) const + namespace { + struct Line { - Vec<3> n = p1-p0; - Vec<3> q = other.p1-other.p0; - double nq = n*q; - Point<3> p = p0 + 0.5*n; - double lambda = (p-other.p0)*n / (nq + 1e-10); - if (lambda >= 0 && lambda <= 1) - return (p-other.p0-lambda*q).Length(); - return 1e99; - } - }; + Point<3> p0, p1; + inline double Length() const { return (p1-p0).Length(); } + inline double Dist(const Line& other) const + { + Vec<3> n = p1-p0; + Vec<3> q = other.p1-other.p0; + double nq = n*q; + Point<3> p = p0 + 0.5*n; + double lambda = (p-other.p0)*n / (nq + 1e-10); + if (lambda >= 0 && lambda <= 1) + return (p-other.p0-lambda*q).Length(); + return 1e99; + } + }; + } void NetgenGeometry :: Clear() { @@ -256,8 +259,8 @@ namespace netgen auto &s = shapes[i]; s->nr = i; for(auto & ident : s->identifications) - if(s.get() == ident.from) - ident.to->identifications.Append(ident); + if(s.get() == ident.from && s.get() != ident.to) + ident.to->identifications.Append(ident); } }; @@ -266,7 +269,7 @@ namespace netgen for(auto & ident: f->identifications) for(auto e : static_cast(ident.from)->edges) for(auto e_other : static_cast(ident.to)->edges) - if(e->IsMappedShape(*e_other, ident.trafo, tol)) + if(ident.trafo && e->IsMappedShape(*e_other, *ident.trafo, tol)) e->identifications.Append( {e, e_other, ident.trafo, ident.type, ident.name} ); for(auto & e : edges) @@ -278,9 +281,11 @@ namespace netgen GeometryVertex * pfrom[] = { &from.GetStartVertex(), &from.GetEndVertex() }; GeometryVertex * pto[] = { &to.GetStartVertex(), &to.GetEndVertex() }; + if(!ident.trafo) continue; + // swap points of other edge if necessary - Point<3> p_from0 = ident.trafo(from.GetStartVertex().GetPoint()); - Point<3> p_from1 = ident.trafo(from.GetEndVertex().GetPoint()); + Point<3> p_from0 = (*ident.trafo)(from.GetStartVertex().GetPoint()); + Point<3> p_from1 = (*ident.trafo)(from.GetEndVertex().GetPoint()); Point<3> p_to0 = to.GetStartVertex().GetPoint(); if(Dist(p_from1, p_to0) < Dist(p_from0, p_to0)) @@ -298,10 +303,7 @@ namespace netgen auto find_primary = [&] (auto & shapes) { for(auto &s : shapes) - { s->primary = s.get(); - s->primary_to_me = Transformation<3>{ Vec<3> {0,0,0} }; // init with identity - } bool changed = true; @@ -313,23 +315,21 @@ namespace netgen { bool need_inverse = ident.from == s.get(); auto other = need_inverse ? ident.to : ident.from; - if(other->nr < s->primary->nr) - { - auto trafo = ident.trafo; - if(need_inverse) - trafo = trafo.CalcInverse(); - s->primary = other; - s->primary_to_me.Combine(trafo, s->primary_to_me); - changed = true; - } if(other->primary->nr < s->primary->nr) { - auto trafo = ident.trafo; - if(need_inverse) - trafo = trafo.CalcInverse(); s->primary = other->primary; - s->primary_to_me.Combine(trafo, other->primary_to_me); - changed = true; + if(ident.trafo) + { + auto trafo = *ident.trafo; + if(need_inverse) + trafo = trafo.CalcInverse(); + if(!s->primary_to_me) + s->primary_to_me = Transformation<3>( Vec<3>{0., 0., 0.} ); + if(!other->primary_to_me) + other->primary_to_me = Transformation<3>( Vec<3>{0., 0., 0.} ); + s->primary_to_me->Combine(trafo, *other->primary_to_me); + changed = true; + } } } } @@ -474,7 +474,7 @@ namespace netgen } for(const auto& mspnt : mparam.meshsize_points) - mesh.RestrictLocalH(mspnt.pnt, mspnt.h); + mesh.RestrictLocalH(mspnt.pnt, mspnt.h, mspnt.layer); mesh.LoadLocalMeshSize(mparam.meshsizefilename); } @@ -485,6 +485,20 @@ namespace netgen static Timer tdivide("Divide Edges"); RegionTimer rt(tdivide); // -------------------- DivideEdge ----------------- + if(properties.partition) + { + points.SetSize(properties.partition->Size()); + params.SetSize(properties.partition->Size()+2); + params[0] = 0.0; + params.Last() = 1.0; + for(auto i : Range(properties.partition->Size())) + { + params[i+1] = (*properties.partition)[i]; + points[i] = GetPoint(params[i+1]); + } + return; + } + tdivedgesections.Start(); auto layer = properties.layer; double safety = 0.5*(1.-mparam.grading); @@ -513,7 +527,7 @@ namespace netgen tdivedgesections.Stop(); - auto n = hvalue.Size()-1; + // auto n = hvalue.Size()-1; int nsubedges = max2(1, int(floor(hvalue.Last()+0.5))); points.SetSize(nsubedges-1); params.SetSize(nsubedges+1); @@ -568,29 +582,30 @@ namespace netgen auto & identifications = mesh.GetIdentifications(); - std::map vert2meshpt; + Array vert2meshpt(vertices.Size()); + vert2meshpt = PointIndex::INVALID; + for(auto & vert : vertices) { auto pi = mesh.AddPoint(vert->GetPoint(), vert->properties.layer); - tree.Insert(mesh[pi], pi); - vert2meshpt[vert->GetHash()] = pi; + vert2meshpt[vert->nr] = pi; mesh[pi].Singularity(vert->properties.hpref); mesh[pi].SetType(FIXEDPOINT); - - Element0d el(pi, pi); + + Element0d el(pi, pi-IndexBASE()+1); el.name = vert->properties.GetName(); - mesh.SetCD3Name(pi, el.name); + mesh.SetCD3Name(pi-IndexBASE()+1, el.name); mesh.pointelements.Append (el); } for(auto & vert : vertices) for(auto & ident : vert->identifications) - identifications.Add(vert2meshpt[ident.from->GetHash()], - vert2meshpt[ident.to->GetHash()], + identifications.Add(vert2meshpt[ident.from->nr], + vert2meshpt[ident.to->nr], ident.name, ident.type); - size_t segnr = 0; + // size_t segnr = 0; auto nedges = edges.Size(); Array> all_pnums(nedges); Array> all_params(nedges); @@ -600,12 +615,12 @@ namespace netgen auto edge = edges[edgenr].get(); PointIndex startp, endp; // throws if points are not found - startp = vert2meshpt.at(edge->GetStartVertex().GetHash()); - endp = vert2meshpt.at(edge->GetEndVertex().GetHash()); + startp = vert2meshpt[edge->GetStartVertex().nr]; + endp = vert2meshpt[edge->GetEndVertex().nr]; // ignore collapsed edges - if(startp == endp && edge->GetLength() < 1e-10 * bounding_box.Diam()) - continue; + if(edge->IsDegenerated()) + continue; // ----------- Add Points to mesh and create segments ----- auto & pnums = all_pnums[edgenr]; @@ -644,7 +659,7 @@ namespace netgen { auto nr_primary = edge->primary->nr; auto & pnums_primary = all_pnums[nr_primary]; - auto & params_primary = all_params[nr_primary]; + // auto & params_primary = all_params[nr_primary]; auto trafo = edge->primary_to_me; auto np = pnums_primary.Size(); @@ -652,7 +667,9 @@ namespace netgen edge_params.SetSize(np-2); for(auto i : Range(np-2)) { - edge_points[i] = trafo(mesh[pnums_primary[i+1]]); + edge_points[i] = mesh[pnums_primary[i+1]]; + if(trafo) + edge_points[i] = (*trafo)(edge_points[i]); EdgePointGeomInfo gi; edge->ProjectPoint(edge_points[i], &gi); edge_params[i] = gi.dist; @@ -683,7 +700,8 @@ namespace netgen { for(size_t i : std::vector{0UL, pnums_primary.Size()-1}) { - auto p_mapped = trafo(mesh[pnums_primary[i]]); + auto p_mapped = mesh[pnums_primary[i]]; + if(trafo) p_mapped = (*trafo)(p_mapped); EdgePointGeomInfo gi; edge->ProjectPoint(p_mapped, &gi); params[i] = gi.dist; @@ -701,13 +719,14 @@ namespace netgen for(auto i : Range(edge_points)) { auto pi = mesh.AddPoint(edge_points[i], edge->properties.layer); - tree.Insert(mesh[pi], pi); + if(edge->identifications.Size()) + tree.Insert(mesh[pi], pi, edge->nr); pnums[i+1] = pi; } for(auto i : Range(pnums.Size()-1)) { - segnr++; + // segnr++; Segment seg; seg[0] = pnums[i]; seg[1] = pnums[i+1]; @@ -733,10 +752,16 @@ namespace netgen if(ident.from == edge.get()) { auto & pnums = all_pnums[edge->nr]; + if(pnums.Size() < 2) continue; // degenerated edge // start and end vertex are already identified for(auto pi : pnums.Range(1, pnums.Size()-1)) { - auto pi_other = tree.Find(ident.trafo(mesh[pi])); + Point<3> p_other = mesh[pi]; + if(ident.trafo) + p_other = (*ident.trafo)(mesh[pi]); + else + static_cast(ident.to)->ProjectPoint(p_other, nullptr); + auto pi_other = tree.Find(p_other, ident.to->nr); identifications.Add(pi, pi_other, ident.name, ident.type); } } @@ -775,7 +800,10 @@ namespace netgen PointIndex pi = vert->nr + 1; if(glob2loc[pi] == 0) { - meshing.AddPoint(mesh[pi], pi); + auto gi = face.Project(mesh[pi]); + MultiPointGeomInfo mgi; + mgi.AddPointGeomInfo(gi); + meshing.AddPoint(mesh[pi], pi, &mgi); cntp++; glob2loc[pi] = cntp; } @@ -829,7 +857,7 @@ namespace netgen if(face.primary == &face) { // check if this face connects two identified closesurfaces - auto & idents = mesh.GetIdentifications(); + // auto & idents = mesh.GetIdentifications(); std::set relevant_edges; auto segments = face.GetBoundary(mesh); for(const auto &s : segments) @@ -842,7 +870,7 @@ namespace netgen for(auto pi : s.PNums()) if(!is_point_in_tree[pi]) { - tree.Insert(mesh[pi], pi); + tree.Insert(mesh[pi], pi, -1); is_point_in_tree[pi] = true; } @@ -851,7 +879,7 @@ namespace netgen constexpr int NOT_MAPPED = -1; mapped_edges = UNINITIALIZED; - Transformation<3> trafo; + optional> trafo; if(face.IsConnectingCloseSurfaces()) { @@ -866,7 +894,7 @@ namespace netgen { auto edgenr = s.edgenr-1; auto & edge = *edges[edgenr]; - ShapeIdentification *edge_mapping; + // ShapeIdentification *edge_mapping; // have edgenr first time, search for closesurface identification @@ -893,8 +921,6 @@ namespace netgen Element2d sel(4); sel[0] = s[0]; sel[1] = s[1]; - sel[2] = tree.Find(trafo(mesh[s[1]])); - sel[3] = tree.Find(trafo(mesh[s[0]])); auto gis = sel.GeomInfo(); for(auto i : Range(2)) { @@ -902,6 +928,21 @@ namespace netgen gis[i].v = s.epgeominfo[i].v; } + Point<3> p2 = mesh[s[1]]; + Point<3> p3 = mesh[s[0]]; + if(trafo) + { + p2 = (*trafo)(p2); + p3 = (*trafo)(p3); + } + else + { + edges[mapped_edges[edgenr]]->ProjectPoint(p2, nullptr); + edges[mapped_edges[edgenr]]->ProjectPoint(p3, nullptr); + } + sel[2] = tree.Find(p2, -1); + sel[3] = tree.Find(p3, -1); + // find mapped segment to set PointGeomInfo correctly Segment s_other; for(auto si_other : p2seg[sel[2]]) @@ -944,11 +985,12 @@ namespace netgen } bool have_identifications = false; + std::map, PointIndex> mapto; for(auto & face : faces) if(face->primary != face.get()) { have_identifications = true; - MapSurfaceMesh(mesh, *face); + MapSurfaceMesh(mesh, *face, mapto); } // identify points on faces @@ -979,7 +1021,7 @@ namespace netgen if(mesh[pi].Type() == SURFACEPOINT && pi_to_face[pi]==-1) { pi_to_face[pi] = face->nr; - tree.Insert(mesh[pi], pi); + tree.Insert(mesh[pi], pi, -1); pi_of_face[face->nr].Append(pi); } } @@ -992,7 +1034,8 @@ namespace netgen if(ident.from == face.get()) for(auto pi : pi_of_face[face->nr]) { - auto pi_other = tree.Find(ident.trafo(mesh[pi])); + auto pi_primary = ident.from->primary->nr == ident.from->nr ? pi : mapto[{pi, ident.to->primary->nr}]; + auto pi_other = ident.to->primary->nr == ident.to->nr ? pi_primary : mapto[{pi_primary, ident.to->nr}]; mesh_ident.Add(pi, pi_other, ident.name, ident.type); } } @@ -1002,7 +1045,7 @@ namespace netgen multithread.task = savetask; } - void NetgenGeometry :: MapSurfaceMesh( Mesh & mesh, const GeometryFace & dst ) const + void NetgenGeometry :: MapSurfaceMesh( Mesh & mesh, const GeometryFace & dst, std::map, PointIndex> & mapto ) const { static Timer timer("MapSurfaceMesh"); RegionTimer rt(timer); @@ -1029,7 +1072,24 @@ namespace netgen auto pi = seg[i]; if(!is_point_in_tree[pi]) { - tree.Insert(trafo(mesh[pi]), pi); + auto p = mesh[pi]; + if(trafo) + p = (*trafo)(p); + else + for(auto& edge: dst.edges) + if (edge->primary->nr == seg.edgenr-1) + { + if (mesh[pi].Type() == FIXEDPOINT) { + if((edge->GetStartVertex().GetPoint() - p).Length2() >\ + (edge->GetEndVertex().GetPoint() - p).Length2()) + p = edge->GetEndVertex().GetPoint(); + else + p = edge->GetStartVertex().GetPoint(); + } + else + edge->ProjectPoint(p, nullptr); + } + tree.Insert(p, pi, -1); is_point_in_tree[pi] = true; } } @@ -1041,7 +1101,7 @@ namespace netgen { auto pi = seg[i]; if(!pmap[pi].IsValid()) - pmap[tree.Find(mesh[pi])] = pi; + pmap[tree.Find(mesh[pi], -1)] = pi; // store uv values (might be different values for same point in case of internal edges) double u = seg.epgeominfo[i].u; @@ -1057,12 +1117,7 @@ namespace netgen } xbool do_invert = maybe; - if(dst.identifications[0].type == Identifications::PERIODIC) - { - auto other = static_cast(dst.primary); - if(dst.domin != other->domout && dst.domout != other->domin) - do_invert = true; - } + if(!trafo) do_invert = true; // now insert mapped surface elements for(auto sei : mesh.SurfaceElements().Range()) @@ -1071,14 +1126,6 @@ namespace netgen if(sel.GetIndex() != src.nr+1) continue; - if(do_invert.IsMaybe()) - { - auto n_src = src.GetNormal(mesh[sel[0]]); - auto n_dist = dst.GetNormal(trafo(mesh[sel[0]])); - Mat<3> normal_matrix; - CalcInverse(Trans(trafo.GetMatrix()), normal_matrix); - do_invert = n_src * (normal_matrix * n_dist) < 0.0; - } auto sel_new = sel; sel_new.SetIndex(dst.nr+1); for(auto i : Range(sel.PNums())) @@ -1086,60 +1133,75 @@ namespace netgen auto pi = sel[i]; if(!pmap[pi].IsValid()) { - pmap[pi] = mesh.AddPoint(trafo(mesh[pi]), 1, SURFACEPOINT); + auto p = mesh[pi]; + if(trafo) + p = (*trafo)(p); + else + dst.Project(p); + pmap[pi] = mesh.AddPoint(p, 1, SURFACEPOINT); } sel_new[i] = pmap[pi]; + mapto[{pi, dst.nr}] = pmap[pi]; + mapto[{pmap[pi], src.nr}] = pi; } - if(do_invert.IsTrue()) - sel_new.Invert(); + if(do_invert.IsMaybe()) + { + auto n_src = src.GetNormal(mesh[sel[0]]); + auto n_dist = dst.GetNormal(mesh[sel_new[0]]); + Mat<3> normal_matrix; + CalcInverse(Trans(trafo->GetMatrix()), normal_matrix); + do_invert = (normal_matrix * n_src) * n_dist < 0.0; + } + if(do_invert.IsTrue()) + sel_new.Invert(); - for(auto i : Range(sel.PNums())) - { - auto pi = sel_new[i]; - if(uv_values.Range().Next() <= pi) - { - // new point (inner surface point) - PointGeomInfo gi; - dst.CalcPointGeomInfo(mesh[sel_new[i]], gi); - sel_new.GeomInfo()[i] = gi; - continue; - } + for(auto i : Range(sel.PNums())) + { + auto pi = sel_new[i]; + if(uv_values.Range().Next() <= pi) + { + // new point (inner surface point) + PointGeomInfo gi; + dst.CalcPointGeomInfo(mesh[sel_new[i]], gi); + sel_new.GeomInfo()[i] = gi; + continue; + } - const auto & uvs = uv_values[pi]; - if(uvs.Size() == 1) - { - // appears only once -> take uv values from edgepointgeominfo - const auto & [u,v] = uvs[0]; - PointGeomInfo gi; - gi.u = u; - gi.v = v; - sel_new.GeomInfo()[i] = gi; - } - else if(uvs.Size() > 1) - { - // multiple uv pairs -> project to close point and select closest uv pair - double eps = 1e-3; - auto p = Point<3>((1.0-eps)*Vec<3>(mesh[sel_new.PNumMod(i+1)]) + - eps/2*Vec<3>(mesh[sel_new.PNumMod(i+2)]) + - eps/2*Vec<3>(mesh[sel_new.PNumMod(i+3)])); - PointGeomInfo gi_p, gi; - dst.CalcPointGeomInfo(p, gi_p); - gi.trignum = gi_p.trignum; - double min_dist = numeric_limits::max(); - for(const auto & [u,v] : uvs) - { - double dist = (gi_p.u-u)*(gi_p.u-u) + (gi_p.v-v)*(gi_p.v-v); - if(dist < min_dist) - { - min_dist = dist; - gi.u = u; - gi.v = v; - } - } - sel_new.GeomInfo()[i] = gi; - } - else - throw Exception(string(__FILE__) + ":"+ToString(__LINE__) + " shouldn't come here"); + const auto & uvs = uv_values[pi]; + if(uvs.Size() == 1) + { + // appears only once -> take uv values from edgepointgeominfo + const auto & [u,v] = uvs[0]; + PointGeomInfo gi; + gi.u = u; + gi.v = v; + sel_new.GeomInfo()[i] = gi; + } + else if(uvs.Size() > 1) + { + // multiple uv pairs -> project to close point and select closest uv pair + double eps = 1e-3; + auto p = Point<3>((1.0-eps)*Vec<3>(mesh[sel_new.PNumMod(i+1)]) + + eps/2*Vec<3>(mesh[sel_new.PNumMod(i+2)]) + + eps/2*Vec<3>(mesh[sel_new.PNumMod(i+3)])); + PointGeomInfo gi_p, gi; + dst.CalcPointGeomInfo(p, gi_p); + gi.trignum = gi_p.trignum; + double min_dist = numeric_limits::max(); + for(const auto & [u,v] : uvs) + { + double dist = (gi_p.u-u)*(gi_p.u-u) + (gi_p.v-v)*(gi_p.v-v); + if(dist < min_dist) + { + min_dist = dist; + gi.u = u; + gi.v = v; + } + } + sel_new.GeomInfo()[i] = gi; + } + else + throw Exception(string(__FILE__) + ":"+ToString(__LINE__) + " shouldn't come here"); } mesh.AddSurfaceElement(sel_new); } @@ -1158,6 +1220,7 @@ namespace netgen { PrintMessage(3, "Optimization step ", i); meshopt.SetFaceIndex(k+1); + meshopt.SetMetricWeight (mparam.elsizeweight); int innerstep = 0; for(auto optstep : mparam.optimize2d) { @@ -1186,8 +1249,7 @@ namespace netgen void NetgenGeometry :: FinalizeMesh(Mesh& mesh) const { - if(solids.Size()) - for (int i = 0; i < mesh.GetNDomains(); i++) + for (int i = 0; i < std::min(solids.Size(), (size_t)mesh.GetNDomains()); i++) if (auto name = solids[i]->properties.name) mesh.SetMaterial (i+1, *name); @@ -1253,6 +1315,13 @@ namespace netgen if(multithread.terminate || mparam.perfstepsend <= MESHCONST_MESHEDGES) return 0; + if(dimension == 1) + { + FinalizeMesh(*mesh); + mesh->SetDimension(1); + return 0; + } + if (mparam.perfstepsstart <= MESHCONST_MESHSURFACE) { MeshSurface(*mesh, mparam); @@ -1277,9 +1346,6 @@ namespace netgen if (res != MESHING3_OK) return 1; if (multithread.terminate) return 0; - RemoveIllegalElements (*mesh); - if (multithread.terminate) return 0; - MeshQuality3d (*mesh); } diff --git a/libsrc/meshing/basegeom.hpp b/libsrc/meshing/basegeom.hpp index bb9a508c..fd22ece8 100644 --- a/libsrc/meshing/basegeom.hpp +++ b/libsrc/meshing/basegeom.hpp @@ -7,10 +7,18 @@ /* Date: 23. Aug. 09 */ /**************************************************************************/ +#include +#include + +#include "meshtype.hpp" +#include "meshclass.hpp" + struct Tcl_Interp; namespace netgen { + class Refinement; + struct ShapeProperties { optional name; @@ -19,10 +27,12 @@ namespace netgen double hpref = 0; // number of hp refinement levels (will be multiplied by factor later) int layer = 1; optional quad_dominated; + optional> partition; void Merge(const ShapeProperties & prop2) { if (!name && prop2.name) name = prop2.name; if (!col && prop2.col) col = prop2.col; + if (!partition && prop2.partition) partition = prop2.partition; maxh = min2(maxh, prop2.maxh); hpref = max2(hpref, prop2.hpref); if(!quad_dominated.has_value()) quad_dominated = prop2.quad_dominated; @@ -44,7 +54,7 @@ namespace netgen { GeometryShape * from; GeometryShape * to; - Transformation<3> trafo; + optional> trafo; Identifications::ID_TYPE type; string name = ""; }; @@ -57,10 +67,9 @@ namespace netgen ShapeProperties properties; Array identifications; GeometryShape * primary; - Transformation<3> primary_to_me; + optional> primary_to_me = nullopt; virtual ~GeometryShape() {} - virtual size_t GetHash() const = 0; virtual bool IsMappedShape( const GeometryShape & other, const Transformation<3> & trafo, double tolerance ) const; }; @@ -77,6 +86,9 @@ namespace netgen protected: GeometryVertex *start, *end; public: + // Neighboring domains in 2d + // In 3d unused, EXCEPT for free floating edges in a domain, + // then both are pointing to the containing domain int domin=-1, domout=-1; GeometryEdge( GeometryVertex &start_, GeometryVertex &end_ ) @@ -178,7 +190,10 @@ namespace netgen }; class DLL_HEADER GeometrySolid : public GeometryShape - { }; + { + public: + Array free_edges; // edges with no adjacent face + }; class DLL_HEADER NetgenGeometry { @@ -203,11 +218,18 @@ namespace netgen size_t GetNVertices() const { return vertices.Size(); } size_t GetNEdges() const { return edges.Size(); } size_t GetNFaces() const { return faces.Size(); } + size_t GetNSolids() const { return solids.Size(); } + const GeometrySolid & GetSolid(int i) const { return *solids[i]; } const GeometryFace & GetFace(int i) const { return *faces[i]; } const GeometryEdge & GetEdge(int i) const { return *edges[i]; } const GeometryVertex & GetVertex(int i) const { return *vertices[i]; } + auto Solids() const { return FlatArray{solids}; } + auto Faces() const { return FlatArray{faces}; } + auto Edges() const { return FlatArray{edges}; } + auto Vertices() const { return FlatArray{vertices}; } + virtual Array GetFaceVertices(const GeometryFace& face) const { return Array{}; } void Clear(); @@ -235,7 +257,7 @@ namespace netgen virtual void MeshSurface(Mesh& mesh, const MeshingParameters& mparam) const; virtual bool MeshFace(Mesh& mesh, const MeshingParameters& mparam, int nr, FlatArray glob2loc) const; - virtual void MapSurfaceMesh( Mesh & mesh, const GeometryFace & dst ) const; + virtual void MapSurfaceMesh( Mesh & mesh, const GeometryFace & dst, std::map, PointIndex> & mapto) const; virtual void OptimizeSurface(Mesh& mesh, const MeshingParameters& mparam) const; virtual void FinalizeMesh(Mesh& mesh) const; @@ -249,7 +271,7 @@ namespace netgen virtual void ProjectPointEdge (int surfind, int surfind2, Point<3> & p, EdgePointGeomInfo* gi = nullptr) const { - if(gi && gi->edgenr < edges.Size()) + if(gi && gi->edgenr < edges.Size() && gi->edgenr >= 0) edges[gi->edgenr]->ProjectPoint(p, gi); } @@ -312,13 +334,6 @@ namespace netgen throw Exception("Base geometry get tangent called"); } - virtual size_t GetEdgeIndex(const GeometryEdge& edge) const - { - for(auto i : Range(edges)) - if(edge.GetHash() == edges[i]->GetHash()) - return i; - throw Exception("Couldn't find edge index"); - } virtual void Save (const filesystem::path & filename) const; virtual void SaveToMeshFile (ostream & /* ost */) const { ; } }; diff --git a/libsrc/meshing/bisect.cpp b/libsrc/meshing/bisect.cpp index fcabc286..bc9b44d0 100644 --- a/libsrc/meshing/bisect.cpp +++ b/libsrc/meshing/bisect.cpp @@ -1,25 +1,17 @@ #include -#include "meshing.hpp" +#include + +#include "meshclass.hpp" +#include "bisect.hpp" +#include "validate.hpp" +#include "paralleltop.hpp" + +// #include "meshing.hpp" // quickfix for parallel #define noDEBUG - namespace netgen { - class MarkedTet; - class MarkedPrism; - class MarkedIdentification; - class MarkedTri; - class MarkedQuad; - - typedef Array T_MTETS; - typedef NgArray T_MPRISMS; - typedef NgArray T_MIDS; - typedef NgArray T_MTRIS; - typedef NgArray T_MQUADS; - - - class MarkedTet { public: @@ -43,6 +35,7 @@ namespace netgen // unsigned char faceedges[4]; bool incorder; unsigned int order:6; + int8_t newest_vertex; MarkedTet() = default; /* @@ -204,6 +197,7 @@ namespace netgen bool incorder; unsigned int order:6; + int8_t newest_vertex; }; ostream & operator<< (ostream & ost, const MarkedTri & mt) @@ -301,30 +295,28 @@ namespace netgen - + template int BTSortEdges (const Mesh & mesh, - const NgArray< NgArray* > & idmaps, - INDEX_2_CLOSED_HASHTABLE & edgenumber) + const NgArray & idmaps, + HASHTABLE_EDGENUMBER & edgenumber) { PrintMessage(4,"sorting ... "); // if (mesh.PureTetMesh()) - if (1) + if (true) { // new, fast version + Array> edges; - NgArray edges; - NgArray eclasses; - - int i, j, k; + // int i, j, k; int cntedges = 0; - int go_on; + bool go_on; int ned(0); // enumerate edges: - for (i = 1; i <= mesh.GetNE(); i++) - { - const Element & el = mesh.VolumeElement (i); + + for (const Element & el : mesh.VolumeElements()) + { static int tetedges[6][2] = { { 1, 2 }, { 1, 3 }, @@ -378,11 +370,10 @@ namespace netgen throw NgException("Bisect, element type not handled in switch"); } - for (j = 0; j < ned; j++) + for (int j = 0; j < ned; j++) { - INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1])); + PointIndices<2> i2(el.PNum(tip[j][0]), el.PNum(tip[j][1])); i2.Sort(); - //(*testout) << "edge " << i2 << endl; if (!edgenumber.Used(i2)) { cntedges++; @@ -393,9 +384,9 @@ namespace netgen } // additional surface edges: - for (i = 1; i <= mesh.GetNSE(); i++) - { - const Element2d & el = mesh.SurfaceElement (i); + + for (const Element2d & el : mesh.SurfaceElements()) + { static int trigedges[3][2] = { { 1, 2 }, { 2, 3 }, @@ -433,9 +424,9 @@ namespace netgen } } - for (j = 0; j < ned; j++) + for (int j = 0; j < ned; j++) { - INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1])); + PointIndices<2> i2(el.PNum(tip[j][0]), el.PNum(tip[j][1])); i2.Sort(); if (!edgenumber.Used(i2)) { @@ -447,20 +438,17 @@ namespace netgen } - - - - eclasses.SetSize (cntedges); - for (i = 1; i <= cntedges; i++) + NgArray eclasses(cntedges); + for (int i = 1; i <= cntedges; i++) eclasses.Elem(i) = i; // identify edges in element stack do { - go_on = 0; - for (i = 1; i <= mesh.GetNE(); i++) + go_on = false; + for (auto ei : mesh.VolumeElements().Range()) { - const Element & el = mesh.VolumeElement (i); + const Element & el = mesh[ei]; if (el.GetType() != PRISM && el.GetType() != PRISM12 && @@ -495,12 +483,12 @@ namespace netgen throw NgException("Bisect, element type not handled in switch, 2"); } - for (j = 0; j < 3; j++) + for (int j = 0; j < 3; j++) { - INDEX_2 e1 (el.PNum(pairs[j][0]), - el.PNum(pairs[j][1])); - INDEX_2 e2 (el.PNum(pairs[j][2]), - el.PNum(pairs[j][3])); + PointIndices<2> e1 (el.PNum(pairs[j][0]), + el.PNum(pairs[j][1])); + PointIndices<2> e2 (el.PNum(pairs[j][2]), + el.PNum(pairs[j][3])); e1.Sort(); e2.Sort(); @@ -514,34 +502,32 @@ namespace netgen { eclasses.Elem(eclass1) = eclasses.Get(eclass2); - go_on = 1; + go_on = true; } else if (eclasses.Get(eclass2) > eclasses.Get(eclass1)) { eclasses.Elem(eclass2) = eclasses.Get(eclass1); - go_on = 1; + go_on = true; } } } - for(SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) - { - const Element2d & el2d = mesh[sei]; - - for(i = 0; i < el2d.GetNP(); i++) + for (const Element2d & el2d : mesh.SurfaceElements()) + { + for(int i = 0; i < el2d.GetNP(); i++) { - INDEX_2 e1(el2d[i], el2d[(i+1) % el2d.GetNP()]); + PointIndices<2> e1(el2d[i], el2d[(i+1) % el2d.GetNP()]); e1.Sort(); - INDEX_2 e2; + PointIndices<2> e2; - for(k = 0; k < idmaps.Size(); k++) + for(int k = 0; k < idmaps.Size(); k++) { - e2.I1() = (*idmaps[k])[e1.I1()]; - e2.I2() = (*idmaps[k])[e1.I2()]; + e2[0] = (*idmaps[k])[e1[0]]; + e2[1] = (*idmaps[k])[e1[1]]; - if(e2.I1() == 0 || e2.I2() == 0 || + if(!e2.I1().IsValid() || !e2.I2().IsValid() || e1.I1() == e2.I1() || e1.I2() == e2.I2()) continue; @@ -560,14 +546,14 @@ namespace netgen eclasses.Get(eclass2); - go_on = 1; + go_on = true; } else if (eclasses.Get(eclass2) > eclasses.Get(eclass1)) { eclasses.Elem(eclass2) = eclasses.Get(eclass1); - go_on = 1; + go_on = true; } } } @@ -592,13 +578,8 @@ namespace netgen edgelength.Elem(i) = 1e20; */ - for (i = 1; i <= cntedges; i++) - { - INDEX_2 edge = edges.Get(i); - double elen = Dist (mesh.Point(edge.I1()), - mesh.Point(edge.I2())); - edgelength.Elem (i) = elen; - } + for (int i = 0; i < cntedges; i++) + edgelength[i] = Dist (mesh[edges[i][0]], mesh[edges[i][1]]); /* for (i = 1; i <= mesh.GetNE(); i++) @@ -659,7 +640,7 @@ namespace netgen */ - for (i = 1; i <= cntedges; i++) + for (int i = 1; i <= cntedges; i++) { if (eclasses.Get(i) != i) { @@ -671,8 +652,8 @@ namespace netgen TABLE eclasstab(cntedges); - for (i = 1; i <= cntedges; i++) - eclasstab.Add1 (eclasses.Get(i), i); + for (int i = 1; i <= cntedges; i++) + eclasstab.Add1 (eclasses.Get(i), i-1); // sort edges: @@ -681,14 +662,12 @@ namespace netgen QuickSort (edgelength, sorted); int cnt = 0; - for (i = 1; i <= cntedges; i++) + for (int i = 1; i <= cntedges; i++) { int ii = sorted.Get(i); - for (j = 1; j <= eclasstab.EntrySize(ii); j++) - { - cnt++; - edgenumber.Set (edges.Get(eclasstab.Get(ii, j)), cnt); - } + for (int j = 1; j <= eclasstab.EntrySize(ii); j++) + edgenumber.Set (edges[eclasstab.Get(ii, j)], ++cnt); + } return cnt; } @@ -698,9 +677,9 @@ namespace netgen { // old version - int i, j; + // int i, j; int cnt = 0; - int found; + bool found; double len2, maxlen2; INDEX_2 ep; @@ -709,12 +688,13 @@ namespace netgen do { - found = 0; + found = false; maxlen2 = 1e30; - for (i = 1; i <= mesh.GetNE(); i++) + // for (int i = 1; i <= mesh.GetNE(); i++) + for (auto ei : mesh.VolumeElements().Range()) { - const Element & el = mesh.VolumeElement (i); + const Element & el = mesh[ei]; // .VolumeElement (i); int ned; int tetedges[6][2] = { { 1, 2 }, @@ -764,9 +744,9 @@ namespace netgen throw NgException("Bisect, element type not handled in switch, 3"); } - for (j = 0; j < ned; j++) + for (int j = 0; j < ned; j++) { - INDEX_2 i2(el.PNum(tip[j][0]), el.PNum(tip[j][1])); + PointIndices<2> i2(el.PNum(tip[j][0]), el.PNum(tip[j][1])); i2.Sort(); if (!edgenumber.Used(i2)) { @@ -776,7 +756,7 @@ namespace netgen { maxlen2 = len2; ep = i2; - found = 1; + found = true; } } } @@ -788,13 +768,14 @@ namespace netgen // find connected edges: - int go_on = 0; + bool go_on = false; do { - go_on = 0; - for (i = 1; i <= mesh.GetNE(); i++) + go_on = false; + //for (int i = 1; i <= mesh.GetNE(); i++) + for (auto ei : mesh.VolumeElements().Range()) { - const Element & el = mesh.VolumeElement (i); + const Element & el = mesh[ei]; // .VolumeElement (i); if (el.GetNP() != 6) continue; int prismpairs[3][4] = @@ -824,29 +805,29 @@ namespace netgen throw NgException("Bisect, element type not handled in switch, 3a"); } - for (j = 0; j < 3; j++) + for (int j = 0; j < 3; j++) { - INDEX_2 e1 (el.PNum(pairs[j][0]), - el.PNum(pairs[j][1])); - INDEX_2 e2 (el.PNum(pairs[j][2]), - el.PNum(pairs[j][3])); + PointIndices<2> e1 (el.PNum(pairs[j][0]), + el.PNum(pairs[j][1])); + PointIndices<2> e2 (el.PNum(pairs[j][2]), + el.PNum(pairs[j][3])); e1.Sort(); e2.Sort(); - int used1 = edgenumber.Used (e1); - int used2 = edgenumber.Used (e2); + bool used1 = edgenumber.Used (e1); + bool used2 = edgenumber.Used (e2); if (used1 && !used2) { cnt++; edgenumber.Set (e2, cnt); - go_on = 1; + go_on = true; } if (used2 && !used1) { cnt++; edgenumber.Set (e1, cnt); - go_on = 1; + go_on = true; } } } @@ -862,9 +843,9 @@ namespace netgen - + template void BTDefineMarkedTet (const Element & el, - INDEX_2_CLOSED_HASHTABLE & edgenumber, + T_EDGENUMBER & edgenumber, MarkedTet & mt) { for (int i = 0; i < 4; i++) @@ -881,7 +862,7 @@ namespace netgen for (int i = 0; i < 3; i++) for (int j = i+1; j < 4; j++) { - INDEX_2 i2(mt.pnums[i], mt.pnums[j]); + PointIndices<2> i2(mt.pnums[i], mt.pnums[j]); i2.Sort(); int hval = edgenumber.Get(i2); if (hval > val) @@ -901,9 +882,12 @@ namespace netgen for (int j = i+1; j < 4; j++) if (i != k && j != k) { - INDEX_2 i2(mt.pnums[i], mt.pnums[j]); + /* + PointIndices<2> i2(mt.pnums[i], mt.pnums[j]); i2.Sort(); int hval = edgenumber.Get(i2); + */ + int hval = edgenumber[ { mt.pnums[i], mt.pnums[j] } ]; if (hval > val) { val = hval; @@ -916,9 +900,9 @@ namespace netgen - + template void BTDefineMarkedPrism (const Element & el, - INDEX_2_CLOSED_HASHTABLE & edgenumber, + T_EDGENUMBER & edgenumber, MarkedPrism & mp) { if (el.GetType() == PRISM || @@ -959,7 +943,7 @@ namespace netgen for (int i = 0; i < 2; i++) for (int j = i+1; j < 3; j++) { - INDEX_2 i2(mp.pnums[i], mp.pnums[j]); + PointIndices<2> i2(mp.pnums[i], mp.pnums[j]); i2.Sort(); int hval = edgenumber.Get(i2); if (hval > val) @@ -971,16 +955,17 @@ namespace netgen } - + template bool BTDefineMarkedId(const Element2d & el, - INDEX_2_CLOSED_HASHTABLE & edgenumber, - const NgArray & idmap, + T_EDGENUMBER & edgenumber, + const idmap_type & idmap, MarkedIdentification & mi) { bool identified = true; mi.np = el.GetNP(); - int min1(0),min2(0); + // int min1(0),min2(0); + PointIndex min1(PointIndex::INVALID), min2(PointIndex::INVALID); for(int j = 0; identified && j < mi.np; j++) { mi.pnums[j] = el[j]; @@ -991,7 +976,7 @@ namespace netgen if(j == 0 || mi.pnums[j+mi.np] < min2) min2 = mi.pnums[j+mi.np]; - identified = (mi.pnums[j+mi.np] != 0 && mi.pnums[j+mi.np] != mi.pnums[j]); + identified = (mi.pnums[j+mi.np].IsValid() && mi.pnums[j+mi.np] != mi.pnums[j]); } identified = identified && (min1 < min2); @@ -1006,7 +991,7 @@ namespace netgen int val = 0; for (int i = 0; i < mi.np; i++) { - INDEX_2 i2(mi.pnums[i], mi.pnums[(i+1)%mi.np]); + PointIndices<2> i2(mi.pnums[i], mi.pnums[(i+1)%mi.np]); i2.Sort(); int hval = edgenumber.Get(i2); if (hval > val) @@ -1020,9 +1005,10 @@ namespace netgen return identified; } - + + template void BTDefineMarkedTri (const Element2d & el, - INDEX_2_CLOSED_HASHTABLE & edgenumber, + T_EDGENUMBER & edgenumber, MarkedTri & mt) { for (int i = 0; i < 3; i++) @@ -1037,13 +1023,17 @@ namespace netgen mt.incorder = 0; mt.order = 1; - int val = 0; + int val = -1; for (int i = 0; i < 2; i++) for (int j = i+1; j < 3; j++) { - INDEX_2 i2(mt.pnums[i], mt.pnums[j]); + /* + PointIndices<2> i2(mt.pnums[i], mt.pnums[j]); i2.Sort(); int hval = edgenumber.Get(i2); + */ + int hval = edgenumber[ SortedPointIndices<2>(mt.pnums[i], mt.pnums[j]) ]; + // int hval = edgenumber[ { mt.pnums[i], mt.pnums[j] }]; if (hval > val) { val = hval; @@ -1076,9 +1066,9 @@ namespace netgen - + template void BTDefineMarkedQuad (const Element2d & el, - INDEX_2_CLOSED_HASHTABLE & edgenumber, + T_EDGENUMBER & edgenumber, MarkedQuad & mq) { for (int i = 0; i < 4; i++) @@ -1113,15 +1103,16 @@ namespace netgen for (int step = 1; step <= 2; step++) { - for (int i = 1; i <= mtets.Size(); i++) + // for (int i = 1; i <= mtets.Size(); i++) + for (ElementIndex ei : mtets.Range()) { double h = 0; for (int j = 0; j < 3; j++) for (int k = j+1; k < 4; k++) { - const Point<3> & p1 = mesh.Point (mtets[i-1].pnums[j]); - const Point<3> & p2 = mesh.Point (mtets[i-1].pnums[k]); + const Point<3> & p1 = mesh.Point (mtets[ei].pnums[j]); + const Point<3> & p2 = mesh.Point (mtets[ei].pnums[k]); double hh = Dist2 (p1, p2); if (hh > h) h = hh; } @@ -1130,7 +1121,7 @@ namespace netgen double hshould = 1e10; for (int j = 0; j < 4; j++) { - double hi = hv (mtets[i-1].pnums[j]-1); + double hi = hv (mtets[ei].pnums[j]-IndexBASE()); if (hi < hshould) hshould = hi; } @@ -1145,13 +1136,12 @@ namespace netgen { if (h > hshould * hfac) { - mtets[i-1].marked = 1; + mtets[ei].marked = 1; marked = 1; } else - mtets[i-1].marked = 0; + mtets[ei].marked = 0; } - } for (int i = 1; i <= mprisms.Size(); i++) { @@ -1170,7 +1160,7 @@ namespace netgen double hshould = 1e10; for (int j = 0; j < 6; j++) { - double hi = hv (mprisms.Get(i).pnums[j]-1); + double hi = hv (mprisms.Get(i).pnums[j]-IndexBASE()); if (hi < hshould) hshould = hi; } @@ -1221,7 +1211,7 @@ namespace netgen - void BTBisectTet (const MarkedTet & oldtet, int newp, + void BTBisectTet (const MarkedTet & oldtet, PointIndex newp, MarkedTet & newtet1, MarkedTet & newtet2) { #ifdef DEBUG @@ -1267,6 +1257,8 @@ namespace netgen newtet1.marked = nm; newtet2.marked = nm; + newtet1.newest_vertex = oldtet.newest_vertex; + #ifdef DEBUG *testout << "newtet1,before = " << newtet1 << endl; *testout << "newtet2,before = " << newtet2 << endl; @@ -1276,6 +1268,7 @@ namespace netgen { if (i == oldtet.tetedge1) { + newtet2.newest_vertex = i; newtet2.pnums[i] = newp; newtet2.faceedges[i] = oldtet.faceedges[i]; // inherited face newtet2.faceedges[vis1] = i; // cut faces @@ -1359,7 +1352,7 @@ namespace netgen - void BTBisectPrism (const MarkedPrism & oldprism, int newp1, int newp2, + void BTBisectPrism (const MarkedPrism & oldprism, PointIndex newp1, PointIndex newp2, MarkedPrism & newprism1, MarkedPrism & newprism2) { for (int i = 0; i < 6; i++) @@ -1396,7 +1389,7 @@ namespace netgen void BTBisectIdentification (const MarkedIdentification & oldid, - NgArray & newp, + Array & newp, MarkedIdentification & newid1, MarkedIdentification & newid2) { @@ -1452,8 +1445,7 @@ namespace netgen } - - void BTBisectTri (const MarkedTri & oldtri, int newp, const PointGeomInfo & newpgi, + void BTBisectTri (const MarkedTri & oldtri, PointIndex newp, const PointGeomInfo & newpgi, MarkedTri & newtri1, MarkedTri & newtri2) { for (int i = 0; i < 3; i++) @@ -1472,11 +1464,12 @@ namespace netgen newtri1.pnums[pe2] = newp; newtri1.pgeominfo[pe2] = newpgi; newtri1.markededge = pe2; + newtri1.newest_vertex = oldtri.newest_vertex; newtri2.pnums[pe1] = newp; newtri2.pgeominfo[pe1] = newpgi; newtri2.markededge = pe1; - + newtri2.newest_vertex = pe1; newtri1.surfid = oldtri.surfid; newtri2.surfid = oldtri.surfid; @@ -1494,8 +1487,8 @@ namespace netgen void BTBisectQuad (const MarkedQuad & oldquad, - int newp1, const PointGeomInfo & npgi1, - int newp2, const PointGeomInfo & npgi2, + PointIndex newp1, const PointGeomInfo & npgi1, + PointIndex newp2, const PointGeomInfo & npgi2, MarkedQuad & newquad1, MarkedQuad & newquad2) { for (int i = 0; i < 4; i++) @@ -1588,9 +1581,9 @@ namespace netgen } - + template int MarkHangingIdentifications(T_MIDS & mids, - const INDEX_2_CLOSED_HASHTABLE & cutedges) + const HASHTABLE_CUTEDGES & cutedges) { int hanging = 0; for (int i = 1; i <= mids.Size(); i++) @@ -1604,10 +1597,10 @@ namespace netgen const int np = mids.Get(i).np; for(int j = 0; j < np; j++) { - INDEX_2 edge1(mids.Get(i).pnums[j], - mids.Get(i).pnums[(j+1) % np]); - INDEX_2 edge2(mids.Get(i).pnums[j+np], - mids.Get(i).pnums[((j+1) % np) + np]); + PointIndices<2> edge1(mids.Get(i).pnums[j], + mids.Get(i).pnums[(j+1) % np]); + PointIndices<2> edge2(mids.Get(i).pnums[j+np], + mids.Get(i).pnums[((j+1) % np) + np]); edge1.Sort(); edge2.Sort(); @@ -1683,8 +1676,9 @@ namespace netgen */ + template int MarkHangingTets (T_MTETS & mtets, - const INDEX_2_CLOSED_HASHTABLE & cutedges, + const HASHTABLE_CUTEDGES & cutedges, NgTaskManager tm) { static int timer = NgProfiler::CreateTimer ("MarkHangingTets"); @@ -1692,13 +1686,15 @@ namespace netgen int hanging = 0; // for (int i = 1; i <= mtets.Size(); i++) - ParallelForRange - (tm, mtets.Size(), [&] (size_t begin, size_t end) + ngcore::ParallelForRange + // (tm, mtets.Size(), [&] (size_t begin, size_t end) + (mtets.Range(), [&] (auto myrange) { bool my_hanging = false; - for (size_t i = begin; i < end; i++) + // for (size_t i = begin; i < end; i++) + for (auto ei : myrange) { - MarkedTet & teti = mtets[i]; + MarkedTet & teti = mtets[ei]; if (teti.marked) { @@ -1709,8 +1705,8 @@ namespace netgen for (int j = 0; j < 3; j++) for (int k = j+1; k < 4; k++) { - INDEX_2 edge(teti.pnums[j], - teti.pnums[k]); + PointIndices<2> edge(teti.pnums[j], + teti.pnums[k]); edge.Sort(); if (cutedges.Used (edge)) { @@ -1726,9 +1722,9 @@ namespace netgen } - + template int MarkHangingPrisms (T_MPRISMS & mprisms, - const INDEX_2_CLOSED_HASHTABLE & cutedges) + const HASHTABLE_CUTEDGES & cutedges) { int hanging = 0; for (int i = 1; i <= mprisms.Size(); i++) @@ -1742,10 +1738,10 @@ namespace netgen for (int j = 0; j < 2; j++) for (int k = j+1; k < 3; k++) { - INDEX_2 edge1(mprisms.Get(i).pnums[j], - mprisms.Get(i).pnums[k]); - INDEX_2 edge2(mprisms.Get(i).pnums[j+3], - mprisms.Get(i).pnums[k+3]); + PointIndices<2> edge1(mprisms.Get(i).pnums[j], + mprisms.Get(i).pnums[k]); + PointIndices<2> edge2(mprisms.Get(i).pnums[j+3], + mprisms.Get(i).pnums[k+3]); edge1.Sort(); edge2.Sort(); if (cutedges.Used (edge1) || @@ -1760,9 +1756,9 @@ namespace netgen } - + template bool MarkHangingTris (T_MTRIS & mtris, - const INDEX_2_CLOSED_HASHTABLE & cutedges, + const HASHTABLE_CUTEDGES & cutedges, NgTaskManager tm) { bool hanging = false; @@ -1783,10 +1779,13 @@ namespace netgen for (int j = 0; j < 2; j++) for (int k = j+1; k < 3; k++) { - INDEX_2 edge(tri.pnums[j], - tri.pnums[k]); + /* + PointIndices<2> edge(tri.pnums[j], + tri.pnums[k]); edge.Sort(); if (cutedges.Used (edge)) + */ + if (cutedges.Used( { tri.pnums[j], tri.pnums[k] } )) { tri.marked = 1; my_hanging = true; @@ -1799,9 +1798,9 @@ namespace netgen } - + template int MarkHangingQuads (T_MQUADS & mquads, - const INDEX_2_CLOSED_HASHTABLE & cutedges) + const HASHTABLE_CUTEDGES & cutedges) { int hanging = 0; for (int i = 1; i <= mquads.Size(); i++) @@ -1812,10 +1811,10 @@ namespace netgen continue; } - INDEX_2 edge1(mquads.Get(i).pnums[0], - mquads.Get(i).pnums[1]); - INDEX_2 edge2(mquads.Get(i).pnums[2], - mquads.Get(i).pnums[3]); + PointIndices<2> edge1(mquads.Get(i).pnums[0], + mquads.Get(i).pnums[1]); + PointIndices<2> edge2(mquads.Get(i).pnums[2], + mquads.Get(i).pnums[3]); edge1.Sort(); edge2.Sort(); if (cutedges.Used (edge1) || @@ -1828,10 +1827,10 @@ namespace netgen } // he/sz: second case: split horizontally - INDEX_2 edge3(mquads.Get(i).pnums[1], - mquads.Get(i).pnums[3]); - INDEX_2 edge4(mquads.Get(i).pnums[2], - mquads.Get(i).pnums[0]); + PointIndices<2> edge3(mquads.Get(i).pnums[1], + mquads.Get(i).pnums[3]); + PointIndices<2> edge4(mquads.Get(i).pnums[2], + mquads.Get(i).pnums[0]); edge3.Sort(); edge4.Sort(); @@ -1865,23 +1864,28 @@ namespace netgen } } + BisectionInfo::BisectionInfo() + { + mtets = make_unique(); + mprisms = make_unique(); + mids = make_unique(); + mtris = make_unique(); + mquads = make_unique(); + } + BisectionInfo::~BisectionInfo() {} - - T_MTETS mtets; - T_MPRISMS mprisms; - T_MIDS mids; - T_MTRIS mtris; - T_MQUADS mquads; - - - void WriteMarkedElements(ostream & ost) + void WriteMarkedElements(const Mesh& mesh, ostream & ost) { ost << "Marked Elements\n"; - + const auto& mtets = *mesh.bisectioninfo.mtets; + const auto& mprisms = *mesh.bisectioninfo.mprisms; + const auto& mids = *mesh.bisectioninfo.mids; + const auto& mtris = *mesh.bisectioninfo.mtris; + const auto& mquads = *mesh.bisectioninfo.mquads; ost << mtets.Size() << "\n"; - for(int i=0; i> auxstring; @@ -1920,13 +1930,15 @@ namespace netgen ist >> size; mtets.SetSize(size); - for(int i=0; i(); + // for(int i=0; i(size) ) { - ist >> mtets[i]; - if(mtets[i].pnums[0] > mesh.GetNV() || - mtets[i].pnums[1] > mesh.GetNV() || - mtets[i].pnums[2] > mesh.GetNV() || - mtets[i].pnums[3] > mesh.GetNV()) + ist >> mtets[ei]; + if(mtets[ei].pnums[0] >= PI0+mesh.GetNV() || + mtets[ei].pnums[1] >= PI0+mesh.GetNV() || + mtets[ei].pnums[2] >= PI0+mesh.GetNV() || + mtets[ei].pnums[3] >= PI0+mesh.GetNV()) return false; } @@ -1959,9 +1971,14 @@ namespace netgen void BisectTetsCopyMesh (Mesh & mesh, const NetgenGeometry *, BisectionOptions & opt, - const NgArray< NgArray* > & idmaps, + const NgArray & idmaps, const string & refinfofile) { + auto& mtets = *mesh.bisectioninfo.mtets; + auto& mprisms = *mesh.bisectioninfo.mprisms; + auto& mids = *mesh.bisectioninfo.mids; + auto& mtris = *mesh.bisectioninfo.mtris; + auto& mquads = *mesh.bisectioninfo.mquads; if (mesh.GetDimension() < 2) throw Exception ("Mesh bisection is available in 2D and 3D"); // mtets.SetName ("bisection, tets"); @@ -2002,15 +2019,16 @@ namespace netgen INDEX_2_HASHTABLE shortedges(100); - for (int i = 1; i <= ne; i++) + // for (int i = 1; i <= ne; i++) + for (auto ei : mesh.VolumeElements().Range()) { - const Element & el = mesh.VolumeElement(i); + const Element & el = mesh[ei]; if (el.GetType() == PRISM || el.GetType() == PRISM12) { for (int j = 1; j <= 3; j++) { - INDEX_2 se(el.PNum(j), el.PNum(j+3)); + PointIndices<2> se(el.PNum(j), el.PNum(j+3)); se.Sort(); shortedges.Set (se, 1); } @@ -2020,14 +2038,16 @@ namespace netgen // INDEX_2_HASHTABLE edgenumber(np); - INDEX_2_CLOSED_HASHTABLE edgenumber(9*ne+4*nse); - + // INDEX_2_CLOSED_HASHTABLE edgenumber(9*ne+4*nse); + // ClosedHashTable edgenumber(9*ne+4*nse); + ClosedHashTable, int> edgenumber(9*ne+4*nse); BTSortEdges (mesh, idmaps, edgenumber); - for (int i = 1; i <= ne; i++) + // for (int i = 1; i <= ne; i++) + for (auto ei : mesh.VolumeElements().Range()) { - const Element & el = mesh.VolumeElement(i); + const Element & el = mesh[ei]; switch (el.GetType()) { @@ -2040,7 +2060,7 @@ namespace netgen for (int j = 1; j <= 3; j++) for (int k = j+1; k <= 4; k++) { - INDEX_2 se(el.PNum(j), el.PNum(k)); + PointIndices<2> se(el.PNum(j), el.PNum(k)); se.Sort(); if (shortedges.Used (se)) { @@ -2095,7 +2115,7 @@ namespace netgen // eventually rotate MarkedPrism mp; - INDEX_2 se(el.PNum(1), el.PNum(2)); + PointIndices<2> se(el.PNum(1), el.PNum(2)); se.Sort(); if (shortedges.Used (se)) { @@ -2129,9 +2149,14 @@ namespace netgen } } - for (int i = 1; i <= nse; i++) + // for (int i = 1; i <= nse; i++) + /* + for (SurfaceElementIndex sei = 0; sei < nse; sei++) { - const Element2d & el = mesh.SurfaceElement(i); + const Element2d & el = mesh[sei]; + */ + for (const Element2d & el : mesh.SurfaceElements()) + { if (el.GetType() == TRIG || el.GetType() == TRIG6) { @@ -2156,12 +2181,16 @@ namespace netgen } if(mesh.GetDimension() == 2) { + /* for (SegmentIndex j=0; j 0 && seg[1] > 0 && (*map)[seg[0]] && (*map)[seg[1]]) + if (seg[0].IsValid() && seg[1].IsValid() && (*map)[seg[0]].IsValid() && (*map)[seg[1]].IsValid()) { MarkedIdentification mi; mi.np = 2; @@ -2187,11 +2216,14 @@ namespace netgen mesh.mlparentelement.SetSize(ne); - for (int i = 1; i <= ne; i++) - mesh.mlparentelement.Elem(i) = 0; + // for (int i = 1; i <= ne; i++) + // mesh.mlparentelement.Elem(i) = 0; + mesh.mlparentelement = ElementIndex::INVALID; + mesh.mlparentsurfaceelement.SetSize(nse); - for (int i = 1; i <= nse; i++) - mesh.mlparentsurfaceelement.Elem(i) = 0; + // for (int i = 1; i <= nse; i++) + // mesh.mlparentsurfaceelement.Elem(i) = 0; + mesh.mlparentsurfaceelement = SurfaceElementIndex::INVALID; if (printmessage_importance>0) { @@ -2460,7 +2492,7 @@ namespace netgen void UpdateEdgeMarks (Mesh & mesh, - const NgArray< NgArray* > & idmaps) + const NgArray< idmap_type* > & idmaps) //const NgArray < NgArray* > & elements_before, //const NgArray < NgArray* > & markedelts_num, // const NgArray < NgArray* > & surfelements_before, @@ -2473,6 +2505,13 @@ namespace netgen T_MTRIS mtris_old; mtris_old.Copy(mtris); T_MQUADS mquads_old; mquads_old.Copy(mquads); */ + + auto& mtets = *mesh.bisectioninfo.mtets; + auto& mprisms = *mesh.bisectioninfo.mprisms; + auto& mids = *mesh.bisectioninfo.mids; + auto& mtris = *mesh.bisectioninfo.mtris; + auto& mquads = *mesh.bisectioninfo.mquads; + T_MTETS mtets_old (mtets); T_MPRISMS mprisms_old (mprisms); T_MIDS mids_old (mids); @@ -2490,17 +2529,19 @@ namespace netgen //int nv = mesh.GetNV(); - INDEX_2_CLOSED_HASHTABLE edgenumber(9*mesh.GetNE()+4*mesh.GetNSE()); + // INDEX_2_CLOSED_HASHTABLE edgenumber(9*mesh.GetNE()+4*mesh.GetNSE()); + ClosedHashTable, int> edgenumber; int maxnum = BTSortEdges (mesh, idmaps, edgenumber); - for(int m = 0; m < mtets_old.Size(); m++) + // for(int m = 0; m < mtets_old.Size(); m++) + for (auto mi : mtets_old.Range()) { - MarkedTet & mt = mtets_old[m]; + MarkedTet & mt = mtets_old[mi]; //(*testout) << "old mt " << mt; - INDEX_2 edge (mt.pnums[mt.tetedge1],mt.pnums[mt.tetedge2]); + PointIndices<2> edge (mt.pnums[mt.tetedge1],mt.pnums[mt.tetedge2]); edge.Sort(); if(edgenumber.Used(edge)) { @@ -2543,11 +2584,14 @@ namespace netgen - - for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++) + /* + for (auto ei : mesh.VolumeElements().Range()) { const Element & el = mesh[ei]; - + */ + + for (const Element & el : mesh.VolumeElements()) + { //int pos = elements_before[el[0]]->Pos(el); //int elnum = (pos >= 0) ? (*markedelts_num[el[0]])[pos] : -1; @@ -2591,12 +2635,14 @@ namespace netgen } - - - for(SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) + /* + for(SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) { const Element2d & el = mesh[sei]; + */ + for (const Element2d & el : mesh.SurfaceElements()) + { /* for(int k=0; k<3; k++) auxind3[k] = el[k]; @@ -2698,6 +2744,12 @@ namespace netgen PrintMessage(1,"Mesh bisection"); PushStatus("Mesh bisection"); + auto& mtets = *mesh.bisectioninfo.mtets; + auto& mprisms = *mesh.bisectioninfo.mprisms; + auto& mids = *mesh.bisectioninfo.mids; + auto& mtris = *mesh.bisectioninfo.mtris; + auto& mquads = *mesh.bisectioninfo.mquads; + static int timer = NgProfiler::CreateTimer ("Bisect"); static int timer1 = NgProfiler::CreateTimer ("Bisect 1"); static int timer1a = NgProfiler::CreateTimer ("Bisect 1a"); @@ -2725,12 +2777,12 @@ namespace netgen LocalizeEdgePoints(mesh); delete loct; - NgArray< NgArray* > idmaps; + NgArray< idmap_type* > idmaps; for(int i=1; i<=mesh.GetIdentifications().GetMaxNr(); i++) { if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC) { - idmaps.Append(new NgArray); + idmaps.Append(new idmap_type); mesh.GetIdentifications().GetMap(i,*idmaps.Last(),true); } } @@ -2775,6 +2827,20 @@ namespace netgen int np = mesh.GetNV(); mesh.SetNP(np); + +#ifdef PARALLEL + if (mesh.GetCommunicator().Size() > 1) + { + mesh.GetParallelTopology().IdentifyVerticesAfterRefinement(); + mesh.GetCommunicator().Barrier(); + mesh.GetParallelTopology().EnumeratePointsGlobally(); + } +#endif + + + + + // int ne = mesh.GetNE(); // int nse = mesh.GetNSE(); // int i, j, l; @@ -2792,10 +2858,11 @@ namespace netgen if (opt.refine_p) { - int ne = mesh.GetNE(); + // int ne = mesh.GetNE(); int nse = mesh.GetNSE(); int ox,oy,oz; - for (ElementIndex ei = 0; ei < ne; ei++) + // for (ElementIndex ei = 0; ei < ne; ei++) + for (auto ei : mesh.VolumeElements().Range()) if (mesh[ei].TestRefinementFlag()) { mesh[ei].GetOrder(ox,oy,oz); @@ -2814,10 +2881,12 @@ namespace netgen #ifndef SABINE //Nachbarelemente mit ordx,ordy,ordz - NgArray v_order (mesh.GetNP()); + // NgArray v_order (mesh.GetNP()); + Array v_order (mesh.GetNP()); v_order = 0; - for (ElementIndex ei = 0; ei < ne; ei++) + // for (ElementIndex ei = 0; ei < ne; ei++) + for (auto ei : mesh.VolumeElements().Range()) for (int j = 0; j < mesh[ei].GetNP(); j++) if (mesh[ei].GetOrder() > v_order[mesh[ei][j]]) v_order[mesh[ei][j]] = mesh[ei].GetOrder(); @@ -2827,7 +2896,8 @@ namespace netgen if (mesh[sei].GetOrder() > v_order[mesh[sei][j]]) v_order[mesh[sei][j]] = mesh[sei].GetOrder(); - for (ElementIndex ei = 0; ei < ne; ei++) + // for (ElementIndex ei = 0; ei < ne; ei++) + for (auto ei : mesh.VolumeElements().Range()) for (int j = 0; j < mesh[ei].GetNP(); j++) if (mesh[ei].GetOrder() < v_order[mesh[ei][j]]-1) mesh[ei].SetOrder(v_order[mesh[ei][j]]-1); @@ -2846,7 +2916,9 @@ namespace netgen // INDEX_2_HASHTABLE cutedges(10 + 5 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size())); - INDEX_2_CLOSED_HASHTABLE cutedges(10 + 9 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size())); + // INDEX_2_CLOSED_HASHTABLE cutedges(10 + 9 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size())); + // ClosedHashTable cutedges(10 + 9 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size())); + ClosedHashTable, PointIndex> cutedges(10 + 9 * (mtets.Size()+mprisms.Size()+mtris.Size()+mquads.Size())); bool noprojection = false; NgProfiler::StopTimer (timer1a); @@ -2864,8 +2936,12 @@ namespace netgen if(st == "refinementinfo") // new version { + /* for(int i=1; i<=mtets.Size(); i++) mtets[i-1].marked = 0; + */ + for(auto ei : mtets.Range()) + mtets[ei].marked = 0; for(int i=1; i<=mprisms.Size(); i++) mprisms.Elem(i).marked = 0; for(int i=1; i<=mtris.Size(); i++) @@ -2906,7 +2982,8 @@ namespace netgen while(inf && isint) { - mtets[atoi(st.c_str())-1].marked = 3; + // mtets[atoi(st.c_str())-1].marked = 3; + mtets[IndexBASE()+(atoi(st.c_str())-1)].marked = 3; marked = 1; inf >> st; @@ -2923,7 +3000,8 @@ namespace netgen int cnt = 0; - for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++) + // for(ElementIndex ei = 0; ei < mesh.GetNE(); ei++) + for (auto ei : mesh.VolumeElements().Range()) { const Element & el = mesh[ei]; @@ -2993,12 +3071,13 @@ namespace netgen inf.open(opt.refinementfilename); char ch; - for (int i = 1; i <= mtets.Size(); i++) + // for (int i = 1; i <= mtets.Size(); i++) + for (auto ei : mtets.Range()) { inf >> ch; if(!inf) throw NgException("something wrong with refinementinfo file (old format)"); - mtets[i-1].marked = (ch == '1'); + mtets[ei].marked = (ch == '1'); } marked = 1; } @@ -3012,24 +3091,25 @@ namespace netgen // all in one ! if (mprisms.Size()) { - int cnttet = 0; + ElementIndex cnttet = IndexBASE(); int cntprism = 0; - for (int i = 1; i <= mesh.GetNE(); i++) + // for (int i = 1; i <= mesh.GetNE(); i++) + for (auto ei : mesh.VolumeElements().Range()) { - if (mesh.VolumeElement(i).GetType() == TET || - mesh.VolumeElement(i).GetType() == TET10) + if (mesh.VolumeElement(ei).GetType() == TET || + mesh.VolumeElement(ei).GetType() == TET10) { - cnttet++; - mtets[cnttet-1].marked = - (opt.onlyonce ? 3 : 1) * mesh.VolumeElement(i).TestRefinementFlag(); - if (mtets[cnttet-1].marked) + mtets[cnttet].marked = + (opt.onlyonce ? 3 : 1) * mesh.VolumeElement(ei).TestRefinementFlag(); + if (mtets[cnttet].marked) cntm++; + cnttet++; } else { cntprism++; mprisms.Elem(cntprism).marked = - 2 * mesh.VolumeElement(i).TestRefinementFlag(); + 2 * mesh.VolumeElement(ei).TestRefinementFlag(); if (mprisms.Elem(cntprism).marked) cntm++; } @@ -3037,11 +3117,12 @@ namespace netgen } } else - for (int i = 1; i <= mtets.Size(); i++) + // for (int i = 1; i <= mtets.Size(); i++) + for (auto ei : mtets.Range()) { - mtets[i-1].marked = - (opt.onlyonce ? 1 : 3) * mesh.VolumeElement(i).TestRefinementFlag(); - if (mtets[i-1].marked) + mtets[ei].marked = + (opt.onlyonce ? 1 : 3) * mesh.VolumeElement(ei).TestRefinementFlag(); + if (mtets[ei].marked) cntm++; } @@ -3063,14 +3144,15 @@ namespace netgen int cnttrig = 0; int cntquad = 0; - for (int i = 1; i <= mesh.GetNSE(); i++) + // for (int i = 1; i <= mesh.GetNSE(); i++) + for (SurfaceElementIndex sei = 0; sei < mesh.GetNSE(); sei++) { - if (mesh.SurfaceElement(i).GetType() == TRIG || - mesh.SurfaceElement(i).GetType() == TRIG6) + if (mesh[sei].GetType() == TRIG || + mesh[sei].GetType() == TRIG6) { cnttrig++; mtris.Elem(cnttrig).marked = - mesh.SurfaceElement(i).TestRefinementFlag() ? (opt.onlyonce ? 1 : 2) : 0; + mesh[sei].TestRefinementFlag() ? (opt.onlyonce ? 1 : 2) : 0; // mtris.Elem(cnttrig).marked = 0; if (mtris.Elem(cnttrig).marked) cntm++; @@ -3080,7 +3162,7 @@ namespace netgen cntquad++; // 2d: marked=2, 3d prisms: marked=1 mquads.Elem(cntquad).marked = - mesh.SurfaceElement(i).TestRefinementFlag() ? 4-mesh.GetDimension() : 0 ; + mesh[sei].TestRefinementFlag() ? 4-mesh.GetDimension() : 0 ; // mquads.Elem(cntquad).marked = 0; if (mquads.Elem(cntquad).marked) cntm++; @@ -3138,12 +3220,12 @@ namespace netgen { PrintMessage(3,"refine p"); - for (int i = 1; i <= mtets.Size(); i++) - mtets[i-1].incorder = mtets[i-1].marked ? 1 : 0; + for (auto ei : mtets.Range()) + mtets[ei].incorder = mtets[ei].marked ? 1 : 0; - for (int i = 1; i <= mtets.Size(); i++) - if (mtets[i-1].incorder) - mtets[i-1].marked = 0; + for (auto ei : mtets.Range()) + if (mtets[ei].incorder) + mtets[ei].marked = 0; for (int i = 1; i <= mprisms.Size(); i++) @@ -3167,7 +3249,7 @@ namespace netgen if (opt.refine_hp) { PrintMessage(3,"refine hp"); - NgBitArray singv(np); + TBitArray singv(np); singv.Clear(); if (mesh.GetDimension() == 3) @@ -3175,8 +3257,8 @@ namespace netgen for (int i = 1; i <= mesh.GetNSeg(); i++) { const Segment & seg = mesh.LineSegment(i); - singv.Set (seg[0]); - singv.Set (seg[1]); + singv.SetBit (seg[0]); + singv.SetBit (seg[1]); } /* for ( i=1; i<= mesh.GetNSE(); i++) @@ -3190,37 +3272,40 @@ namespace netgen else { // vertices with 2 different bnds - NgArray bndind(np); + Array bndind(np); bndind = 0; for (int i = 1; i <= mesh.GetNSeg(); i++) { const Segment & seg = mesh.LineSegment(i); for (int j = 0; j < 2; j++) { - int pi = (j == 0) ? seg[0] : seg[1]; - if (bndind.Elem(pi) == 0) - bndind.Elem(pi) = seg.edgenr; - else if (bndind.Elem(pi) != seg.edgenr) - singv.Set (pi); + PointIndex pi = (j == 0) ? seg[0] : seg[1]; + if (bndind[pi] == 0) + bndind[pi] = seg.edgenr; + else if (bndind[pi] != seg.edgenr) + singv.SetBit (pi); } } } - for (int i = 1; i <= mtets.Size(); i++) - mtets[i-1].incorder = 1; - for (int i = 1; i <= mtets.Size(); i++) + // for (int i = 1; i <= mtets.Size(); i++) + for (auto ei : mtets.Range()) + mtets[ei].incorder = 1; + // for (int i = 1; i <= mtets.Size(); i++) + for (auto ei : mtets.Range()) { - if (!mtets[i-1].marked) - mtets[i-1].incorder = 0; + if (!mtets[ei].marked) + mtets[ei].incorder = 0; for (int j = 0; j < 4; j++) - if (singv.Test (mtets[i-1].pnums[j])) - mtets[i-1].incorder = 0; + if (singv.Test (mtets[ei].pnums[j])) + mtets[ei].incorder = 0; } - for (int i = 1; i <= mtets.Size(); i++) - if (mtets[i-1].incorder) - mtets[i-1].marked = 0; + // for (int i = 1; i <= mtets.Size(); i++) + for (auto ei : mtets.Range()) + if (mtets[ei].incorder) + mtets[ei].marked = 0; for (int i = 1; i <= mprisms.Size(); i++) @@ -3271,14 +3356,14 @@ namespace netgen NgProfiler::StartTimer (timer_bisecttet); (*opt.tracer)("bisecttet", false); size_t nel = mtets.Size(); - for (size_t i = 0; i < nel; i++) - if (mtets[i].marked) + // for (size_t i = 0; i < nel; i++) + for (auto ei : ngcore::T_Range(nel)) + if (mtets[ei].marked) { - MarkedTet oldtet = mtets[i]; + MarkedTet oldtet = mtets[ei]; - INDEX_2 edge(oldtet.pnums[oldtet.tetedge1], - oldtet.pnums[oldtet.tetedge2]); - edge.Sort(); + SortedPointIndices<2> edge(oldtet.pnums[oldtet.tetedge1], + oldtet.pnums[oldtet.tetedge2]); PointIndex newp; if (auto optnewp = cutedges.GetIfUsed(edge)) @@ -3287,8 +3372,7 @@ namespace netgen } else { - Point<3> npt = Center (mesh.Point (edge.I1()), - mesh.Point (edge.I2())); + Point<3> npt = Center (mesh[edge[0]], mesh[edge[1]]); newp = mesh.AddPoint (npt); cutedges.Set (edge, newp); } @@ -3296,9 +3380,9 @@ namespace netgen MarkedTet newtet1, newtet2; BTBisectTet (oldtet, newp, newtet1, newtet2); - mtets[i] = newtet1; + mtets[ei] = newtet1; mtets.Append (newtet2); - mesh.mlparentelement.Append (i+1); + mesh.mlparentelement.Append (ei); } NgProfiler::StopTimer (timer_bisecttet); (*opt.tracer)("bisecttet", true); @@ -3315,20 +3399,17 @@ namespace netgen if (pi1 == oldprism.markededge) pi1++; int pi2 = 3-pi1-oldprism.markededge; - - INDEX_2 edge1(oldprism.pnums[pi1], - oldprism.pnums[pi2]); - INDEX_2 edge2(oldprism.pnums[pi1+3], - oldprism.pnums[pi2+3]); - edge1.Sort(); - edge2.Sort(); + + SortedPointIndices<2> edge1(oldprism.pnums[pi1], + oldprism.pnums[pi2]); + SortedPointIndices<2> edge2(oldprism.pnums[pi1+3], + oldprism.pnums[pi2+3]); if (cutedges.Used (edge1)) newp1 = cutedges.Get(edge1); else { - Point<3> npt = Center (mesh.Point (edge1.I1()), - mesh.Point (edge1.I2())); + Point<3> npt = Center (mesh[edge1[0]], mesh[edge1[1]]); newp1 = mesh.AddPoint (npt); cutedges.Set (edge1, newp1); } @@ -3336,8 +3417,7 @@ namespace netgen newp2 = cutedges.Get(edge2); else { - Point<3> npt = Center (mesh.Point (edge2.I1()), - mesh.Point (edge2.I2())); + Point<3> npt = Center (mesh[edge2[0]], mesh[edge2[1]]); newp2 = mesh.AddPoint (npt); cutedges.Set (edge2, newp2); } @@ -3355,22 +3435,26 @@ namespace netgen if (mids.Elem(i).marked) { MarkedIdentification oldid,newid1,newid2; - NgArray newp; + Array newp; oldid = mids.Get(i); - NgArray edges; - edges.Append(INDEX_2(oldid.pnums[oldid.markededge], - oldid.pnums[(oldid.markededge+1)%oldid.np])); - edges.Append(INDEX_2(oldid.pnums[oldid.markededge + oldid.np], - oldid.pnums[(oldid.markededge+1)%oldid.np + oldid.np])); - + NgArray> edges; + edges.Append( { + oldid.pnums[oldid.markededge], + oldid.pnums[(oldid.markededge+1)%oldid.np] } ); + edges.Append( { + oldid.pnums[oldid.markededge + oldid.np], + oldid.pnums[(oldid.markededge+1)%oldid.np + oldid.np] } ); + if(oldid.np == 4) { - edges.Append(INDEX_2(oldid.pnums[(oldid.markededge+2)%oldid.np], - oldid.pnums[(oldid.markededge+3)%oldid.np])); - edges.Append(INDEX_2(oldid.pnums[(oldid.markededge+2)%oldid.np + oldid.np], - oldid.pnums[(oldid.markededge+3)%oldid.np + oldid.np])); + edges.Append( { + oldid.pnums[(oldid.markededge+2)%oldid.np], + oldid.pnums[(oldid.markededge+3)%oldid.np]} ); + edges.Append( { + oldid.pnums[(oldid.markededge+2)%oldid.np + oldid.np], + oldid.pnums[(oldid.markededge+3)%oldid.np + oldid.np] } ); } for (int j = 0; j < edges.Size(); j++) { @@ -3416,7 +3500,7 @@ namespace netgen MarkedTri oldtri = mtris[i]; PointIndex oldpi1 = oldtri.pnums[(oldtri.markededge+1)%3]; PointIndex oldpi2 = oldtri.pnums[(oldtri.markededge+2)%3]; - INDEX_2 edge(oldpi1, oldpi2); + PointIndices<2> edge(oldpi1, oldpi2); edge.Sort(); int si = mesh.GetFaceDescriptor (oldtri.surfid).SurfNr(); @@ -3433,8 +3517,8 @@ namespace netgen } else { - Point<3> npt = Center (mesh.Point (edge.I1()), - mesh.Point (edge.I2())); + Point<3> npt = Center (mesh.Point (edge[0]), + mesh.Point (edge[1])); newp = mesh.AddPoint (npt); cutedges.Set (edge, newp); geo.PointBetween (mesh.Point (oldpi1), mesh.Point (oldpi2), @@ -3445,7 +3529,7 @@ namespace netgen mtris[i] = newtri1; mtris.Append (newtri2); - mesh.mlparentsurfaceelement.Append (i+1); + mesh.mlparentsurfaceelement.Append (i); } NgProfiler::StopTimer (timer_bisecttrig); @@ -3466,21 +3550,21 @@ namespace netgen INDEX_2 edge2(oldquad.pnums[2], oldquad.pnums[3]); */ - INDEX_2 edge1, edge2; + PointIndices<2> edge1, edge2; PointGeomInfo pgi11, pgi12, pgi21, pgi22; if (oldquad.markededge==0 || oldquad.markededge==2) { - edge1.I1()=oldquad.pnums[0]; pgi11=oldquad.pgeominfo[0]; - edge1.I2()=oldquad.pnums[1]; pgi12=oldquad.pgeominfo[1]; - edge2.I1()=oldquad.pnums[2]; pgi21=oldquad.pgeominfo[2]; - edge2.I2()=oldquad.pnums[3]; pgi22=oldquad.pgeominfo[3]; + edge1[0] = oldquad.pnums[0]; pgi11=oldquad.pgeominfo[0]; + edge1[1] = oldquad.pnums[1]; pgi12=oldquad.pgeominfo[1]; + edge2[0] = oldquad.pnums[2]; pgi21=oldquad.pgeominfo[2]; + edge2[1] = oldquad.pnums[3]; pgi22=oldquad.pgeominfo[3]; } else // 3 || 1 { - edge1.I1()=oldquad.pnums[0]; pgi11=oldquad.pgeominfo[0]; - edge1.I2()=oldquad.pnums[2]; pgi12=oldquad.pgeominfo[2]; - edge2.I1()=oldquad.pnums[1]; pgi21=oldquad.pgeominfo[1]; - edge2.I2()=oldquad.pnums[3]; pgi22=oldquad.pgeominfo[3]; + edge1[0] = oldquad.pnums[0]; pgi11=oldquad.pgeominfo[0]; + edge1[1] = oldquad.pnums[2]; pgi12=oldquad.pgeominfo[2]; + edge2[0] = oldquad.pnums[1]; pgi21=oldquad.pgeominfo[1]; + edge2[1] = oldquad.pnums[3]; pgi22=oldquad.pgeominfo[3]; } edge1.Sort(); @@ -3492,8 +3576,8 @@ namespace netgen } else { - Point<3> np1 = Center (mesh.Point (edge1.I1()), - mesh.Point (edge1.I2())); + Point<3> np1 = Center (mesh.Point (edge1[0]), + mesh.Point (edge1[1])); newp1 = mesh.AddPoint (np1); cutedges.Set (edge1, newp1); } @@ -3504,8 +3588,8 @@ namespace netgen } else { - Point<3> np2 = Center (mesh.Point (edge2.I1()), - mesh.Point (edge2.I2())); + Point<3> np2 = Center (mesh.Point (edge2[0]), + mesh.Point (edge2[1])); newp2 = mesh.AddPoint (np2); cutedges.Set (edge2, newp2); } @@ -3543,7 +3627,7 @@ namespace netgen for (int i = 1; i <= nseg; i++) { Segment & seg = mesh.LineSegment (i); - INDEX_2 edge(seg[0], seg[1]); + PointIndices<2> edge(seg[0], seg[1]); edge.Sort(); if (cutedges.Used (edge)) { @@ -3551,7 +3635,7 @@ namespace netgen Segment nseg1 = seg; Segment nseg2 = seg; - int newpi = cutedges.Get(edge); + PointIndex newpi = cutedges.Get(edge); nseg1[1] = newpi; nseg2[0] = newpi; @@ -3607,22 +3691,25 @@ namespace netgen if (opt.refine_hp) { // - NgArray v_order (mesh.GetNP()); + Array v_order (mesh.GetNP()); v_order = 0; if (mesh.GetDimension() == 3) { - for (int i = 1; i <= mtets.Size(); i++) - if (mtets[i-1].incorder) - mtets[i-1].order++; + // for (int i = 1; i <= mtets.Size(); i++) + for (auto ei : mtets.Range()) + if (mtets[ei].incorder) + mtets[ei].order++; - for (int i = 0; i < mtets.Size(); i++) + // for (int i = 0; i < mtets.Size(); i++) + for (auto ei : mtets.Range()) for (int j = 0; j < 4; j++) - if (int(mtets[i].order) > v_order.Elem(mtets[i].pnums[j])) - v_order.Elem(mtets[i].pnums[j]) = mtets[i].order; - for (int i = 0; i < mtets.Size(); i++) + if (int(mtets[ei].order) > v_order[mtets[ei].pnums[j]]) + v_order[mtets[ei].pnums[j]] = mtets[ei].order; + // for (int i = 0; i < mtets.Size(); i++) + for (auto ei : mtets.Range()) for (int j = 0; j < 4; j++) - if (int(mtets[i].order) < v_order.Elem(mtets[i].pnums[j])-1) - mtets[i].order = v_order.Elem(mtets[i].pnums[j])-1; + if (int(mtets[ei].order) < v_order[mtets[ei].pnums[j]]-1) + mtets[ei].order = v_order[mtets[ei].pnums[j]]-1; } else { @@ -3634,13 +3721,13 @@ namespace netgen for (int i = 0; i < mtris.Size(); i++) for (int j = 0; j < 3; j++) - if (int(mtris[i].order) > v_order.Elem(mtris[i].pnums[j])) - v_order.Elem(mtris[i].pnums[j]) = mtris[i].order; + if (int(mtris[i].order) > v_order[mtris[i].pnums[j]]) + v_order[mtris[i].pnums[j]] = mtris[i].order; for (int i = 0; i < mtris.Size(); i++) { for (int j = 0; j < 3; j++) - if (int(mtris[i].order) < v_order.Elem(mtris[i].pnums[j])-1) - mtris[i].order = v_order.Elem(mtris[i].pnums[j])-1; + if (int(mtris[i].order) < v_order[mtris[i].pnums[j]]-1) + mtris[i].order = v_order[mtris[i].pnums[j]]-1; } } } @@ -3670,18 +3757,19 @@ namespace netgen mesh.AddVolumeElement (el); } */ - ParallelForRange - (opt.task_manager, mtets.Size(), [&] (size_t begin, size_t end) + ngcore::ParallelForRange + (mtets.Range(), [&] (auto myrange) { - for (size_t i = begin; i < end; i++) + for (auto ei : myrange) { Element el(TET); - auto & tet = mtets[i]; + auto & tet = mtets[ei]; el.SetIndex (tet.matindex); el.SetOrder (tet.order); for (int j = 0; j < 4; j++) el[j] = tet.pnums[j]; - mesh.SetVolumeElement (ElementIndex(i), el); + el.NewestVertex() = tet.newest_vertex; + mesh.SetVolumeElement (ei, el); } }); @@ -3777,6 +3865,7 @@ namespace netgen el[j] = trig.pnums[j]; el.GeomInfoPi(j+1) = trig.pgeominfo[j]; } + el.NewestVertex() = trig.newest_vertex; mesh.SetSurfaceElement (SurfaceElementIndex(i), el); } }); @@ -3801,11 +3890,15 @@ namespace netgen if (mesh.level_nv.Size() <= 1) { PrintMessage(4,"RESETTING mlbetweennodes"); + /* for (int i = 1; i <= np; i++) { mesh.mlbetweennodes.Elem(i).I1() = 0; mesh.mlbetweennodes.Elem(i).I2() = 0; } + */ + for (auto i : mesh.mlbetweennodes.Range()) + mesh.mlbetweennodes[i] = { PointIndex::INVALID, PointIndex::INVALID }; } mesh.level_nv.Append (np); @@ -3823,21 +3916,30 @@ namespace netgen */ - NgBitArray isnewpoint(np); + TBitArray isnewpoint(np); isnewpoint.Clear(); { static Timer t("update mlbetween"); RegionTimer reg(t); + /* for (int i = 0; i < cutedges.Size(); i++) if (cutedges.UsedPos0(i)) { INDEX_2 edge; PointIndex newpi; cutedges.GetData0 (i, edge, newpi); - isnewpoint.Set(newpi); - mesh.mlbetweennodes.Elem(newpi) = edge; + isnewpoint.SetBit(newpi); + mesh.mlbetweennodes[newpi] = edge; } + */ + for (auto [edge,newpi] : cutedges) + { + isnewpoint.SetBit(newpi); + mesh.mlbetweennodes[newpi] = edge; + } } + + /* mesh.PrintMemInfo (cout); cout << "tets "; @@ -3914,7 +4016,7 @@ namespace netgen // update identification tables for (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++) { - NgArray identmap; + idmap_type identmap; mesh.GetIdentifications().GetMap (i, identmap); @@ -3937,14 +4039,16 @@ namespace netgen } */ + + /* for (int j = 0; j < cutedges.Size(); j++) if (cutedges.UsedPos0(j)) { - INDEX_2 i2; + PointIndices<2> i2; PointIndex newpi; cutedges.GetData0 (j, i2, newpi); - INDEX_2 oi2(identmap.Get(i2.I1()), - identmap.Get(i2.I2())); + PointIndices<2> oi2(identmap[i2[0]], + identmap[i2[1]]); oi2.Sort(); if (cutedges.Used (oi2)) { @@ -3952,6 +4056,20 @@ namespace netgen mesh.GetIdentifications().Add (newpi, onewpi, i); } } + */ + for (auto [i2, newpi] : cutedges) + { + PointIndices<2> oi2(identmap[i2[0]], + identmap[i2[1]]); + if((!oi2[0].IsValid()) || (!oi2[1].IsValid())) + continue; + oi2.Sort(); + if (cutedges.Used (oi2)) + { + PointIndex onewpi = cutedges.Get(oi2); + mesh.GetIdentifications().Add (newpi, onewpi, i); + } + } } (*opt.tracer)("Bisect", true); @@ -3969,9 +4087,10 @@ namespace netgen if(noprojection) { do_repair = false; - for(int ii=1; ii<=mesh.GetNP(); ii++) + // for(int ii=1; ii<=mesh.GetNP(); ii++) + for (auto ii : mesh.Points().Range()) { - if(isnewpoint.Test(ii) && mesh.mlbetweennodes[ii][0] > 0) + if(isnewpoint.Test(ii) && mesh.mlbetweennodes[ii][0].IsValid()) { mesh.Point(ii) = Center(mesh.Point(mesh.mlbetweennodes[ii][0]), mesh.Point(mesh.mlbetweennodes[ii][1])); @@ -4102,7 +4221,7 @@ namespace netgen PrintMessage(3,"writing marked-elements information to \"",refelementinfofilewrite,"\""); ofstream ofst(refelementinfofilewrite.c_str()); - WriteMarkedElements(ofst); + WriteMarkedElements(mesh, ofst); ofst.close(); } @@ -4117,8 +4236,7 @@ namespace netgen NgProfiler::StopTimer (timer3); } - - + BisectionOptions :: BisectionOptions () { diff --git a/libsrc/meshing/bisect.hpp b/libsrc/meshing/bisect.hpp index eef60d73..2e10a87b 100644 --- a/libsrc/meshing/bisect.hpp +++ b/libsrc/meshing/bisect.hpp @@ -1,5 +1,13 @@ -#ifndef BISECT -#define BISECT +#ifndef NETGEN_BISECT_HPP +#define NETGEN_BISECT_HPP + +#include +#include +#include "basegeom.hpp" +#include "meshclass.hpp" + +namespace netgen +{ class BisectionOptions { @@ -59,4 +67,6 @@ public: virtual void LocalizeEdgePoints(Mesh & /* mesh */) const {;} }; -#endif +} // namespace netgen + +#endif // NETGEN_BISECT_HPP diff --git a/libsrc/meshing/boundarylayer.cpp b/libsrc/meshing/boundarylayer.cpp index 72924f25..b5c56929 100644 --- a/libsrc/meshing/boundarylayer.cpp +++ b/libsrc/meshing/boundarylayer.cpp @@ -1,1415 +1,1471 @@ -#include -#include "meshing.hpp" +#include "boundarylayer.hpp" +#include "boundarylayer_limiter.hpp" + +#include +#include +#include + #include "debugging.hpp" #include "global.hpp" - -#include -#include +#include "meshfunc.hpp" namespace netgen { - // checks if a segment is intersecting a plane, spanned by three points, lam will be set s.t. p_intersect = seg[0] + lam * (seg[1]-seg[0]) - bool isIntersectingPlane ( const array, 2> & seg, const array, 3> & trig, double & lam) - { - auto n = Cross(trig[1]-trig[0], trig[2]-trig[0]); - auto v0n = (seg[0]-trig[0])*n; - auto v1n = (seg[1]-trig[0])*n; - if(v0n * v1n >= 0) - return false; - lam = -v0n/(v1n-v0n); - lam *= 0.9; - if(lam < -1e-8 || lam>1+1e-8) - return false; - return true; - } +struct SpecialPointException : public Exception +{ + SpecialPointException () + : Exception("") {} +}; - bool isIntersectingPlane ( const array, 2> & seg, const ArrayMem, 4> & face, double & lam) - { - lam = 1.0; - bool intersect0 = isIntersectingPlane( seg, array, 3>{face[0], face[1], face[2]}, lam ); - if(face.Size()==3) - return intersect0; +std::tuple FindCloseVectors (FlatArray> ns, + bool find_max = true) +{ + int maxpos1 = 0; + int maxpos2 = 0; - double lam1 = 1.0; - bool intersect1 = isIntersectingPlane( seg, array, 3>{face[2], face[3], face[0]}, lam1 ); - lam = min(lam, lam1); - return intersect0 || intersect1; - } - - bool isIntersectingTrig ( const array, 2> & seg, const array, 3> & trig, double & lam) - { - if(!isIntersectingPlane(seg, trig, lam)) - return false; - - auto p = seg[0] + lam/0.9*(seg[1]-seg[0]); - - auto n_trig = Cross(trig[1]-trig[0], trig[2]-trig[0]).Normalize(); - for(auto i : Range(3)) + double val = find_max ? -1e99 : 1e99; + for (auto i : Range(ns)) + for (auto j : Range(i + 1, ns.Size())) { - // check if p0 and p are on same side of segment p1-p2 - auto p0 = trig[i]; - auto p1 = trig[(i+1)%3]; - auto p2 = trig[(i+2)%3]; - auto n = Cross(p2-p1, n_trig); - - auto v0 = (p2-p1).Normalize(); - auto v1 = (p0-p1).Normalize(); - auto inside_dir = (v1 - (v1*v0) * v0).Normalize(); - auto v2 = (p-p1).Normalize(); - if(inside_dir * v1 < 0) - inside_dir = -inside_dir; - - if( (inside_dir*v2) < 0 ) - return false; - } - return true; - }; - - bool isIntersectingFace( const array, 2> & seg, const ArrayMem, 4> & face, double & lam ) - { - lam = 1.0; - double lam0 = 1.0; - bool intersect0 = isIntersectingTrig( seg, {face[0], face[1], face[2]}, lam0 ); - if(intersect0) - lam = min(lam, lam0); - if(face.Size()==3) - return intersect0; - - double lam1 = 1.0; - bool intersect1 = isIntersectingTrig( seg, {face[2], face[3], face[0]}, lam1 ); - if(intersect1) - lam = min(lam, lam1); - return intersect0 || intersect1; - } - - array, 2> BoundaryLayerTool :: GetMappedSeg( PointIndex pi ) - { - return { mesh[pi], mesh[pi] + height*limits[pi]*growthvectors[pi] }; - } - - ArrayMem, 4> BoundaryLayerTool :: GetFace( SurfaceElementIndex sei ) - { - const auto & sel = mesh[sei]; - ArrayMem, 4> points(sel.GetNP()); - for(auto i : Range(sel.GetNP())) - points[i] = mesh[sel[i]]; - return points; - } - - ArrayMem, 4> BoundaryLayerTool :: GetMappedFace( SurfaceElementIndex sei ) - { - const auto & sel = mesh[sei]; - ArrayMem, 4> points(sel.GetNP()); - for(auto i : Range(sel.GetNP())) - points[i] = mesh[sel[i]] + height * limits[sel[i]]*growthvectors[sel[i]]; - return points; - } - - ArrayMem, 4> BoundaryLayerTool :: GetMappedFace( SurfaceElementIndex sei, int face ) - { - if(face == -1) return GetFace(sei); - if(face == -2) return GetMappedFace(sei); - const auto & sel = mesh[sei]; - auto np = sel.GetNP(); - auto pi0 = sel[face % np]; - auto pi1 = sel[(face+1) % np]; - ArrayMem, 4> points(4); - points[0] = points[3] = mesh[pi0]; - points[1] = points[2] = mesh[pi1]; - points[3] += height * limits[pi0]*growthvectors[pi0]; - points[2] += height * limits[pi1]*growthvectors[pi1]; - return points; - } - - Vec<3> BoundaryLayerTool :: getEdgeTangent(PointIndex pi, int edgenr) - { - Vec<3> tangent = 0.0; - ArrayMem pts; - for(auto segi : topo.GetVertexSegments(pi)) - { - auto & seg = mesh[segi]; - if(seg.edgenr != edgenr+1) - continue; - PointIndex other = seg[0]+seg[1]-pi; - if(!pts.Contains(other)) - pts.Append(other); - } - if(pts.Size() != 2) - throw Exception("Something went wrong in getEdgeTangent!"); - tangent = mesh[pts[1]] - mesh[pts[0]]; - return tangent.Normalize(); - } - - void BoundaryLayerTool :: LimitGrowthVectorLengths() - { - static Timer tall("BoundaryLayerTool::LimitGrowthVectorLengths"); RegionTimer rtall(tall); - - limits.SetSize(np); - limits = 1.0; - - auto smooth = [&] (size_t nsteps) { - for(auto i : Range(nsteps)) - for(const auto & sel : mesh.SurfaceElements()) - { - double min_limit = 999; - for(auto pi : sel.PNums()) - min_limit = min(min_limit, limits[pi]); - for(auto pi : sel.PNums()) - limits[pi] = min(limits[pi], 1.4*min_limit); - } - }; - - // check for self-intersection within new elements (prisms/hexes) - auto self_intersection = [&] () { - for(SurfaceElementIndex sei : mesh.SurfaceElements().Range()) + double ip = ns[i] * ns[j]; + if ((find_max && (ip > val)) || (!find_max && (ip < val))) { - auto facei = mesh[sei].GetIndex(); - if(facei < nfd_old && !params.surfid.Contains(facei)) - continue; - - auto sel = mesh[sei]; - auto np = sel.GetNP(); - // check if a new edge intesects the plane of any opposing face - double lam; - for(auto i : Range(np)) - for(auto fi : Range(np-2)) - if(isIntersectingPlane(GetMappedSeg(sel[i]), GetMappedFace(sei, i+fi+1), lam)) - if(lam < 1.0) - limits[sel[i]] *= lam; + val = ip; + maxpos1 = i; + maxpos2 = j; } - }; + } + return {maxpos1, maxpos2}; +} - // first step: intersect with other surface elements that are boundary of domain the layer is grown into - // second (and subsequent) steps: intersect with other boundary layers, allow restriction by 20% in each step - auto changed_domains = domains; - if(!params.outside) - changed_domains.Invert(); - - bool limit_reached = true; - double lam_lower_limit = 1.0; - int step = 0; - while(limit_reached || step<2) +Vec<3> CalcGrowthVector (FlatArray> ns) +{ + if (ns.Size() == 0) + return {0, 0, 0}; + if (ns.Size() == 1) + return ns[0]; + if (ns.Size() == 2) { - if(step>0) - lam_lower_limit *= 0.8; - limit_reached = false; - - // build search tree with all surface elements (bounding box of a surface element also covers the generated boundary layer) - Box<3> bbox(Box<3>::EMPTY_BOX); - for(auto pi : mesh.Points().Range()) - { - bbox.Add(mesh[pi]); - bbox.Add(mesh[pi]+limits[pi]*height*growthvectors[pi]); - } - BoxTree<3> tree(bbox); - - for(auto sei : mesh.SurfaceElements().Range()) - { - const auto & sel = mesh[sei]; - Box<3> box(Box<3>::EMPTY_BOX); - const auto& fd = mesh.GetFaceDescriptor(sel.GetIndex()); - if(!changed_domains.Test(fd.DomainIn()) && - !changed_domains.Test(fd.DomainOut())) - continue; - for(auto pi : sel.PNums()) - box.Add(mesh[pi]); - // also add moved points to bounding box - if(params.surfid.Contains(sel.GetIndex())) - for(auto pi : sel.PNums()) - box.Add(mesh[pi]+limits[pi]*height*growthvectors[pi]); - tree.Insert(box, sei); - } - - for(auto pi : mesh.Points().Range()) - { - if(mesh[pi].Type() == INNERPOINT) - continue; - if(growthvectors[pi].Length2() == 0.0) - continue; - Box<3> box(Box<3>::EMPTY_BOX); - auto seg = GetMappedSeg(pi); - box.Add(seg[0]); - box.Add(seg[1]); - double lam = 1.0; - tree.GetFirstIntersecting(box.PMin(), box.PMax(), [&](SurfaceElementIndex sei) - { - const auto & sel = mesh[sei]; - if(sel.PNums().Contains(pi)) - return false; - auto face = GetMappedFace(sei, -2); - double lam_ = 999; - bool is_bl_sel = params.surfid.Contains(sel.GetIndex()); - - if(step==0) - { - if(isIntersectingFace(seg, face, lam_)) - { - if(is_bl_sel) // allow only half the distance if the opposing surface element has a boundary layer too - lam_ *= 0.5; - lam = min(lam, lam_); - } - } - // if the opposing surface element has a boundary layer, we need to additionally intersect with the new faces - if(step>0 && is_bl_sel) - { - for(auto facei : Range(-1, sel.GetNP())) - { - auto face = GetMappedFace(sei, facei); - if(isIntersectingFace(seg, face, lam_)) // && lam_ > other_limit) - { - lam = min(lam, lam_); - } - } - } - return false; - }); - if(lam<1) - { - if(lam0) - { - limit_reached = true; - lam = lam_lower_limit; - } - limits[pi] = min(limits[pi], lam); - } - } - step++; + auto gw = ns[0]; + auto n = ns[1]; + auto npn = gw * n; + auto npnp = gw * gw; + auto nn = n * n; + if (fabs(nn - npn * npn / npnp) < 1e-6) + return n; + gw += (nn - npn) / (nn - npn * npn / npnp) * (n - npn / npnp * gw); + return gw; } - - self_intersection(); - smooth(3); - - for(auto pi : Range(growthvectors)) - growthvectors[pi] *= limits[pi]; - - } - - - // depending on the geometry type, the mesh contains segments multiple times (once for each face) - bool HaveSingleSegments( const Mesh & mesh ) - { - auto& topo = mesh.GetTopology(); - NgArray surf_els; - - for(auto segi : Range(mesh.LineSegments())) - { - mesh.GetTopology().GetSegmentSurfaceElements(segi+1, surf_els); - if(surf_els.Size()<2) - continue; - - auto seg = mesh[segi]; - auto pi0 = min(seg[0], seg[1]); - auto pi1 = max(seg[0], seg[1]); - auto p0_segs = topo.GetVertexSegments(seg[0]); - - for(auto segi_other : p0_segs) - { - if(segi_other == segi) - continue; - - auto seg_other = mesh[segi_other]; - auto pi0_other = min(seg_other[0], seg_other[1]); - auto pi1_other = max(seg_other[0], seg_other[1]); - if( pi0_other == pi0 && pi1_other == pi1 ) - return false; - } - - // found segment with multiple adjacent surface elements but no other segments with same points -> have single segments - return true; - } - - return true; - } - - // duplicates segments (and sets seg.si accordingly) to have a unified data structure for all geometry types - Array BuildSegments( Mesh & mesh ) - { - Array segments; - auto& topo = mesh.GetTopology(); - - NgArray surf_els; - - for(auto segi : Range(mesh.LineSegments())) - { - auto seg = mesh[segi]; - mesh.GetTopology().GetSegmentSurfaceElements(segi+1, surf_els); - for(auto seli : surf_els) - { - const auto & sel = mesh[seli]; - seg.si = sel.GetIndex(); - - auto np = sel.GetNP(); - for(auto i : Range(np)) - { - if(sel[i] == seg[0]) - { - if(sel[(i+1)%np] != seg[1]) - swap(seg[0], seg[1]); - break; - } - } - - segments.Append(seg); - } - } - return segments; - } - - void MergeAndAddSegments( Mesh & mesh, FlatArray new_segments) - { - INDEX_2_HASHTABLE already_added( 2*new_segments.Size() ); - - for(auto & seg : mesh.LineSegments()) - { - INDEX_2 i2 (seg[0], seg[1]); - i2.Sort(); - if(!already_added.Used(i2)) - already_added.Set(i2, true); - } - - for(auto & seg : new_segments) - { - INDEX_2 i2 (seg[0], seg[1]); - i2.Sort(); - - if(!already_added.Used(i2)) - { - mesh.AddSegment(seg); - already_added.Set(i2, true); - } - } - } - - void BoundaryLayerTool :: InterpolateSurfaceGrowthVectors() - { - static Timer tall("InterpolateSurfaceGrowthVectors"); RegionTimer rtall(tall); - static Timer tsmooth("InterpolateSurfaceGrowthVectors-Smoothing"); - auto np = mesh.GetNP(); - BitArray is_point_on_bl_surface(np+1); - is_point_on_bl_surface.Clear(); - BitArray is_point_on_other_surface(np+1); - is_point_on_other_surface.Clear(); - Array, PointIndex> normals(np); - for(auto pi : Range(growthvectors)) - normals[pi] = growthvectors[pi]; - - ParallelForRange( mesh.SurfaceElements().Range(), [&] ( auto myrange ) - { - for(SurfaceElementIndex sei : myrange) - { - auto facei = mesh[sei].GetIndex(); - if(facei < nfd_old && !params.surfid.Contains(facei)) - { - for(auto pi : mesh[sei].PNums()) - if(mesh[pi].Type() == SURFACEPOINT) - is_point_on_other_surface.SetBitAtomic(pi); - } - else - { - for(auto pi : mesh[sei].PNums()) - if(mesh[pi].Type() == SURFACEPOINT) - is_point_on_bl_surface.SetBitAtomic(pi); - } - } - }); - - Array points; - for(PointIndex pi : mesh.Points().Range()) - { - if(is_point_on_bl_surface[pi]) - { - points.Append(pi); - growthvectors[pi] = 0.0; - } - if(is_point_on_other_surface[pi]) - { - points.Append(pi); - } - } - - // smooth tangential part of growth vectors from edges to surface elements - RegionTimer rtsmooth(tsmooth); - for(auto i : Range(10)) + if (ns.Size() == 3) { - for(auto pi : points) - { - auto sels = p2sel[pi]; - Vec<3> new_gw = growthvectors[pi]; - int cnt = 1; - std::set suround; - suround.insert(pi); - auto normal = normals[pi]; - for(auto sei: sels) - { - const auto & sel = mesh[sei]; - for(auto pi1 : sel.PNums()) - if(suround.count(pi1)==0) - { - suround.insert(pi1); - auto gw_other = growthvectors[pi1]; - auto normal_other = getNormal(mesh[sei]); - auto tangent_part = gw_other - (gw_other*normal_other)*normal_other; - if(is_point_on_bl_surface[pi]) - new_gw += tangent_part; - else - new_gw += gw_other; - } - } + DenseMatrix mat(3, 3); + for (auto i : Range(3)) + for (auto j : Range(3)) + mat(i, j) = ns[i][j]; - growthvectors[pi] = 1.0/suround.size() * new_gw; + if (fabs(mat.Det()) > 1e-2) + { + DenseMatrix mat(3, 3); + for (auto i : Range(3)) + for (auto j : Range(3)) + mat(i, j) = ns[i] * ns[j]; + if (fabs(mat.Det()) > 1e-2) + { + Vector rhs(3); + rhs = 1.; + Vector res(3); + DenseMatrix inv(3, ns.Size()); + CalcInverse(mat, inv); + inv.Mult(rhs, res); + Vec<3> growth = 0.; + for (auto i : Range(ns)) + growth += res[i] * ns[i]; + return growth; + } } } + auto [maxpos1, maxpos2] = FindCloseVectors(ns); + Array> new_normals; + new_normals = ns; + // const auto dot = ns[maxpos1] * ns[maxpos2]; + auto average = 0.5 * (ns[maxpos1] + ns[maxpos2]); + average.Normalize(); + new_normals[maxpos1] = average; + new_normals.DeleteElement(maxpos2); + auto gw = CalcGrowthVector(new_normals); - for(auto pi : points) - growthvectors[pi] += normals[pi]; - } + for (auto n : ns) + if (n * gw < 0) + throw SpecialPointException(); + return gw; +} +SpecialBoundaryPoint ::GrowthGroup ::GrowthGroup (FlatArray faces_, + FlatArray> normals) +{ + faces = faces_; + growth_vector = CalcGrowthVector(normals); +} - BoundaryLayerTool::BoundaryLayerTool(Mesh & mesh_, const BoundaryLayerParameters & params_) - : mesh(mesh_), topo(mesh_.GetTopology()), params(params_) - { - static Timer timer("BoundaryLayerTool::ctor"); - RegionTimer regt(timer); - - //for(auto & seg : mesh.LineSegments()) - //seg.edgenr = seg.epgeominfo[1].edgenr; - - height = 0.0; - for (auto h : params.heights) - height += h; - - max_edge_nr = -1; - for(const auto& seg : mesh.LineSegments()) - if(seg.edgenr > max_edge_nr) - max_edge_nr = seg.edgenr; - - int ndom = mesh.GetNDomains(); - ndom_old = ndom; - - new_mat_nrs.SetSize(mesh.FaceDescriptors().Size() + 1); - new_mat_nrs = -1; - for(auto [bcname, matname] : params.new_mat) - { - mesh.SetMaterial(++ndom, matname); - regex pattern(bcname); - for(auto i : Range(1, mesh.GetNFD()+1)) - { - auto& fd = mesh.GetFaceDescriptor(i); - if(regex_match(fd.GetBCName(), pattern)) - new_mat_nrs[i] = ndom; - } - } - - domains = params.domains; - if(!params.outside) - domains.Invert(); - - topo.SetBuildVertex2Element(true); - mesh.UpdateTopology(); - - have_single_segments = HaveSingleSegments(mesh); - if(have_single_segments) - segments = BuildSegments(mesh); - else - segments = mesh.LineSegments(); - - np = mesh.GetNP(); - ne = mesh.GetNE(); - nse = mesh.GetNSE(); - nseg = segments.Size(); - - p2sel = mesh.CreatePoint2SurfaceElementTable(); - - nfd_old = mesh.GetNFD(); - moved_surfaces.SetSize(nfd_old+1); - moved_surfaces.Clear(); - si_map.SetSize(nfd_old+1); - for(auto i : Range(nfd_old+1)) - si_map[i] = i; - } - - void BoundaryLayerTool :: CreateNewFaceDescriptors() - { - surfacefacs.SetSize(nfd_old+1); - surfacefacs = 0.0; - // create new FaceDescriptors - for(auto i : Range(1, nfd_old+1)) - { - const auto& fd = mesh.GetFaceDescriptor(i); - string name = fd.GetBCName(); - if(params.surfid.Contains(i)) - { - if(auto isIn = domains.Test(fd.DomainIn()); isIn != domains.Test(fd.DomainOut())) - { - int new_si = mesh.GetNFD()+1; - surfacefacs[i] = isIn ? 1. : -1.; - // -1 surf nr is so that curving does not do anything - FaceDescriptor new_fd(-1, isIn ? new_mat_nrs[i] : fd.DomainIn(), - isIn ? fd.DomainOut() : new_mat_nrs[i], -1); - new_fd.SetBCProperty(new_si); - mesh.AddFaceDescriptor(new_fd); - si_map[i] = new_si; - moved_surfaces.SetBit(i); - mesh.SetBCName(new_si-1, "mapped_" + name); - } - } - } - } - - void BoundaryLayerTool ::CreateFaceDescriptorsSides() - { - BitArray face_done(mesh.GetNFD()+1); - face_done.Clear(); - for(const auto& sel : mesh.SurfaceElements()) - { - auto facei = sel.GetIndex(); - if(face_done.Test(facei)) - continue; - bool point_moved = false; - bool point_fixed = false; - for(auto pi : sel.PNums()) - { - if(growthvectors[pi].Length() > 0) - point_moved = true; - else - point_fixed = true; - } - if(point_moved && !moved_surfaces.Test(facei)) - { - int new_si = mesh.GetNFD()+1; - const auto& fd = mesh.GetFaceDescriptor(facei); - auto isIn = domains.Test(fd.DomainIn()); - auto isOut = domains.Test(fd.DomainOut()); - int si = params.sides_keep_surfaceindex ? facei : -1; - // domin and domout can only be set later - FaceDescriptor new_fd(si, -1, - -1, si); - new_fd.SetBCProperty(new_si); - mesh.AddFaceDescriptor(new_fd); - si_map[facei] = new_si; - mesh.SetBCName(new_si-1, fd.GetBCName()); - face_done.SetBit(facei); - } - } - } - - void BoundaryLayerTool :: CalculateGrowthVectors() - { - growthvectors.SetSize(np); - growthvectors = 0.; - - for(auto pi : mesh.Points().Range()) +SpecialBoundaryPoint ::SpecialBoundaryPoint ( + const std::map>& normals) +{ + // find opposing face normals + Array> ns; + Array faces; + for (auto [face, normal] : normals) { - const auto & p = mesh[pi]; - if(p.Type() == INNERPOINT) + ns.Append(normal); + faces.Append(face); + } + + auto [minface1, minface2] = FindCloseVectors(ns, false); + minface1 = faces[minface1]; + minface2 = faces[minface2]; + Array g1_faces; + g1_faces.Append(minface1); + Array g2_faces; + g2_faces.Append(minface2); + auto n1 = normals.at(minface1); + auto n2 = normals.at(minface2); + separating_direction = 0.5 * (n2 - n1); + + Array> normals1, normals2; + for (auto [facei, normali] : normals) + if (facei != minface1 && facei != minface2) + { + g1_faces.Append(facei); + g2_faces.Append(facei); + } + for (auto fi : g1_faces) + normals1.Append(normals.at(fi)); + for (auto fi : g2_faces) + normals2.Append(normals.at(fi)); + growth_groups.Append(GrowthGroup(g1_faces, normals1)); + growth_groups.Append(GrowthGroup(g2_faces, normals2)); +} + +Vec<3> BoundaryLayerTool ::getEdgeTangent (PointIndex pi, int edgenr, FlatArray segs) +{ + Vec<3> tangent = 0.0; + ArrayMem pts; + for (auto* p_seg : segs) + { + auto& seg = *p_seg; + if (seg.edgenr != edgenr) + continue; + PointIndex other = seg[0] - pi + seg[1]; + if (!pts.Contains(other)) + pts.Append(other); + } + if (pts.Size() != 2) + { + cout << "getEdgeTangent pi = " << pi << ", edgenr = " << edgenr << endl; + cout << pts << endl; + for (auto* p_seg : segs) + cout << *p_seg << endl; + throw NG_EXCEPTION("Something went wrong in getEdgeTangent!"); + } + tangent = mesh[pts[1]] - mesh[pts[0]]; + return tangent.Normalize(); +} + +void BoundaryLayerTool ::LimitGrowthVectorLengths () +{ + static Timer tall("BoundaryLayerTool::LimitGrowthVectorLengths"); + RegionTimer rtall(tall); + + GrowthVectorLimiter limiter(*this); + limiter.Perform(); +} + +// depending on the geometry type, the mesh contains segments multiple times +// (once for each face) +bool HaveSingleSegments (const Mesh& mesh) +{ + auto& topo = mesh.GetTopology(); + NgArray surf_els; + + for (auto segi : Range(mesh.LineSegments())) + { + mesh.GetTopology().GetSegmentSurfaceElements(segi + 1, surf_els); + if (surf_els.Size() < 2) + continue; + + auto seg = mesh[segi]; + auto pi0 = min(seg[0], seg[1]); + auto pi1 = max(seg[0], seg[1]); + auto p0_segs = topo.GetVertexSegments(seg[0]); + + for (auto segi_other : p0_segs) + { + if (segi_other == segi) continue; - std::map> normals; - - // calculate one normal vector per face (average with angles as weights for multiple surface elements within a face) - for(auto sei : p2sel[pi]) - { - const auto & sel = mesh[sei]; - auto facei = sel.GetIndex(); - if(!params.surfid.Contains(facei)) - continue; - - auto n = surfacefacs[sel.GetIndex()] * getNormal(sel); - - int itrig = sel.PNums().Pos(pi); - itrig += sel.GetNP(); - auto v0 = (mesh[sel.PNumMod(itrig+1)] - mesh[pi]).Normalize(); - auto v1 = (mesh[sel.PNumMod(itrig-1)] - mesh[pi]).Normalize(); - if(normals.count(facei)==0) - normals[facei] = {0.,0.,0.}; - normals[facei] += acos(v0*v1)*n; + auto seg_other = mesh[segi_other]; + auto pi0_other = min(seg_other[0], seg_other[1]); + auto pi1_other = max(seg_other[0], seg_other[1]); + if (pi0_other == pi0 && pi1_other == pi1) + return false; } - for(auto & [facei, n] : normals) - n *= 1.0/n.Length(); + // found segment with multiple adjacent surface elements but no other + // segments with same points -> have single segments + return true; + } - // combine normal vectors for each face to keep uniform distances - auto & np = growthvectors[pi]; - ArrayMem, 3> ns; - for (auto &[facei, n] : normals) { + return true; +} + +// duplicates segments (and sets seg.si accordingly) to have a unified data +// structure for all geometry types +void BuildSegments (Mesh& mesh, bool have_single_segments, Array& segments, Array& free_segments) +{ + // auto& topo = mesh.GetTopology(); + + NgArray surf_els; + + for (auto segi : Range(mesh.LineSegments())) + { + auto seg = mesh[segi]; + if (seg.domin == seg.domout && seg.domin > 0) + { + free_segments.Append(seg); + continue; + } + if (!have_single_segments) + { + segments.Append(seg); + continue; + } + mesh.GetTopology().GetSegmentSurfaceElements(segi + 1, surf_els); + for (auto seli : surf_els) + { + const auto& sel = mesh[seli]; + seg.si = sel.GetIndex(); + + auto np = sel.GetNP(); + for (auto i : Range(np)) + { + if (sel[i] == seg[0]) + { + if (sel[(i + 1) % np] != seg[1]) + swap(seg[0], seg[1]); + break; + } + } + + segments.Append(seg); + } + } +} + +void MergeAndAddSegments (Mesh& mesh, FlatArray segments, FlatArray new_segments) +{ + INDEX_2_HASHTABLE already_added(segments.Size() + 2 * new_segments.Size()); + + mesh.LineSegments().SetSize0(); + + auto addSegment = [&] (auto seg) { + SortedPointIndices<2> i2(seg[0], seg[1]); + if (!already_added.Used(i2)) + { + seg.si = seg.edgenr + 1; + mesh.AddSegment(seg); + already_added.Set(i2, true); + } + }; + + for (const auto& seg : segments) + addSegment(seg); + + for (const auto& seg : new_segments) + addSegment(seg); +} + +BoundaryLayerTool::BoundaryLayerTool (Mesh& mesh_, + const BoundaryLayerParameters& params_) + : mesh(mesh_), topo(mesh_.GetTopology()), params(params_) +{ + static Timer timer("BoundaryLayerTool::ctor"); + RegionTimer regt(timer); + ProcessParameters(); + if (domains.NumSet() == 0) + return; + + topo.SetBuildVertex2Element(true); + mesh.UpdateTopology(); + + old_segments = mesh.LineSegments(); + have_single_segments = HaveSingleSegments(mesh); + + BuildSegments(mesh, have_single_segments, segments, free_segments); + + np = mesh.GetNP(); + first_new_pi = IndexBASE() + np; + ne = mesh.GetNE(); + nse = mesh.GetNSE(); + nseg = segments.Size(); + + p2sel = mesh.CreatePoint2SurfaceElementTable(); + + nfd_old = mesh.GetNFD(); + moved_surfaces.SetSize(nfd_old + 1); + moved_surfaces.Clear(); + si_map.SetSize(nfd_old + 1); + for (auto i : Range(nfd_old + 1)) + si_map[i] = i; +} + +void BoundaryLayerTool ::CreateNewFaceDescriptors () +{ + surfacefacs.SetSize(nfd_old + 1); + surfacefacs = 0.0; + // create new FaceDescriptors + for (auto i : Range(1, nfd_old + 1)) + { + const auto& fd = mesh.GetFaceDescriptor(i); + string name = fd.GetBCName(); + if (par_surfid.Contains(i)) + { + if (auto isIn = domains.Test(fd.DomainIn()); + isIn != domains.Test(fd.DomainOut())) + { + int new_si = mesh.GetNFD() + 1; + surfacefacs[i] = isIn ? 1. : -1.; + moved_surfaces.SetBit(i); + if (!insert_only_volume_elements) + { + // -1 surf nr is so that curving does not do anything + FaceDescriptor new_fd(-1, isIn ? new_mat_nrs[i] : fd.DomainIn(), isIn ? fd.DomainOut() : new_mat_nrs[i], -1); + new_fd.SetBCProperty(new_si); + new_fd.SetSurfColour(fd.SurfColour()); + mesh.AddFaceDescriptor(new_fd); + si_map[i] = new_si; + mesh.SetBCName(new_si - 1, "mapped_" + name); + } + } + // curving of surfaces with boundary layers will often + // result in pushed through elements, since we do not (yet) + // curvature through layers. + // Therefore we disable curving for these surfaces. + if (params.disable_curving) + mesh.GetFaceDescriptor(i).SetSurfNr(-1); + } + } + + for (auto si : par_surfid) + if (surfacefacs[si] == 0.0) + throw Exception("Surface " + to_string(si) + " is not a boundary of the domain to be grown into!"); +} + +void BoundaryLayerTool ::CreateFaceDescriptorsSides () +{ + if (insert_only_volume_elements) + return; + BitArray face_done(mesh.GetNFD() + 1); + face_done.Clear(); + for (const auto& sel : mesh.SurfaceElements()) + { + auto facei = sel.GetIndex(); + if (face_done.Test(facei)) + continue; + bool point_moved = false; + // bool point_fixed = false; + for (auto pi : sel.PNums()) + { + if (growthvectors[pi].Length() > 0) + point_moved = true; + /* + else + point_fixed = true; + */ + } + if (point_moved && !moved_surfaces.Test(facei)) + { + int new_si = mesh.GetNFD() + 1; + const auto& fd = mesh.GetFaceDescriptor(facei); + // auto isIn = domains.Test(fd.DomainIn()); + // auto isOut = domains.Test(fd.DomainOut()); + int si = params.sides_keep_surfaceindex ? facei : -1; + // domin and domout can only be set later + FaceDescriptor new_fd(si, -1, -1, si); + new_fd.SetBCProperty(new_si); + mesh.AddFaceDescriptor(new_fd); + si_map[facei] = new_si; + mesh.SetBCName(new_si - 1, fd.GetBCName()); + face_done.SetBit(facei); + } + } +} + +void BoundaryLayerTool ::CalculateGrowthVectors () +{ + growthvectors.SetSize(np); + growthvectors = 0.; + + for (auto pi : mesh.Points().Range()) + { + const auto& p = mesh[pi]; + if (p.Type() == INNERPOINT) + continue; + + std::map> normals; + + // calculate one normal vector per face (average with angles as weights for + // multiple surface elements within a face) + for (auto sei : p2sel[pi]) + { + const auto& sel = mesh[sei]; + auto facei = sel.GetIndex(); + if (!par_surfid.Contains(facei)) + continue; + + auto n = surfacefacs[sel.GetIndex()] * getNormal(sel); + + int itrig = sel.PNums().Pos(pi); + itrig += sel.GetNP(); + auto v0 = (mesh[sel.PNumMod(itrig + 1)] - mesh[pi]).Normalize(); + auto v1 = (mesh[sel.PNumMod(itrig - 1)] - mesh[pi]).Normalize(); + if (normals.count(facei) == 0) + normals[facei] = {0., 0., 0.}; + normals[facei] += acos(v0 * v1) * n; + } + + for (auto& [facei, n] : normals) + n *= 1.0 / n.Length(); + + // combine normal vectors for each face to keep uniform distances + ArrayMem, 5> ns; + for (auto& [facei, n] : normals) + { ns.Append(n); } - ArrayMem, 3> removed; - // reduce to full rank of max 3 - while(true) - { - if(ns.Size() <= 1) - break; - if(ns.Size() == 2 && ns[0] * ns[1] < 1 - 1e-6) - break; - if (ns.Size() == 3) - { - DenseMatrix mat(3,3); - for(auto i : Range(3)) - for(auto j : Range(3)) - mat(i,j) = ns[i][j]; - if(fabs(mat.Det()) > 1e-6) - break; - } - int maxpos1; - int maxpos2; - double val = 0; - for (auto i : Range(ns)) - { - for (auto j : Range(i + 1, ns.Size())) - { - double ip = ns[i] * ns[j]; - if(ip > val) - { - val = ip; - maxpos1 = i; - maxpos2 = j; - } - } - } - removed.Append(ns[maxpos1]); - removed.Append(ns[maxpos2]); - ns[maxpos1] = 0.5 * (ns[maxpos1] + ns[maxpos2]); - ns.DeleteElement(maxpos2); - } - - if(ns.Size() == 0) - continue; - if(ns.Size() == 1) - np = ns[0]; - else if(ns.Size() == 2) - { - np = ns[0]; - auto n = ns[1]; - auto npn = np * n; - auto npnp = np * np; - auto nn = n * n; - if(nn-npn*npn/npnp == 0) { np = n; continue; } - np += (nn - npn)/(nn - npn*npn/npnp) * (n - npn/npnp * np); - } - else // ns.Size() == 3 - { - DenseMatrix mat(3,3); - for(auto i : Range(3)) - for(auto j : Range(3)) - mat(i, j) = ns[i] * ns[j]; - Vector rhs(3); - rhs = 1.; - Vector res(3); - DenseMatrix inv(3, ns.Size()); - CalcInverse(mat, inv); - inv.Mult(rhs, res); - for(auto i : Range(ns)) - np += res[i] * ns[i]; - } - for(auto& n : removed) - if(n * np < 0) - cout << "WARNING: Growth vector at point " << pi << " in opposite direction to face normal!" << endl << "Growthvector = " << np << ", face normal = " << n << endl; - } - } - - Array>, SegmentIndex> BoundaryLayerTool :: BuildSegMap() - { - // Bit array to keep track of segments already processed - BitArray segs_done(nseg+1); - segs_done.Clear(); - - // map for all segments with same points - // points to pair of SegmentIndex, int - // int is type of other segment, either: - // 0 == adjacent surface grows layer - // 1 == adjacent surface doesn't grow layer, but layer ends on it - // 2 == adjacent surface is interior surface that ends on layer - // 3 == adjacent surface is exterior surface that ends on layer (not allowed yet) - Array>, SegmentIndex> segmap(segments.Size()); - - // moved segments - is_edge_moved.SetSize(max_edge_nr+1); - is_edge_moved = false; - - // boundaries to project endings to - is_boundary_projected.SetSize(nfd_old+1); - is_boundary_projected.Clear(); - is_boundary_moved.SetSize(nfd_old+1); - is_boundary_moved.Clear(); - - for(auto si : Range(segments)) - { - if(segs_done[si]) continue; - const auto& segi = segments[si]; - if(!moved_surfaces.Test(segi.si)) continue; - segs_done.SetBit(si); - segmap[si].Append(make_pair(si, 0)); - moved_segs.Append(si); - is_edge_moved.SetBit(segi.edgenr); - for(auto sj : Range(segments)) - { - if(segs_done.Test(sj)) continue; - const auto& segj = segments[sj]; - if((segi[0] == segj[0] && segi[1] == segj[1]) || - (segi[0] == segj[1] && segi[1] == segj[0])) - { - segs_done.SetBit(sj); - int type; - if(moved_surfaces.Test(segj.si)) - type = 0; - else if(const auto& fd = mesh.GetFaceDescriptor(segj.si); domains.Test(fd.DomainIn()) && domains.Test(fd.DomainOut())) - { - type = 2; - if(fd.DomainIn() == 0 || fd.DomainOut() == 0) - is_boundary_projected.SetBit(segj.si); - } - else if(const auto& fd = mesh.GetFaceDescriptor(segj.si); !domains.Test(fd.DomainIn()) && !domains.Test(fd.DomainOut())) - { - type = 3; - is_boundary_moved.SetBit(segj.si); - } - else - { - type = 1; - // in case 1 we project the growthvector onto the surface - is_boundary_projected.SetBit(segj.si); - } - segmap[si].Append(make_pair(sj, type)); - } - } - } - - return segmap; - } - - BitArray BoundaryLayerTool :: ProjectGrowthVectorsOnSurface() - { - BitArray in_surface_direction(nfd_old+1); - in_surface_direction.Clear(); - // project growthvector on surface for inner angles - if(params.grow_edges) - { - for(const auto& sel : mesh.SurfaceElements()) - if(is_boundary_projected.Test(sel.GetIndex())) - { - auto n = getNormal(sel); - for(auto i : Range(sel.PNums())) - { - auto pi = sel.PNums()[i]; - if(growthvectors[pi].Length2() == 0.) - continue; - auto next = sel.PNums()[(i+1)%sel.GetNV()]; - auto prev = sel.PNums()[i == 0 ? sel.GetNV()-1 : i-1]; - auto v1 = (mesh[next] - mesh[pi]).Normalize(); - auto v2 = (mesh[prev] - mesh[pi]).Normalize(); - auto v3 = growthvectors[pi]; - v3.Normalize(); - auto tol = v1.Length() * 1e-12; - if((v1 * v3 > -tol) && (v2 * v3 > -tol)) - in_surface_direction.SetBit(sel.GetIndex()); - else - continue; - - if(!params.project_boundaries.Contains(sel.GetIndex())) - continue; - auto& g = growthvectors[pi]; - auto ng = n * g; - auto gg = g * g; - auto nn = n * n; - // if(fabs(ng*ng-nn*gg) < 1e-12 || fabs(ng) < 1e-12) continue; - auto a = -ng*ng/(ng*ng-nn * gg); - auto b = ng*gg/(ng*ng-nn*gg); - g += a*g + b*n; - } - } - } - else - { - for(const auto& seg : segments) - { - int count = 0; - for(const auto& seg2 : segments) - if(((seg[0] == seg2[0] && seg[1] == seg2[1]) || (seg[0] == seg2[1] && seg[1] == seg2[0])) && params.surfid.Contains(seg2.si)) - count++; - if(count == 1) - { - growthvectors[seg[0]] = {0., 0., 0.}; - growthvectors[seg[1]] = {0., 0., 0.}; - } - } - } - - return in_surface_direction; - } - - void BoundaryLayerTool :: InterpolateGrowthVectors() - { - // interpolate tangential component of growth vector along edge - for(auto edgenr : Range(max_edge_nr)) - { - // if(!is_edge_moved[edgenr+1]) continue; - - // build sorted list of edge - Array points; - // find first vertex on edge - double edge_len = 0.; - auto is_end_point = [&] (PointIndex pi) + try { - // if(mesh[pi].Type() == FIXEDPOINT) - // return true; - // return false; - auto segs = topo.GetVertexSegments(pi); - auto first_edgenr = mesh[segs[0]].edgenr; - for(auto segi : segs) - if(mesh[segi].edgenr != first_edgenr) - return true; - return false; - }; + growthvectors[pi] = CalcGrowthVector(ns); + } + catch (const SpecialPointException& e) + { + special_boundary_points.emplace(pi, normals); + growthvectors[pi] = + special_boundary_points[pi].growth_groups[0].growth_vector; + } + } +} - bool any_grows = false; - - for(const auto& seg : segments) +Array>, SegmentIndex> +BoundaryLayerTool ::BuildSegMap () +{ + // Bit array to keep track of segments already processed + BitArray segs_done(nseg + 1); + segs_done.Clear(); + + // map for all segments with same points + // points to pair of SegmentIndex, int + // int is type of other segment, either: + // 0 == adjacent surface grows layer + // 1 == adjacent surface doesn't grow layer, but layer ends on it + // 2 == adjacent surface is interior surface that ends on layer + // 3 == adjacent surface is exterior surface that ends on layer (not allowed + // yet) + Array>, SegmentIndex> segmap(segments.Size()); + + // moved segments + is_edge_moved.SetSize(max_edge_nr + 1); + is_edge_moved = false; + + // boundaries to project endings to + is_boundary_projected.SetSize(nfd_old + 1); + is_boundary_projected.Clear(); + is_boundary_moved.SetSize(nfd_old + 1); + is_boundary_moved.Clear(); + + for (auto si : Range(segments)) + { + if (segs_done[si]) + continue; + const auto& segi = segments[si]; + if (!moved_surfaces.Test(segi.si)) + continue; + segs_done.SetBit(si); + segmap[si].Append(make_pair(si, 0)); + moved_segs.Append(si); + is_edge_moved.SetBit(segi.edgenr); + for (auto sj : Range(segments)) + { + if (segs_done.Test(sj)) + continue; + const auto& segj = segments[sj]; + if ((segi[0] == segj[0] && segi[1] == segj[1]) || (segi[0] == segj[1] && segi[1] == segj[0])) + { + segs_done.SetBit(sj); + int type; + if (moved_surfaces.Test(segj.si)) + { + type = 0; + moved_segs.Append(sj); + } + else if (const auto& fd = mesh.GetFaceDescriptor(segj.si); + domains.Test(fd.DomainIn()) && domains.Test(fd.DomainOut())) + { + type = 2; + if (fd.DomainIn() == 0 || fd.DomainOut() == 0) + is_boundary_projected.SetBit(segj.si); + } + else if (const auto& fd = mesh.GetFaceDescriptor(segj.si); + !domains.Test(fd.DomainIn()) && !domains.Test(fd.DomainOut())) + { + type = 3; + // cout << "set is_moved boundary to type 3 for " << segj.si << endl; + is_boundary_moved.SetBit(segj.si); + } + else + { + type = 1; + // in case 1 we project the growthvector onto the surface + is_boundary_projected.SetBit(segj.si); + } + segmap[si].Append(make_pair(sj, type)); + } + } + } + + return segmap; +} + +BitArray BoundaryLayerTool ::ProjectGrowthVectorsOnSurface () +{ + BitArray in_surface_direction(nfd_old + 1); + in_surface_direction.Clear(); + // project growthvector on surface for inner angles + if (params.grow_edges) + { + for (const auto& sel : mesh.SurfaceElements()) + if (is_boundary_projected.Test(sel.GetIndex())) { - if(seg.edgenr-1 == edgenr) + auto n = getNormal(sel); + for (auto i : Range(sel.PNums())) { - if(growthvectors[seg[0]].Length2() != 0 || - growthvectors[seg[1]].Length2() != 0) - any_grows = true; - if(points.Size() == 0 && is_end_point(seg[0])) - { - points.Append(seg[0]); - points.Append(seg[1]); - edge_len += (mesh[seg[1]] - mesh[seg[0]]).Length(); - } + auto pi = sel.PNums()[i]; + if (growthvectors[pi].Length2() == 0.) + continue; + auto next = sel.PNums()[(i + 1) % sel.GetNV()]; + auto prev = sel.PNums()[i == 0 ? sel.GetNV() - 1 : i - 1]; + auto v1 = (mesh[next] - mesh[pi]).Normalize(); + auto v2 = (mesh[prev] - mesh[pi]).Normalize(); + auto v3 = growthvectors[pi]; + v3.Normalize(); + auto tol = v1.Length() * 1e-12; + if ((v1 * v3 > -tol) && (v2 * v3 > -tol)) + in_surface_direction.SetBit(sel.GetIndex()); + else + continue; + + if (!par_project_boundaries.Contains(sel.GetIndex())) + continue; + auto& g = growthvectors[pi]; + auto ng = n * g; + auto gg = g * g; + auto nn = n * n; + // if(fabs(ng*ng-nn*gg) < 1e-12 || fabs(ng) < 1e-12) continue; + auto a = -ng * ng / (ng * ng - nn * gg); + auto b = ng * gg / (ng * ng - nn * gg); + g += a * g + b * n; } } + } + else + { + for (const auto& seg : segments) + { + int count = 0; + for (const auto& seg2 : segments) + if (((seg[0] == seg2[0] && seg[1] == seg2[1]) || (seg[0] == seg2[1] && seg[1] == seg2[0])) && par_surfid.Contains(seg2.si)) + count++; + if (count == 1) + { + growthvectors[seg[0]] = {0., 0., 0.}; + growthvectors[seg[1]] = {0., 0., 0.}; + } + } + } - if(!any_grows) - continue; + return in_surface_direction; +} - if(!points.Size()) - throw Exception("Could not find startpoint for edge " + ToString(edgenr)); +void BoundaryLayerTool ::InsertNewElements ( + FlatArray>, SegmentIndex> segmap, + const BitArray& in_surface_direction) +{ + static Timer timer("BoundaryLayerTool::InsertNewElements"); + RegionTimer rt(timer); + mapto.SetSize(0); + mapto.SetSize(np); + mapfrom.SetSize(mesh.GetNP()); + mapfrom = PointIndex::INVALID; - while(true) - { - bool point_found = false; - for(auto si : topo.GetVertexSegments(points.Last())) - { - const auto& seg = mesh[si]; - if(seg.edgenr-1 != edgenr) - continue; - if(seg[0] == points.Last() && points[points.Size()-2] !=seg[1]) - { - edge_len += (mesh[points.Last()] - mesh[seg[1]]).Length(); - points.Append(seg[1]); - point_found = true; - break; - } - else if(seg[1] == points.Last() && - points[points.Size()-2] != seg[0]) - { - edge_len += (mesh[points.Last()] - mesh[seg[0]]).Length(); - points.Append(seg[0]); - point_found = true; - break; - } - } - if(is_end_point(points.Last())) - break; - if(!point_found) - { - throw Exception(string("Could not find connected list of line segments for edge ") + edgenr); - } - } + auto changed_domains = domains; + if (!params.outside) + changed_domains.Invert(); - if(growthvectors[points[0]].Length2() == 0 && - growthvectors[points.Last()].Length2() == 0) - continue; + auto& identifications = mesh.GetIdentifications(); + const int identnr = identifications.GetNr("boundarylayer"); - // tangential part of growth vectors - auto t1 = (mesh[points[1]]-mesh[points[0]]).Normalize(); - auto gt1 = growthvectors[points[0]] * t1 * t1; - auto t2 = (mesh[points.Last()]-mesh[points[points.Size()-2]]).Normalize(); - auto gt2 = growthvectors[points.Last()] * t2 * t2; - - if(!is_edge_moved[edgenr+1]) - { - if(growthvectors[points[0]] * (mesh[points[1]] - mesh[points[0]]) < 0) - gt1 = 0.; - if(growthvectors[points.Last()] * (mesh[points[points.Size()-2]] - mesh[points.Last()]) < 0) - gt2 = 0.; - } - - double len = 0.; - for(size_t i = 1; i < points.Size()-1; i++) - { - auto pi = points[i]; - len += (mesh[pi] - mesh[points[i-1]]).Length(); - auto t = getEdgeTangent(pi, edgenr); - auto lam = len/edge_len; - auto interpol = (1-lam) * (gt1 * t) * t + lam * (gt2 * t) * t; - growthvectors[pi] += interpol; - } + auto add_points = [&] (PointIndex pi, Vec<3>& growth_vector, Array& new_points) { + Point<3> p = mesh[pi]; + PointIndex pi_last = pi; + double height = 0.0; + for (auto i : Range(par_heights)) + { + height += par_heights[i]; + auto pi_new = mesh.AddPoint(p); + // mesh.AddLockedPoint(pi_new); + mapfrom.Append(pi); + new_points.Append(pi_new); + growth_vector_map[pi_new] = {&growth_vector, height}; + // if (special_boundary_points.count(pi) > 0) + // mesh.AddLockedPoint(pi_new); + pi_last = pi_new; } + }; - InterpolateSurfaceGrowthVectors(); - } - - void BoundaryLayerTool :: InsertNewElements( FlatArray>, SegmentIndex> segmap, const BitArray & in_surface_direction ) - { - static Timer timer("BoundaryLayerTool::InsertNewElements"); RegionTimer rt(timer); - Array, PointIndex> mapto(np); - // insert new points - for (PointIndex pi = 1; pi <= np; pi++) + // insert new points + // for (PointIndex pi = 1; pi <= np; pi++) + for (PointIndex pi = IndexBASE(); + pi < IndexBASE() + np; + pi++) + { if (growthvectors[pi].Length2() != 0) { - Point<3> p = mesh[pi]; - for(auto i : Range(params.heights)) + if (special_boundary_points.count(pi)) { - p += params.heights[i] * growthvectors[pi]; - mapto[pi].Append(mesh.AddPoint(p)); + for (auto& group : special_boundary_points[pi].growth_groups) + add_points(pi, group.growth_vector, group.new_points); + } + else + add_points(pi, growthvectors[pi], mapto[pi]); + } + } + + // get point from mapto (or the group if point is mapped to multiple new + // points) layer = -1 means last point (top of boundary layer) + auto newPoint = [&] (PointIndex pi, int layer = -1, int group = 0) { + if (layer == -1) + layer = par_heights.Size() - 1; + if (special_boundary_points.count(pi)) + return special_boundary_points[pi].growth_groups[group].new_points[layer]; + else + return mapto[pi][layer]; + }; + + auto hasMoved = [&] (PointIndex pi) { + return mapto[pi].Size() > 0 || special_boundary_points.count(pi); + }; + + auto numGroups = [&] (PointIndex pi) -> size_t { + if (special_boundary_points.count(pi)) + return special_boundary_points[pi].growth_groups.Size(); + else + return 1; + }; + + auto getGroups = [&] (PointIndex pi, int face_index) -> Array { + auto n = numGroups(pi); + Array groups; + if (n == 1) + { + groups.Append(0); + return groups; + } + const auto& all_groups = special_boundary_points[pi].growth_groups; + for (auto i : Range(n)) + if (all_groups[i].faces.Contains(face_index)) + groups.Append(i); + // cout << "groups " << pi << ", " << face_index << endl << groups; + return groups; + }; + + // add 2d quads on required surfaces + map, int> seg2edge; + map edge_map; + int edge_nr = max_edge_nr; + auto getEdgeNr = [&] (int ei) { + if (edge_map.count(ei) == 0) + edge_map[ei] = ++edge_nr; + return edge_map[ei]; + }; + if (params.grow_edges) + { + for (auto sei : moved_segs) + { + // copy here since we will add segments and this would + // invalidate a reference! + // auto segi = segments[sei]; + for (auto [sej, type] : segmap[sei]) + { + auto segj = segments[sej]; + if (type == 0) + { + auto addSegment = [&] (PointIndex p0, PointIndex p1, bool extra_edge_nr = false) { + Segment s; + s[0] = p0; + s[1] = p1; + s[2] = PointIndex::INVALID; + [[maybe_unused]] auto pair = + s[0] < s[1] ? make_pair(s[0], s[1]) : make_pair(s[1], s[0]); + if (extra_edge_nr) + s.edgenr = ++edge_nr; + else + s.edgenr = getEdgeNr(segj.edgenr); + s.si = si_map[segj.si]; + new_segments.Append(s); + // cout << __LINE__ <<"\t" << s << endl; + return s; + }; + + auto p0 = segj[0], p1 = segj[1]; + auto g0 = getGroups(p0, segj.si); + auto g1 = getGroups(p1, segj.si); + + if (g0.Size() == 1 && g1.Size() == 1) + { + auto p0_new = newPoint(p0, -1, g0[0]); + auto p1_new = newPoint(p1, -1, g1[0]); + addSegment(p0_new, p1_new); + } + else + { + if (g0.Size() == 2) + addSegment(newPoint(p0, -1, g0[0]), newPoint(p0, -1, g0[1])); + if (g1.Size() == 2) + addSegment(newPoint(p1, -1, g1[0]), newPoint(p1, -1, g1[1])); + } + } + // here we need to grow the quad elements + else if (type == 1) + { + PointIndex pp1 = segj[1]; + PointIndex pp2 = segj[0]; + if (in_surface_direction.Test(segj.si)) + { + Swap(pp1, pp2); + is_boundary_moved.SetBit(segj.si); + } + PointIndex p1 = pp1; + PointIndex p2 = pp2; + PointIndex p3, p4; + Segment s0; + s0[0] = p1; + s0[1] = p2; + s0[2] = PointIndex::INVALID; + s0.edgenr = segj.edgenr; + s0.si = segj.si; + new_segments.Append(s0); + if (type == 3) + new_segments_on_moved_bnd.Append(s0); + + for (auto i : Range(par_heights)) + { + Element2d sel(QUAD); + p3 = newPoint(pp2, i); + p4 = newPoint(pp1, i); + sel[0] = p1; + sel[1] = p2; + sel[2] = p3; + sel[3] = p4; + for (auto i : Range(4)) + { + sel.GeomInfo()[i].u = 0.0; + sel.GeomInfo()[i].v = 0.0; + } + identifications.Add(p1, p4, identnr); + identifications.Add(p2, p3, identnr); + sel.SetIndex(si_map[segj.si]); + new_sels.Append(sel); + new_sels_on_moved_bnd.Append(sel); + + // TODO: Too many, would be enough to only add outermost ones + Segment s1; + s1[0] = p2; + s1[1] = p3; + s1[2] = PointIndex::INVALID; + auto pair = make_pair(p2, p3); + s1.edgenr = getEdgeNr(segj.edgenr); + s1.si = segj.si; + // new_segments.Append(s1); + Segment s2; + s2[0] = p4; + s2[1] = p1; + s2[2] = PointIndex::INVALID; + pair = make_pair(p1, p4); + s2.edgenr = getEdgeNr(segj.edgenr); + s2.si = segj.si; + // new_segments.Append(s2); + p1 = p4; + p2 = p3; + } + Segment s3; + s3[0] = p3; + s3[1] = p4; + s3[2] = PointIndex::INVALID; + // auto pair = p3 < p4 ? make_pair(p3, p4) : make_pair(p4, p3); + s3.edgenr = getEdgeNr(segj.edgenr); + s3.si = segj.si; + new_segments.Append(s3); + if (type == 3) + new_segments_on_moved_bnd.Append(s0); + } + else if (type == 3) + { + PointIndex pp1 = segj[1]; + PointIndex pp2 = segj[0]; + if (!in_surface_direction.Test(segj.si)) + { + Swap(pp1, pp2); + } + PointIndex p1 = pp1; + PointIndex p2 = pp2; + PointIndex p3, p4; + + for (auto i : Range(par_heights)) + { + Element2d sel(QUAD); + p3 = newPoint(pp2, i); + p4 = newPoint(pp1, i); + sel[0] = p1; + sel[1] = p2; + sel[2] = p3; + sel[3] = p4; + for (auto i : Range(4)) + { + sel.GeomInfo()[i].u = 0.0; + sel.GeomInfo()[i].v = 0.0; + } + identifications.Add(p1, p4, identnr); + identifications.Add(p2, p3, identnr); + sel.SetIndex(si_map[segj.si]); + new_sels.Append(sel); + new_sels_on_moved_bnd.Append(sel); + p1 = p4; + p2 = p3; + } + } + } + } + } + + auto getClosestGroup = [&] (PointIndex pi, SurfaceElementIndex sei) { + auto n = numGroups(pi); + if (n == 1) + return 0; + const auto& sel = mesh[sei]; + auto groups = getGroups(pi, sel.GetIndex()); + if (groups.Size() == 1) + return groups[0]; + + // auto& growth_groups = special_boundary_points[pi].growth_groups; + + auto vdir = Center(mesh[sel[0]], mesh[sel[1]], mesh[sel[2]]) - mesh[pi]; + auto dot = vdir * special_boundary_points[pi].separating_direction; + + return dot > 0 ? 1 : 0; + }; + + BitArray fixed_points(np + 1); + fixed_points.Clear(); + auto p2el = mesh.CreatePoint2ElementTable(); + for (SurfaceElementIndex si = 0; si < nse; si++) + { + const auto sel = mesh[si]; + const auto iface = sel.GetIndex(); + + if (moved_surfaces.Test(iface)) + { + const auto np = sel.GetNP(); + ArrayMem points(sel.PNums()); + if (surfacefacs[iface] > 0) + Swap(points[0], points[2]); + ArrayMem groups(points.Size()); + for (auto i : Range(points)) + groups[i] = getClosestGroup(points[i], si); + bool add_volume_element = true; + for (auto pi : points) + if (numGroups(pi) > 1) + add_volume_element = false; + + Element el(2 * np); + el.PNums().Range(np, 2 * np) = points; + auto new_index = new_mat_nrs[iface]; + if (new_index == -1) + throw Exception("Boundary " + ToString(iface) + " with name " + mesh.GetBCName(iface - 1) + " extruded, but no new material specified for it!"); + el.SetIndex(new_index); + + for (auto j : Range(par_heights)) + { + el.PNums().Range(0, np) = el.PNums().Range(np, 2 * np); + for (auto i : Range(np)) + el[np + i] = newPoint(points[i], j, groups[i]); + if (add_volume_element) + mesh.AddVolumeElement(el); + else + { + // Let the volume mesher fill the hole with pyramids/tets + // To insert pyramids, we need close surface identifications on open quads + for (auto i : Range(np)) + if (numGroups(el[i]) == 1) + { + auto pi0 = el[i]; + auto pi1 = el[np + i]; + auto nr = identifications.Get(pi0, pi1); + if (nr == 0) + identifications.Add(pi0, pi1, identnr); + } + } + } + Element2d newel = sel; + for (auto i : Range(np)) + newel[i] = newPoint(points[i], -1, groups[i]); + if (surfacefacs[iface] > 0) + Swap(newel[0], newel[2]); // swap back + newel.SetIndex(si_map[iface]); + new_sels.Append(newel); + } + if (is_boundary_moved.Test(iface)) + { + auto& sel = mesh[si]; + for (auto& p : sel.PNums()) + if (hasMoved(p)) + p = newPoint(p); + } + } + + for (SegmentIndex sei = 0; sei < nseg; sei++) + { + auto& seg = segments[sei]; + if (is_boundary_moved.Test(seg.si)) + { + // cout << "moved setg " << seg << endl; + for (auto& p : seg.PNums()) + if (hasMoved(p)) + { + p = newPoint(p); + if (params.disable_curving) + { + seg.epgeominfo[0].edgenr = -1; + seg.epgeominfo[1].edgenr = -1; + } + } + } + } + + // fill holes in surface mesh at special boundary points (i.e. points with >=4 + // adjacent boundary faces) + auto p2sel = ngcore::CreateSortedTable( + new_sels.Range(), + [&] (auto& table, SurfaceElementIndex ei) { + for (PointIndex pi : new_sels[ei].PNums()) + table.Add(pi, ei); + }, + mesh.GetNP()); + + for (auto& [special_pi, special_point] : special_boundary_points) + { + if (special_point.growth_groups.Size() != 2) + throw Exception("special_point.growth_groups.Size() != 2"); + + // Special points are split into two new points, when mapping a surface + // element, we choose the closer one to the center. Now, find points which + // are mapped to both new points (for different surface elements they belong + // to). At exactly these points we need to insert new surface elements to + // fill the hole. + std::map, 2>> close_group; + for (auto sei : p2sel[special_pi]) + { + const auto& sel = mesh[sei]; + for (auto p : sel.PNums()) + if (p != special_pi) + close_group[sel.GetIndex()][getClosestGroup(special_pi, sei)].insert( + p); + } + + for (auto [fi, groups] : close_group) + { + const auto mapped_fi = si_map[fi]; + std::set common_points; + for (auto pi : groups[0]) + if (groups[1].count(pi) == 1) + common_points.insert(pi); + if (common_points.size() > 0) + { + auto pi_common = mapto[*common_points.begin()].Last(); + auto new_special_pi0 = special_point.growth_groups[0].new_points.Last(); + auto new_special_pi1 = special_point.growth_groups[1].new_points.Last(); + for (auto sei : p2sel[pi_common]) + { + if (mesh[sei].GetIndex() == mapped_fi && mesh[sei].PNums().Contains(new_special_pi0)) + { + auto sel = mesh[sei]; + sel.Invert(); + for (auto& pi : sel.PNums()) + if (pi != pi_common && pi != new_special_pi0) + pi = new_special_pi1; + new_sels.Append(sel); + } + } + } + } + } + + for (auto& [pi, special_point] : special_boundary_points) + { + if (special_point.growth_groups.Size() != 2) + throw Exception("special_point.growth_groups.Size() != 2"); + for (auto igroup : Range(2)) + { + auto& group = special_point.growth_groups[igroup]; + std::set faces; + for (auto face : group.faces) + faces.insert(si_map[face]); + auto pi_new = group.new_points.Last(); + auto pi_new_other = + special_point.growth_groups[1 - igroup].new_points.Last(); + for (auto sei : p2sel[pi_new]) + faces.erase(mesh[sei].GetIndex()); + for (auto face : faces) + for (auto seg : new_segments) + { + if ( // seg.si == face + (seg[0] == pi_new || seg[1] == pi_new) && (seg[0] != pi_new_other && seg[1] != pi_new_other)) + { + bool is_correct_face = false; + auto pi_other = seg[0] == pi_new ? seg[1] : seg[0]; + for (auto sei : p2sel[pi_other]) + { + if (mesh[sei].GetIndex() == face) + { + is_correct_face = true; + break; + } + } + if (is_correct_face) + { + Element2d sel; + sel[0] = seg[1]; + sel[1] = seg[0]; + sel[2] = pi_new_other; + sel.SetIndex(face); + new_sels.Append(sel); + } + } + } + } + } +} + +void BoundaryLayerTool ::SetDomInOut () +{ + if (insert_only_volume_elements) + return; + for (auto i : Range(1, nfd_old + 1)) + if (moved_surfaces.Test(i)) + { + if (auto dom = mesh.GetFaceDescriptor(si_map[i]).DomainIn(); + dom > ndom_old) + mesh.GetFaceDescriptor(i).SetDomainOut(dom); + else + mesh.GetFaceDescriptor(i).SetDomainIn( + mesh.GetFaceDescriptor(si_map[i]).DomainOut()); + } +} + +void BoundaryLayerTool ::SetDomInOutSides () +{ + // Set the domin/domout entries for face descriptors on the "side" of new boundary layers + if (insert_only_volume_elements) + return; + BitArray done(mesh.GetNFD() + 1); + done.Clear(); + + std::map inv_si_map; + + for (auto i : Range(si_map.Size())) + inv_si_map[si_map[i]] = i; + + for (auto sei : Range(mesh.SurfaceElements())) + { + auto& sel = mesh[sei]; + auto index = sel.GetIndex(); + if (done.Test(index)) + continue; + done.SetBit(index); + if (index < nfd_old && moved_surfaces.Test(index)) + continue; + auto& fd = mesh.GetFaceDescriptor(index); + if (fd.DomainIn() != -1) + continue; + + // First check if there are adjacent volume elements, if so, use their domains + int e1 = 0, e2 = 0; + mesh.GetTopology().GetSurface2VolumeElement(sei + 1, e1, e2); + + int dom[2] = {-1, -1}; + + if (e1) + dom[0] = mesh.VolumeElement(e1).GetIndex(); + if (e2) + dom[1] = mesh.VolumeElement(e2).GetIndex(); + + const auto& fd_old = mesh.GetFaceDescriptor(inv_si_map[index]); + int dom_old[2] = {fd_old.DomainIn(), fd_old.DomainOut()}; + + for (auto i : Range(2)) + { + if (dom[i] != -1) + continue; // adjacent volume element -> done + if (dom_old[i] == 0) + { + // outer boundary -> keep 0 + dom[i] = 0; + continue; + } + + // Check if the old domain adjacent to this face gets a new boundary layer domain, if so, use that number + int dom_new = dom_old[i]; + if (domains.Test(dom_old[i]) && new_mat_nrs[dom_old[i]] > 0) + dom_new = new_mat_nrs[dom_old[i]]; + + // This case is tested by test_boundarylayer.py::test_pyramids[False] -> look at the generated mesh to understand the text below :) + // Special case check here: when growing "outside" the new face could have the same domain on both sides (before adding blayer elements). + // Thus we don't know in advance on which side the mapped domain will be. So check, if the other domain has already prisms (adjacent vol elements) with mapped domain. If so, use the original domain instead. + if (dom[1 - i] != dom_new) + { + dom[i] = dom_new; + } + else + { + dom[i] = dom_old[i]; } } - // add 2d quads on required surfaces - map, int> seg2edge; - if(params.grow_edges) - { - for(auto sei : moved_segs) - { - // copy here since we will add segments and this would - // invalidate a reference! - auto segi = segments[sei]; - for(auto [sej, type] : segmap[sei]) - { - auto segj = segments[sej]; - if(type == 0) - { - Segment s; - s[0] = mapto[segj[0]].Last(); - s[1] = mapto[segj[1]].Last(); - s[2] = PointIndex::INVALID; - auto pair = s[0] < s[1] ? make_pair(s[0], s[1]) : make_pair(s[1], s[0]); - if(seg2edge.find(pair) == seg2edge.end()) - seg2edge[pair] = ++max_edge_nr; - s.edgenr = seg2edge[pair]; - s.si = si_map[segj.si]; - new_segments.Append(s); - } - // here we need to grow the quad elements - else if(type == 1) - { - PointIndex pp1 = segj[1]; - PointIndex pp2 = segj[0]; - if(in_surface_direction.Test(segj.si)) - { - Swap(pp1, pp2); - is_boundary_moved.SetBit(segj.si); - } - PointIndex p1 = pp1; - PointIndex p2 = pp2; - PointIndex p3, p4; - Segment s0; - s0[0] = p1; - s0[1] = p2; - s0[2] = PointIndex::INVALID; - s0.edgenr = segj.edgenr; - s0.si = segj.si; - new_segments.Append(s0); + fd.SetDomainIn(dom[0]); + fd.SetDomainOut(dom[1]); + } +} - for(auto i : Range(params.heights)) - { - Element2d sel(QUAD); - p3 = mapto[pp2][i]; - p4 = mapto[pp1][i]; - sel[0] = p1; - sel[1] = p2; - sel[2] = p3; - sel[3] = p4; - for(auto i : Range(4)) - { - sel.GeomInfo()[i].u = 0.0; - sel.GeomInfo()[i].v = 0.0; - } - sel.SetIndex(si_map[segj.si]); - mesh.AddSurfaceElement(sel); - - // TODO: Too many, would be enough to only add outermost ones - Segment s1; - s1[0] = p2; - s1[1] = p3; - s1[2] = PointIndex::INVALID; - auto pair = make_pair(p2, p3); - if(seg2edge.find(pair) == seg2edge.end()) - seg2edge[pair] = ++max_edge_nr; - s1.edgenr = seg2edge[pair]; - s1.si = segj.si; - new_segments.Append(s1); - Segment s2; - s2[0] = p4; - s2[1] = p1; - s2[2] = PointIndex::INVALID; - pair = make_pair(p1, p4); - if(seg2edge.find(pair) == seg2edge.end()) - seg2edge[pair] = ++max_edge_nr; - s2.edgenr = seg2edge[pair]; - s2.si = segj.si; - new_segments.Append(s2); - p1 = p4; - p2 = p3; - } - Segment s3; - s3[0] = p3; - s3[1] = p4; - s3[2] = PointIndex::INVALID; - auto pair = p3 < p4 ? make_pair(p3, p4) : make_pair(p4, p3); - if(seg2edge.find(pair) == seg2edge.end()) - seg2edge[pair] = ++max_edge_nr; - s3.edgenr = seg2edge[pair]; - s3.si = segj.si; - new_segments.Append(s3); - } - } - } - } - - BitArray fixed_points(np+1); - fixed_points.Clear(); - BitArray moveboundarypoint(np+1); - moveboundarypoint.Clear(); - for(SurfaceElementIndex si = 0; si < nse; si++) - { - // copy because surfaceels array will be resized! - auto sel = mesh[si]; - if(moved_surfaces.Test(sel.GetIndex())) - { - Array points(sel.PNums()); - if(surfacefacs[sel.GetIndex()] > 0) Swap(points[0], points[2]); - for(auto j : Range(params.heights)) - { - auto eltype = points.Size() == 3 ? PRISM : HEX; - Element el(eltype); - for(auto i : Range(points)) - el[i] = points[i]; - for(auto i : Range(points)) - points[i] = mapto[sel.PNums()[i]][j]; - if(surfacefacs[sel.GetIndex()] > 0) Swap(points[0], points[2]); - for(auto i : Range(points)) - el[sel.PNums().Size() + i] = points[i]; - el.SetIndex(new_mat_nrs[sel.GetIndex()]); - mesh.AddVolumeElement(el); - } - Element2d newel = sel; - for(auto& p : newel.PNums()) - p = mapto[p].Last(); - newel.SetIndex(si_map[sel.GetIndex()]); - mesh.AddSurfaceElement(newel); - } - else - { - bool has_moved = false; - for(auto p : sel.PNums()) - if(mapto[p].Size()) - has_moved = true; - if(has_moved) - for(auto p : sel.PNums()) - { - if(!mapto[p].Size()) - { - fixed_points.SetBit(p); - if(is_boundary_moved.Test(sel.GetIndex())) - moveboundarypoint.SetBit(p); - } - } - } - if(is_boundary_moved.Test(sel.GetIndex())) - { - for(auto& p : mesh[si].PNums()) - if(mapto[p].Size()) - p = mapto[p].Last(); - } - } - - for(SegmentIndex sei = 0; sei < nseg; sei++) - { - auto& seg = segments[sei]; - if(is_boundary_moved.Test(seg.si)) - for(auto& p : seg.PNums()) - if(mapto[p].Size()) - p = mapto[p].Last(); - } - - for(ElementIndex ei = 0; ei < ne; ei++) - { - auto el = mesh[ei]; - ArrayMem fixed; - ArrayMem moved; - bool moved_bnd = false; - for(const auto& p : el.PNums()) - { - if(fixed_points.Test(p)) - fixed.Append(p); - if(mapto[p].Size()) - moved.Append(p); - if(moveboundarypoint.Test(p)) - moved_bnd = true; - } - - bool do_move, do_insert; - if(domains.Test(el.GetIndex())) - { - do_move = fixed.Size() && moved_bnd; - do_insert = do_move; - } - else - { - do_move = !fixed.Size() || moved_bnd; - do_insert = !do_move; - } - - if(do_move) - { - for(auto& p : mesh[ei].PNums()) - if(mapto[p].Size()) - p = mapto[p].Last(); - } - if(do_insert) - { - if(el.GetType() == TET) - { - if(moved.Size() == 3) // inner corner - { - PointIndex p1 = moved[0]; - PointIndex p2 = moved[1]; - PointIndex p3 = moved[2]; - auto v1 = mesh[p1]; - auto n = Cross(mesh[p2]-v1, mesh[p3]-v1); - auto d = mesh[mapto[p1][0]] - v1; - if(n*d > 0) - Swap(p2,p3); - PointIndex p4 = p1; - PointIndex p5 = p2; - PointIndex p6 = p3; - for(auto i : Range(params.heights)) - { - Element nel(PRISM); - nel[0] = p4; nel[1] = p5; nel[2] = p6; - p4 = mapto[p1][i]; p5 = mapto[p2][i]; p6 = mapto[p3][i]; - nel[3] = p4; nel[4] = p5; nel[5] = p6; - nel.SetIndex(el.GetIndex()); - mesh.AddVolumeElement(nel); - } - } - if(moved.Size() == 2) - { - if(fixed.Size() == 1) - { - PointIndex p1 = moved[0]; - PointIndex p2 = moved[1]; - for(auto i : Range(params.heights)) - { - PointIndex p3 = mapto[moved[1]][i]; - PointIndex p4 = mapto[moved[0]][i]; - Element nel(PYRAMID); - nel[0] = p1; - nel[1] = p2; - nel[2] = p3; - nel[3] = p4; - nel[4] = el[0] + el[1] + el[2] + el[3] - fixed[0] - moved[0] - moved[1]; - if(Cross(mesh[p2]-mesh[p1], mesh[p4]-mesh[p1]) * (mesh[nel[4]]-mesh[nel[1]]) > 0) - Swap(nel[1], nel[3]); - nel.SetIndex(el.GetIndex()); - mesh.AddVolumeElement(nel); - p1 = p4; - p2 = p3; - } - } - } - if(moved.Size() == 1 && fixed.Size() == 1) - { - PointIndex p1 = moved[0]; - for(auto i : Range(params.heights)) - { - Element nel = el; - PointIndex p2 = mapto[moved[0]][i]; - for(auto& p : nel.PNums()) - { - if(p == moved[0]) - p = p1; - else if(p == fixed[0]) - p = p2; - } - p1 = p2; - mesh.AddVolumeElement(nel); - } - } - } - else if(el.GetType() == PYRAMID) - { - if(moved.Size() == 2) - { - if(fixed.Size() != 2) - throw Exception("This case is not implemented yet! Fixed size = " + ToString(fixed.Size())); - PointIndex p1 = moved[0]; - PointIndex p2 = moved[1]; - for(auto i : Range(params.heights)) - { - PointIndex p3 = mapto[moved[1]][i]; - PointIndex p4 = mapto[moved[0]][i]; - Element nel(PYRAMID); - nel[0] = p1; - nel[1] = p2; - nel[2] = p3; - nel[3] = p4; - nel[4] = el[0] + el[1] + el[2] + el[3] + el[4] - fixed[0] - fixed[1] - moved[0] - moved[1]; - if(Cross(mesh[p2] - mesh[p1], mesh[p4]-mesh[p1]) * (mesh[nel[4]]-mesh[nel[1]]) > 0) - Swap(nel[1], nel[3]); - nel.SetIndex(el.GetIndex()); - mesh.AddVolumeElement(nel); - p1 = p4; - p2 = p3; - } - } - else if(moved.Size() == 1) - throw Exception("This case is not implemented yet!"); - } - else - throw Exception("Boundarylayer only implemented for tets and pyramids outside yet!"); - } - } - } - - void BoundaryLayerTool :: SetDomInOut() - { - for(auto i : Range(1, nfd_old+1)) - if(moved_surfaces.Test(i)) - { - if(auto dom = mesh.GetFaceDescriptor(si_map[i]).DomainIn(); dom > ndom_old) - mesh.GetFaceDescriptor(i).SetDomainOut(dom); - else - mesh.GetFaceDescriptor(i).SetDomainIn(mesh.GetFaceDescriptor(si_map[i]).DomainOut()); - } - } - - void BoundaryLayerTool :: SetDomInOutSides() - { - BitArray done(mesh.GetNFD()+1); - done.Clear(); - for(auto sei : Range(mesh.SurfaceElements())) - { - auto& sel = mesh[sei]; - auto index = sel.GetIndex(); - if(done.Test(index)) - continue; - done.SetBit(index); - auto& fd = mesh.GetFaceDescriptor(index); - if(fd.DomainIn() != -1) - continue; - int e1, e2; - mesh.GetTopology().GetSurface2VolumeElement(sei+1, e1, e2); - if(e1 == 0) - fd.SetDomainIn(0); - else - fd.SetDomainIn(mesh.VolumeElement(e1).GetIndex()); - if(e2 == 0) - fd.SetDomainOut(0); - else - fd.SetDomainOut(mesh.VolumeElement(e2).GetIndex()); - } - } - - void BoundaryLayerTool :: AddSegments() - { - if(have_single_segments) - MergeAndAddSegments(mesh, new_segments); - else +void BoundaryLayerTool ::AddSegments () +{ + if (insert_only_volume_elements) { - for(auto & seg : new_segments) + if (params.disable_curving) + { + auto is_mapped = [&] (PointIndex pi) { + return pi >= mapto.Range().Next() || mapto[pi].Size() > 0; + }; + for (auto& seg : old_segments) + if (is_mapped(seg[0]) || is_mapped(seg[1])) + { + seg.epgeominfo[0].edgenr = -1; + seg.epgeominfo[1].edgenr = -1; + } + } + } + + auto& new_segs = + insert_only_volume_elements ? new_segments_on_moved_bnd : new_segments; + + if (params.disable_curving) + { + auto is_mapped = [&] (PointIndex pi) { + return pi >= mapto.Range().Next() || mapto[pi].Size() > 0; + }; + for (auto& seg : segments) + if (is_mapped(seg[0]) || is_mapped(seg[1])) + { + seg.epgeominfo[0].edgenr = -1; + seg.epgeominfo[1].edgenr = -1; + } + + for (auto& seg : segments) + if (is_edge_moved[seg.edgenr]) + { + seg.epgeominfo[0].edgenr = -1; + seg.epgeominfo[1].edgenr = -1; + } + + for (auto& seg : new_segs) + { + seg.epgeominfo[0].edgenr = -1; + seg.epgeominfo[1].edgenr = -1; + } + } + + if (have_single_segments) + MergeAndAddSegments(mesh, segments, new_segs); + else + { + mesh.LineSegments() = segments; + for (auto& seg : new_segs) mesh.AddSegment(seg); } - } - void BoundaryLayerTool :: FixVolumeElements() - { - static Timer timer("BoundaryLayerTool::FixVolumeElements"); RegionTimer rt(timer); - BitArray is_inner_point(mesh.GetNP()+1); - is_inner_point.Clear(); + for (auto& seg : free_segments) + mesh.AddSegment(seg); +} - auto changed_domains = domains; - if(!params.outside) - changed_domains.Invert(); +void BoundaryLayerTool ::AddSurfaceElements () +{ + for (auto& sel : + insert_only_volume_elements ? new_sels_on_moved_bnd : new_sels) + mesh.AddSurfaceElement(sel); +} - for(ElementIndex ei : Range(ne)) - if(changed_domains.Test(mesh[ei].GetIndex())) - for(auto pi : mesh[ei].PNums()) - if(mesh[pi].Type() == INNERPOINT) - is_inner_point.SetBit(pi); +void BoundaryLayerTool ::ProcessParameters () +{ + if (int* bc = get_if(¶ms.boundary); bc) + { + for (int i = 1; i <= mesh.GetNFD(); i++) + if (mesh.GetFaceDescriptor(i).BCProperty() == *bc) + par_surfid.Append(i); + } + else if (string* s = get_if(¶ms.boundary); s) + { + regex pattern(*s); + BitArray boundaries(mesh.GetNFD() + 1); + boundaries.Clear(); + for (int i = 1; i <= mesh.GetNFD(); i++) + { + auto& fd = mesh.GetFaceDescriptor(i); + if (regex_match(fd.GetBCName(), pattern)) + { + boundaries.SetBit(i); + auto dom_pattern = get_if(¶ms.domain); + // only add if adjacent to domain + if (dom_pattern) + { + regex pattern(*dom_pattern); + bool mat1_match = + fd.DomainIn() > 0 && regex_match(mesh.GetMaterial(fd.DomainIn()), pattern); + bool mat2_match = + fd.DomainOut() > 0 && regex_match(mesh.GetMaterial(fd.DomainOut()), pattern); + // if boundary is inner or outer remove from list + if (mat1_match == mat2_match) + boundaries.Clear(i); + // if((fd.DomainIn() > 0 && + // regex_match(mesh.GetMaterial(fd.DomainIn()), pattern)) || + // (fd.DomainOut() > 0 && + // regex_match(self.GetMaterial(fd.DomainOut()), pattern))) + // boundaries.Clear(i); + // par_surfid.Append(i); + } + // else + // par_surfid.Append(i); + } + } + for (int i = 1; i <= mesh.GetNFD(); i++) + if (boundaries.Test(i)) + par_surfid.Append(i); + } + else + { + auto& surfids = *get_if>(¶ms.boundary); + for (auto id : surfids) + par_surfid.Append(id); + } - Array points; - for(auto pi : mesh.Points().Range()) - if(is_inner_point.Test(pi)) - points.Append(pi); + insert_only_volume_elements = !params.new_material.has_value(); + if (params.new_material) + { + if (string* mat = get_if(&*params.new_material); mat) + par_new_mat = {{".*", *mat}}; + else + { + par_new_mat = *get_if>(&*params.new_material); + have_material_map = true; + } + } - auto p2el = mesh.CreatePoint2ElementTable(is_inner_point); + if (params.project_boundaries.has_value()) + { + auto proj_bnd = *params.project_boundaries; + if (string* s = get_if(&proj_bnd); s) + { + regex pattern(*s); + for (int i = 1; i <= mesh.GetNFD(); i++) + if (regex_match(mesh.GetFaceDescriptor(i).GetBCName(), pattern)) + par_project_boundaries.Append(i); + } + else + { + for (auto id : *get_if>(&proj_bnd)) + par_project_boundaries.Append(id); + } + } - // smooth growth vectors to shift additional element layers to the inside and fix flipped tets - for(auto step : Range(10)) - { - for(auto pi : points) - { - Vec<3> average_gw = 0.0; - auto & els = p2el[pi]; - size_t cnt = 0; - for(auto ei : els) - if(ei(¶ms.thickness); height) + { + par_heights.Append(*height); + } + else + { + auto& heights = *get_if>(¶ms.thickness); + for (auto val : heights) + par_heights.Append(val); + } - void BoundaryLayerTool :: Perform() - { - CreateNewFaceDescriptors(); - CalculateGrowthVectors(); - CreateFaceDescriptorsSides(); - auto segmap = BuildSegMap(); + int nr_domains = mesh.GetNDomains(); + domains.SetSize(nr_domains + 1); // one based + domains.Clear(); + if (string* pdomain = get_if(¶ms.domain); pdomain) + { + regex pattern(*pdomain); + for (auto i : Range(1, nr_domains + 1)) + if (regex_match(mesh.GetMaterial(i), pattern)) + domains.SetBit(i); + } + else if (int* idomain = get_if(¶ms.domain); idomain) + { + domains.SetBit(*idomain); + } + else + { + for (auto i : *get_if>(¶ms.domain)) + domains.SetBit(i); + } + if (domains.NumSet() == 0) + return; + total_height = 0.0; + for (auto h : par_heights) + total_height += h; - auto in_surface_direction = ProjectGrowthVectorsOnSurface(); - InterpolateGrowthVectors(); + max_edge_nr = -1; + for (const auto& seg : mesh.LineSegments()) + if (seg.edgenr > max_edge_nr) + max_edge_nr = seg.edgenr; - if(params.limit_growth_vectors) - LimitGrowthVectorLengths(); - FixVolumeElements(); - InsertNewElements(segmap, in_surface_direction); - SetDomInOut(); - AddSegments(); - mesh.GetTopology().ClearEdges(); - mesh.SetNextMajorTimeStamp(); - mesh.UpdateTopology(); - SetDomInOutSides(); - MeshingParameters mp; - mp.optimize3d ="m"; - mp.optsteps3d = 4; - OptimizeVolume(mp, mesh); - } + int ndom = mesh.GetNDomains(); + ndom_old = ndom; - void GenerateBoundaryLayer(Mesh& mesh, const BoundaryLayerParameters& blp) - { - static Timer timer("Create Boundarylayers"); - RegionTimer regt(timer); + new_mat_nrs.SetSize(mesh.FaceDescriptors().Size() + 1); + new_mat_nrs = -1; + if (insert_only_volume_elements) + { + for (auto i : Range(1, mesh.GetNFD() + 1)) + { + auto& fd = mesh.GetFaceDescriptor(i); + auto domin = fd.DomainIn(); + auto domout = fd.DomainOut(); + for (int dom : {domin, domout}) + if (domains.Test(dom)) + { + if (params.outside) + { + dom = domin + domout - dom; + if (dom == 0) + throw NG_EXCEPTION("No new material specified for boundarylayer " + "on the outside of domain"); + } + new_mat_nrs[i] = dom; + } + } + } + else + { + for (auto [bcname, matname] : par_new_mat) + { + mesh.SetMaterial(++ndom, matname); + regex pattern(bcname); + for (auto i : Range(1, mesh.GetNFD() + 1)) + { + auto& fd = mesh.GetFaceDescriptor(i); + if (regex_match(fd.GetBCName(), pattern)) + new_mat_nrs[i] = ndom; + } + } + } - BoundaryLayerTool tool(mesh, blp); - tool.Perform(); - } + if (!params.outside) + domains.Invert(); +} + +void BoundaryLayerTool ::Perform () +{ + if (domains.NumSet() == 0) + return; + CreateNewFaceDescriptors(); + CalculateGrowthVectors(); + CreateFaceDescriptorsSides(); + auto segmap = BuildSegMap(); + + auto in_surface_direction = ProjectGrowthVectorsOnSurface(); + + InsertNewElements(segmap, in_surface_direction); + + SetDomInOut(); + AddSegments(); + + mesh.CalcSurfacesOfNode(); + topo.SetBuildVertex2Element(true); + mesh.UpdateTopology(); + + InterpolateGrowthVectors(); + InterpolateSurfaceGrowthVectors(); + + AddSurfaceElements(); + + if (params.limit_growth_vectors) + LimitGrowthVectorLengths(); + + FixSurfaceElements(); + + for (auto [pi, data] : growth_vector_map) + { + auto [gw, height] = data; + mesh[pi] += height * (*gw); + } + + auto& identifications = mesh.GetIdentifications(); + NgArray pairs; + for (auto nr : Range(0, identifications.GetMaxNr() + 1)) + { + identifications.GetPairs(nr, pairs); + for (auto pair : pairs) + { + auto p0 = pair[0]; + auto p1 = pair[1]; + if (max(p0, p1) < first_new_pi && mapto[p0].Size() && mapto[p1].Size()) + for (auto i : Range(mapto[p0].Size())) + identifications.Add(mapto[p0][i], mapto[p1][i], nr); + } + } + + // there is still a bug with segment edge numbers in moved boundaries. + // As a workaround, don't add them at all if only volume elements are inserted + if (insert_only_volume_elements) + mesh.LineSegments() = old_segments; + + mesh.CalcSurfacesOfNode(); + mesh.GetTopology().ClearEdges(); + mesh.SetNextMajorTimeStamp(); + mesh.UpdateTopology(); + SetDomInOutSides(); + + if (have_material_map) + { + AddFacesBetweenDomains(mesh); + mesh.SplitFacesByAdjacentDomains(); + } +} + +void GenerateBoundaryLayer (Mesh& mesh, const BoundaryLayerParameters& blp) +{ + static Timer timer("Create Boundarylayers"); + RegionTimer regt(timer); + + BoundaryLayerTool tool(mesh, blp); + tool.Perform(); +} } // namespace netgen diff --git a/libsrc/meshing/boundarylayer.hpp b/libsrc/meshing/boundarylayer.hpp index 3b83dc05..0d8e20f5 100644 --- a/libsrc/meshing/boundarylayer.hpp +++ b/libsrc/meshing/boundarylayer.hpp @@ -1,91 +1,113 @@ -#ifndef FILE_BOUNDARYLAYER -#define FILE_BOUNDARYLAYER +#ifndef NETGEN_BOUNDARYLAYER_HPP +#define NETGEN_BOUNDARYLAYER_HPP +#include +#include +#include + +namespace netgen +{ /// -DLL_HEADER extern void InsertVirtualBoundaryLayer (Mesh & mesh); +DLL_HEADER extern void InsertVirtualBoundaryLayer (Mesh& mesh); -/// Create a typical prismatic boundary layer on the given +/// Create a typical prismatic boundary layer on the given /// surfaces -class BoundaryLayerParameters +struct SpecialBoundaryPoint { -public: - // parameters by Philippose .. - Array surfid; - Array heights; - map new_mat; - BitArray domains; - bool outside = false; // set the boundary layer on the outside - bool grow_edges = false; - bool limit_growth_vectors = true; - bool sides_keep_surfaceindex = false; - Array project_boundaries; + struct GrowthGroup + { + Array faces; + Vec<3> growth_vector; + Array new_points; + + GrowthGroup (FlatArray faces_, FlatArray> normals); + GrowthGroup (const GrowthGroup&) = default; + GrowthGroup () = default; + }; + Array growth_groups; + Vec<3> separating_direction; + + SpecialBoundaryPoint (const std::map>& normals); + SpecialBoundaryPoint () = default; }; -DLL_HEADER void GenerateBoundaryLayer (Mesh & mesh, - const BoundaryLayerParameters & blp); +DLL_HEADER void GenerateBoundaryLayer (Mesh& mesh, + const BoundaryLayerParameters& blp); -DLL_HEADER int /* new_domain_number */ GenerateBoundaryLayer2 (Mesh & mesh, int domain, const Array & thicknesses, bool should_make_new_domain=true, const Array & boundaries=Array{}); +DLL_HEADER int /* new_domain_number */ GenerateBoundaryLayer2 (Mesh& mesh, int domain, const Array& thicknesses, bool should_make_new_domain = true, const Array& boundaries = Array{}); class BoundaryLayerTool { - public: - BoundaryLayerTool(Mesh & mesh_, const BoundaryLayerParameters & params_); - void Perform(); +public: + BoundaryLayerTool (Mesh& mesh_, const BoundaryLayerParameters& params_); + void ProcessParameters (); + void Perform (); - protected: - Mesh & mesh; - MeshTopology & topo; - BoundaryLayerParameters params; - Array, PointIndex> growthvectors; - Table p2sel; + Mesh& mesh; + MeshTopology& topo; + BoundaryLayerParameters params; + Array, PointIndex> growthvectors; + std::map> non_bl_growth_vectors; + Table p2sel; - BitArray domains, is_edge_moved, is_boundary_projected, is_boundary_moved; - Array moved_segs; - int max_edge_nr, nfd_old, ndom_old; - Array new_mat_nrs; - BitArray moved_surfaces; - int np, nseg, nse, ne; - double height; + BitArray domains, is_edge_moved, is_boundary_projected, is_boundary_moved; + Array moved_segs; + int max_edge_nr, nfd_old, ndom_old; + Array new_mat_nrs; + BitArray moved_surfaces; + int np, nseg, nse, ne; + PointIndex first_new_pi; + double total_height; + Array point_types; - bool have_single_segments; - Array segments, new_segments; + // These parameters are derived from given BoundaryLayerParameters and the Mesh + Array par_heights; + Array par_surfid; + bool insert_only_volume_elements; + map par_new_mat; + bool have_material_map = false; + Array par_project_boundaries; - Array surfacefacs; - Array si_map; - Array limits; + bool have_single_segments; + Array old_segments, free_segments, segments, new_segments, new_segments_on_moved_bnd; + Array new_sels, new_sels_on_moved_bnd; + Array, PointIndex> mapto; + Array mapfrom; - // major steps called in Perform() - void CreateNewFaceDescriptors(); - void CreateFaceDescriptorsSides(); - void CalculateGrowthVectors(); - Array>, SegmentIndex> BuildSegMap(); + Array surfacefacs; + Array si_map; - BitArray ProjectGrowthVectorsOnSurface(); - void InterpolateSurfaceGrowthVectors(); - void InterpolateGrowthVectors(); - void LimitGrowthVectorLengths(); + std::map special_boundary_points; + std::map*, double>> growth_vector_map; - void InsertNewElements(FlatArray>, SegmentIndex> segmap, const BitArray & in_surface_direction); - void SetDomInOut(); - void SetDomInOutSides(); - void AddSegments(); - void FixVolumeElements(); + // major steps called in Perform() + void CreateNewFaceDescriptors (); + void CreateFaceDescriptorsSides (); + void CalculateGrowthVectors (); + Array>, SegmentIndex> BuildSegMap (); - // utility functions - array, 2> GetMappedSeg( PointIndex pi ); - ArrayMem, 4> GetFace( SurfaceElementIndex sei ); - ArrayMem, 4> GetMappedFace( SurfaceElementIndex sei ); - ArrayMem, 4> GetMappedFace( SurfaceElementIndex sei, int face ); + BitArray ProjectGrowthVectorsOnSurface (); + void InterpolateSurfaceGrowthVectors (); + void InterpolateGrowthVectors (); + void LimitGrowthVectorLengths (); + void FixSurfaceElements (); - Vec<3> getNormal(const Element2d & el) - { - auto v0 = mesh[el[0]]; - return Cross(mesh[el[1]]-v0, mesh[el[2]]-v0).Normalize(); - } + void InsertNewElements (FlatArray>, SegmentIndex> segmap, const BitArray& in_surface_direction); + void SetDomInOut (); + void SetDomInOutSides (); + void AddSegments (); + void AddSurfaceElements (); - Vec<3> getEdgeTangent(PointIndex pi, int edgenr); + Vec<3> getNormal (const Element2d& el) + { + auto v0 = mesh[el[0]]; + return Cross(mesh[el[1]] - v0, mesh[el[2]] - v0).Normalize(); + } + + Vec<3> getEdgeTangent (PointIndex pi, int edgenr, FlatArray segs); }; -#endif +} // namespace netgen +#endif // NETGEN_BOUNDARYLAYER_HPP diff --git a/libsrc/meshing/boundarylayer2d.cpp b/libsrc/meshing/boundarylayer2d.cpp index 36f35513..bb5ab6e6 100644 --- a/libsrc/meshing/boundarylayer2d.cpp +++ b/libsrc/meshing/boundarylayer2d.cpp @@ -1,5 +1,5 @@ #include -#include "meshing.hpp" +#include "boundarylayer.hpp" #include "meshing2.hpp" #include "../geom2d/csg2d.hpp" @@ -165,11 +165,12 @@ namespace netgen } auto oldnf = mesh.GetNSE(); - auto res = meshing.GenerateMesh (mesh, mp, mp.maxh, domain); + // auto res = + meshing.GenerateMesh (mesh, mp, mp.maxh, domain); for (SurfaceElementIndex sei : Range(oldnf, mesh.GetNSE())) mesh[sei].SetIndex (domain); - - int hsteps = mp.optsteps2d; + + // int hsteps = mp.optsteps2d; const char * optstr = mp.optimize2d.c_str(); MeshOptimize2d meshopt(mesh); @@ -219,7 +220,7 @@ namespace netgen int np = mesh.GetNP(); int nseg = line_segments.Size(); - int ne = mesh.GetNSE(); + // int ne = mesh.GetNSE(); mesh.UpdateTopology(); double total_thickness = 0.0; @@ -242,19 +243,15 @@ namespace netgen Array segments; - // surface index map - Array si_map(mesh.GetNFD()+2); - si_map = -1; - - int fd_old = mesh.GetNFD(); + // int fd_old = mesh.GetNFD(); int max_edge_nr = -1; int max_domain = -1; for(const auto& seg : line_segments) { - if(seg.epgeominfo[0].edgenr > max_edge_nr) - max_edge_nr = seg.epgeominfo[0].edgenr; + if(seg.edgenr > max_edge_nr) + max_edge_nr = seg.edgenr; if(seg.domin > max_domain) max_domain = seg.domin; if(seg.domout > max_domain) @@ -262,6 +259,7 @@ namespace netgen } int new_domain = max_domain+1; + int new_edge_nr = max_edge_nr+1; BitArray active_boundaries(max_edge_nr+1); BitArray active_segments(nseg); @@ -282,11 +280,15 @@ namespace netgen } { - FaceDescriptor new_fd(0, 0, 0, -1); + FaceDescriptor new_fd(0, 0, 0, -1); new_fd.SetBCProperty(new_domain); - int new_fd_index = mesh.AddFaceDescriptor(new_fd); + // int new_fd_index = + mesh.AddFaceDescriptor(new_fd); if(should_make_new_domain) - mesh.SetBCName(new_domain-1, "mapped_" + mesh.GetBCName(domain-1)); + { + mesh.SetMaterial(new_domain, "layer_" + mesh.GetMaterial(domain)); + mesh.SetBCName(new_edge_nr - 1, "moved"); + } } for(auto segi : Range(line_segments)) @@ -327,7 +329,7 @@ namespace netgen auto current_si = si; auto first = current_seg[0]; - auto current = -1; + PointIndex current(PointIndex::INVALID); auto next = current_seg[1]; if(points_done.Test(first)) @@ -352,7 +354,7 @@ namespace netgen current_si = sj; current_seg = mesh[sj]; - next = current_seg[0] + current_seg[1] - current; + next = current_seg[0]-current + current_seg[1]; break; } } @@ -488,10 +490,10 @@ namespace netgen for ( auto pi : {seg0[0], seg0[1]} ) { - if(growthvectors[pi] == 0.0) + if(growthvectors[pi].Length2() == 0.0) continue; - PointIndex pi1 = seg0[0] + seg0[1] - pi; + PointIndex pi1 = seg0[0] - pi + seg0[1]; auto p1 = mesh[pi1]; auto p = mesh[pi]; @@ -523,7 +525,7 @@ namespace netgen { double safety = 1.3; double t = safety*total_thickness; - if(growthvectors[pi] == 0.0) + if(growthvectors[pi].Length2() == 0.0) continue; Point<3> points[] = { p10, p10+t*growthvectors[seg1[0]], p11, p11+t*growthvectors[seg1[1]] }; @@ -534,16 +536,21 @@ namespace netgen double alpha, beta; - if(X_INTERSECTION == intersect( P2(p0), P2(p1), P2(points[0]), P2(points[2]), alpha, beta )) + auto checkIntersection = [] (Point<2> p0, Point<2> p1, Point<2> q0, Point<2> q1, double & alpha, double & beta) { + auto intersection_type = intersect( p0, p1, q0, q1, alpha, beta ); + return intersection_type == X_INTERSECTION || intersection_type == T_INTERSECTION_P || intersection_type == T_INTERSECTION_Q; + }; + + if(checkIntersection( P2(p0), P2(p1), P2(points[0]), P2(points[2]), alpha, beta )) intersections.Append({alpha, 0.0}); - if(X_INTERSECTION == intersect( P2(p0), P2(p1), P2(points[1]), P2(points[3]), alpha, beta )) + if(checkIntersection( P2(p0), P2(p1), P2(points[1]), P2(points[3]), alpha, beta )) intersections.Append({alpha, 1.0}); - if(X_INTERSECTION == intersect( P2(p0), P2(p1), P2(points[0]), P2(points[1]), alpha, beta )) + if(checkIntersection( P2(p0), P2(p1), P2(points[0]), P2(points[1]), alpha, beta )) intersections.Append({alpha, beta}); - if(X_INTERSECTION == intersect( P2(p0), P2(p1), P2(points[2]), P2(points[3]), alpha, beta )) + if(checkIntersection( P2(p0), P2(p1), P2(points[2]), P2(points[3]), alpha, beta )) intersections.Append({alpha, beta}); QuickSort(intersections); @@ -577,13 +584,15 @@ namespace netgen auto p2 = [](Point<3> p) { return Point<2>{p[0], p[1]}; }; auto seg = line_segments[segi]; - double alpha,beta; - intersect( p2(mesh[seg[0]]), p2(mesh[seg[0]]+total_thickness*growthvectors[seg[0]]), p2(mesh[seg[1]]), p2(mesh[seg[1]]+total_thickness*growthvectors[seg[1]]), alpha, beta ); - - if(beta>0 && alpha>0 && alpha<1.1) - growth[seg[0]] = min(growth[seg[0]], 0.8*alpha); - if(alpha>0 && beta>0 && beta<1.1) - growth[seg[1]] = min(growth[seg[1]], 0.8*beta); + double alpha=0.0; + double beta=0.0; + if (intersect(p2(mesh[seg[0]]), p2(mesh[seg[0]] + total_thickness * growthvectors[seg[0]]), p2(mesh[seg[1]]), p2(mesh[seg[1]] + total_thickness * growthvectors[seg[1]]), alpha, beta)) + { + if (beta > 0 && alpha > 0 && alpha < 1.1) + growth[seg[0]] = min(growth[seg[0]], 0.8 * alpha); + if (alpha > 0 && beta > 0 && beta < 1.1) + growth[seg[1]] = min(growth[seg[1]], 0.8 * beta); + } for (auto segj : Range(mesh.LineSegments())) if(segi!=segj) @@ -609,8 +618,6 @@ namespace netgen } } - map, int> seg2edge; - // insert new elements ( and move old ones ) for(auto si : moved_segs) { @@ -620,8 +627,6 @@ namespace netgen auto & pm0 = mapto[seg[0]]; auto & pm1 = mapto[seg[1]]; - auto newindex = si_map[domain]; - Segment s = seg; s.geominfo[0] = {}; s.geominfo[1] = {}; @@ -629,10 +634,10 @@ namespace netgen s[1] = pm1.Last(); s[2] = PointIndex::INVALID; auto pair = s[0] < s[1] ? make_pair(s[0], s[1]) : make_pair(s[1], s[0]); - if(seg2edge.find(pair) == seg2edge.end()) - seg2edge[pair] = ++max_edge_nr; - s.edgenr = seg2edge[pair]; - s.si = seg.si; + s.edgenr = new_edge_nr; + s.epgeominfo[0].edgenr = -1; + s.epgeominfo[1].edgenr = -1; + s.si = s.edgenr; mesh.AddSegment(s); for ( auto i : Range(thicknesses)) @@ -658,7 +663,7 @@ namespace netgen auto p0 = mesh[pi0]; auto p1 = mesh[pi1]; auto q0 = mesh[pi2]; - auto q1 = mesh[pi3]; + // auto q1 = mesh[pi3]; Vec<2> n = {-p1[1]+p0[1], p1[0]-p0[0]}; Vec<2> v = { q0[0]-p0[0], q0[1]-p0[1]}; diff --git a/libsrc/meshing/boundarylayer_interpolate.cpp b/libsrc/meshing/boundarylayer_interpolate.cpp new file mode 100644 index 00000000..f4e742e2 --- /dev/null +++ b/libsrc/meshing/boundarylayer_interpolate.cpp @@ -0,0 +1,497 @@ +#include "boundarylayer.hpp" + +namespace netgen +{ + +namespace detail +{ +struct Neighbor +{ + PointIndex pi; + SurfaceElementIndex sei; + double weight; +}; +} // namespace detail + +Array> +BuildNeighbors (FlatArray points, const Mesh& mesh) +{ + auto p2sel = mesh.CreatePoint2SurfaceElementTable(); + + Array> neighbors(points.Size()); + + ArrayMem angles; + ArrayMem inv_dists; + for (auto i : points.Range()) + { + auto& p_neighbors = neighbors[i]; + auto pi = points[i]; + angles.SetSize(0); + inv_dists.SetSize(0); + for (auto sei : p2sel[pi]) + { + const auto& sel = mesh[sei]; + for (auto pi1 : sel.PNums()) + { + if (pi1 == pi) + continue; + auto pi2 = pi1; + for (auto pi_ : sel.PNums()) + { + if (pi_ != pi && pi_ != pi1) + { + pi2 = pi_; + break; + } + } + p_neighbors.Append({pi1, sei, 0.0}); + inv_dists.Append(1.0 / (mesh[pi1] - mesh[pi]).Length()); + auto dot = (mesh[pi1] - mesh[pi]).Normalize() * (mesh[pi2] - mesh[pi]).Normalize(); + angles.Append(acos(dot)); + } + } + double sum_inv_dist = 0.0; + for (auto inv_dist : inv_dists) + sum_inv_dist += inv_dist; + double sum_angle = 0.0; + for (auto angle : angles) + sum_angle += angle; + + double sum_weight = 0.0; + for (auto i : Range(inv_dists)) + { + p_neighbors[i].weight = + inv_dists[i] * angles[i] / sum_inv_dist / sum_angle; + sum_weight += p_neighbors[i].weight; + } + for (auto i : Range(inv_dists)) + p_neighbors[i].weight /= sum_weight; + } + return neighbors; +} + +void BoundaryLayerTool ::InterpolateGrowthVectors () +{ + point_types.SetSize(mesh.GetNP()); + for (auto p : mesh.Points().Range()) + point_types[p] = mesh[p].Type(); + + int new_max_edge_nr = max_edge_nr; + for (const auto& seg : segments) + if (seg.edgenr > new_max_edge_nr) + new_max_edge_nr = seg.edgenr; + for (const auto& seg : new_segments) + if (seg.edgenr > new_max_edge_nr) + new_max_edge_nr = seg.edgenr; + + auto getGW = [&] (PointIndex pi) -> Vec<3> { + if (growth_vector_map.count(pi) == 0) + growth_vector_map[pi] = {&growthvectors[pi], total_height}; + auto [gw, height] = growth_vector_map[pi]; + return height * (*gw); + }; + auto addGW = [&] (PointIndex pi, Vec<3> vec) { + if (growth_vector_map.count(pi) == 0) + growth_vector_map[pi] = {&growthvectors[pi], total_height}; + auto [gw, height] = growth_vector_map[pi]; + *gw += 1.0 / height * vec; + }; + + // interpolate tangential component of growth vector along edge + if (max_edge_nr >= new_max_edge_nr) + return; + + auto edgenr2seg = ngcore::CreateSortedTable( + Range(segments.Size() + new_segments.Size()), + [&] (auto& table, size_t segi) { + auto& seg = segi < segments.Size() + ? segments[segi] + : new_segments[segi - segments.Size()]; + table.Add(seg.edgenr, &seg); + }, + new_max_edge_nr + 1); + auto point2seg = ngcore::CreateSortedTable( + Range(segments.Size() + new_segments.Size()), + [&] (auto& table, size_t segi) { + auto& seg = segi < segments.Size() + ? segments[segi] + : new_segments[segi - segments.Size()]; + table.Add(seg[0], &seg); + table.Add(seg[1], &seg); + }, + mesh.GetNP()); + + for (auto edgenr : Range(1, new_max_edge_nr + 1)) + { + // "inner" edges between two flat faces are not treated as edges for interpolation + bool no_angles = true; + ArrayMem faces; + + for (auto* p_seg : edgenr2seg[edgenr]) + { + auto& seg = *p_seg; + faces.SetSize(0); + // if (seg[0] <= p2sel.Size()) + if (seg[0] < IndexBASE() + p2sel.Size()) + { + for (auto sei : p2sel[seg[0]]) + if (moved_surfaces.Test(mesh[sei].GetIndex()) && p2sel[seg[1]].Contains(sei)) + faces.Append(sei); + } + + if (faces.Size() == 2 && mesh[faces[0]].GetIndex() != mesh[faces[1]].GetIndex()) + { + auto n0 = getNormal(mesh[faces[0]]); + auto n1 = getNormal(mesh[faces[1]]); + if (n0 * n1 < 0.99) + no_angles = false; + } + else + { + no_angles = false; + } + } + + if (no_angles && faces.Size() == 2 && have_material_map) + if (par_new_mat[mesh.GetBCName(mesh[faces[0]].GetIndex() - 1)] != par_new_mat[mesh.GetBCName(mesh[faces[1]].GetIndex() - 1)]) + no_angles = false; + + if (no_angles) + { + for (auto* p_seg : edgenr2seg[edgenr]) + for (auto pi : p_seg->PNums()) + { + if (pi >= first_new_pi) + continue; + if (point_types[pi] == EDGEPOINT) + point_types[pi] = SURFACEPOINT; + else if (point_types[pi] == FIXEDPOINT) + { + // Check at edge corners if all adjacent surface elements have roughly the same normal. + // If so, also treat this point as surface point for growth vector interpolation + Vec<3> n = 0.0; + for (auto si : p2sel[pi]) + n += getNormal(mesh[si]); + n.Normalize(); + bool is_corner = false; + for (auto si : p2sel[pi]) + if (getNormal(mesh[si]) * n < 0.99) + is_corner = true; + if (!is_corner) + point_types[pi] = SURFACEPOINT; + } + } + continue; + } + } + + for (auto edgenr : Range(max_edge_nr + 1, new_max_edge_nr + 1)) + { + double edge_len = 0.; + bool any_grows = false; + + auto is_end_point = [&] (PointIndex pi) { + auto segs = point2seg[pi]; + if (segs.Size() == 1) + return true; + auto first_edgenr = (*segs[0]).edgenr; + for (auto* p_seg : segs) + if (p_seg->edgenr != first_edgenr) + return true; + return false; + }; + + Array points; + for (auto* p_seg : edgenr2seg[edgenr]) + { + auto& seg = *p_seg; + + if (getGW(seg[0]).Length2() != 0 || getGW(seg[1]).Length2() != 0) + any_grows = true; + + if (points.Size() == 0) + for (auto i : Range(2)) + if (is_end_point(seg[i])) + { + points.Append(seg[i]); + points.Append(seg[1 - i]); + edge_len += (mesh[seg[1]] - mesh[seg[0]]).Length(); + break; + } + } + + if (!any_grows) + { + PrintMessage(1, "BLayer: skip interpolating growth vectors at edge ", edgenr + 1); + continue; + } + + if (!points.Size()) + { + if (debugparam.debugoutput) + cerr << "Could not find startpoint for edge " << edgenr << endl; + continue; + } + + std::set points_set; + points_set.insert(points[0]); + points_set.insert(points[1]); + + bool point_found = true; + while (point_found) + { + if (is_end_point(points.Last())) + break; + point_found = false; + for (auto* p_seg : point2seg[points.Last()]) + { + const auto& seg = *p_seg; + if (seg.edgenr != edgenr) + continue; + auto plast = points.Last(); + if (plast != seg[0] && plast != seg[1]) + continue; + auto pnew = plast == seg[0] ? seg[1] : seg[0]; + if (pnew == points[0] && points.Size() > 1) + { + } + if (points_set.count(pnew) > 0 && (pnew != points[0] || points.Size() == 2)) + continue; + edge_len += (mesh[points.Last()] - mesh[pnew]).Length(); + points.Append(pnew); + points_set.insert(pnew); + point_found = true; + break; + } + } + if (!point_found) + { + if (debugparam.debugoutput) + { + cerr << "Could not find connected list of line segments for edge " + << edgenr << endl; + cerr << "current points: " << endl + << points << endl; + } + continue; + } + + if (getGW(points[0]).Length2() == 0 && getGW(points.Last()).Length2() == 0) + continue; + + // tangential part of growth vectors + auto t1 = (mesh[points[1]] - mesh[points[0]]).Normalize(); + auto gt1 = getGW(points[0]) * t1 * t1; + auto t2 = + (mesh[points.Last()] - mesh[points[points.Size() - 2]]).Normalize(); + auto gt2 = getGW(points.Last()) * t2 * t2; + + double len = 0.; + for (auto i : IntRange(1, points.Size() - 1)) + { + auto pi = points[i]; + len += (mesh[pi] - mesh[points[i - 1]]).Length(); + auto t = getEdgeTangent(pi, edgenr, point2seg[pi]); + auto lam = len / edge_len; + auto interpol = (1 - lam) * (gt1 * t) * t + lam * (gt2 * t) * t; + addGW(pi, interpol); + } + } +} + +void BoundaryLayerTool ::InterpolateSurfaceGrowthVectors () +{ + static Timer tall("InterpolateSurfaceGrowthVectors"); + RegionTimer rtall(tall); + static Timer tsmooth("InterpolateSurfaceGrowthVectors-Smoothing"); + auto np_old = this->np; + [[maybe_unused]] auto np = mesh.GetNP(); + + auto hasMoved = [&] (PointIndex pi) { + return (pi - IndexBASE() >= np_old) || mapto[pi].Size() > 0 || special_boundary_points.count(pi); + }; + + std::set points_set; + for (const auto& sel : mesh.SurfaceElements()) + { + for (auto pi : sel.PNums()) + if (point_types[pi] == SURFACEPOINT && hasMoved(pi)) + points_set.insert(pi); + } + + Array points; + for (auto pi : points_set) + points.Append(pi); + QuickSort(points); + + // smooth tangential part of growth vectors from edges to surface elements + Array, PointIndex> corrections(mesh.GetNP()); + corrections = 0.0; + RegionTimer rtsmooth(tsmooth); + auto neighbors = BuildNeighbors(points, mesh); + + Array, SurfaceElementIndex> surf_normals(mesh.GetNSE()); + for (auto sei : mesh.SurfaceElements().Range()) + surf_normals[sei] = getNormal(mesh[sei]); + + BitArray interpolate_tangent(mesh.GetNP() + 1); + interpolate_tangent = false; + for (auto pi : points) + { + for (auto sei : p2sel[pi]) + if (is_boundary_moved[mesh[sei].GetIndex()]) + interpolate_tangent.SetBit(pi); + } + + constexpr int N_STEPS = 64; + for ([[maybe_unused]] auto i : Range(N_STEPS)) + { + for (auto i : points.Range()) + { + auto pi = points[i]; + auto& p_neighbors = neighbors[i]; + + ArrayMem, 20> g_vectors; + double max_len = 0.0; + double sum_len = 0.0; + + // average only tangent component on new bl points, average whole growth + // vector otherwise + bool do_average_tangent = true; + for (const auto& s : p_neighbors) + { + auto gw_other = growthvectors[s.pi] + corrections[s.pi]; + if (do_average_tangent) + { + auto n = surf_normals[s.sei]; + gw_other = gw_other - (gw_other * n) * n; + } + auto v = gw_other; + auto len = v.Length2(); + sum_len += len; + max_len = max(max_len, len); + g_vectors.Append(v); + } + + if (max_len == 0.0) + continue; + + double lambda = 0; + if (i > N_STEPS / 4.) + lambda = 2.0 * (i - N_STEPS / 4.) / (N_STEPS / 2.); + lambda = min(1.0, lambda); + + auto& correction = corrections[pi]; + correction = 0.0; + for (const auto i : p_neighbors.Range()) + { + auto v = g_vectors[i]; + double weight = lambda * p_neighbors[i].weight + (1.0 - lambda) * v.Length2() / sum_len; + correction += weight * v; + } + + if (!do_average_tangent) + correction -= growthvectors[pi]; + } + } + + for (auto pi : points) + growthvectors[pi] += corrections[pi]; +} + +void BoundaryLayerTool ::FixSurfaceElements () +{ + static Timer tall("FixSurfaceElements"); + RegionTimer rtall(tall); + [[maybe_unused]] auto np_old = this->np; + [[maybe_unused]] auto np = mesh.GetNP(); + + non_bl_growth_vectors.clear(); + + auto getGW = [&] (PointIndex pi) -> Vec<3> { + // return growthvectors[pi]; + if (growth_vector_map.count(pi) == 0) + { + non_bl_growth_vectors[pi] = .0; + growth_vector_map[pi] = {&non_bl_growth_vectors[pi], 1.0}; + } + auto [gw, height] = growth_vector_map[pi]; + return height * (*gw); + }; + + auto addGW = [&] (PointIndex pi, Vec<3> vec) { + if (growth_vector_map.count(pi) == 0) + { + non_bl_growth_vectors[pi] = .0; + growth_vector_map[pi] = {&non_bl_growth_vectors[pi], 1.0}; + } + auto [gw, height] = growth_vector_map[pi]; + *gw += 1.0 / height * vec; + }; + + std::set points_set; + // only smooth over old surface elements + for (SurfaceElementIndex sei : Range(nse)) + { + const auto& sel = mesh[sei]; + if (sel.GetNP() == 3 && is_boundary_moved[sel.GetIndex()]) + for (auto pi : sel.PNums()) + if (point_types[pi] == SURFACEPOINT) + points_set.insert(pi); + } + + Array points; + for (auto pi : points_set) + points.Append(pi); + QuickSort(points); + + Array, PointIndex> corrections(mesh.GetNP()); + corrections = 0.0; + + auto neighbors = BuildNeighbors(points, mesh); + + constexpr int N_STEPS = 32; + for ([[maybe_unused]] auto i : Range(N_STEPS)) + { + for (auto i : points.Range()) + { + auto pi = points[i]; + auto& p_neighbors = neighbors[i]; + + ArrayMem, 20> g_vectors; + double max_len = 0.0; + double sum_len = 0.0; + + for (const auto& s : p_neighbors) + { + auto v = getGW(s.pi) + corrections[s.pi]; + auto len = v.Length2(); + sum_len += len; + max_len = max(max_len, len); + g_vectors.Append(v); + } + + if (max_len == 0.0) + continue; + + double lambda = 0; + if (i > N_STEPS / 4.) + lambda = 2.0 * (i - N_STEPS / 4.) / (N_STEPS / 2.); + lambda = min(1.0, lambda); + + auto& correction = corrections[pi]; + correction = 0.0; + for (const auto i : p_neighbors.Range()) + { + auto v = g_vectors[i]; + double weight = lambda * p_neighbors[i].weight + (1.0 - lambda) * v.Length2() / sum_len; + correction += weight * v; + } + } + } + + for (auto pi : points) + addGW(pi, corrections[pi]); +} + +} // namespace netgen diff --git a/libsrc/meshing/boundarylayer_limiter.hpp b/libsrc/meshing/boundarylayer_limiter.hpp new file mode 100644 index 00000000..e869c69b --- /dev/null +++ b/libsrc/meshing/boundarylayer_limiter.hpp @@ -0,0 +1,780 @@ +#include "boundarylayer.hpp" +#include + +namespace netgen +{ + +struct Intersection_ +{ + bool is_intersecting = false; + double lam0 = -1, lam1 = -1; + Point<3> p; + double bary[3]; + operator bool() const { return is_intersecting; } +}; + +struct GrowthVectorLimiter +{ + typedef std::array, 2> Seg; + typedef std::array, 3> Trig; + + BoundaryLayerTool& tool; + const BoundaryLayerParameters& params; + Mesh& mesh; + double height; + Array limits; + FlatArray, PointIndex> growthvectors; + BitArray changed_domains; + unique_ptr> tree; + Array map_from; + Table p2sel; + + GrowthVectorLimiter (BoundaryLayerTool& tool_) + : tool(tool_), params(tool_.params), mesh(tool_.mesh), height(tool_.total_height), growthvectors(tool_.growthvectors), map_from(mesh.Points().Size()) + { + changed_domains = tool.domains; + if (!params.outside) + changed_domains.Invert(); + + map_from = tool.mapfrom; + p2sel = ngcore::CreateSortedTable( + tool.new_sels.Range(), + [&] (auto& table, SurfaceElementIndex ei) { + for (PointIndex pi : tool.new_sels[ei].PNums()) + table.Add(pi, ei); + }, + mesh.GetNP()); + } + + auto SurfaceElementsRange () { return Range(tool.nse + tool.new_sels.Size()); } + + void WriteErrorMesh (string name) + { + if (!debugparam.write_mesh_on_error) + return; + Mesh out_mesh; + out_mesh = mesh; + for (auto [pi, data] : tool.growth_vector_map) + { + auto [gw, height] = data; + out_mesh[pi] += limits[pi] * height * (*gw); + } + out_mesh.Save(name); + } + + const auto& Get (SurfaceElementIndex sei) + { + if (sei < tool.nse) + return mesh[sei]; + return tool.new_sels[sei - tool.nse]; + } + + std::pair GetMinMaxLimit (SurfaceElementIndex sei) + { + const auto& sel = Get(sei); + double min_limit = GetLimit(sel[0]); + double max_limit = min_limit; + for (auto i : IntRange(1, sel.GetNP())) + { + auto limit = GetLimit(sel[i]); + min_limit = min(min_limit, limit); + max_limit = max(max_limit, limit); + } + return {min_limit, max_limit}; + } + + double GetLimit (PointIndex pi) + { + if (pi < tool.first_new_pi) + return limits[pi]; + return limits[map_from[pi]]; + } + + bool SetLimit (PointIndex pi, double new_limit) + { + double& limit = (pi < tool.first_new_pi) ? limits[pi] : limits[map_from[pi]]; + if (limit <= new_limit) + return false; + limit = new_limit; + return true; + } + + bool ScaleLimit (PointIndex pi, double factor) + { + double& limit = (pi < tool.first_new_pi) ? limits[pi] : limits[map_from[pi]]; + return SetLimit(pi, limit * factor); + } + + Vec<3> GetVector (PointIndex pi_to, double shift = 1., bool apply_limit = false) + { + auto [gw, height] = tool.growth_vector_map[pi_to]; + if (apply_limit) + shift *= GetLimit(pi_to); + return shift * height * (*gw); + } + + Point<3> GetPoint (PointIndex pi_to, double shift = 1., bool apply_limit = false) + { + if (pi_to < tool.first_new_pi || tool.growth_vector_map.count(pi_to) == 0) + return mesh[pi_to]; + + return mesh[pi_to] + GetVector(pi_to, shift, apply_limit); + } + + Point<3> GetMappedPoint (PointIndex pi_from, double shift = 1., bool apply_limit = false) + { + auto pi_to = tool.mapto[pi_from].Last(); + return GetPoint(pi_to, shift, apply_limit); + } + + Seg GetMappedSeg (PointIndex pi_from, double shift = 1.) + { + return {mesh[pi_from], GetMappedPoint(pi_from, shift)}; + } + + Seg GetSeg (PointIndex pi_to, double shift = 1., bool apply_limit = false) + { + return {GetPoint(pi_to, 0), GetPoint(pi_to, shift, apply_limit)}; + } + + Trig GetTrig (SurfaceElementIndex sei, double shift = 0.0, bool apply_limit = false) + { + auto sel = Get(sei); + Trig trig; + for (auto i : Range(3)) + trig[i] = GetPoint(sel[i], shift, apply_limit); + return trig; + } + + Trig GetMappedTrig (SurfaceElementIndex sei, double shift = 0.0) + { + auto sel = Get(sei); + Trig trig; + for (auto i : Range(3)) + trig[i] = GetMappedPoint(sel[i], shift); + return trig; + } + + Trig GetSideTrig (SurfaceElementIndex sei, int index, double shift = 0.0, bool grow_first_vertex = true) + { + auto trig = GetMappedTrig(sei, 0.0); + auto sel = Get(sei); + auto index1 = (index + 1) % 3; + if (!grow_first_vertex) + index1 = (index + 2) % 3; + trig[index] = GetMappedPoint(sel[index1], shift, true); + return trig; + } + + array GetSideTrigs (SurfaceElementIndex sei, int i0, double shift = 0.0) + { + auto trig = GetMappedTrig(sei, 0.0); + array trigs{trig, trig, trig, trig}; + + auto sel = Get(sei); + auto i1 = (i0 + 1) % 3; + auto i2 = (i0 + 2) % 3; + auto p1 = GetMappedPoint(sel[i1], shift, true); + auto p2 = GetMappedPoint(sel[i2], shift, true); + + // create four trigs to span the quad from i1,i2 and their shifted points + // i1, i2, shifted i1 + trigs[0][i0] = p1; + + // i1, i2, shifted i2 + trigs[1][i0] = p2; + + // i1, shifted i1, shifted i2 + trigs[2][i0] = p1; + trigs[2][i2] = p2; + + // i2, shifted i1, shifted i2 + trigs[2][i0] = p2; + trigs[2][i1] = p1; + + return trigs; + } + + static constexpr double INTERSECTION_SAFETY = .9; + bool LimitGrowthVector (PointIndex pi_to, SurfaceElementIndex sei, double trig_shift, double seg_shift, bool check_prism_sides = false) + { + auto pi_from = map_from[pi_to]; + if (!pi_from.IsValid()) + return false; + + for (auto pi : Get(sei).PNums()) + { + if (pi == pi_from) + return false; + if (map_from[pi] == pi_from) + return false; + } + + if (check_prism_sides || trig_shift > .0) + { + auto [trig_min_limit, trig_max_limit] = GetMinMaxLimit(sei); + if (GetLimit(pi_to) < trig_min_limit) + return false; + + auto getTrigs = [&] (double scaling = 1.0) -> ArrayMem { + ArrayMem trigs; + if (check_prism_sides) + for (auto i : Range(3)) + for (auto trig : GetSideTrigs(sei, i, scaling * trig_shift)) + trigs.Append(trig); + else + trigs.Append(GetTrig(sei, scaling * trig_shift, true)); + return trigs; + }; + + if (!check_prism_sides) + { + // If the growth vectors of all points are pointing in the same direction, + // an intersection means, we also have an intersection with a prism side face + // this is an extra check and handled later + auto seg = GetSeg(pi_to, 1.0, false); + auto gw = seg[1] - seg[0]; + + bool have_same_growth_direction = true; + for (auto pi : Get(sei).PNums()) + { + auto p_seg = GetSeg(pi, 1.0, false); + auto p_gw = p_seg[1] - p_seg[0]; + have_same_growth_direction &= (gw * p_gw) > 0; + } + if (have_same_growth_direction) + return false; + } + + double scaling = 1.0; + while (true) + { + bool have_intersection = false; + auto seg = GetSeg(pi_to, scaling * seg_shift, true); + for (auto trig : getTrigs(scaling)) + have_intersection |= isIntersectingTrig(seg, trig); + if (!have_intersection) + break; + scaling *= 0.9; + } + if (scaling == 1.0) + return false; + + double new_limit = scaling * max(GetLimit(pi_to), trig_max_limit); + SetLimit(pi_to, new_limit); + for (auto pi : Get(sei).PNums()) + SetLimit(pi, new_limit); + return true; + } + else + { + auto seg = GetSeg(pi_to, seg_shift, false); + auto trig = GetTrig(sei, 0.0); + auto intersection = isIntersectingTrig(seg, trig); + // checking with original surface elements -> allow only half the distance + auto new_seg_limit = 0.40 * intersection.lam0 * seg_shift; + if (intersection && new_seg_limit < GetLimit(pi_from)) + return SetLimit(pi_from, new_seg_limit); + return false; + } + } + + void EqualizeLimits (double factor = .5) + { + static Timer t("GrowthVectorLimiter::EqualizeLimits"); + PrintMessage(5, "GrowthVectorLimiter - equalize limits"); + RegionTimer reg(t); + if (factor == 0.0) + return; + // for (PointIndex pi : IntRange(tool.np, mesh.GetNP())) + for (PointIndex pi : mesh.Points().Range().Modify(tool.np, 0)) + { + // auto pi_from = map_from[pi]; + std::set pis; + for (auto sei : p2sel[pi]) + for (auto pi_ : tool.new_sels[sei].PNums()) + pis.insert(pi_); + ArrayMem limits; + for (auto pi1 : pis) + { + auto limit = GetLimit(pi1); + if (limit > 0.0) + limits.Append(GetLimit(pi1)); + } + + if (limits.Size() == 0) + continue; + + double average = 0.0; + for (auto l : limits) + average += l; + average /= limits.Size(); + + SetLimit(pi, factor * average + (1.0 - factor) * GetLimit(pi)); + } + } + + void LimitSelfIntersection (double safety = 1.4) + { + static Timer t("GrowthVectorLimiter::LimitSelfIntersection"); + PrintMessage(5, "GrowthVectorLimiter - self intersection"); + RegionTimer reg(t); + // check for self-intersection within new elements (prisms/hexes) + auto isIntersecting = [&] (SurfaceElementIndex sei, double shift) { + // checks if surface element is self intersecting when growing with factor + // shift + + // ignore new surface elements, side trigs are only built + // from original surface elements + if (sei >= tool.nse) + return false; + const auto sel = Get(sei); + auto np = sel.GetNP(); + for (auto i : Range(np)) + { + if (sel[i] >= tool.first_new_pi) + return false; + if (tool.mapto[sel[i]].Size() == 0) + return false; + } + for (auto i : Range(np)) + { + auto seg = GetMappedSeg(sel[i], shift * limits[sel[i]]); + for (auto fi : Range(np - 2)) + { + for (auto side : {true, false}) + { + auto trig = GetSideTrig(sei, i + fi, 1.0, side); + if (isIntersectingPlane(seg, trig)) + return true; + } + } + } + return false; + }; + + for (SurfaceElementIndex sei : mesh.SurfaceElements().Range()) + { + auto sel = mesh[sei]; + if (sei >= tool.nse) + continue; + if (!tool.moved_surfaces[sel.GetIndex()]) + continue; + if (sel.GetNP() == 4) + continue; + + // const auto& fd = mesh.GetFaceDescriptor(sel.GetIndex()); + auto np = sel.GetNP(); + + double shift = 1.0; + const double step_factor = 0.9; + while (isIntersecting(sei, shift * safety)) + { + shift *= step_factor; + double max_limit = 0; + for (auto i : Range(np)) + max_limit = max(max_limit, limits[sel[i]]); + for (auto i : Range(np)) + if (max_limit == limits[sel[i]]) + ScaleLimit(sel[i], step_factor); + // if (max_limit < 0.01) break; + } + } + } + + // checks if a segment is intersecting a plane, spanned by three points, lam + // will be set s.t. p_intersect = seg[0] + lam * (seg[1]-seg[0]) + Intersection_ isIntersectingPlane (const Seg& seg, + const Trig& trig) + { + auto t1 = trig[1] - trig[0]; + auto t2 = trig[2] - trig[0]; + auto n = Cross(t1, t2); + auto v0n = (seg[0] - trig[0]) * n; + auto v1n = (seg[1] - trig[0]) * n; + + Intersection_ intersection; + intersection.lam0 = -v0n / (v1n - v0n); + intersection.p = seg[0] + intersection.lam0 * (seg[1] - seg[0]); + intersection.is_intersecting = (v0n * v1n < 0) && (intersection.lam0 > -1e-8) && (intersection.lam0 < 1 + 1e-8); + + return intersection; + } + + Intersection_ isIntersectingTrig (const Seg& seg, const Trig& trig) + { + auto intersection = isIntersectingPlane(seg, trig); + if (!intersection) + return intersection; + + auto p = seg[0] + intersection.lam0 * (seg[1] - seg[0]) - trig[0]; + + Vec3d col1 = trig[1] - trig[0]; + Vec3d col2 = trig[2] - trig[0]; + Vec3d col3 = Cross(col1, col2); + Vec3d rhs = p; + Vec3d bary; + SolveLinearSystem(col1, col2, col3, rhs, bary); + + intersection.lam1 = 0; + double eps = 1e-4; + if (bary.X() >= -eps && bary.Y() >= -eps && bary.X() + bary.Y() <= 1 + eps) + { + intersection.bary[0] = bary.X(); + intersection.bary[1] = bary.Y(); + intersection.bary[2] = 1.0 - bary.X() - bary.Y(); + } + else + intersection.is_intersecting = false; + return intersection; + } + + Intersection_ isIntersectingTrig (PointIndex pi_from, PointIndex pi_to, SurfaceElementIndex sei, double shift = 0.0) + { + // JS: where is that GetSeg function ? + return isIntersectingTrig(GetSeg(pi_from, pi_to), GetTrig(sei, shift)); + } + + void BuildSearchTree (double trig_shift) + { + static Timer t("BuildSearchTree"); + RegionTimer rt(t); + Box<3> bbox(Box<3>::EMPTY_BOX); + for (PointIndex pi : mesh.Points().Range()) + { + bbox.Add(mesh[pi]); + bbox.Add(GetPoint(pi, 1.1)); + } + + tree = make_unique>(bbox); + + for (auto sei : SurfaceElementsRange()) + { + const auto& sel = Get(sei); + // auto sel_index = sel.GetIndex(); + + Box<3> box(Box<3>::EMPTY_BOX); + for (auto pi : sel.PNums()) + { + box.Add(GetPoint(pi, 0.)); + box.Add(GetPoint(pi, trig_shift * GetLimit(pi))); + } + tree->Insert(box, sei); + } + } + + template + void FindTreeIntersections (double trig_shift, double seg_shift, TFunc f, TBitArray* relevant_points = nullptr) + { + static Timer t("GrowthVectorLimiter::FindTreeIntersections"); + RegionTimer rt(t); + BuildSearchTree(trig_shift); + auto np_new = mesh.Points().Size(); + // int counter = 0; + for (auto i : IntRange(tool.np, np_new)) + { + PointIndex pi_to = i + IndexBASE(); + PointIndex pi_from = map_from[pi_to]; + if (!pi_from.IsValid()) + throw Exception("Point not mapped"); + + if (relevant_points && !relevant_points->Test(pi_to) && !relevant_points->Test(pi_from)) + continue; + + Box<3> box(Box<3>::EMPTY_BOX); + // auto seg = GetSeg(pi_to, seg_shift); + + box.Add(GetPoint(pi_to, 0)); + box.Add(GetPoint(pi_to, GetLimit(pi_from))); + tree->GetFirstIntersecting(box.PMin(), box.PMax(), [&] (SurfaceElementIndex sei) { + const auto& sel = Get(sei); + if (sel.PNums().Contains(pi_from)) + return false; + if (sel.PNums().Contains(pi_to)) + return false; + // counter++; + f(pi_to, sei); + return false; + }); + } + } + + void FixIntersectingSurfaceTrigs () + { + static Timer t("GrowthVectorLimiter::FixIntersectingSurfaceTrigs"); + RegionTimer reg(t); + // check if surface trigs are intersecting each other + bool changed = true; + std::set special_points; + + if (tool.insert_only_volume_elements) + for (auto [pi, special_point] : tool.special_boundary_points) + { + special_points.insert(pi); + for (auto& group : special_point.growth_groups) + special_points.insert(group.new_points.Last()); + } + + auto skip_trig = [&] (const Element2d& tri) { + if (!tool.insert_only_volume_elements) + return false; + for (auto pi : tri.PNums()) + if (special_points.find(pi) != special_points.end()) + return true; + return false; + }; + + while (changed) + { + changed = false; + Point3d pmin, pmax; + mesh.GetBox(pmin, pmax); + BoxTree<3, SurfaceElementIndex> setree(pmin, pmax); + + for (auto sei : SurfaceElementsRange()) + { + const Element2d& tri = Get(sei); + + if (skip_trig(tri)) + continue; + + Box<3> box(Box<3>::EMPTY_BOX); + for (PointIndex pi : tri.PNums()) + box.Add(GetPoint(pi, 1.0, true)); + + box.Increase(1e-3 * box.Diam()); + setree.Insert(box, sei); + } + + for (auto sei : SurfaceElementsRange()) + { + const Element2d& tri = Get(sei); + + if (skip_trig(tri)) + continue; + + Box<3> box(Box<3>::EMPTY_BOX); + for (PointIndex pi : tri.PNums()) + box.Add(GetPoint(pi, 1.0, true)); + + setree.GetFirstIntersecting(box.PMin(), box.PMax(), [&] (size_t sej) { + const Element2d& tri2 = Get(sej); + + if (mesh[tri[0]].GetLayer() != mesh[tri2[0]].GetLayer()) + return false; + + netgen::Point<3> tri1_points[3], tri2_points[3]; + const netgen::Point<3>*trip1[3], *trip2[3]; + for (int k = 0; k < 3; k++) + { + trip1[k] = &tri1_points[k]; + trip2[k] = &tri2_points[k]; + } + auto set_points = [&] () { + for (int k = 0; k < 3; k++) + { + tri1_points[k] = GetPoint(tri[k], 1.0, true); + tri2_points[k] = GetPoint(tri2[k], 1.0, true); + } + }; + + set_points(); + + int counter = 0; + while (IntersectTriangleTriangle(&trip1[0], &trip2[0])) + { + changed = true; + PointIndex pi_max_limit = PointIndex::INVALID; + for (PointIndex pi : + {tri[0], tri[1], tri[2], tri2[0], tri2[1], tri2[2]}) + if (pi >= tool.first_new_pi && (!pi_max_limit.IsValid() || GetLimit(pi) > GetLimit(pi_max_limit))) + pi_max_limit = map_from[pi]; + + if (!pi_max_limit.IsValid()) + break; + + ScaleLimit(pi_max_limit, 0.9); + set_points(); + counter++; + if (GetLimit(pi_max_limit) < 1e-10) + { + WriteErrorMesh("error_blayer_self_intersection_pi" + ToString(pi_max_limit) + ".vol.gz"); + throw NgException("Stop meshing in boundary layer thickness limitation: overlapping regions detected at elements " + ToString(tri) + " and " + ToString(tri2)); + } + if (debugparam.debugoutput && counter > 20) + { + cerr << "Limit intersecting surface elements: too many " + "limitation steps, sels: " + << Get(sei) << '\t' << Get(sej) << endl; + for (auto si : {sei, sej}) + { + auto sel = Get(si); + cerr << "Limits: "; + for (auto pi : sel.PNums()) + cerr << GetLimit(pi) << ",\t"; + cerr << endl; + for (auto pi : sel.PNums()) + cerr << GetPoint(pi, 1.0, true) << "\t"; + cerr << endl; + } + cerr << "pi_max_limit " << pi_max_limit << endl; + break; + } + } + return false; + }); + } + } + } + + void LimitOriginalSurface (double safety) + { + static Timer t("GrowthVectorLimiter::LimitOriginalSurface"); + RegionTimer reg(t); + PrintMessage(5, "GrowthVectorLimiter - original surface"); + // limit to not intersect with other (original) surface elements + double trig_shift = 0; + double seg_shift = safety; + FindTreeIntersections( + trig_shift, seg_shift, [&] (PointIndex pi_to, SurfaceElementIndex sei) { + if (sei >= tool.nse) + return; // ignore new surface elements in first pass + LimitGrowthVector(pi_to, sei, trig_shift, seg_shift); + }); + } + + void LimitBoundaryLayer (double safety = 1.1) + { + static Timer t("GrowthVectorLimiter::LimitBoundaryLayer"); + PrintMessage(5, "GrowthVectorLimiter - boundary layer"); + // now limit again with shifted surface elements + double trig_shift = safety; + double seg_shift = safety; + size_t limit_counter = 1; + + TBitArray relevant_points, relevant_points_next; + relevant_points.SetSize(mesh.Points().Size() + 1); + relevant_points_next.SetSize(mesh.Points().Size() + 1); + relevant_points.Set(); + + while (limit_counter) + { + RegionTimer reg(t); + size_t find_counter = 0; + limit_counter = 0; + relevant_points_next.Clear(); + FindTreeIntersections( + trig_shift, seg_shift, [&] (PointIndex pi_to, SurfaceElementIndex sei) { + find_counter++; + auto sel = Get(sei); + + if (LimitGrowthVector(pi_to, sei, trig_shift, seg_shift)) + { + limit_counter++; + relevant_points_next.SetBit(pi_to); + relevant_points_next.SetBit(map_from[pi_to]); + for (auto pi : sel.PNums()) + { + relevant_points_next.SetBit(pi); + if (pi >= tool.first_new_pi) + relevant_points_next.SetBit(map_from[pi]); + } + } + + for (auto pi : sel.PNums()) + { + if (pi >= tool.first_new_pi) + return; + if (tool.mapto[pi].Size() == 0) + return; + } + if (LimitGrowthVector(pi_to, sei, trig_shift, seg_shift, true)) + limit_counter++; + }, + &relevant_points); + relevant_points = relevant_points_next; + } + } + + void CheckLimits (int line) + { + auto check_point = [&] (PointIndex pi) { + if (limits[pi] < 1e-8) + { + WriteErrorMesh("error_blayer_intersection_pi" + ToString(pi) + ".vol.gz"); + throw NgException(__FILE__ + ToString(line) + ": Stop meshing in boundary layer thickness limitation: overlapping regions detected at point " + ToString(pi)); + } + }; + + for (auto pi : Range(growthvectors)) + check_point(pi); + + if (!tool.insert_only_volume_elements) + for (auto& [special_pi, special_point] : tool.special_boundary_points) + check_point(special_pi); + } + + void Perform () + { + limits.SetSize(mesh.Points().Size()); + limits = 1.0; + if (tool.special_boundary_points.size()) + { + auto point_to_sel = tool.mesh.CreatePoint2SurfaceElementTable(); + for (auto& [pi, special_point] : tool.special_boundary_points) + { + auto maxh = mesh.GetH(mesh[pi]); + auto new_limit = min(0.3 * maxh / tool.total_height, 1.0); + if (new_limit < 1.0) + { + limits[pi] = new_limit; + for (auto sei : point_to_sel[pi]) + for (auto pi_ : Get(sei).PNums()) + limits[pi_] = new_limit; + } + } + } + + std::array safeties = {0.5, 1.1, 1.5, 1.5}; + + // No smoothing in the last pass, to avoid generating new intersections + std::array smoothing_factors = {0.8, 0.7, 0.5, 0.0}; + + for (auto i_pass : Range(safeties.size())) + { + PrintMessage(4, "GrowthVectorLimiter pass ", i_pass); + double safety = safeties[i_pass]; + CheckLimits(__LINE__); + // intersect segment with original surface elements + LimitOriginalSurface(2.1); + CheckLimits(__LINE__); + // intersect prisms with themself + LimitSelfIntersection(1.3 * safety); + CheckLimits(__LINE__); + // intesect segment with prism + LimitBoundaryLayer(safety); + CheckLimits(__LINE__); + + for ([[maybe_unused]] auto i : Range(10)) + EqualizeLimits(smoothing_factors[i_pass]); + CheckLimits(__LINE__); + + if (i_pass == safeties.size() - 1) + FixIntersectingSurfaceTrigs(); + CheckLimits(__LINE__); + } + + for (auto i : Range(growthvectors)) + growthvectors[i] *= limits[i]; + + for (auto& [special_pi, special_point] : tool.special_boundary_points) + { + for (auto& group : special_point.growth_groups) + { + group.growth_vector *= limits[special_pi]; + } + } + } +}; + +} // namespace netgen diff --git a/libsrc/meshing/classifyhpel.hpp b/libsrc/meshing/classifyhpel.hpp index 51ebae59..9fab7d7d 100644 --- a/libsrc/meshing/classifyhpel.hpp +++ b/libsrc/meshing/classifyhpel.hpp @@ -1,16 +1,20 @@ -HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges, INDEX_2_HASHTABLE & edgepoint_dom, - NgBitArray & cornerpoint, NgBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, - INDEX_2_HASHTABLE & surf_edges, NgArray & facepoint) +// typename INDEX_2_HASHTABLE HT_EDGEPOINT_DOM; +typedef ClosedHashTable, int> HT_EDGEPOINT_DOM; + + +HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, + TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, + INDEX_2_HASHTABLE & surf_edges, Array & facepoint) { int ep1(0), ep2(0), ep3(0), ep4(0), cp1(0), cp2(0), cp3(0), cp4(0), fp1, fp2, fp3, fp4; int isedge1(0), isedge2(0), isedge3(0), isedge4(0), isedge5(0), isedge6(0); int isfedge1, isfedge2, isfedge3, isfedge4, isfedge5, isfedge6; - int isface1(0), isface2(0), isface3(0), isface4(0); + bool isface[4]; HPREF_ELEMENT_TYPE type = HP_NONE; - int debug = 0; + /* for (int j = 0;j < 4; j++) { if (el.pnums[j] == 444) debug++; @@ -19,9 +23,10 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges if (el.pnums[j] == 281) debug++; } if (debug < 4) debug = 0; + */ + + // *testout << "new el" << endl; - - for (int j = 0; j < 4; j++) for (int k = 0; k < 4; k++) { @@ -55,12 +60,12 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges cp3 = cornerpoint.Test (el.pnums[pi3]); cp4 = cornerpoint.Test (el.pnums[pi4]); - isedge1 = edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[k])); - isedge2 = edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[pi3])); - isedge3 = edges.Used (INDEX_2::Sort (el.pnums[j], el.pnums[pi4])); - isedge4 = edges.Used (INDEX_2::Sort (el.pnums[k], el.pnums[pi3])); - isedge5 = edges.Used (INDEX_2::Sort (el.pnums[k], el.pnums[pi4])); - isedge6 = edges.Used (INDEX_2::Sort (el.pnums[pi3], el.pnums[pi4])); + isedge1 = edges.Used (PointIndices<2>::Sort (el.pnums[j], el.pnums[k])); + isedge2 = edges.Used (PointIndices<2>::Sort (el.pnums[j], el.pnums[pi3])); + isedge3 = edges.Used (PointIndices<2>::Sort (el.pnums[j], el.pnums[pi4])); + isedge4 = edges.Used (PointIndices<2>::Sort (el.pnums[k], el.pnums[pi3])); + isedge5 = edges.Used (PointIndices<2>::Sort (el.pnums[k], el.pnums[pi4])); + isedge6 = edges.Used (PointIndices<2>::Sort (el.pnums[pi3], el.pnums[pi4])); if (debug) { @@ -72,31 +77,23 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges } - isface1 = isface2 = isface3 = isface4 = 0; + for (int j = 0; j < 4; j++) isface[j] = false; for (int l = 0; l < 4; l++) { - INDEX_3 i3(0,0,0); + PointIndices<3> i3(PointIndex::INVALID, PointIndex::INVALID, PointIndex::INVALID); switch (l) { - case 0: i3.I1() = el.pnums[k]; i3.I1() = el.pnums[pi3]; i3.I1() = el.pnums[pi4]; break; - case 1: i3.I1() = el.pnums[j]; i3.I1() = el.pnums[pi3]; i3.I1() = el.pnums[pi4]; break; - case 2: i3.I1() = el.pnums[j]; i3.I1() = el.pnums[k]; i3.I1() = el.pnums[pi4]; break; - case 3: i3.I1() = el.pnums[j]; i3.I1() = el.pnums[k]; i3.I1() = el.pnums[pi3]; break; + case 0: i3[0] = el.pnums[k]; i3[1] = el.pnums[pi3]; i3[2] = el.pnums[pi4]; break; + case 1: i3[0] = el.pnums[j]; i3[1] = el.pnums[pi3]; i3[2] = el.pnums[pi4]; break; + case 2: i3[0] = el.pnums[j]; i3[1] = el.pnums[k]; i3[2] = el.pnums[pi4]; break; + case 3: i3[0] = el.pnums[j]; i3[1] = el.pnums[k]; i3[2] = el.pnums[pi3]; break; } i3.Sort(); if (faces.Used (i3)) { int domnr = faces.Get(i3); if (domnr == -1 || domnr == el.GetIndex()) - { - switch (l) - { - case 0: isface1 = 1; break; - case 1: isface2 = 1; break; - case 2: isface3 = 1; break; - case 3: isface4 = 1; break; - } - } + isface[l] = true; } } /* @@ -109,15 +106,15 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges isfedge1 = isfedge2 = isfedge3 = isfedge4 = isfedge5 = isfedge6 = 0; for (int l = 0; l < 6; l++) { - INDEX_2 i2(0,0); + PointIndices<2> i2(PointIndex::INVALID, PointIndex::INVALID); switch (l) { - case 0: i2.I1() = el.pnums[j]; i2.I2() = el[k]; break; - case 1: i2.I1() = el.pnums[j]; i2.I2() = el.pnums[pi3]; break; - case 2: i2.I1() = el.pnums[j]; i2.I2() = el.pnums[pi4]; break; - case 3: i2.I1() = el.pnums[k]; i2.I2() = el.pnums[pi3]; break; - case 4: i2.I1() = el.pnums[k]; i2.I2() = el.pnums[pi4]; break; - case 5: i2.I1() = el.pnums[pi3]; i2.I2() = el.pnums[pi4]; break; + case 0: i2[0] = el.pnums[j]; i2[1] = el[k]; break; + case 1: i2[0] = el.pnums[j]; i2[1] = el.pnums[pi3]; break; + case 2: i2[0] = el.pnums[j]; i2[1] = el.pnums[pi4]; break; + case 3: i2[0] = el.pnums[k]; i2[1] = el.pnums[pi3]; break; + case 4: i2[0] = el.pnums[k]; i2[1] = el.pnums[pi4]; break; + case 5: i2[0] = el.pnums[pi3]; i2[1] = el.pnums[pi4]; break; } i2.Sort(); if (face_edges.Used (i2)) @@ -149,7 +146,7 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges fp1 = fp2 = fp3 = fp4 = 0; for (int l = 0; l < 4; l++) { - int pti(0); + PointIndex pti = PointIndex::INVALID; switch (l) { case 0: pti = el.pnums[j]; break; @@ -169,16 +166,60 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges } } } - + + /* + ep1 |= cp1; + ep2 |= cp2; + ep3 |= cp3; + ep4 |= cp4; + + fp1 |= ep1; + fp2 |= ep2; + fp3 |= ep3; + fp4 |= ep4; + */ + /* fp1 = facepoint[el.pnums[j]] != 0; fp2 = facepoint[el.pnums[k]] != 0; fp3 = facepoint[el.pnums[pi3]] != 0; fp4 = facepoint[el.pnums[pi4]] != 0; */ - - - switch (isface1+isface2+isface3+isface4) + + // cout << "marked faces: " + // << isface[0] << isface[1] << isface[2] << isface[3] + // << ", num = " << isface[0]+isface[1]+isface[2]+isface[3] << endl; + + + bool sp1 = cp1 + || (ep1 && !isedge1 && !isedge2 && !isedge3) + || (fp1 && !isfedge1 && !isfedge2 && !isfedge3); + + bool sp2 = cp2 + || (ep2 && !isedge1 && !isedge4 && !isedge5) + || (fp2 && !isfedge1 && !isfedge4 && !isfedge5); + + bool sp3 = cp3 + || (ep3 && !isedge2 && !isedge4 && !isedge6) + || (fp3 && !isfedge2 && !isfedge4 && !isfedge6); + + bool sp4 = cp4 + || (ep4 && !isedge3 && !isedge5 && !isedge6) + || (fp4 && !isfedge3 && !isfedge5 && !isfedge6); + + bool se1 = isedge1 || (isfedge1 && !isface[2] && !isface[3]); + bool se2 = isedge2 || (isfedge2 && !isface[1] && !isface[3]); + bool se3 = isedge3 || (isfedge3 && !isface[1] && !isface[2]); + bool se4 = isedge4 || (isfedge4 && !isface[0] && !isface[3]); + bool se5 = isedge5 || (isfedge5 && !isface[0] && !isface[2]); + bool se6 = isedge6 || (isfedge6 && !isface[0] && !isface[1]); + + // *testout << "sp = " << sp1 << sp2 << sp3 << sp4 << endl; + // *testout << "se = " << se1 << se2 << se3 << se4 << se5 << se6 << endl; + // *testout << "sf = " << isface[0] << isface[1] << isface[2] << isface[3] << endl; + + + switch (isface[0]+isface[1]+isface[2]+isface[3]) { case 0: { @@ -198,19 +239,19 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges { case 0: { - if (!ep1 && !ep2 && !ep3 && !ep4) + if (!sp1 && !sp2 && !sp3 && !sp4) type = HP_TET; - if (ep1 && !ep2 && !ep3 && !ep4) + if (sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_0E_1V; - if (ep1 && ep2 && !ep3 && !ep4) + if (sp1 && sp2 && !sp3 && !sp4) type = HP_TET_0E_2V; - if (ep1 && ep2 && ep3 && !ep4) + if (sp1 && sp2 && sp3 && !sp4) type = HP_TET_0E_3V; - if (ep1 && ep2 && ep3 && ep4) + if (sp1 && sp2 && sp3 && sp4) type = HP_TET_0E_4V; break; @@ -220,34 +261,34 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges { if (!isedge1) break; - if (!cp1 && !cp2 && !ep3 && !ep4) + if (!sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_1E_0V; - if (cp1 && !cp2 && !ep3 && !ep4) + if (sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_1E_1VA; - if (!cp1 && !cp2 && !ep3 && ep4) + if (!sp1 && !sp2 && !sp3 && sp4) type = HP_TET_1E_1VB; - if (cp1 && cp2 && !ep3 && !ep4) + if (sp1 && sp2 && !sp3 && !sp4) type = HP_TET_1E_2VA; - if (cp1 && !cp2 && ep3 && !ep4) + if (sp1 && !sp2 && sp3 && !sp4) type = HP_TET_1E_2VB; - if (cp1 && !cp2 && !ep3 && ep4) + if (sp1 && !sp2 && !sp3 && sp4) type = HP_TET_1E_2VC; - if (!cp1 && !cp2 && ep3 && ep4) + if (!sp1 && !sp2 && sp3 && sp4) type = HP_TET_1E_2VD; - if (cp1 && cp2 && ep3 && !ep4) + if (sp1 && sp2 && sp3 && !sp4) type = HP_TET_1E_3VA; - if (cp1 && !cp2 && ep3 && ep4) + if (sp1 && !sp2 && sp3 && sp4) type = HP_TET_1E_3VB; - if (cp1 && cp2 && ep3 && ep4) + if (sp1 && sp2 && sp3 && sp4) type = HP_TET_1E_4V; break; @@ -256,42 +297,42 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges { if (isedge1 && isedge2) { - if (!cp2 && !cp3 && !ep4) + if (!sp2 && !sp3 && !sp4) type = HP_TET_2EA_0V; - if (cp2 && !cp3 && !ep4) + if (sp2 && !sp3 && !sp4) type = HP_TET_2EA_1VA; - if (!cp2 && cp3 && !ep4) + if (!sp2 && sp3 && !sp4) type = HP_TET_2EA_1VB; - if (!cp2 && !cp3 && ep4) + if (!sp2 && !sp3 && sp4) type = HP_TET_2EA_1VC; - if (cp2 && cp3 && !ep4) + if (sp2 && sp3 && !sp4) type = HP_TET_2EA_2VA; - if (cp2 && !cp3 && ep4) + if (sp2 && !sp3 && sp4) type = HP_TET_2EA_2VB; - if (!cp2 && cp3 && ep4) + if (!sp2 && sp3 && sp4) type = HP_TET_2EA_2VC; - if (cp2 && cp3 && ep4) + if (sp2 && sp3 && sp4) type = HP_TET_2EA_3V; } if (isedge1 && isedge6) { - if (!cp1 && !cp2 && !cp3 && !cp4) + if (!sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_2EB_0V; - if (cp1 && !cp2 && !cp3 && !cp4) + if (sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_2EB_1V; - if (cp1 && cp2 && !cp3 && !cp4) + if (sp1 && sp2 && !sp3 && !sp4) type = HP_TET_2EB_2VA; - if (cp1 && !cp2 && cp3 && !cp4) + if (sp1 && !sp2 && sp3 && !sp4) type = HP_TET_2EB_2VB; - if (cp1 && !cp2 && !cp3 && cp4) + if (sp1 && !sp2 && !sp3 && sp4) type = HP_TET_2EB_2VC; - if (cp1 && cp2 && cp3 && !cp4) + if (sp1 && sp2 && sp3 && !sp4) type = HP_TET_2EB_3V; - if (cp1 && cp2 && cp3 && cp4) + if (sp1 && sp2 && sp3 && sp4) type = HP_TET_2EB_4V; } break; @@ -300,33 +341,39 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges { if (isedge1 && isedge2 && isedge3) { - if (!cp2 && !cp3 && !cp4) + if (!sp2 && !sp3 && !sp4) type = HP_TET_3EA_0V; - if (cp2 && !cp3 && !cp4) + if (sp2 && !sp3 && !sp4) type = HP_TET_3EA_1V; - if (cp2 && cp3 && !cp4) + if (sp2 && sp3 && !sp4) type = HP_TET_3EA_2V; - if (cp2 && cp3 && cp4) + if (sp2 && sp3 && sp4) type = HP_TET_3EA_3V; } if (isedge1 && isedge3 && isedge4) { - if (!cp3 && !cp4) + if (!sp3 && !sp4) type = HP_TET_3EB_0V; - if (cp3 && !cp4) + if (sp3 && !sp4) type = HP_TET_3EB_1V; - if (cp3 && cp4) + if (sp3 && sp4) type = HP_TET_3EB_2V; } if (isedge1 && isedge2 && isedge5) { - if (!cp3 && !cp4) + if (!sp3 && !sp4) type = HP_TET_3EC_0V; - if (cp3 && !cp4) + if (sp3 && !sp4) type = HP_TET_3EC_1V; - if (cp3 && cp4) + if (sp3 && sp4) type = HP_TET_3EC_2V; } + if (isedge1 && isedge2 && isedge4) + { + if (!sp4) + type = HP_TET_3ED_3V; // a loop + } + break; } } @@ -337,9 +384,22 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges case 1: // one singular face { - if (!isface1) break; - - switch (isfedge1+isfedge2+isfedge3+isedge4+isedge5+isedge6) + if (!isface[0]) break; + + /* + cout << "1F and 1E, isedge = " << isedge1 << isedge2 << isedge3 << isedge4 << isedge5 << isedge6 << endl; + cout << "spoints = " << sp1 << sp2 << sp3 << sp4 << endl; + cout << "cpoints = " << cp1 << cp2 << cp3 << cp4 << endl; + cout << "epoints = " << ep1 << ep2 << ep3 << ep4 << endl; + cout << "fpoints = " << fp1 << fp2 << fp3 << fp4 << endl; + */ + + isedge1 |= isfedge1; + isedge2 |= isfedge2; + isedge3 |= isfedge3; + + // switch (isedge1+isedge2+isedge3+isedge4+isedge5+isedge6) + switch (se1+se2+se3+se4+se5+se6) { case 0: { @@ -349,22 +409,70 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges type = HP_TET_1F_0E_1VB; if (!fp1 && ep2 && !ep3 & !ep4) type = HP_TET_1F_0E_1VA; + if (!fp1 && ep2 && ep3 & !ep4) + type = HP_TET_1F_0E_2V; + + if (!sp1 && sp2 && sp3 && sp4) + type = HP_TET_1F_0E_3V; break; } case 1: { - if (isfedge1) + if (se1) { - if (!ep1 && !ep3 && !ep4) + if (!sp1 && !sp3 && !sp4) type = HP_TET_1F_1EA_0V; + if (!sp1 && sp2 && sp3 && !sp4) + type = HP_TET_1F_1E_2VA; + if (!sp1 && sp2 && !sp3 && sp4) + type = HP_TET_1F_1E_2VB; + if (!sp1 && !sp2 && sp3 && sp4) + type = HP_TET_1F_1E_2VC; + if (!sp1 && sp2 && sp3 && sp4) + type = HP_TET_1F_1EA_3V; } - if (isedge4) // V1-V3 + if (se4) // V2-V3 { - if (!ep1 && !cp2 && !cp3 && !ep4) + if (!sp1 && !sp2 && !sp3 && !sp4) type = HP_TET_1F_1EB_0V; + if (!sp1 && sp2 && !sp3 && !sp4) + type = HP_TET_1F_1E_1VA; + if (!sp1 && sp2 && sp3 && sp4) + type = HP_TET_1F_1E_3V; } + if (se5) // V2-V4 + { + if (!sp1 && sp2 && !sp3 && !sp4) + type = HP_TET_1F_1E_1VB; + } break; } + case 2: + { + if (isedge1 && isedge2) + { + if (sp1 && sp2 && sp3 && !sp4) + type = HP_TET_1F_2Eoo_3V; + } + if (isedge6 && isedge3) + if (!cp1 && !cp2 && !cp3) + type = HP_TET_1F_2E_0VA; + if (isedge6 && isedge2) + { + if (!cp1 && !cp2 && !cp4) + type = HP_TET_1F_2E_0VB; + } + if (se4 && se5) + { // 2 edges in face + if (!sp1 && sp2 && !sp3 && !sp4) + type = HP_TET_1F_2E_1V; + if (!sp1 && sp2 && sp3 && sp4) + type = HP_TET_1F_2E_3V; + } + break; + } + default: + ; } break; } @@ -372,26 +480,79 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges case 2: // two singular faces { - if (!isface1 || !isface2) break; + if (!isface[0] || !isface[1]) break; switch (isfedge1+isedge2+isedge3+isedge4+isedge5) { case 0: { if (!ep1 && !ep2 && !cp3 && !cp4) - type = HP_TET_2F_0E_0V; - break; + { + type = HP_TET_2F_0E_0V; + break; + } + if (!ep1 && !ep2 && !cp3 && cp4) + { + type = HP_TET_2F_0E_1V; + break; + } + break; } + case 1: + { + // *testout << "so far: 2F, 1E, sp = " << sp1 << sp2 << sp3 << sp4 << endl; + + if (isedge4) + { + if (!ep1 && !cp2 && !cp4) + { + type = HP_TET_2F_1E_0VA; + break; + } + if (!sp1 && sp2 && sp3 && sp4) + { + type = HP_TET_2F_1E_3VA; + break; + } + if (sp1 && sp2 && sp3 && sp4) + { + type = HP_TET_2F_1E_4VA; + break; + } + } + + if (isedge5 && !ep1 && !cp2 && !cp3) + { + type = HP_TET_2F_1E_0VB; + break; + } + break; + } + default: + *testout << "2F, 2E or more not implemented so far" << endl; } break; } - - + + case 3: + { + if (!isface[3]) + if (!cp1 && !cp2 && !cp3) + { + type = HP_TET_3F_0E_0V; + break; + } + break; + } + case 4: + { + *testout << "4 singular faces" << endl; + } } if (type != HP_NONE) { - int pnums[4]; + PointIndex pnums[4]; pnums[0] = el.pnums[j]; pnums[1] = el.pnums[k]; pnums[2] = el.pnums[pi3]; @@ -407,13 +568,20 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges if (type == HP_NONE) { // cnt_undef++; - (*testout) << "undefined element" << endl + (*testout) << "unclassified element " + << el.pnums[0] << " " + << el.pnums[1] << " " + << el.pnums[2] << " " + << el.pnums[3] << endl << "cp = " << cp1 << cp2 << cp3 << cp4 << endl << "ep = " << ep1 << ep2 << ep3 << ep4 << endl + << "fp = " << fp1 << fp2 << fp3 << fp4 << endl << "isedge = " << isedge1 << isedge2 << isedge3 << isedge4 << isedge5 << isedge6 << endl - << "isface = " << isface1 << isface2 << isface3 << isface4 << endl; - cout << "undefined element !!! " << endl; + << "isfedge = " << isfedge1 << isfedge2 << isfedge3 + << isfedge4 << isfedge5 << isfedge6 << endl + << "isface = " << isface[0] << isface[1] << isface[2] << isface[3] << endl; + cout << "unclassified element !!! " << endl; } @@ -422,9 +590,9 @@ HPREF_ELEMENT_TYPE ClassifyTet(HPRefElement & el, INDEX_2_HASHTABLE & edges -HPREF_ELEMENT_TYPE ClassifyPrism(HPRefElement & el, INDEX_2_HASHTABLE & edges, INDEX_2_HASHTABLE & edgepoint_dom, - NgBitArray & cornerpoint, NgBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, - INDEX_2_HASHTABLE & surf_edges, NgArray & facepoint) +HPREF_ELEMENT_TYPE ClassifyPrism(HPRefElement & el, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, + TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, + INDEX_2_HASHTABLE & surf_edges, Array & facepoint) { HPREF_ELEMENT_TYPE type = HP_NONE; @@ -458,7 +626,7 @@ HPREF_ELEMENT_TYPE ClassifyPrism(HPRefElement & el, INDEX_2_HASHTABLE & edg const ELEMENT_EDGE * eledges = MeshTopology::GetEdges1 (PRISM); for(int k=0;k<9;k++) { - INDEX_2 i2 = INDEX_2 :: Sort(el.PNum(p[eledges[k][0]-1]),el.PNum(p[eledges[k][1]-1])); + PointIndices<2> i2 = PointIndices<2> :: Sort(el.PNum(p[eledges[k][0]-1]),el.PNum(p[eledges[k][1]-1])); if (edges.Used(i2)) edge_sing[k] = 2; else edge_sing[k] = face_edges.Used(i2); } @@ -466,16 +634,17 @@ HPREF_ELEMENT_TYPE ClassifyPrism(HPRefElement & el, INDEX_2_HASHTABLE & edg const ELEMENT_FACE * elfaces = MeshTopology::GetFaces1 (PRISM); for (int k=0;k<5;k++) { - INDEX_3 i3; + PointIndices<3> i3; if(k<2) - i3 = INDEX_3::Sort(el.pnums[p[elfaces[k][0]-1]-1], el.pnums[p[elfaces[k][1]-1]-1], - el.pnums[p[elfaces[k][2]-1]-1]); + i3 = PointIndices<3>::Sort(el.pnums[p[elfaces[k][0]-1]-1], el.pnums[p[elfaces[k][1]-1]-1], + el.pnums[p[elfaces[k][2]-1]-1]); else { - INDEX_4 i4 = INDEX_4(el.pnums[p[elfaces[k][0]-1]-1], el.pnums[p[elfaces[k][1]-1]-1], el.pnums[p[elfaces[k][2]-1]-1],el.pnums[p[elfaces[k][3]-1]-1]); + PointIndices<4> i4 (el.pnums[p[elfaces[k][0]-1]-1], el.pnums[p[elfaces[k][1]-1]-1], + el.pnums[p[elfaces[k][2]-1]-1],el.pnums[p[elfaces[k][3]-1]-1]); i4.Sort(); - i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3()); + i3 = PointIndices<3>(i4[0], i4[1], i4[2]); } if (faces.Used (i3)) @@ -645,7 +814,7 @@ HPREF_ELEMENT_TYPE ClassifyPrism(HPRefElement & el, INDEX_2_HASHTABLE & edg if(type != HP_NONE) { - int pnums[6]; + PointIndex pnums[6]; for(int j=0;j<6;j++) pnums[j] = el.PNum (p[j]); for(int k=0;k<6;k++) el.pnums[k] = pnums[k]; } @@ -658,18 +827,20 @@ HPREF_ELEMENT_TYPE ClassifyPrism(HPRefElement & el, INDEX_2_HASHTABLE & edg } -// #ifdef SABINE -HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE & edges, INDEX_2_HASHTABLE & edgepoint_dom, - NgBitArray & cornerpoint, NgBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, - INDEX_2_HASHTABLE & surf_edges, NgArray & facepoint, int dim, const FaceDescriptor & fd) +// #ifdef SABINE + + +HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, + TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, + INDEX_2_HASHTABLE & surf_edges, Array & facepoint, int dim, const FaceDescriptor & fd) { HPREF_ELEMENT_TYPE type = HP_NONE; - int pnums[3]; + PointIndex pnums[3]; int p[3]; - INDEX_3 i3 (el.pnums[0], el.pnums[1], el.pnums[2]); + PointIndices<3> i3 (el.pnums[0], el.pnums[1], el.pnums[2]); i3.Sort(); bool sing_face = faces.Used (i3); @@ -718,7 +889,7 @@ HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE & edge { int ep1=p[eledges[k][0]-1]; int ep2=p[eledges[k][1]-1]; - INDEX_2 i2(el.PNum(ep1),el.PNum(ep2)); + PointIndices<2> i2(el.PNum(ep1),el.PNum(ep2)); if(edges.Used(i2)) { @@ -761,14 +932,14 @@ HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE & edge int ep1=p[eledges[k][0]-1]; int ep2=p[eledges[k][1]-1]; - INDEX_2 i2 = INDEX_2::Sort(el.PNum(ep1),el.PNum(ep2)); + PointIndices<2> i2 = PointIndices<2>::Sort(el.PNum(ep1),el.PNum(ep2)); if(edges.Used(i2)) { - if(edgepoint_dom.Used(INDEX_2(fd.SurfNr(),pnums[ep1-1])) || - edgepoint_dom.Used(INDEX_2(-1,pnums[ep1-1])) || - edgepoint_dom.Used(INDEX_2(fd.SurfNr(),pnums[ep2-1])) || - edgepoint_dom.Used(INDEX_2(-1,pnums[ep2-1]))) + if(edgepoint_dom.Used( { fd.SurfNr(),pnums[ep1-1] } ) || + edgepoint_dom.Used( { -1,pnums[ep1-1] } ) || + edgepoint_dom.Used( { fd.SurfNr(), pnums[ep2-1]} ) || + edgepoint_dom.Used( { -1,pnums[ep2-1] } )) { edge_sing[k]=2; point_sing[ep1-1] = 2; @@ -783,11 +954,11 @@ HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE & edge for (int k=0;k<3;k++) if (edgepoint.Test(pnums[k]) && - (dim==3 || edgepoint_dom.Used(INDEX_2(fd.SurfNr(),pnums[k])) || edgepoint_dom.Used(INDEX_2(-1,pnums[k])))) + (dim==3 || edgepoint_dom.Used( { fd.SurfNr(),pnums[k] } ) || edgepoint_dom.Used( { -1,pnums[k] } ))) //edgepoint, but not member of sing_edge on trig -> cp { - INDEX_2 i2a=INDEX_2::Sort(el.PNum(p[k]), el.PNum(p[(k+1)%3])); - INDEX_2 i2b=INDEX_2::Sort(el.PNum(p[k]), el.PNum(p[(k+2)%3])); + PointIndices<2> i2a = PointIndices<2>::Sort(el.PNum(p[k]), el.PNum(p[(k+1)%3])); + PointIndices<2> i2b = PointIndices<2>::Sort(el.PNum(p[k]), el.PNum(p[(k+2)%3])); if(!edges.Used(i2a) && !edges.Used(i2b)) point_sing[p[k]-1] = 3; @@ -797,7 +968,7 @@ HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE & edge if(cornerpoint.Test(el.PNum(p[k]))) point_sing[p[k]-1] = 3; - *testout << "point_sing = " << point_sing[0] << point_sing[1] << point_sing[2] << endl; + // *testout << "point_sing = " << point_sing[0] << point_sing[1] << point_sing[2] << endl; if(edge_sing[0] + edge_sing[1] + edge_sing[2] == 0) { @@ -861,7 +1032,7 @@ HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE & edge if(type!=HP_NONE) break; } - *testout << "type = " << type << endl; + // *testout << "type = " << type << endl; for(int k=0;k<3;k++) el[k] = pnums[k]; /*if(type != HP_NONE) @@ -1136,16 +1307,16 @@ HPREF_ELEMENT_TYPE ClassifyTrig(HPRefElement & el, INDEX_2_HASHTABLE & edge return(type); } #endif -HPREF_ELEMENT_TYPE ClassifyQuad(HPRefElement & el, INDEX_2_HASHTABLE & edges, INDEX_2_HASHTABLE & edgepoint_dom, - NgBitArray & cornerpoint, NgBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, - INDEX_2_HASHTABLE & surf_edges, NgArray & facepoint, int dim, const FaceDescriptor & fd) +HPREF_ELEMENT_TYPE ClassifyQuad(HPRefElement & el, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, + TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, + INDEX_2_HASHTABLE & surf_edges, Array & facepoint, int dim, const FaceDescriptor & fd) { HPREF_ELEMENT_TYPE type = HP_NONE; int ep1(-1), ep2(-1), ep3(-1), ep4(-1), cp1(-1), cp2(-1), cp3(-1), cp4(-1); int isedge1, isedge2, isedge3, isedge4; - *testout << "edges = " << edges << endl; + // *testout << "edges = " << edges << endl; for (int j = 1; j <= 4; j++) { @@ -1156,10 +1327,10 @@ HPREF_ELEMENT_TYPE ClassifyQuad(HPRefElement & el, INDEX_2_HASHTABLE & edge if (dim == 2) { - ep1 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j))); - ep2 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j+1))); - ep3 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j+2))); - ep4 = edgepoint_dom.Used (INDEX_2 (el.GetIndex(), el.PNumMod(j+3))); + ep1 = edgepoint_dom.Used ( { el.GetIndex(), el.PNumMod(j) } ); + ep2 = edgepoint_dom.Used ( { el.GetIndex(), el.PNumMod(j+1) } ); + ep3 = edgepoint_dom.Used ( { el.GetIndex(), el.PNumMod(j+2) }); + ep4 = edgepoint_dom.Used ( { el.GetIndex(), el.PNumMod(j+3) }); } cp1 = cornerpoint.Test (el.PNumMod (j)); @@ -1172,7 +1343,7 @@ HPREF_ELEMENT_TYPE ClassifyQuad(HPRefElement & el, INDEX_2_HASHTABLE & edge ep3 |= cp3; ep4 |= cp4; - int p[4] = { el.PNumMod (j), el.PNumMod (j+1), el.PNumMod (j+2), el.PNumMod(j+4)}; + PointIndex p[4] = { el.PNumMod (j), el.PNumMod (j+1), el.PNumMod (j+2), el.PNumMod(j+4)}; //int epp[4] = { ep1, ep2, ep3, ep4}; int cpp[4] = { cp1, cp2, cp3, cp4}; for(int k=0;k<0;k++) @@ -1187,8 +1358,7 @@ HPREF_ELEMENT_TYPE ClassifyQuad(HPRefElement & el, INDEX_2_HASHTABLE & edge if(dim ==3) { - INDEX_2 i2; - i2 = INDEX_2(el.PNumMod (j), el.PNumMod (j+1)); + PointIndices<2> i2 = PointIndices<2>(el.PNumMod (j), el.PNumMod (j+1)); // i2.Sort(); isedge1 = edges.Used (i2); i2.Sort(); @@ -1486,9 +1656,9 @@ HPREF_ELEMENT_TYPE ClassifyQuad(HPRefElement & el, INDEX_2_HASHTABLE & edge } -HPREF_ELEMENT_TYPE ClassifyHex(HPRefElement & el, INDEX_2_HASHTABLE & edges, INDEX_2_HASHTABLE & edgepoint_dom, - NgBitArray & cornerpoint, NgBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, - INDEX_2_HASHTABLE & surf_edges, NgArray & facepoint) +HPREF_ELEMENT_TYPE ClassifyHex(HPRefElement & el, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, + TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, + INDEX_2_HASHTABLE & surf_edges, Array & facepoint) { HPREF_ELEMENT_TYPE type = HP_NONE; @@ -1586,9 +1756,55 @@ HPREF_ELEMENT_TYPE ClassifyHex(HPRefElement & el, INDEX_2_HASHTABLE & edges } -HPREF_ELEMENT_TYPE ClassifySegm(HPRefElement & hpel, INDEX_2_HASHTABLE & edges, INDEX_2_HASHTABLE & edgepoint_dom, - NgBitArray & cornerpoint, NgBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, - INDEX_2_HASHTABLE & surf_edges, NgArray & facepoint) + + + + + +HPREF_ELEMENT_TYPE ClassifyHex7 (HPRefElement & el, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, + TBitArray & cornerpoint, TBitArray & edgepoint, + INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, + INDEX_2_HASHTABLE & surf_edges, Array & facepoint) +{ + // HPREF_ELEMENT_TYPE type = HP_NONE; + + // no singular + // singular bottom + // singular top + + // indices of bot,top-faces combinations + // int index[6][2] = {{0,1},{1,0},{2,4},{4,2},{3,5},{5,3}}; + // int p[8]; + // const ELEMENT_FACE * elfaces = MeshTopology::GetFaces1 (HEX); + // const ELEMENT_EDGE * eledges = MeshTopology::GetEdges1 (HEX); + + INDEX_4 fbot4 = { el.pnums[0], el.pnums[1], el.pnums[2], el.pnums[3] }; + INDEX_3 ftop = { el.pnums[4], el.pnums[5], el.pnums[6] }; + fbot4.Sort(); + INDEX_3 fbot = { fbot4[0], fbot4[1], fbot4[2] }; + ftop.Sort(); + + bool singbot = faces.Used(fbot); + bool singtop = faces.Used(ftop); + + if (singbot) + el.type = HP_HEX7_1FA; + else if (singtop) + el.type = HP_HEX7_1FB; + else + el.type = HP_HEX7; + + return el.type; +} + + + + + +HPREF_ELEMENT_TYPE ClassifySegm(HPRefElement & hpel, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, + TBitArray & cornerpoint, TBitArray & edgepoint, + INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, + INDEX_2_HASHTABLE & surf_edges, Array & facepoint) { int cp1 = cornerpoint.Test (hpel[0]); @@ -1629,10 +1845,16 @@ HPREF_ELEMENT_TYPE ClassifySegm(HPRefElement & hpel, INDEX_2_HASHTABLE & ed } -HPREF_ELEMENT_TYPE ClassifyPyramid(HPRefElement & el, INDEX_2_HASHTABLE & edges, INDEX_2_HASHTABLE & edgepoint_dom, - NgBitArray & cornerpoint, NgBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, - INDEX_2_HASHTABLE & surf_edges, NgArray & facepoint) +HPREF_ELEMENT_TYPE ClassifyPyramid(HPRefElement & el, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, + TBitArray & cornerpoint, TBitArray & edgepoint, + INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, + INDEX_2_HASHTABLE & surf_edges, Array & facepoint) { + // *testout << "classify pyramid, pnums = "; + // for (int i = 0; i < 5; i++) *testout << el.pnums[i] << " "; + // *testout << endl; + + HPREF_ELEMENT_TYPE type = HP_NONE; // implementation only for HP_PYRAMID @@ -1655,6 +1877,7 @@ HPREF_ELEMENT_TYPE ClassifyPyramid(HPRefElement & el, INDEX_2_HASHTABLE & e for(int m=0;m<4 && type == HP_NONE;m++) { + *testout << "m = " << m << endl; int p[5] = {m%4, m%4+1, m%4+2, m%4+3, 4}; for(int l=0;l<5;l++) @@ -1685,12 +1908,27 @@ HPREF_ELEMENT_TYPE ClassifyPyramid(HPRefElement & el, INDEX_2_HASHTABLE & e for (int k=0;k<5;k++) { - INDEX_3 i3; - INDEX_4 i4 = INDEX_4(el.pnums[p[elfaces[k][0]-1]], el.pnums[p[elfaces[k][1]-1]], el.pnums[p[elfaces[k][2]-1]], + INDEX_3 i3; + /* + INDEX_4 i4 = INDEX_4(el.pnums[p[elfaces[k][0]-1]], el.pnums[p[elfaces[k][1]-1]], el.pnums[p[elfaces[k][2]-1]], el.pnums[p[elfaces[k][3]-1]]); i4.Sort(); i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3()); - + */ + if (k < 4) + { + i3 = INDEX_3(el.pnums[p[elfaces[k][0]-1]], el.pnums[p[elfaces[k][1]-1]], el.pnums[p[elfaces[k][2]-1]]); + i3.Sort(); + } + else + { + INDEX_4 i4 = INDEX_4(el.pnums[p[elfaces[k][0]-1]], el.pnums[p[elfaces[k][1]-1]], el.pnums[p[elfaces[k][2]-1]], + el.pnums[p[elfaces[k][3]-1]]); + i4.Sort(); + i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3()); + } + + if (faces.Used (i3)) { @@ -1700,7 +1938,19 @@ HPREF_ELEMENT_TYPE ClassifyPyramid(HPRefElement & el, INDEX_2_HASHTABLE & e } sface +=face_sing[k]; } - + + *testout << "point_sing: "; + for (int k = 0; k < 5; k++) *testout << point_sing[k] << " "; + *testout << endl; + + *testout << "edge_sing: "; + for (int k = 0; k < 4; k++) *testout << edge_sing[k] << " "; + *testout << endl; + + *testout << "face_sing: "; + for (int k = 0; k < 5; k++) *testout << face_sing[k] << " "; + *testout << endl; + if(!sface && !spoint && !sedge) return(HP_PYRAMID); if(!sface && !sedge && point_sing[p[0]] == spoint) @@ -1711,7 +1961,12 @@ HPREF_ELEMENT_TYPE ClassifyPyramid(HPRefElement & el, INDEX_2_HASHTABLE & e type = HP_PYRAMID_EDGES; if(sface && sface == face_sing[0] && spoint == point_sing[4] + 2) - type = HP_PYRAMID_1FB_0E_1VA; + { + if (point_sing[4] == 1) + type = HP_PYRAMID_1FB_0E_0V; + else + type = HP_PYRAMID_1FB_0E_1VA; + } if(type != HP_NONE) diff --git a/libsrc/meshing/clusters.cpp b/libsrc/meshing/clusters.cpp index 4b544a20..a2532678 100644 --- a/libsrc/meshing/clusters.cpp +++ b/libsrc/meshing/clusters.cpp @@ -1,6 +1,6 @@ #include -#include "meshing.hpp" +#include "clusters.hpp" namespace netgen { @@ -23,6 +23,7 @@ namespace netgen // static int timer2 = NgProfiler::CreateTimer ("clusters2"); // static int timer3 = NgProfiler::CreateTimer ("clusters3"); RegionTimer reg (timer); + constexpr auto PI0 = IndexBASE(); const MeshTopology & top = mesh.GetTopology(); @@ -41,7 +42,7 @@ namespace netgen ned = top.GetNEdges(); nfa = top.GetNFaces(); ne = mesh.GetNE(); - int nse = mesh.GetNSE(); + // int nse = mesh.GetNSE(); cluster_reps.SetSize (nv+ned+nfa+ne); cluster_reps = -1; @@ -86,16 +87,18 @@ namespace netgen [&] (auto myrange) { NgArray nnums; // , ednums, fanums; - for (int i_ : myrange) + for (auto i_ : myrange) { - int i = i_+1; - const Element & el = mesh.VolumeElement(i); + int i = i_-IndexBASE()+1; + const Element & el = mesh.VolumeElement(i_); ELEMENT_TYPE typ = el.GetType(); // top.GetElementEdges (i, ednums); - auto ednums = top.GetEdges (ElementIndex(i_)); + // auto ednums = top.GetEdges (ElementIndex(i_)); + auto ednums = top.GetEdges (i_); // top.GetElementFaces (i, fanums); - auto fanums = top.GetFaces (ElementIndex(i_)); + // auto fanums = top.GetFaces (ElementIndex(i_)); + auto fanums = top.GetFaces (i_); int elnv = top.GetNVertices (typ); int elned = ednums.Size(); @@ -103,7 +106,7 @@ namespace netgen nnums.SetSize(elnv+elned+elnfa+1); for (int j = 0; j < elnv; j++) - nnums[j] = el[j]+1-PointIndex::BASE; + nnums[j] = el[j]+1-PI0; for (int j = 0; j < elned; j++) nnums[elnv+j] = nv+ednums[j]+1; for (int j = 0; j < elnfa; j++) @@ -131,7 +134,7 @@ namespace netgen nnums.SetSize(elnv+elned+1); for (int j = 1; j <= elnv; j++) - nnums.Elem(j) = el.PNum(j)+1-PointIndex::BASE; + nnums.Elem(j) = el.PNum(j)+1-PI0; for (int j = 1; j <= elned; j++) nnums.Elem(elnv+j) = nv+ednums.Elem(j); nnums.Elem(elnv+elned+1) = fanum; @@ -140,29 +143,31 @@ namespace netgen cluster_reps.Elem(nnums[j]) = nnums[j]; } */ + + ngcore::ParallelForRange (mesh.SurfaceElements().Range(), [&] (auto myrange) { NgArrayMem nnums; // , ednums; - for (int i_ : myrange) + for (SurfaceElementIndex i_ : myrange) { - int i = i_+1; - const Element2d & el = mesh.SurfaceElement(i); + // int i = i_+1; + const Element2d & el = mesh[i_]; // .SurfaceElement(i); ELEMENT_TYPE typ = el.GetType(); // top.GetSurfaceElementEdges (i, ednums); - auto ednums = top.GetEdges (SurfaceElementIndex(i_)); + auto ednums = top.GetEdges (i_); // cout << "ednums = " << ednums << endl; - int fanum = top.GetSurfaceElementFace (i); + int fanum = top.GetFace(i_)+1; int elnv = top.GetNVertices (typ); int elned = ednums.Size(); nnums.SetSize(elnv+elned+1); for (int j = 0; j < elnv; j++) - nnums[j] = el[j]+1-PointIndex::BASE; + nnums[j] = el[j]+1-PI0; for (int j = 0; j < elned; j++) nnums[elnv+j] = nv+ednums[j]+1; nnums[elnv+elned] = fanum; @@ -218,18 +223,19 @@ namespace netgen static const int tet_cluster34[] = { 2, 3, 1, 1, 4, 5, 1, 6, 4, 5, 5, 4, 7, 7, 7 }; - int cnt = 0; - + // int cnt = 0; do { static Timer t("update cluster, identify"); RegionTimer rtr(t); - cnt++; + // cnt++; changed = 0; for (int i = 1; i <= ne; i++) { - const Element & el = mesh.VolumeElement(i); + ElementIndex ei(i-1); + + const Element & el = mesh[ei]; ELEMENT_TYPE typ = el.GetType(); const int * clustertab = NULL; @@ -247,23 +253,23 @@ namespace netgen break; case TET: case TET10: - if (cluster_reps.Get(el.PNum(1)+1-PointIndex::BASE) == - cluster_reps.Get(el.PNum(2)+1-PointIndex::BASE)) + if (cluster_reps.Get(el.PNum(1)+1-PI0) == + cluster_reps.Get(el.PNum(2)+1-PI0)) clustertab = tet_cluster12; - else if (cluster_reps.Get(el.PNum(1)+1-PointIndex::BASE) == - cluster_reps.Get(el.PNum(3)+1-PointIndex::BASE)) + else if (cluster_reps.Get(el.PNum(1)+1-PI0) == + cluster_reps.Get(el.PNum(3)+1-PI0)) clustertab = tet_cluster13; - else if (cluster_reps.Get(el.PNum(1)+1-PointIndex::BASE) == - cluster_reps.Get(el.PNum(4)+1-PointIndex::BASE)) + else if (cluster_reps.Get(el.PNum(1)+1-PI0) == + cluster_reps.Get(el.PNum(4)+1-PI0)) clustertab = tet_cluster14; - else if (cluster_reps.Get(el.PNum(2)+1-PointIndex::BASE) == - cluster_reps.Get(el.PNum(3)+1-PointIndex::BASE)) + else if (cluster_reps.Get(el.PNum(2)+1-PI0) == + cluster_reps.Get(el.PNum(3)+1-PI0)) clustertab = tet_cluster23; - else if (cluster_reps.Get(el.PNum(2)+1-PointIndex::BASE) == - cluster_reps.Get(el.PNum(4)+1-PointIndex::BASE)) + else if (cluster_reps.Get(el.PNum(2)+1-PI0) == + cluster_reps.Get(el.PNum(4)+1-PI0)) clustertab = tet_cluster24; - else if (cluster_reps.Get(el.PNum(3)+1-PointIndex::BASE) == - cluster_reps.Get(el.PNum(4)+1-PointIndex::BASE)) + else if (cluster_reps.Get(el.PNum(3)+1-PI0) == + cluster_reps.Get(el.PNum(4)+1-PI0)) clustertab = tet_cluster34; else @@ -277,8 +283,8 @@ namespace netgen { // top.GetElementEdges (i, ednums); // top.GetElementFaces (i, fanums); - auto ednums = top.GetEdges (ElementIndex(i-1)); - auto fanums = top.GetFaces (ElementIndex(i-1)); + auto ednums = top.GetEdges (ei); + auto fanums = top.GetFaces (ei); int elnv = top.GetNVertices (typ); int elned = ednums.Size(); @@ -286,7 +292,7 @@ namespace netgen nnums.SetSize(elnv+elned+elnfa+1); for (int j = 0; j < elnv; j++) - nnums[j] = el[j]+1-PointIndex::BASE; + nnums[j] = el[j]+1-IndexBASE(); for (int j = 0; j < elned; j++) nnums[elnv+j] = nv+ednums[j]+1; for (int j = 0; j < elnfa; j++) diff --git a/libsrc/meshing/clusters.hpp b/libsrc/meshing/clusters.hpp index 21854f39..e9cc901c 100644 --- a/libsrc/meshing/clusters.hpp +++ b/libsrc/meshing/clusters.hpp @@ -1,5 +1,5 @@ -#ifndef CLUSTERS -#define CLUSTERS +#ifndef NETGEN_CLUSTERS_HPP +#define NETGEN_CLUSTERS_HPP /**************************************************************************/ /* File: clusers.hh */ @@ -13,6 +13,10 @@ nodes, edges, faces, elements */ +#include "meshclass.hpp" + +namespace netgen +{ class AnisotropicClusters { @@ -38,5 +42,5 @@ public: int GetElementRepresentant (int enr) const { return cluster_reps.Get(nv+ned+nfa+enr); } }; - -#endif +} // namespace netgen +#endif // NETGEN_CLUSTERS_HPP diff --git a/libsrc/meshing/curvedelems.cpp b/libsrc/meshing/curvedelems.cpp index 50d3fa35..84e681c3 100644 --- a/libsrc/meshing/curvedelems.cpp +++ b/libsrc/meshing/curvedelems.cpp @@ -1,15 +1,14 @@ #include #include "meshing.hpp" - -#include "../general/autodiff.hpp" +// #include "../general/autodiff.hpp" namespace netgen { + using namespace std; // bool rational = true; - static void ComputeGaussRule (int n, NgArray & xi, NgArray & wi) { xi.SetSize (n); @@ -405,18 +404,24 @@ namespace netgen } } - - static NgArray> jacpols2; - - void CurvedElements::buildJacPols() + struct JacobiRecPols { - if (!jacpols2.Size()) - { - jacpols2.SetSize (100); - for (int i = 0; i < 100; i++) - jacpols2[i] = make_shared (100, i, 2); - } - } + static constexpr size_t N = 100; + ArrayMem, N> jacpols; + + JacobiRecPols() + { + jacpols.SetSize (N); + for (int i = 0; i < N; i++) + jacpols[i] = make_unique(N, i, 2); + } + + const unique_ptr & operator[] (int i) { + return jacpols[i]; + } + }; + + static JacobiRecPols jacpols2; // compute face bubbles up to order n, 0 < y, y-x < 1, x+y < 1 template @@ -561,7 +566,7 @@ namespace netgen auto comm = mesh.GetCommunicator(); #ifdef PARALLEL - enum { MPI_TAG_CURVE = MPI_TAG_MESH+20 }; + enum { NG_MPI_TAG_CURVE = NG_MPI_TAG_MESH+20 }; const ParallelMeshTopology & partop = mesh.GetParallelTopology (); #endif int ntasks = comm.Size(); @@ -608,7 +613,7 @@ namespace netgen if (aorder <= 1) { - for (ElementIndex ei = 0; ei < mesh.GetNE(); ei++) + for (ElementIndex ei : mesh.VolumeElements().Range()) if (mesh[ei].GetType() == TET10) ishighorder = 1; return; @@ -654,8 +659,8 @@ namespace netgen } if (ntasks > 1) - // MyMPI_ExchangeTable (send_orders, recv_orders, MPI_TAG_CURVE, comm); - comm.ExchangeTable (send_orders, recv_orders, MPI_TAG_CURVE); + // MyMPI_ExchangeTable (send_orders, recv_orders, NG_MPI_TAG_CURVE, comm); + comm.ExchangeTable (send_orders, recv_orders, NG_MPI_TAG_CURVE); if (ntasks > 1 && working) { @@ -710,7 +715,6 @@ namespace netgen ComputeGaussRule (aorder+4, xi, weight); // on (0,1) - buildJacPols(); PrintMessage (3, "Curving edges"); if (mesh.GetDimension() == 3 || rational) @@ -770,8 +774,8 @@ namespace netgen } } - // MyMPI_ExchangeTable (senddata, recvdata, MPI_TAG_CURVE, comm); - comm.ExchangeTable (senddata, recvdata, MPI_TAG_CURVE); + // MyMPI_ExchangeTable (senddata, recvdata, NG_MPI_TAG_CURVE, comm); + comm.ExchangeTable (senddata, recvdata, NG_MPI_TAG_CURVE); NgArray cnt(ntasks); cnt = 0; @@ -801,8 +805,9 @@ namespace netgen if (surfnr[e] == -1) continue; SetThreadPercent(double(e)/surfnr.Size()*100.); - PointIndex pi1, pi2; - top.GetEdgeVertices (e+1, pi1, pi2); + // PointIndex pi1, pi2; + // top.GetEdgeVertices (e+1, pi1, pi2); + auto [pi1,pi2] = top.GetEdgeVertices(e); bool swap = (pi1 > pi2); Point<3> p1 = mesh[pi1]; @@ -975,8 +980,8 @@ namespace netgen } } - // MyMPI_ExchangeTable (senddata, recvdata, MPI_TAG_CURVE, comm); - comm.ExchangeTable (senddata, recvdata, MPI_TAG_CURVE); + // MyMPI_ExchangeTable (senddata, recvdata, NG_MPI_TAG_CURVE, comm); + comm.ExchangeTable (senddata, recvdata, NG_MPI_TAG_CURVE); NgArray cnt(ntasks); cnt = 0; @@ -1014,8 +1019,9 @@ namespace netgen SetThreadPercent(double(edgenr)/edge_surfnr1.Size()*100.); - PointIndex pi1, pi2; - top.GetEdgeVertices (edgenr+1, pi1, pi2); + // PointIndex pi1, pi2; + // top.GetEdgeVertices (edgenr+1, pi1, pi2); + auto [pi1,pi2] = top.GetEdgeVertices(edgenr); bool swap = swap_edge[edgenr]; // (pi1 > pi2); if (swap) Swap (pi1, pi2); @@ -1164,8 +1170,8 @@ namespace netgen } if (ntasks > 1) - // MyMPI_ExchangeTable (send_surfnr, recv_surfnr, MPI_TAG_CURVE, comm); - comm.ExchangeTable (send_surfnr, recv_surfnr, MPI_TAG_CURVE); + // MyMPI_ExchangeTable (send_surfnr, recv_surfnr, NG_MPI_TAG_CURVE, comm); + comm.ExchangeTable (send_surfnr, recv_surfnr, NG_MPI_TAG_CURVE); if (ntasks > 1 && working) { @@ -1187,9 +1193,10 @@ namespace netgen // if (el.GetType() == TRIG && order >= 3) if (top.GetFaceType(facenr+1) == TRIG && order >= 3) { - NgArrayMem verts(3); - top.GetFaceVertices (facenr+1, verts); - + // NgArrayMem verts(3); + // top.GetFaceVertices (facenr+1, verts); + auto verts = top.GetFaceVertices(facenr); + int fnums[] = { 0, 1, 2 }; /* if (el[fnums[0]] > el[fnums[1]]) swap (fnums[0], fnums[1]); @@ -1239,8 +1246,9 @@ namespace netgen int first = edgecoeffsindex[edgenrs[k]]; Vector eshape(eorder-1); - int vi1, vi2; - top.GetEdgeVertices (edgenrs[k]+1, vi1, vi2); + // int vi1, vi2; + // top.GetEdgeVertices (edgenrs[k]+1, vi1, vi2); + auto [vi1,vi2] = top.GetEdgeVertices(edgenrs[k]); if (vi1 > vi2) swap (vi1, vi2); int v1 = -1, v2 = -1; for (int j = 0; j < 3; j++) @@ -1270,7 +1278,7 @@ namespace netgen with MPI and an interior surface element between volume elements assigned to different procs, only one of them has the surf-el **/ - SurfaceElementIndex sei = top.GetFace2SurfaceElement (f+1)-1; + SurfaceElementIndex sei = top.GetFace2SurfaceElement(f); if (sei != SurfaceElementIndex(-1)) { PointGeomInfo gi = mesh[sei].GeomInfoPi(1); // use improved initial guess @@ -1658,12 +1666,21 @@ namespace netgen if (info.order > 1) { const MeshTopology & top = mesh.GetTopology(); - + + /* top.GetSurfaceElementEdges (elnr+1, info.edgenrs); for (int i = 0; i < info.edgenrs.Size(); i++) info.edgenrs[i]--; - info.facenr = top.GetSurfaceElementFace (elnr+1)-1; - + */ + /* + auto edgs = top.GetEdges(SurfaceElementIndex(elnr)); + info.edgenrs.SetSize(edgs.Size()); + for (auto [i,nr] : Enumerate(edgs)) + info.edgenrs[i] = nr; + */ + info.SetEdges (top.GetEdges(SurfaceElementIndex(elnr))); + + info.facenr = top.GetFace(elnr); for (int i = 0; i < info.edgenrs.Size(); i++) info.ndof += edgecoeffsindex[info.edgenrs[i]+1] - edgecoeffsindex[info.edgenrs[i]]; info.ndof += facecoeffsindex[info.facenr+1] - facecoeffsindex[info.facenr]; @@ -1739,11 +1756,14 @@ namespace netgen if (info.order > 1) { const MeshTopology & top = mesh.GetTopology(); - + + /* top.GetSurfaceElementEdges (elnr+1, info.edgenrs); for (int i = 0; i < info.edgenrs.Size(); i++) info.edgenrs[i]--; - info.facenr = top.GetSurfaceElementFace (elnr+1)-1; + */ + info.SetEdges(top.GetEdges(SurfaceElementIndex(elnr))); + info.facenr = top.GetFace(elnr); bool firsttry = true; @@ -2430,7 +2450,7 @@ namespace netgen const HPRefElement & hpref_el = (*mesh.hpelements) [mesh[elnr].GetHpElnr()]; - return mesh.coarsemesh->GetCurvedElements().IsElementCurved (hpref_el.coarse_elnr); + return mesh.coarsemesh->GetCurvedElements().IsElementCurved (ElementIndex(hpref_el.coarse_elnr)); } const Element & el = mesh[elnr]; @@ -2482,7 +2502,7 @@ namespace netgen const HPRefElement & hpref_el = (*mesh.hpelements) [mesh[elnr].GetHpElnr()]; - return mesh.coarsemesh->GetCurvedElements().IsElementHighOrder (hpref_el.coarse_elnr); + return mesh.coarsemesh->GetCurvedElements().IsElementHighOrder (ElementIndex(hpref_el.coarse_elnr)); } const Element & el = mesh[elnr]; @@ -2546,7 +2566,8 @@ namespace netgen for (int j = 0; j < 3; j++) coarse_xi(j) += hpref_el.param[i][j] * lami[i]; - mesh.coarsemesh->GetCurvedElements().CalcElementTransformation (coarse_xi, hpref_el.coarse_elnr, x, &dxdxic /* , curved */); + mesh.coarsemesh->GetCurvedElements(). + CalcElementTransformation (coarse_xi, ElementIndex(hpref_el.coarse_elnr), x, &dxdxic /* , curved */); if (dxdxi) *dxdxi = dxdxic * trans; @@ -2787,15 +2808,20 @@ namespace netgen int vi1 = edges[i][0]-1, vi2 = edges[i][1]-1; if (el[vi1] > el[vi2]) swap (vi1, vi2); - T bubz = lamiz[vi1]*lamiz[vi2]; - T polyz = lamiz[vi1] - lamiz[vi2]; T bubxy = lami[vi1]; - + /* + T bubz = lamiz[vi1]*lamiz[vi2]; + T polyz = lamiz[vi1] - lamiz[vi2]; for (int j = 0; j < eorder-1; j++) { shapes(ii+j) = bubxy * bubz; bubz *= polyz; } + */ + CalcEdgeShape (eorder, lamiz[vi1]-lamiz[vi2], &shapes(ii)); + for (int j = 0; j < eorder-1; j++) + shapes(ii+j) *= bubxy; + ii += eorder-1; } } @@ -3029,8 +3055,8 @@ namespace netgen const Element & el = mesh[info.elnr]; // dshapes.SetSize(info.ndof); - if ( (long int)(&dshapes(0,0)) % alignof(T) != 0) - throw NgException ("alignment problem"); + // if ( (long int)(&dshapes(0,0)) % alignof(T) != 0) + // throw NgException ("alignment problem"); if (dshapes.Height() != info.ndof) throw NgException ("wrong height"); if (rational && info.order >= 2) @@ -3245,7 +3271,8 @@ namespace netgen int ii = 6; if (info.order == 1) return; - + + NgArrayMem hshapes(order+1), hdshapes(order+1); const ELEMENT_EDGE * edges = MeshTopology::GetEdges1 (PRISM); for (int i = 0; i < 6; i++) // horizontal edges @@ -3304,14 +3331,14 @@ namespace netgen int vi1 = (edges[i][0]-1), vi2 = (edges[i][1]-1); if (el[vi1] > el[vi2]) swap (vi1, vi2); - T bubz = lamiz[vi1] * lamiz[vi2]; - T dbubz = dlamiz[vi1]*lamiz[vi2] + lamiz[vi1]*dlamiz[vi2]; - T polyz = lamiz[vi1] - lamiz[vi2]; - T dpolyz = dlamiz[vi1] - dlamiz[vi2]; + // T bubz = lamiz[vi1] * lamiz[vi2]; + // T dbubz = dlamiz[vi1]*lamiz[vi2] + lamiz[vi1]*dlamiz[vi2]; + // T polyz = lamiz[vi1] - lamiz[vi2]; + // T dpolyz = dlamiz[vi1] - dlamiz[vi2]; T bubxy = lami[(vi1)%3]; T dbubxydx = dlami[(vi1)%3][0]; T dbubxydy = dlami[(vi1)%3][1]; - + /* for (int j = 0; j < eorder-1; j++) { dshapes(ii+j,0) = dbubxydx * bubz; @@ -3321,6 +3348,18 @@ namespace netgen dbubz = bubz * dpolyz + dbubz * polyz; bubz *= polyz; } + */ + + CalcEdgeShapeDx (eorder, lamiz[vi1]-lamiz[vi2], &hshapes[0], &hdshapes[0]); + for (int j = 0; j < eorder-1; j++) + { + dshapes(ii+j,0) = dbubxydx * hshapes[j]; + dshapes(ii+j,1) = dbubxydy * hshapes[j]; + dshapes(ii+j,2) = bubxy * hdshapes[j]; + } + + + ii += eorder-1; } } @@ -4165,11 +4204,14 @@ namespace netgen if (info.order > 1) { const MeshTopology & top = mesh.GetTopology(); - + + /* top.GetSurfaceElementEdges (elnr+1, info.edgenrs); for (int i = 0; i < info.edgenrs.Size(); i++) info.edgenrs[i]--; - info.facenr = top.GetSurfaceElementFace (elnr+1)-1; + */ + info.SetEdges(top.GetEdges(elnr)); + info.facenr = top.GetFace (elnr); bool firsttry = true; @@ -4327,7 +4369,7 @@ namespace netgen const double * xi, size_t sxi, double * x, size_t sx, double * dxdxi, size_t sdxdxi); - + template void CurvedElements :: CalcMultiPointSurfaceTransformation<2> (SurfaceElementIndex elnr, int npts, @@ -4557,7 +4599,7 @@ namespace netgen } mesh.coarsemesh->GetCurvedElements(). - CalcMultiPointElementTransformation (hpref_el.coarse_elnr, n, + CalcMultiPointElementTransformation (ElementIndex(hpref_el.coarse_elnr), n, &coarse_xi[0], 3, x, sx, dxdxi, sdxdxi); diff --git a/libsrc/meshing/curvedelems.hpp b/libsrc/meshing/curvedelems.hpp index 59fbb86d..91f6ce92 100644 --- a/libsrc/meshing/curvedelems.hpp +++ b/libsrc/meshing/curvedelems.hpp @@ -1,5 +1,5 @@ -#ifndef CURVEDELEMS -#define CURVEDELEMS +#ifndef NETGEN_CURVEDELEMS_HPP +#define NETGEN_CURVEDELEMS_HPP /**************************************************************************/ /* File: curvedelems.hpp */ @@ -8,11 +8,17 @@ /* Date: 27. Sep. 02, Feb 2006 */ /**************************************************************************/ +#include +#include +#include +#include "meshtype.hpp" +#include "meshclass.hpp" - +namespace netgen +{ class Refinement; - +class Mesh; class CurvedElements { @@ -33,7 +39,6 @@ class CurvedElements bool rational; bool ishighorder; - void buildJacPols(); public: DLL_HEADER CurvedElements (const Mesh & amesh); @@ -51,8 +56,6 @@ public: void DoArchive(Archive& ar) { - if(ar.Input()) - buildJacPols(); ar & edgeorder & faceorder & edgecoeffsindex & facecoeffsindex & edgecoeffs & facecoeffs & edgeweight & order & rational & ishighorder; } @@ -207,7 +210,7 @@ private: Mat<3> hdxdxi; Vec<3> hcoefs[10]; // enough for second order tets - void SetEdges (FlatArray edges) + void SetEdges (FlatArray edges) { nedges = edges.Size(); for (int i = 0; i < edges.Size(); i++) @@ -217,7 +220,7 @@ private: auto GetEdges() const { return FlatArray(nedges, edgenrs); } - void SetFaces (FlatArray faces) + void SetFaces (FlatArray faces) { nfaces = faces.Size(); for (int i = 0; i < faces.Size(); i++) @@ -246,6 +249,14 @@ private: int ndof; NgArrayMem edgenrs; int facenr; + + void SetEdges (FlatArray edges) + { + edgenrs.SetSize(edges.Size()); + for (int i = 0; i < edges.Size(); i++) + edgenrs[i] = edges[i]; + } + }; template @@ -259,6 +270,5 @@ private: bool EvaluateMapping (SurfaceElementInfo & info, const Point<2,T> xi, Point & x, Mat & jac) const; }; - - -#endif +} //namespace netgen +#endif // NETGEN_CURVEDELEMS_HPP diff --git a/libsrc/meshing/debugging.cpp b/libsrc/meshing/debugging.cpp index 949bb45c..feba17ab 100644 --- a/libsrc/meshing/debugging.cpp +++ b/libsrc/meshing/debugging.cpp @@ -1,8 +1,9 @@ #include +#include "debugging.hpp" namespace netgen { - unique_ptr GetOpenElements( const Mesh & m, int dom = 0 ) + unique_ptr GetOpenElements( const Mesh & m, int dom, bool only_quads ) { static Timer t("GetOpenElements"); RegionTimer rt(t); auto mesh = make_unique(); @@ -36,13 +37,14 @@ namespace netgen mesh->SetMaterial(2, "2_points"); mesh->SetMaterial(3, "3_points"); mesh->SetMaterial(4, "4_points"); - mesh->Compress(); mesh->ClearSurfaceElements(); for (auto & el : openelements) - mesh->AddSurfaceElement( el ); + if(!only_quads || el.GetNP() == 4) + mesh->AddSurfaceElement( el ); + mesh->Compress(); return mesh; } @@ -95,6 +97,127 @@ namespace netgen return mesh_ptr; } + void CheckMesh (const Mesh& mesh, MESHING_STEP step) + { + if (step == MESHCONST_OPTVOLUME) + { + bool have_error = false; + for (auto el : mesh.VolumeElements()) + { + double volume = el.Volume(mesh.Points()); + if (volume < 0) + { + have_error = true; + cout << "volume of element " << el << " is negative: " << volume << endl; + } + } + if (have_error) + throw Exception("Negative volume"); + CheckElementsAroundEdges(mesh); + } + } -} + void CheckElementsAroundEdges (const Mesh& mesh) + { + static Mesh last_good_mesh; + + Array> edges; + auto elementsonnode = mesh.CreatePoint2ElementTable(); + BuildEdgeList(mesh, elementsonnode, edges); + mesh.BoundaryEdge(1, 2); // trigger build of boundary edges + + ArrayMem hasbothpoints; + for (auto [pi0, pi1] : edges) + { + if (mesh.BoundaryEdge(pi0, pi1)) + continue; + + hasbothpoints.SetSize(0); + for (ElementIndex ei : elementsonnode[pi0]) + if (mesh[ei].PNums().Contains(pi1)) + hasbothpoints.Append(ei); + + bool skip = false; + for (ElementIndex ei : hasbothpoints) + { + if (mesh[ei].GetType() != TET) + { + skip = true; + break; + } + } + if (skip) + continue; + + int nsuround = hasbothpoints.Size(); + ArrayMem suroundpts(nsuround + 1); + suroundpts = PointIndex::INVALID; + ArrayMem tetused(nsuround); + tetused = false; + tetused[0] = true; + + auto el = mesh[hasbothpoints[0]]; + PointIndex pi2 = PointIndex::INVALID; + PointIndex pi3 = PointIndex::INVALID; + for (auto pi : el.PNums()) + if (pi != pi0 && pi != pi1) + { + pi3 = pi2; + pi2 = pi; + } + suroundpts[0] = pi2; + suroundpts[1] = pi3; + + for (auto i : Range(2, nsuround + 1)) + { + PointIndex oldpi = suroundpts[i - 1]; + PointIndex newpi = PointIndex::INVALID; + + for (int k = 0; k < nsuround && !newpi.IsValid(); k++) + if (!tetused[k]) + { + const Element& nel = mesh[hasbothpoints[k]]; + for (int k2 = 0; k2 < 4 && !newpi.IsValid(); k2++) + if (nel[k2] == oldpi) + { + newpi = nel[0] - pi0 + nel[1] - pi1 + nel[2] - oldpi + nel[3]; + tetused[k] = true; + suroundpts[i] = newpi; + + ArrayMem nelpts{nel[0], nel[1], nel[2], nel[3]}; + ArrayMem check_points{pi0, pi1, oldpi, newpi}; + QuickSort(check_points); + QuickSort(nelpts); + if (check_points != nelpts) + { + cout << __FILE__ << ":" << __LINE__ << "\tFound error" << endl; + cout << "i = " << i << endl; + cout << "oldpi = " << oldpi << endl; + cout << "newpi = " << newpi << endl; + cout << "Elements: " << endl; + cout << "nel " << nel << endl; + for (auto ei : hasbothpoints) + cout << mesh[ei] << endl; + cout << endl; + cout << "check_points: " << check_points << endl; + cout << "nelpts: " << nelpts << endl; + cout << "hasbothpoints: " << hasbothpoints << endl; + cout << "suroundpts: " << suroundpts << endl; + throw Exception("Found error"); + } + } + } + } + if (suroundpts.Last() != suroundpts[0]) + { + cout << __FILE__ << ":" << __LINE__ << "\tFound error" << endl; + cout << "hasbothpoints: " << hasbothpoints << endl; + cout << "suroundpts: " << suroundpts << endl; + for (auto ei : hasbothpoints) + cout << mesh[ei] << endl; + throw Exception("Found error"); + } + } + } +} // namespace netgen diff --git a/libsrc/meshing/debugging.hpp b/libsrc/meshing/debugging.hpp index 726fb203..722fffa0 100644 --- a/libsrc/meshing/debugging.hpp +++ b/libsrc/meshing/debugging.hpp @@ -1,12 +1,17 @@ -#include "meshclass.hpp" +#include "meshfunc.hpp" namespace netgen { - unique_ptr GetOpenElements( const Mesh & m, int dom = 0 ); + unique_ptr GetOpenElements( const Mesh & m, int dom = 0, bool only_quads = false ); unique_ptr FilterMesh( const Mesh & m, FlatArray points, FlatArray sels = Array{}, FlatArray els = Array{} ); + // Checks if the mesh is valid. This is called automatically on various places if debugparam.slowchecks is set + void CheckMesh( const Mesh & m, MESHING_STEP meshing_step ); - + // Sometimes during SwapImprove we discover topological errors in the mesh. For instance, an edge is adjacent to 8 tets around it, but + // the 8 "other" points of the tets don't form a closed path around the edge. Instead there are 2 sets of 4 points/tets each, which are not connected. + // This function checks for such errors and returns true if any are found. + void CheckElementsAroundEdges( const Mesh & m ); } diff --git a/libsrc/meshing/delaunay.cpp b/libsrc/meshing/delaunay.cpp index 349a021e..05541632 100644 --- a/libsrc/meshing/delaunay.cpp +++ b/libsrc/meshing/delaunay.cpp @@ -34,21 +34,19 @@ namespace netgen int NB(int i) const { return nb[i]; } - int FaceNr (INDEX_3 & face) const // which face nr is it ? + int FaceNr (const PointIndices<3> & face) const // which face nr is it ? { for (int i = 0; i < 3; i++) - if (pnums[i] != face.I1() && - pnums[i] != face.I2() && - pnums[i] != face.I3()) + if (pnums[i] != face[0] && pnums[i] != face[1] && pnums[i] != face[2]) return i; return 3; } - INDEX_3 GetFace (int i) const + PointIndices<3> GetFace (int i) const { - return INDEX_3 (pnums[deltetfaces[i][0]], - pnums[deltetfaces[i][1]], - pnums[deltetfaces[i][2]]); + return { pnums[deltetfaces[i][0]], + pnums[deltetfaces[i][1]], + pnums[deltetfaces[i][2]] }; } void GetFace (int i, Element2d & face) const @@ -374,10 +372,10 @@ namespace netgen } else { - INDEX_3 i3 = tempels.Get(helind).GetFace (k); - const Point<3> & p1 = mesh[PointIndex (i3.I1())]; - const Point<3> & p2 = mesh[PointIndex (i3.I2())]; - const Point<3> & p3 = mesh[PointIndex (i3.I3())]; + PointIndices<3> i3 = tempels.Get(helind).GetFace (k); + const Point<3> & p1 = mesh[i3[0]]; + const Point<3> & p2 = mesh[i3[1]]; + const Point<3> & p3 = mesh[i3[2]]; Vec<3> n = Cross (p2-p1, p3-p1); n /= n.Length(); @@ -564,7 +562,7 @@ namespace netgen - void Delaunay1 (Mesh & mesh, const MeshingParameters & mp, AdFront3 * adfront, + void Delaunay1 (Mesh & mesh, int domainnr, const MeshingParameters & mp, const AdFront3 & adfront, NgArray & tempels, int oldnp, DelaunayTet & startel, Point3d & pmin, Point3d & pmax) { @@ -575,7 +573,7 @@ namespace netgen Box<3> bbox(Box<3>::EMPTY_BOX); - for (auto & face : adfront->Faces()) + for (auto & face : adfront.Faces()) for (PointIndex pi : face.Face().PNums()) bbox.Add (mesh.Point(pi)); @@ -612,17 +610,27 @@ namespace netgen Array usep(np); usep = false; - for (auto & face : adfront->Faces()) + for (auto & face : adfront.Faces()) for (PointIndex pi : face.Face().PNums()) usep[pi] = true; - + + /* for (size_t i = oldnp + PointIndex::BASE; i < np + PointIndex::BASE; i++) + */ + for (auto i : mesh.Points().Range().Modify(oldnp, -4)) usep[i] = true; for (PointIndex pi : mesh.LockedPoints()) usep[pi] = true; + // mark points of free edge segments (no adjacent face) + for (auto & seg : mesh.LineSegments()) + if(seg.domin == domainnr && seg.domout == domainnr) + { + usep[seg[0]] = true; + usep[seg[1]] = true; + } NgArray freelist; @@ -666,7 +674,7 @@ namespace netgen IndexSet closesphere(mesh.GetNP()); // "random" reordering of points (speeds a factor 3 - 5 !!!) - NgArray mixed(np); + Array mixed(np); // int prims[] = { 11, 13, 17, 19, 23, 29, 31, 37 }; // int prims[] = { 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 }; int prims[] = { 211, 223, 227, 229, 233, 239, 241, 251, 257, 263 }; @@ -677,24 +685,25 @@ namespace netgen while (np % prims[i] == 0) i++; prim = prims[i]; } - + // for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End()-4; pi++) for (PointIndex pi : mesh.Points().Range().Modify(0, -4)) - mixed[pi] = PointIndex ( (prim * pi) % np + PointIndex::BASE ); + // mixed[pi] = PointIndex ( (prim * pi) % np + PointIndex::BASE ); + mixed[pi] = (prim * (pi-IndexBASE()+1)) % np + IndexBASE() ; Array newels; // for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End()-4; pi++) for (PointIndex pi : mesh.Points().Range().Modify(0, -4)) { - if (pi % 1000 == 0) + if ((pi-IndexBASE()) % 1000 == 0) { - if (pi % 10000 == 0) + if ((pi-IndexBASE()) % 10000 == 0) PrintDot ('+'); else PrintDot ('.'); } - multithread.percent = 100.0 * pi / np; + multithread.percent = 100.0 * (pi-IndexBASE()) / np; if (multithread.terminate) break; @@ -714,7 +723,7 @@ namespace netgen } for (int i = tempels.Size(); i >= 1; i--) - if (tempels.Get(i)[0] <= 0) + if (!tempels.Get(i)[0].IsValid()) tempels.DeleteElement (i); PrintDot ('\n'); @@ -740,7 +749,7 @@ namespace netgen { static Timer tdegenerated("Delaunay - remove degenerated"); RegionTimer rt(tdegenerated); - NgBitArray badnode(points.Size()); + TBitArray badnode(points.Size()); badnode.Clear(); int ndeg = 0; @@ -762,13 +771,15 @@ namespace netgen double h = v1.Length() + v2.Length() + v3.Length(); if (fabs (vol) < 1e-8 * (h * h * h) && - (el[0] <= np && el[1] <= np && - el[2] <= np && el[3] <= np) ) // old: 1e-12 + (el[0] < IndexBASE()+np && + el[1] < IndexBASE()+np && + el[2] < IndexBASE()+np && + el[3] < IndexBASE()+np) ) // old: 1e-12 { - badnode.Set(el[0]); - badnode.Set(el[1]); - badnode.Set(el[2]); - badnode.Set(el[3]); + badnode.SetBitAtomic(el[0]); + badnode.SetBitAtomic(el[1]); + badnode.SetBitAtomic(el[2]); + badnode.SetBitAtomic(el[3]); ndeg++; (*testout) << "vol = " << vol << " h = " << h << endl; } @@ -798,7 +809,7 @@ namespace netgen static Timer topenel("Delaunay - find openel"); RegionTimer rt(topenel); // find surface triangles which are no face of any tet - BitArray bnd_points( mesh.GetNP() + PointIndex::BASE ); + TBitArray bnd_points( mesh.GetNP() ); bnd_points.Clear(); for (int i = 1; i <= mesh.GetNOpenElements(); i++) @@ -840,16 +851,17 @@ namespace netgen tets_with_3_bnd_points.SetSize(cnt); static Timer t1("Build face table"); t1.Start(); - ngcore::ClosedHashTable< ngcore::INT<3>, int > face_table( 4*cnt + 3 ); - for(auto ei : tets_with_3_bnd_points) - for(auto j : Range(4)) + // ngcore::ClosedHashTable< ngcore::IVec<3>, int > face_table( 4*cnt + 3 ); + ngcore::ClosedHashTable< PointIndices<3>, int > face_table( 4*cnt + 3 ); + for (auto ei : tets_with_3_bnd_points) + for (auto j : Range(4)) { - auto i3_ = tempels[ei].GetFace (j); - ngcore::INT<3> i3 = {i3_[0], i3_[1], i3_[2]}; - if(bnd_points[i3[0]] && bnd_points[i3[1]] && bnd_points[i3[2]]) + PointIndices<3> i3 = tempels[ei].GetFace (j); + // ngcore::IVec<3> i3 = {i3_[0], i3_[1], i3_[2]}; + if(bnd_points[i3[0]] && bnd_points[i3[1]] && bnd_points[i3[2]]) { - i3.Sort(); - face_table.Set( i3, true ); + i3.Sort(); + face_table.Set( i3, true ); } } t1.Stop(); @@ -860,7 +872,8 @@ namespace netgen for (int i = 1; i <= mesh.GetNOpenElements(); i++) { const Element2d & tri = mesh.OpenElement(i); - ngcore::INT<3> i3(tri[0], tri[1], tri[2]); + // ngcore::IVec<3,PointIndex> i3(tri[0], tri[1], tri[2]); + PointIndices<3> i3(tri[0], tri[1], tri[2]); i3.Sort(); if(!face_table.Used(i3)) openels.Append(i); @@ -878,7 +891,7 @@ namespace netgen table.Add(tri[2], openel_i); }, mesh.GetNP()); - ngcore::BitArray badnode(mesh.GetNP()+PointIndex::BASE); + TBitArray badnode(mesh.GetNP()); badnode.Clear(); ngcore::ParallelForRange(openels.Size(), [&] (auto myrange) { @@ -912,7 +925,7 @@ namespace netgen { auto & tri_other = mesh.OpenElement(i_other); PointIndex pi2 = tri[(edge+2)%3]; - PointIndex pi3 = tri_other[0]+tri_other[1]+tri_other[2] - pi0 - pi1; + PointIndex pi3 = tri_other[0]-pi0+tri_other[1]-pi1+tri_other[2]; if(pi2>pi3) Swap(pi2, pi3); @@ -936,8 +949,8 @@ namespace netgen double h = v1.Length() + v2.Length() + v3.Length(); if (fabs (vol) < 1e-4 * (h * h * h)) // old: 1e-12 { - badnode.SetBitAtomic(pi2); - badnode.SetBitAtomic(pi3); + badnode.SetBitAtomic(pi2); + badnode.SetBitAtomic(pi3); } break; } @@ -1005,7 +1018,7 @@ namespace netgen for (int j = 0; j < 4; j++) { pp[j] = &mesh.Point(el[j]); - tetpi[j] = el[j]; + tetpi[j] = el[j]-IndexBASE()+1; } Point3d tetpmin(*pp[0]); @@ -1034,7 +1047,7 @@ namespace netgen for (int k = 1; k <= 3; k++) { tripp[k-1] = &mesh.Point (tri.PNum(k)); - tripi[k-1] = tri.PNum(k); + tripi[k-1] = tri.PNum(k)-IndexBASE()+1; } if (IntersectTetTriangle (&pp[0], &tripp[0], tetpi, tripi)) @@ -1077,7 +1090,7 @@ namespace netgen } } - void DelaunayRemoveOuter( const Mesh & mesh, NgArray & tempels, AdFront3 * adfront ) + void DelaunayRemoveOuter( const Mesh & mesh, NgArray & tempels, const AdFront3 & adfront ) { static Timer trem_outer("Delaunay - remove outer"); RegionTimer rt(trem_outer); @@ -1101,7 +1114,7 @@ namespace netgen */ for (const Element2d & tri : mesh.OpenElements()) { - INDEX_3 i3 (tri[0], tri[1], tri[2]); + PointIndices<3> i3 (tri[0], tri[1], tri[2]); i3.Sort(); boundaryfaces.PrepareSet (i3); } @@ -1109,7 +1122,7 @@ namespace netgen for (int i = 1; i <= mesh.GetNOpenElements(); i++) { const Element2d & tri = mesh.OpenElement(i); - INDEX_3 i3 (tri[0], tri[1], tri[2]); + PointIndices<3> i3 (tri[0], tri[1], tri[2]); i3.Sort(); boundaryfaces.Set (i3, 1); } @@ -1122,16 +1135,13 @@ namespace netgen for (auto & el : tempels) for (int j = 0; j < 4; j++) el.NB(j) = 0; - - TABLE elsonpoint(mesh.GetNP()); + /* - for (int i = 0; i < tempels.Size(); i++) - { - const DelaunayTet & el = tempels[i]; - */ + TABLE elsonpoint(mesh.GetNP()); + for (const DelaunayTet & el : tempels) { - INDEX_4 i4(el[0], el[1], el[2], el[3]); + PointIndices<4> i4(el[0], el[1], el[2], el[3]); i4.Sort(); elsonpoint.IncSizePrepare (i4.I1()); elsonpoint.IncSizePrepare (i4.I2()); @@ -1142,12 +1152,30 @@ namespace netgen for (int i = 0; i < tempels.Size(); i++) { const DelaunayTet & el = tempels[i]; - INDEX_4 i4(el[0], el[1], el[2], el[3]); + PointIndices<4> i4(el[0], el[1], el[2], el[3]); i4.Sort(); elsonpoint.Add (i4.I1(), i+1); elsonpoint.Add (i4.I2(), i+1); } + */ + TableCreator creator(mesh.GetNP()); + while (!creator.Done()) + { + for (int i = 0; i < tempels.Size(); i++) + { + const DelaunayTet & el = tempels[i]; + PointIndices<4> i4(el[0], el[1], el[2], el[3]); + i4.Sort(); + creator.Add (i4[0], i+1); + creator.Add (i4[1], i+1); + } + creator++; + } + auto elsonpoint = creator.MoveTable(); + + + // cout << "elsonpoint mem: "; // elsonpoint.PrintMemInfo(cout); @@ -1171,7 +1199,7 @@ namespace netgen if (hel[0] == pi) { - INDEX_3 i3(hel[0], hel[1], hel[2]); + PointIndices<3> i3(hel[0], hel[1], hel[2]); if (!boundaryfaces.Used (i3)) { @@ -1186,7 +1214,7 @@ namespace netgen { hel.Invert(); hel.NormalizeNumbering(); - INDEX_3 i3i(hel[0], hel[1], hel[2]); + PointIndices<3> i3i(hel[0], hel[1], hel[2]); INDEX_2 i2(i, j); faceht.Set (i3i, i2); } @@ -1270,7 +1298,7 @@ namespace netgen auto ne = tempels.Size(); - NgBitArray inner(ne), outer(ne); + BitArray inner(ne+1), outer(ne+1); inner.Clear(); outer.Clear(); NgArray elstack; @@ -1315,7 +1343,7 @@ namespace netgen Point3d ci = Center (p1, p2, p3, p4); - inside = adfront->Inside (ci); + inside = adfront.Inside (ci); /* cout << "startel: " << i << endl; @@ -1335,9 +1363,9 @@ namespace netgen if (!inner.Test(ei) && !outer.Test(ei)) { if (inside) - inner.Set(ei); + inner.SetBit(ei); else - outer.Set(ei); + outer.SetBit(ei); for (int j = 1; j <= 4; j++) @@ -1397,7 +1425,7 @@ namespace netgen // if (adfront->Inside (ci) != adfront->Inside (Center (ci, p1))) // cout << "ERROR: outer test unclear !!!" << endl; - if (inner.Test(i) != adfront->Inside (ci)) + if (inner.Test(i) != adfront.Inside (ci)) { /* cout << "ERROR: outer test wrong !!!" @@ -1425,10 +1453,10 @@ namespace netgen } - if (adfront->Inside(ci)) + if (adfront.Inside(ci)) outer.Clear(i); else - outer.Set(i); + outer.SetBit(i); } } @@ -1554,7 +1582,7 @@ namespace netgen int np = mesh.GetNP(); - Delaunay1 (mesh, mp, adfront, tempels, oldnp, startel, pmin, pmax); + Delaunay1 (mesh, domainnr, mp, *adfront, tempels, oldnp, startel, pmin, pmax); { // improve delaunay - mesh by swapping !!!! @@ -1625,10 +1653,13 @@ namespace netgen // tempmesh.Save ("tempmesh.vol"); { - MeshOptimize3d meshopt(mp); + MeshOptimize3d meshopt(tempmesh, mp); + meshopt.SetGoal(OPT_CONFORM); tempmesh.Compress(); tempmesh.FindOpenElements (); + #ifndef EMSCRIPTEN RegionTaskManager rtm(mp.parallel_meshing ? mp.nthreads : 0); + #endif // EMSCRIPTEN for (auto i : Range(10)) { PrintMessage (5, "Num open: ", tempmesh.GetNOpenElements()); @@ -1636,7 +1667,7 @@ namespace netgen if(i%5==0) tempmesh.FreeOpenElementsEnvironment (1); - meshopt.SwapImprove(tempmesh, OPT_CONFORM); + meshopt.SwapImprove(); } tempmesh.Compress(); } @@ -1654,7 +1685,7 @@ namespace netgen NgArray openels; DelaunayRemoveTwoTriaTets(mesh, tempels, openels); DelaunayRemoveIntersecting(mesh, tempels, openels, pmin, pmax); - DelaunayRemoveOuter(mesh, tempels, adfront); + DelaunayRemoveOuter(mesh, tempels, *adfront); for (int i = 0; i < tempels.Size(); i++) { diff --git a/libsrc/meshing/delaunay2d.cpp b/libsrc/meshing/delaunay2d.cpp index db6bcc71..bd0b974d 100644 --- a/libsrc/meshing/delaunay2d.cpp +++ b/libsrc/meshing/delaunay2d.cpp @@ -6,6 +6,7 @@ namespace netgen { + using namespace std; void DelaunayTrig::CalcCenter (FlatArray, PointIndex> points) { Point<2> p1 = points[pnums[0]]; @@ -37,7 +38,7 @@ namespace netgen if(p1 hash = {p0,p1}; + PointIndices<2> hash = {p0,p1}; auto pos = edge_to_trig.Position(hash); if (pos == -1) return -1; @@ -52,7 +53,7 @@ namespace netgen if(p1 hash = {p0,p1}; + PointIndices<2> hash = {p0,p1}; auto pos = edge_to_trig.Position(hash); if (pos == -1) edge_to_trig[hash] = {eli, -1}; @@ -79,7 +80,7 @@ namespace netgen if(p1 hash = {p0,p1}; + PointIndices<2> hash = {p0,p1}; auto pos = edge_to_trig.Position(hash); auto i2 = edge_to_trig.GetData(pos); @@ -92,7 +93,7 @@ namespace netgen } - void DelaunayMesh::AppendTrig( int pi0, int pi1, int pi2 ) + void DelaunayMesh::AppendTrig( PointIndex pi0, PointIndex pi1, PointIndex pi2 ) { DelaunayTrig el; el[0] = pi0; @@ -173,7 +174,8 @@ namespace netgen { const auto trig = trigs[i_trig]; - if(trig[0]==-1) + // if(trig[0]==-1) + if(!trig[0].IsValid()) continue; double rad2 = trig.Radius2(); @@ -253,9 +255,9 @@ namespace netgen const DelaunayTrig & trig = trigs[j]; for (int k = 0; k < 3; k++) { - int p1 = trig[k]; - int p2 = trig[(k+1)%3]; - INT<2> edge{p1,p2}; + PointIndex p1 = trig[k]; + PointIndex p2 = trig[(k+1)%3]; + PointIndices<2> edge{p1,p2}; edge.Sort(); bool found = false; for (int l = 0; l < edges.Size(); l++) @@ -308,9 +310,9 @@ namespace netgen for (int j : intersecting) { UnsetNeighbours(j); - trigs[j][0] = -1; - trigs[j][1] = -1; - trigs[j][2] = -1; + trigs[j][0] = PointIndex::INVALID; + trigs[j][1] = PointIndex::INVALID; + trigs[j][2] = PointIndex::INVALID; } for (auto edge : edges) @@ -330,7 +332,8 @@ namespace netgen for (DelaunayTrig & trig : trigs) { - if (trig[0] < 0) continue; + // if (trig[0] < 0) continue; + if (!trig[0].IsValid()) continue; Vec<3> n = Cross (P3(points[trig[1]])-P3(points[trig[0]]), P3(points[trig[2]])-P3(points[trig[0]])); @@ -426,7 +429,7 @@ namespace netgen } tcut.Stop(); - mesh.LocalHFunction().FindInnerBoxes (&adfront, NULL); + mesh.LocalHFunction().FindInnerBoxes (adfront, NULL); npoints.SetSize(0); mesh.LocalHFunction().GetInnerPoints (npoints); @@ -520,7 +523,7 @@ namespace netgen loch2.CutBoundary (bbox); } - loch2.FindInnerBoxes (&adfront, NULL); + loch2.FindInnerBoxes (adfront, NULL); // outer points : smooth mesh-grading npoints.SetSize(0); @@ -586,7 +589,7 @@ namespace netgen t2.Start(); Array old_points; - BitArray add_point(mesh.Points().Size()+1); + TBitArray add_point(mesh.Points().Size()+1); Array addpoints; add_point.Clear(); /* @@ -707,7 +710,8 @@ namespace netgen for (auto & trig : dmesh.GetElements()) { - if (trig[0] < 0) continue; + // if (trig[0] < 0) continue; + if (!trig[0].IsValid()) continue; Element2d el(trig[0], trig[1], trig[2]); el.SetIndex (1); @@ -718,7 +722,7 @@ namespace netgen while(!conforming) { conforming = true; - BitArray marked_points(tempmesh.Points().Size()+1); + TBitArray marked_points(tempmesh.Points().Size()+1); marked_points = false; // Check for trigs cutting a boundary edge (non-conforming mesh) auto point_to_trigs = tempmesh.CreatePoint2SurfaceElementTable( 0 ); @@ -775,7 +779,7 @@ namespace netgen auto & el0 = tempmesh[cutting_trigs[0]]; auto & el1 = tempmesh[cutting_trigs[1]]; - pi1 = el1[0]+el1[1]+el1[2] - pi2-pi3; + pi1 = el1[0]-pi2+el1[1]-pi3+el1[2]; if(marked_points.Test(pi1)) continue; @@ -800,16 +804,16 @@ namespace netgen // Mark edges and trigs as inside or outside, starting with boundary edges enum POSITION { UNKNOWN, BOUNDARY, INSIDE, OUTSIDE }; Array trig_pos(tempmesh.SurfaceElements().Size()); - ngcore::ClosedHashTable, POSITION> edge_pos(3*tempmesh.SurfaceElements().Size()); + ngcore::ClosedHashTable, POSITION> edge_pos(3*tempmesh.SurfaceElements().Size()); trig_pos = UNKNOWN; for (auto & seg : tempmesh.LineSegments()) { ArrayMem els; - INT<2> edge{seg[0], seg[1]}; + PointIndices<2> edge{seg[0], seg[1]}; edge.Sort(); edge_pos[edge] = BOUNDARY; - + for(auto sei : point_to_trigs[seg[0]]) for( auto i : Range(3)) if(tempmesh[sei][i] == seg[1]) @@ -818,7 +822,7 @@ namespace netgen for(auto sei : els) { auto & el = tempmesh[sei]; - PointIndex pi2 = el[0]+el[1]+el[2] - seg[0] - seg[1]; + PointIndex pi2 = el[0]-seg[0]+el[1]-seg[1]+el[2]; bool is_left = ::netgen::Area(P2(tempmesh[seg[0]]), P2(tempmesh[seg[1]]), P2(tempmesh[pi2]))>0.0; POSITION pos; @@ -827,8 +831,8 @@ namespace netgen else pos = OUTSIDE; - INT<2> e1{seg[0], pi2}; - INT<2> e2{seg[1], pi2}; + PointIndices<2> e1{seg[0], pi2}; + PointIndices<2> e2{seg[1], pi2}; e1.Sort(); e2.Sort(); if(!edge_pos.Used(e1)) @@ -856,7 +860,7 @@ namespace netgen // any edge of unknown trig already marked? for(auto i : IntRange(3)) { - INT<2> edge{el[(i+1)%3], el[(i+2)%3]}; + PointIndices<2> edge{el[(i+1)%3], el[(i+2)%3]}; edge.Sort(); if(edge_pos.Used(edge) && edge_pos[edge]!=BOUNDARY) { @@ -870,7 +874,7 @@ namespace netgen if(trig_pos[sei] != UNKNOWN) for(auto i : IntRange(3)) { - INT<2> edge{el[(i+1)%3], el[(i+2)%3]}; + PointIndices<2> edge{el[(i+1)%3], el[(i+2)%3]}; edge.Sort(); if(!edge_pos.Used(edge) || edge_pos[edge]==BOUNDARY) edge_pos[edge] = trig_pos[sei]; diff --git a/libsrc/meshing/delaunay2d.hpp b/libsrc/meshing/delaunay2d.hpp index 40f3b000..137c10f7 100644 --- a/libsrc/meshing/delaunay2d.hpp +++ b/libsrc/meshing/delaunay2d.hpp @@ -2,7 +2,6 @@ namespace netgen { - using ngcore::INT; static inline Point<2> P2( Point<3> p ) { @@ -23,7 +22,7 @@ namespace netgen double r; double rad2; DelaunayTrig () = default; - DelaunayTrig (int p1, int p2, int p3) + DelaunayTrig (PointIndex p1, PointIndex p2, PointIndex p3) { pnums[0] = p1; pnums[1] = p2; @@ -39,19 +38,19 @@ namespace netgen double Radius2() const { return rad2; } Box<2> BoundingBox() const { return Box<2> (c-Vec<2>(r,r), c+Vec<2>(r,r)); } - mutable PointIndex visited_pi = -1; + mutable PointIndex visited_pi = PointIndex::INVALID; // -1; }; class DelaunayMesh { - ngcore::ClosedHashTable, INT<2>> edge_to_trig; + ngcore::ClosedHashTable, IVec<2>> edge_to_trig; Array trigs; unique_ptr> tree; Array, PointIndex> & points; Array closeels; Array intersecting; - Array> edges; + Array> edges; int GetNeighbour( int eli, int edge ); @@ -59,7 +58,7 @@ namespace netgen void UnsetNeighbours( int eli ); - void AppendTrig( int pi0, int pi1, int pi2 ); + void AppendTrig( PointIndex pi0, PointIndex pi1, PointIndex pi2 ); public: DelaunayMesh( Array, PointIndex> & points_, Box<2> box ); diff --git a/libsrc/meshing/fieldlines.cpp b/libsrc/meshing/fieldlines.cpp index 84cf0a65..35dfa0fe 100644 --- a/libsrc/meshing/fieldlines.cpp +++ b/libsrc/meshing/fieldlines.cpp @@ -9,6 +9,25 @@ namespace netgen { + inline int GetVolElement(const Mesh& mesh, const Point<3>& p, + double* lami) + { + if(mesh.GetDimension() == 3) + { + auto ei = mesh.GetElementOfPoint(p, lami, true); + if(!ei.IsValid()) + return -1; + return ei; + } + else + { + auto ei = mesh.GetSurfaceElementOfPoint(p, lami, true); + if(!ei.IsValid()) + return -1; + return ei; + } + } + RKStepper :: ~RKStepper() { delete a; @@ -190,9 +209,9 @@ namespace netgen for(int i=0; i *pointsi, NgArray *facesi) + void GeomSearch3d :: Init (Array *pointsi, NgArray *facesi) { points = pointsi; faces = facesi; @@ -105,6 +106,12 @@ namespace netgen size.i1 = int (boxext.X()/midext.X()/hashelemsizefactor+1); size.i2 = int (boxext.Y()/midext.Y()/hashelemsizefactor+1); size.i3 = int (boxext.Z()/midext.Z()/hashelemsizefactor+1); + + int nfaces = faces->Size(); + size.i1 = min(size.i1, nfaces); + size.i2 = min(size.i2, nfaces); + size.i3 = min(size.i3, nfaces); + // PrintMessage (5, "hashsizes = ", size.i1, ", ", size.i2, ", ", size.i3); elemsize.X()=boxext.X()/size.i1; @@ -189,7 +196,7 @@ namespace netgen MinCoords(maxextreal,maxp); - int cluster = faces->Get(fstind).Cluster(); + PointIndex cluster = faces->Get(fstind).Cluster(); int sx = int((minp.X()-minext.X())/elemsize.X()+1.); int ex = int((maxp.X()-minext.X())/elemsize.X()+1.); @@ -199,9 +206,9 @@ namespace netgen int ez = int((maxp.Z()-minext.Z())/elemsize.Z()+1.); int ix,iy,iz,i,k; - int cnt1 = 0; // test, how efficient hashtable is - int cnt2 = 0; - int cnt3 = 0; + [[maybe_unused]] int cnt1 = 0; // test, how efficient hashtable is + [[maybe_unused]] int cnt2 = 0; + [[maybe_unused]] int cnt3 = 0; for (ix = sx; ix <= ex; ix++) { diff --git a/libsrc/meshing/geomsearch.hpp b/libsrc/meshing/geomsearch.hpp index 5adba567..858107de 100644 --- a/libsrc/meshing/geomsearch.hpp +++ b/libsrc/meshing/geomsearch.hpp @@ -1,5 +1,5 @@ -#ifndef FILE_GEOMSEARCH -#define FILE_GEOMSEARCH +#ifndef NETGEN_GEOMSEARCH_HPP +#define NETGEN_GEOMSEARCH_HPP /**************************************************************************/ /* File: geomsearch.hh */ @@ -7,6 +7,11 @@ /* Date: 19. Nov. 97 */ /**************************************************************************/ +#include "meshtype.hpp" + +namespace netgen +{ + class FrontPoint3; class FrontFace; class MiniElement2d; @@ -22,7 +27,7 @@ public: virtual ~GeomSearch3d(); /// - void Init (NgArray *pointsi, NgArray *facesi); + void Init (Array *pointsi, NgArray *facesi); ///get elements max extension void ElemMaxExt(Point3d& minp, Point3d& maxp, const MiniElement2d& elem); @@ -47,7 +52,7 @@ public: private: NgArray *faces; // Pointers to Arrays in Adfront - NgArray *points; + Array *points; NgArray *> hashtable; @@ -60,58 +65,5 @@ private: int reset; int hashcount; }; - -#endif - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} // namespace netgen +#endif // NETGEN_GEOMSEARCH_HPP diff --git a/libsrc/meshing/global.cpp b/libsrc/meshing/global.cpp index 9bbce766..bdde3046 100644 --- a/libsrc/meshing/global.cpp +++ b/libsrc/meshing/global.cpp @@ -1,11 +1,12 @@ #include -#include "meshing.hpp" +#include "global.hpp" #include - +#include "msghandler.hpp" +#include "meshtype.hpp" namespace netgen { - + class NetgenGeometry; class TraceGlobal { string name; diff --git a/libsrc/meshing/global.hpp b/libsrc/meshing/global.hpp index e19c094b..1ab2ad32 100644 --- a/libsrc/meshing/global.hpp +++ b/libsrc/meshing/global.hpp @@ -1,5 +1,5 @@ -#ifndef FILE_GLOBAL -#define FILE_GLOBAL +#ifndef NETGEN_GLOBAL_HPP +#define NETGEN_GLOBAL_HPP /**************************************************************************/ @@ -12,9 +12,11 @@ global functions and variables */ +#include + namespace netgen { - + using namespace ngcore; /// DLL_HEADER extern double GetTime (); DLL_HEADER extern void ResetTime (); @@ -47,6 +49,9 @@ namespace netgen DLL_HEADER extern volatile multithreadt multithread; + class DebugParameters; + class Mesh; + DLL_HEADER extern string ngdir; DLL_HEADER extern DebugParameters debugparam; DLL_HEADER extern bool verbose; @@ -61,6 +66,6 @@ namespace netgen // global communicator for netgen (dummy if no MPI) // extern DLL_HEADER NgMPI_Comm ng_comm; -} +} // namespace netgen -#endif +#endif // NETGEN_GLOBAL_HPP diff --git a/libsrc/meshing/hpref_hex.hpp b/libsrc/meshing/hpref_hex.hpp index 11e3f86e..00d10b20 100644 --- a/libsrc/meshing/hpref_hex.hpp +++ b/libsrc/meshing/hpref_hex.hpp @@ -54,6 +54,8 @@ HPRef_Struct refhex_1f_0e_0v = + + // HP_HEX_1FA_1FB ... face (1 - 4 - 3 -2) and face (1-2-6-5) singular int refhex_1fa_1fb_0e_0v_splitedges[][3] = { @@ -234,3 +236,95 @@ HPRef_Struct refhex_1fa_1fb_0e_0v = }; + + + + +// HP_HEX ... no refinement +int refhex7_splitedges[][3] = + { + { 0, 0, 0 } + }; +HPREF_ELEMENT_TYPE refhex7_newelstypes[] = + { + HP_HEX7, + HP_NONE, + }; +int refhex7_newels[][8] = + { + { 1, 2, 3, 4, 5, 6, 7 } + }; +HPRef_Struct refhex7 = + { + HP_HEX7, + refhex7_splitedges, + 0, 0, + refhex7_newelstypes, + refhex7_newels + }; + +// HP_HEX_1FA ... face (1 - 4 - 3 -2) singular +int refhex7_1fa_splitedges[][3] = + { + { 1, 5, 8 }, + { 2, 6, 9 }, + { 3, 7, 10 }, + { 4, 7, 11 }, + { 0, 0, 0 } + }; +HPREF_ELEMENT_TYPE refhex7_1fa_newelstypes[] = + { + HP_HEX_1F_0E_0V, + HP_HEX7, + HP_NONE, + }; +int refhex7_1fa_newels[][8] = + { + { 1, 2, 3, 4, 8, 9, 10, 11 }, + { 8, 9, 10, 11, 5, 6, 7 } + }; +HPRef_Struct refhex7_1fa = + { + HP_HEX7, + refhex7_1fa_splitedges, + 0, 0, + refhex7_1fa_newelstypes, + refhex7_1fa_newels + }; + + + + +// HP_HEX_1FB ... face (5,6,7) singular +int refhex7_1fb_splitedges[][3] = + { + { 5, 1, 8 }, + { 6, 2, 9 }, + { 7, 3, 10 }, + { 7, 4, 11 }, + { 0, 0, 0 } + }; +HPREF_ELEMENT_TYPE refhex7_1fb_newelstypes[] = + { + HP_HEX, + HP_HEX7_1FB, + HP_NONE, + }; +int refhex7_1fb_newels[][8] = + { + { 1, 2, 3, 4, 8, 9, 10, 11 }, + { 8, 9, 10, 11, 5, 6, 7 } + }; +HPRef_Struct refhex7_1fb = + { + HP_HEX7, + refhex7_1fb_splitedges, + 0, 0, + refhex7_1fb_newelstypes, + refhex7_1fb_newels + }; + + + + + diff --git a/libsrc/meshing/hpref_prism.hpp b/libsrc/meshing/hpref_prism.hpp index 3cceb44a..23b6f896 100644 --- a/libsrc/meshing/hpref_prism.hpp +++ b/libsrc/meshing/hpref_prism.hpp @@ -342,7 +342,7 @@ }; -// HP_PRISM_1FB_1EA_0V ... quad face 1-2-4-5 +// HP_PRISM_1FB_1EA_0V ... quad face 1-2-4-5, edge is 1-4 int refprism_1fb_1ea_0v_splitedges[][3] = { { 1, 3, 7 }, diff --git a/libsrc/meshing/hpref_pyramid.hpp b/libsrc/meshing/hpref_pyramid.hpp index 521daf50..ef51ccee 100644 --- a/libsrc/meshing/hpref_pyramid.hpp +++ b/libsrc/meshing/hpref_pyramid.hpp @@ -78,6 +78,42 @@ +// singular face 1-2-5 + // HP_PYRAMID_1FB_0E_0V + int refpyramid_1fb_0e_0v_splitedges[][3] = + { + { 1, 4, 6 }, + { 2, 3, 7 }, + { 5, 3, 8 }, + { 5, 4, 9 }, + { 0, 0, 0 }, + }; + + HPREF_ELEMENT_TYPE refpyramid_1fb_0e_0v_newelstypes[] = + { + HP_HEX7_1FB, + HP_PRISM, + HP_NONE, + }; + int refpyramid_1fb_0e_0v_newels[][8] = + { + { 6, 7, 8, 9, 1, 2, 5 }, + { 3, 7, 8, 4, 6, 9 }, + }; + HPRef_Struct refpyramid_1fb_0e_0v = + { + HP_PYRAMID, + refpyramid_1fb_0e_0v_splitedges, + 0, 0, + refpyramid_1fb_0e_0v_newelstypes, + refpyramid_1fb_0e_0v_newels + }; + + + + + + // singular face 1-2-5 singular point 5 // HP_PYRAMID_1FB_0E_1VA int refpyramid_1fb_0e_1va_splitedges[][3] = diff --git a/libsrc/meshing/hpref_tet.hpp b/libsrc/meshing/hpref_tet.hpp index df0e2af8..2fe0d06d 100644 --- a/libsrc/meshing/hpref_tet.hpp +++ b/libsrc/meshing/hpref_tet.hpp @@ -1,5 +1,210 @@ + + + + + + +enum VNUM { V1, V2, V3, V4, + E12, E13, E14, + E21, E23, E24, + E31, E32, E34, + E41, E42, E43, + F123, F124, F134, + F213, F214, F234, + F312, F314, F324, + F412, F413, F423 +}; + +class El +{ +public: + HPREF_ELEMENT_TYPE type; + std::vector vertices; + + El (HPREF_ELEMENT_TYPE atype, + std::vector avertices) + : type(atype), vertices(avertices) { } +}; + +extern std::map & GetHPRegistry(); + +template +class HPRefStruct : public HPRef_Struct +{ + typedef int int3[3]; + typedef int int4[4]; + typedef int int8[8]; + std::vector> refedges; + std::vector> reffaces; + std::vector neweltypes_vec; + std::vector> newelverts; + +public: + HPRefStruct(HPREF_ELEMENT_TYPE type, + std::vector list) + { + GetHPRegistry()[type] = this; + + geom = GEOM; + std::map mapnums; + int ii = 0; + for (auto v : { V1, V2, V3, V4}) + mapnums[v] = ++ii; + + for (auto el : list) + for (auto v : el.vertices) + if (mapnums.count(v)==0) + mapnums[v] = ++ii; + + int elist[][3] = + { { 1, 2, E12 }, + { 1, 3, E13 }, + { 1, 4, E14 }, + { 2, 1, E21 }, + { 2, 3, E23 }, + { 2, 4, E24 }, + { 3, 1, E31 }, + { 3, 2, E32 }, + { 3, 4, E34 }, + { 4, 1, E41 }, + { 4, 2, E42 }, + { 4, 3, E43 } + }; + int flist[][4] = + { { 1, 2, 3, F123 }, + { 1, 2, 4, F124 }, + { 1, 3, 4, F134 }, + { 2, 1, 3, F213 }, + { 2, 1, 4, F214 }, + { 2, 3, 4, F234 }, + { 3, 1, 2, F312 }, + { 3, 1, 4, F314 }, + { 3, 2, 4, F324 }, + { 4, 1, 2, F412 }, + { 4, 1, 3, F413 }, + { 4, 2, 3, F423 } + }; + + /* + // too advanced ... + for (auto [i1,i2,inew] : elist) + if (mapnums.count(VNUM(inew))) + refedges.push_back( { i1, i2, mapnums[VNUM(inew)] }); + */ + for (int i = 0; i < size(elist); i++) + { + int i1 = elist[i][0]; + int i2 = elist[i][1]; + int inew = elist[i][2]; + if (mapnums.count(VNUM(inew))) + refedges.push_back( { i1, i2, mapnums[VNUM(inew)] }); + } + + refedges.push_back( { 0, 0, 0 } ); + splitedges = (int3*) &refedges[0][0]; + + /* + // too advanced ... + for (auto [i1,i2,i3,inew] : flist) + if (mapnums.count(VNUM(inew))) + reffaces.push_back( { i1, i2, i3, mapnums[VNUM(inew)] }); + */ + for (int i = 0; i < size(flist); i++) + { + int i1 = flist[i][0]; + int i2 = flist[i][1]; + int i3 = flist[i][2]; + int inew = flist[i][3]; + if (mapnums.count(VNUM(inew))) + reffaces.push_back( { i1, i2, i3, mapnums[VNUM(inew)] }); + } + + + + reffaces.push_back( { 0, 0, 0 } ); + splitfaces = (int4*) &reffaces[0][0]; + + + + splitelements = nullptr; + + for (auto el : list) + { + neweltypes_vec.push_back (el.type); + std::array verts; + for (int j = 0; j < std::min(verts.size(), el.vertices.size()); j++) + verts[j] = mapnums[VNUM(el.vertices[j])]; + newelverts.push_back(verts); + } + + neweltypes_vec.push_back (HP_NONE); + + neweltypes = &neweltypes_vec[0]; + newels = (int8*) &newelverts[0][0]; + + /* + int ind = 0; + cout << "rule, split edges:" << endl; + while (splitedges[ind][0]) + { + cout << splitedges[ind][0] << "-" << splitedges[ind][1] << ": " << splitedges[ind][2] << endl; + ind++; + } + + ind = 0; + cout << "rule, split faces:" << endl; + while (splitfaces[ind][0]) + { + cout << splitfaces[ind][0] << "-" << splitfaces[ind][1] + << "-" << splitfaces[ind][2] << ": " << splitfaces[ind][3] << endl; + ind++; + } + + ind = 0; + cout << "rule, new els:" << endl; + while (neweltypes[ind] != HP_NONE) + { + cout << "new type " << neweltypes[ind] << ", verts: "; + for (int j = 0; j < 8; j++) + cout << newels[ind][j] << " "; + ind++; + } + */ + } +}; + + + + + +// HP_NONETET +int refnonetet_splitedges[][3] = +{ + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE refnonetet_newelstypes[] = +{ + HP_TET, + HP_NONE, +}; +int refnonetet_newels[][8] = +{ + { 1, 1, 1, 1 }, +}; +HPRef_Struct refnonetet = +{ + HP_TET, + refnonetet_splitedges, + 0, 0, + refnonetet_newelstypes, + refnonetet_newels +}; + + + + // HP_TET int reftet_splitedges[][3] = @@ -56,6 +261,16 @@ HPRef_Struct reftet_0e_1v = reftet_0e_1v_newels }; +/* + // new syntax ??? +HPRef_Struct2 str = + { + HP_TET_0E_1V, HP_TET, + El(HP_TET_0E_1V, { V1, V12, V13, V14 }) + }; +*/ + + // HP_TET_0E_2V @@ -2858,6 +3073,77 @@ HPRef_Struct reftet_3ec_2v = +// HP_TET_3ED_3V, +int reftet_3ed_3v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 1, 4, 7 }, + { 2, 1, 8 }, + { 2, 3, 9 }, + { 2, 4, 10 }, + { 3, 1, 11 }, + { 3, 2, 12 }, + { 3, 4, 13 }, + { 0, 0, 0 } +}; +int reftet_3ed_3v_splitfaces[][4] = + { + { 1, 2, 3, 14 }, + { 2, 3, 1, 15 }, + { 3, 1, 2, 16 }, + { 0, 0, 0, 0 } + }; +int reftet_3ed_3v_splitelements[][5] = + { + { 0 }, + }; + +HPREF_ELEMENT_TYPE reftet_3ed_3v_newelstypes[] = + { + HP_TET, + HP_PRISM, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_NONE, + }; +int reftet_3ed_3v_newels[][8] = +{ + { 7, 10, 13, 4 }, + { 14, 15, 16, 7, 10, 13 }, + { 5, 14, 7, 8, 15, 10 }, + { 9, 15, 10, 12, 16, 13 }, + { 11, 16, 13, 6, 14, 7 }, + { 1, 5, 14, 7 }, + { 1, 6, 7, 14 }, + { 2, 8, 10, 15 }, + { 2, 9, 15, 10 }, + { 3, 12, 13, 16 }, + { 3, 11, 16, 13 } +}; + +HPRef_Struct reftet_3ed_3v = +{ + HP_TET, + reftet_3ed_3v_splitedges, + reftet_3ed_3v_splitfaces, + reftet_3ed_3v_splitelements, + reftet_3ed_3v_newelstypes, + reftet_3ed_3v_newels +}; + + + + + + @@ -2897,7 +3183,7 @@ HPRef_Struct reftet_1f_0e_0v = - +/* // HP_TET_1F_0E_1VA ... singular vertex in face int reftet_1f_0e_1va_splitedges[][3] = { @@ -2910,14 +3196,16 @@ int reftet_1f_0e_1va_splitedges[][3] = }; HPREF_ELEMENT_TYPE reftet_1f_0e_1va_newelstypes[] = { - HP_HEX_1F_0E_0V, + // HP_HEX_1F_0E_0V, + HP_HEX7_1FA, HP_TET_1F_0E_1VA, HP_TET, HP_NONE, }; int reftet_1f_0e_1va_newels[][8] = { - { 3, 6, 7, 4, 8, 5, 5, 9 }, + // { 3, 6, 7, 4, 8, 5, 5, 9 }, + { 4, 3, 6, 7, 9, 8, 5 }, { 5, 2, 6, 7 }, { 5, 9, 8, 1 }, }; @@ -2929,8 +3217,18 @@ HPRef_Struct reftet_1f_0e_1va = reftet_1f_0e_1va_newelstypes, reftet_1f_0e_1va_newels }; +*/ +HPRefStruct reftet_1f_0e_1va + { + HP_TET_1F_0E_1VA, + { + El(HP_HEX7_1FA, { V4, V3, E23, E24, E41, E31, E21 }), + El(HP_TET_1F_0E_1VA, { E21, V2, E23, E24 }), + El(HP_TET, { E21, E41, E31, V1 }) + } + }; @@ -2973,6 +3271,78 @@ HPRef_Struct reftet_1f_0e_1vb = +// HP_TET_1F_0E_2V ... face 234, sing verts v2,v3 +int reftet_1f_0e_2v_splitedges[][3] = +{ + { 2, 1, 5 }, + { 2, 3, 6 }, + { 2, 4, 7 }, + { 3, 1, 8 }, + { 3, 2, 9 }, + { 3, 4, 10 }, + { 4, 1, 11 }, + { 0, 0, 0 } +}; +HPREF_ELEMENT_TYPE reftet_1f_0e_2v_newelstypes[] = +{ + HP_TET_0E_1V, + HP_PRISM_1FA_0E_0V, + HP_PRISM_1FB_0E_0V, + HP_TET_1F_0E_1VA, + HP_TET_1F_0E_1VA, + HP_NONE, +}; +int reftet_1f_0e_2v_newels[][8] = +{ + { 1, 5, 8, 11 }, + { 4, 10, 7, 11, 8, 5 }, + { 9, 10, 8, 6, 7, 5 }, + { 5, 2, 6, 7 }, + { 8, 3, 10, 9 } +}; +HPRef_Struct reftet_1f_0e_2v = +{ + HP_TET, + reftet_1f_0e_2v_splitedges, + 0, 0, + reftet_1f_0e_2v_newelstypes, + reftet_1f_0e_2v_newels +}; + + + + + + + + +HPRefStruct reftet_1f_0e_3v + { + HP_TET_1F_0E_3V, + { + El(HP_TET, { V1, E21, E31, E41 }), + El(HP_PRISM_1FA_0E_0V, { F234, F423, F324, E21, E41, E31 }), + El(HP_PRISM_1FB_1EA_0V, { E32, F324, E31, E23, F234, E21 }), + El(HP_PRISM_1FB_1EA_0V, { E43, F423, E41, E34, F324, E31 }), + El(HP_PRISM_1FB_1EA_0V, { E24, F234, E21, E42, F423, E41 }), + El(HP_TET_1F_0E_0V, { E21, E24, E23, F234 }), + El(HP_TET_1F_0E_1VA, { E21, V2, E23, E24 }), + El(HP_TET_1F_0E_0V, { E31, E32, E34, F324 }), + El(HP_TET_1F_0E_1VA, { E31, V3, E34, E32 }), + El(HP_TET_1F_0E_0V, { E41, E43, E42, F423 }), + El(HP_TET_1F_0E_1VA, { E41, V4, E42, E43 }), + } + }; + + + + + + + + + + // HP_TET_1F_1EA_0V ... sing edge is 1..2 int reftet_1f_1ea_0v_splitedges[][3] = @@ -3072,6 +3442,423 @@ HPRef_Struct reftet_1f_1eb_0v = +// HP_TET_1F_1E_1VA // 1 sing edge in face e23, sing vert 2 +int reftet_1f_1e_1va_splitedges[][3] = +{ + { 2, 1, 5 }, + { 2, 3, 10 }, + { 2, 4, 6 }, + { 3, 1, 7 }, + { 3, 4, 8 }, + { 4, 1, 9 }, + { 0, 0, 0 } +}; + +HPREF_ELEMENT_TYPE reftet_1f_1e_1va_newelstypes[] = +{ + HP_PRISM_1FB_1EA_0V, + HP_PRISM_1FA_0E_0V, + HP_TET, + HP_TET_1F_1E_1VA, + HP_NONE, +}; +int reftet_1f_1e_1va_newels[][8] = +{ + { 3, 8, 7, 10, 6, 5 }, + { 6, 4, 8, 5, 9, 7 }, + { 5, 9, 7, 1}, + { 5, 2, 10, 6 } +}; +HPRef_Struct reftet_1f_1e_1va = +{ + HP_TET, + reftet_1f_1e_1va_splitedges, + 0, 0, + reftet_1f_1e_1va_newelstypes, + reftet_1f_1e_1va_newels +}; + + + + + + + +// HP_TET_1F_1E_1VB // 1 sing edge in face e24, sing vert 2 +int reftet_1f_1e_1vb_splitedges[][3] = +{ + { 2, 1, 5 }, + { 2, 3, 6 }, + { 2, 4, 7 }, + { 3, 1, 8 }, + { 4, 1, 9 }, + { 4, 3, 10 }, + { 0, 0, 0 } +}; + +HPREF_ELEMENT_TYPE reftet_1f_1e_1vb_newelstypes[] = +{ + HP_PRISM_1FB_1EA_0V, + HP_PRISM_1FA_0E_0V, + HP_TET, + HP_TET_1F_1E_1VB, + HP_NONE, +}; +int reftet_1f_1e_1vb_newels[][8] = +{ + { 4, 9, 10, 7, 5, 6 }, + { 3, 6, 10, 8, 5, 9 }, + { 5, 9, 8, 1}, + { 5, 2, 6, 7 } +}; +HPRef_Struct reftet_1f_1e_1vb = +{ + HP_TET, + reftet_1f_1e_1vb_splitedges, + 0, 0, + reftet_1f_1e_1vb_newelstypes, + reftet_1f_1e_1vb_newels +}; + + + + + + + + + + + + +// HP_TET_1F_1E_2VA // 1 sing edge not in face (e12), sing v2,v3 +int reftet_1f_1e_2va_splitedges[][3] = +{ + { 1, 3, 5 }, + { 1, 4, 6 }, + { 2, 1, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 3, 1, 10 }, + { 3, 2, 11 }, + { 3, 4, 12 }, + { 4, 1, 13 }, + { 0, 0, 0 } +}; + +int reftet_1f_1e_2va_splitfaces[][4] = + { + { 2, 1, 3, 14 }, + { 2, 1, 4, 15 }, + { 0, 0, 0, 0 } + }; + + +HPREF_ELEMENT_TYPE reftet_1f_1e_2va_newelstypes[] = +{ + HP_PRISM, + HP_PRISM_SINGEDGE, + HP_PRISM_1FB_0E_0V, + HP_TET_1F_0E_1VA, + HP_TET_1F_0E_1VA, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_HEX7_1FB, + HP_NONE, +}; +int reftet_1f_1e_2va_newels[][8] = +{ + { 5, 14, 10, 6, 15, 13 }, + { 1, 5, 6, 7, 14, 15 }, + { 8, 14, 9, 11, 10, 12 }, + { 10, 3, 12, 11 }, + { 14, 2, 8, 9 }, + { 2, 7, 15, 14 }, + { 2, 9, 14, 15 }, + // { 13, 10, 14, 15, 4, 12, 9 } + { 10, 13, 15, 14, 12, 4, 9 } +}; +HPRef_Struct reftet_1f_1e_2va = +{ + HP_TET, + reftet_1f_1e_2va_splitedges, + reftet_1f_1e_2va_splitfaces, + 0, + reftet_1f_1e_2va_newelstypes, + reftet_1f_1e_2va_newels +}; + + + + + +// HP_TET_1F_1E_2VB // 1 sing edge not in face (e12), sing v2,v4 +int reftet_1f_1e_2vb_splitedges[][3] = +{ + { 1, 3, 5 }, + { 1, 4, 6 }, + { 2, 1, 7 }, + { 2, 3, 8 }, + { 2, 4, 9 }, + { 3, 1, 10 }, + { 4, 1, 11 }, + { 4, 2, 12 }, + { 4, 3, 13 }, + { 0, 0, 0 } +}; + +int reftet_1f_1e_2vb_splitfaces[][4] = + { + { 2, 1, 3, 14 }, + { 2, 1, 4, 15 }, + { 0, 0, 0, 0 } + }; + + +HPREF_ELEMENT_TYPE reftet_1f_1e_2vb_newelstypes[] = +{ + HP_PRISM, + HP_PRISM_SINGEDGE, + HP_PRISM_1FB_0E_0V, + HP_TET_1F_0E_1VA, + HP_TET_1F_0E_1VA, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_HEX7_1FB, + HP_NONE, + +}; +int reftet_1f_1e_2vb_newels[][8] = +{ + { 5, 14, 10, 6, 15, 11 }, + { 1, 5, 6, 7, 14, 15 }, + { 8, 15, 9, 13, 11, 12 }, + { 11, 4, 12, 13 }, + { 15, 2, 8, 9 }, + { 2, 7, 15, 14 }, + { 2, 8, 14, 15 }, + { 10, 11, 15, 14, 3, 13, 8 } +}; +HPRef_Struct reftet_1f_1e_2vb = +{ + HP_TET, + reftet_1f_1e_2vb_splitedges, + reftet_1f_1e_2vb_splitfaces, + 0, + reftet_1f_1e_2vb_newelstypes, + reftet_1f_1e_2vb_newels +}; + + + + + + +// HP_TET_1F_1EA_3V +HPRefStruct reftet_1f_1ea_3v + { + HP_TET_1F_1EA_3V, + { + El(HP_PRISM, { E14, E41, F214, E13, E31, F213 }), + El(HP_PRISM_SINGEDGE, { V1, E13, E14, E21, F213, F214 }), + El(HP_HEX7_1FB, { E31, E41, F214, F213, F324, F423, F234 }), + El(HP_PRISM_1FB_0E_0V, { F234, E23, F213, F324, E32, E31 }), + El(HP_PRISM_1FB_0E_0V, { F423, E42, E41, F234, E24, F214 }), + El(HP_PRISM_1FB_0E_0V, { F324, E34, E31, F423, E43, E41 }), + El(HP_TET_1F_0E_0V, { E31, E32, E34, F324 }), + El(HP_TET_1F_0E_1VA, { E31, V3, E34, E32 }), + + El(HP_TET_1F_0E_0V, { E41, E43, E42, F423 }), + El(HP_TET_1F_0E_1VA, { E41, V4, E42, E43 }), + El(HP_PYRAMID_1FB_0E_0V, { E24, E23, F213, F214, F234 }), // needs check + El(HP_PYRAMID_1FB_0E_1VA, { E23, E24, F214, F213, V2 }), + El(HP_TET_1E_1VA, { V2, E21, F214, F213 }), + } + }; + + + +// HP_TET_1F_1E_3V e4 (E23), V2, V3, V4 +HPRefStruct reftet_1f_1e_3v + { + HP_TET_1F_1E_3V, + { + El(HP_TET, { V1, E21, E31, E41 }), + El(HP_HEX7_1FA, { E34, E24, E42, E43, E31, E21, E41 }), + El(HP_PRISM_1FB_1EA_0V, { E32, E34, E31, E23, E24, E21 }), + El(HP_TET_1F_0E_1VA, { E41, V4, E42, E43 }), + El(HP_TET_1F_1E_1VB, { E21, V2, E23, E24 }), + El(HP_TET_1F_1E_1VA, { E31, V3, E34, E32 }), + } + }; + + + +HPRefStruct reftet_1f_2eoo_3v + { + HP_TET_1F_2Eoo_3V, + { + El(HP_TET, { E14, E41, F214, F314 }), + El(HP_PRISM_1FA_0E_0V, { V4, E34, E24, E41, F314, F214 }), + El(HP_PRISM, { F123, F213, F312, E14, F214, F314 }), + El(HP_PRISM_SINGEDGE, { E12, F123, E14, E21, F213, F214 }), + El(HP_PRISM_SINGEDGE, { E13, E14, F123, E31, F314, F312 }), + El(HP_HEX_1F_0E_0V, { E32, E23, E24, E34, F312, F213, F214, F314 }), + El(HP_TET_1E_1VA, { V1, E12, F123, E14 }), + El(HP_TET_1E_1VA, { V1, E13, E14, F123 }), + El(HP_PYRAMID_1FB_0E_1VA, { E34, E32, F312, F314, V3 }), + El(HP_PYRAMID_1FB_0E_1VA, { E23, E24, F214, F213, V2 }), + El(HP_TET_1E_1VA, { V2, E21, F214, F213 }), + El(HP_TET_1E_1VA, { V3, E31, F312, F314 }), + + } + }; + +// HP_TET_1F_2E_0VA singular edge in face 234 is 34, and edge not in face is 14 +int reftet_1f_2e_0va_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 2, 1, 7 }, + { 3, 1, 8 }, + { 3, 2, 9 }, + { 4, 1, 10 }, + { 4, 2, 11 }, + { 4, 3, 12 }, + { 0, 0, 0 } +}; + +int reftet_1f_2e_0va_splitfaces[][4] = +{ + { 4, 1, 2, 13 }, + { 4, 1, 3, 14 }, + { 0, 0, 0, 0 } +}; + +HPREF_ELEMENT_TYPE reftet_1f_2e_0va_newelstypes[] = +{ + HP_PRISM, + HP_PRISM_SINGEDGE, + HP_HEX7_1FB, + HP_PRISM_1FB_1EA_0V, + HP_TET_1F_1E_1VA, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_NONE, +}; +int reftet_1f_2e_0va_newels[][8] = +{ + { 6, 8, 14, 5, 7, 13 }, + { 1, 5, 6, 10, 13, 14 }, + { 7, 8, 14, 13, 2, 9, 11 }, + { 3, 8, 9, 12, 14, 11 }, + { 14, 4, 11, 12 }, + { 4, 11, 13, 14 }, + { 4, 10, 14, 13 } +}; +HPRef_Struct reftet_1f_2e_0va = +{ + HP_TET, + reftet_1f_2e_0va_splitedges, + reftet_1f_2e_0va_splitfaces, + 0, + reftet_1f_2e_0va_newelstypes, + reftet_1f_2e_0va_newels +}; + + + + + +// HP_TET_1F_2E_0VB singular edge in face 234 is 34, and edge not in face is 13 +int reftet_1f_2e_0vb_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 4, 6 }, + { 2, 1, 7 }, + { 3, 1, 8 }, + { 3, 2, 9 }, + { 3, 4, 10 }, + { 4, 1, 11 }, + { 4, 2, 12 }, + { 0, 0, 0 } +}; + +int reftet_1f_2e_0vb_splitfaces[][4] = +{ + { 3, 1, 2, 13 }, + { 3, 1, 4, 14 }, + { 0, 0, 0, 0 } +}; + +HPREF_ELEMENT_TYPE reftet_1f_2e_0vb_newelstypes[] = +{ + HP_PRISM, + HP_PRISM_SINGEDGE, + HP_HEX7_1FB, + HP_PRISM_1FB_1EA_0V, + HP_TET_1F_1E_1VA, + HP_TET_1E_1VA, + HP_TET_1E_1VA, + HP_NONE, +}; +int reftet_1f_2e_0vb_newels[][8] = +{ + { 6, 14, 11, 5, 13, 7 }, + { 1, 6, 5, 8, 14, 13 }, + { 11, 7, 13, 14, 12, 2, 9 }, + { 4, 12, 11, 10, 9, 14 }, + { 14, 3, 10, 9 }, + { 3, 8, 13, 14 }, + { 3, 9, 14, 13 } +}; +HPRef_Struct reftet_1f_2e_0vb = +{ + HP_TET, + reftet_1f_2e_0vb_splitedges, + reftet_1f_2e_0vb_splitfaces, + 0, + reftet_1f_2e_0vb_newelstypes, + reftet_1f_2e_0vb_newels +}; + + + + + +// HP_TET_1F_2E_1V e4,e5 (E23,E24), V2 +HPRefStruct reftet_1f_2e_1v + { + HP_TET_1F_2E_1V, + { + El(HP_TET, { V1, E21, E31, E41 }), + El(HP_PRISM_1FA_0E_0V, { F234, E43, E34, E21, E41, E31 }), + El(HP_PRISM_1FB_1EA_0V, { V3, E34, E31, E23, F234, E21 }), + El(HP_PRISM_1FB_1EA_0V, { E24, F234, E21, V4, E43, E41 }), + El(HP_TET_1F_1E_1VA, { E21, V2, E23, F234 }), + El(HP_TET_1F_1E_1VB, { E21, V2, F234, E24 }), + } + }; + + + +// HP_TET_1F_2E_3V e4,e5 (E23,E24), V2, V3, V4 +HPRefStruct reftet_1f_2e_3v + { + HP_TET_1F_2E_3V, + { + El(HP_TET, { V1, E21, E31, E41 }), + El(HP_PRISM_1FA_0E_0V, { F234, E43, E34, E21, E41, E31 }), + El(HP_PRISM_1FB_1EA_0V, { E32, E34, E31, E23, F234, E21 }), + El(HP_PRISM_1FB_1EA_0V, { E24, F234, E21, E42, E43, E41 }), + El(HP_TET_1F_1E_1VA, { E21, V2, E23, F234 }), + El(HP_TET_1F_1E_1VB, { E21, V2, F234, E24 }), + El(HP_TET_1F_1E_1VA, { E31, V3, E34, E32 }), + El(HP_TET_1F_1E_1VB, { E41, V4, E42, E43 }), + } + }; + + @@ -3126,3 +3913,277 @@ HPRef_Struct reftet_2f_0e_0v = reftet_2f_0e_0v_newels }; + + + + +// HP_TET_2F_0E_1V +int reftet_2f_0e_1v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 2, 1, 6 }, + { 3, 1, 7 }, + { 3, 2, 8 }, + { 4, 1, 9 }, + { 4, 2, 10 }, + { 4, 3, 13 }, + { 0, 0, 0 } +}; + +int reftet_2f_0e_1v_splitfaces[][4] = + { + { 3, 1, 2, 11 }, + { 4, 1, 2, 12 }, + { 0, 0, 0, 0 } + }; + + +HPREF_ELEMENT_TYPE reftet_2f_0e_1v_newelstypes[] = +{ + HP_PRISM_1FA_0E_0V, + HP_PRISM_1FA_0E_0V, + HP_PRISM_1FB_1EA_0V, + HP_PRISM_1FB_1EA_0V, + HP_TET, + HP_TET_1F_1E_1VB, + HP_TET_1F_1E_1VA, + HP_NONE +}; +int reftet_2f_0e_1v_newels[][8] = +{ + { 2, 10, 8, 6, 12, 11 }, + { 1, 7, 9, 5, 11, 12 }, + // { 3, 11, 8, 4, 12, 10 }, + { 13, 10, 12, 3, 8, 11 }, + { 3, 7, 11, 13, 9, 12 }, + { 5, 6, 11, 12 }, + { 12, 4, 10, 13 }, + { 12, 4, 13, 9 } +}; +HPRef_Struct reftet_2f_0e_1v = +{ + HP_TET, + reftet_2f_0e_1v_splitedges, + reftet_2f_0e_1v_splitfaces, + 0, + reftet_2f_0e_1v_newelstypes, + reftet_2f_0e_1v_newels +}; + + + + + + + + +// HP_TET_2F_1E_0VA, // 2 singular faces, sing edge e4 +int reftet_2f_1e_0va_splitedges[][3] = +{ + { 1, 2, 5 }, + { 2, 1, 6 }, + { 2, 4, 7 }, + { 3, 1, 8 }, + { 3, 2, 9 }, + { 3, 4, 10 }, + { 4, 1, 11 }, + { 4, 2, 12 }, + { 0, 0, 0 } +}; + +int reftet_2f_1e_0va_splitfaces[][4] = + { + { 3, 2, 1, 13 }, + { 3, 2, 4, 14 }, + { 4, 1, 2, 15 }, + { 0, 0, 0, 0 } + }; + +HPREF_ELEMENT_TYPE reftet_2f_1e_0va_newelstypes[] = +{ + HP_TET, + HP_PRISM_1FA_0E_0V, + HP_PRISM_1FA_0E_0V, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_TET_1F_1E_1VA, + HP_TET_1F_1E_1VB, + HP_TET_1F_1E_1VB, + HP_NONE, +}; +int reftet_2f_1e_0va_newels[][8] = +{ + { 5, 6, 13, 15 }, + { 1, 8, 11, 5, 13, 15 }, + { 7, 12, 14, 6, 15, 13 }, + { 2, 6, 7, 9, 13, 14 }, + { 4, 15, 11, 10, 13, 8 }, + { 4, 12, 15, 10, 14, 13, }, + { 13, 3, 10, 14 }, + { 13, 3, 14, 9 }, + { 13, 3, 8, 10 }, +}; +HPRef_Struct reftet_2f_1e_0va = +{ + HP_TET, + reftet_2f_1e_0va_splitedges, + reftet_2f_1e_0va_splitfaces, + 0, + reftet_2f_1e_0va_newelstypes, + reftet_2f_1e_0va_newels +}; + + +// HP_TET_2F_1E_0VB = 602, // 2 singular faces f234,f134, sing edge e5=e24 +int reftet_2f_1e_0vb_splitedges[][3] = +{ + { 1, 2, 5 }, + { 2, 1, 6 }, + { 2, 3, 7 }, + { 3, 1, 8 }, + { 3, 2, 9 }, + { 4, 1, 10 }, + { 4, 2, 11 }, + { 4, 3, 12 }, + { 0, 0, 0 } +}; + +int reftet_2f_1e_0vb_splitfaces[][4] = + { + { 4, 2, 3, 13 }, + { 4, 1, 2, 14 }, + { 3, 1, 2, 15 }, + { 0, 0, 0, 0 } + }; + +HPREF_ELEMENT_TYPE reftet_2f_1e_0vb_newelstypes[] = +{ + HP_TET, + HP_PRISM_1FA_0E_0V, + HP_PRISM_1FA_0E_0V, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_PRISM_SINGEDGE, + HP_TET_1F_1E_1VA, + HP_TET_1F_1E_1VB, + HP_TET_1F_1E_1VB, + HP_NONE, +}; +int reftet_2f_1e_0vb_newels[][8] = +{ + { 5, 6, 15, 14 }, + { 1, 8, 10, 5, 15, 14 }, + { 7, 13, 9, 6, 14, 15 }, + { 2, 7, 6, 11, 13, 14 }, + { 3, 8, 15, 12, 10, 14 }, + { 3, 15, 9, 12, 14, 13 }, + { 14, 4, 11, 13 }, + { 14, 4, 13, 12 }, + { 14, 4, 12, 10 }, +}; + +HPRef_Struct reftet_2f_1e_0vb = +{ + HP_TET, + reftet_2f_1e_0vb_splitedges, + reftet_2f_1e_0vb_splitfaces, + 0, + reftet_2f_1e_0vb_newelstypes, + reftet_2f_1e_0vb_newels +}; + + +// HP_TET_3F_0E_0V = 610, // 3 singular faces, no additional points or edges +int reftet_3f_0e_0v_splitedges[][3] = +{ + { 1, 2, 5 }, + { 1, 3, 6 }, + { 2, 1, 7 }, + { 2, 3, 8 }, + { 3, 1, 9 }, + { 3, 2, 10 }, + { 4, 1, 11 }, + { 4, 2, 12 }, + { 4, 3, 13 }, + { 0, 0, 0 } +}; + +int reftet_3f_0e_0v_splitfaces[][4] = + { + { 1, 2, 3, 14 }, + { 2, 3, 1, 15 }, + { 3, 1, 2, 16 }, + { 4, 1, 2, 17 }, + { 4, 1, 3, 18 }, + { 4, 2, 3, 19 }, + { 0, 0, 0, 0 } + }; + +int reftet_3f_0e_0v_splitelements[][5] = + { + { 4, 1, 2, 3, 20 }, + { 0 } + }; +HPREF_ELEMENT_TYPE reftet_3f_0e_0v_newelstypes[] = +{ + HP_TET, + HP_PRISM_1FA_0E_0V, + HP_PRISM_1FA_0E_0V, + HP_PRISM_1FA_0E_0V, + + HP_PRISM_1FB_1EA_0V, + HP_PRISM_1FB_1EA_0V, + HP_PRISM_1FB_1EA_0V, + HP_PRISM_1FB_1EA_0V, + HP_PRISM_1FB_1EA_0V, + HP_PRISM_1FB_1EA_0V, + + HP_TET_1F_1E_1VA, // 1E_1VA + HP_TET_1F_0E_0V, + HP_TET_1F_0E_0V, // 1E_1VA + HP_TET_1F_0E_0V, // 1E_1VA + HP_TET_1F_0E_0V, // 1E_1VA + HP_TET_1F_0E_0V, // 1E_1VA + HP_NONE, +}; +int reftet_3f_0e_0v_newels[][8] = +{ + { 14, 15, 16, 20 }, + { 5, 17, 7, 14, 20, 15 }, + { 6, 9, 18, 14, 16, 20 }, + { 10, 8, 19, 16, 15, 20 }, + + { 1, 5, 14, 11, 17, 20 }, + { 11, 18, 20, 1, 6, 14 }, + { 2, 8, 15, 12, 19, 20 }, + { 12, 17, 20, 2, 7, 15 }, + { 3, 9, 16, 13, 18, 20 }, + { 13, 19, 20, 3, 10, 16 }, + + { 20, 4, 11, 17 }, + { 20, 4, 17, 12 }, + { 20, 4, 12, 19 }, + { 20, 4, 19, 13 }, + { 20, 4, 13, 18 }, + { 20, 4, 18, 11 } +}; +HPRef_Struct reftet_3f_0e_0v = +{ + HP_TET, + reftet_3f_0e_0v_splitedges, + reftet_3f_0e_0v_splitfaces, + reftet_3f_0e_0v_splitelements, + reftet_3f_0e_0v_newelstypes, + reftet_3f_0e_0v_newels +}; + + + + + + + +/* + +*/ diff --git a/libsrc/meshing/hpref_trig.hpp b/libsrc/meshing/hpref_trig.hpp index 3676ad0f..8c527c48 100644 --- a/libsrc/meshing/hpref_trig.hpp +++ b/libsrc/meshing/hpref_trig.hpp @@ -774,3 +774,75 @@ HPRef_Struct reftrig_3singedges = reftrig_3singedges_newelstypes, reftrig_3singedges_newels }; + +// HP_TRIG_ALFELD +int reftrig_Alfeld_splitedges[][3] = +{ + { 0, 0, 0 } +}; +int reftrig_Alfeld_splitfaces[][4] = +{ + { 1, 2, 3, 4 }, + { 0, 0, 0, 0 } +}; + +HPREF_ELEMENT_TYPE reftrig_Alfeld_newelstypes[] = +{ + HP_TRIG, HP_TRIG, HP_TRIG, + HP_NONE, +}; +int reftrig_Alfeld_newels[][8] = +{ + { 1, 2, 4 }, + { 2, 3, 4 }, + { 3, 1, 4 }, +}; +HPRef_Struct reftrig_Alfeld = +{ + HP_TRIG, + reftrig_Alfeld_splitedges, + reftrig_Alfeld_splitfaces, + 0, + reftrig_Alfeld_newelstypes, + reftrig_Alfeld_newels +}; + + +// HP_TRIG_POWELL +int reftrig_Powell_splitedges[][3] = +{ + { 1, 2, 4 }, + { 2, 3, 5 }, + { 3, 1, 6 }, + { 0, 0, 0 }, +}; +int reftrig_Powell_splitfaces[][4] = +{ + { 1, 2, 3, 7 }, + { 0, 0, 0, 0 } +}; + +HPREF_ELEMENT_TYPE reftrig_Powell_newelstypes[] = +{ + HP_TRIG, HP_TRIG, HP_TRIG, HP_TRIG, HP_TRIG, HP_TRIG, + HP_NONE, +}; +int reftrig_Powell_newels[][8] = +{ + { 1, 4, 7 }, + { 4, 2, 7 }, + { 2, 5, 7 }, + { 5, 3, 7 }, + { 3, 6, 7 }, + { 6, 1, 7 }, +}; +HPRef_Struct reftrig_Powell = +{ + HP_TRIG, + reftrig_Powell_splitedges, + reftrig_Powell_splitfaces, + 0, + reftrig_Powell_newelstypes, + reftrig_Powell_newels +}; + diff --git a/libsrc/meshing/hprefinement.cpp b/libsrc/meshing/hprefinement.cpp index d6819c44..b0353a59 100644 --- a/libsrc/meshing/hprefinement.cpp +++ b/libsrc/meshing/hprefinement.cpp @@ -1,6 +1,5 @@ #include #include "meshing.hpp" -#include "hprefinement.hpp" namespace netgen { @@ -120,12 +119,22 @@ namespace netgen param[k][l]=0.; } } - + + + std::map & GetHPRegistry()\ + { + static std::map registry; + return registry; + } HPRef_Struct * Get_HPRef_Struct (HPREF_ELEMENT_TYPE type) { HPRef_Struct * hps = NULL; - + /* + if (type >= 100 && type < 1000) + if (type != HP_TET_1F_0E_1VA) + type = HP_NONETET; + */ switch (type) { case HP_SEGM: @@ -174,7 +183,12 @@ namespace netgen case HP_TRIG_3SINGEDGES: hps = &reftrig_3singedges; break; - + case HP_TRIG_ALFELD: + hps = &reftrig_Alfeld; break; + case HP_TRIG_POWELL: + hps = &reftrig_Powell; break; + + case HP_QUAD: hps = &refquad; break; case HP_DUMMY_QUAD_SINGCORNER: @@ -287,6 +301,8 @@ namespace netgen case HP_TET: hps = &reftet; break; + case HP_NONETET: + hps = &refnonetet; break; case HP_TET_0E_1V: hps = &reftet_0e_1v; break; case HP_TET_0E_2V: @@ -373,22 +389,47 @@ namespace netgen hps = &reftet_3ec_1v; break; case HP_TET_3EC_2V: hps = &reftet_3ec_2v; break; + case HP_TET_3ED_3V: + hps = &reftet_3ed_3v; break; case HP_TET_1F_0E_0V: hps = &reftet_1f_0e_0v; break; - case HP_TET_1F_0E_1VA: - hps = &reftet_1f_0e_1va; break; + // case HP_TET_1F_0E_1VA: + // hps = &reftet_1f_0e_1va; break; case HP_TET_1F_0E_1VB: hps = &reftet_1f_0e_1vb; break; + case HP_TET_1F_0E_2V: + hps = &reftet_1f_0e_2v; break; + // case HP_TET_1F_0E_3V: + // hps = &reftet_1f_0e_3v; break; case HP_TET_1F_1EA_0V: hps = &reftet_1f_1ea_0v; break; case HP_TET_1F_1EB_0V: hps = &reftet_1f_1eb_0v; break; + case HP_TET_1F_1E_1VA: + hps = &reftet_1f_1e_1va; break; + case HP_TET_1F_1E_1VB: + hps = &reftet_1f_1e_1vb; break; + case HP_TET_1F_1E_2VA: + hps = &reftet_1f_1e_2va; break; + case HP_TET_1F_1E_2VB: + hps = &reftet_1f_1e_2vb; break; + case HP_TET_1F_2E_0VA: + hps = &reftet_1f_2e_0va; break; + case HP_TET_1F_2E_0VB: + hps = &reftet_1f_2e_0vb; break; case HP_TET_2F_0E_0V: hps = &reftet_2f_0e_0v; break; - - + case HP_TET_2F_0E_1V: + hps = &reftet_2f_0e_1v; break; + case HP_TET_2F_1E_0VA: + hps = &reftet_2f_1e_0va; break; + case HP_TET_2F_1E_0VB: + hps = &reftet_2f_1e_0vb; break; + case HP_TET_3F_0E_0V: + hps = &reftet_3f_0e_0v; break; + case HP_PRISM: hps = &refprism; break; case HP_PRISM_SINGEDGE: @@ -503,6 +544,8 @@ namespace netgen hps = &refpyramid_0e_1v; break; case HP_PYRAMID_EDGES: hps = &refpyramid_edges; break; + case HP_PYRAMID_1FB_0E_0V: + hps = &refpyramid_1fb_0e_0v; break; case HP_PYRAMID_1FB_0E_1VA: hps = &refpyramid_1fb_0e_1va; break; @@ -523,11 +566,21 @@ namespace netgen case HP_HEX_1FA_1FB_0E_0V: hps = &refhex_1fa_1fb_0e_0v; break; + case HP_HEX7: + hps = &refhex7; break; + case HP_HEX7_1FA: + hps = &refhex7_1fa; break; + case HP_HEX7_1FB: + hps = &refhex7_1fb; break; + default: { - hps = NULL; + if (GetHPRegistry().count(type)) + hps = GetHPRegistry()[type]; + else + hps = NULL; } } @@ -550,19 +603,21 @@ namespace netgen return hps; } - bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HASHTABLE & edgepoiclt_dom, + template + bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoiclt_dom, NgBitArray & cornerpoint, NgBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, - INDEX_2_HASHTABLE & surf_edges, NgArray & facepoint, int & levels, int & act_ref); + INDEX_2_HASHTABLE & surf_edges, Array & facepoint, int & levels, int & act_ref); - bool ClassifyHPElements (Mesh & mesh, NgArray & elements, int & act_ref, int & levels); + bool ClassifyHPElements (Mesh & mesh, NgArray & elements, SplittingType split, int & act_ref, int & levels); void InitHPElements(Mesh & mesh, NgArray & elements) { - for(ElementIndex i = 0; i < mesh.GetNE(); i++) + // for(ElementIndex i = 0; i < mesh.GetNE(); i++) + for(ElementIndex i : mesh.VolumeElements().Range()) { HPRefElement hpel(mesh[i]); - hpel.coarse_elnr = i; + hpel.coarse_elnr = int(i); switch (mesh[i].GetType()) { @@ -623,9 +678,7 @@ namespace netgen INDEX_2_HASHTABLE newpts(elements.Size()+1); INDEX_3_HASHTABLE newfacepts(elements.Size()+1); - // prepare new points - - fac1 = max(0.001,min(0.33,fac1)); + double fac2 = max(0.001,min(1.0/3,fac1)); // factor for face points PrintMessage(3, " in HP-REFINEMENT with fac1 ", fac1); *testout << " in HP-REFINEMENT with fac1 " << fac1 << endl; @@ -648,6 +701,8 @@ namespace netgen { INDEX_2 i2(el.pnums[hprs->splitedges[j][0]-1], el.pnums[hprs->splitedges[j][1]-1]); + if (fac1 == 0.5) i2.Sort(); + if (!newpts.Used (i2)) { Point<3> np; @@ -675,8 +730,8 @@ namespace netgen { Point<3> np; for( int l=0;l<3;l++) - np(l) = (1-2*fac1)*mesh.Point(i3.I1())(l) - + fac1*mesh.Point(i3.I2())(l) + fac1*mesh.Point(i3.I3())(l); + np(l) = (1-2*fac2)*mesh.Point(i3.I1())(l) + + fac2*mesh.Point(i3.I2())(l) + fac2*mesh.Point(i3.I3())(l); int npi = mesh.AddPoint (np); newfacepts.Set (i3, npi); } @@ -699,6 +754,7 @@ namespace netgen case HP_PYRAMID: oldnp = 5; break; case HP_PRISM: oldnp = 6; break; case HP_HEX: oldnp = 8; break; + case HP_HEX7: oldnp = 7; break; default: cerr << "HPRefElement: illegal type (3) " << hprs->geom << endl; @@ -712,6 +768,7 @@ namespace netgen el.type == HP_TET || el.type == HP_PRISM || el.type == HP_HEX || + el.type == HP_HEX7 || el.type == HP_PYRAMID) newlevel = el.levelx; @@ -734,7 +791,8 @@ namespace netgen { INDEX_2 i2(el.pnums[hprs->splitedges[j][0]-1], el.pnums[hprs->splitedges[j][1]-1]); - + if (fac1 == 0.5) i2.Sort(); + int npi = newpts.Get(i2); newpnums[hprs->splitedges[j][2]-1] = npi; @@ -762,9 +820,9 @@ namespace netgen for (int l = 0; l < 3; l++) newparam[hprs->splitfaces[j][3]-1][l] = - (1-2*fac1) * el.param[hprs->splitfaces[j][0]-1][l] + - fac1 * el.param[hprs->splitfaces[j][1]-1][l] + - fac1 * el.param[hprs->splitfaces[j][2]-1][l]; + (1-2*fac2) * el.param[hprs->splitfaces[j][0]-1][l] + + fac2 * el.param[hprs->splitfaces[j][1]-1][l] + + fac2 * el.param[hprs->splitfaces[j][2]-1][l]; j++; } // split elements @@ -818,6 +876,7 @@ namespace netgen newel.type == HP_TET || newel.type == HP_PRISM || newel.type == HP_HEX || + newel.type == HP_HEX7 || newel.type == HP_PYRAMID) newel.levelx = newel.levely = newel.levelz = newlevel; else @@ -829,6 +888,7 @@ namespace netgen case HP_QUAD: newel.np=4; break; case HP_TRIG: newel.np=3; break; case HP_HEX: newel.np=8; break; + case HP_HEX7: newel.np=7; break; case HP_PRISM: newel.np=6; break; case HP_TET: newel.np=4; break; case HP_PYRAMID: newel.np=5; break; @@ -1306,7 +1366,8 @@ namespace netgen /* ***************************** HPRefinement ********************************** */ - void HPRefinement (Mesh & mesh, Refinement * ref, int levels, double fac1, bool setorders, bool reflevels) + void HPRefinement (Mesh & mesh, Refinement * ref, SplittingType split, + int levels, double fac1, bool setorders, bool reflevels) { PrintMessage (1, "HP Refinement called, levels = ", levels); @@ -1333,7 +1394,7 @@ namespace netgen nplevel.Append (mesh.GetNP()); int act_ref=1; - bool sing = ClassifyHPElements (mesh,hpelements, act_ref, levels); + bool sing = ClassifyHPElements (mesh,hpelements, split, act_ref, levels); sing = true; // iterate at least once while(sing) @@ -1392,7 +1453,8 @@ namespace netgen seg.domin = hpel.domin; seg.domout=hpel.domout; // he: needed for segments! seg.hp_elnr = i; seg.singedge_left = hpel.singedge_left; - seg.singedge_right = hpel.singedge_right; + seg.singedge_right = hpel.singedge_right; + seg.SetCurved (coarseseg.IsCurved()); mesh.AddSegment (seg); break; } @@ -1413,6 +1475,7 @@ namespace netgen break; } case HP_HEX: + case HP_HEX7: case HP_TET: case HP_PRISM: case HP_PYRAMID: @@ -1441,14 +1504,15 @@ namespace netgen act_ref++; - sing = ClassifyHPElements(mesh,hpelements, act_ref, levels); + sing = ClassifyHPElements(mesh,hpelements, split, act_ref, levels); } PrintMessage(3, " HP-Refinement done with ", --act_ref, " refinement steps."); if(act_ref>=1) { - for(ElementIndex i=0;i & edges, INDEX_2_HASHTABLE & edgepoint_dom, - NgBitArray & cornerpoint, NgBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, - INDEX_2_HASHTABLE & surf_edges, NgArray & facepoint, int & levels, int & act_ref) + template + bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, HT_EDGEPOINT_DOM & edgepoint_dom, + TBitArray & cornerpoint, TBitArray & edgepoint, INDEX_3_HASHTABLE & faces, INDEX_2_HASHTABLE & face_edges, + INDEX_2_HASHTABLE & surf_edges, Array & facepoint, int & levels, int & act_ref) { bool sing = 0; if (mesh.GetDimension() == 3) @@ -1606,11 +1674,11 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS { if (mesh.Point(i).Singularity() * levels >= act_ref) { - cornerpoint.Set(i); + cornerpoint.SetBit(i); sing = 1; } } - cout << endl; + // cout << endl; for (int i = 1; i <= mesh.GetNSeg(); i++) if (mesh.LineSegment(i).singedge_left * levels >= act_ref) @@ -1631,16 +1699,17 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS edges.Set (i2s, 1); - edgepoint.Set (i2.I1()); - edgepoint.Set (i2.I2()); + edgepoint.SetBit (i2.I1()); + edgepoint.SetBit (i2.I2()); sing = 1; } // if 2 adjacent edges of an element are singular, the // common point must be a singular point - for (int i = 1; i <= mesh.GetNE(); i++) + // for (int i = 1; i <= mesh.GetNE(); i++) + for (auto ei : mesh.VolumeElements().Range()) { - const Element & el = mesh.VolumeElement(i); + const Element & el = mesh[ei]; const ELEMENT_EDGE * eledges = MeshTopology::GetEdges1 (el.GetType()); int nedges = MeshTopology::GetNEdges (el.GetType()); for (int j = 0; j < nedges; j++) @@ -1653,10 +1722,10 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS ek.Sort(); if (edges.Used(ej) && edges.Used(ek)) { - if (ej.I1() == ek.I1()) cornerpoint.Set (ek.I1()); - if (ej.I1() == ek.I2()) cornerpoint.Set (ek.I2()); - if (ej.I2() == ek.I1()) cornerpoint.Set (ek.I1()); - if (ej.I2() == ek.I2()) cornerpoint.Set (ek.I2()); + if (ej.I1() == ek.I1()) cornerpoint.SetBit (ek.I1()); + if (ej.I1() == ek.I2()) cornerpoint.SetBit (ek.I2()); + if (ej.I2() == ek.I1()) cornerpoint.SetBit (ek.I1()); + if (ej.I2() == ek.I2()) cornerpoint.SetBit (ek.I2()); } } } @@ -1702,6 +1771,7 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS i3 = INDEX_3(i4.I1(), i4.I2(), i4.I3()); } faces.Set (i3, domnr); + *testout << "set face " << i3 << ", domnr = " << domnr << endl; for (int j = 0; j < el.GetNP(); j++) { @@ -1713,8 +1783,9 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS } } - (*testout) << "singular faces = " << faces << endl; - (*testout) << "singular faces_edges = " << face_edges << endl; + // (*testout) << "singular edges = " << edges << endl; + // (*testout) << "singular faces = " << faces << endl; + // (*testout) << "singular faces_edges = " << face_edges << endl; } else { @@ -1734,33 +1805,33 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS if (seg.singedge_left * levels >= act_ref) { INDEX_2 i2 = INDEX_2::Sort(mesh.LineSegment(i)[0], - mesh.LineSegment(i)[1]); + mesh.LineSegment(i)[1]); edges.Set(i2,1); - edgepoint.Set(i2.I1()); - edgepoint.Set(i2.I2()); + edgepoint.SetBit(i2.I1()); + edgepoint.SetBit(i2.I2()); *testout << " singleft " << endl; *testout << " mesh.LineSegment(i).domout " << mesh.LineSegment(i).domout << endl; *testout << " mesh.LineSegment(i).domin " << mesh.LineSegment(i).domin << endl; - edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domin, i2.I1()), 1); - edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domin, i2.I2()), 1); + edgepoint_dom.Set ( { mesh.LineSegment(i).domin, i2.I1() }, 1); + edgepoint_dom.Set ( { mesh.LineSegment(i).domin, i2.I2() }, 1); sing = 1; } if (seg.singedge_right * levels >= act_ref) { - INDEX_2 i2 = INDEX_2::Sort(mesh.LineSegment(i)[1], - mesh.LineSegment(i)[0]); + PointIndices<2> i2 = INDEX_2::Sort(mesh.LineSegment(i)[1], + mesh.LineSegment(i)[0]); edges.Set (i2, 1); - edgepoint.Set(i2.I1()); - edgepoint.Set(i2.I2()); + edgepoint.SetBit(i2.I1()); + edgepoint.SetBit(i2.I2()); *testout << " singright " << endl; *testout << " mesh.LineSegment(i).domout " << mesh.LineSegment(i).domout << endl; *testout << " mesh.LineSegment(i).domin " << mesh.LineSegment(i).domin << endl; - edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domout, i2.I1()), 1); - edgepoint_dom.Set (INDEX_2(mesh.LineSegment(i).domout, i2.I2()), 1); + edgepoint_dom.Set ( { mesh.LineSegment(i).domout, i2.I1() }, 1); + edgepoint_dom.Set ( { mesh.LineSegment(i).domout, i2.I2() }, 1); sing = 1; } @@ -1791,14 +1862,14 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS if (surfonpoint.Get(i).I1()) { // cornerpoint.Set(i); // disabled by JS, Aug 2009 - edgepoint.Set(i); + edgepoint.SetBit(i); } // mark points for refinement that are explicitly specified in input file if (mesh.Point(i).Singularity()*levels >= act_ref) { - cornerpoint.Set(i); - edgepoint.Set(i); + cornerpoint.SetBit(i); + edgepoint.SetBit(i); sing = 1; } } @@ -1820,14 +1891,16 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS - bool ClassifyHPElements (Mesh & mesh, NgArray & elements, int & act_ref, int & levels) + bool ClassifyHPElements (Mesh & mesh, NgArray & elements, SplittingType split, int & act_ref, int & levels) { INDEX_2_HASHTABLE edges(mesh.GetNSeg()+1); - NgBitArray edgepoint(mesh.GetNP()); - INDEX_2_HASHTABLE edgepoint_dom(mesh.GetNSeg()+1); + TBitArray edgepoint(mesh.GetNP()); + // INDEX_2_HASHTABLE edgepoint_dom(mesh.GetNSeg()+1); + HT_EDGEPOINT_DOM edgepoint_dom; + edgepoint.Clear(); - NgBitArray cornerpoint(mesh.GetNP()); + TBitArray cornerpoint(mesh.GetNP()); cornerpoint.Clear(); // value = nr > 0 ... refine elements in domain nr @@ -1835,40 +1908,49 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS INDEX_3_HASHTABLE faces(mesh.GetNSE()+1); INDEX_2_HASHTABLE face_edges(mesh.GetNSE()+1); INDEX_2_HASHTABLE surf_edges(mesh.GetNSE()+1); - NgArray facepoint(mesh.GetNP()); + Array facepoint(mesh.GetNP()); bool sing = CheckSingularities(mesh, edges, edgepoint_dom, cornerpoint, edgepoint, faces, face_edges, - surf_edges, facepoint, levels, act_ref); - + surf_edges, facepoint, levels, act_ref); + + if (act_ref == 1 && split == SPLIT_ALFELD) + sing = true; + if (act_ref == 1 && split == SPLIT_POWELL) + sing = true; if(sing==0) return(sing); int cnt_undef = 0, cnt_nonimplement = 0; NgArray misses(10000); misses = 0; - (*testout) << "edgepoint_dom = " << endl << edgepoint_dom << endl; + // (*testout) << "edgepoint_dom = " << endl << edgepoint_dom << endl; + for( int i = 0; igeom) { case HP_TET: { - hpel.type = ClassifyTet(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces,face_edges, surf_edges, facepoint); + hpel.type = ClassifyTet(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces,face_edges, surf_edges, facepoint); + /* + // if (i != 182) + if ( (!hpel.PNums().Contains(40)) || (!hpel.PNums().Contains(41)) ) + hpel.type = HP_NONETET; + else + cout << "type = " << hpel.type << endl; + */ break; } case HP_PRISM: @@ -1879,6 +1961,12 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS break; } + case HP_HEX7: + { + hpel.type = ClassifyHex7(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces, + face_edges, surf_edges, facepoint); + break; + } case HP_HEX: { hpel.type = ClassifyHex(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces, @@ -1886,30 +1974,37 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS break; } case HP_TRIG: - { + { int dim = mesh.GetDimension(); - const FaceDescriptor & fd = mesh.GetFaceDescriptor (hpel.GetIndex()); - - hpel.type = ClassifyTrig(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, - faces, face_edges, surf_edges, facepoint, dim, fd); - - dd = 2; + const FaceDescriptor & fd = mesh.GetFaceDescriptor (hpel.GetIndex()); + + if (split == SPLIT_HP) + hpel.type = ClassifyTrig(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, + faces, face_edges, surf_edges, facepoint, dim, fd); + else if (split == SPLIT_ALFELD) + hpel.type = HP_TRIG_ALFELD; + else if (split == SPLIT_POWELL) + hpel.type = HP_TRIG_POWELL; + + dd = 2; break; } case HP_QUAD: { int dim = mesh.GetDimension(); - const FaceDescriptor & fd = mesh.GetFaceDescriptor (hpel.GetIndex()); + const FaceDescriptor & fd = mesh.GetFaceDescriptor (hpel.GetIndex()); hpel.type = ClassifyQuad(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces, face_edges, surf_edges, facepoint, dim, fd); - dd = 2; break; } case HP_SEGM: { - hpel.type = ClassifySegm(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, - faces, face_edges, surf_edges, facepoint); + if (split == SPLIT_HP) + hpel.type = ClassifySegm(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, + faces, face_edges, surf_edges, facepoint); + else if (split == SPLIT_POWELL) + hpel.type = HP_SEGM_SINGCORNERL; dd = 1; break; } @@ -1917,8 +2012,6 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS { hpel.type = ClassifyPyramid(hpel, edges, edgepoint_dom, cornerpoint, edgepoint, faces, face_edges, surf_edges, facepoint); - - cout << " ** Pyramid classified " << hpel.type << endl; break; } default: @@ -1927,15 +2020,13 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS throw NgException ("hprefinement.cpp: don't know how to set parameters"); } } - + if(hpel.type == HP_NONE) cnt_undef++; //else //cout << "elem " << i << " classified type " << hpel.type << endl; - - if (!Get_HPRef_Struct (hpel.type)) { (*testout) << "hp-element-type " << hpel.type << " not implemented " << endl; @@ -1958,15 +2049,13 @@ bool CheckSingularities(Mesh & mesh, INDEX_2_HASHTABLE & edges, INDEX_2_HAS } } - - + PrintMessage(3, "undefined elements update classification: ", cnt_undef); PrintMessage(3, "non-implemented in update classification: ", cnt_nonimplement); - + for (int i = 0; i < misses.Size(); i++) if (misses[i]) cout << " in update classification missing case " << i << " occurred " << misses[i] << " times" << endl; - return(sing); } } diff --git a/libsrc/meshing/hprefinement.hpp b/libsrc/meshing/hprefinement.hpp index 0affd82b..c7d654ab 100644 --- a/libsrc/meshing/hprefinement.hpp +++ b/libsrc/meshing/hprefinement.hpp @@ -11,7 +11,11 @@ HP Refinement */ +#include "bisect.hpp" +#include "meshtype.hpp" +namespace netgen +{ enum HPREF_ELEMENT_TYPE { @@ -41,6 +45,9 @@ enum HPREF_ELEMENT_TYPE { HP_TRIG_SINGEDGES23, HP_TRIG_3SINGEDGES = 40, + HP_TRIG_ALFELD, + HP_TRIG_POWELL, + HP_QUAD = 50, HP_QUAD_SINGCORNER, HP_DUMMY_QUAD_SINGCORNER, @@ -102,6 +109,7 @@ enum HPREF_ELEMENT_TYPE { HP_TET = 100, // no singular vertex/edge + HP_NONETET, // make void HP_TET_0E_1V, // V1 HP_TET_0E_2V, // V1,2 HP_TET_0E_3V, // V1,2,3 @@ -148,14 +156,38 @@ enum HPREF_ELEMENT_TYPE { HP_TET_3EC_0V = 430, // 3 edges chain, alter HP_TET_3EC_1V, // 3 edges chain, alter HP_TET_3EC_2V, // 3 edges chain, alter + HP_TET_3ED_3V, // 3 edges in a loop e12, e13, e23 NEW .. done HP_TET_1F_0E_0V = 500, // 1 singular face - HP_TET_1F_0E_1VA, // 1 sing vertex in face (V2) + HP_TET_1F_0E_1VA, // 1 sing vertex in face (V2) FIX ... (needs HEX7) HP_TET_1F_0E_1VB, // 1 sing vertex not in face (V1) + HP_TET_1F_0E_2V, // 2 sing vertex in face (V2,V3) NEW .. done + HP_TET_1F_0E_3V, // 3 sing vertex in face (V2,V3,V4) NEWNEW HP_TET_1F_1EA_0V, // 1 sing edge not in face HP_TET_1F_1EB_0V, // 1 sing edge in face + HP_TET_1F_1E_1VA, // 1 sing edge in face e23, sing vert 2 NEW done + HP_TET_1F_1E_1VB, // 1 sing edge in face e24, sing vert 2 NEW done + HP_TET_1F_1E_2VA, // 1 sing edge not in face (e12), sing v2,v3 NEW done + HP_TET_1F_1E_2VB, // 1 sing edge not in face (e12), sing v2,v4 NEW done + HP_TET_1F_1E_2VC, // 1 sing edge not in face (e12), sing v3,v4 NEW + HP_TET_1F_1EA_3V, // 1 sing edge out of face e12, sing v2, v3, v4 NEWNEW WIP, need Pyramid with 1 sing trig-face + HP_TET_1F_1E_3V, // 1 sing edge in face e23, sing v2, v3, v4 NEWNEW done + HP_TET_1F_2Eoo_3V, // 2e out of face: f234, e12, e13, v1,v2,v3 NEWNEW + HP_TET_1F_2E_0VA, // edge6 && fedge3 .. 1 in face, 1 not in face NEW done + HP_TET_1F_2E_0VB, // edge6 && fedge2 .. 1 in face, 1 not in face NEW done + HP_TET_1F_2E_1V, // e4,e5 (E23,E24), V2 NEW NEW WIP + HP_TET_1F_2E_3V, // e4,e5 (E23,E24), V2,V3,V4 NEW NEW done + HP_TET_2F_0E_0V = 600, // 2 singular faces + HP_TET_2F_0E_1V, // 2 singular faces f234, f134, sing point V4 NEW + HP_TET_2F_1E_0VA, // 2 singular faces, sing edge e4 NEW done + HP_TET_2F_1E_0VB, // 2 singular faces, sing edge e5 NEW done + + HP_TET_2F_1E_3VA, // 2 singular faces f234,f134, e23, v2,v3,v4 NEW3 + HP_TET_2F_1E_4VA, // 2 singular faces f234,f134, e23, v2,v3,v4 NEW3 + + HP_TET_3F_0E_0V = 700, // 3 singular faces, no additional points or edges NEW done HP_PRISM = 1000, HP_PRISM_SINGEDGE, @@ -167,8 +199,8 @@ enum HPREF_ELEMENT_TYPE { HP_PRISM_2FA_0E_0V, // 2 singular trig faces HP_PRISM_1FB_0E_0V, // 1 singular quad face 1-2-4-5 - HP_PRISM_1FB_1EA_0V, // 1 singular quad face, edge is 1-2 - HP_PRISM_1FA_1E_0V, + HP_PRISM_1FB_1EA_0V, // 1 singular quad face, edge is 1-4 + HP_PRISM_1FA_1E_0V, HP_PRISM_2FA_1E_0V, HP_PRISM_1FA_1FB_0E_0V, HP_PRISM_2FA_1FB_0E_0V, @@ -218,6 +250,7 @@ enum HPREF_ELEMENT_TYPE { HP_PYRAMID = 2000, HP_PYRAMID_0E_1V, HP_PYRAMID_EDGES, + HP_PYRAMID_1FB_0E_0V, // 1 trig face F125 HP_PYRAMID_1FB_0E_1VA, // 1 trig face, top vertex HP_HEX = 3000, @@ -226,7 +259,11 @@ enum HPREF_ELEMENT_TYPE { HP_HEX_1E_0V, HP_HEX_3E_0V, HP_HEX_1F_0E_0V, - HP_HEX_1FA_1FB_0E_0V + HP_HEX_1FA_1FB_0E_0V, + + HP_HEX7 = 3100, + HP_HEX7_1FA, // singular quad face 1,2,3,4 + HP_HEX7_1FB // singular trig face 5,6,7 }; @@ -296,7 +333,7 @@ public: int levely; int levelz; int np; - int coarse_elnr; + int coarse_elnr; // issue (JS): same class is for ElementIndex, SurfaceElementIndex, SegmentIndex int domin, domout; // he: needed for segment!! in 3d there should be surf1, surf2!! // int coarse_hpelnr; PointIndex & operator[](int i) { return(pnums[i]);} @@ -304,17 +341,24 @@ public: PointIndex & PNum(int i) {return pnums[(i-1)]; }; int GetIndex () const { return index; }; double singedge_left, singedge_right; - + auto PNums() const { return FlatArray(np, &pnums[0]); } // EdgePointGeomInfo epgeominfo[2]; }; +enum SplittingType { SPLIT_HP, SPLIT_ALFELD, SPLIT_POWELL}; -DLL_HEADER extern void HPRefinement (Mesh & mesh, Refinement * ref, int levels, +DLL_HEADER extern void HPRefinement (Mesh & mesh, Refinement * ref, SplittingType split, int levels, double fac1=0.125, bool setorders=true, bool ref_level = false); +inline void HPRefinement (Mesh & mesh, Refinement * ref, int levels, + double fac1=0.125, bool setorders=true, bool ref_level = false) +{ + HPRefinement (mesh, ref, SPLIT_HP, levels, fac1, setorders, ref_level); +} +} // namespace netgen #endif diff --git a/libsrc/meshing/improve2.cpp b/libsrc/meshing/improve2.cpp index 139eddb4..0d6d9b82 100644 --- a/libsrc/meshing/improve2.cpp +++ b/libsrc/meshing/improve2.cpp @@ -57,6 +57,7 @@ namespace netgen if (t2 == -1) return false; if (swapped[t1] || swapped[t2]) return false; if (mesh[t2].IsDeleted()) return false; + if (mesh[t2].GetNP() != 3) return false; const int faceindex = mesh[t1].GetIndex(); const int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr(); @@ -211,7 +212,7 @@ namespace netgen } Array neighbors(mesh.GetNSE()); - auto elements_on_node = mesh.CreatePoint2SurfaceElementTable(faceindex); + auto elements_on_node = mesh.CreateCompressedPoint2SurfaceElementTable(faceindex); Array swapped(mesh.GetNSE()); Array pdef(mesh.GetNP()); @@ -352,7 +353,7 @@ namespace netgen improvement_candidates[cnt++]= std::make_pair(t1,o1); }); - auto elements_with_improvement = improvement_candidates.Range(cnt.load()); + auto elements_with_improvement = improvement_candidates.Range(0, cnt.load()); QuickSort(elements_with_improvement); for (auto [t1,o1] : elements_with_improvement) @@ -365,9 +366,9 @@ namespace netgen - + template double CombineImproveEdge( Mesh & mesh, - const Table & elementsonnode, + const T_PI2SEI & elementsonnode, Array, PointIndex> & normals, Array & fixed, PointIndex pi1, PointIndex pi2, @@ -600,9 +601,9 @@ namespace netgen int np = mesh.GetNP(); - auto elementsonnode = mesh.CreatePoint2SurfaceElementTable(faceindex); + auto elementsonnode = mesh.CreateCompressedPoint2SurfaceElementTable(faceindex); - int ntasks = ngcore::TaskManager::GetMaxThreads(); + // int ntasks = ngcore::TaskManager::GetMaxThreads(); Array> edges; BuildEdgeList( mesh, elementsonnode, edges ); @@ -712,7 +713,7 @@ namespace netgen if (mesh.IsSegment (pi1, pi2)) continue; - INDEX_2 ii2 (pi1, pi2); + PointIndices<2> ii2 (pi1, pi2); ii2.Sort(); if (els_on_edge.Used (ii2)) { @@ -738,7 +739,7 @@ namespace netgen if (mesh.LegalTrig(sel)) continue; // find longest edge - INDEX_2 edge; + PointIndices<2> edge; double edge_len = 0; PointIndex pi1, pi2, pi3, pi4; PointGeomInfo gi1, gi2, gi3, gi4; diff --git a/libsrc/meshing/improve2.hpp b/libsrc/meshing/improve2.hpp index 444062a2..ebecdc2e 100644 --- a/libsrc/meshing/improve2.hpp +++ b/libsrc/meshing/improve2.hpp @@ -1,5 +1,10 @@ -#ifndef FILE_IMPROVE2 -#define FILE_IMPROVE2 +#ifndef NETGEN_IMPROVE2_HPP +#define NETGEN_IMPROVE2_HPP + +#include "meshtype.hpp" + +namespace netgen +{ inline void AppendEdges( const Element2d & elem, PointIndex pi, Array> & edges ) { @@ -31,10 +36,10 @@ inline void AppendEdges( const Element & elem, PointIndex pi, Array -void BuildEdgeList( const Mesh & mesh, const Table & elementsonnode, Array> & edges ) +template +void BuildEdgeList( const Mesh & mesh, const T_PI2SEI & elementsonnode, Array> & edges ) { - static_assert(is_same_v||is_same_v, "Invalid type for TINDEX"); + // static_assert(is_same_v||is_same_v, "Invalid type for TINDEX"); static Timer tbuild_edges("Build edges"); RegionTimer reg(tbuild_edges); int ntasks = 4*ngcore::TaskManager::GetMaxThreads(); @@ -57,7 +62,7 @@ void BuildEdgeList( const Mesh & mesh, const Table & element } QuickSort(local_edges); - auto edge_prev = std::make_tuple(-1,-1); + auto edge_prev = std::make_tuple(PointIndex::INVALID, PointIndex::INVALID); for(auto edge : local_edges) if(edge != edge_prev) @@ -169,7 +174,5 @@ extern double CalcTriangleBadness (const Point<3> & p1, const Vec<3> & n, double metricweight, double h); - -#endif - - +} // namespace netgen +#endif // NETGEN_IMPROVE2_HPP diff --git a/libsrc/meshing/improve2gen.cpp b/libsrc/meshing/improve2gen.cpp index 02fa5fd6..db7485fc 100644 --- a/libsrc/meshing/improve2gen.cpp +++ b/libsrc/meshing/improve2gen.cpp @@ -11,9 +11,9 @@ namespace netgen public: NgArray oldels; NgArray newels; - NgArray deledges; - NgArray incelsonnode; - NgArray reused; + NgArray> deledges; + Array incelsonnode; + Array reused; int bonus; int onp; }; @@ -55,128 +55,137 @@ namespace netgen NgArray rules; NgArray elmap; NgArray elrot; - NgArray pmap; - NgArray pgi; + Array pmap; + Array pgi; int surfnr = mesh.GetFaceDescriptor (faceindex).SurfNr(); ImprovementRule * r1; + PointIndex p1 = IndexBASE(); + PointIndex p2 = p1+1; + PointIndex p3 = p2+1; + PointIndex p4 = p3+1; + PointIndex p5 = p4+1; + PointIndex p6 = p5+1; + PointIndex p7 = p6+1; + + // 2 triangles to quad r1 = new ImprovementRule; - r1->oldels.Append (Element2d (1, 2, 3)); - r1->oldels.Append (Element2d (3, 2, 4)); - r1->newels.Append (Element2d (1, 2, 4, 3)); - r1->deledges.Append (INDEX_2 (2,3)); + r1->oldels.Append (Element2d (p1, p2, p3)); + r1->oldels.Append (Element2d (p3, p2, p4)); + r1->newels.Append (Element2d (p1, p2, p4, p3)); + r1->deledges.Append ( { p2, p3 } ); r1->onp = 4; r1->bonus = 2; rules.Append (r1); // 2 quad to 1 quad r1 = new ImprovementRule; - r1->oldels.Append (Element2d (1, 2, 3, 4)); - r1->oldels.Append (Element2d (4, 3, 2, 5)); - r1->newels.Append (Element2d (1, 2, 5, 4)); - r1->deledges.Append (INDEX_2 (2, 3)); - r1->deledges.Append (INDEX_2 (3, 4)); + r1->oldels.Append (Element2d (p1, p2, p3, p4)); + r1->oldels.Append (Element2d (p4, p3, p2, p5)); + r1->newels.Append (Element2d (p1, p2, p5, p4)); + r1->deledges.Append ( { p2, p3 } ); + r1->deledges.Append ( { p3, p4 } ); r1->onp = 5; r1->bonus = 0; rules.Append (r1); // swap quads r1 = new ImprovementRule; - r1->oldels.Append (Element2d (1, 2, 3, 4)); - r1->oldels.Append (Element2d (3, 2, 5, 6)); - r1->newels.Append (Element2d (1, 6, 3, 4)); - r1->newels.Append (Element2d (1, 2, 5, 6)); - r1->deledges.Append (INDEX_2 (2, 3)); + r1->oldels.Append (Element2d (p1, p2, p3, p4)); + r1->oldels.Append (Element2d (p3, p2, p5, p6)); + r1->newels.Append (Element2d (p1, p6, p3, p4)); + r1->newels.Append (Element2d (p1, p2, p5, p6)); + r1->deledges.Append ( { p2, p3 } ); r1->onp = 6; r1->bonus = 0; rules.Append (r1); // three quads to 2 r1 = new ImprovementRule; - r1->oldels.Append (Element2d (1, 2, 3, 4)); - r1->oldels.Append (Element2d (2, 5, 6, 3)); - r1->oldels.Append (Element2d (3, 6, 7, 4)); - r1->newels.Append (Element2d (1, 2, 5, 4)); - r1->newels.Append (Element2d (4, 5, 6, 7)); - r1->deledges.Append (INDEX_2 (2, 3)); - r1->deledges.Append (INDEX_2 (3, 4)); - r1->deledges.Append (INDEX_2 (3, 6)); + r1->oldels.Append (Element2d (p1, p2, p3, p4)); + r1->oldels.Append (Element2d (p2, p5, p6, p3)); + r1->oldels.Append (Element2d (p3, p6, p7, p4)); + r1->newels.Append (Element2d (p1, p2, p5, p4)); + r1->newels.Append (Element2d (p4, p5, p6, p7)); + r1->deledges.Append ( { p2, p3 } ); + r1->deledges.Append ( { p3, p4 } ); + r1->deledges.Append ( { p3, p6 } ); r1->onp = 7; r1->bonus = -1; rules.Append (r1); // quad + 2 connected trigs to quad r1 = new ImprovementRule; - r1->oldels.Append (Element2d (1, 2, 3, 4)); - r1->oldels.Append (Element2d (2, 5, 3)); - r1->oldels.Append (Element2d (3, 5, 4)); - r1->newels.Append (Element2d (1, 2, 5, 4)); - r1->deledges.Append (INDEX_2 (2, 3)); - r1->deledges.Append (INDEX_2 (3, 4)); - r1->deledges.Append (INDEX_2 (3, 5)); + r1->oldels.Append (Element2d (p1, p2, p3, p4)); + r1->oldels.Append (Element2d (p2, p5, p3)); + r1->oldels.Append (Element2d (p3, p5, p4)); + r1->newels.Append (Element2d (p1, p2, p5, p4)); + r1->deledges.Append ( { p2, p3 } ); + r1->deledges.Append ( { p3, p4 } ); + r1->deledges.Append ( { p3, p5 } ); r1->onp = 5; r1->bonus = 0; rules.Append (r1); // quad + 2 non-connected trigs to quad (a and b) r1 = new ImprovementRule; - r1->oldels.Append (Element2d (1, 2, 3, 4)); - r1->oldels.Append (Element2d (2, 6, 3)); - r1->oldels.Append (Element2d (1, 4, 5)); - r1->newels.Append (Element2d (1, 3, 4, 5)); - r1->newels.Append (Element2d (1, 2, 6, 3)); - r1->deledges.Append (INDEX_2 (1, 4)); - r1->deledges.Append (INDEX_2 (2, 3)); + r1->oldels.Append (Element2d (p1, p2, p3, p4)); + r1->oldels.Append (Element2d (p2, p6, p3)); + r1->oldels.Append (Element2d (p1, p4, p5)); + r1->newels.Append (Element2d (p1, p3, p4, p5)); + r1->newels.Append (Element2d (p1, p2, p6, p3)); + r1->deledges.Append ( { p1, p4 } ); + r1->deledges.Append ( { p2, p3 } ); r1->onp = 6; r1->bonus = 0; rules.Append (r1); r1 = new ImprovementRule; - r1->oldels.Append (Element2d (1, 2, 3, 4)); - r1->oldels.Append (Element2d (2, 6, 3)); - r1->oldels.Append (Element2d (1, 4, 5)); - r1->newels.Append (Element2d (1, 2, 4, 5)); - r1->newels.Append (Element2d (4, 2, 6, 3)); - r1->deledges.Append (INDEX_2 (1, 4)); - r1->deledges.Append (INDEX_2 (2, 3)); + r1->oldels.Append (Element2d (p1, p2, p3, p4)); + r1->oldels.Append (Element2d (p2, p6, p3)); + r1->oldels.Append (Element2d (p1, p4, p5)); + r1->newels.Append (Element2d (p1, p2, p4, p5)); + r1->newels.Append (Element2d (p4, p2, p6, p3)); + r1->deledges.Append ( { p1, p4 } ); + r1->deledges.Append ( { p2, p3 } ); r1->onp = 6; r1->bonus = 0; rules.Append (r1); // two quad + trig -> one quad + trig r1 = new ImprovementRule; - r1->oldels.Append (Element2d (1, 2, 3, 4)); - r1->oldels.Append (Element2d (2, 5, 6, 3)); - r1->oldels.Append (Element2d (4, 3, 6)); - r1->newels.Append (Element2d (1, 2, 6, 4)); - r1->newels.Append (Element2d (2, 5, 6)); - r1->deledges.Append (INDEX_2 (2, 3)); - r1->deledges.Append (INDEX_2 (3, 4)); - r1->deledges.Append (INDEX_2 (3, 6)); + r1->oldels.Append (Element2d (p1, p2, p3, p4)); + r1->oldels.Append (Element2d (p2, p5, p6, p3)); + r1->oldels.Append (Element2d (p4, p3, p6)); + r1->newels.Append (Element2d (p1, p2, p6, p4)); + r1->newels.Append (Element2d (p2, p5, p6)); + r1->deledges.Append ( { p2, p3 } ); + r1->deledges.Append ( { p3, p4 } ); + r1->deledges.Append ( { p3, p6 } ); r1->onp = 6; r1->bonus = -1; rules.Append (r1); // swap quad + trig (a and b) r1 = new ImprovementRule; - r1->oldels.Append (Element2d (1, 2, 3, 4)); - r1->oldels.Append (Element2d (2, 5, 3)); - r1->newels.Append (Element2d (2, 5, 3, 4)); - r1->newels.Append (Element2d (1, 2, 4)); - r1->deledges.Append (INDEX_2 (2, 3)); + r1->oldels.Append (Element2d (p1, p2, p3, p4)); + r1->oldels.Append (Element2d (p2, p5, p3)); + r1->newels.Append (Element2d (p2, p5, p3, p4)); + r1->newels.Append (Element2d (p1, p2, p4)); + r1->deledges.Append ( { p2, p3 } ); r1->onp = 5; r1->bonus = 0; rules.Append (r1); r1 = new ImprovementRule; - r1->oldels.Append (Element2d (1, 2, 3, 4)); - r1->oldels.Append (Element2d (2, 5, 3)); - r1->newels.Append (Element2d (1, 2, 5, 3)); - r1->newels.Append (Element2d (1, 3, 4)); - r1->deledges.Append (INDEX_2 (2, 3)); + r1->oldels.Append (Element2d (p1, p2, p3, p4)); + r1->oldels.Append (Element2d (p2, p5, p3)); + r1->newels.Append (Element2d (p1, p2, p5, p3)); + r1->newels.Append (Element2d (p1, p3, p4)); + r1->deledges.Append ( { p2, p3 } ); r1->onp = 5; r1->bonus = 0; rules.Append (r1); @@ -184,12 +193,12 @@ namespace netgen // 2 quads to quad + 2 trigs r1 = new ImprovementRule; - r1->oldels.Append (Element2d (1, 2, 3, 4)); - r1->oldels.Append (Element2d (3, 2, 5, 6)); - r1->newels.Append (Element2d (1, 5, 6, 4)); - r1->newels.Append (Element2d (1, 2, 5)); - r1->newels.Append (Element2d (4, 6, 3)); - r1->deledges.Append (INDEX_2 (2, 3)); + r1->oldels.Append (Element2d (p1, p2, p3, p4)); + r1->oldels.Append (Element2d (p3, p2, p5, p6)); + r1->newels.Append (Element2d (p1, p5, p6, p4)); + r1->newels.Append (Element2d (p1, p2, p5)); + r1->newels.Append (Element2d (p4, p6, p3)); + r1->deledges.Append ( { p2, p3 } ); r1->onp = 6; r1->bonus = 0; // rules.Append (r1); @@ -203,18 +212,21 @@ namespace netgen mapped = 0; - for (int ri = 0; ri < rules.Size(); ri++) { ImprovementRule & rule = *rules[ri]; rule.incelsonnode.SetSize (rule.onp); rule.reused.SetSize (rule.onp); + /* for (int j = 0; j < rule.onp; j++) { rule.incelsonnode[j] = 0; rule.reused[j] = 0; } + */ + rule.incelsonnode = 0; + rule.reused = 0; /* for (int j = 1; j <= rule.oldels.Size(); j++) @@ -226,15 +238,15 @@ namespace netgen */ for (const Element2d & el : rule.oldels) for (PointIndex pi : el.PNums()) - rule.incelsonnode[pi-PointIndex::BASE]--; + rule.incelsonnode[pi]--; for (int j = 1; j <= rule.newels.Size(); j++) { const Element2d & el = rule.newels.Elem(j); for (int k = 1; k <= el.GetNP(); k++) { - rule.incelsonnode.Elem(el.PNum(k))++; - rule.reused.Elem(el.PNum(k)) = 1; + rule.incelsonnode[el.PNum(k)]++; + rule.reused[el.PNum(k)] = 1; } } } @@ -242,8 +254,8 @@ namespace netgen - TABLE elonnode(np); - NgArray nelonnode(np); + DynamicTable elonnode(np); + Array nelonnode(np); TABLE nbels(ne); nelonnode = -4; @@ -314,13 +326,13 @@ namespace netgen if (el0.IsDeleted()) continue; if (el0.GetNP() != rel0.GetNP()) continue; - - pmap = PointIndex (-1); + // pmap = PointIndex (-1); + for (auto & p : pmap) p.Invalidate(); for (int k = 0; k < el0.GetNP(); k++) { - pmap.Elem(rel0[k]) = el0.PNumMod(k+elrot[0]+1); - pgi.Elem(rel0[k]) = el0.GeomInfoPiMod(k+elrot[0]+1); + pmap[rel0[k]] = el0.PNumMod(k+elrot[0]+1); + pgi[rel0[k]] = el0.GeomInfoPiMod(k+elrot[0]+1); } ok = 1; @@ -342,16 +354,16 @@ namespace netgen possible = 1; for (int k = 0; k < rel.GetNP(); k++) - if (pmap.Elem(rel[k]) != -1 && - pmap.Elem(rel[k]) != el.PNumMod (k+elrot[i]+1)) + if (pmap[rel[k]].IsValid() && + pmap[rel[k]] != el.PNumMod (k+elrot[i]+1)) possible = 0; if (possible) { for (int k = 0; k < el.GetNP(); k++) { - pmap.Elem(rel[k]) = el.PNumMod(k+elrot[i]+1); - pgi.Elem(rel[k]) = el.GeomInfoPiMod(k+elrot[i]+1); + pmap[rel[k]] = el.PNumMod(k+elrot[i]+1); + pgi[rel[k]] = el.GeomInfoPiMod(k+elrot[i]+1); } break; } @@ -370,8 +382,8 @@ namespace netgen for(int i=0; ok && i olddef) continue; @@ -398,7 +410,8 @@ namespace netgen // calc metric badness double bad1 = 0, bad2 = 0; // SelectSurfaceOfPoint (mesh.Point(pmap.Get(1)), pgi.Get(1)); - auto n = geo.GetNormal(surfnr, mesh.Point(pmap.Get(1)), &pgi.Elem(1)); + // auto n = geo.GetNormal(surfnr, mesh.Point(pmap.Get(1)), &pgi.Elem(1)); + auto n = geo.GetNormal(surfnr, mesh.Point(pmap.First()), pgi.Data()); for (int j = 0; j < rule.oldels.Size(); j++) bad1 += mesh[elmap[j]].CalcJacobianBadness (mesh.Points(), n); @@ -409,7 +422,7 @@ namespace netgen const Element2d & rnel = rule.newels.Get(j); Element2d nel(rnel.GetNP()); for (int k = 1; k <= rnel.GetNP(); k++) - nel.PNum(k) = pmap.Get(rnel.PNum(k)); + nel.PNum(k) = pmap[rnel.PNum(k)]; bad2 += nel.CalcJacobianBadness (mesh.Points(), n); } @@ -427,8 +440,8 @@ namespace netgen nel.SetIndex (faceindex); for (int k = 1; k <= rnel.GetNP(); k++) { - nel.PNum(k) = pmap.Get(rnel.PNum(k)); - nel.GeomInfoPi(k) = pgi.Get(rnel.PNum(k)); + nel.PNum(k) = pmap[rnel.PNum(k)]; + nel.GeomInfoPi(k) = pgi[rnel.PNum(k)]; } mesh.AddSurfaceElement(nel); @@ -437,8 +450,8 @@ namespace netgen for (int j = 0; j < rule.oldels.Size(); j++) mesh.Delete (elmap[j]); - for (int j = 1; j <= pmap.Size(); j++) - nelonnode[pmap.Get(j)] += rule.incelsonnode.Get(j); + for (PointIndex j : pmap.Range()) + nelonnode[pmap[j]] += rule.incelsonnode[j]; used[ri]++; } diff --git a/libsrc/meshing/improve3.cpp b/libsrc/meshing/improve3.cpp index b9ee7585..7be9252b 100644 --- a/libsrc/meshing/improve3.cpp +++ b/libsrc/meshing/improve3.cpp @@ -14,6 +14,21 @@ namespace netgen { +bool WrongOrientation(Point<3> p1, Point<3> p2, Point<3> p3, Point<3> p4) +{ + Vec<3> v1 = p2 - p1; + Vec<3> v2 = p3 - p1; + Vec<3> v3 = p4 - p1; + + Vec<3> n = Cross(v1, v2); + return n * v3 > 0; +} + +static constexpr int tetedges[6][2] = + { { 0, 1 }, { 0, 2 }, { 0, 3 }, + { 1, 2 }, { 1, 3 }, { 2, 3 } }; + + static constexpr int IMPROVEMENT_CONFORMING_EDGE = -1e6; static inline bool NotTooBad(double bad1, double bad2) @@ -41,7 +56,7 @@ static ArrayMem SplitElement (Element old, PointIndex pi0, PointInde ArrayMem new_elements; // split element by cutting edge pi0,pi1 at pinew auto np = old.GetNP(); - old.Flags().illegal_valid = 0; + old.Touch(); if(np == 4) { // Split tet into two tets @@ -89,13 +104,13 @@ static ArrayMem SplitElement (Element old, PointIndex pi0, PointInde } return new_elements; -}; +} static double SplitElementBadness (const Mesh::T_POINTS & points, const MeshingParameters & mp, Element old, PointIndex pi0, PointIndex pi1, MeshPoint & pnew) { double badness = 0; auto np = old.GetNP(); - PointIndex dummy{-1}; + PointIndex dummy{PointIndex::INVALID}; if(np == 4) { // Split tet into two tets @@ -133,7 +148,63 @@ static double SplitElementBadness (const Mesh::T_POINTS & points, const MeshingP } return badness; -}; +} + + +tuple MeshOptimize3d :: UpdateBadness() +{ + static Timer tbad("UpdateBadness"); + RegionTimer reg(tbad); + + double totalbad = 0.0; + double maxbad = 0.0; + atomic bad_elements = 0; + + ParallelForRange(Range(mesh.GetNE()), [&] (auto myrange) { + double totalbad_local = 0.0; + double maxbad_local = 0.0; + int bad_elements_local = 0; + for (ElementIndex ei : myrange) + { + auto & el = mesh[ei]; + if(mp.only3D_domain_nr && mp.only3D_domain_nr != el.GetIndex()) continue; + if(!el.BadnessValid()) + el.SetBadness(CalcBad(mesh.Points(), el, 0)); + double bad = el.GetBadness(); + totalbad_local += bad; + maxbad_local = max(maxbad_local, bad); + if(bad > min_badness) + bad_elements_local++; + } + AtomicAdd(totalbad, totalbad_local); + AtomicMax(maxbad, maxbad_local); + bad_elements += bad_elements_local; + }); + return {totalbad, maxbad, bad_elements}; +} + +bool MeshOptimize3d :: HasBadElement(FlatArray els) +{ + for(auto ei : els) + if(mesh[ei].GetBadness()>min_badness) + return true; + return false; +} + +bool MeshOptimize3d :: HasIllegalElement(FlatArray els) +{ + for(auto ei : els) + if(!mesh.LegalTet(mesh[ei])) + return true; + return false; +} + +bool MeshOptimize3d :: NeedsOptimization(FlatArray els) +{ + if(goal == OPT_LEGAL) return HasIllegalElement(els); + if(goal == OPT_QUALITY) return HasBadElement(els); + return true; +} /* @@ -143,10 +214,8 @@ static double SplitElementBadness (const Mesh::T_POINTS & points, const MeshingP Connect inner point to boundary point, if one point is inner point. */ -double MeshOptimize3d :: CombineImproveEdge (Mesh & mesh, - const MeshingParameters & mp, +double MeshOptimize3d :: CombineImproveEdge ( Table & elements_of_point, - Array & elerrs, PointIndex pi0, PointIndex pi1, FlatArray is_point_removed, bool check_only) @@ -185,6 +254,7 @@ double MeshOptimize3d :: CombineImproveEdge (Mesh & mesh, { Element & elem = mesh[ei]; if (elem.IsDeleted()) return false; + if(elem.GetType() != TET) return false; // TODO: implement case where pi0 or pi1 is top of a pyramid if (elem[0] == pi0 || elem[1] == pi0 || elem[2] == pi0 || elem[3] == pi0) { @@ -199,9 +269,29 @@ double MeshOptimize3d :: CombineImproveEdge (Mesh & mesh, double badness_old = 0.0; for (auto ei : has_one_point) - badness_old += elerrs[ei]; + badness_old += mesh[ei].GetBadness(); for (auto ei : has_both_points) - badness_old += elerrs[ei]; + badness_old += mesh[ei].GetBadness(); + + if (goal == OPT_CONFORM && p0.Type() <= EDGEPOINT) { + // check if the optimization improves conformity with free segments + std::set edges_before, edges_after; + + for (auto ei : has_one_point) { + const auto el = mesh[ei]; + for(auto i : Range(6)) { + auto e0 = el[tetedges[i][0]]; + auto e1 = el[tetedges[i][1]]; + if(e0 == pi0 || e1 == pi0) edges_before.insert(e0 == pi0 ? e1 : e0); + if(e0 == pi1 || e1 == pi1) edges_after.insert(e0 == pi1 ? e1 : e0); + } + } + + for(auto new_edge : edges_after) { + if (edges_before.count(new_edge) == 0 && mesh[new_edge].Type() <= EDGEPOINT && mesh.BoundaryEdge (new_edge, pi0)) + badness_old += GetLegalPenalty(); + } + } MeshPoint pnew = p0; if (p0.Type() == INNERPOINT) @@ -224,7 +314,7 @@ double MeshOptimize3d :: CombineImproveEdge (Mesh & mesh, for (auto ei : has_one_point) { Element elem = mesh[ei]; - int l; + // int l; for (int l = 0; l < 4; l++) if (elem[l] == pi1) { @@ -232,9 +322,9 @@ double MeshOptimize3d :: CombineImproveEdge (Mesh & mesh, break; } - elem.Flags().illegal_valid = 0; + elem.Touch(); if (!mesh.LegalTet(elem)) - badness_new += 1e4; + badness_new += GetLegalPenalty(); } } @@ -255,17 +345,17 @@ double MeshOptimize3d :: CombineImproveEdge (Mesh & mesh, if (elem[l] == pi1) elem[l] = pi0; - elem.Flags().illegal_valid = 0; + elem.Touch(); if (!mesh.LegalTet (elem)) (*testout) << "illegal tet " << ei << endl; } for (auto i : Range(has_one_point)) - elerrs[has_one_point[i]] = one_point_badness[i]; + mesh[has_one_point[i]].SetBadness(one_point_badness[i]); for (auto ei : has_both_points) { - mesh[ei].Flags().illegal_valid = 0; + mesh[ei].Touch(); mesh[ei].Delete(); } } @@ -273,14 +363,12 @@ double MeshOptimize3d :: CombineImproveEdge (Mesh & mesh, return d_badness; } -void MeshOptimize3d :: CombineImprove (Mesh & mesh, - OPTIMIZEGOAL goal) +void MeshOptimize3d :: CombineImprove () { static Timer t("MeshOptimize3d::CombineImprove"); RegionTimer reg(t); static Timer topt("Optimize"); - static Timer tsearch("Search"); + static Timer tsearch("Search-combine"); static Timer tbuild_elements_table("Build elements table"); - static Timer tbad("CalcBad"); mesh.BuildBoundaryEdges(false); @@ -288,7 +376,6 @@ void MeshOptimize3d :: CombineImprove (Mesh & mesh, int ne = mesh.GetNE(); int ntasks = 4*ngcore::TaskManager::GetNumThreads(); - Array elerrs (ne); Array is_point_removed (np); is_point_removed = false; @@ -300,26 +387,11 @@ void MeshOptimize3d :: CombineImprove (Mesh & mesh, multithread.task = "Optimize Volume: Combine Improve"; - tbad.Start(); - double totalbad = 0.0; - ParallelForRange(Range(ne), [&] (auto myrange) - { - double totalbad_local = 0.0; - for (ElementIndex ei : myrange) - { - if(mesh.GetDimension()==3 && mp.only3D_domain_nr && mp.only3D_domain_nr != mesh[ei].GetIndex()) - continue; - double elerr = CalcBad (mesh.Points(), mesh[ei], 0); - totalbad_local += elerr; - elerrs[ei] = elerr; - } - AtomicAdd(totalbad, totalbad_local); - }, ntasks); - tbad.Stop(); + UpdateBadness(); - if (goal == OPT_QUALITY) + if (goal == OPT_QUALITY && testout->good()) { - totalbad = mesh.CalcTotalBad (mp); + double totalbad = mesh.CalcTotalBad (mp); (*testout) << "Total badness = " << totalbad << endl; } @@ -338,7 +410,7 @@ void MeshOptimize3d :: CombineImprove (Mesh & mesh, for(auto i : myrange) { auto [p0,p1] = edges[i]; - double d_badness = CombineImproveEdge (mesh, mp, elementsonnode, elerrs, p0, p1, is_point_removed, true); + double d_badness = CombineImproveEdge (elementsonnode, p0, p1, is_point_removed, true); if(d_badness<0.0) { int index = improvement_counter++; @@ -360,7 +432,7 @@ void MeshOptimize3d :: CombineImprove (Mesh & mesh, for(auto [d_badness, ei] : edges_with_improvement) { auto [p0,p1] = edges[ei]; - if (CombineImproveEdge (mesh, mp, elementsonnode, elerrs, p0, p1, is_point_removed, false) < 0.0) + if (CombineImproveEdge (elementsonnode, p0, p1, is_point_removed, false) < 0.0) cnt++; } topt.Stop(); @@ -371,13 +443,14 @@ void MeshOptimize3d :: CombineImprove (Mesh & mesh, PrintMessage (5, cnt, " elements combined"); (*testout) << "CombineImprove done" << "\n"; - if (goal == OPT_QUALITY) + if (goal == OPT_QUALITY && testout->good()) { - totalbad = mesh.CalcTotalBad (mp); + double totalbad = mesh.CalcTotalBad (mp); (*testout) << "Total badness = " << totalbad << endl; int cntill = 0; - for (ElementIndex ei = 0; ei < ne; ei++) + // for (ElementIndex ei = 0; ei < ne; ei++) + for (ElementIndex ei : ngcore::T_Range(ne)) if(!(mesh.GetDimension()==3 && mp.only3D_domain_nr && mp.only3D_domain_nr != mesh.VolumeElement(ei).GetIndex())) if (!mesh.LegalTet (mesh[ei])) cntill++; @@ -389,10 +462,10 @@ void MeshOptimize3d :: CombineImprove (Mesh & mesh, -double MeshOptimize3d :: SplitImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, Table & elementsonnode, Array &elerrs, NgArray &locfaces, double badmax, PointIndex pi1, PointIndex pi2, PointIndex ptmp, bool check_only) +double MeshOptimize3d :: SplitImproveEdge (Table & elementsonnode, NgArray> &locfaces, double badmax, PointIndex pi1, PointIndex pi2, PointIndex ptmp, bool check_only) { double d_badness = 0.0; - int cnt = 0; + // int cnt = 0; ArrayMem hasbothpoints; @@ -418,21 +491,14 @@ double MeshOptimize3d :: SplitImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, Table if(mp.only3D_domain_nr != mesh[ei].GetIndex()) return 0.0; - if (goal == OPT_LEGAL) - { - bool all_tets_legal = true; - for(auto ei : hasbothpoints) - if( !mesh.LegalTet (mesh[ei]) || elerrs[ei] > 1e3) - all_tets_legal = false; - if(all_tets_legal) - return 0.0; - } + if (!NeedsOptimization(hasbothpoints)) + return 0.0; double bad1 = 0.0; double bad1_max = 0.0; for (ElementIndex ei : hasbothpoints) { - double bad = elerrs[ei]; + double bad = mesh[ei].GetBadness(); bad1 += bad; bad1_max = max(bad1_max, bad); } @@ -457,11 +523,11 @@ double MeshOptimize3d :: SplitImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, Table for (int l = 0; l < 4; l++) if (el[l] == pi1 || el[l] == pi2) { - INDEX_3 i3; + PointIndices<3> i3; Element2d face(TRIG); el.GetFace (l+1, face); - for (int kk = 1; kk <= 3; kk++) - i3.I(kk) = face.PNum(kk); + for (int kk = 0; kk < 3; kk++) + i3[kk] = face[kk]; locfaces.Append (i3); } } @@ -481,7 +547,7 @@ double MeshOptimize3d :: SplitImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, Table { int pok = pf.Func (px) < 1e10; if (!pok) - pok = FindInnerPoint (mesh.Points(), locfaces, pnew); + pok = FindInnerPoint (mesh.Points(), locfaces, pnew); if(pok) { @@ -497,36 +563,47 @@ double MeshOptimize3d :: SplitImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, Table double bad2 = pf.Func (px); - mesh[ptmp] = Point<3>(pnew); - for (int k = 0; k < hasbothpoints.Size(); k++) { Element & oldel = mesh[hasbothpoints[k]]; Element newel1 = oldel; Element newel2 = oldel; - oldel.Flags().illegal_valid = 0; - newel1.Flags().illegal_valid = 0; - newel2.Flags().illegal_valid = 0; + newel1.Touch(); + newel2.Touch(); + Point<3> pel1[4]; + Point<3> pel2[4]; for (int l = 0; l < 4; l++) { - if (newel1[l] == pi2) newel1[l] = ptmp; - if (newel2[l] == pi1) newel2[l] = ptmp; + pel1[l] = pel2[l] = mesh[oldel[l]]; + if (newel1[l] == pi2) { + newel1[l] = ptmp; + pel1[l] = pnew; + } + if (newel2[l] == pi1) { + newel2[l] = ptmp; + pel2[l] = pnew; + } } - if (!mesh.LegalTet (oldel)) bad1 += 1e6; - if (!mesh.LegalTet (newel1)) bad2 += 1e6; - if (!mesh.LegalTet (newel2)) bad2 += 1e6; + if (!mesh.LegalTet (oldel)) return 0.0; + if (!mesh.LegalTet (newel1)) return 0.0; + if (!mesh.LegalTet (newel2)) return 0.0; + + if( WrongOrientation(pel1[0], pel1[1], pel1[2], pel1[3]) || + WrongOrientation(pel2[0], pel2[1], pel2[2], pel2[3]) ) + return 0.0; } + if(bad2 >= 1e24) return 0.0; d_badness = bad2-bad1; if(check_only) return d_badness; if (d_badness<0.0) { - cnt++; + // cnt++; PointIndex pinew = mesh.AddPoint (pnew); @@ -536,11 +613,8 @@ double MeshOptimize3d :: SplitImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, Table Element newel1 = oldel; Element newel2 = oldel; - oldel.Flags().illegal_valid = 0; - oldel.Delete(); - - newel1.Flags().illegal_valid = 0; - newel2.Flags().illegal_valid = 0; + newel1.Touch(); + newel2.Touch(); for (int l = 0; l < 4; l++) { @@ -548,6 +622,9 @@ double MeshOptimize3d :: SplitImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, Table if (newel2[l] == pi1) newel2[l] = pinew; } + oldel.Touch(); + oldel.Delete(); + mesh.AddVolumeElement (newel1); mesh.AddVolumeElement (newel2); } @@ -555,22 +632,19 @@ double MeshOptimize3d :: SplitImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, Table return d_badness; } -void MeshOptimize3d :: SplitImprove (Mesh & mesh, - OPTIMIZEGOAL goal) +void MeshOptimize3d :: SplitImprove () { static Timer t("MeshOptimize3d::SplitImprove"); RegionTimer reg(t); static Timer topt("Optimize"); - static Timer tsearch("Search"); + static Timer tsearch("Search-split"); - int np = mesh.GetNP(); + // int np = mesh.GetNP(); int ne = mesh.GetNE(); double bad = 0.0; double badmax = 0.0; auto elementsonnode = mesh.CreatePoint2ElementTable(nullopt, mp.only3D_domain_nr); - Array elerrs(ne); - const char * savetask = multithread.task; multithread.task = "Optimize Volume: Split Improve"; @@ -578,17 +652,9 @@ void MeshOptimize3d :: SplitImprove (Mesh & mesh, (*testout) << "start SplitImprove" << "\n"; mesh.BuildBoundaryEdges(false); - ParallelFor( mesh.VolumeElements().Range(), [&] (ElementIndex ei) NETGEN_LAMBDA_INLINE - { - if(mp.only3D_domain_nr && mp.only3D_domain_nr != mesh.VolumeElement(ei).GetIndex()) - return; + UpdateBadness(); - elerrs[ei] = CalcBad (mesh.Points(), mesh[ei], 0); - bad += elerrs[ei]; - AtomicMax(badmax, elerrs[ei]); - }); - - if (goal == OPT_QUALITY) + if (goal == OPT_QUALITY && testout->good()) { bad = mesh.CalcTotalBad (mp); (*testout) << "Total badness = " << bad << endl; @@ -605,12 +671,12 @@ void MeshOptimize3d :: SplitImprove (Mesh & mesh, tsearch.Start(); ParallelForRange(Range(edges), [&] (auto myrange) { - NgArray locfaces; + NgArray> locfaces; for(auto i : myrange) { auto [p0,p1] = edges[i]; - double d_badness = SplitImproveEdge (mesh, goal, elementsonnode, elerrs, locfaces, badmax, p0, p1, ptmp, true); + double d_badness = SplitImproveEdge (elementsonnode, locfaces, badmax, p0, p1, ptmp, true); if(d_badness<0.0) { int index = improvement_counter++; @@ -629,11 +695,11 @@ void MeshOptimize3d :: SplitImprove (Mesh & mesh, // Apply actual optimizations topt.Start(); int cnt = 0; - NgArray locfaces; + NgArray> locfaces; for(auto [d_badness, ei] : edges_with_improvement) { auto [p0,p1] = edges[ei]; - if (SplitImproveEdge (mesh, goal, elementsonnode, elerrs, locfaces, badmax, p0, p1, ptmp, false) < 0.0) + if (SplitImproveEdge (elementsonnode, locfaces, badmax, p0, p1, ptmp, false) < 0.0) cnt++; } topt.Stop(); @@ -643,12 +709,16 @@ void MeshOptimize3d :: SplitImprove (Mesh & mesh, if (goal == OPT_QUALITY) { - bad = mesh.CalcTotalBad (mp); - (*testout) << "Total badness = " << bad << endl; + if(testout->good()) + { + bad = mesh.CalcTotalBad (mp); + (*testout) << "Total badness = " << bad << endl; + } - int cntill = 0; + [[maybe_unused]] int cntill = 0; ne = mesh.GetNE(); - for (ElementIndex ei = 0; ei < ne; ei++) + // for (ElementIndex ei = 0; ei < ne; ei++) + for (auto ei : ngcore::T_Range(ne)) if (!mesh.LegalTet (mesh[ei])) cntill++; // cout << cntill << " illegal tets" << endl; @@ -657,21 +727,12 @@ void MeshOptimize3d :: SplitImprove (Mesh & mesh, multithread.task = savetask; } - -double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, - const NgBitArray * working_elements, +double MeshOptimize3d :: SwapImproveEdge ( + const TBitArray * working_elements, Table & elementsonnode, INDEX_3_HASHTABLE & faces, PointIndex pi1, PointIndex pi2, bool check_only) { - PointIndex pi3(PointIndex::INVALID), pi4(PointIndex::INVALID), - pi5(PointIndex::INVALID), pi6(PointIndex::INVALID); - - double bad1, bad2, bad3; - - Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET); - Element el1(TET), el2(TET), el3(TET), el4(TET); - Element el1b(TET), el2b(TET), el3b(TET), el4b(TET); ArrayMem hasbothpoints; double d_badness = 0.0; @@ -706,8 +767,6 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, } } - bool have_bad_element = false; - for (ElementIndex ei : hasbothpoints) { if (mesh[ei].GetType () != TET) @@ -722,26 +781,57 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, if(working_elements && ei < working_elements->Size() && - !working_elements->Test(ei)) + !working_elements->Test(ei)) return 0.0; if (mesh[ei].IsDeleted()) return 0.0; - if ((goal == OPT_LEGAL) && - mesh.LegalTet (mesh[ei]) && - CalcBad (mesh.Points(), mesh[ei], 0) >= 1e3) - have_bad_element = true; + if(WrongOrientation(mesh.Points(), mesh[ei])) + return 0.0; } - if ((goal == OPT_LEGAL) && !have_bad_element) + if(!NeedsOptimization(hasbothpoints)) return 0.0; int nsuround = hasbothpoints.Size(); int mattyp = mesh[hasbothpoints[0]].GetIndex(); + auto fix_orientation = [&] (Element & el) { + if (WrongOrientation (mesh.Points(), el)) + el.Invert(); + }; + + auto El = [&] ( PointIndex pi0, PointIndex pi1, PointIndex pi2, PointIndex pi3) -> Element { + Element el(TET); + el[0] = pi0; + el[1] = pi1; + el[2] = pi2; + el[3] = pi3; + el.SetIndex (mattyp); + // fix_orientation(el); + return el; + }; + + auto combined_badness = [&] (std::initializer_list els, bool apply_illegal_penalty = true) { + double bad = 0.0; + bool have_illegal = false; + for (auto el : els) { + bad += CalcBad(mesh.Points(), el, 0); + if(apply_illegal_penalty && !have_illegal) { + el.Touch(); + have_illegal = !mesh.LegalTet(el); + } + } + if(have_illegal && apply_illegal_penalty) + bad += GetLegalPenalty(); + return bad; + }; + if ( nsuround == 3 ) { + PointIndex pi3(PointIndex::INVALID), pi4(PointIndex::INVALID), pi5(PointIndex::INVALID); + Element & elem = mesh[hasbothpoints[0]]; for (int l = 0; l < 4; l++) if (elem[l] != pi1 && elem[l] != pi2) @@ -750,12 +840,7 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, pi3 = elem[l]; } - el31[0] = pi1; - el31[1] = pi2; - el31[2] = pi3; - el31[3] = pi4; - el31.SetIndex (mattyp); - + auto el31 = El(pi1, pi2, pi3, pi4); if (WrongOrientation (mesh.Points(), el31)) { Swap (pi3, pi4); @@ -783,57 +868,18 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, throw NgException("Illegal state observed in SwapImprove"); - el32[0] = pi1; - el32[1] = pi2; - el32[2] = pi4; - el32[3] = pi5; - el32.SetIndex (mattyp); + auto el32 = El(pi1, pi2, pi4, pi5); + auto el33 = El(pi1, pi2, pi5, pi3); - el33[0] = pi1; - el33[1] = pi2; - el33[2] = pi5; - el33[3] = pi3; - el33.SetIndex (mattyp); + auto el21 = El(pi3, pi4, pi5, pi2); + auto el22 = El(pi5, pi4, pi3, pi1); - bad1 = CalcBad (mesh.Points(), el31, 0) + - CalcBad (mesh.Points(), el32, 0) + - CalcBad (mesh.Points(), el33, 0); + double bad1 = combined_badness({el31, el32, el33}); + double bad2 = combined_badness({el21, el22}); - el31.Flags().illegal_valid = 0; - el32.Flags().illegal_valid = 0; - el33.Flags().illegal_valid = 0; - - if (!mesh.LegalTet(el31) || - !mesh.LegalTet(el32) || - !mesh.LegalTet(el33)) - bad1 += 1e4; - - el21[0] = pi3; - el21[1] = pi4; - el21[2] = pi5; - el21[3] = pi2; - el21.SetIndex (mattyp); - - el22[0] = pi5; - el22[1] = pi4; - el22[2] = pi3; - el22[3] = pi1; - el22.SetIndex (mattyp); - - bad2 = CalcBad (mesh.Points(), el21, 0) + - CalcBad (mesh.Points(), el22, 0); - - el21.Flags().illegal_valid = 0; - el22.Flags().illegal_valid = 0; - - if (!mesh.LegalTet(el21) || - !mesh.LegalTet(el22)) - bad2 += 1e4; - - - if (goal == OPT_CONFORM && NotTooBad(bad1, bad2)) + if ((goal == OPT_CONFORM) && NotTooBad(bad1, bad2)) { - INDEX_3 face(pi3, pi4, pi5); + PointIndices<3> face(pi3, pi4, pi5); face.Sort(); if (faces.Used(face)) { @@ -866,8 +912,6 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, mesh[hasbothpoints[1]].Delete(); mesh[hasbothpoints[2]].Delete(); - el21.Flags().illegal_valid = 0; - el22.Flags().illegal_valid = 0; mesh.AddVolumeElement(el21); mesh.AddVolumeElement(el22); } @@ -875,6 +919,9 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, if (nsuround == 4) { + PointIndex pi3(PointIndex::INVALID), pi4(PointIndex::INVALID); + PointIndex pi5(PointIndex::INVALID), pi6(PointIndex::INVALID); + const Element & elem1 = mesh[hasbothpoints[0]]; for (int l = 0; l < 4; l++) if (elem1[l] != pi1 && elem1[l] != pi2) @@ -883,9 +930,7 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, pi3 = elem1[l]; } - el1[0] = pi1; el1[1] = pi2; - el1[2] = pi3; el1[3] = pi4; - el1.SetIndex (mattyp); + auto el1 = El(pi1, pi2, pi3, pi4); if (WrongOrientation (mesh.Points(), el1)) { @@ -920,115 +965,26 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, } } - el1[0] = pi1; el1[1] = pi2; - el1[2] = pi3; el1[3] = pi4; - el1.SetIndex (mattyp); + el1 = El(pi1, pi2, pi3, pi4); + auto el2 = El(pi1, pi2, pi4, pi5); + auto el3 = El(pi1, pi2, pi5, pi6); + auto el4 = El(pi1, pi2, pi6, pi3); + double bad1 = combined_badness({el1, el2, el3, el4}, goal != OPT_CONFORM); - el2[0] = pi1; el2[1] = pi2; - el2[2] = pi4; el2[3] = pi5; - el2.SetIndex (mattyp); + el1 = El(pi3, pi5, pi2, pi4); + el2 = El(pi3, pi5, pi4, pi1); + el3 = El(pi3, pi5, pi1, pi6); + el4 = El(pi3, pi5, pi6, pi2); + double bad2 = combined_badness({el1, el2, el3, el4}, goal != OPT_CONFORM); - el3[0] = pi1; el3[1] = pi2; - el3[2] = pi5; el3[3] = pi6; - el3.SetIndex (mattyp); + auto el1b = El(pi4, pi6, pi3, pi2); + auto el2b = El(pi4, pi6, pi2, pi5); + auto el3b = El(pi4, pi6, pi5, pi1); + auto el4b = El(pi4, pi6, pi1, pi3); + double bad3 = combined_badness({el1b, el2b, el3b, el4b}, goal != OPT_CONFORM); - el4[0] = pi1; el4[1] = pi2; - el4[2] = pi6; el4[3] = pi3; - el4.SetIndex (mattyp); - - bad1 = CalcBad (mesh.Points(), el1, 0) + - CalcBad (mesh.Points(), el2, 0) + - CalcBad (mesh.Points(), el3, 0) + - CalcBad (mesh.Points(), el4, 0); - - - el1.Flags().illegal_valid = 0; - el2.Flags().illegal_valid = 0; - el3.Flags().illegal_valid = 0; - el4.Flags().illegal_valid = 0; - - - if (goal != OPT_CONFORM) - { - if (!mesh.LegalTet(el1) || - !mesh.LegalTet(el2) || - !mesh.LegalTet(el3) || - !mesh.LegalTet(el4)) - bad1 += 1e4; - } - - el1[0] = pi3; el1[1] = pi5; - el1[2] = pi2; el1[3] = pi4; - el1.SetIndex (mattyp); - - el2[0] = pi3; el2[1] = pi5; - el2[2] = pi4; el2[3] = pi1; - el2.SetIndex (mattyp); - - el3[0] = pi3; el3[1] = pi5; - el3[2] = pi1; el3[3] = pi6; - el3.SetIndex (mattyp); - - el4[0] = pi3; el4[1] = pi5; - el4[2] = pi6; el4[3] = pi2; - el4.SetIndex (mattyp); - - bad2 = CalcBad (mesh.Points(), el1, 0) + - CalcBad (mesh.Points(), el2, 0) + - CalcBad (mesh.Points(), el3, 0) + - CalcBad (mesh.Points(), el4, 0); - - el1.Flags().illegal_valid = 0; - el2.Flags().illegal_valid = 0; - el3.Flags().illegal_valid = 0; - el4.Flags().illegal_valid = 0; - - if (goal != OPT_CONFORM) - { - if (!mesh.LegalTet(el1) || - !mesh.LegalTet(el2) || - !mesh.LegalTet(el3) || - !mesh.LegalTet(el4)) - bad2 += 1e4; - } - - - el1b[0] = pi4; el1b[1] = pi6; - el1b[2] = pi3; el1b[3] = pi2; - el1b.SetIndex (mattyp); - - el2b[0] = pi4; el2b[1] = pi6; - el2b[2] = pi2; el2b[3] = pi5; - el2b.SetIndex (mattyp); - - el3b[0] = pi4; el3b[1] = pi6; - el3b[2] = pi5; el3b[3] = pi1; - el3b.SetIndex (mattyp); - - el4b[0] = pi4; el4b[1] = pi6; - el4b[2] = pi1; el4b[3] = pi3; - el4b.SetIndex (mattyp); - - bad3 = CalcBad (mesh.Points(), el1b, 0) + - CalcBad (mesh.Points(), el2b, 0) + - CalcBad (mesh.Points(), el3b, 0) + - CalcBad (mesh.Points(), el4b, 0); - - el1b.Flags().illegal_valid = 0; - el2b.Flags().illegal_valid = 0; - el3b.Flags().illegal_valid = 0; - el4b.Flags().illegal_valid = 0; - - if (goal != OPT_CONFORM) - { - if (!mesh.LegalTet(el1b) || - !mesh.LegalTet(el2b) || - !mesh.LegalTet(el3b) || - !mesh.LegalTet(el4b)) - bad3 += 1e4; - } - - bool swap2, swap3; + bool swap2=false; + bool swap3=false; if (goal == OPT_CONFORM) { @@ -1054,10 +1010,6 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, for (auto i : IntRange(4)) mesh[hasbothpoints[i]].Delete(); - el1.Flags().illegal_valid = 0; - el2.Flags().illegal_valid = 0; - el3.Flags().illegal_valid = 0; - el4.Flags().illegal_valid = 0; mesh.AddVolumeElement (el1); mesh.AddVolumeElement (el2); mesh.AddVolumeElement (el3); @@ -1068,10 +1020,6 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, for (auto i : IntRange(4)) mesh[hasbothpoints[i]].Delete(); - el1b.Flags().illegal_valid = 0; - el2b.Flags().illegal_valid = 0; - el3b.Flags().illegal_valid = 0; - el4b.Flags().illegal_valid = 0; mesh.AddVolumeElement (el1b); mesh.AddVolumeElement (el2b); mesh.AddVolumeElement (el3b); @@ -1082,7 +1030,7 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, // if (goal == OPT_QUALITY) if (nsuround >= 5) { - Element hel(TET); + PointIndex pi3(PointIndex::INVALID), pi4(PointIndex::INVALID); NgArrayMem suroundpts(nsuround); NgArrayMem tetused(nsuround); @@ -1096,19 +1044,8 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, pi3 = elem[l]; } - hel[0] = pi1; - hel[1] = pi2; - hel[2] = pi3; - hel[3] = pi4; - hel.SetIndex (mattyp); - - if (WrongOrientation (mesh.Points(), hel)) - { + if (WrongOrientation (mesh.Points(), El(pi1, pi2, pi3, pi4))) Swap (pi3, pi4); - hel[2] = pi3; - hel[3] = pi4; - } - // suroundpts.SetSize (nsuround); suroundpts = PointIndex::INVALID; @@ -1131,10 +1068,7 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, for (int k2 = 0; k2 < 4 && !newpi.IsValid(); k2++) if (nel[k2] == oldpi) { - newpi = - nel[0] + nel[1] + nel[2] + nel[3] - - pi1 - pi2 - oldpi; - + newpi = nel[0] - pi1 + nel[1] - pi2 + nel[2] - oldpi + nel[3]; tetused[k] = true; suroundpts[l] = newpi; } @@ -1142,17 +1076,9 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, } - bad1 = 0; - for (int k = 0; k < nsuround; k++) - { - hel[0] = pi1; - hel[1] = pi2; - hel[2] = suroundpts[k]; - hel[3] = suroundpts[(k+1) % nsuround]; - hel.SetIndex (mattyp); - - bad1 += CalcBad (mesh.Points(), hel, 0); - } + double bad1 = 0; + for (auto k : Range(nsuround)) + bad1 += CalcBad (mesh.Points(), El(pi1, pi2, suroundpts[k], suroundpts[(k+1) % nsuround]), 0); // (*testout) << "nsuround = " << nsuround << " bad1 = " << bad1 << endl; @@ -1164,27 +1090,16 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, for (int l = 0; l < nsuround; l++) { - bad2 = 0; + double bad2 = 0; for (int k = l+1; k <= nsuround + l - 2; k++) { - hel[0] = suroundpts[l]; - hel[1] = suroundpts[k % nsuround]; - hel[2] = suroundpts[(k+1) % nsuround]; - hel[3] = pi2; + PointIndex pil = suroundpts[l]; + PointIndex pik0 = suroundpts[k % nsuround]; + PointIndex pik1 = suroundpts[(k+1) % nsuround]; - bad2 += CalcBad (mesh.Points(), hel, 0); - hel.Flags().illegal_valid = 0; - if (!mesh.LegalTet(hel)) bad2 += 1e4; - - hel[2] = suroundpts[k % nsuround]; - hel[1] = suroundpts[(k+1) % nsuround]; - hel[3] = pi1; - - bad2 += CalcBad (mesh.Points(), hel, 0); - - hel.Flags().illegal_valid = 0; - if (!mesh.LegalTet(hel)) bad2 += 1e4; + bad2 += combined_badness({El(pil, pik0, pik1, pi2)}); + bad2 += combined_badness({El(pil, pik1, pik0, pi1)}); } // (*testout) << "bad2," << l << " = " << bad2 << endl; @@ -1201,9 +1116,9 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, for (int k = l+1; k <= nsuround + l - 2; k++) { - INDEX_3 hi3(suroundpts[l], - suroundpts[k % nsuround], - suroundpts[(k+1) % nsuround]); + PointIndices<3> hi3(suroundpts[l], + suroundpts[k % nsuround], + suroundpts[(k+1) % nsuround]); hi3.Sort(); if (faces.Used(hi3)) { @@ -1247,30 +1162,25 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, for (int k = bestl+1; k <= nsuround + bestl - 2; k++) { - int k1; - - hel[0] = suroundpts[bestl]; - hel[1] = suroundpts[k % nsuround]; - hel[2] = suroundpts[(k+1) % nsuround]; - hel[3] = pi2; - hel.Flags().illegal_valid = 0; + // int k1; + PointIndex pi = suroundpts[bestl]; + PointIndex pik0 = suroundpts[k % nsuround]; + PointIndex pik1 = suroundpts[(k+1) % nsuround]; + auto el = El(pi, pik0, pik1, pi2); /* (*testout) << nsuround << "-swap, new el,top = " - << hel << endl; + << el << endl; */ - mesh.AddVolumeElement (hel); - - hel[2] = suroundpts[k % nsuround]; - hel[1] = suroundpts[(k+1) % nsuround]; - hel[3] = pi1; + mesh.AddVolumeElement (el); + el = El(pi, pik1, pik0, pi1); /* (*testout) << nsuround << "-swap, new el,bot = " - << hel << endl; + << el << endl; */ - mesh.AddVolumeElement (hel); + mesh.AddVolumeElement (el); } for (int k = 0; k < nsuround; k++) @@ -1289,19 +1199,18 @@ double MeshOptimize3d :: SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, return d_badness; } -void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal, - const NgBitArray * working_elements) +void MeshOptimize3d :: SwapImprove (const TBitArray * working_elements) { static Timer t("MeshOptimize3d::SwapImprove"); RegionTimer reg(t); static Timer tloop("MeshOptimize3d::SwapImprove loop"); int cnt = 0; - int np = mesh.GetNP(); - int ne = mesh.GetNE(); + // int np = mesh.GetNP(); + // int ne = mesh.GetNE(); mesh.BuildBoundaryEdges(false); - BitArray free_points(mesh.GetNP()+PointIndex::BASE); + TBitArray free_points(mesh.GetNP()); free_points.Clear(); ParallelForRange(mesh.VolumeElements().Range(), [&] (auto myrange) @@ -1309,7 +1218,7 @@ void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal, for (ElementIndex eli : myrange) { const auto & el = mesh[eli]; - if(el.Flags().fixed) + if(el.Flags().fixed || el.GetType() != TET) continue; if(mp.only3D_domain_nr && mp.only3D_domain_nr != el.GetIndex()) @@ -1337,14 +1246,14 @@ void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal, for (int i = 1; i <= mesh.GetNOpenElements(); i++) { const Element2d & hel = mesh.OpenElement(i); - INDEX_3 face(hel[0], hel[1], hel[2]); + PointIndices<3> face(hel[0], hel[1], hel[2]); face.Sort(); faces.Set (face, i); } } // Calculate total badness - if (goal == OPT_QUALITY) + if (goal == OPT_QUALITY && testout->good()) { double bad1 = mesh.CalcTotalBad (mp); (*testout) << "Total badness = " << bad1 << endl; @@ -1356,6 +1265,8 @@ void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal, Array> candidate_edges(edges.Size()); std::atomic improvement_counter(0); + UpdateBadness(); + tloop.Start(); auto num_elements_before = mesh.VolumeElements().Range().Next(); @@ -1368,7 +1279,7 @@ void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal, break; auto [pi0, pi1] = edges[i]; - double d_badness = SwapImproveEdge (mesh, goal, working_elements, elementsonnode, faces, pi0, pi1, true); + double d_badness = SwapImproveEdge (working_elements, elementsonnode, faces, pi0, pi1, true); if(d_badness<0.0) { int index = improvement_counter++; @@ -1383,7 +1294,7 @@ void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal, for(auto [d_badness, ei] : edges_with_improvement) { auto [pi0,pi1] = edges[ei]; - if(SwapImproveEdge (mesh, goal, working_elements, elementsonnode, faces, pi0, pi1, false) < 0.0) + if(SwapImproveEdge (working_elements, elementsonnode, faces, pi0, pi1, false) < 0.0) cnt++; } @@ -1402,7 +1313,7 @@ void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal, { Element2d sel; el.GetFace(i, sel); - INDEX_3 face(sel[0], sel[1], sel[2]); + PointIndices<3> face(sel[0], sel[1], sel[2]); face.Sort(); if(faces.Used(face)) open_els[faces.Get(face)-1].Delete(); @@ -1425,12 +1336,12 @@ void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal, -void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, - const NgBitArray * working_elements, - const NgArray< NgArray* > * idmaps) +void MeshOptimize3d :: SwapImproveSurface ( + const TBitArray * working_elements, + const NgArray< idmap_type* > * idmaps) { - NgArray< NgArray* > locidmaps; - const NgArray< NgArray* > * used_idmaps; + NgArray< idmap_type* > locidmaps; + const NgArray< idmap_type* > * used_idmaps; if(idmaps) used_idmaps = idmaps; @@ -1442,14 +1353,14 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, { if(mesh.GetIdentifications().GetType(i) == Identifications::PERIODIC) { - locidmaps.Append(new NgArray); + locidmaps.Append(new idmap_type); mesh.GetIdentifications().GetMap(i,*locidmaps.Last(),true); } } } - PointIndex pi1, pi2, pi3, pi4, pi5, pi6; + PointIndex pi1, pi2; // , pi3, pi4, pi5, pi6; PointIndex pi1other, pi2other; int cnt = 0; @@ -1465,9 +1376,9 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, // contains at least all elements at node - TABLE elementsonnode(np); - TABLE surfaceelementsonnode(np); - TABLE surfaceindicesonnode(np); + DynamicTable elementsonnode(np); + DynamicTable surfaceelementsonnode(np); + DynamicTable surfaceindicesonnode(np); NgArray hasbothpoints; NgArray hasbothpointsother; @@ -1517,9 +1428,7 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, if (mesh[ei].IsDeleted()) continue; - if ((goal == OPT_LEGAL) && - mesh.LegalTet (mesh[ei]) && - CalcBad (mesh.Points(), mesh[ei], 0) < 1e3) + if (goal == OPT_LEGAL && mesh.LegalTet (mesh[ei])) continue; const Element & elemi = mesh[ei]; @@ -1536,10 +1445,6 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, // loop over edges - static const int tetedges[6][2] = - { { 0, 1 }, { 0, 2 }, { 0, 3 }, - { 1, 2 }, { 1, 3 }, { 2, 3 } }; - pi1 = elemi[tetedges[j][0]]; pi2 = elemi[tetedges[j][1]]; @@ -1551,11 +1456,11 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, bool found = false; for(int k=0; !found && kSize(); k++) { - if(pi2 < (*used_idmaps)[k]->Size() + PointIndex::BASE) + if(pi2 < (*used_idmaps)[k]->Size() + IndexBASE()) { pi1other = (*(*used_idmaps)[k])[pi1]; pi2other = (*(*used_idmaps)[k])[pi2]; - found = (pi1other != 0 && pi2other != 0 && pi1other != pi1 && pi2other != pi2); + found = (pi1other.IsValid() && pi2other.IsValid() && pi1other != pi1 && pi2other != pi2); if(found) idnum = k; } @@ -1576,14 +1481,14 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, othermattype = -1; - INDEX_2 i2 (pi1, pi2); + PointIndices<2> i2 (pi1, pi2); i2.Sort(); if (edgeused.Used(i2)) continue; edgeused.Set (i2, 1); if(periodic) { - i2.I1() = pi1other; - i2.I2() = pi2other; + i2[0] = pi1other; + i2[1] = pi2other; i2.Sort(); edgeused.Set(i2,1); } @@ -1739,7 +1644,7 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, //(*testout) << "sel1 " << sel1 << " sel2 " << sel2 << " el " << mesh[sel1] << " resp. " << mesh[sel2] << endl; - PointIndex sp1(0), sp2(0); + PointIndex sp1(PointIndex::INVALID), sp2(PointIndex::INVALID); PointIndex sp1other, sp2other; for(int l=0; l outerpoints(nsuround+1); + NgArray < PointIndex > outerpoints(nsuround+1); outerpoints[0] = sp1; for(int i=0; i 0) + if(mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0].IsValid()) (*testout) << mesh[hasbothpoints[ii]][jj] << " between " << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] << " and " << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][1] << endl; @@ -1841,11 +1746,11 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, << "sel2 " << mesh[sel2] << endl; for(int ii=0; ii<3; ii++) { - if(mesh.mlbetweennodes[mesh[sel1][ii]][0] > 0) + if(mesh.mlbetweennodes[mesh[sel1][ii]][0].IsValid()) (*testout) << mesh[sel1][ii] << " between " << mesh.mlbetweennodes[mesh[sel1][ii]][0] << " and " << mesh.mlbetweennodes[mesh[sel1][ii]][1] << endl; - if(mesh.mlbetweennodes[mesh[sel2][ii]][0] > 0) + if(mesh.mlbetweennodes[mesh[sel2][ii]][0].IsValid()) (*testout) << mesh[sel2][ii] << " between " << mesh.mlbetweennodes[mesh[sel2][ii]][0] << " and " << mesh.mlbetweennodes[mesh[sel2][ii]][1] << endl; @@ -1853,7 +1758,7 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, } - NgArray < int > outerpointsother; + NgArray < PointIndex > outerpointsother; if(nsuroundother > 0) { @@ -1894,7 +1799,7 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, { (*testout) << mesh[hasbothpoints[ii]] << endl; for(int jj=0; jj 0) + if(mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0].IsValid()) (*testout) << mesh[hasbothpoints[ii]][jj] << " between " << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][0] << " and " << mesh.mlbetweennodes[mesh[hasbothpoints[ii]][jj]][1] << endl; @@ -1904,11 +1809,11 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, << "sel2 " << mesh[sel2] << endl; for(int ii=0; ii<3; ii++) { - if(mesh.mlbetweennodes[mesh[sel1][ii]][0] > 0) + if(mesh.mlbetweennodes[mesh[sel1][ii]][0].IsValid()) (*testout) << mesh[sel1][ii] << " between " << mesh.mlbetweennodes[mesh[sel1][ii]][0] << " and " << mesh.mlbetweennodes[mesh[sel1][ii]][1] << endl; - if(mesh.mlbetweennodes[mesh[sel2][ii]][0] > 0) + if(mesh.mlbetweennodes[mesh[sel2][ii]][0].IsValid()) (*testout) << mesh[sel2][ii] << " between " << mesh.mlbetweennodes[mesh[sel2][ii]][0] << " and " << mesh.mlbetweennodes[mesh[sel2][ii]][1] << endl; @@ -1920,7 +1825,7 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, { (*testout) << mesh[hasbothpointsother[ii]] << endl; for(int jj=0; jj 0) + if(mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][0].IsValid()) (*testout) << mesh[hasbothpointsother[ii]][jj] << " between " << mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][0] << " and " << mesh.mlbetweennodes[mesh[hasbothpointsother[ii]][jj]][1] << endl; @@ -1930,11 +1835,11 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, << "sel2other " << mesh[sel2other] << endl; for(int ii=0; ii<3; ii++) { - if(mesh.mlbetweennodes[mesh[sel1other][ii]][0] > 0) + if(mesh.mlbetweennodes[mesh[sel1other][ii]][0].IsValid()) (*testout) << mesh[sel1other][ii] << " between " << mesh.mlbetweennodes[mesh[sel1other][ii]][0] << " and " << mesh.mlbetweennodes[mesh[sel1other][ii]][1] << endl; - if(mesh.mlbetweennodes[mesh[sel2other][ii]][0] > 0) + if(mesh.mlbetweennodes[mesh[sel2other][ii]][0].IsValid()) (*testout) << mesh[sel2other][ii] << " between " << mesh.mlbetweennodes[mesh[sel2other][ii]][0] << " and " << mesh.mlbetweennodes[mesh[sel2other][ii]][1] << endl; @@ -2287,9 +2192,9 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal, 2 -> 3 conversion */ -double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementIndex eli1, int face, - Table & elementsonnode, - TABLE & belementsonnode, bool check_only ) +double MeshOptimize3d :: SwapImprove2 ( ElementIndex eli1, int face, + Table & elementsonnode, + DynamicTable & belementsonnode, bool conform_segments, bool check_only ) { PointIndex pi1, pi2, pi3, pi4, pi5; Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET); @@ -2323,28 +2228,31 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI } - bool bface = 0; - for (int k = 0; k < belementsonnode[pi1].Size(); k++) - { - const Element2d & bel = - mesh[belementsonnode[pi1][k]]; + if(!conform_segments) + { + bool bface = 0; + for (int k = 0; k < belementsonnode[pi1].Size(); k++) + { + const Element2d & bel = + mesh[belementsonnode[pi1][k]]; - bool bface1 = 1; - for (int l = 0; l < 3; l++) - if (bel[l] != pi1 && bel[l] != pi2 && bel[l] != pi3) + bool bface1 = 1; + for (int l = 0; l < 3; l++) + if (bel[l] != pi1 && bel[l] != pi2 && bel[l] != pi3) + { + bface1 = 0; + break; + } + + if (bface1) { - bface1 = 0; + bface = 1; break; } - - if (bface1) - { - bface = 1; - break; } - } - if (bface) return 0.0; + if (bface) return 0.0; + } FlatArray row = elementsonnode[pi1]; @@ -2370,6 +2278,10 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI if (elem2.GetType() != TET) continue; + ArrayMem elis = {eli1, eli2}; + if(!NeedsOptimization(elis)) + continue; + int comnodes=0; for (int l = 1; l <= 4; l++) if (elem2.PNum(l) == pi1 || elem2.PNum(l) == pi2 || @@ -2384,13 +2296,14 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI if (comnodes == 3) { - bad1 = CalcBad (mesh.Points(), elem, 0) + - CalcBad (mesh.Points(), elem2, 0); + bad1 = elem.GetBadness() + elem2.GetBadness(); if (!mesh.LegalTet(elem) || !mesh.LegalTet(elem2)) - bad1 += 1e4; + bad1 += GetLegalPenalty(); + if(mesh.BoundaryEdge (pi4, pi5)) + bad1 += GetLegalPenalty(); el31.PNum(1) = pi1; el31.PNum(2) = pi2; @@ -2415,14 +2328,14 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI CalcBad (mesh.Points(), el33, 0); - el31.Flags().illegal_valid = 0; - el32.Flags().illegal_valid = 0; - el33.Flags().illegal_valid = 0; + el31.Touch(); + el32.Touch(); + el33.Touch(); if (!mesh.LegalTet(el31) || !mesh.LegalTet(el32) || !mesh.LegalTet(el33)) - bad2 += 1e4; + bad2 += GetLegalPenalty(); d_badness = bad2 - bad1; @@ -2436,9 +2349,9 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI if (d_badness<0.0) { - el31.Flags().illegal_valid = 0; - el32.Flags().illegal_valid = 0; - el33.Flags().illegal_valid = 0; + el31.Touch(); + el32.Touch(); + el33.Touch(); mesh[eli1].Delete(); mesh[eli2].Delete(); @@ -2457,29 +2370,32 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI 2 -> 3 conversion */ -void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) +void MeshOptimize3d :: SwapImprove2 (bool conform_segments) { static Timer t("MeshOptimize3d::SwapImprove2"); RegionTimer reg(t); - if (goal == OPT_CONFORM) return; + if (!conform_segments && goal == OPT_CONFORM) return; mesh.BuildBoundaryEdges(false); int cnt = 0; - double bad1, bad2; + // double bad1, bad2; int np = mesh.GetNP(); int ne = mesh.GetNE(); int nse = mesh.GetNSE(); // contains at least all elements at node - TABLE belementsonnode(np); + DynamicTable belementsonnode(np); PrintMessage (3, "SwapImprove2 "); (*testout) << "\n" << "Start SwapImprove2" << "\n"; - bad1 = mesh.CalcTotalBad (mp); - (*testout) << "Total badness = " << bad1 << endl; + if(testout->good()) + { + double bad1 = mesh.CalcTotalBad (mp); + (*testout) << "Total badness = " << bad1 << endl; + } // find elements on node @@ -2495,6 +2411,8 @@ void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) Array> faces_with_improvement; Array>> faces_with_improvement_threadlocal(num_threads); + UpdateBadness(); + ParallelForRange( Range(ne), [&]( auto myrange ) { int tid = ngcore::TaskManager::GetThreadId(); @@ -2510,9 +2428,7 @@ void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) if (mesh[eli1].GetType() != TET) continue; - if ((goal == OPT_LEGAL) && - mesh.LegalTet (mesh[eli1]) && - CalcBad (mesh.Points(), mesh[eli1], 0) < 1e3) + if (goal == OPT_LEGAL && mesh.LegalTet (mesh[eli1])) continue; if(mesh.GetDimension()==3 && mp.only3D_domain_nr && mp.only3D_domain_nr != mesh.VolumeElement(eli1).GetIndex()) @@ -2520,7 +2436,7 @@ void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) for (int j = 0; j < 4; j++) { - double d_badness = SwapImprove2( mesh, goal, eli1, j, elementsonnode, belementsonnode, true); + double d_badness = SwapImprove2( eli1, j, elementsonnode, belementsonnode, conform_segments, true); if(d_badness<0.0) my_faces_with_improvement.Append( std::make_tuple(d_badness, eli1, j) ); } @@ -2536,22 +2452,24 @@ void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) { if(mesh[eli].IsDeleted()) continue; - if(SwapImprove2( mesh, goal, eli, j, elementsonnode, belementsonnode, false) < 0.0) + if(SwapImprove2( eli, j, elementsonnode, belementsonnode, conform_segments, false) < 0.0) cnt++; } PrintMessage (5, cnt, " swaps performed"); mesh.Compress(); - bad1 = mesh.CalcTotalBad (mp); - (*testout) << "Total badness = " << bad1 << endl; - (*testout) << "swapimprove2 done" << "\n"; + if(testout->good()) + { + double bad1 = mesh.CalcTotalBad (mp); + (*testout) << "Total badness = " << bad1 << endl; + (*testout) << "swapimprove2 done" << "\n"; + } } -double MeshOptimize3d :: SplitImprove2Element (Mesh & mesh, +double MeshOptimize3d :: SplitImprove2Element ( ElementIndex ei, const Table & elements_of_point, - const Array & el_badness, bool check_only) { auto & el = mesh[ei]; @@ -2559,17 +2477,13 @@ double MeshOptimize3d :: SplitImprove2Element (Mesh & mesh, return false; // Optimize only bad elements - if(el_badness[ei] < 100) + if(el.GetBadness() < 100) return false; // search for very flat tets, with two disjoint edges nearly crossing, like a rectangle with diagonals - static constexpr int tetedges[6][2] = - { { 0, 1 }, { 0, 2 }, { 0, 3 }, - { 1, 2 }, { 1, 3 }, { 2, 3 } }; - int minedge = -1; double mindist = 1e99; - double minlam0, minlam1; + double minlam0=0, minlam1=0; for (int i : Range(3)) { @@ -2618,6 +2532,7 @@ double MeshOptimize3d :: SplitImprove2Element (Mesh & mesh, Element & elem = mesh[ei0]; if (elem.IsDeleted()) return false; if (ei0 == ei) continue; + if (elem.GetType() != TET) return false; if (elem[0] == pi1 || elem[1] == pi1 || elem[2] == pi1 || elem[3] == pi1 || (elem.GetNP()==5 && elem[4]==pi1) ) if(!has_both_points0.Contains(ei0)) @@ -2629,27 +2544,28 @@ double MeshOptimize3d :: SplitImprove2Element (Mesh & mesh, Element & elem = mesh[ei1]; if (elem.IsDeleted()) return false; if (ei1 == ei) continue; + if (elem.GetType() != TET) return false; if (elem[0] == pi3 || elem[1] == pi3 || elem[2] == pi3 || elem[3] == pi3 || (elem.GetNP()==5 && elem[4]==pi3)) if(!has_both_points1.Contains(ei1)) has_both_points1.Append (ei1); } - double badness_before = el_badness[ei]; + double badness_before = mesh[ei].GetBadness(); double badness_after = 0.0; for (auto ei0 : has_both_points0) { if(mesh[ei0].GetType()!=TET) return false; - badness_before += el_badness[ei0]; + badness_before += mesh[ei0].GetBadness(); badness_after += SplitElementBadness (mesh.Points(), mp, mesh[ei0], pi0, pi1, pnew); } for (auto ei1 : has_both_points1) { if(mesh[ei1].GetType()!=TET) return false; - badness_before += el_badness[ei1]; + badness_before += mesh[ei1].GetBadness(); badness_after += SplitElementBadness (mesh.Points(), mp, mesh[ei1], pi2, pi3, pnew); } @@ -2659,7 +2575,7 @@ double MeshOptimize3d :: SplitImprove2Element (Mesh & mesh, if(badness_after new point where diagonals cross, remove the flat tet -void MeshOptimize3d :: SplitImprove2 (Mesh & mesh) +void MeshOptimize3d :: SplitImprove2 () { static Timer t("MeshOptimize3d::SplitImprove2"); RegionTimer reg(t); static Timer tsearch("Search"); @@ -2695,18 +2611,7 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh) const char * savetask = multithread.task; multithread.task = "Optimize Volume: Split Improve 2"; - Array el_badness (ne); - - ParallelForRange(Range(ne), [&] (auto myrange) - { - for (ElementIndex ei : myrange) - { - if(mp.only3D_domain_nr && mp.only3D_domain_nr != mesh[ei].GetIndex()) - continue; - el_badness[ei] = CalcBad (mesh.Points(), mesh[ei], 0); - } - }); - + UpdateBadness(); mesh.BuildBoundaryEdges(false); Array> split_candidates(ne); @@ -2719,7 +2624,7 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh) { if(mp.only3D_domain_nr && mp.only3D_domain_nr != mesh[ei].GetIndex()) continue; - double d_badness = SplitImprove2Element(mesh, ei, elements_of_point, el_badness, true); + double d_badness = SplitImprove2Element(ei, elements_of_point, true); if(d_badness<0.0) { int index = improvement_counter++; @@ -2736,7 +2641,7 @@ void MeshOptimize3d :: SplitImprove2 (Mesh & mesh) topt.Start(); for(auto [d_badness, ei] : elements_with_improvement) { - if( SplitImprove2Element(mesh, ei, elements_of_point, el_badness, false) < 0.0) + if( SplitImprove2Element(ei, elements_of_point, false) < 0.0) cnt++; } topt.Stop(); diff --git a/libsrc/meshing/improve3.hpp b/libsrc/meshing/improve3.hpp index 605c523c..92987dd6 100644 --- a/libsrc/meshing/improve3.hpp +++ b/libsrc/meshing/improve3.hpp @@ -1,42 +1,54 @@ #ifndef FILE_IMPROVE3 #define FILE_IMPROVE3 - -extern double CalcTotalBad (const Mesh::T_POINTS & points, - const Array & elements, - const MeshingParameters & mp); +namespace netgen +{ /// class MeshOptimize3d { + Mesh & mesh; const MeshingParameters & mp; + OPTIMIZEGOAL goal = OPT_QUALITY; + double min_badness = 0; + + bool HasBadElement(FlatArray els); + bool HasIllegalElement(FlatArray els); + bool NeedsOptimization(FlatArray els); public: - MeshOptimize3d (const MeshingParameters & amp) : mp(amp) { ; } - double CombineImproveEdge (Mesh & mesh, const MeshingParameters & mp, + MeshOptimize3d (Mesh & m, const MeshingParameters & amp, OPTIMIZEGOAL agoal = OPT_QUALITY) : + mesh(m), mp(amp), goal(agoal) { ; } + + void SetGoal(OPTIMIZEGOAL agoal) { goal = agoal; } + void SetMinBadness(double badness) { min_badness = badness; } + + tuple UpdateBadness(); + + double CombineImproveEdge ( Table & elements_of_point, - Array & elerrs, PointIndex pi0, PointIndex pi1, + PointIndex pi0, PointIndex pi1, FlatArray is_point_removed, bool check_only=false); - void CombineImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY); + void CombineImprove (); - void SplitImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY); - double SplitImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, Table & elementsonnode, Array &elerrs, NgArray &locfaces, double badmax, PointIndex pi1, PointIndex pi2, PointIndex ptmp, bool check_only=false); + void SplitImprove (); + double SplitImproveEdge (Table & elementsonnode, NgArray> &locfaces, double badmax, PointIndex pi1, PointIndex pi2, PointIndex ptmp, bool check_only=false); - void SplitImprove2 (Mesh & mesh); - double SplitImprove2Element (Mesh & mesh, ElementIndex ei, const Table & elements_of_point, const Array & elerrs, bool check_only); + void SplitImprove2 (); + double SplitImprove2Element (ElementIndex ei, const Table & elements_of_point, bool check_only); - double SwapImproveEdge (Mesh & mesh, OPTIMIZEGOAL goal, const NgBitArray * working_elements, Table & elementsonnode, INDEX_3_HASHTABLE & faces, PointIndex pi1, PointIndex pi2, bool check_only=false); - void SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY, - const NgBitArray * working_elements = NULL); - void SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY, - const NgBitArray * working_elements = NULL, - const NgArray< NgArray* > * idmaps = NULL); - void SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal = OPT_QUALITY); - double SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementIndex eli1, int face, Table & elementsonnode, TABLE & belementsonnode, bool check_only=false ); + double SwapImproveEdge (const TBitArray * working_elements, Table & elementsonnode, INDEX_3_HASHTABLE & faces, PointIndex pi1, PointIndex pi2, bool check_only=false); + void SwapImprove (const TBitArray * working_elements = NULL); + void SwapImproveSurface (const TBitArray * working_elements = NULL, + const NgArray< idmap_type* > * idmaps = NULL); + void SwapImprove2 (bool conform_segments = false); + double SwapImprove2 (ElementIndex eli1, int face, Table & elementsonnode, DynamicTable & belementsonnode, bool conform_segments, bool check_only=false ); + + void ImproveMesh() { mesh.ImproveMesh(mp, goal); } double CalcBad (const Mesh::T_POINTS & points, const Element & elem, double h) @@ -48,10 +60,9 @@ public: } - double CalcTotalBad (const Mesh::T_POINTS & points, - const Array & elements) + double GetLegalPenalty() { - return netgen::CalcTotalBad (points, elements, mp); + return goal == OPT_LEGAL ? 1e15 : 1e6; } }; @@ -97,12 +108,12 @@ public: class PointFunction1 : public MinFunction { Mesh::T_POINTS & points; - const NgArray & faces; + const NgArray> & faces; const MeshingParameters & mp; double h; public: PointFunction1 (Mesh::T_POINTS & apoints, - const NgArray & afaces, + const NgArray> & afaces, const MeshingParameters & amp, double ah); @@ -136,6 +147,5 @@ public: inline void UnSetNV(void) {onplane = false;} }; - - +} // namespace netgen #endif diff --git a/libsrc/meshing/localh.cpp b/libsrc/meshing/localh.cpp index b8121b8f..ee8b4e0b 100644 --- a/libsrc/meshing/localh.cpp +++ b/libsrc/meshing/localh.cpp @@ -196,54 +196,41 @@ namespace netgen fabs (p(1) - root->xmid[1]) > root->h2) return; - if (GetH(p) <= 1.2 * h) return; - - GradingBox * box = root; - GradingBox * nbox = root; - GradingBox * ngb; - int childnr; - double x1[3], x2[3]; - - while (nbox) - { - box = nbox; - childnr = 0; - if (p(0) > box->xmid[0]) childnr += 1; - if (p(1) > box->xmid[1]) childnr += 2; - nbox = box->childs[childnr]; - }; + GradingBox * box = Find(p); + if (box->HOpt() <= 1.2 * h) return; while (2 * box->h2 > h) { - childnr = 0; - if (p(0) > box->xmid[0]) childnr += 1; - if (p(1) > box->xmid[1]) childnr += 2; - + int childnr = 0; + double x1[3], x2[3]; + double h2 = box->h2; - if (childnr & 1) + if (p(0) > box->xmid[0]) { + childnr += 1; x1[0] = box->xmid[0]; - x2[0] = x1[0]+h2; // box->x2[0]; + x2[0] = x1[0]+h2; } else { x2[0] = box->xmid[0]; - x1[0] = x2[0]-h2; // box->x1[0]; + x1[0] = x2[0]-h2; } - if (childnr & 2) + if (p(1) > box->xmid[1]) { + childnr += 2; x1[1] = box->xmid[1]; - x2[1] = x1[1]+h2; // box->x2[1]; + x2[1] = x1[1]+h2; } else { x2[1] = box->xmid[1]; - x1[1] = x2[1]-h2; // box->x1[1]; + x1[1] = x2[1]-h2; } x1[2] = x2[2] = 0; - ngb = new GradingBox (x1, x2); + auto ngb = new GradingBox (x1, x2); box->childs[childnr] = ngb; ngb->father = box; @@ -276,67 +263,52 @@ namespace netgen fabs (p(2) - root->xmid[2]) > root->h2) return; - if (GetH(p) <= 1.2 * h) return; - - GradingBox * box = root; - GradingBox * nbox = root; - GradingBox * ngb; - int childnr; - double x1[3], x2[3]; - - while (nbox) - { - box = nbox; - childnr = 0; - if (p(0) > box->xmid[0]) childnr += 1; - if (p(1) > box->xmid[1]) childnr += 2; - if (p(2) > box->xmid[2]) childnr += 4; - nbox = box->childs[childnr]; - }; - + GradingBox * box = Find(p); + if (box->HOpt() <= 1.2 * h) return; while (2 * box->h2 > h) { - childnr = 0; - if (p(0) > box->xmid[0]) childnr += 1; - if (p(1) > box->xmid[1]) childnr += 2; - if (p(2) > box->xmid[2]) childnr += 4; - + double x1[3], x2[3]; + int childnr = 0; double h2 = box->h2; - if (childnr & 1) + + if (p(0) > box->xmid[0]) { + childnr += 1; x1[0] = box->xmid[0]; - x2[0] = x1[0]+h2; // box->x2[0]; + x2[0] = x1[0]+h2; } else { x2[0] = box->xmid[0]; - x1[0] = x2[0]-h2; // box->x1[0]; + x1[0] = x2[0]-h2; } - if (childnr & 2) + if (p(1) > box->xmid[1]) { + childnr += 2; x1[1] = box->xmid[1]; - x2[1] = x1[1]+h2; // box->x2[1]; + x2[1] = x1[1]+h2; } else { x2[1] = box->xmid[1]; - x1[1] = x2[1]-h2; // box->x1[1]; + x1[1] = x2[1]-h2; } - if (childnr & 4) + if (p(2) > box->xmid[2]) { + childnr += 4; x1[2] = box->xmid[2]; - x2[2] = x1[2]+h2; // box->x2[2]; + x2[2] = x1[2]+h2; } else { x2[2] = box->xmid[2]; - x1[2] = x2[2]-h2; // box->x1[2]; + x1[2] = x2[2]-h2; } - ngb = new GradingBox (x1, x2); + auto ngb = new GradingBox (x1, x2); box->childs[childnr] = ngb; ngb->father = box; @@ -366,37 +338,7 @@ namespace netgen double LocalH :: GetH (Point<3> x) const { - const GradingBox * box = root; - if (dimension == 2) - { - while (1) - { - int childnr = 0; - if (x(0) > box->xmid[0]) childnr += 1; - if (x(1) > box->xmid[1]) childnr += 2; - - if (box->childs[childnr]) - box = box->childs[childnr]; - else - return box->hopt; - } - } - else - { - while (1) - { - int childnr = 0; - if (x(0) > box->xmid[0]) childnr += 1; - if (x(1) > box->xmid[1]) childnr += 2; - if (x(2) > box->xmid[2]) childnr += 4; - - if (box->childs[childnr]) - box = box->childs[childnr]; - else - return box->hopt; - } - } - + return Find(x)->HOpt(); } @@ -488,15 +430,50 @@ namespace netgen } + GradingBox * LocalH :: Find (Point<3> p) const + { + GradingBox * box = root; + if (dimension == 2) + { + while (1) + { + int childnr = 0; + if (p(0) > box->xmid[0]) childnr += 1; + if (p(1) > box->xmid[1]) childnr += 2; - void LocalH :: FindInnerBoxes (AdFront3 * adfront, + if (box->childs[childnr]) + box = box->childs[childnr]; + else + return box; + } + } + else + { + while (1) + { + int childnr = 0; + if (p(0) > box->xmid[0]) childnr += 1; + if (p(1) > box->xmid[1]) childnr += 2; + if (p(2) > box->xmid[2]) childnr += 4; + + if (box->childs[childnr]) + box = box->childs[childnr]; + else + return box; + } + } + return nullptr; + } + + + void LocalH :: FindInnerBoxes (const AdFront3 & adfront, int (*testinner)(const Point3d & p1)) { static Timer timer("LocalH::FindInnerBoxes"); RegionTimer reg (timer); - int nf = adfront->GetNF(); + int nf = adfront.GetNF(); for (int i = 0; i < boxes.Size(); i++) boxes[i] -> flags.isinner = 0; @@ -509,7 +486,7 @@ namespace netgen // Point3d rx1 = rpmid - rv; - root->flags.pinner = !adfront->SameSide (rpmid, rx2); + root->flags.pinner = !adfront.SameSide (rpmid, rx2); if (testinner) (*testout) << "inner = " << root->flags.pinner << " =?= " @@ -521,7 +498,7 @@ namespace netgen for (int i = 1; i <= nf; i++) { faceinds.Elem(i) = i; - adfront->GetFaceBoundingBox(i, faceboxes.Elem(i)); + adfront.GetFaceBoundingBox(i, faceboxes.Elem(i)); } for (int i = 0; i < 8; i++) @@ -531,7 +508,7 @@ namespace netgen void LocalH :: FindInnerBoxesRec2 (GradingBox * box, - class AdFront3 * adfront, + const AdFront3 & adfront, NgArray & faceboxes, NgArray & faceinds, int nfinbox) { @@ -592,7 +569,7 @@ namespace netgen box->flags.pinner = 1; else { - if (adfront->SameSide (c, cf, &faceused2)) + if (adfront.SameSide (c, cf, &faceused2)) box->flags.pinner = father->flags.pinner; else box->flags.pinner = 1 - father->flags.pinner; @@ -644,7 +621,7 @@ namespace netgen - void LocalH :: FindInnerBoxes (AdFront2 * adfront, + void LocalH :: FindInnerBoxes (const AdFront2 & adfront, int (*testinner)(const Point<2> & p1)) { static Timer t("LocalH::FindInnerBoxes 2d"); RegionTimer reg (t); @@ -667,23 +644,23 @@ namespace netgen // Point<2> rx1 = rpmid - rv; - root->flags.pinner = !adfront->SameSide (rpmid, rx2); + root->flags.pinner = !adfront.SameSide (rpmid, rx2); if (testinner) (*testout) << "inner = " << root->flags.pinner << " =?= " << testinner(rpmid) << endl; - int nf = adfront->GetNFL(); + int nf = adfront.GetNFL(); Array faceinds(nf); Array> faceboxes(nf); for (int i = 0; i < nf; i++) { faceinds[i] = i; - const FrontLine & line = adfront->GetLine(i); - Point<3> p1 = adfront->GetPoint (line.L().I1()); - Point<3> p2 = adfront->GetPoint (line.L().I2()); + const FrontLine & line = adfront.GetLine(i); + Point<3> p1 = adfront.GetPoint (line.L().I1()); + Point<3> p2 = adfront.GetPoint (line.L().I2()); faceboxes[i].Set (Point<2> (p1(0), p1(1))); faceboxes[i].Add (Point<2> (p2(0), p2(1))); @@ -697,7 +674,7 @@ namespace netgen void LocalH :: FindInnerBoxesRec2 (GradingBox * box, - class AdFront2 * adfront, + const class AdFront2 & adfront, FlatArray> faceboxes, FlatArray faceinds) // , int nfinbox) { @@ -743,7 +720,7 @@ namespace netgen // bool sameside = adfront->SameSide (c2d, cf2d, &faceused2); auto sub = faceinds.Range(0, iused); - bool sameside = adfront->SameSide (c, fc, &sub); + bool sameside = adfront.SameSide (c, fc, &sub); if (sameside) box->flags.pinner = father->flags.pinner; else diff --git a/libsrc/meshing/localh.hpp b/libsrc/meshing/localh.hpp index 979a7ec3..dc061368 100644 --- a/libsrc/meshing/localh.hpp +++ b/libsrc/meshing/localh.hpp @@ -54,6 +54,7 @@ namespace netgen Point<3> PMid() const { return Point<3> (xmid[0], xmid[1], xmid[2]); } double H2() const { return h2; } + double HOpt() const { return hopt; } bool HasChilds() const { @@ -119,12 +120,14 @@ namespace netgen void CutBoundary (const Box<3> & box) { CutBoundaryRec (box.PMin(), box.PMax(), root); } + + GradingBox * Find(Point<3> p) const; /// find inner boxes - void FindInnerBoxes (class AdFront3 * adfront, + void FindInnerBoxes (const class AdFront3 & adfront, int (*testinner)(const Point3d & p1)); - void FindInnerBoxes (class AdFront2 * adfront, + void FindInnerBoxes (const class AdFront2 & adfront, int (*testinner)(const Point<2> & p1)); @@ -166,7 +169,7 @@ namespace netgen /// void FindInnerBoxesRec2 (GradingBox * box, - class AdFront3 * adfront, + const class AdFront3 & adfront, NgArray & faceboxes, NgArray & finds, int nfinbox); @@ -177,7 +180,7 @@ namespace netgen /// void FindInnerBoxesRec2 (GradingBox * box, - class AdFront2 * adfront, + const class AdFront2 & adfront, FlatArray> faceboxes, FlatArray finds); // , int nfinbox); diff --git a/libsrc/meshing/meshclass.cpp b/libsrc/meshing/meshclass.cpp index a5595b23..64ba6f47 100644 --- a/libsrc/meshing/meshclass.cpp +++ b/libsrc/meshing/meshclass.cpp @@ -1,26 +1,26 @@ +#include #include #include +#include #include +#include "core/array.hpp" #include "meshing.hpp" #include "../general/gzstream.h" -#ifdef NG_PYTHON -// must be included to instantiate Archive::Shallow(NetgenGeometry&) -#include -#endif +#include +#include "basegeom.hpp" namespace netgen { - - int Find3dElement (const Mesh& mesh, - const netgen::Point<3> & p, - double * lami, - const NgArray * const indices, - BoxTree<3> * searchtree, - const bool allowindex = true) + ElementIndex Find3dElement (const Mesh& mesh, + const netgen::Point<3> & p, + double * lami, + optional> indices, + BoxTree<3, ElementIndex> * searchtree, + const bool allowindex) { int ne = 0; - NgArray locels; + Array locels; if (searchtree) { searchtree->GetIntersecting (p, p, locels); @@ -29,92 +29,90 @@ namespace netgen else ne = mesh.GetNE(); - for (int i = 1; i <= ne; i++) + for (auto i : Range(ne)) { - int ii; + ElementIndex ei; if (searchtree) - ii = locels.Get(i); + ei = locels[i]; else - ii = i; + ei = i; - if(indices != NULL && indices->Size() > 0) + if(indices && indices->Size() > 0) { - bool contained = indices->Contains(mesh.VolumeElement(ii).GetIndex()); + bool contained = indices->Contains(mesh[ei].GetIndex()); if((allowindex && !contained) || (!allowindex && contained)) continue; } - if(mesh.PointContainedIn3DElement(p,lami,ii)) - return ii; + if(mesh.PointContainedIn3DElement(p,lami,ei)) + return ei; } // Not found, try uncurved variant: - for (int i = 1; i <= ne; i++) + for (auto i : Range(ne)) { - int ii; + ElementIndex ei; if (searchtree) - ii = locels.Get(i); + ei = locels[i]; else - ii = i; + ei = i; - if(indices != NULL && indices->Size() > 0) + if(indices && indices->Size() > 0) { - bool contained = indices->Contains(mesh.VolumeElement(ii).GetIndex()); + bool contained = indices->Contains(mesh[ei].GetIndex()); if((allowindex && !contained) || (!allowindex && contained)) continue; } - if(mesh.PointContainedIn3DElementOld(p,lami,ii)) + if(mesh.PointContainedIn3DElementOld(p,lami,ei)) { (*testout) << "WARNING: found element of point " << p <<" only for uncurved mesh" << endl; - return ii; + return ei; } } - return 0; + return ElementIndex::INVALID; } - int Find2dElement (const Mesh& mesh, - const netgen::Point<3> & p, - double * lami, - const NgArray * const indices, - BoxTree<3> * searchtree, - const bool allowindex = true) + SurfaceElementIndex + Find2dElement (const Mesh& mesh, + const netgen::Point<3> & p, + double * lami, + std::optional> indices, + BoxTree<3, SurfaceElementIndex> * searchtree, + bool allowindex) { double vlam[3]; - int velement = 0; + ElementIndex velement = ElementIndex::INVALID; if(mesh.GetNE()) - velement = Find3dElement(mesh, p,vlam,NULL,searchtree,allowindex); + { + if(searchtree) + const_cast(mesh).BuildElementSearchTree(3); + velement = Find3dElement(mesh, p,vlam, nullopt,searchtree ? mesh.GetElementSearchTree() : nullptr,allowindex); + } //(*testout) << "p " << p << endl; //(*testout) << "velement " << velement << endl; // first try to find a volume element containing p and project to face - if(velement!=0) + if(velement.IsValid()) { auto & topology = mesh.GetTopology(); - // NgArray faces; - // topology.GetElementFaces(velement,faces); - auto faces = Array (topology.GetFaces(ElementIndex(velement-1))); - - //(*testout) << "faces " << faces << endl; - - for(int i=0; i(); + for(auto face : fnrs) + faces.Append(topology.GetFace2SurfaceElement(face)); for(int i=0; iSize() != 0 && !indices->Contains(sel.GetIndex())) + if(indices && indices->Size() > 0 && !indices->Contains(sel.GetIndex())) continue; - auto & el = mesh.VolumeElement(velement); - + auto & el = mesh[velement]; if (el.GetType() == TET) { double lam4[4] = { vlam[0], vlam[1], vlam[2], 1.0-vlam[0]-vlam[1]-vlam[2] }; @@ -127,7 +125,7 @@ namespace netgen for(auto k : Range(4)) if(sel[j] == el[k]) lami[j-1] = lam4[k]/(1.0-face_lam); - return faces[i]; + return SurfaceElementIndex(faces[i]); } } @@ -139,9 +137,8 @@ namespace netgen // Did't find any matching face of a volume element, search 2d elements directly int ne; - NgArray locels; - // TODO: build search tree for surface elements - if (!mesh.GetNE() && searchtree) + Array locels; + if (searchtree) { searchtree->GetIntersecting (p, p, locels); ne = locels.Size(); @@ -149,47 +146,56 @@ namespace netgen else ne = mesh.GetNSE(); - for (int i = 1; i <= ne; i++) + for (auto i : Range(ne)) { - int ii; + SurfaceElementIndex ii; if (locels.Size()) - ii = locels.Get(i); + ii = locels[i]; else ii = i; - if(indices != NULL && indices->Size() > 0) + if(indices && indices->Size() > 0) { - bool contained = indices->Contains(mesh.SurfaceElement(ii).GetIndex()); + bool contained = indices->Contains(mesh[ii].GetIndex()); if((allowindex && !contained) || (!allowindex && contained)) continue; } - - if(mesh.PointContainedIn2DElement(p,lami,ii)) return ii; - + if(mesh.PointContainedIn2DElement(p,lami,ii)) + return ii; } - return 0; + return SurfaceElementIndex::INVALID; } - int Find1dElement (const Mesh& mesh, - const netgen::Point<3> & p, - double * lami, - const NgArray * const indices, - BoxTree<3> * searchtree, - const bool allowindex = true) + SegmentIndex Find1dElement (const Mesh& mesh, + const netgen::Point<3> & p, + double * lami, + std::optional> indices, + BoxTree<3> * searchtree, + const bool allowindex = true) { double vlam[3]; - int velement = Find2dElement(mesh, p, vlam, NULL, searchtree, allowindex); - if(velement == 0) + if(searchtree) + const_cast(mesh).BuildElementSearchTree(2); + auto velement = Find2dElement(mesh, p, vlam, nullopt, searchtree ? mesh.GetSurfaceElementSearchTree() : nullptr, allowindex); + if(!velement.IsValid()) return 0; vlam[2] = 1.-vlam[0] - vlam[1]; - NgArray edges; + // NgArray edges; auto & topology = mesh.GetTopology(); + + /* topology.GetSurfaceElementEdges(velement, edges); Array segs(edges.Size()); for(auto i : Range(edges)) segs[i] = topology.GetSegmentOfEdge(edges[i]); - + */ + auto hedges = topology.GetEdges(SurfaceElementIndex(velement-1)); + Array segs(hedges.Size()); + for(auto i : Range(hedges)) + segs[i] = topology.GetSegmentOfEdge(hedges[i]+1); + + for(auto i : Range(segs)) { if(IsInvalid(segs[i])) @@ -197,8 +203,8 @@ namespace netgen auto& el = mesh.SurfaceElement(velement); if(el.GetType() == TRIG) { - double seg_lam; - double lam; + double seg_lam=-1; + double lam=-1; auto seg = mesh.LineSegment(segs[i]); for(auto k : Range(3)) { @@ -226,14 +232,9 @@ namespace netgen Mesh :: Mesh () : topology(*this), surfarea(*this) { - boundaryedges = nullptr; - surfelementht = nullptr; - segmentht = nullptr; - lochfunc = {nullptr}; - // mglevels = 1; - elementsearchtree = nullptr; - elementsearchtreets = NextTimeStamp(); + for(auto i : Range(4)) + elementsearchtreets[i] = NextTimeStamp(); majortimestamp = timestamp = NextTimeStamp(); hglob = 1e10; hmin = 0; @@ -244,9 +245,6 @@ namespace netgen clusters = make_unique (*this); ident = make_unique (*this); - hpelements = NULL; - coarsemesh = NULL; - ps_startelement = 0; geomtype = NO_GEOM; @@ -254,7 +252,6 @@ namespace netgen bcnames.SetSize(0); cd2names.SetSize(0); - // this->comm = netgen :: ng_comm; #ifdef PARALLEL paralleltop = make_unique (*this); #endif @@ -263,17 +260,6 @@ namespace netgen Mesh :: ~Mesh() { - // delete lochfunc; - // delete boundaryedges; - // delete surfelementht; - // delete segmentht; - // delete curvedelems; - // delete clusters; - // delete ident; - // delete elementsearchtree; - // delete coarsemesh; - // delete hpelements; - for (int i = 0; i < materials.Size(); i++) delete materials[i]; for(int i = 0; i < userdata_int.Size(); i++) @@ -295,6 +281,12 @@ namespace netgen // #endif } + shared_ptr Mesh :: GetGeometry() const + { + static auto global_geometry = make_shared(); + return geometry ? geometry : global_geometry; + } + void Mesh :: SetCommunicator(NgMPI_Comm acomm) { this->comm = acomm; @@ -314,27 +306,35 @@ namespace netgen hglob = mesh2.hglob; hmin = mesh2.hmin; maxhdomain = mesh2.maxhdomain; + pointelements = mesh2.pointelements; + // Remap string* values to new mesh + std::map names_map; + for (auto fi : Range(facedecoding)) + names_map[&mesh2.facedecoding[fi].bcname] = &facedecoding[fi].bcname; + + auto get_name = [&](const string *old_name) -> string* { + if (!old_name) return nullptr; + if (names_map.count(old_name)) return names_map[old_name]; + return new string(*old_name); + }; materials.SetSize( mesh2.materials.Size() ); for ( int i = 0; i < mesh2.materials.Size(); i++ ) - if ( mesh2.materials[i] ) materials[i] = new string ( *mesh2.materials[i] ); + { + const string * old_name = mesh2.materials[i]; + if ( old_name ) materials[i] = dimension == 2 ? get_name(old_name) : new string ( *old_name ); else materials[i] = 0; + } - std::map bcmap; bcnames.SetSize( mesh2.bcnames.Size() ); for ( int i = 0; i < mesh2.bcnames.Size(); i++ ) { - if ( mesh2.bcnames[i] ) bcnames[i] = new string ( *mesh2.bcnames[i] ); + const string * old_name = mesh2.bcnames[i]; + if ( old_name ) bcnames[i] = dimension == 3 ? get_name(old_name) : new string ( *old_name ); else bcnames[i] = 0; - bcmap[mesh2.bcnames[i]] = bcnames[i]; } - // Remap string* members in FaceDescriptor to new mesh - for (auto & f : facedecoding) - f.SetBCName( bcmap[&f.GetBCName()] ); - - cd2names.SetSize(mesh2.cd2names.Size()); for (int i=0; i < mesh2.cd2names.Size(); i++) if (mesh2.cd2names[i]) cd2names[i] = new string(*mesh2.cd2names[i]); @@ -439,8 +439,10 @@ namespace netgen lock.Lock(); timestamp = NextTimeStamp(); - int maxn = max2 (s[0], s[1]); - maxn += 1-PointIndex::BASE; + // int maxn = max2 (s[0], s[1]); + // maxn += 1-PointIndex::BASE; + int maxn = max2 (s[0]-IndexBASE()+1, + s[1]-IndexBASE()+1); /* if (maxn > ptyps.Size()) @@ -527,12 +529,19 @@ namespace netgen void Mesh :: SetSurfaceElement (SurfaceElementIndex sei, const Element2d & el) { + /* int maxn = el[0]; for (int i = 1; i < el.GetNP(); i++) if (el[i] > maxn) maxn = el[i]; maxn += 1-PointIndex::BASE; + */ + PointIndex maxpi = el[0]; + for (int i = 1; i < el.GetNP(); i++) + if (el[i] > maxpi) maxpi = el[i]; + int maxn = maxpi-IndexBASE()+1; + if (maxn <= points.Size()) { for (int i = 0; i < el.GetNP(); i++) @@ -599,7 +608,7 @@ namespace netgen { volelements.Append (el); } - volelements.Last().Flags().illegal_valid = 0; + volelements.Last().Touch(); volelements.Last().Flags().fixed = 0; volelements.Last().Flags().deleted = 0; @@ -622,7 +631,7 @@ namespace netgen */ volelements[ei] = el; - volelements[ei].Flags().illegal_valid = 0; + volelements[ei].Touch(); volelements[ei].Flags().fixed = 0; volelements[ei].Flags().deleted = 0; } @@ -830,9 +839,12 @@ namespace netgen outfile.setf (ios::fixed, ios::floatfield); outfile.setf (ios::showpoint); + /* PointIndex pi; for (pi = PointIndex::BASE; pi < GetNP()+PointIndex::BASE; pi++) + */ + for (PointIndex pi : (*this).Points().Range()) { outfile.width(22); outfile << (*this)[pi](0)/scale << " "; @@ -888,20 +900,29 @@ namespace netgen outfile << " " << type; } outfile << "\n"; + outfile << "identificationnames\n"; + outfile << ident -> GetMaxNr() << "\n"; + for (i = 1; i <= ident -> GetMaxNr(); i++) + { + string name = ident -> GetName(i); + if(name == "") + name = "default"; + outfile << name << "\n"; + } } int cntmat = 0; - for (i = 1; i <= materials.Size(); i++) - if (materials.Get(i) && materials.Get(i)->length()) + for (int i = 0; i < materials.Size(); i++) + if (materials[i] && materials[i]->length()) cntmat++; if (cntmat) { outfile << "materials" << endl; outfile << cntmat << endl; - for (i = 1; i <= materials.Size(); i++) - if (materials.Get(i) && materials.Get(i)->length()) - outfile << i << " " << *materials.Get(i) << endl; + for (int i = 0; i < materials.Size(); i++) + if (materials[i] && materials[i]->length()) + outfile << i+1 << " " << *materials[i] << endl; } @@ -1020,7 +1041,7 @@ namespace netgen // for (PointIndex pi = points.Begin(); pi < points.End(); pi++) for (PointIndex pi : points.Range()) if ((*this)[pi].Singularity()>=1.) - outfile << int(pi) << "\t" << (*this)[pi].Singularity() << endl; + outfile << pi << "\t" << (*this)[pi].Singularity() << endl; } cnt_sing = 0; @@ -1180,7 +1201,7 @@ namespace netgen throw NgException ("mesh file not found"); } - int rank = GetCommunicator().Rank(); + // int rank = GetCommunicator().Rank(); int ntasks = GetCommunicator().Size(); char str[100]; @@ -1194,6 +1215,8 @@ namespace netgen facedecoding.SetSize(0); bool endmesh = false; + + bool has_facedescriptors = false; while (infile.good() && !endmesh) @@ -1213,9 +1236,10 @@ namespace netgen if (strcmp (str, "facedescriptors") == 0) { + has_facedescriptors = true; int nfd; infile >> nfd; - for(auto i : Range(nfd)) + for([[maybe_unused]] auto i : Range(nfd)) { int surfnr, domin, domout, tlosurf, bcprop; infile >> surfnr >> domin >> domout >> tlosurf >> bcprop; @@ -1306,7 +1330,7 @@ namespace netgen el.SetNP(nep); el.SetCurved (nep != 4); for (int j = 0; j < nep; j++) - infile >> (int&)(el[j]); + infile >> el[j]; if (inverttets) el.Invert(); @@ -1435,11 +1459,22 @@ namespace netgen ident -> SetType(i,Identifications::ID_TYPE(type)); } } + if (strcmp (str, "identificationnames") == 0) + { + infile >> n; + PrintMessage (3, n, " identificationnames"); + for (i = 1; i <= n; i++) + { + string name; + infile >> name; + ident -> SetName(i,name); + } + } if (strcmp (str, "materials") == 0) { infile >> n; - for ( auto i : Range(n) ) + for ([[maybe_unused]] auto i : Range(n) ) { int nr; string mat; @@ -1597,7 +1632,11 @@ namespace netgen surfnr--; - if(surfnr > 0) + if(has_facedescriptors) + { + GetFaceDescriptor(i).SetSurfColour(surfcolour); + } + else if(surfnr > 0) { for(int facedesc = 1; facedesc <= cnt_facedesc; facedesc++) { @@ -1615,7 +1654,7 @@ namespace netgen { int cnt_facedesc = GetNFD(); infile >> n; - int index = 1; + // int index = 1; if(n == cnt_facedesc) { for(int index = 1; index <= n; index++) @@ -1624,7 +1663,14 @@ namespace netgen double transp; infile >> surfnr >> transp; surfnr--; - if(surfnr > 0) + if(has_facedescriptors) + { + auto& fd = GetFaceDescriptor(index); + auto scol = fd.SurfColour(); + scol[3] = transp; + fd.SetSurfColour(scol); + } + else if(surfnr > 0) { for(int facedesc = 1; facedesc <= cnt_facedesc; facedesc++) { @@ -1676,7 +1722,7 @@ namespace netgen if (comm.Rank() == 0) archive & dimension; - auto rank = comm.Rank(); + // auto rank = comm.Rank(); auto & partop = GetParallelTopology(); @@ -1697,8 +1743,8 @@ namespace netgen maxglob = max(globnum[pi], maxglob); } - maxglob = comm.AllReduce (maxglob, MPI_MAX); - int numglob = maxglob+1-PointIndex::BASE; + maxglob = comm.AllReduce (maxglob, NG_MPI_MAX); + int numglob = maxglob+1-IndexBASE(); if (comm.Rank() > 0) { comm.Send (globnum, 0, 200); @@ -1783,6 +1829,33 @@ namespace netgen archive & copy_el1d; } + + // sending 0D elements + auto copy_el0d (pointelements); + for (auto & el : copy_el0d) + { + auto & pi = el.pnum; + if (pi != PointIndex(PointIndex::INVALID)) + pi = globnum[pi]; + } + + if (comm.Rank() > 0) + comm.Send(copy_el0d, 0, 200); + else + { + Array el0di; + for (int j = 1; j < comm.Size(); j++) + { + comm.Recv(el0di, j, 200); + for (auto & el : el0di) + copy_el0d += el; + } + archive & copy_el0d; + } + + + + if (comm.Rank() == 0) { archive & facedecoding; @@ -1812,6 +1885,7 @@ namespace netgen archive & surfelements; archive & volelements; archive & segments; + archive & pointelements; archive & facedecoding; archive & materials & bcnames & cd2names & cd3names; archive & numvertices; @@ -1833,7 +1907,7 @@ namespace netgen if (archive.Input()) { - int rank = GetCommunicator().Rank(); + // int rank = GetCommunicator().Rank(); int ntasks = GetCommunicator().Size(); RebuildSurfaceElementLists(); @@ -2028,7 +2102,7 @@ namespace netgen for (int j = 0; j < nep; j++) { - infile >> (int&)(el[j]); + infile >> el[j]; el[j] = el[j]+oldnp; } @@ -2097,7 +2171,7 @@ namespace netgen for (ElementIndex ei = 0; ei < volelements.Size(); ei++) { for (int j = 0; j < 4; j++) - if ( (*this)[ei][j] <= PointIndex::BASE-1) + if ( !(*this)[ei][j].IsValid()) { (*testout) << "El " << ei << " has 0 nodes: "; for (int k = 0; k < 4; k++) @@ -2138,9 +2212,9 @@ namespace netgen if (sel.GetNP() <= 4) for (int j = 0; j < sel.GetNP(); j++) { - INDEX_2 i2; - i2.I1() = sel.PNumMod(j+1); - i2.I2() = sel.PNumMod(j+2); + PointIndices<2> i2; + i2[0] = sel.PNumMod(j+1); + i2[1] = sel.PNumMod(j+2); i2.Sort(); boundaryedges->Set (i2, 1); } @@ -2148,9 +2222,9 @@ namespace netgen { for (int j = 0; j < 3; j++) { - INDEX_2 i2; - i2.I1() = sel[j]; - i2.I2() = sel[(j+1)%3]; + PointIndices<2> i2; + i2[0] = sel[j]; + i2[1] = sel[(j+1)%3]; i2.Sort(); boundaryedges->Set (i2, 1); } @@ -2159,7 +2233,7 @@ namespace netgen cerr << "illegal element for buildboundaryedges" << endl; } - + /* for (int i = 0; i < openelements.Size(); i++) { const Element2d & sel = openelements[i]; @@ -2174,7 +2248,18 @@ namespace netgen points[sel[j]].SetType(FIXEDPOINT); } } + */ + for (const Element2d & sel : openelements) + for (int j = 0; j < sel.GetNP(); j++) + { + PointIndices<2> i2 { sel.PNumMod(j+1), sel.PNumMod(j+2) }; + i2.Sort(); + boundaryedges->Set (i2, 1); + points[sel[j]].SetType(FIXEDPOINT); + } + + /* for (int i = 0; i < GetNSeg(); i++) { const Segment & seg = segments[i]; @@ -2184,7 +2269,15 @@ namespace netgen boundaryedges -> Set (i2, 2); //segmentht -> Set (i2, i); } + */ + for (const Segment & seg : segments) + { + PointIndices<2> i2 { seg[0], seg[1] }; + i2.Sort(); + boundaryedges -> Set (i2, 2); + //segmentht -> Set (i2, i); + } } @@ -2194,7 +2287,7 @@ namespace netgen static Timer tn2se("Mesh::CalcSurfacesOfNode - surf on node"); static Timer tht("Mesh::CalcSurfacesOfNode - surfelementht"); // surfacesonnode.SetSize (GetNP()); - TABLE surfacesonnode(GetNP()); + DynamicTable surfacesonnode(GetNP()); // delete boundaryedges; // boundaryedges = NULL; @@ -2275,10 +2368,10 @@ namespace netgen const Element2d & sel = surfelements[sei]; if (sel.IsDeleted()) continue; - INDEX_3 i3; - i3.I1() = sel.PNum(1); - i3.I2() = sel.PNum(2); - i3.I3() = sel.PNum(3); + PointIndices<3> i3; + i3[0] = sel.PNum(1); + i3[1] = sel.PNum(2); + i3[2] = sel.PNum(3); i3.Sort(); surfelementht -> Set (i3, sei); // war das wichtig ??? sel.GetIndex()); } @@ -2375,7 +2468,7 @@ namespace netgen for (int i = 0; i < GetNSeg(); i++) { const Segment & seg = segments[i]; - INDEX_2 i2(seg[0], seg[1]); + PointIndices<2> i2(seg[0], seg[1]); i2.Sort(); //boundaryedges -> Set (i2, 2); @@ -2384,15 +2477,15 @@ namespace netgen } // NgBitArray base is PointIndex::BASE ... - void Mesh :: FixPoints (const NgBitArray & fixpoints) + void Mesh :: FixPoints (const TBitArray & fixpoints) { if (fixpoints.Size() != GetNP()) { cerr << "Mesh::FixPoints: sizes don't fit" << endl; return; } - int np = GetNP(); /* + int np = GetNP(); for (int i = 1; i <= np; i++) if (fixpoints.Test(i)) { @@ -2412,7 +2505,7 @@ namespace netgen static Timer t_pointloop("Mesh::FindOpenElements - pointloop"); int np = GetNP(); - int ne = GetNE(); + // int ne = GetNE(); int nse = GetNSE(); t_table.Start(); @@ -2426,10 +2519,10 @@ namespace netgen { if (el.GetNP() == 4) { - INDEX_4 i4(el[0], el[1], el[2], el[3]); + PointIndices<4> i4(el[0], el[1], el[2], el[3]); i4.Sort(); - table.Add (PointIndex(i4.I1()), ei); - table.Add (PointIndex(i4.I2()), ei); + table.Add (i4.I1(), ei); + table.Add (i4.I2(), ei); } else { @@ -2713,7 +2806,7 @@ namespace netgen hel.NormalizeNumbering(); if (hel.PNum(1) == pi) { - INDEX_3 i3(hel[0], hel[1], hel[2]); + PointIndices<3> i3(hel[0], hel[1], hel[2]); tval i2; i2.index = GetFaceDescriptor(ind).DomainIn(); i2.p4 = (hel.GetNP() == 3) @@ -2729,7 +2822,7 @@ namespace netgen hel.NormalizeNumbering(); if (hel.PNum(1) == pi) { - INDEX_3 i3(hel[0], hel[1], hel[2]); + PointIndices<3> i3(hel[0], hel[1], hel[2]); tval i2; i2.index = GetFaceDescriptor(ind).DomainOut(); i2.p4 = (hel.GetNP() == 3) @@ -2756,14 +2849,14 @@ namespace netgen if (hel[0] == pi) { - INDEX_3 i3(hel[0], hel[1], hel[2]); + PointIndices<3> i3(hel[0], hel[1], hel[2]); if (faceht.Used (i3)) { tval i2 = faceht.Get(i3); if (i2.index == el.GetIndex()) { - i2.index = PointIndex::BASE-1; + i2.index = long(PointIndex::BASE)-1; faceht.Set (i3, i2); } else @@ -2785,7 +2878,7 @@ namespace netgen { hel.Invert(); hel.NormalizeNumbering(); - INDEX_3 i3(hel[0], hel[1], hel[2]); + PointIndices<3> i3(hel[0], hel[1], hel[2]); tval i2; i2.index = el.GetIndex(); @@ -2807,7 +2900,7 @@ namespace netgen faceht.GetData (i, i3, i2); if (i2.index != PointIndex::BASE-1) { - Element2d tri ( (i2.p4 == PointIndex::BASE-1) ? TRIG : QUAD); + Element2d tri ( (!i2.p4.IsValid()) ? TRIG : QUAD); for (int l = 0; l < 3; l++) tri[l] = i3.I(l+1); tri.PNum(4) = i2.p4; @@ -2947,6 +3040,7 @@ namespace netgen // bool buggy = false; // ofstream bout("buggy.out"); + for (int i = 1; i <= GetNSE(); i++) { const Element2d & el = SurfaceElement(i); @@ -2956,10 +3050,10 @@ namespace netgen { for (int j = 1; j <= el.GetNP(); j++) { - INDEX_3 seg (el.PNumMod(j), el.PNumMod(j+1), el.GetIndex()); - int data; + PointIndices<3> seg (el.PNumMod(j), el.PNumMod(j+1), el.GetIndex()); + // int data; - if (seg.I1() < PointIndex::BASE || seg.I2() < PointIndex::BASE) + if (!seg.I1().IsValid() || !seg.I2().IsValid()) cerr << "seg = " << seg << endl; if (faceht.Used(seg)) @@ -3023,7 +3117,7 @@ namespace netgen for (int i = 1; i <= faceht.GetNBags(); i++) for (int j = 1; j <= faceht.GetBagSize(i); j++) { - INDEX_3 i2; + PointIndices<3> i2; int data; faceht.GetData (i, j, i2, data); if (data) // surfnr @@ -3146,14 +3240,14 @@ namespace netgen int np = GetNP(); FindOpenSegments(); - NgBitArray frontpoints(np+1); // for 0- and 1-based + TBitArray frontpoints(np); // for 0- and 1-based frontpoints.Clear(); for (int i = 1; i <= GetNOpenSegments(); i++) { const Segment & seg = GetOpenSegment(i); - frontpoints.Set (seg[0]); - frontpoints.Set (seg[1]); + frontpoints.SetBit (seg[0]); + frontpoints.SetBit (seg[1]); } for (int i = 1; i <= GetNSE(); i++) @@ -3199,47 +3293,53 @@ namespace netgen void Mesh :: FreeOpenElementsEnvironment (int layers) { static Timer timer("FreeOpenElementsEnvironment"); RegionTimer rt(timer); - int i, j, k; - PointIndex pi; const int large = 9999; - NgArray dist(GetNP()); + Array dist(GetNP()); dist = large; for (int i = 1; i <= GetNOpenElements(); i++) { const Element2d & face = OpenElement(i); - for (j = 0; j < face.GetNP(); j++) + for (int j = 0; j < face.GetNP(); j++) dist[face[j]] = 1; } - for (k = 1; k <= layers; k++) + for (int k = 1; k <= layers; k++) + /* for (i = 1; i <= GetNE(); i++) { const Element & el = VolumeElement(i); - if (el[0] == -1 || el.IsDeleted()) continue; + */ + for (auto & el : VolumeElements()) + { + if (!el[0].IsValid() || el.IsDeleted()) continue; int elmin = large; - for (j = 0; j < el.GetNP(); j++) + for (int j = 0; j < el.GetNP(); j++) if (dist[el[j]] < elmin) elmin = dist[el[j]]; - + if (elmin < large) { - for (j = 0; j < el.GetNP(); j++) + for (int j = 0; j < el.GetNP(); j++) if (dist[el[j]] > elmin+1) dist[el[j]] = elmin+1; } } int cntfree = 0; - for (i = 1; i <= GetNE(); i++) + /* + for (int i = 1; i <= GetNE(); i++) { Element & el = VolumeElement(i); - if (el[0] == -1 || el.IsDeleted()) continue; + */ + for (auto & el : VolumeElements()) + { + if (!el[0].IsValid() || el.IsDeleted()) continue; int elmin = large; - for (j = 0; j < el.GetNP(); j++) + for (int j = 0; j < el.GetNP(); j++) if (dist[el[j]] < elmin) elmin = dist[el[j]]; @@ -3253,8 +3353,8 @@ namespace netgen PrintMessage (5, "free: ", cntfree, ", fixed: ", GetNE()-cntfree); (*testout) << "free: " << cntfree << ", fixed: " << GetNE()-cntfree << endl; - for (pi = PointIndex::BASE; - pi < GetNP()+PointIndex::BASE; pi++) + for (PointIndex pi = IndexBASE(); + pi < GetNP()+IndexBASE(); pi++) { if (dist[pi] > layers+1) points[pi].SetType(FIXEDPOINT); @@ -3328,7 +3428,7 @@ namespace netgen double Mesh :: MaxHDomain (int dom) const { - if (maxhdomain.Size()) + if (dom >= 0 && dom < maxhdomain.Size()) return maxhdomain.Get(dom); else return 1e10; @@ -3554,18 +3654,16 @@ namespace netgen SetLocalH (pmin, pmax, grading, layer); } - PointIndex i,j; - double hl; + // double hl; - - for (i = PointIndex::BASE; - i < GetNP()+PointIndex::BASE; i++) + for (PointIndex i = IndexBASE(); + i < GetNP()+IndexBASE(); i++) { - for(j=i+1; j(); j++) { const Point3d & p1 = points[i]; const Point3d & p2 = points[j]; - hl = Dist(p1,p2); + double hl = Dist(p1,p2); RestrictLocalH(p1,hl); RestrictLocalH(p2,hl); //cout << "restricted h at " << p1 << " and " << p2 << " to " << hl << endl; @@ -3597,18 +3695,18 @@ namespace netgen for (i = 1; i <= GetNSeg(); i++) { const Segment & seg = LineSegment(i); - INDEX_2 i2(seg[0], seg[1]); + PointIndices<2> i2(seg[0], seg[1]); i2.Sort(); bedges.Set (i2, 1); } for (i = 1; i <= GetNSE(); i++) { const Element2d & sel = SurfaceElement(i); - if (!sel.PNum(1)) + if (!sel.PNum(1).IsValid()) continue; for (j = 1; j <= 3; j++) { - INDEX_2 i2(sel.PNumMod(j), sel.PNumMod(j+1)); + PointIndices<2> i2(sel.PNumMod(j), sel.PNumMod(j+1)); i2.Sort(); if (bedges.Used(i2)) continue; @@ -3618,22 +3716,22 @@ namespace netgen const Element2d & elother = SurfaceElement(other); - int pi3 = 1; - while ( (sel.PNum(pi3) == i2.I1()) || - (sel.PNum(pi3) == i2.I2())) - pi3++; - pi3 = sel.PNum(pi3); + int pi3_ = 1; + while ( (sel.PNum(pi3_) == i2[0]) || + (sel.PNum(pi3_) == i2[1])) + pi3_++; + PointIndex pi3 = sel.PNum(pi3_); - int pi4 = 1; - while ( (elother.PNum(pi4) == i2.I1()) || - (elother.PNum(pi4) == i2.I2())) - pi4++; - pi4 = elother.PNum(pi4); + int pi4_ = 1; + while ( (elother.PNum(pi4_) == i2[0]) || + (elother.PNum(pi4_) == i2[1])) + pi4_++; + PointIndex pi4 = elother.PNum(pi4_); - double rad = ComputeCylinderRadius (Point (PointIndex(i2.I1())), - Point (PointIndex(i2.I2())), - Point (PointIndex(pi3)), - Point (PointIndex(pi4))); + double rad = ComputeCylinderRadius (Point (i2[0]), + Point (i2[1]), + Point (pi3), + Point (pi4)); RestrictLocalHLine (Point(PointIndex(i2.I1())), Point(PointIndex(i2.I2())), rad/elperr); @@ -3967,7 +4065,7 @@ namespace netgen */ for (int i = 0; i < volelements.Size(); i++) - if (volelements[i][0] <= PointIndex::BASE-1 || + if (!volelements[i][0].IsValid() || volelements[i].IsDeleted()) { volelements.DeleteElement(i); @@ -3983,7 +4081,7 @@ namespace netgen } for (int i = 0; i < segments.Size(); i++) - if (segments[i][0] <= PointIndex::BASE-1) + if (!segments[i][0].IsValid()) { segments.DeleteElement(i); i--; @@ -4039,6 +4137,9 @@ namespace netgen pused[seg[j]] = true; } + for(auto& pe : pointelements) + pused[pe.pnum] = true; + for (int i = 0; i < openelements.Size(); i++) { const Element2d & el = openelements[i]; @@ -4067,7 +4168,7 @@ namespace netgen { Array hpoints; - int npi = PointIndex::BASE; + PointIndex npi = IndexBASE(); for (PointIndex pi : points.Range()) if (pused[pi]) { @@ -4125,6 +4226,9 @@ namespace netgen seg[j] = op2np[seg[j]]; } + for(auto& pe : pointelements) + pe.pnum = op2np[pe.pnum]; + for (int i = 1; i <= openelements.Size(); i++) { Element2d & el = openelements.Elem(i); @@ -4135,6 +4239,8 @@ namespace netgen for (int i = 0; i < lockedpoints.Size(); i++) lockedpoints[i] = op2np[lockedpoints[i]]; + + GetIdentifications().MapPoints(op2np); /* for (int i = 0; i < facedecoding.Size(); i++) facedecoding[i].firstelement = -1; @@ -4452,30 +4558,30 @@ namespace netgen } return 1; - if ( /* hp */ 1) // needed for old, simple hp-refinement - { - // trigs with 2 or more segments are illegal - int i; - int nseg = 0; + // if ( /* hp */ 1) // needed for old, simple hp-refinement + // { + // // trigs with 2 or more segments are illegal + // int i; + // int nseg = 0; - if (!segmentht) - { - cerr << "no segmentht allocated" << endl; - return 0; - } + // if (!segmentht) + // { + // cerr << "no segmentht allocated" << endl; + // return 0; + // } - // Point3d cp(0.5, 0.5, 0.5); - for (i = 1; i <= 3; i++) - { - INDEX_2 i2(el.PNumMod (i), el.PNumMod (i+1)); - i2.Sort(); - if (segmentht -> Used (i2)) - nseg++; - } - if (nseg >= 2) - return 0; - } - return 1; + // // Point3d cp(0.5, 0.5, 0.5); + // for (i = 1; i <= 3; i++) + // { + // INDEX_2 i2(el.PNumMod (i), el.PNumMod (i+1)); + // i2.Sort(); + // if (segmentht -> Used (i2)) + // nseg++; + // } + // if (nseg >= 2) + // return 0; + // } + // return 1; } double Mesh :: CalcTotalBad (const MeshingParameters & mp ) @@ -4493,7 +4599,11 @@ namespace netgen double local_sum = 0.0; double teterrpow = mp.opterrpow; - std::array classes_local{}; + // std::array classes_local{}; + size_t n_classes = tets_in_qualclass.Size(); + Array classes_local(n_classes); + for (int i = 0; i < n_classes; i++) + classes_local[i] = 0; for (auto i : myrange) { @@ -4709,15 +4819,30 @@ namespace netgen for (auto & seg : LineSegments()) seg.si = seg.edgenr; } + if (dimension == 3 && dim == 1) + { + for(auto str : materials) + delete str; + materials.SetSize(0); + for(auto str : bcnames) + delete str; + bcnames.SetSize(0); + for(auto str: cd2names) + materials.Append(str); + cd2names.SetSize(0); + for(auto str : cd3names) + bcnames.Append(str); + cd3names.SetSize(0); + } dimension = dim; } void Mesh :: SurfaceMeshOrientation () { - int i, j; + // int i, j; int nse = GetNSE(); - NgBitArray used(nse); + BitArray used(nse+1); used.Clear(); INDEX_2_HASHTABLE edges(nse+1); @@ -4725,12 +4850,12 @@ namespace netgen const Element2d & tri = SurfaceElement(1); - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) { INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1)); edges.Set (i2, 1); } - used.Set(1); + used.SetBit(1); bool unused; do @@ -4739,12 +4864,12 @@ namespace netgen do { changed = 0; - for (i = 1; i <= nse; i++) + for (int i = 1; i <= nse; i++) if (!used.Test(i)) { Element2d & el = surfelements[i-1]; int found = 0, foundrev = 0; - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) { INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1)); if (edges.Used(i2)) @@ -4760,12 +4885,12 @@ namespace netgen swap (el.PNum(2), el.PNum(3)); changed = 1; - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) { INDEX_2 i2(el.PNumMod(j), el.PNumMod(j+1)); edges.Set (i2, 1); } - used.Set (i); + used.SetBit (i); } } if (changed) @@ -4775,17 +4900,17 @@ namespace netgen unused = 0; - for (i = 1; i <= nse; i++) + for (int i = 1; i <= nse; i++) if (!used.Test(i)) { unused = 1; const Element2d & tri = SurfaceElement(i); - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) { INDEX_2 i2(tri.PNumMod(j), tri.PNumMod(j+1)); edges.Set (i2, 1); } - used.Set(i); + used.SetBit(i); break; } } @@ -4812,8 +4937,7 @@ namespace netgen // make minimal node to node 1 int minpi=0; - PointIndex minpnum; - minpnum = GetNP() + 1; + PointIndex minpnum = IndexBASE()+GetNP(); for (int j = 1; j <= 6; j++) { @@ -4833,10 +4957,9 @@ namespace netgen while (minpi > 1) { - int hi = 0; for (int j = 0; j <= 3; j+= 3) { - hi = el.PNum(1+j); + PointIndex hi = el.PNum(1+j); el.PNum(1+j) = el.PNum(2+j); el.PNum(2+j) = el.PNum(3+j); el.PNum(3+j) = hi; @@ -4908,8 +5031,7 @@ namespace netgen // make minimal node to node 1 int minpi=0; - PointIndex minpnum; - minpnum = GetNP() + 1; + PointIndex minpnum = GetNP() + IndexBASE(); for (int j = 1; j <= 8; j++) { @@ -4929,10 +5051,9 @@ namespace netgen while (minpi > 1) { - int hi = 0; for (int j = 0; j <= 4; j+= 4) { - hi = el.PNum(1+j); + PointIndex hi = el.PNum(1+j); el.PNum(1+j) = el.PNum(2+j); el.PNum(2+j) = el.PNum(3+j); el.PNum(3+j) = el.PNum(4+j); @@ -5143,92 +5264,95 @@ namespace netgen RebuildSurfaceElementLists(); } - void Mesh :: BuildElementSearchTree () + void Mesh :: BuildElementSearchTree (int dim) { - if (elementsearchtreets == GetTimeStamp()) return; + if(dim < 2) + return; + if (elementsearchtreets[dim] == GetTimeStamp()) + return; { std::lock_guard guard(buildsearchtree_mutex); - if (elementsearchtreets != GetTimeStamp()) + // check again to see if some other thread built while waiting for lock + if (elementsearchtreets[dim] == GetTimeStamp()) return; + + elementsearchtreets[dim] = GetTimeStamp(); + + PrintMessage (4, "Rebuild element searchtree dim " + ToString(dim)); + + + Point3d pmin, pmax; + GetBox(pmin, pmax); + Box<3> box(pmin, pmax); + if (dim == 3) + elementsearchtree_vol = make_unique>(box); + else + elementsearchtree_surf = make_unique>(box); + + if (dim == 3) { - NgLock lock(mutex); - lock.Lock(); - - PrintMessage (4, "Rebuild element searchtree"); - - elementsearchtree = nullptr; - - int ne = (dimension == 2) ? GetNSE() : GetNE(); - if (dimension == 3 && !GetNE() && GetNSE()) - ne = GetNSE(); - - if (ne) + for(auto ei : volelements.Range()) { - if (dimension == 2 || (dimension == 3 && !GetNE()) ) + const auto& el = volelements[ei]; + Box<3> box (Box<3>::EMPTY_BOX); + for (auto pi : el.PNums()) + box.Add (points[pi]); + + if(el.IsCurved() && curvedelems->IsElementCurved(ei)) { - Box<3> box (Box<3>::EMPTY_BOX); - for (SurfaceElementIndex sei = 0; sei < ne; sei++) - // box.Add (points[surfelements[sei].PNums()]); - for (auto pi : surfelements[sei].PNums()) - box.Add (points[pi]); - - box.Increase (1.01 * box.Diam()); - elementsearchtree = make_unique> (box); - - for (SurfaceElementIndex sei = 0; sei < ne; sei++) - { - // box.Set (points[surfelements[sei].PNums()]); + // add edge/face midpoints to box + auto eltype = el.GetType(); + const auto verts = topology.GetVertices(eltype); - Box<3> box (Box<3>::EMPTY_BOX); - for (auto pi : surfelements[sei].PNums()) - box.Add (points[pi]); + const auto edges = FlatArray(topology.GetNEdges(eltype), topology.GetEdges0(eltype)); + for (const auto & edge: edges) { + netgen::Point<3> lam = netgen::Point<3>(0.5* (verts[edge[0]] + verts[edge[1]])); + auto p = netgen::Point<3>(0.0); + curvedelems->CalcElementTransformation(lam,ei,p); + box.Add(p); + } - auto & el = surfelements[sei]; - if(el.IsCurved() && curvedelems->IsSurfaceElementCurved(sei)) - { - netgen::Point<2> lami [4] = {netgen::Point<2>(0.5,0), netgen::Point<2>(0,0.5), netgen::Point<2>(0.5,0.5), netgen::Point<2>(1./3,1./3)}; - for (auto lam : lami) - { - netgen::Point<3> x; - Mat<3,2> Jac; - - curvedelems->CalcSurfaceTransformation(lam,sei,x,Jac); - box.Add (x); - } - box.Scale(1.2); - } - elementsearchtree -> Insert (box, sei+1); + const auto faces = FlatArray(topology.GetNFaces(eltype), topology.GetFaces0(eltype)); + for (const auto & face: faces) { + netgen::Vec<3> lam = netgen::Vec<3>(verts[face[0]] + verts[face[1]] + verts[face[2]]); + if(face[3] != -1) { + lam += netgen::Vec<3>(verts[face[3]]); + lam *= 0.25; } + else + lam *= 1.0/3; + auto p = netgen::Point<3>(0.0); + curvedelems->CalcElementTransformation(netgen::Point<3>(lam),ei,p); + box.Add(p); + } } - else + box.Scale(1.2); + elementsearchtree_vol -> Insert (box, ei); + } + } + else if (dim == 2) + { + for (auto ei : Range(surfelements)) + { + const auto& el = surfelements[ei]; + Box<3> box (Box<3>::EMPTY_BOX); + for (auto pi : el.PNums()) + box.Add (points[pi]); + + if(el.IsCurved() && curvedelems->IsSurfaceElementCurved(ei)) { - Box<3> box (Box<3>::EMPTY_BOX); - for (ElementIndex ei = 0; ei < ne; ei++) - // box.Add (points[volelements[ei].PNums()]); - for (auto pi : volelements[ei].PNums()) - box.Add (points[pi]); - - box.Increase (1.01 * box.Diam()); - elementsearchtree = make_unique> (box); - - for (ElementIndex ei = 0; ei < ne; ei++) + netgen::Point<2> lami [4] = {netgen::Point<2>(0.5,0), netgen::Point<2>(0,0.5), netgen::Point<2>(0.5,0.5), netgen::Point<2>(1./3,1./3)}; + for (auto lam : lami) { - // box.Set (points[volelements[ei].PNums()]); + netgen::Point<3> x; + Mat<3,2> Jac; - Box<3> box (Box<3>::EMPTY_BOX); - for (auto pi : volelements[ei].PNums()) - box.Add (points[pi]); - - auto & el = volelements[ei]; - if(el.IsCurved() && curvedelems->IsElementCurved(ei)) - box.Scale(1.2); - - - elementsearchtree -> Insert (box, ei+1); + curvedelems->CalcSurfaceTransformation(lam,ei,x,Jac); + box.Add (x); } + box.Scale(1.2); } - - elementsearchtreets = GetTimeStamp(); + elementsearchtree_surf -> Insert (box, ei); } } } @@ -5268,7 +5392,7 @@ namespace netgen bool Mesh :: PointContainedIn2DElement(const Point3d & p, double lami[3], - const int element, + SurfaceElementIndex ei, bool consider3D) const { Vec3d col1, col2, col3; @@ -5279,9 +5403,9 @@ namespace netgen //SZ - if(SurfaceElement(element).GetType()==QUAD) + if(surfelements[ei].GetType()==QUAD) { - const Element2d & el = SurfaceElement(element); + const Element2d & el = surfelements[ei]; const Point3d & p1 = Point(el.PNum(1)); const Point3d & p2 = Point(el.PNum(2)); @@ -5300,7 +5424,7 @@ namespace netgen int i = 0; while(delta > 1e-16 && i < maxits) { - curvedelems->CalcSurfaceTransformation(lam,element-1,x,Jac); + curvedelems->CalcSurfaceTransformation(lam,ei,x,Jac); rhs = p - x; Jac.Solve(rhs,deltalam); lam += deltalam; @@ -5629,7 +5753,7 @@ namespace netgen { // SurfaceElement(element).GetTets (loctets); loctrigs.SetSize(1); - loctrigs.Elem(1) = SurfaceElement(element); + loctrigs.Elem(1) = surfelements[ei]; @@ -5664,11 +5788,11 @@ namespace netgen //(*testout) << "col1 " << col1 << " col2 " << col2 << " col3 " << col3 << " rhs " << rhs << endl; //(*testout) << "sol " << sol << endl; - if (SurfaceElement(element).GetType() ==TRIG6 || curvedelems->IsSurfaceElementCurved(element-1)) + if (surfelements[ei].GetType() ==TRIG6 || curvedelems->IsSurfaceElementCurved(ei)) { // netgen::Point<2> lam(1./3,1./3); netgen::Point<2> lam(sol.X(), sol.Y()); - if(SurfaceElement(element).GetType() != TRIG6) + if(surfelements[ei].GetType() != TRIG6) { lam[0] = 1-sol.X()-sol.Y(); lam[1] = sol.X(); @@ -5680,14 +5804,14 @@ namespace netgen double delta=1; - bool retval; + // bool retval; int i = 0; const int maxits = 30; while(delta > 1e-16 && iCalcSurfaceTransformation(lam,element-1,x,Jac); + curvedelems->CalcSurfaceTransformation(lam,ei,x,Jac); rhs = p-x; Jac.Solve(rhs,deltalam); @@ -5706,7 +5830,7 @@ namespace netgen sol.X() = lam(0); sol.Y() = lam(1); - if (SurfaceElement(element).GetType() !=TRIG6 ) + if (surfelements[ei].GetType() !=TRIG6 ) { sol.Z() = sol.X(); sol.X() = sol.Y(); @@ -5738,7 +5862,7 @@ namespace netgen bool Mesh :: PointContainedIn3DElement(const Point3d & p, double lami[3], - const int element) const + ElementIndex ei) const { //bool oldresult = PointContainedIn3DElementOld(p,lami,element); //(*testout) << "old result: " << oldresult @@ -5749,7 +5873,7 @@ namespace netgen const double eps = 1.e-4; - const Element & el = VolumeElement(element); + const Element & el = volelements[ei]; netgen::Point<3> lam = 0.0; @@ -5784,7 +5908,7 @@ namespace netgen const int maxits = 30; while(delta > 1e-16 && iCalcElementTransformation(lam,element-1,x,Jac); + curvedelems->CalcElementTransformation(lam,ei,x,Jac); rhs = p-x; Jac.Solve(rhs,deltalam); @@ -5906,101 +6030,87 @@ namespace netgen } - int Mesh :: GetElementOfPoint (const netgen::Point<3> & p, - double lami[3], - bool build_searchtree, - const int index, - const bool allowindex) const + ElementIndex Mesh :: GetElementOfPoint (const netgen::Point<3> & p, + double* lami, + bool build_searchtree, + int index, + bool allowindex) const { if(index != -1) { - NgArray dummy(1); + Array dummy(1); dummy[0] = index; - return GetElementOfPoint(p,lami,&dummy,build_searchtree,allowindex); + return GetElementOfPoint(p,lami,dummy,build_searchtree,allowindex); } else - return GetElementOfPoint(p,lami,NULL,build_searchtree,allowindex); + return GetElementOfPoint(p,lami,nullopt,build_searchtree,allowindex); } - int Mesh :: GetElementOfPoint (const netgen::Point<3> & p, - double lami[3], - const NgArray * const indices, - bool build_searchtree, - const bool allowindex) const + ElementIndex Mesh :: GetElementOfPoint (const netgen::Point<3> & p, + double* lami, + std::optional> indices, + bool build_searchtree, + bool allowindex) const { - if ( (dimension == 2 && !GetNSE()) || - (dimension == 3 && !GetNE() && !GetNSE()) ) - return -1; - if (build_searchtree) - const_cast(*this).BuildElementSearchTree (); - - if (dimension == 2 || (dimension==3 && !GetNE() && GetNSE())) - return Find2dElement(*this, p, lami, indices, elementsearchtree.get(), allowindex); - - return Find3dElement(*this, p, lami, indices, elementsearchtree.get(), allowindex); + const_cast(*this).BuildElementSearchTree (3); + return Find3dElement(*this, p, lami, indices, elementsearchtree_vol.get(), allowindex); } - int Mesh :: GetSurfaceElementOfPoint (const netgen::Point<3> & p, - double lami[3], - bool build_searchtree, - const int index, - const bool allowindex) const + SurfaceElementIndex Mesh :: + GetSurfaceElementOfPoint (const netgen::Point<3> & p, + double* lami, + bool build_searchtree, + int index, + bool allowindex) const { - if(index != -1) + if(index != -1) { - NgArray dummy(1); + Array dummy(1); dummy[0] = index; - return GetSurfaceElementOfPoint(p,lami,&dummy,build_searchtree,allowindex); + return GetSurfaceElementOfPoint(p,lami,dummy,build_searchtree,allowindex); } else - return GetSurfaceElementOfPoint(p,lami,NULL,build_searchtree,allowindex); + return GetSurfaceElementOfPoint(p,lami,nullopt,build_searchtree,allowindex); } - - - - int Mesh :: GetSurfaceElementOfPoint (const netgen::Point<3> & p, - double lami[3], - const NgArray * const indices, - bool build_searchtree, - const bool allowindex) const + SurfaceElementIndex Mesh :: + GetSurfaceElementOfPoint (const netgen::Point<3> & p, + double* lami, + std::optional> indices, + bool build_searchtree, + bool allowindex) const { - if (!GetNE() && build_searchtree) - const_cast(*this).BuildElementSearchTree (); - - if (dimension == 2) - return Find1dElement(*this, p, lami, indices, elementsearchtree.get(), allowindex); - else - return Find2dElement(*this, p, lami, indices, elementsearchtree.get(), allowindex); - return 0; + if (build_searchtree) + const_cast(*this).BuildElementSearchTree(2); + return Find2dElement(*this, p, lami, indices, elementsearchtree_surf.get(), allowindex); } void Mesh::GetIntersectingVolEls(const Point3d& p1, const Point3d& p2, - NgArray & locels) const + Array & locels) const { - elementsearchtree->GetIntersecting (p1, p2, locels); + elementsearchtree_vol->GetIntersecting (p1, p2, locels); } void Mesh :: SplitIntoParts() { - int i, j, dom; + // int i, j, dom; int ne = GetNE(); int np = GetNP(); int nse = GetNSE(); - NgBitArray surfused(nse); - NgBitArray pused (np); + BitArray surfused(nse+1); + TBitArray pused (np); surfused.Clear(); - dom = 0; + int dom = 0; while (1) { @@ -6011,15 +6121,15 @@ namespace netgen pused.Clear(); int found = 0; - for (i = 1; i <= nse; i++) + for (int i = 1; i <= nse; i++) if (!surfused.Test(i)) { SurfaceElement(i).SetIndex (dom); - for (j = 1; j <= 3; j++) - pused.Set (SurfaceElement(i).PNum(j)); + for (int j = 1; j <= 3; j++) + pused.SetBit (SurfaceElement(i).PNum(j)); found = 1; cntd = 1; - surfused.Set(i); + surfused.SetBit(i); break; } @@ -6030,10 +6140,10 @@ namespace netgen do { change = 0; - for (i = 1; i <= nse; i++) + for (int i = 1; i <= nse; i++) { int is = 0, isnot = 0; - for (j = 1; j <= 3; j++) + for (int j = 1; j <= 3; j++) if (pused.Test(SurfaceElement(i).PNum(j))) is = 1; else @@ -6042,15 +6152,15 @@ namespace netgen if (is && isnot) { change = 1; - for (j = 1; j <= 3; j++) - pused.Set (SurfaceElement(i).PNum(j)); + for (int j = 1; j <= 3; j++) + pused.SetBit (SurfaceElement(i).PNum(j)); } if (is) { if (!surfused.Test(i)) { - surfused.Set(i); + surfused.SetBit(i); SurfaceElement(i).SetIndex (dom); cntd++; } @@ -6058,10 +6168,10 @@ namespace netgen } - for (i = 1; i <= ne; i++) + for (int i = 1; i <= ne; i++) { int is = 0, isnot = 0; - for (j = 1; j <= 4; j++) + for (int j = 1; j <= 4; j++) if (pused.Test(VolumeElement(i).PNum(j))) is = 1; else @@ -6070,8 +6180,8 @@ namespace netgen if (is && isnot) { change = 1; - for (j = 1; j <= 4; j++) - pused.Set (VolumeElement(i).PNum(j)); + for (int j = 1; j <= 4; j++) + pused.SetBit (VolumeElement(i).PNum(j)); } if (is) @@ -6095,7 +6205,7 @@ namespace netgen } */ ClearFaceDescriptors(); - for (i = 1; i <= dom; i++) + for (int i = 1; i <= dom; i++) AddFaceDescriptor (FaceDescriptor (0, i, 0, 0)); CalcSurfacesOfNode(); timestamp = NextTimeStamp(); @@ -6107,7 +6217,7 @@ namespace netgen int fdi; int np = GetNP(); - NgBitArray usedp(np); + TBitArray usedp(np); Array els_of_face; fdi = 1; @@ -6125,7 +6235,7 @@ namespace netgen usedp.Clear(); for (int j = 1; j <= SurfaceElement(firstel).GetNP(); j++) - usedp.Set (SurfaceElement(firstel).PNum(j)); + usedp.SetBit (SurfaceElement(firstel).PNum(j)); bool changed; do @@ -6151,7 +6261,7 @@ namespace netgen if (has) for (int j = 0; j < el.GetNP(); j++) - usedp.Set (el[j]); + usedp.SetBit (el[j]); } } while (changed); @@ -6291,28 +6401,32 @@ namespace netgen mapped_points = false; // Add new points - for(auto [p1p2, idnr] : identpts) + for(auto [hash, dummy] : identpts) { - if(idnr != nr) + auto [hash_pts, hash_nr] = hash; + if(hash_nr != nr) continue; - auto& ipts = inserted_points[{p1p2.I1(), p1p2.I2()}]; - auto p1 = Point(p1p2.I1()); - auto p2 = Point(p1p2.I2()); - ipts.Append(p1p2.I1()); - mapped_points.SetBit(p1p2.I1()); + // auto& ipts = inserted_points[{p1p2.I1(), p1p2.I2()}]; + auto& ipts = inserted_points[ { hash_pts[0], hash_pts[1] }]; + auto p1 = Point(hash_pts.I1()); + auto p2 = Point(hash_pts.I2()); + ipts.Append(hash_pts.I1()); + mapped_points.SetBit(hash_pts.I1()); for(auto slice : slices) { auto np = p1 + slice * (p2-p1); auto npi = AddPoint(np); ipts.Append(npi); } - ipts.Append(p1p2.I2()); + ipts.Append(hash_pts.I2()); } // Split segments for(auto si : Range(segments)) { auto& seg = segments[si]; + // Copy segment, as reference above might get invalidated in AddSegment() + auto reference_seg = seg; auto p1 = seg[0]; auto p2 = seg[1]; @@ -6332,7 +6446,7 @@ namespace netgen seg[1] = ipts[1]; for(auto i : Range(size_t(1), ipts.Size()-1)) { - Segment snew = seg; + Segment snew = reference_seg; if(c2) { snew[0] = ipts[ipts.Size()-1-i]; @@ -6411,8 +6525,9 @@ namespace netgen // for(auto edgei : eledges) for(auto edgei : topology.GetEdges(ElementIndex(ei))) { - int p1, p2; - topology.GetEdgeVertices(edgei+1, p1, p2); + // int p1, p2; + // topology.GetEdgeVertices(edgei+1, p1, p2); + auto [p1, p2] = topology.GetEdgeVertices(edgei); auto c1 = inserted_points.count({p1, p2}); auto c2 = inserted_points.count({p2, p1}); if(c1 == 0 && c2 == 0) @@ -6479,8 +6594,8 @@ namespace netgen SurfaceElementIndex si = facedecoding[facenr-1].firstelement; while (si != -1) { - if ( (*this)[si].GetIndex () == facenr && (*this)[si][0] >= PointIndex::BASE && - !(*this)[si].IsDeleted() ) + if ( (*this)[si].GetIndex () == facenr && (*this)[si][0].IsValid() && + !(*this)[si].IsDeleted() ) { sei.Append (si); } @@ -6494,21 +6609,21 @@ namespace netgen void Mesh :: CalcMinMaxAngle (double badellimit, double * retvalues) { - int i, j; int lpi1, lpi2, lpi3, lpi4; double phimax = 0, phimin = 10; double facephimax = 0, facephimin = 10; int illegaltets = 0, negativetets = 0, badtets = 0; - for (i = 1; i <= GetNE(); i++) + // for (int i = 1; i <= GetNE(); i++) + for (ElementIndex ei : Range(VolumeElements())) { int badel = 0; - Element & el = VolumeElement(i); + Element & el = VolumeElement(ei); if (el.GetType() != TET) { - VolumeElement(i).Flags().badel = 0; + VolumeElement(ei).Flags().badel = 0; continue; } @@ -6523,8 +6638,8 @@ namespace netgen { badel = 1; illegaltets++; - (*testout) << "illegal tet: " << i << " "; - for (j = 1; j <= el.GetNP(); j++) + (*testout) << "illegal tet: " << ei << " "; + for (int j = 1; j <= el.GetNP(); j++) (*testout) << el.PNum(j) << " "; (*testout) << endl; } @@ -6563,7 +6678,7 @@ namespace netgen // angles in faces - for (j = 1; j <= 4; j++) + for (int j = 1; j <= 4; j++) { Element2d face(TRIG); el.GetFace (j, face); @@ -6590,7 +6705,7 @@ namespace netgen } - VolumeElement(i).Flags().badel = badel; + VolumeElement(ei).Flags().badel = badel; if (badel) badtets++; } @@ -6621,7 +6736,7 @@ namespace netgen } - int Mesh :: MarkIllegalElements () + int Mesh :: MarkIllegalElements (int domain) { if(!boundaryedges) BuildBoundaryEdges(); @@ -6631,7 +6746,7 @@ namespace netgen { int cnt_local = 0; for(auto & el : volelements.Range(myrange)) - if (!LegalTet (el)) + if ((domain==0 || el.GetIndex() == domain) && !LegalTet (el)) cnt_local++; cnt += cnt_local; }); @@ -6714,14 +6829,14 @@ namespace netgen // } // #endif - int Mesh::IdentifyPeriodicBoundaries(const string &s1, - const string &s2, + int Mesh::IdentifyPeriodicBoundaries(const string& id_name, + const string &s1, const Transformation<3> &mapping, double pointTolerance) { - auto nr = ident->GetMaxNr() + 1; + auto nr = ident->GetNr(id_name); ident->SetType(nr, Identifications::PERIODIC); - double lami[4]; + // double lami[4]; set identified_points; if(pointTolerance < 0.) { @@ -6729,43 +6844,38 @@ namespace netgen GetBox(pmin, pmax); pointTolerance = 1e-8 * (pmax-pmin).Length(); } - for(const auto& se : surfelements) + size_t nse = GetDimension() == 3 ? surfelements.Size() : segments.Size(); + for(auto sei : Range(nse)) { - if(GetBCName(se.index-1) != s1) + auto name = GetDimension() == 3 ? GetBCName(surfelements[sei].index-1) : + GetBCName(segments[sei].edgenr-1); + if(name != s1) continue; - for(const auto& pi : se.PNums()) + const auto& pnums = GetDimension() == 3 ? surfelements[sei].PNums() : + segments[sei].PNums(); + for(const auto& pi : pnums) { if(identified_points.find(pi) != identified_points.end()) continue; auto pt = (*this)[pi]; auto mapped_pt = mapping(pt); - auto other_nr = GetElementOfPoint(mapped_pt, lami, true); - int index = -1; - if(other_nr != 0) + bool found = false; + for(auto other_pi : Range(points)) { - auto other_el = VolumeElement(other_nr); - for(auto i : Range(other_el.PNums().Size())) - if((mapped_pt - (*this)[other_el.PNums()[i]]).Length() < pointTolerance) - { - index = i; - break; - } - if(index == -1) + if((mapped_pt - (*this)[other_pi]).Length() < pointTolerance) { - cout << "point coordinates = " << pt << endl; - cout << "mapped coordinates = " << mapped_pt << endl; - throw Exception("Did not find mapped point with nr " + ToString(pi) + ", are you sure your mesh is periodic?"); + identified_points.insert(pi); + ident->Add(pi, other_pi, nr); + found = true; + break; } - auto other_pi = other_el.PNums()[index]; - identified_points.insert(pi); - ident->Add(pi, other_pi, nr); } - else + if(!found) { cout << "point coordinates = " << pt << endl; cout << "mapped coordinates = " << mapped_pt << endl; - throw Exception("Mapped point with nr " + ToString(pi) + " is outside of mesh, are you sure your mesh is periodic?"); + throw Exception("Did not find mapped point with nr " + ToString(pi) + ", are you sure your mesh is periodic?"); } } } @@ -6859,19 +6969,21 @@ namespace netgen int mlold = mlbetweennodes.Size(); mlbetweennodes.SetSize(np); if (np > mlold) - for (int i = mlold+PointIndex::BASE; - i < np+PointIndex::BASE; i++) + for (PointIndex i = mlold+IndexBASE(); + i < np+IndexBASE(); i++) { - mlbetweennodes[i].I1() = PointIndex::BASE-1; - mlbetweennodes[i].I2() = PointIndex::BASE-1; + mlbetweennodes[i][0].Invalidate(); + mlbetweennodes[i][1].Invalidate(); } GetIdentifications().SetMaxPointNr (np + PointIndex::BASE-1); } - Table Mesh :: CreatePoint2ElementTable(std::optional points, int domain) const + Table Mesh :: CreatePoint2ElementTable(std::optional> points, int domain) const { + static Timer timer("Mesh::CreatePoint2VolumeElementTable"); RegionTimer rt(timer); + if(points) { const auto & free_points = *points; @@ -6930,6 +7042,42 @@ namespace netgen }, GetNP()); } + + CompressedTable Mesh :: CreateCompressedPoint2SurfaceElementTable( int faceindex ) const + { + static Timer timer("Mesh::CreatePoint2SurfaceElementTable"); RegionTimer rt(timer); + + CompressedTableCreator creator; + + if(faceindex==0) + { + for ( ; !creator.Done(); creator++) + for (auto sei : SurfaceElements().Range()) + for (auto pi : (*this)[sei].PNums()) + creator.Add(pi, sei); + } + else + { + Array face_els; + GetSurfaceElementsOfFace(faceindex, face_els); + + for ( ; !creator.Done(); creator++) + for (auto sei : face_els) + for (auto pi : (*this)[sei].PNums()) + creator.Add(pi, sei); + } + + + auto compressed_table = creator.MoveTable(); + + for (auto row : compressed_table.GetTable()) + QuickSort (row); + + return compressed_table; + } + + + /* @@ -7105,6 +7253,149 @@ namespace netgen SetNextMajorTimeStamp(); } + void Mesh :: SplitFacesByAdjacentDomains () + { + UpdateTopology(); + std::map, int> face_doms_2_new_face; + int nfaces = FaceDescriptors().Size(); + Array first_visit(nfaces); + first_visit = true; + + for (auto sei : Range(SurfaceElements())) + { + int eli0, eli1; + GetTopology().GetSurface2VolumeElement(sei+1, eli0, eli1); + // auto [ei0,ei1] = GetTopology().GetSurface2VolumeElement(sei); // the way to go + if(eli0 == 0) + continue; + auto & sel = (*this)[sei]; + int face = sel.GetIndex(); + int domin = VolumeElement(eli0).GetIndex(); + int domout = eli1 ? VolumeElement(eli1).GetIndex() : 0; + if(domin < domout) + swap(domin, domout); + + auto key = std::make_tuple(face, domin, domout); + if(face_doms_2_new_face.find(key) == face_doms_2_new_face.end()) + { + { + auto & fd = FaceDescriptors()[face-1]; + if(domout == 0 && min(fd.DomainIn(), fd.DomainOut()) > 0) + continue; + } + if(!first_visit[face-1]) { + nfaces++; + FaceDescriptor new_fd = FaceDescriptors()[face-1]; + new_fd.bcprop = nfaces; + new_fd.domin = domin; + new_fd.domout = domout; + AddFaceDescriptor(new_fd); + SetBCName(nfaces-1, new_fd.GetBCName()); + face_doms_2_new_face[key] = nfaces; + } + else { + face_doms_2_new_face[key] = face; + auto & fd = FaceDescriptors()[face-1]; + fd.domin = domin; + fd.domout = domout; + } + first_visit[face-1] = false; + } + sel.SetIndex(face_doms_2_new_face[key]); + } + SetNextMajorTimeStamp(); + RebuildSurfaceElementLists (); + CalcSurfacesOfNode(); + UpdateTopology(); + } + + shared_ptr Mesh :: GetSubMesh(string domains, string faces) const + { + // Copy the mesh into a new one, then delete unwanted elements + // Unused points are deleted by the Compress() function at the end + auto mesh_ptr = make_unique(); + auto & mesh = *mesh_ptr; + mesh = (*this); + + auto ndomains = GetNDomains(); + auto nfaces = GetNFD(); + + BitArray keep_point(GetNP()+1); + BitArray keep_face(nfaces+1); + BitArray keep_domain(ndomains+1); + keep_point.Clear(); + keep_face.Clear(); + keep_domain.Clear(); + + regex regex_faces(faces); + regex regex_domains(domains); + + if(dimension == 3) { + for(auto dom : Range(ndomains)) + if(regex_match(mesh.GetMaterial(dom+1), regex_domains)) + keep_domain.SetBit(dom); + + for(auto fi : Range(nfaces)) + { + auto & fd = mesh.FaceDescriptors()[fi]; + if (regex_match(fd.GetBCName(), regex_faces) + || keep_domain[fd.DomainIn()] || keep_domain[fd.DomainOut()]) + keep_face.SetBit(fd.BCProperty()); + } + } + else { + for(auto fi : Range(nfaces)) + { + auto & fd = mesh.FaceDescriptors()[fi]; + auto mat = GetMaterial(fd.BCProperty()); + if (regex_match(mat, regex_faces)) + keep_face.SetBit(fd.BCProperty()); + } + } + + auto filter_elements = [&keep_point](auto & elements, auto & keep_region) + { + for(auto & el : elements) + { + if(keep_region[el.GetIndex()]) + for (auto pi : el.PNums()) + keep_point.SetBit(pi); + else + el.Delete(); + } + }; + + filter_elements(mesh.VolumeElements(), keep_domain); + filter_elements(mesh.SurfaceElements(), keep_face); + + // Keep line segments only if all points are kept + // Check them in reverse order because they are deleted from the end + auto nsegments = mesh.LineSegments().Size(); + for(auto i : Range(nsegments)) + { + SegmentIndex segi = nsegments-i-1; + auto seg = mesh[segi]; + bool keep = true; + for(auto pi : seg.PNums()) + keep &= keep_point[pi]; + + if(!keep) + mesh.LineSegments().DeleteElement(segi); + } + + // Check in reverse order because they are deleted from the end + auto npointelements = mesh.pointelements.Size(); + for(auto i : Range(npointelements)) + { + auto pel = mesh.pointelements[npointelements-i-1]; + if(!keep_point[pel.pnum]) + mesh.pointelements.DeleteElement(npointelements-i-1); + } + + mesh.Compress(); + return mesh_ptr; + } + void Mesh :: SetMaterial (int domnr, const string & mat) { if (domnr > materials.Size()) @@ -7118,14 +7409,15 @@ namespace netgen materials.Elem(domnr) = new char[strlen(mat)+1]; strcpy (materials.Elem(domnr), mat); */ - materials.Elem(domnr) = new string(mat); + materials[domnr-1] = new string(mat); } string Mesh :: defaultmat = "default"; + string_view Mesh :: defaultmat_sv = "default"; const string & Mesh :: GetMaterial (int domnr) const { - if (domnr <= materials.Size()) - return *materials.Get(domnr); + if (domnr <= materials.Size() && materials[domnr-1]) + return *materials[domnr-1]; static string emptystring("default"); return emptystring; } @@ -7253,9 +7545,9 @@ namespace netgen } string Mesh :: cd3_default_name = "default"; + static string defaultstring = "default"; const string & Mesh :: GetCD3Name (int cd3nr) const { - static string defaultstring = "default"; if (!cd3names.Size()) return defaultstring; @@ -7269,7 +7561,7 @@ namespace netgen } - NgArray & Mesh :: GetRegionNamesCD (int codim) + Array & Mesh :: GetRegionNamesCD (int codim) { switch (codim) { @@ -7281,6 +7573,24 @@ namespace netgen } } + + std::string_view Mesh :: GetRegionName (const Segment & el) const + { + return *const_cast(*this).GetRegionNamesCD(GetDimension()-1)[el.edgenr-1]; + } + + std::string_view Mesh :: GetRegionName (const Element2d & el) const + { + return *const_cast(*this).GetRegionNamesCD(GetDimension()-2)[GetFaceDescriptor(el).BCProperty()-1]; + } + + std::string_view Mesh :: GetRegionName (const Element & el) const + { + const auto& names = const_cast(*this).GetRegionNamesCD(GetDimension()-3); + if(names.Size() <= el.GetIndex()) + return defaultstring; + return *const_cast(*this).GetRegionNamesCD(GetDimension()-3)[el.GetIndex()-1]; + } void Mesh :: SetUserData(const char * id, NgArray & data) @@ -7376,15 +7686,17 @@ namespace netgen auto v = pmax-pmin; double eps = v.Length()*1e-8; + /* auto onPlane = [&] (const MeshPoint & p) -> bool { auto v = p_plane-p; auto l = v.Length(); if(l PointIndex @@ -7491,4 +7803,108 @@ namespace netgen return nm_; } + void AddFacesBetweenDomains(Mesh & mesh) + { + static Timer timer("AddFacesBetweenDomains"); RegionTimer rt(timer); + auto & topo = mesh.GetTopology(); + auto p2el = mesh.CreatePoint2ElementTable(); + + Array els_per_domain(mesh.GetNDomains()+1); + els_per_domain = 0; + + for(const auto & el : mesh.VolumeElements()) + els_per_domain[el.GetIndex()]++; + + std::map, int> doms_2_new_face; + + for(const auto & [facei, fd]: Enumerate(mesh.FaceDescriptors())) + { + auto dom0 = fd.DomainIn(); + auto dom1 = fd.DomainOut(); + if(dom0 > dom1) + swap(dom0, dom1); + + doms_2_new_face[{dom0, dom1}] = facei+1; + } + + for(auto dom : Range(1, 1+mesh.GetNDomains())) + { + if(els_per_domain[dom] == 0) + continue; + + mesh.UpdateTopology(); + + mesh.FindOpenElements(dom); + for(const auto & openel : mesh.OpenElements()) + { + std::set has_p1, has_p2, has_p3; + for (auto ei: topo.GetVertexElements(openel[0])) + has_p1.insert(ei); + for (auto ei: topo.GetVertexElements(openel[1])) + has_p2.insert(ei); + for (auto ei: topo.GetVertexElements(openel[2])) + has_p3.insert(ei); + + std::set has_p12, has_all; + set_intersection(has_p1.begin(), has_p1.end(), + has_p2.begin(), has_p2.end(), + inserter(has_p12, has_p12.begin())); + set_intersection(has_p12.begin(), has_p12.end(), + has_p3.begin(), has_p3.end(), + inserter(has_all, has_all.begin())); + + ArrayMem els; + for(auto ei : has_all) + els.Append(ei); + + if(els.Size() == 2 && mesh[els[0]].GetIndex() != mesh[els[1]].GetIndex()) + { + auto dom0 = mesh[els[0]].GetIndex(); + auto dom1 = mesh[els[1]].GetIndex(); + ElementIndex ei0 = els[0]; + if(dom0 > dom1) + { + Swap(dom0, dom1); + ei0 = els[1]; + } + + if(dom1 == dom) + continue; + + if(doms_2_new_face.count({dom0, dom1}) == 0) + { + auto fd = FaceDescriptor(-1, dom0, dom1, -1); + auto new_si = mesh.GetNFD()+1; + fd.SetBCProperty(new_si); + auto new_face = mesh.AddFaceDescriptor(fd); + mesh.SetBCName(new_si - 1, "default"); + doms_2_new_face[{dom0, dom1}] = new_face; + } + for(auto face : topo.GetFaces(ei0)) { + auto verts = topo.GetFaceVertices(face); + if(verts.Contains(openel[0]) && verts.Contains(openel[1]) && verts.Contains(openel[2])) { + Element2d sel(static_cast(verts.Size())); + sel.SetIndex(doms_2_new_face[{dom0, dom1}]); + + for(auto j : Range(verts.Size())) + sel[j] = verts[j]; + auto normal = Cross(mesh[sel[1]]-mesh[sel[0]], mesh[sel[2]]-mesh[sel[0]]); + Vec<3> surf_center = Vec<3>(Center(mesh[sel[0]] , mesh[sel[1]] , mesh[sel[2]])); + Vec<3> center(0., 0., 0.); + for(auto pi : mesh[ei0].PNums()) + center += Vec<3>(mesh[pi]); + center *= 1.0/mesh[ei0].GetNP(); + if((normal * (center - surf_center)) < 0) + sel.Invert(); + mesh.AddSurfaceElement(sel); + break; + } + } + } + } + } + + + } + } diff --git a/libsrc/meshing/meshclass.hpp b/libsrc/meshing/meshclass.hpp index 22ac8960..285448a3 100644 --- a/libsrc/meshing/meshclass.hpp +++ b/libsrc/meshing/meshclass.hpp @@ -1,5 +1,5 @@ -#ifndef MESHCLASS -#define MESHCLASS +#ifndef NETGEN_MESHCLASS_HPP +#define NETGEN_MESHCLASS_HPP /**************************************************************************/ /* File: meshclass.hpp */ @@ -13,11 +13,20 @@ #include +#include +#include + +#include "meshtype.hpp" +#include "localh.hpp" +#include "topology.hpp" +#include "paralleltop.hpp" + namespace netgen { + class NetgenGeometry; using namespace std; - static constexpr int MPI_TAG_MESH = 210; + static constexpr int NG_MPI_TAG_MESH = 210; enum resthtype { RESTRICTH_FACE, RESTRICTH_EDGE, @@ -27,6 +36,30 @@ namespace netgen class CurvedElements; class AnisotropicClusters; class ParallelMeshTopology; + + class MarkedTet; + class MarkedPrism; + class MarkedIdentification; + class MarkedTri; + class MarkedQuad; + + typedef Array T_MTETS; + typedef NgArray T_MPRISMS; + typedef NgArray T_MIDS; + typedef NgArray T_MTRIS; + typedef NgArray T_MQUADS; + + struct BisectionInfo + { + unique_ptr mtets; + unique_ptr mprisms; + unique_ptr mids; + unique_ptr mtris; + unique_ptr mquads; + + BisectionInfo(); + ~BisectionInfo(); + }; /// 2d/3d mesh class Mesh @@ -95,18 +128,26 @@ namespace netgen */ NgArray edgedecoding; + Array region_name_cd[4]; + Array & materials = region_name_cd[0]; + Array & bcnames = region_name_cd[1]; + Array & cd2names = region_name_cd[2]; + Array & cd3names = region_name_cd[3]; + + /* /// sub-domain materials - NgArray materials; + Array materials; /// labels for boundary conditions - NgArray bcnames; + Array bcnames; /// labels for co dim 2 bboundary conditions - NgArray cd2names; + Array cd2names; /// labels for co dim 3 bbboundary conditions - NgArray cd3names; - + Array cd3names; + */ + /// Periodic surface, close surface, etc. identifications unique_ptr ident; @@ -115,9 +156,10 @@ namespace netgen int numvertices; /// geometric search tree for interval intersection search - unique_ptr> elementsearchtree; + unique_ptr> elementsearchtree_vol; + unique_ptr> elementsearchtree_surf; /// time stamp for tree - mutable int elementsearchtreets; + mutable size_t elementsearchtreets[4]; /// element -> face, element -> edge etc ... MeshTopology topology; @@ -167,17 +209,18 @@ namespace netgen DLL_HEADER bool PointContainedIn2DElement(const Point3d & p, double lami[3], - const int element, + SurfaceElementIndex element, bool consider3D = false) const; DLL_HEADER bool PointContainedIn3DElement(const Point3d & p, double lami[3], - const int element) const; + ElementIndex element) const; DLL_HEADER bool PointContainedIn3DElementOld(const Point3d & p, double lami[3], const int element) const; public: Signal<> updateSignal; + BisectionInfo bisectioninfo; // store coarse mesh before hp-refinement unique_ptr> hpelements; @@ -189,11 +232,11 @@ namespace netgen // number of vertices on each refinement level: NgArray level_nv; /// refinement hierarchy - NgArray,PointIndex::BASE> mlbetweennodes; + Array,PointIndex> mlbetweennodes; /// parent element of volume element - NgArray mlparentelement; + Array mlparentelement; /// parent element of surface element - NgArray mlparentsurfaceelement; + Array mlparentsurfaceelement; @@ -202,7 +245,7 @@ namespace netgen /// DLL_HEADER ~Mesh(); - Mesh & operator= (const Mesh & mesh2); + DLL_HEADER Mesh & operator= (const Mesh & mesh2); /// DLL_HEADER void DeleteMesh(); @@ -236,17 +279,19 @@ namespace netgen auto GetNP () const { return points.Size(); } // [[deprecated("Use Point(PointIndex) instead of int !")]] - MeshPoint & Point(int i) + MeshPoint & Point(int i) // 1-based { // return points.Elem(i); - return Point (PointIndex(i+PointIndex::BASE-1)); - } + // return Point (PointIndex(i+PointIndex::BASE-1)); + return Point (PointIndex(IndexBASE()+i-1)); + } MeshPoint & Point(PointIndex pi) { return points[pi]; } // [[deprecated("Use Point(PointIndex) instead of int !")]] const MeshPoint & Point(int i) const { // return points.Get(i); - return Point (PointIndex(i+PointIndex::BASE-1)); + // return Point (PointIndex(i+PointIndex::BASE-1)); + return Point (PointIndex(IndexBASE()+i-1)); } const MeshPoint & Point(PointIndex pi) const { return points[pi]; } @@ -342,7 +387,7 @@ namespace netgen const auto & SurfaceElements() const { return surfelements; } auto & SurfaceElements() { return surfelements; } - + DLL_HEADER void RebuildSurfaceElementLists (); DLL_HEADER void GetSurfaceElementsOfFace (int facenr, Array & sei) const; @@ -353,9 +398,9 @@ namespace netgen auto GetNE () const { return volelements.Size(); } // [[deprecated("Use VolumeElement(ElementIndex) instead of int !")]] - Element & VolumeElement(int i) { return volelements[i-1]; } + Element & VolumeElement(int i) { return volelements[IndexBASE()+(i-1)]; } // [[deprecated("Use VolumeElement(ElementIndex) instead of int !")]] - const Element & VolumeElement(int i) const { return volelements[i-1]; } + const Element & VolumeElement(int i) const { return volelements[IndexBASE()+(i-1)]; } // [[deprecated("Use mesh[](VolumeElementIndex) instead !")]] Element & VolumeElement(ElementIndex i) { return volelements[i]; } // [[deprecated("Use mesh[](VolumeElementIndex) instead !")]] @@ -390,7 +435,7 @@ namespace netgen DLL_HEADER void CalcSurfacesOfNode (); /// additional (temporarily) fix points - void FixPoints (const NgBitArray & fixpoints); + void FixPoints (const TBitArray & fixpoints); /** finds elements without neighbour and @@ -472,7 +517,7 @@ namespace netgen /// LocalH & LocalHFunction (int layer=1) { return * lochfunc[layer-1]; } - shared_ptr GetLocalH(int layer=1) const + shared_ptr & GetLocalH(int layer=1) const { if(lochfunc.Size() == 1) return lochfunc[0]; @@ -518,8 +563,8 @@ namespace netgen { if(!boundaryedges) const_cast(this)->BuildBoundaryEdges(); - - INDEX_2 i2 (pi1, pi2); + + PointIndices<2> i2(pi1, pi2); i2.Sort(); return boundaryedges->Used (i2); } @@ -531,14 +576,14 @@ namespace netgen bool IsSegment (PointIndex pi1, PointIndex pi2) const { - INDEX_2 i2 (pi1, pi2); + PointIndices<2> i2 (pi1, pi2); i2.Sort(); return segmentht->Used (i2); } SegmentIndex SegmentNr (PointIndex pi1, PointIndex pi2) const { - INDEX_2 i2 (pi1, pi2); + PointIndices<2> i2(pi1, pi2); i2.Sort(); return segmentht->Get (i2); } @@ -571,13 +616,14 @@ namespace netgen DLL_HEADER void ImproveMesh (const MeshingParameters & mp, OPTIMIZEGOAL goal = OPT_QUALITY); /// - void ImproveMeshJacobian (const MeshingParameters & mp, OPTIMIZEGOAL goal = OPT_QUALITY, const NgBitArray * usepoint = NULL); + void ImproveMeshJacobian (const MeshingParameters & mp, OPTIMIZEGOAL goal = OPT_QUALITY, + const TBitArray * usepoint = NULL); /// void ImproveMeshJacobianOnSurface (const MeshingParameters & mp, - const NgBitArray & usepoint, + const TBitArray & usepoint, const NgArray< Vec<3>* > & nv, OPTIMIZEGOAL goal = OPT_QUALITY, - const NgArray< NgArray* > * idmaps = NULL); + const NgArray< idmap_type* > * idmaps = NULL); /** free nodes in environment of openelements for optimiztion @@ -616,7 +662,7 @@ namespace netgen Marks elements which are dangerous to refine return: number of illegal elements */ - DLL_HEADER int MarkIllegalElements (); + DLL_HEADER int MarkIllegalElements (int domain=0); /// orient surface mesh, for one sub-domain only DLL_HEADER void SurfaceMeshOrientation (); @@ -626,35 +672,48 @@ namespace netgen /// build box-search tree - DLL_HEADER void BuildElementSearchTree (); + DLL_HEADER void BuildElementSearchTree (int dim); + BoxTree<3, ElementIndex>* GetElementSearchTree () const + { + return elementsearchtree_vol.get(); + } + + BoxTree<3, SurfaceElementIndex>* GetSurfaceElementSearchTree () const + { + return elementsearchtree_surf.get(); + } void SetPointSearchStartElement(const int el) const {ps_startelement = el;} /// gives element of point, barycentric coordinates - DLL_HEADER int GetElementOfPoint (const netgen::Point<3> & p, - double * lami, - bool build_searchtree = 0, - const int index = -1, - const bool allowindex = true) const; - DLL_HEADER int GetElementOfPoint (const netgen::Point<3> & p, - double * lami, - const NgArray * const indices, - bool build_searchtree = 0, - const bool allowindex = true) const; - DLL_HEADER int GetSurfaceElementOfPoint (const netgen::Point<3> & p, - double * lami, - bool build_searchtree = 0, - const int index = -1, - const bool allowindex = true) const; - DLL_HEADER int GetSurfaceElementOfPoint (const netgen::Point<3> & p, - double * lami, - const NgArray * const indices, - bool build_searchtree = 0, - const bool allowindex = true) const; + DLL_HEADER ElementIndex + GetElementOfPoint (const netgen::Point<3> & p, + double * lami, + bool build_searchtree = false, + int index = -1, + bool allowindex = true) const; + DLL_HEADER ElementIndex + GetElementOfPoint (const netgen::Point<3> & p, + double * lami, + std::optional> indices, + bool build_searchtree = 0, + bool allowindex = true) const; + DLL_HEADER SurfaceElementIndex + GetSurfaceElementOfPoint (const netgen::Point<3> & p, + double * lami, + bool build_searchtree = false, + int index = -1, + bool allowindex = true) const; + DLL_HEADER SurfaceElementIndex + GetSurfaceElementOfPoint (const netgen::Point<3> & p, + double * lami, + std::optional> indices, + bool build_searchtree = false, + bool allowindex = true) const; /// give list of vol elements which are int the box(p1,p2) void GetIntersectingVolEls(const Point3d& p1, const Point3d& p2, - NgArray & locels) const; + Array & locels) const; /// int AddFaceDescriptor(const FaceDescriptor& fd) @@ -666,6 +725,9 @@ namespace netgen auto & GetCommunicator() const { return this->comm; } void SetCommunicator(NgMPI_Comm acomm); + DLL_HEADER void SplitFacesByAdjacentDomains(); + DLL_HEADER shared_ptr GetSubMesh(string domains="", string faces="") const; + /// DLL_HEADER void SetMaterial (int domnr, const string & mat); /// @@ -673,7 +735,7 @@ namespace netgen DLL_HEADER static string defaultmat; const string * GetMaterialPtr (int domnr) const // 1-based { - return domnr <= materials.Size() ? materials.Get(domnr) : &defaultmat; + return domnr <= materials.Size() ? materials[domnr-1] : &defaultmat; } DLL_HEADER void SetNBCNames ( int nbcn ); @@ -712,7 +774,24 @@ namespace netgen { return (bcnr < bcnames.Size() && bcnames[bcnr]) ? bcnames[bcnr] : &default_bc; } - NgArray & GetRegionNamesCD (int codim); + DLL_HEADER Array & GetRegionNamesCD (int codim); + + DLL_HEADER std::string_view GetRegionName(const Segment & el) const; + DLL_HEADER std::string_view GetRegionName(const Element2d & el) const; + DLL_HEADER std::string_view GetRegionName(const Element & el) const; + + std::string_view GetRegionName(SegmentIndex ei) const { return GetRegionName((*this)[ei]); } + std::string_view GetRegionName(SurfaceElementIndex ei) const { return GetRegionName((*this)[ei]); } + std::string_view GetRegionName(ElementIndex ei) const { return GetRegionName((*this)[ei]); } + + DLL_HEADER static string_view defaultmat_sv; + std::string_view GetRegionName (int dim, int domnr) // 1-based domnr + { + domnr--; + auto & names = region_name_cd[dimension-dim]; + if (domnr < names.Size() && names[domnr]) return *names[domnr]; + return defaultmat_sv; + } /// void ClearFaceDescriptors() @@ -740,8 +819,8 @@ namespace netgen { return facedecoding[i-1]; } // { return facedecoding.Elem(i); } - int IdentifyPeriodicBoundaries(const string& s1, - const string& s2, + int IdentifyPeriodicBoundaries(const string& id_name, + const string& s1, const Transformation<3>& mapping, double pointTolerance); @@ -797,8 +876,10 @@ namespace netgen - DLL_HEADER Table CreatePoint2ElementTable(std::optional points = std::nullopt, int domain = 0) const; + DLL_HEADER Table CreatePoint2ElementTable(std::optional> points = std::nullopt, int domain = 0) const; + // DLL_HEADER Table CreatePoint2SurfaceElementTable( int faceindex=0 ) const; DLL_HEADER Table CreatePoint2SurfaceElementTable( int faceindex=0 ) const; + DLL_HEADER CompressedTable CreateCompressedPoint2SurfaceElementTable( int faceindex=0 ) const; DLL_HEADER bool PureTrigMesh (int faceindex = 0) const; DLL_HEADER bool PureTetMesh () const; @@ -874,11 +955,7 @@ namespace netgen NgMutex & MajorMutex () { return majormutex; } - shared_ptr GetGeometry() const - { - static auto global_geometry = make_shared(); - return geometry ? geometry : global_geometry; - } + DLL_HEADER shared_ptr GetGeometry() const; void SetGeometry (shared_ptr geom) { geometry = geom; @@ -913,7 +990,7 @@ namespace netgen /// distributes the master-mesh to local meshes DLL_HEADER void Distribute (); DLL_HEADER void Distribute (NgArray & volume_weights, NgArray & surface_weights, - NgArray & segment_weights); + NgArray & segment_weights); /// find connection to parallel meshes @@ -923,20 +1000,19 @@ namespace netgen // void FindExchangeFaces (); /// use metis to decompose master mesh - DLL_HEADER void ParallelMetis (int nproc); // NgArray & neloc ); + DLL_HEADER void ParallelMetis (int nproc); DLL_HEADER void ParallelMetis (NgArray & volume_weights, NgArray & surface_weights, - NgArray & segment_weights); - - void PartHybridMesh (); // NgArray & neloc ); - void PartDualHybridMesh (); // NgArray & neloc ); - void PartDualHybridMesh2D (); // ( NgArray & neloc ); + NgArray & segment_weights); + void PartHybridMesh (); + void PartDualHybridMesh (); + void PartDualHybridMesh2D (); /// send mesh from master to local procs void SendRecvMesh (); /// send mesh to parallel machine, keep global mesh at master - void SendMesh ( ) const; // Mesh * mastermesh, NgArray & neloc) const; + void SendMesh ( ) const; /// loads a mesh sent from master processor void ReceiveParallelMesh (); @@ -949,7 +1025,7 @@ namespace netgen NgArray & segment_weights){ } #endif - NgArray vol_partition; + Array vol_partition; NgArray surf_partition; NgArray seg_partition; @@ -990,9 +1066,7 @@ namespace netgen return FlatArray(GetNFaces ( (*mesh)[elnr].GetType()), &faces[elnr][0]); } - + DLL_HEADER void AddFacesBetweenDomains(Mesh & mesh); } -#endif - - +#endif // NETGEN_MESHCLASS_HPP diff --git a/libsrc/meshing/meshfunc.cpp b/libsrc/meshing/meshfunc.cpp index a9a05f20..5dee0579 100644 --- a/libsrc/meshing/meshfunc.cpp +++ b/libsrc/meshing/meshfunc.cpp @@ -3,6 +3,7 @@ #include #include "meshing.hpp" #include "debugging.hpp" +#include "boundarylayer.hpp" namespace netgen { @@ -54,10 +55,15 @@ namespace netgen Array> ipmap; ipmap.SetSize(num_domains); - auto dim = mesh.GetDimension(); + // auto dim = mesh.GetDimension(); auto num_points = mesh.GetNP(); auto num_facedescriptors = mesh.GetNFD(); + + constexpr PointIndex state0 = IndexBASE()-1; + constexpr PointIndex state1 = state0+1; + constexpr PointIndex state2 = state0+2; + for(auto i : Range(ret)) { auto & md = ret[i]; @@ -72,7 +78,7 @@ namespace netgen m.SetLocalH(mesh.GetLocalH()); ipmap[i].SetSize(num_points); - ipmap[i] = PointIndex::INVALID; + ipmap[i] = state0; // 0; // PointIndex::INVALID; m.SetDimension( mesh.GetDimension() ); m.SetGeometry( mesh.GetGeometry() ); @@ -80,6 +86,16 @@ namespace netgen m.AddFaceDescriptor( mesh.GetFaceDescriptor(i) ); } + // mark interior edge points + for(const auto& seg : mesh.LineSegments()) + { + if(seg.domin > 0 && seg.domin == seg.domout) + { + ipmap[seg.domin-1][seg[0]] = state1; // 1; + ipmap[seg.domin-1][seg[1]] = state1; // 1; + } + } + // mark used points for each domain, add surface elements (with wrong point numbers) to domain mesh for(const auto & sel : mesh.SurfaceElements()) { @@ -89,12 +105,12 @@ namespace netgen for( auto dom : {dom_in, dom_out} ) { - if(dom==0) + if(dom<=0) continue; auto & sels = ret[dom-1].mesh->SurfaceElements(); for(auto pi : sel.PNums()) - ipmap[dom-1][pi] = 1; + ipmap[dom-1][pi] = state1; // 1; sels.Append(sel); } } @@ -103,17 +119,17 @@ namespace netgen for(const auto & el : mesh.VolumeElements()) { auto dom = el.GetIndex(); - + auto & els = ret[dom-1].mesh->VolumeElements(); for(auto pi : el.PNums()) - ipmap[dom-1][pi] = 1; + ipmap[dom-1][pi] = state1; // 1; els.Append(el); } // mark locked/fixed points for each domain TODO: domain bounding box to add only relevant points? for(auto pi : mesh.LockedPoints()) for(auto i : Range(ret)) - ipmap[i][pi] = 2; + ipmap[i][pi] = state2; // 2; // add used points to domain mesh, build point mapping for(auto i : Range(ret)) @@ -122,11 +138,11 @@ namespace netgen auto & pmap = ret[i].pmap; for(auto pi : Range(ipmap[i])) - if(ipmap[i][pi]) + if(ipmap[i][pi] != state0) { const auto& mp = mesh[pi]; auto pi_new = m.AddPoint( mp, mp.GetLayer(), mp.Type() ); - if(ipmap[i][pi] == 2) + if(ipmap[i][pi] == state2) // 2) mesh.AddLockedPoint(pi_new); ipmap[i][pi] = pi_new; pmap.Append( pi ); @@ -200,8 +216,8 @@ namespace netgen if(!have_closesurfaces) return; - NgArray map; - std::set> hex_faces; + idmap_type map; + std::set> hex_faces; for(auto identnr : Range(1,nmax+1)) { if(identifications.GetType(identnr) != Identifications::CLOSESURFACES) @@ -232,7 +248,7 @@ namespace netgen // insert prism/hex auto np = sel.GetNP(); Element el(2*np); - std::set pis; + std::set pis; for(auto i : Range(np)) { el[i] = sel[i]; @@ -346,7 +362,8 @@ namespace netgen meshing.GenerateMesh (mesh, mpquad); - for (int i = oldne + 1; i <= mesh.GetNE(); i++) + // for (int i = oldne + 1; i <= mesh.GetNE(); i++) + for (ElementIndex i : mesh.VolumeElements().Range().Modify(oldne, 0)) mesh.VolumeElement(i).SetIndex (domain); (*testout) @@ -359,8 +376,11 @@ namespace netgen if (mesh.HasOpenQuads()) { - if(debugparam.write_mesh_on_error) - md.mesh->Save("open_quads_"+ToString(md.domain)+".vol.gz"); + if(debugparam.write_mesh_on_error) { + md.mesh->Save("open_quads_starting_mesh_"+ToString(md.domain)+".vol.gz"); + GetOpenElements(*md.mesh, md.domain)->Save("open_quads_rest_" + ToString(md.domain)+".vol.gz"); + GetOpenElements(*md.mesh, md.domain, true)->Save("open_quads_rest_" + ToString(md.domain)+"_only_quads.vol.gz"); + } PrintSysError ("mesh has still open quads"); throw NgException ("Stop meshing since too many attempts"); // return MESHING3_GIVEUP; @@ -384,34 +404,35 @@ namespace netgen for (int i = 1; i <= mesh.GetNOpenElements(); i++) md.meshing->AddBoundaryElement (mesh.OpenElement(i)); - if (mp.delaunay && mesh.GetNOpenElements()) - { + if (mp.delaunay && mesh.GetNOpenElements()) + { int oldne = mesh.GetNE(); md.meshing->Delaunay (mesh, domain, mp); - for (int i = oldne + 1; i <= mesh.GetNE(); i++) + // for (int i = oldne + 1; i <= mesh.GetNE(); i++) + for (ElementIndex i : mesh.VolumeElements().Range().Modify(oldne, 0)) mesh.VolumeElement(i).SetIndex (domain); PrintMessage (3, mesh.GetNP(), " points, ", mesh.GetNE(), " elements"); mesh.FindOpenElements(domain); - } + } - Box<3> domain_bbox( Box<3>::EMPTY_BOX ); + Box<3> domain_bbox( Box<3>::EMPTY_BOX ); - for (auto & sel : mesh.SurfaceElements()) + for (auto & sel : mesh.SurfaceElements()) { if (sel.IsDeleted() ) continue; for (auto pi : sel.PNums()) domain_bbox.Add (mesh[pi]); } - domain_bbox.Increase (0.01 * domain_bbox.Diam()); + domain_bbox.Increase (0.01 * domain_bbox.Diam()); - int cntsteps = 0; - int meshed; - if (mesh.GetNOpenElements()) + int cntsteps = 0; + int meshed; + if (mesh.GetNOpenElements()) do { if (multithread.terminate) @@ -419,14 +440,18 @@ namespace netgen mesh.FindOpenElements(domain); PrintMessage (5, mesh.GetNOpenElements(), " open faces"); - // GetOpenElements( mesh, domain )->Save("open_"+ToString(cntsteps)+".vol"); + // GetOpenElements( mesh, domain )->Save("open_"+ToString(domain)+"_"+ToString(cntsteps)+".vol"); cntsteps++; if (cntsteps > mp.maxoutersteps) { if(debugparam.write_mesh_on_error) + { md.mesh->Save("meshing_error_domain_"+ToString(md.domain)+".vol.gz"); + if(mesh.GetNOpenElements()) + GetOpenElements(*md.mesh, md.domain)->Save("meshing_error_rest_" + ToString(md.domain)+".vol.gz"); + } throw NgException ("Stop meshing since too many attempts in domain " + ToString(md.domain)); } @@ -439,14 +464,14 @@ namespace netgen for (PointIndex pi : mesh.Points().Range()) if (domain_bbox.IsIn (mesh[pi])) - glob2loc[pi] = meshing.AddPoint (mesh[pi], pi); + glob2loc[pi] = meshing.AddPoint (mesh[pi], pi); - for (auto sel : mesh.OpenElements() ) - { - for(auto & pi : sel.PNums()) + for (auto sel : mesh.OpenElements()) + { + for(auto & pi : sel.PNums()) pi = glob2loc[pi]; - meshing.AddBoundaryElement (sel); - } + meshing.AddBoundaryElement (sel); + } int oldne = mesh.GetNE(); @@ -454,8 +479,8 @@ namespace netgen mp.sloppy = 5; meshing.GenerateMesh (mesh, mp); - for (ElementIndex ei = oldne; ei < mesh.GetNE(); ei++) - mesh[ei].SetIndex (domain); + for (auto & el : mesh.VolumeElements().Range(oldne, END)) + el.SetIndex (domain); mesh.CalcSurfacesOfNode(); @@ -467,7 +492,7 @@ namespace netgen meshed = 0; PrintMessage (5, mesh.GetNOpenElements(), " open faces found"); - MeshOptimize3d optmesh(mp); + MeshOptimize3d optmesh(mesh, mp, OPT_REST); const char * optstr = "mcmstmcmstmcmstmcm"; for (size_t j = 1; j <= strlen(optstr); j++) @@ -479,11 +504,11 @@ namespace netgen switch (optstr[j-1]) { - case 'c': optmesh.CombineImprove(mesh, OPT_REST); break; - case 'd': optmesh.SplitImprove(mesh, OPT_REST); break; - case 's': optmesh.SwapImprove(mesh, OPT_REST); break; - case 't': optmesh.SwapImprove2(mesh, OPT_REST); break; - case 'm': mesh.ImproveMesh(mp, OPT_REST); break; + case 'c': optmesh.CombineImprove(); break; + case 'd': optmesh.SplitImprove(); break; + case 's': optmesh.SwapImprove(); break; + case 't': optmesh.SwapImprove2(); break; + case 'm': optmesh.ImproveMesh(); break; } } @@ -499,22 +524,22 @@ namespace netgen PrintMessage (1, "Success !"); } } - while (!meshed); - - { - PrintMessage (3, "Check subdomain ", domain, " / ", mesh.GetNDomains()); + while (!meshed); - mesh.FindOpenElements(domain); + PrintMessage (3, "Check subdomain ", domain, " / ", mesh.GetNDomains()); - bool res = (mesh.CheckConsistentBoundary() != 0); - if (res) - { - if(debugparam.write_mesh_on_error) - md.mesh->Save("inconsistent_surface_domain_"+ToString(md.domain)+".vol.gz"); - PrintError ("Surface mesh not consistent"); - throw NgException ("Stop meshing since surface mesh not consistent"); - } - } + mesh.FindOpenElements(domain); + + bool res = (mesh.CheckConsistentBoundary() != 0); + if (res) + { + if(debugparam.write_mesh_on_error) + md.mesh->Save("inconsistent_surface_domain_"+ToString(md.domain)+".vol.gz"); + PrintError ("Surface mesh not consistent"); + throw NgException ("Stop meshing since surface mesh not consistent"); + } + RemoveIllegalElements (mesh, domain); + ConformToFreeSegments (mesh, domain); } void MergeMeshes( Mesh & mesh, Array & md ) @@ -532,12 +557,14 @@ namespace netgen } mesh.VolumeElements().DeleteAll(); + mesh.GetIdentifications().GetIdentifiedPoints().DeleteData(); + for(auto & m_ : md) { auto first_new_pi = m_.pmap.Range().Next(); auto & m = *m_.mesh; Array pmap(m.Points().Size()); - for(auto pi : Range(PointIndex(PointIndex::BASE), first_new_pi)) + for(auto pi : Range(IndexBASE(), first_new_pi)) pmap[pi] = m_.pmap[pi]; for (auto pi : Range(first_new_pi, m.Points().Range().Next())) @@ -551,6 +578,16 @@ namespace netgen el.SetIndex(m_.domain); mesh.AddVolumeElement(el); } + // for(const auto& [p1p2, dummy] : m.GetIdentifications().GetIdentifiedPoints()) + // mesh.GetIdentifications().Add(pmap[p1p2[0]], pmap[p1p2[1]], p1p2[2]); + for(const auto& [p1p2, dummy] : m.GetIdentifications().GetIdentifiedPoints()) + mesh.GetIdentifications().Add( pmap[ get<0>(p1p2)[0] ], pmap[ get<0>(p1p2)[1]] , get<1>(p1p2) ); + for(auto i : Range(m.GetIdentifications().GetMaxNr())) + { + mesh.GetIdentifications().SetType(i+1, m.GetIdentifications().GetType(i+1)); + if(auto name = m.GetIdentifications().GetName(i+1); name != "") + mesh.GetIdentifications().SetName(i+1, name); + } } } @@ -561,7 +598,7 @@ namespace netgen for(auto & m : meshes) { Array pmap(m.Points().Size()); - for(auto pi : Range(PointIndex(PointIndex::BASE), first_new_pi)) + for(auto pi : Range(IndexBASE(), first_new_pi)) pmap[pi] = pi; for (auto pi : Range(first_new_pi, m.Points().Range().Next())) @@ -584,11 +621,17 @@ namespace netgen mesh3d.Compress(); - - if(mesh3d.GetNDomains()==0) return MESHING3_OK; + auto geo = mesh3d.GetGeometry(); + for (auto i : Range(std::min(geo->GetNSolids(), (size_t)mesh3d.GetNDomains()))) + if (auto name = geo->GetSolid(i).properties.name) + mesh3d.SetMaterial (i+1, *name); + + for (auto bl : mp.boundary_layers) + GenerateBoundaryLayer(mesh3d, bl); + if (!mesh3d.HasLocalHFunction()) mesh3d.CalcLocalH(mp.grading); @@ -598,18 +641,26 @@ namespace netgen { ParallelFor( md.Range(), [&](int i) { - if (mp.checkoverlappingboundary) - if (md[i].mesh->CheckOverlappingBoundary()) - { - if(debugparam.write_mesh_on_error) - md[i].mesh->Save("overlapping_mesh_domain_"+ToString(md[i].domain)+".vol.gz"); - throw NgException ("Stop meshing since boundary mesh is overlapping"); - } + try { + if (mp.checkoverlappingboundary) + if (md[i].mesh->CheckOverlappingBoundary()) + { + if(debugparam.write_mesh_on_error) + md[i].mesh->Save("overlapping_mesh_domain_"+ToString(md[i].domain)+".vol.gz"); + throw NgException ("Stop meshing since boundary mesh is overlapping"); + } - if(md[i].mesh->GetGeometry()->GetGeomType() == Mesh::GEOM_OCC) - FillCloseSurface( md[i] ); - CloseOpenQuads( md[i] ); - MeshDomain(md[i]); + if(md[i].mesh->GetGeometry()->GetGeomType() == Mesh::GEOM_OCC) + FillCloseSurface( md[i] ); + CloseOpenQuads( md[i] ); + MeshDomain(md[i]); + } + catch (const Exception & e) { + if(debugparam.write_mesh_on_error) + md[i].mesh->Save("meshing_error_domain_"+ToString(md[i].domain)+".vol.gz"); + cerr << "Meshing of domain " << i+1 << " failed with error: " << e.what() << endl; + throw e; + } }, md.Size()); } catch(...) @@ -631,11 +682,13 @@ namespace netgen // const CSGeometry * geometry) { static Timer t("OptimizeVolume"); RegionTimer reg(t); + #ifndef EMSCRIPTEN RegionTaskManager rtm(mp.parallel_meshing ? mp.nthreads : 0); + #endif // EMSCRIPTEN const char* savetask = multithread.task; multithread.task = "Optimize Volume"; - int i; + // int i; PrintMessage (1, "Volume Optimization"); @@ -651,13 +704,31 @@ namespace netgen */ mesh3d.CalcSurfacesOfNode(); + + MeshOptimize3d optmesh(mesh3d, mp); + + // optimize only bad elements first + optmesh.SetMinBadness(1000.); + bool do_split = mp.optimize3d.find('d') != string::npos; + bool do_swap = mp.optimize3d.find('s') != string::npos; + bool do_swap2 = mp.optimize3d.find('t') != string::npos; + for([[maybe_unused]] auto i : Range(mp.optsteps3d)) + { + auto [total_badness, max_badness, bad_els] = optmesh.UpdateBadness(); + if(bad_els==0) break; + if(do_split) optmesh.SplitImprove(); + if(do_swap) optmesh.SwapImprove(); + if(do_swap2) optmesh.SwapImprove2(); + } + + // Now optimize all elements + optmesh.SetMinBadness(0); + for (auto i : Range(mp.optsteps3d)) { if (multithread.terminate) break; - MeshOptimize3d optmesh(mp); - // teterrpow = mp.opterrpow; // for (size_t j = 1; j <= strlen(mp.optimize3d); j++) for (auto j : Range(mp.optimize3d.size())) @@ -668,12 +739,16 @@ namespace netgen switch (mp.optimize3d[j]) { - case 'c': optmesh.CombineImprove(mesh3d, OPT_REST); break; - case 'd': optmesh.SplitImprove(mesh3d); break; - case 'D': optmesh.SplitImprove2(mesh3d); break; - case 's': optmesh.SwapImprove(mesh3d); break; + case 'c': + optmesh.SetGoal(OPT_REST); + optmesh.CombineImprove(); + optmesh.SetGoal(OPT_QUALITY); + break; + case 'd': optmesh.SplitImprove(); break; + case 'D': optmesh.SplitImprove2(); break; + case 's': optmesh.SwapImprove(); break; // case 'u': optmesh.SwapImproveSurface(mesh3d); break; - case 't': optmesh.SwapImprove2(mesh3d); break; + case 't': optmesh.SwapImprove2(); break; #ifdef SOLIDGEOM case 'm': mesh3d.ImproveMesh(*geometry); break; case 'M': mesh3d.ImproveMesh(*geometry); break; @@ -693,16 +768,171 @@ namespace netgen } + void ConformToFreeSegments (Mesh & mesh, int domain) + { + auto geo = mesh.GetGeometry(); + if(!geo) return; + auto n_solids = geo->GetNSolids(); + if(n_solids < domain) return; + if(geo->GetSolid(domain-1).free_edges.Size() == 0) + return; + + Array free_segs; + for (auto segi : Range(mesh.LineSegments())) + if(mesh[segi].domin == domain && mesh[segi].domout == domain) + free_segs.Append(segi); + + auto get_nonconforming = [&] (const auto & p2el) { + Array nonconforming; + + for (auto segi : free_segs) { + auto seg = mesh[segi]; + + auto has_p0 = p2el[seg[0]]; + bool has_both = false; + + for(auto ei : has_p0) { + if(mesh[ei].PNums().Contains(seg[1])) + has_both = true; + } + + if(!has_both) + nonconforming.Append(segi); + } + return nonconforming; + }; + + auto split_segment = [&] (SegmentIndex segi, const auto & p2el) { + auto seg = mesh[segi]; + auto p_new = Center(mesh[seg[0]], mesh[seg[1]]); + double lam[3]; + ElementIndex ei_start = mesh.GetElementOfPoint(p_new, lam, false, domain); + + if(!ei_start.IsValid()) { + PrintMessage(1, "Could not find volume element with new point"); + return; + } + + if(mesh[ei_start].IsDeleted()) + return; + + double max_inside = -1.; + ElementIndex ei_max_inside = ElementIndex::INVALID; + + // search for adjacent volume element, where the new point is "most inside", + // i.e. the minimal barycentric coordinate is maximal + for(auto pi : mesh[ei_start].PNums()) { + for(auto ei1 : p2el[pi]) { + double lam[3]; + + if(mesh[ei1].IsDeleted()) + return; + if(!mesh.PointContainedIn3DElement(p_new, lam, ei1)) + continue; + + double inside = min(min(lam[0], lam[1]), min(lam[2], 1.0-lam[0]-lam[1])); + if(inside > max_inside) { + max_inside = inside; + ei_max_inside = ei1; + } + } + } + + if(max_inside < 1e-4) { + PrintMessage(3, "Could not find volume element with new point inside"); + return; + } + + // split tet into 4 new tests, with new point inside + auto el = mesh[ei_max_inside]; + if(el.GetNP() != 4) { + PrintMessage(3, "Only tet elements are supported to split around free segments"); + return; + } + + if(el.IsDeleted()) { + PrintMessage(3,"Element to split is already deleted"); + return; + } + + auto pi_new = mesh.AddPoint(p_new); + auto seg_new0 = seg; + auto seg_new1 = seg; + seg_new0[1] = pi_new; + seg_new1[0] = pi_new; + + mesh[segi][0] = PointIndex::INVALID; + mesh.AddSegment(seg_new0); + mesh.AddSegment(seg_new1); - void RemoveIllegalElements (Mesh & mesh3d) + int pmap[4][4] = { + {0,1,2,4}, + {1,3,2,4}, + {0,2,3,4}, + {0,3,1,4} + }; + + PointIndex pis[5] = {el[0], el[1], el[2], el[3], pi_new}; + + for (auto i : Range(4)) { + Element el_new; + el_new = el; + for (auto j : Range(4)) + el_new[j] = pis[pmap[i][j]]; + mesh.AddVolumeElement(el_new); + } + mesh[ei_max_inside].Delete(); + }; + + size_t last_num_bad_segs = -1; + for ([[maybe_unused]] auto i : Range(10)) { + auto p2el = mesh.CreatePoint2ElementTable(); + + auto bad_segs = get_nonconforming(p2el); + auto num_bad_segs = bad_segs.Size(); + + if(num_bad_segs == 0) + return; + + PrintMessage(3, "Non-conforming free segments in domain ", domain, ": ", num_bad_segs); + + if(i>=5 || num_bad_segs != last_num_bad_segs) { + for(auto i : bad_segs) + split_segment(i, p2el); + mesh.Compress(); + } + + MeshingParameters dummymp; + MeshOptimize3d optmesh(mesh, dummymp, OPT_CONFORM); + + for ([[maybe_unused]] auto i : Range(3)) { + optmesh.ImproveMesh(); + optmesh.SwapImprove2(true); + optmesh.ImproveMesh(); + optmesh.SwapImprove(); + optmesh.ImproveMesh(); + optmesh.CombineImprove(); + } + last_num_bad_segs = num_bad_segs; + } + + auto p2el = mesh.CreatePoint2ElementTable(); + auto bad_segs = get_nonconforming(p2el); + + if(bad_segs.Size() > 0) { + auto bad_seg = mesh[bad_segs[0]]; + if(debugparam.write_mesh_on_error) + mesh.Save("free_segment_not_conformed_dom_"+ToString(domain)+"_seg_"+ToString(bad_seg[0])+"_"+ToString(bad_seg[1])+".vol.gz"); + throw Exception("Segment not resolved in volume mesh in domain " + ToString(domain)+ ", seg: " + ToString(bad_seg)); + } + } + + + void RemoveIllegalElements (Mesh & mesh3d, int domain) { static Timer t("RemoveIllegalElements"); RegionTimer reg(t); - int it = 10; - int nillegal, oldn; - - PrintMessage (1, "Remove Illegal Elements"); // return, if non-pure tet-mesh /* if (!mesh3d.PureTetMesh()) @@ -710,25 +940,34 @@ namespace netgen */ mesh3d.CalcSurfacesOfNode(); - nillegal = mesh3d.MarkIllegalElements(); + int nillegal = mesh3d.MarkIllegalElements(domain); + if(nillegal) + PrintMessage (1, "Remove Illegal Elements"); + + int oldn = nillegal; + int nillegal_min = nillegal; MeshingParameters dummymp; - MeshOptimize3d optmesh(dummymp); + MeshOptimize3d optmesh(mesh3d, dummymp, OPT_LEGAL); + int it = 10; while (nillegal && (it--) > 0) { if (multithread.terminate) break; PrintMessage (5, nillegal, " illegal tets"); - optmesh.SplitImprove (mesh3d, OPT_LEGAL); + optmesh.SplitImprove (); mesh3d.MarkIllegalElements(); // test - optmesh.SwapImprove (mesh3d, OPT_LEGAL); + optmesh.SwapImprove (); mesh3d.MarkIllegalElements(); // test - optmesh.SwapImprove2 (mesh3d, OPT_LEGAL); + optmesh.SwapImprove2 (); oldn = nillegal; nillegal = mesh3d.MarkIllegalElements(); + nillegal_min = min(nillegal_min, nillegal); + if(nillegal > nillegal_min) + break; if (oldn != nillegal) it = 10; diff --git a/libsrc/meshing/meshfunc.hpp b/libsrc/meshing/meshfunc.hpp index fdbdef4e..8d603212 100644 --- a/libsrc/meshing/meshfunc.hpp +++ b/libsrc/meshing/meshfunc.hpp @@ -7,7 +7,12 @@ /* Date: 26. Jan. 98 */ /**************************************************************************/ +#include +#include "meshing3.hpp" +#include "meshtype.hpp" +namespace netgen +{ /* Functions for mesh-generations strategies */ @@ -25,7 +30,8 @@ DLL_HEADER MESHING3_RESULT MeshVolume (const MeshingParameters & mp, Mesh& mesh3 DLL_HEADER MESHING3_RESULT OptimizeVolume (const MeshingParameters & mp, Mesh& mesh3d); // const CSGeometry * geometry = NULL); -DLL_HEADER void RemoveIllegalElements (Mesh & mesh3d); +DLL_HEADER void RemoveIllegalElements (Mesh & mesh3d, int domain = 0); +DLL_HEADER void ConformToFreeSegments (Mesh & mesh3d, int domain); enum MESHING_STEP { @@ -36,6 +42,6 @@ enum MESHING_STEP { MESHCONST_MESHVOLUME = 5, MESHCONST_OPTVOLUME = 6 }; - +} // namespace netgen #endif diff --git a/libsrc/meshing/meshfunc2d.cpp b/libsrc/meshing/meshfunc2d.cpp index 84f5d399..d3a2542b 100644 --- a/libsrc/meshing/meshfunc2d.cpp +++ b/libsrc/meshing/meshfunc2d.cpp @@ -4,7 +4,7 @@ namespace netgen { - DLL_HEADER void Optimize2d (Mesh & mesh, MeshingParameters & mp) + DLL_HEADER void Optimize2d (Mesh & mesh, MeshingParameters & mp, int faceindex) { static Timer timer("optimize2d"); RegionTimer reg(timer); @@ -33,19 +33,25 @@ namespace netgen optimize_swap_separate_faces = true; } + if(faceindex) + optimize_swap_separate_faces = false; + const char * optstr = mp.optimize2d.c_str(); int optsteps = mp.optsteps2d; + // reset topology + mesh.GetTopology() = MeshTopology(mesh); for (int i = 1; i <= optsteps; i++) for (size_t j = 1; j <= strlen(optstr); j++) { if (multithread.terminate) break; + MeshOptimize2d meshopt(mesh); + meshopt.SetMetricWeight (mp.elsizeweight); + meshopt.SetFaceIndex(faceindex); switch (optstr[j-1]) { case 's': { // topological swap - MeshOptimize2d meshopt(mesh); - meshopt.SetMetricWeight (mp.elsizeweight); if(optimize_swap_separate_faces) { @@ -57,16 +63,12 @@ namespace netgen } else { - meshopt.SetFaceIndex(0); meshopt.EdgeSwapping (0); } break; } case 'S': { // metric swap - MeshOptimize2d meshopt(mesh); - meshopt.SetMetricWeight (mp.elsizeweight); - if(optimize_swap_separate_faces) { for(auto i : Range(1, mesh.GetNFD()+1)) @@ -77,22 +79,17 @@ namespace netgen } else { - meshopt.SetFaceIndex(0); meshopt.EdgeSwapping (1); } break; } case 'm': { - MeshOptimize2d meshopt(mesh); - meshopt.SetMetricWeight (mp.elsizeweight); meshopt.ImproveMesh(mp); break; } case 'c': { - MeshOptimize2d meshopt(mesh); - meshopt.SetMetricWeight (mp.elsizeweight); meshopt.CombineImprove(); break; } diff --git a/libsrc/meshing/meshing.hpp b/libsrc/meshing/meshing.hpp index 52a0dfc2..188447b3 100644 --- a/libsrc/meshing/meshing.hpp +++ b/libsrc/meshing/meshing.hpp @@ -1,37 +1,35 @@ #ifndef FILE_MESHING #define FILE_MESHING - - #include "../include/myadt.hpp" #include "../include/gprim.hpp" #include "../include/linalg.hpp" #include "../include/opti.hpp" - namespace netgen { // extern int printmessage_importance; // class CSGeometry; + using namespace std; class NetgenGeometry; } -#include "msghandler.hpp" -#include "meshtype.hpp" -#include "localh.hpp" -#include "topology.hpp" -#include "meshclass.hpp" -#include "global.hpp" +// #include "msghandler.hpp" +// #include "meshtype.hpp" +// #include "localh.hpp" +// #include "topology.hpp" +// #include "meshclass.hpp" +// #include "global.hpp" - -namespace netgen -{ #include "meshtool.hpp" + #include "ruler2.hpp" #include "adfront2.hpp" + + #include "meshing2.hpp" #include "improve2.hpp" @@ -40,8 +38,6 @@ namespace netgen #include "adfront3.hpp" #include "ruler3.hpp" -#define _INCLUDE_MORE - #include "findip.hpp" #include "findip2.hpp" @@ -50,16 +46,12 @@ namespace netgen #include "curvedelems.hpp" #include "clusters.hpp" - #include "meshfunc.hpp" #include "bisect.hpp" #include "hprefinement.hpp" -#include "boundarylayer.hpp" + #include "specials.hpp" - -} - #include "validate.hpp" #include "basegeom.hpp" #include "surfacegeom.hpp" @@ -67,4 +59,5 @@ namespace netgen #include "paralleltop.hpp" + #endif diff --git a/libsrc/meshing/meshing2.cpp b/libsrc/meshing/meshing2.cpp index deadcd10..96a2fe97 100644 --- a/libsrc/meshing/meshing2.cpp +++ b/libsrc/meshing/meshing2.cpp @@ -1,5 +1,7 @@ #include -#include "meshing.hpp" + +#include "meshing2.hpp" + #include "visual_interface.hpp" namespace netgen @@ -246,8 +248,8 @@ namespace netgen { static Timer timer("surface meshing"); RegionTimer reg(timer); - static int timer1 = NgProfiler::CreateTimer ("surface meshing1"); - static int timer2 = NgProfiler::CreateTimer ("surface meshing2"); + static Timer timer1("surface meshing1"); + static Timer timer2("surface meshing2"); static int timer3 = NgProfiler::CreateTimer ("surface meshing3"); static int ts1 = NgProfiler::CreateTimer ("surface meshing start 1"); @@ -285,7 +287,7 @@ namespace netgen NgArray plainzones; auto loclinesptr = make_shared>(); auto &loclines = *loclinesptr; - int cntelem = 0, trials = 0, nfaces = 0; + int trials = 0, nfaces = 0; int oldnl = 0; UpdateVisSurfaceMeshData(oldnl, locpointsptr, loclinesptr, plainpointsptr); @@ -408,7 +410,7 @@ namespace netgen RegionTimer rloop(tloop); while (!adfront.Empty() && !multithread.terminate) { - NgProfiler::RegionTimer reg1 (timer1); + // RegionTimer reg1 (timer1); if (multithread.terminate) throw NgException ("Meshing stopped"); @@ -487,8 +489,7 @@ namespace netgen pindex, lindex, 2*hinner); // tgetlocals.Stop(); - NgProfiler::RegionTimer reg2 (timer2); - + // RegionTimer reg2 (timer2); //(*testout) << "h for locals: " << 2*hinner << endl; @@ -541,8 +542,8 @@ namespace netgen // problem recognition ! if (found && - (gpi1 < illegalpoint.Size()+PointIndex::BASE) && - (gpi2 < illegalpoint.Size()+PointIndex::BASE) ) + (gpi1 < illegalpoint.Size()+IndexBASE()) && + (gpi2 < illegalpoint.Size()+IndexBASE()) ) { if (illegalpoint[gpi1] || illegalpoint[gpi2]) found = 0; @@ -557,7 +558,7 @@ namespace netgen oldnl = loclines.Size(); UpdateVisSurfaceMeshData(oldnl); - + if (debugflag) (*testout) << "define new transformation" << endl; @@ -574,15 +575,16 @@ namespace netgen *testout << "3d points: " << endl << locpoints << endl; } - - for (size_t i = 0; i < locpoints.Size(); i++) - { - Point<2> pp; - TransformToPlain (locpoints[i], mpgeominfo[i], - pp, h, plainzones[i]); - plainpoints[i] = pp; - } - + { + // RegionTimer reg2 (timer2); + for (size_t i = 0; i < locpoints.Size(); i++) + { + Point<2> pp; + TransformToPlain (locpoints[i], mpgeominfo[i], + pp, h, plainzones[i]); + plainpoints[i] = pp; + } + } /* for (int i = 1; i <= locpoints.Size(); i++) { @@ -633,7 +635,6 @@ namespace netgen // plainpoints.Elem(i) = Point2d (1e4, 1e4); */ - for (int i = 2; i <= loclines.Size(); i++) // don't remove first line { @@ -858,7 +859,8 @@ namespace netgen const Element2d & el = locelements.Get(i); for (int j = 1; j <= el.GetNP(); j++) - if (el.PNum(j) <= oldnp && pindex.Get(el.PNum(j)) == -1) + // if (el.PNum(j) <= oldnp && pindex.Get(el.PNum(j)) == -1) + if (el.PNum(j) < IndexBASE()+oldnp && pindex.Get(el.PNum(j)) == -1) { found = 0; PrintSysError ("meshing2, index missing"); @@ -1379,7 +1381,7 @@ namespace netgen mesh.AddSurfaceElement (mtri); - cntelem++; + // cntelem++; // cout << "elements: " << cntelem << endl; diff --git a/libsrc/meshing/meshing2.hpp b/libsrc/meshing/meshing2.hpp index 2af29296..1cf07222 100644 --- a/libsrc/meshing/meshing2.hpp +++ b/libsrc/meshing/meshing2.hpp @@ -1,5 +1,5 @@ -#ifndef FILE_MESHING2 -#define FILE_MESHING2 +#ifndef NETGEN_MESHING2_HPP +#define NETGEN_MESHING2_HPP /**************************************************************************/ /* File: meshing2.hpp */ @@ -8,6 +8,13 @@ /**************************************************************************/ +#include "adfront2.hpp" +#include "ruler2.hpp" +#include "basegeom.hpp" + +namespace netgen +{ + enum MESHING2_RESULT { @@ -151,19 +158,6 @@ protected: }; +} // namespace netgen - - - - - - - -#endif - - - - - - - +#endif // NETGEN_MESHING2_HPP diff --git a/libsrc/meshing/meshing3.cpp b/libsrc/meshing/meshing3.cpp index 2d5436f3..c83424d4 100644 --- a/libsrc/meshing/meshing3.cpp +++ b/libsrc/meshing/meshing3.cpp @@ -1,5 +1,8 @@ #include -#include "meshing.hpp" + +#include "meshing3.hpp" +#include "findip.hpp" +#include "findip2.hpp" namespace netgen { @@ -9,8 +12,6 @@ double minwithoutother; - - MeshingStat3d :: MeshingStat3d () { cntsucc = cnttrials = cntelem = qualclass = 0; @@ -24,13 +25,14 @@ Meshing3 :: Meshing3 (const string & rulefilename) tolfak = 1; LoadRules (rulefilename.c_str(), NULL); - adfront = new AdFront3; + adfront = make_unique(); problems.SetSize (rules.Size()); foundmap.SetSize (rules.Size()); canuse.SetSize (rules.Size()); ruleused.SetSize (rules.Size()); + /* for (int i = 1; i <= rules.Size(); i++) { problems.Elem(i) = new char[255]; @@ -38,6 +40,11 @@ Meshing3 :: Meshing3 (const string & rulefilename) canuse.Elem(i) = 0; ruleused.Elem(i) = 0; } + */ + + foundmap = 0; + canuse = 0; + ruleused = 0; } @@ -46,13 +53,14 @@ Meshing3 :: Meshing3 (const char ** rulep) tolfak = 1; LoadRules (NULL, rulep); - adfront = new AdFront3; + adfront = make_unique(); problems.SetSize (rules.Size()); foundmap.SetSize (rules.Size()); canuse.SetSize (rules.Size()); ruleused.SetSize (rules.Size()); + /* for (int i = 0; i < rules.Size(); i++) { problems[i] = new char[255]; @@ -60,16 +68,22 @@ Meshing3 :: Meshing3 (const char ** rulep) canuse[i] = 0; ruleused[i] = 0; } + */ + foundmap = 0; + canuse = 0; + ruleused = 0; } Meshing3 :: ~Meshing3 () { - delete adfront; + // delete adfront; + /* for (int i = 0; i < rules.Size(); i++) { delete [] problems[i]; delete rules[i]; } + */ } @@ -181,21 +195,21 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) // NgProfiler::RegionTimer reg (meshing3_timer); - NgArray locpoints; // local points - NgArray locfaces; // local faces - NgArray pindex; // mapping from local to front point numbering - NgArray allowpoint; // point is allowed ? - NgArray findex; // mapping from local to front face numbering + Array locpoints; // local points + Array locfaces; // local faces + Array pindex; // mapping from local to front point numbering + Array allowpoint; // point is allowed (0/1/2) ? + Array findex; // mapping from local to front face numbering //INDEX_2_HASHTABLE connectedpairs(100); // connecgted pairs for prism meshing - NgArray plainpoints; // points in reference coordinates - NgArray delpoints, delfaces; // points and lines to be deleted + Array plainpoints; // points in reference coordinates + // NgArray delpoints; // points to be deleted + NgArray delfaces; // lines to be deleted NgArray locelements; // new generated elements int j, oldnp, oldnf; int found; referencetransform trans; - int rotind; Point3d inp; float err; @@ -211,15 +225,15 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) // for star-shaped domain meshing - NgArray grouppoints; - NgArray groupfaces; - NgArray grouppindex; - NgArray groupfindex; + Array grouppoints; + Array groupfaces; + Array grouppindex; + Array groupfindex; float minerr; int hasfound; - double tetvol; + [[maybe_unused]] double tetvol; // int giveup = 0; @@ -313,7 +327,7 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) if (loktestmode) { - (*testout) << "baseel = " << baseelem << ", ind = " << findex.Get(1) << endl; + (*testout) << "baseel = " << baseelem << ", ind = " << findex[0] << endl; int pi1 = pindex[locfaces[0].PNum(1)]; int pi2 = pindex[locfaces[0].PNum(2)]; int pi3 = pindex[locfaces[0].PNum(3)]; @@ -342,10 +356,11 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) allowpoint.SetSize(locpoints.Size()); if (uselocalh && stat.qualclass <= 3) - for(int i = 1; i <= allowpoint.Size(); i++) + //for(int i = 1; i <= allowpoint.Size(); i++) + for(auto i : allowpoint.Range()) { - allowpoint.Elem(i) = - (mesh.GetH (locpoints.Get(i)) > 0.4 * hshould / mp.sloppy) ? 2 : 1; + allowpoint[i] = + (mesh.GetH (locpoints[i]) > 0.4 * hshould / mp.sloppy) ? 2 : 1; } else allowpoint = 2; @@ -367,40 +382,41 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) grouppindex, groupfindex); bool onlytri = 1; - for (auto i : groupfaces.Range()) - if (groupfaces[i].GetNP() != 3) - onlytri = 0; - + for (auto & f : groupfaces) + if (f.GetNP() != 3) + onlytri = 0; + + if (onlytri && groupfaces.Size() <= 20 + 2*stat.qualclass && - FindInnerPoint (grouppoints, groupfaces, inp)) + FindInnerPoint (grouppoints, groupfaces, inp) && + !adfront->PointInsideGroup(grouppindex, groupfaces)) { (*testout) << "inner point found" << endl; - for(int i = 1; i <= groupfaces.Size(); i++) - adfront -> DeleteFace (groupfindex.Get(i)); - + for(int i = 0; i < groupfaces.Size(); i++) + adfront -> DeleteFace (groupfindex[i]); + for(int i = 1; i <= groupfaces.Size(); i++) for (j = 1; j <= locfaces.Size(); j++) - if (findex.Get(j) == groupfindex.Get(i)) + if (findex[j-1] == groupfindex[i-1]) delfaces.Append (j); delfaces.SetSize (0); - INDEX npi; Element newel(TET); - npi = mesh.AddPoint (inp); + PointIndex npi = mesh.AddPoint (inp); newel.SetNP(4); newel.PNum(4) = npi; - for(int i = 1; i <= groupfaces.Size(); i++) + for(int i = 0; i < groupfaces.Size(); i++) { for (j = 1; j <= 3; j++) { newel.PNum(j) = adfront->GetGlobalIndex - (grouppindex.Get(groupfaces.Get(i).PNum(j))); + (grouppindex[groupfaces[i].PNum(j)]); } mesh.AddVolumeElement (newel); } @@ -435,7 +451,7 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) bool impossible = 1; - for (rotind = 1; rotind <= locfaces[0].GetNP(); rotind++) + for (int rotind = 1; rotind <= locfaces[0].GetNP(); rotind++) { // set transformatino to reference coordinates @@ -468,12 +484,12 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) if (stat.cnttrials % 100 == 0) { (*testout) << "\n"; - for(int i = 1; i <= canuse.Size(); i++) - { - (*testout) << foundmap.Get(i) << "/" - << canuse.Get(i) << "/" - << ruleused.Get(i) << " map/can/use rule " << rules.Get(i)->Name() << "\n"; - } + for(int i : canuse.Range()) + { + (*testout) << foundmap[i] << "/" + << canuse[i] << "/" + << ruleused[i] << " map/can/use rule " << rules[i]->Name() << "\n"; + } (*testout) << endl; } @@ -504,9 +520,13 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) if (found) stat.cntsucc++; locpoints.SetSize (plainpoints.Size()); + /* for (int i = oldnp+1; i <= plainpoints.Size(); i++) trans.FromPlain (plainpoints.Elem(i), locpoints.Elem(i)); - + */ + for (auto i : plainpoints.Range().Modify(oldnp,0)) + trans.FromPlain (plainpoints[i], locpoints[i]); + // avoid meshing from large to small mesh-size @@ -540,8 +560,8 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) if (found) - ruleused.Elem(found)++; - + ruleused[found-1]++; + // plotstat->Plot(stat); @@ -564,14 +584,15 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) if (testmode) { (*testout) << "found is active, 3" << endl; - for(int i = 1; i <= plainpoints.Size(); i++) + //for(int i = 1; i <= plainpoints.Size(); i++) + for(auto i : plainpoints.Range()) { (*testout) << "p"; - if (i <= pindex.Size()) - (*testout) << pindex.Get(i) << ": "; + if (i < pindex.Range().Next()) + (*testout) << pindex[i] << ": "; else (*testout) << "new: "; - (*testout) << plainpoints.Get(i) << endl; + (*testout) << plainpoints[i] << endl; } } @@ -581,20 +602,24 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) minerr = err; tempnewpoints.SetSize (0); - for(int i = oldnp+1; i <= locpoints.Size(); i++) - tempnewpoints.Append (locpoints.Get(i)); + // for(int i = oldnp+1; i <= locpoints.Size(); i++) + for (auto i : locpoints.Range().Modify(oldnp,0)) + tempnewpoints.Append (locpoints[i]); tempnewfaces.SetSize (0); - for(int i = oldnf+1; i <= locfaces.Size(); i++) - tempnewfaces.Append (locfaces.Get(i)); + // for(int i = oldnf+1; i <= locfaces.Size(); i++) + for (auto i : locfaces.Range().Modify(oldnf,0)) + tempnewfaces.Append (locfaces[i]); tempdelfaces.SetSize (0); - for(int i = 1; i <= delfaces.Size(); i++) - tempdelfaces.Append (delfaces.Get(i)); + // for(int i = 1; i <= delfaces.Size(); i++) + for (auto i : delfaces.Range()) + tempdelfaces.Append (delfaces[i]); templocelements.SetSize (0); - for(int i = 1; i <= locelements.Size(); i++) - templocelements.Append (locelements.Get(i)); + // for(int i = 1; i <= locelements.Size(); i++) + for (auto i : locelements.Range()) + templocelements.Append (locelements[i]); /* optother = @@ -636,14 +661,14 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) if (loktestmode) { (*testout) << "apply rule" << endl; - for(int i = 1; i <= locpoints.Size(); i++) + for (auto i : locpoints.Range()) { (*testout) << "p"; - if (i <= pindex.Size()) - (*testout) << pindex.Get(i) << ": "; + if (pindex.Range().Contains(i)) + (*testout) << pindex[i] << ": "; else (*testout) << "new: "; - (*testout) << locpoints.Get(i) << endl; + (*testout) << locpoints[i] << endl; } } @@ -651,10 +676,11 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) pindex.SetSize(locpoints.Size()); - for (int i = oldnp+1; i <= locpoints.Size(); i++) + // for (int i = oldnp+1; i <= locpoints.Size(); i++) + for (auto i : locpoints.Range().Modify(oldnp,0)) { - PointIndex globind = mesh.AddPoint (locpoints.Get(i)); - pindex.Elem(i) = adfront -> AddPoint (locpoints.Get(i), globind); + PointIndex globind = mesh.AddPoint (locpoints[i]); + pindex[i] = adfront -> AddPoint (locpoints[i], globind); } for (int i = 1; i <= locelements.Size(); i++) @@ -675,31 +701,31 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) stat.cntelem++; } - for(int i = oldnf+1; i <= locfaces.Size(); i++) + for(int i = oldnf; i < locfaces.Size(); i++) { - for (j = 1; j <= locfaces.Get(i).GetNP(); j++) - locfaces.Elem(i).PNum(j) = - pindex[locfaces.Get(i).PNum(j)]; + for (j = 1; j <= locfaces[i].GetNP(); j++) + locfaces[i].PNum(j) = + pindex[locfaces[i].PNum(j)]; // (*testout) << "add face " << locfaces.Get(i) << endl; - adfront->AddFace (locfaces.Get(i)); + adfront->AddFace (locfaces[i]); } for(int i = 1; i <= delfaces.Size(); i++) - adfront->DeleteFace (findex.Get(delfaces.Get(i))); + adfront->DeleteFace (findex[delfaces.Get(i)-1]); } else { - adfront->IncrementClass (findex.Get(1)); + adfront->IncrementClass (findex[0]); if (impossible && mp.check_impossible) { (*testout) << "skip face since it is impossible" << endl; for (j = 0; j < 100; j++) - adfront->IncrementClass (findex.Get(1)); + adfront->IncrementClass (findex[0]); } } locelements.SetSize (0); - delpoints.SetSize(0); + // delpoints.SetSize(0); delfaces.SetSize(0); if (stat.qualclass >= mp.giveuptol) @@ -708,9 +734,9 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp) PrintMessage (5, ""); // line feed after statistics - for(int i = 1; i <= ruleused.Size(); i++) - (*testout) << setw(4) << ruleused.Get(i) - << " times used rule " << rules.Get(i) -> Name() << endl; + for(int i : ruleused.Range()) + (*testout) << setw(4) << ruleused[i] + << " times used rule " << rules[i] -> Name() << endl; if (!mp.baseelnp && adfront->Empty()) @@ -926,7 +952,7 @@ void Meshing3 :: BlockFill (Mesh & mesh, double gh) for(int i = 1; i <= n; i++) { - pointnr.Elem(i) = 0; + pointnr.Elem(i) = PointIndex::INVALID; frontpointnr.Elem(i) = 0; } @@ -942,7 +968,7 @@ void Meshing3 :: BlockFill (Mesh & mesh, double gh) for (j3 = i3; j3 <= i3+1; j3++) { j = j3 + (j2-1) * n3 + (j1-1) * n2 * n3; - if (pointnr.Get(j) == 0) + if (!pointnr.Get(j).IsValid()) { Point3d hp(xmin + (j1-1) * gh, ymin + (j2-1) * gh, @@ -1173,7 +1199,7 @@ void Meshing3 :: BlockFillLocalH (Mesh & mesh, tbox.Stop(); // locadfront = adfront; - loch.FindInnerBoxes (adfront, NULL); + loch.FindInnerBoxes (*adfront, NULL); npoints.SetSize(0); loch.GetInnerPoints (npoints); @@ -1259,7 +1285,7 @@ void Meshing3 :: BlockFillLocalH (Mesh & mesh, tloch2.Stop(); // locadfront = adfront; - loch2.FindInnerBoxes (adfront, NULL); + loch2.FindInnerBoxes (*adfront, NULL); npoints.SetSize(0); loch2.GetOuterPoints (npoints); diff --git a/libsrc/meshing/meshing3.hpp b/libsrc/meshing/meshing3.hpp index 65b153b9..a4659547 100644 --- a/libsrc/meshing/meshing3.hpp +++ b/libsrc/meshing/meshing3.hpp @@ -1,8 +1,12 @@ #ifndef FILE_MESHING3 #define FILE_MESHING3 +#include "meshclass.hpp" +#include "adfront3.hpp" +#include "ruler3.hpp" - +namespace netgen +{ enum MESHING3_RESULT { @@ -19,13 +23,13 @@ enum MESHING3_RESULT class Meshing3 { /// current state of front - AdFront3 * adfront; + unique_ptr adfront; /// 3d generation rules - NgArray rules; + Array> rules; /// counts how often a rule is used - NgArray ruleused, canuse, foundmap; + Array ruleused, canuse, foundmap; /// describes, why a rule is not applied - NgArray problems; + Array problems; /// tolerance criterion double tolfak; public: @@ -42,9 +46,9 @@ public: MESHING3_RESULT GenerateMesh (Mesh & mesh, const MeshingParameters & mp); /// - int ApplyRules (NgArray & lpoints, - NgArray & allowpoint, - NgArray & lfaces, INDEX lfacesplit, + int ApplyRules (Array & lpoints, + Array & allowpoint, + Array & lfaces, INDEX lfacesplit, INDEX_2_HASHTABLE & connectedpairs, NgArray & elements, NgArray & delfaces, int tolerance, @@ -114,18 +118,6 @@ extern int FindInnerPoint (POINTArray & grouppoints, */ - - - +} // namespace netgen #endif - - - - - - - - - - diff --git a/libsrc/meshing/meshtool.hpp b/libsrc/meshing/meshtool.hpp index 4bfac0e3..10474208 100644 --- a/libsrc/meshing/meshtool.hpp +++ b/libsrc/meshing/meshtool.hpp @@ -1,7 +1,14 @@ -#ifndef FILE_MESHTOOL -#define FILE_MESHTOOL +#ifndef NETGEN_MESHTOOL_HPP +#define NETGEN_MESHTOOL_HPP +// #include "../general/ngarray.hpp" +// #include "../gprim/geom3d.hpp" +// #include "../gprim/geomobjects.hpp" +#include "meshtype.hpp" +#include "meshclass.hpp" + +namespace netgen { /// extern void MeshQuality2d (const Mesh & mesh); @@ -78,4 +85,6 @@ extern int CheckSurfaceMesh2 (const Mesh & mesh); extern int CheckMesh3D (const Mesh & mesh); /// extern void RemoveProblem (Mesh & mesh, int domainnr); -#endif + +} // namespace netgen +#endif // NETGEN_MESHTOOL_HPP diff --git a/libsrc/meshing/meshtype.cpp b/libsrc/meshing/meshtype.cpp index 068c1ed8..839c2bdb 100644 --- a/libsrc/meshing/meshtype.cpp +++ b/libsrc/meshing/meshtype.cpp @@ -18,125 +18,125 @@ namespace netgen #ifdef PARALLEL - MPI_Datatype MeshPoint :: MyGetMPIType ( ) + NG_MPI_Datatype MeshPoint :: MyGetMPIType ( ) { - static MPI_Datatype type = MPI_DATATYPE_NULL; - static MPI_Datatype htype = MPI_DATATYPE_NULL; - if (type == MPI_DATATYPE_NULL) + static NG_MPI_Datatype type = NG_MPI_DATATYPE_NULL; + static NG_MPI_Datatype htype = NG_MPI_DATATYPE_NULL; + if (type == NG_MPI_DATATYPE_NULL) { MeshPoint hp; int blocklen[] = { 3, 1, 1 }; - MPI_Aint displ[] = { (char*)&hp.x[0] - (char*)&hp, + NG_MPI_Aint displ[] = { (char*)&hp.x[0] - (char*)&hp, (char*)&hp.layer - (char*)&hp, (char*)&hp.singular - (char*)&hp }; - MPI_Datatype types[] = { MPI_DOUBLE, MPI_INT, MPI_DOUBLE }; + NG_MPI_Datatype types[] = { NG_MPI_DOUBLE, NG_MPI_INT, NG_MPI_DOUBLE }; // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; // *testout << "sizeof = " << sizeof (MeshPoint) << endl; - MPI_Type_create_struct (3, blocklen, displ, types, &htype); - MPI_Type_commit ( &htype ); - MPI_Aint lb, ext; - MPI_Type_get_extent (htype, &lb, &ext); + NG_MPI_Type_create_struct (3, blocklen, displ, types, &htype); + NG_MPI_Type_commit ( &htype ); + NG_MPI_Aint lb, ext; + NG_MPI_Type_get_extent (htype, &lb, &ext); // *testout << "lb = " << lb << endl; // *testout << "ext = " << ext << endl; ext = sizeof (MeshPoint); - MPI_Type_create_resized (htype, lb, ext, &type); - MPI_Type_commit ( &type ); + NG_MPI_Type_create_resized (htype, lb, ext, &type); + NG_MPI_Type_commit ( &type ); } return type; } - MPI_Datatype Element2d :: MyGetMPIType ( ) + NG_MPI_Datatype Element2d :: MyGetMPIType ( ) { - static MPI_Datatype type = MPI_DATATYPE_NULL; - static MPI_Datatype htype = MPI_DATATYPE_NULL; - if (type == MPI_DATATYPE_NULL) + static NG_MPI_Datatype type = NG_MPI_DATATYPE_NULL; + static NG_MPI_Datatype htype = NG_MPI_DATATYPE_NULL; + if (type == NG_MPI_DATATYPE_NULL) { Element2d hel; int blocklen[] = { ELEMENT2D_MAXPOINTS, 1, 1, 1 }; - MPI_Aint displ[] = + NG_MPI_Aint displ[] = { (char*)&hel.pnum[0] - (char*)&hel, (char*)&hel.index - (char*)&hel, (char*)&hel.typ - (char*)&hel, (char*)&hel.np - (char*)&hel }; - MPI_Datatype types[] = { GetMPIType(), GetMPIType(hel.index), + NG_MPI_Datatype types[] = { GetMPIType(), GetMPIType(hel.index), GetMPIType(hel.typ), GetMPIType(hel.np) }; // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; // *testout << "sizeof = " << sizeof (MeshPoint) << endl; - MPI_Type_create_struct (4, blocklen, displ, types, &htype); - MPI_Type_commit ( &htype ); - MPI_Aint lb, ext; - MPI_Type_get_extent (htype, &lb, &ext); + NG_MPI_Type_create_struct (4, blocklen, displ, types, &htype); + NG_MPI_Type_commit ( &htype ); + NG_MPI_Aint lb, ext; + NG_MPI_Type_get_extent (htype, &lb, &ext); // *testout << "lb = " << lb << endl; // *testout << "ext = " << ext << endl; ext = sizeof (Element2d); - MPI_Type_create_resized (htype, lb, ext, &type); - MPI_Type_commit ( &type ); + NG_MPI_Type_create_resized (htype, lb, ext, &type); + NG_MPI_Type_commit ( &type ); } return type; } - MPI_Datatype Element :: MyGetMPIType ( ) + NG_MPI_Datatype Element :: MyGetMPIType ( ) { - static MPI_Datatype type = MPI_DATATYPE_NULL; - static MPI_Datatype htype = MPI_DATATYPE_NULL; - if (type == MPI_DATATYPE_NULL) + static NG_MPI_Datatype type = NG_MPI_DATATYPE_NULL; + static NG_MPI_Datatype htype = NG_MPI_DATATYPE_NULL; + if (type == NG_MPI_DATATYPE_NULL) { Element hel; int blocklen[] = { ELEMENT_MAXPOINTS, 1, 1, 1 }; - MPI_Aint displ[] = + NG_MPI_Aint displ[] = { (char*)&hel.pnum[0] - (char*)&hel, (char*)&hel.index - (char*)&hel, (char*)&hel.typ - (char*)&hel, (char*)&hel.np - (char*)&hel }; - MPI_Datatype types[] = { GetMPIType(), GetMPIType(hel.index), + NG_MPI_Datatype types[] = { GetMPIType(), GetMPIType(hel.index), GetMPIType(hel.typ), GetMPIType(hel.np) }; // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; // *testout << "sizeof = " << sizeof (MeshPoint) << endl; - MPI_Type_create_struct (4, blocklen, displ, types, &htype); - MPI_Type_commit ( &htype ); - MPI_Aint lb, ext; - MPI_Type_get_extent (htype, &lb, &ext); + NG_MPI_Type_create_struct (4, blocklen, displ, types, &htype); + NG_MPI_Type_commit ( &htype ); + NG_MPI_Aint lb, ext; + NG_MPI_Type_get_extent (htype, &lb, &ext); // *testout << "lb = " << lb << endl; // *testout << "ext = " << ext << endl; ext = sizeof (Element); - MPI_Type_create_resized (htype, lb, ext, &type); - MPI_Type_commit ( &type ); + NG_MPI_Type_create_resized (htype, lb, ext, &type); + NG_MPI_Type_commit ( &type ); } return type; } - MPI_Datatype Segment :: MyGetMPIType ( ) + NG_MPI_Datatype Segment :: MyGetMPIType ( ) { - static MPI_Datatype type = MPI_DATATYPE_NULL; - static MPI_Datatype htype = MPI_DATATYPE_NULL; - if (type == MPI_DATATYPE_NULL) + static NG_MPI_Datatype type = NG_MPI_DATATYPE_NULL; + static NG_MPI_Datatype htype = NG_MPI_DATATYPE_NULL; + if (type == NG_MPI_DATATYPE_NULL) { Segment hel; int blocklen[] = { 3, 1, 1, 1 }; - MPI_Aint displ[] = + NG_MPI_Aint displ[] = { (char*)&hel.pnums[0] - (char*)&hel, (char*)&hel.edgenr - (char*)&hel, (char*)&hel.cd2i - (char*)&hel, (char*)&hel.si - (char*)&hel }; - MPI_Datatype types[] = { + NG_MPI_Datatype types[] = { GetMPIType(), GetMPIType(hel.edgenr), GetMPIType(hel.cd2i), GetMPIType(hel.si) }; // *testout << "displ = " << displ[0] << ", " << displ[1] << ", " << displ[2] << endl; // *testout << "sizeof = " << sizeof (MeshPoint) << endl; - MPI_Type_create_struct (4, blocklen, displ, types, &htype); - MPI_Type_commit ( &htype ); - MPI_Aint lb, ext; - MPI_Type_get_extent (htype, &lb, &ext); + NG_MPI_Type_create_struct (4, blocklen, displ, types, &htype); + NG_MPI_Type_commit ( &htype ); + NG_MPI_Aint lb, ext; + NG_MPI_Type_get_extent (htype, &lb, &ext); // *testout << "lb = " << lb << endl; // *testout << "ext = " << ext << endl; ext = sizeof (Segment); - MPI_Type_create_resized (htype, lb, ext, &type); - MPI_Type_commit ( &type ); + NG_MPI_Type_create_resized (htype, lb, ext, &type); + NG_MPI_Type_commit ( &type ); } return type; } @@ -144,7 +144,40 @@ namespace netgen #endif +#ifdef PARALLEL + NG_MPI_Datatype Element0d :: MyGetMPIType() + { + static NG_MPI_Datatype type = NG_MPI_DATATYPE_NULL; + static NG_MPI_Datatype htype = NG_MPI_DATATYPE_NULL; + if (type == NG_MPI_DATATYPE_NULL) + { + Element0d hel; + int blocklen[] = { 1, 1 }; + NG_MPI_Aint displ[] = + { (char*)&hel.pnum - (char*)&hel, + (char*)&hel.index - (char*)&hel, + }; + NG_MPI_Datatype types[] = { + GetMPIType(hel.pnum), GetMPIType(hel.index) + }; + NG_MPI_Type_create_struct (2, blocklen, displ, types, &htype); + NG_MPI_Type_commit ( &htype ); + NG_MPI_Aint lb, ext; + NG_MPI_Type_get_extent (htype, &lb, &ext); + // *testout << "lb = " << lb << endl; + // *testout << "ext = " << ext << endl; + ext = sizeof (Element0d); + NG_MPI_Type_create_resized (htype, lb, ext, &type); + NG_MPI_Type_commit ( &type ); + } + return type; + } +#endif + void Element0d :: DoArchive (Archive & ar) + { + ar & pnum & index; + } Segment :: Segment() : is_curved(false) @@ -204,7 +237,7 @@ namespace netgen { for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++) { - pnum[i] = 0; + pnum[i].Invalidate(); geominfo[i].trignum = 0; } np = 3; @@ -216,7 +249,7 @@ namespace netgen orderx = ordery = 1; refflag = 1; strongrefflag = false; - is_curved = false; + is_curved = 0; } Element2d :: Element2d (int anp) @@ -266,7 +299,7 @@ namespace netgen - Element2d :: Element2d (int pi1, int pi2, int pi3) + Element2d :: Element2d (PointIndex pi1, PointIndex pi2, PointIndex pi3) { pnum[0] = pi1; pnum[1] = pi2; @@ -289,7 +322,7 @@ namespace netgen is_curved = false; } - Element2d :: Element2d (int pi1, int pi2, int pi3, int pi4) + Element2d :: Element2d (PointIndex pi1, PointIndex pi2, PointIndex pi3, PointIndex pi4) { pnum[0] = pi1; pnum[1] = pi2; @@ -298,8 +331,8 @@ namespace netgen np = 4; typ = QUAD; - pnum[4] = 0; - pnum[5] = 0; + pnum[4].Invalidate(); + pnum[5].Invalidate(); for (int i = 0; i < ELEMENT2D_MAXPOINTS; i++) geominfo[i].trignum = 0; @@ -1005,7 +1038,7 @@ namespace netgen { s << "np = " << el.GetNP(); for (int j = 0; j < el.GetNP(); j++) - s << " " << int(el[j]); + s << " " << el[j]; return s; } @@ -1057,6 +1090,7 @@ namespace netgen case 4: typ = TET; break; case 5: typ = PYRAMID; break; case 6: typ = PRISM; break; + case 7: typ = HEX7; break; case 8: typ = HEX; break; case 10: typ = TET10; break; case 13: typ = PYRAMID13; break; @@ -1139,6 +1173,7 @@ namespace netgen case 4: typ = TET; break; case 5: typ = PYRAMID; break; case 6: typ = PRISM; break; + case 7: typ = HEX7; break; case 8: typ = HEX; break; case 10: typ = TET10; break; case 13: typ = PYRAMID13; break; @@ -1160,6 +1195,7 @@ namespace netgen case TET: np = 4; break; case PYRAMID: np = 5; break; case PRISM: np = 6; break; + case HEX7: np = 7; break; case HEX: np = 8; break; case TET10: np = 10; break; case PYRAMID13: np = 13; break; @@ -1256,6 +1292,16 @@ namespace netgen { 4, 3, 1, 4, 6 } }; + static const int hex7faces[][5] = + { + { 4, 4, 3, 2, 1 }, + { 4, 3, 7, 6, 2 }, + { 3, 7, 5, 6 }, + { 4, 7, 4, 1, 5 }, + { 4, 1, 2, 6, 5 }, + { 3, 3, 4, 7 } + }; + static const int hexfaces[][5] = { { 4, 4, 3, 2, 1 }, @@ -1265,7 +1311,6 @@ namespace netgen { 4, 1, 2, 6, 5 }, { 4, 3, 4, 8, 7 } }; - switch (np) { @@ -1301,6 +1346,14 @@ namespace netgen face.PNum(j) = PNum(prismfaces[i-1][j]); break; } + case 7: // hex7 + { + // face.SetNP(prismfaces[i-1][0]); + face.SetType ( ((i == 3) || (i==6)) ? TRIG : QUAD); + for (int j = 1; j <= face.GetNP(); j++) + face.PNum(j) = PNum(hex7faces[i-1][j]); + break; + } case 8: { face.SetType(QUAD); @@ -1684,6 +1737,20 @@ namespace netgen { 6, 1, 4 } }; + static int hex7trigs[][3] = + { + { 1, 3, 2 }, + { 1, 4, 3 }, + { 5, 6, 7 }, + { 1, 2, 6 }, + { 1, 6, 5 }, + { 2, 3, 7 }, + { 2, 7, 6 }, + { 3, 4, 7 }, + { 4, 1, 7 }, + { 1, 5, 7 } + }; + static int hextrigs[][3] = { { 1, 3, 2 }, @@ -1700,6 +1767,8 @@ namespace netgen { 1, 5, 8 } }; + + int j; int nf; @@ -1732,6 +1801,12 @@ namespace netgen fp = tet10trigs; break; } + case HEX7: + { + nf = 10; + fp = hex7trigs; + break; + } case HEX: { nf = 12; @@ -2046,6 +2121,26 @@ namespace netgen shape[14] = 4 * y * lam * (2*z*z-z); break; } + case HEX7: + { + T y = p(1); + T z = p(2); + // T den = (1-y)*(1-z); + T den = (1-y*z); + den += T(1e-12); + + T x = p(0) / den; + + shape(0) = (1-x)*(1-y)*(1-z); + shape(1) = ( x)*(1-y)*(1-z); + shape(2) = ( x)*( y)*(1-z); + shape(3) = (1-x)*( y)*(1-z); + shape(4) = (1-x)*(1-y)*( z); + shape(5) = ( x)*(1-y)*( z); + shape(6) = ( y)*( z); + break; + } + case HEX: { shape(0) = (1-p(0))*(1-p(1))*(1-p(2)); @@ -2168,6 +2263,7 @@ namespace netgen default: { + /* int np = GetNP(); double eps = 1e-6; NgArrayMem mem(2*np); @@ -2186,6 +2282,18 @@ namespace netgen for (int j = 0; j < np; j++) dshape(j, i) = (shaper(j) - shapel(j)) / (2 * eps); } + */ + + AutoDiff<3,T> adx(p(0), 0); + AutoDiff<3,T> ady(p(1), 1); + AutoDiff<3,T> adz(p(2), 2); + Point<3,AutoDiff<3,T>> adp{adx, ady, adz}; + NgArrayMem,100> mem(np); + TFlatVector> adshape(np, &mem[0]); + GetShapeNew (adp, adshape); + for (int j = 0; j < np; j++) + for (int k = 0; k < 3; k++) + dshape(j,k) = adshape(j).DValue(k); } } } @@ -2586,6 +2694,7 @@ namespace netgen { identifiedpoints.DeleteData(); identifiedpoints_nr.DeleteData(); + idpoints_table.SetSize(0); /* delete identifiedpoints; @@ -2600,8 +2709,8 @@ namespace netgen { ar & maxidentnr; ar & identifiedpoints & identifiedpoints_nr; - ar & idpoints_table; + if (ar.Output()) { size_t s = type.Size(); @@ -2617,6 +2726,8 @@ namespace netgen for (auto & t : type) ar & (unsigned char&)(t); } + if (ar.GetVersion("netgen") > "v6.2.2404-66") + ar & names; } @@ -2624,11 +2735,11 @@ namespace netgen void Identifications :: Add (PointIndex pi1, PointIndex pi2, int identnr) { // (*testout) << "Identification::Add, pi1 = " << pi1 << ", pi2 = " << pi2 << ", identnr = " << identnr << endl; - INDEX_2 pair (pi1, pi2); + PointIndices<2> pair (pi1, pi2); identifiedpoints.Set (pair, identnr); - INDEX_3 tripl (pi1, pi2, identnr); - identifiedpoints_nr.Set (tripl, 1); + // INDEX_3 tripl (pi1, pi2, identnr); + identifiedpoints_nr.Set ( { { pi1, pi2 }, identnr }, 1); if (identnr > maxidentnr) maxidentnr = identnr; names.SetSize(maxidentnr); @@ -2651,8 +2762,9 @@ namespace netgen bool Identifications :: Get (PointIndex pi1, PointIndex pi2, int nr) const { - INDEX_3 tripl(pi1, pi2, nr); - if (identifiedpoints_nr.Used (tripl)) + // INDEX_3 tripl(pi1, pi2, nr); + // if (identifiedpoints_nr.Used (tripl)) + if (identifiedpoints_nr.Used ( { { pi1, pi1 }, nr } ) ) return 1; else return 0; @@ -2674,7 +2786,7 @@ namespace netgen } - void Identifications :: GetMap (int identnr, NgArray & identmap, bool symmetric) const + void Identifications :: GetMap (int identnr, idmap_type & identmap, bool symmetric) const { identmap.SetSize (mesh.GetNP()); identmap = 0; @@ -2692,18 +2804,30 @@ namespace netgen { cout << "getmap, identnr = " << identnr << endl; + /* for (int i = 1; i <= identifiedpoints_nr.GetNBags(); i++) for (int j = 1; j <= identifiedpoints_nr.GetBagSize(i); j++) + */ + for (auto [hash, val] : identifiedpoints_nr) { + /* INDEX_3 i3; int dummy; identifiedpoints_nr.GetData (i, j, i3, dummy); - - if (i3.I3() == identnr || !identnr) + */ + + auto [hash_pts, hash_nr] = hash; + + if (hash_nr == identnr || !identnr) { + /* identmap.Elem(i3.I1()) = i3.I2(); if(symmetric) identmap.Elem(i3.I2()) = i3.I1(); + */ + identmap[hash_pts.I1()] = hash_pts.I2(); + if(symmetric) + identmap[hash_pts.I2()] = hash_pts.I1(); } } } @@ -2711,12 +2835,26 @@ namespace netgen } + Array Identifications :: GetPairs () const + { + Array pairs; + for(auto [hash, dummy] : identifiedpoints_nr) + // pairs.Append(i3); + { + auto [pts,nr] = hash; + pairs.Append ( { pts[0], pts[1], nr } ); + } + return pairs; + } + void Identifications :: GetPairs (int identnr, NgArray & identpairs) const { identpairs.SetSize(0); if (identnr == 0) + { + /* for (int i = 1; i <= identifiedpoints.GetNBags(); i++) for (int j = 1; j <= identifiedpoints.GetBagSize(i); j++) { @@ -2724,8 +2862,14 @@ namespace netgen int nr; identifiedpoints.GetData (i, j, i2, nr); identpairs.Append (i2); - } + } + */ + for (auto [hash,val] : identifiedpoints) + identpairs.Append (hash); + } else + { + /* for (int i = 1; i <= identifiedpoints_nr.GetNBags(); i++) for (int j = 1; j <= identifiedpoints_nr.GetBagSize(i); j++) { @@ -2735,12 +2879,21 @@ namespace netgen if (i3.I3() == identnr) identpairs.Append (INDEX_2(i3.I1(), i3.I2())); - } + } + */ + for (auto [hash,val] : identifiedpoints_nr) + { + auto [hash_pts, hash_nr] = hash; + if (hash_nr == identnr) + identpairs.Append (hash_pts); + } + } } void Identifications :: SetMaxPointNr (int maxpnum) { + /* for (int i = 1; i <= identifiedpoints.GetNBags(); i++) for (int j = 1; j <= identifiedpoints.GetBagSize(i); j++) { @@ -2754,17 +2907,105 @@ namespace netgen identifiedpoints.SetData (i, j, i2, -1); } } + */ + + // can we get data by reference ? + for (auto [hash,data] : identifiedpoints) + { + if (hash.I1() > IndexBASE()+maxpnum-1 || + hash.I2() > IndexBASE()+maxpnum-1) + { + identifiedpoints[hash] = -1; + } + + } } + // Map points in the identifications to new point numbers + // deletes identifications with invalid (mapped) points + void Identifications :: MapPoints(FlatArray op2np) + { + auto pairs = GetPairs(); + Delete(); + + for(auto pair : pairs) + { + auto p1 = op2np[pair.I1()]; + auto p2 = op2np[pair.I2()]; + if(p1.IsValid() && p2.IsValid()) + Add(p1, p2, pair.I3()); + } + } void Identifications :: Print (ostream & ost) const { ost << "Identifications:" << endl; ost << "pairs: " << endl << identifiedpoints << endl; - ost << "pairs and nr: " << endl << identifiedpoints_nr << endl; + // ost << "pairs and nr: " << endl << identifiedpoints_nr << endl; +#pragma message( "Can't ostream a tuple " __FILE__ ) ost << "table: " << endl << idpoints_table << endl; } + ostream & operator<< (ostream & ost, const BoundaryLayerParameters & mp) + { + auto print_vec = [&ost](auto & v) { + ost << "["; + for (const auto & val : v) + ost << val << " "; + ost << "]"; + }; + ost << "BoundaryLayerParameters" << endl; + ost << " boundary: "; + switch(mp.boundary.index()) + { + case 0: ost << std::get<0>(mp.boundary); break; + case 1: ost << std::get<1>(mp.boundary); break; + case 2: print_vec(std::get<2>(mp.boundary)); break; + } + ost << "\n thickness: "; + switch(mp.thickness.index()) + { + case 0: ost << std::get<0>(mp.thickness); break; + case 1: print_vec(std::get<1>(mp.thickness)); break; + } + ost <<"\n new_material: "; + if(!mp.new_material) ost << "nullopt"; + else { + switch(mp.new_material->index()) + { + case 0: ost << std::get<0>(*mp.new_material); break; + case 1: + for (const auto & [key, value] : std::get<1>(*mp.new_material)) + ost << key << " -> " << value << ", "; + break; + } + } + ost << "\n domain: "; + switch(mp.domain.index()) + { + case 0: ost << std::get<0>(mp.domain); break; + case 1: ost << std::get<1>(mp.domain); break; + case 2: print_vec(std::get<2>(mp.domain)); break; + } + ost << "\n outside: " << mp.outside; + ost << "\n project_boundaries: "; + if(mp.project_boundaries) { + auto & proj_bnd = *mp.project_boundaries; + switch(proj_bnd.index()) + { + case 0: ost << std::get<0>(proj_bnd); break; + case 1: print_vec(std::get<1>(proj_bnd)); break; + } + } + else + ost << "nullopt"; + ost << "\n grow_edges: " << mp.grow_edges; + ost << "\n limit_growth_vectors: " << mp.limit_growth_vectors; + ost << "\n sides_keep_surfaceindex: " << (mp.sides_keep_surfaceindex ? ToString(*mp.sides_keep_surfaceindex) : "nullopt"); + ost << "\n disable_curving: " << mp.disable_curving; + ost << endl; + return ost; + } MeshingParameters :: MeshingParameters () { @@ -2898,7 +3139,7 @@ namespace netgen haltsegment = 0; haltsegmentp1 = 0; haltsegmentp2 = 0; - write_mesh_on_error = false; + write_mesh_on_error = getenv("NG_WRITE_MESH_ON_ERROR"); }; diff --git a/libsrc/meshing/meshtype.hpp b/libsrc/meshing/meshtype.hpp index 5c174b30..e0572155 100644 --- a/libsrc/meshing/meshtype.hpp +++ b/libsrc/meshing/meshtype.hpp @@ -8,6 +8,17 @@ /* Date: 01. Okt. 95 */ /**************************************************************************/ +#include + +#include +#include +#include +#include +#include + +#include "core/exception.hpp" +#include "msghandler.hpp" + namespace netgen { @@ -16,34 +27,18 @@ namespace netgen */ - enum ELEMENT_TYPE : unsigned char { SEGMENT = 1, SEGMENT3 = 2, TRIG = 10, QUAD=11, TRIG6 = 12, QUAD6 = 13, QUAD8 = 14, TET = 20, TET10 = 21, PYRAMID = 22, PRISM = 23, PRISM12 = 24, PRISM15 = 27, PYRAMID13 = 28, - HEX = 25, HEX20 = 26 + HEX = 25, HEX20 = 26, HEX7 = 29 }; - /* - typedef int ELEMENT_EDGE[2]; // initial point, end point - typedef int ELEMENT_FACE[4]; // points, last one is -1 for trig - */ - struct ELEMENT_EDGE - { - int vals[2]; - int & operator[] (size_t i) { return vals[i]; } - int operator[] (size_t i) const { return vals[i]; } - }; - - struct ELEMENT_FACE - { - int vals[4]; - int & operator[] (size_t i) { return vals[i]; } - int operator[] (size_t i) const { return vals[i]; } - }; - + using ELEMENT_EDGE = std::array; + using ELEMENT_FACE = std::array; + #define ELEMENT_MAXPOINTS 20 #define ELEMENT2D_MAXPOINTS 8 @@ -66,10 +61,6 @@ namespace netgen return timestamp; } - /* - extern DLL_HEADER int GetTimeStamp(); - extern DLL_HEADER int NextTimeStamp(); - */ class PointGeomInfo { public: @@ -77,12 +68,10 @@ namespace netgen double u, v; // for OCC Meshing PointGeomInfo () = default; - // : trignum(-1), u(0), v(0) { ; } PointGeomInfo (const PointGeomInfo&) = default; PointGeomInfo (PointGeomInfo &&) = default; PointGeomInfo & operator= (const PointGeomInfo&) = default; PointGeomInfo & operator= (PointGeomInfo&&) = default; - }; inline ostream & operator<< (ostream & ost, const PointGeomInfo & gi) @@ -138,86 +127,311 @@ namespace netgen } - - - - class PointIndex + template + class Index { - int i; public: + T i; + + static constexpr int BASE = BASE_; + static constexpr TIndex Base() { return TIndex(BASE_); } + class t_invalid { public: constexpr t_invalid() = default; }; static constexpr t_invalid INVALID{}; + + typedef decltype( declval()-declval() ) T_diff; - PointIndex () = default; - PointIndex (const PointIndex&) = default; - PointIndex (PointIndex &&) = default; - PointIndex & operator= (const PointIndex&) = default; - PointIndex & operator= (PointIndex&&) = default; - - constexpr PointIndex (int ai) : i(ai) + public: + constexpr Index () = default; + constexpr Index (const Index& i2) = default; + constexpr Index (Index &&) = default; + Index & operator= (const Index&) = default; + Index & operator= (Index&&) = default; + + // private: + constexpr Index (T ai) : i(ai) { #ifdef DEBUG - if (ai < PointIndex::BASE) - cout << "illegal PointIndex, use PointIndex::INVALID instead" << endl; - // throw Exception("illegal PointIndex, use PointIndex::INVALID instead"); + if (ai < BASE_) + cout << "illegal Index, use Index::INVALID instead" << endl; #endif } - constexpr PointIndex (t_invalid inv) : i(PointIndex::BASE-1) { ; } - // PointIndex & operator= (const PointIndex &ai) { i = ai.i; return *this; } - constexpr operator int () const { return i; } - PointIndex operator++ (int) { PointIndex hi(*this); i++; return hi; } - PointIndex operator-- (int) { PointIndex hi(*this); i--; return hi; } - PointIndex & operator++ () { i++; return *this; } - PointIndex operator-- () { i--; return *this; } - PointIndex operator+= (int add) { i += add; return *this; } - void Invalidate() { i = PointIndex::BASE-1; } - bool IsValid() const { return i != PointIndex::BASE-1; } -#ifdef BASE0 - static constexpr size_t BASE = 0; -#else - static constexpr size_t BASE = 1; -#endif + + + /* + // didn't manage constexpr friend functions so far ??? + friend auto operator+ (Index, int) -> TIndex; + friend TIndex operator+ (Index, size_t); + friend TIndex operator+ (int, Index); + friend TIndex operator+ (size_t, Index); + friend constexpr TIndex operator- (Index, int); + friend int operator- (Index, Index); + friend bool operator< (Index a, Index b); + friend bool operator> (Index a, Index b); + friend bool operator>= (Index a, Index b); + friend bool operator<= (Index a, Index b); + friend bool operator== (Index a, Index b); + friend bool operator!= (Index a, Index b); + */ + + public: + constexpr Index (t_invalid inv) : i(long(BASE)-1) { ; } + // protected: + constexpr operator T () const { return i; } + explicit constexpr operator T& () { return i; } + public: + TIndex operator++ (int) { TIndex hi{*this}; i++; return hi; } + TIndex operator-- (int) { TIndex hi(*this); i--; return hi; } + TIndex & operator++ () { i++; return static_cast(*this); } + TIndex & operator-- () { i--; return static_cast(*this); } + + /* + constexpr TIndex operator+= (int add) { i += add; return TIndex{*this}; } + constexpr TIndex operator+= (size_t add) { i += add; return TIndex{*this}; } + constexpr TIndex operator-= (int add) { i -= add; return TIndex{*this}; } + constexpr TIndex operator-= (size_t add) { i -= add; return TIndex{*this}; } + */ + constexpr TIndex operator+= (T_diff add) { i += add; return TIndex{*this}; } + constexpr TIndex operator-= (T_diff add) { i -= add; return TIndex{*this}; } + + constexpr auto operator- (Index i2) const { return i-i2.i; } + + // bool operator== (Index i2) const { return i==i2.i; } + // bool operator!= (Index i2) const { return i!=i2.i; } + void Invalidate() { i = long(TIndex::BASE)-1; } + bool IsValid() const { return i+1 != TIndex::BASE; } + // operator bool() const { return IsValid(); } void DoArchive (Archive & ar) { ar & i; } }; + + template + constexpr auto operator+ (Index ind, int i) { Index res(ind); return res += i; } + template + constexpr auto operator+ (Index ind, size_t i) { Index res(ind); return res += i; } + template + constexpr TIndex operator+ (int i, Index ind) { return ind+i; } // Indexx res(ind); return res += i; + template + inline TIndex operator+ (size_t i, Index ind) { return ind+i; } // TIndex res(ind); res += i; return res; } + + template + constexpr inline auto operator- (Index ind, int i) { Index res(ind); return res -= i; } + // template + // constexpr inline auto operator- (Index pa, Index pb) { return pa.i-pb.i; } + + template + inline bool operator< (Index a, Index b) { return a-b < 0; } + template + inline bool operator> (Index a, Index b) { return a-b > 0; } + template + inline bool operator>= (Index a, Index b) { return a-b >= 0; } + template + inline bool operator<= (Index a, Index b) { return a-b <= 0; } + + template + inline bool operator== (Index a, Index b) { return a.i == b.i; } + template + inline bool operator!= (Index a, Index b) { return a.i != b.i; } + + + template + inline void SetInvalid (Index & id) { id.Invalidate(); } + template + inline bool IsInvalid (const Index & id) { return !id.IsValid(); } + + + + class PointIndex : public Index + { + public: + using Index::Index; + template friend class PointIndices; + }; + } namespace ngcore { template<> - constexpr netgen::PointIndex IndexBASE () { return netgen::PointIndex(netgen::PointIndex::BASE); } + constexpr netgen::PointIndex IndexBASE () { return netgen::PointIndex::Base(); } } namespace netgen { - + // input-output is 1-based inline istream & operator>> (istream & ist, PointIndex & pi) { - int i; ist >> i; pi = PointIndex(i); return ist; + // int i; ist >> i; pi = PointIndex(i); return ist; + int i; ist >> i; + pi = IndexBASE()+i-1; + return ist; } inline ostream & operator<< (ostream & ost, const PointIndex & pi) { - return (ost << int(pi)); + // return (ost << int(pi)); + int intpi = pi - IndexBASE() + 1; + return (ost << intpi); } + + + /* + PointIndices<2> etc are derived from historic INDEX_2 etc to be useable in old HASHTABLEs. + Will change to IVec<2> or std::array when INDEX_2 is not needed anymore + */ + template class PointIndices; template <> class PointIndices<2> : public INDEX_2 { public: PointIndices () = default; - PointIndices (INDEX_2 i2) : INDEX_2(i2) { ; } - PointIndices (PointIndex i1, PointIndex i2) : INDEX_2(i1,i2) { ; } - PointIndex operator[] (int i) const { return PointIndex(INDEX_2::operator[](i)); } + constexpr PointIndices (const PointIndices&) = default; + constexpr PointIndices (PointIndices&&) = default; + PointIndices & operator= (const PointIndices&) = default; + PointIndices & operator= (PointIndices&&) = default; + + constexpr PointIndices (INDEX_2 i2) : INDEX_2(i2) { ; } + constexpr PointIndices (PointIndex i1, PointIndex i2) : INDEX_2(i1,i2) { ; } + constexpr PointIndex operator[] (int i) const { return PointIndex(INDEX_2::operator[](i)); } PointIndex & operator[] (int i) { return reinterpret_cast(INDEX_2::operator[](i)); } + + template + void DoArchive(ARCHIVE& ar) { ar.Do(&I1(), 2); } + + PointIndex & I1 () { return (*this)[0]; } + PointIndex & I2 () { return (*this)[1]; } + PointIndex I1 () const { return (*this)[0]; } + PointIndex I2 () const { return (*this)[1]; } + + using INDEX_2::Sort; static PointIndices Sort(PointIndex i1, PointIndex i2) { return INDEX_2::Sort(i1, i2); } template PointIndex get() const { return PointIndex(INDEX_2::operator[](J)); } }; + + template <> class PointIndices<3> : public INDEX_3 + { + public: + PointIndices () = default; + PointIndices (const PointIndices&) = default; + PointIndices (PointIndices&&) = default; + PointIndices & operator= (const PointIndices&) = default; + PointIndices & operator= (PointIndices&&) = default; + constexpr PointIndices (INDEX_3 i3) : INDEX_3(i3) { ; } + constexpr PointIndices (PointIndex i1, PointIndex i2, PointIndex i3) : INDEX_3(i1,i2,i3) { ; } + PointIndex operator[] (int i) const { return PointIndex(INDEX_3::operator[](i)); } + PointIndex & operator[] (int i) { return reinterpret_cast(INDEX_3::operator[](i)); } + + template + void DoArchive(ARCHIVE& ar) { ar.Do(&I1(), 3); } + + PointIndex & I1 () { return (*this)[0]; } + PointIndex & I2 () { return (*this)[1]; } + PointIndex & I3 () { return (*this)[2]; } + PointIndex I1 () const { return (*this)[0]; } + PointIndex I2 () const { return (*this)[1]; } + PointIndex I3 () const { return (*this)[2]; } + + using INDEX_3::Sort; + static PointIndices Sort(PointIndex i1, PointIndex i2, PointIndex i3) { return INDEX_3::Sort(i1, i2, i3); } + template + PointIndex get() const { return PointIndex(INDEX_3::operator[](J)); } + }; + + template <> class PointIndices<4> : public INDEX_4 + { + public: + PointIndices () = default; + PointIndices (INDEX_4 i4) : INDEX_4(i4) { ; } + PointIndices (PointIndex i1, PointIndex i2, PointIndex i3, PointIndex i4) : INDEX_4(i1,i2,i3,i4) { ; } + PointIndex operator[] (int i) const { return PointIndex(INDEX_4::operator[](i)); } + PointIndex & operator[] (int i) { return reinterpret_cast(INDEX_4::operator[](i)); } + + template + void DoArchive(ARCHIVE& ar) { ar.Do(&I1(), 4); } + + PointIndex & I1 () { return (*this)[0]; } + PointIndex & I2 () { return (*this)[1]; } + PointIndex & I3 () { return (*this)[2]; } + PointIndex & I4 () { return (*this)[3]; } + PointIndex I1 () const { return (*this)[0]; } + PointIndex I2 () const { return (*this)[1]; } + PointIndex I3 () const { return (*this)[2]; } + PointIndex I4 () const { return (*this)[3]; } + + using INDEX_4::Sort; + // static PointIndices Sort(PointIndex i1, PointIndex i2, PointIndex i3, PointIndex i4) { return INDEX_4::Sort(i1, i2, i3, i4); } + template + PointIndex get() const { return PointIndex(INDEX_4::operator[](J)); } + }; + + + template + class SortedPointIndices : public PointIndices + { + using PointIndices::Sort; + public: + constexpr SortedPointIndices (PointIndices pnts) + : PointIndices(pnts.Sort()) { } + + template + constexpr SortedPointIndices (Pnts ...pnts) + : PointIndices(pnts...) + { Sort(); } + }; + } + + +namespace ngcore +{ + + template <> + struct CHT_trait + { + constexpr static inline netgen::PointIndex Invalid() { return netgen::PointIndex::INVALID; } + constexpr static inline size_t HashValue (const netgen::PointIndex & hash, size_t mask) + { return (hash-IndexBASE()) & mask; } + }; + + + template <> + struct CHT_trait> + { + constexpr static inline netgen::PointIndices<2> Invalid() { return { netgen::PointIndex::INVALID, netgen::PointIndex::INVALID} ; } + constexpr static inline size_t HashValue (const netgen::PointIndices<2> & hash, size_t mask) + { return HashValue2(IVec<2>(hash[0]-IndexBASE(), + hash[1]-IndexBASE()), mask); } + }; + + + template <> + struct CHT_trait> + { + constexpr static inline netgen::SortedPointIndices<2> Invalid() { return { netgen::PointIndex::INVALID, netgen::PointIndex::INVALID} ; } + constexpr static inline size_t HashValue (const netgen::SortedPointIndices<2> & hash, size_t mask) + // { return HashValue2(IVec<2,netgen::INDEX>(hash[0], hash[1]), mask); } + { return CHT_trait>::HashValue (hash, mask); } + }; + + + template <> + constexpr inline netgen::PointIndices<3> InvalidHash> () + { return netgen::PointIndices<3>{netgen::PointIndex::INVALID, netgen::PointIndex::INVALID, netgen::PointIndex::INVALID}; } + + /* + template <> + constexpr inline netgen::SortedPointIndices<2> InvalidHash> () + // { return InvalidHash>(); } + { return CHT_trait>::Invalid(); } + */ +} + + namespace std { // structured binding support @@ -229,84 +443,81 @@ namespace std namespace netgen { - class ElementIndex + class ElementIndex : public Index { - int i; public: - ElementIndex () = default; - constexpr ElementIndex (int ai) : i(ai) { ; } - ElementIndex & operator= (const ElementIndex & ai) { i = ai.i; return *this; } - ElementIndex & operator= (int ai) { i = ai; return *this; } - constexpr operator int () const { return i; } - ElementIndex operator++ (int) { return ElementIndex(i++); } - ElementIndex operator-- (int) { return ElementIndex(i--); } - ElementIndex & operator++ () { ++i; return *this; } - ElementIndex & operator-- () { --i; return *this; } - }; - - inline istream & operator>> (istream & ist, ElementIndex & pi) - { - int i; ist >> i; pi = i; return ist; - } - - inline ostream & operator<< (ostream & ost, const ElementIndex & pi) - { - return (ost << int(pi)); - } - - - class SurfaceElementIndex - { - int i; - public: - SurfaceElementIndex () = default; - constexpr SurfaceElementIndex (int ai) : i(ai) { ; } - /* - SurfaceElementIndex & operator= (const SurfaceElementIndex & ai) - { i = ai.i; return *this; } - */ - SurfaceElementIndex & operator= (const SurfaceElementIndex & ai) = default; - SurfaceElementIndex & operator= (int ai) { i = ai; return *this; } - constexpr operator int () const { return i; } - SurfaceElementIndex operator++ (int) { SurfaceElementIndex hi(*this); i++; return hi; } - SurfaceElementIndex operator-- (int) { SurfaceElementIndex hi(*this); i--; return hi; } - SurfaceElementIndex & operator++ () { ++i; return *this; } - SurfaceElementIndex & operator-- () { --i; return *this; } - SurfaceElementIndex & operator+= (int inc) { i+=inc; return *this; } - void DoArchive (Archive & ar) { ar & i; } + using Index::Index; // ::Index; }; - inline void SetInvalid (SurfaceElementIndex & id) { id = -1; } - inline bool IsInvalid (SurfaceElementIndex & id) { return id == -1; } + inline istream & operator>> (istream & ist, ElementIndex & ei) + { + int i; ist >> i; ei = ElementIndex::Base()+i; return ist; + } + + inline ostream & operator<< (ostream & ost, const ElementIndex & ei) + { + return ost << int(ei-ElementIndex::Base()); + } + + + /* + // these should not be needed soon + inline bool operator== (Index ei1, int ei2) { return int(ei1) == int(ei2); }; + inline bool operator< (size_t s, Index ei2) { return int(s) < int(ei2); }; + inline bool operator< ( Index ei1, size_t s) { return int(ei1) < int(s); }; // should not need + inline bool operator< ( Index ei1, int s) { return int(ei1) < int(s); }; // should not need + inline bool operator>= (size_t s, Index ei2) { return int(s) >= int(ei2); }; + */ + + class SurfaceElementIndex : public Index + { + public: + using Index::Index; + }; + + + // these should not be needed soon + /* + inline bool operator== (Index ei1, int ei2) { return int(ei1) == int(ei2); }; + inline bool operator== (int ei2, Index ei1) { return int(ei1) == int(ei2); }; + inline bool operator!= (Index ei1, int ei2) { return int(ei1) != int(ei2); }; + inline bool operator< (size_t s, Index ei2) { return int(s) < int(ei2); }; + inline bool operator< (Index ei1, size_t s) { return int(ei1) < int(s); }; // should not need + inline bool operator< (Index ei1, int s) { return int(ei1) < int(s); }; // should not need + inline bool operator>= (size_t s, Index ei2) { return int(s) >= int(ei2); }; + inline bool operator>= (Index ei1, int s) { return int(ei1) >= int(s); }; + */ + + // inline void SetInvalid (SurfaceElementIndex & id) { id.Invalidate(); } + // inline bool IsInvalid (SurfaceElementIndex & id) { return !id.IsValid(); } inline istream & operator>> (istream & ist, SurfaceElementIndex & pi) { int i; ist >> i; pi = i; return ist; } - inline ostream & operator<< (ostream & ost, const SurfaceElementIndex & pi) + inline ostream & operator<< (ostream & ost, const SurfaceElementIndex & si) { - return (ost << int(pi)); + return ost << (si-IndexBASE(si)); } - class SegmentIndex + + class SegmentIndex : public Index { - int i; public: - SegmentIndex () = default; - constexpr SegmentIndex (int ai) : i(ai) { ; } - SegmentIndex & operator= (const SegmentIndex & ai) - { i = ai.i; return *this; } - SegmentIndex & operator= (int ai) { i = ai; return *this; } - constexpr operator int () const { return i; } - SegmentIndex& operator++ () { ++i; return *this; } - SegmentIndex& operator-- () { --i; return *this; } - SegmentIndex operator++ (int) { return i++; } - SegmentIndex operator-- (int) { return i--; } + using Index::Index; }; - inline void SetInvalid (SegmentIndex & id) { id = -1; } - inline bool IsInvalid (SegmentIndex & id) { return id == -1; } + // these should not be needed soon + /* + inline bool operator== (Index ei1, int ei2) { return int(ei1) == int(ei2); }; + inline bool operator< (size_t s, Index ei2) { return int(s) < int(ei2); }; + inline bool operator< (Index ei1, size_t s) { return int(ei1) < int(s); }; + inline bool operator< (Index ei1, int s) { return int(ei1) < int(s); }; + */ + + // inline void SetInvalid (SegmentIndex & id) { id = -1; } + // inline bool IsInvalid (SegmentIndex & id) { return id == -1; } inline istream & operator>> (istream & ist, SegmentIndex & pi) @@ -314,10 +525,10 @@ namespace netgen int i; ist >> i; pi = i; return ist; } - inline ostream & operator<< (ostream & ost, const SegmentIndex & pi) + inline ostream & operator<< (ostream & ost, const SegmentIndex & si) { - return (ost << int(pi)); - } + return ost << (si - IndexBASE(si)); + } @@ -364,7 +575,7 @@ namespace netgen bool IsSingular() const { return (singular != 0.0); } #ifdef PARALLEL - static MPI_Datatype MyGetMPIType ( ); + static NG_MPI_Datatype MyGetMPIType ( ); #endif void DoArchive (Archive & ar) @@ -415,7 +626,8 @@ namespace netgen // Set a new property for each element, to // control whether it is visible or not bool visible:1; // element visible - bool is_curved:1; // element is (high order) curved + bool is_curved; // element is (high order) curved + int8_t newest_vertex = -1; // from refinement via bisection /// order for hp-FEM unsigned int orderx:6; unsigned int ordery:6; @@ -432,7 +644,8 @@ namespace netgen { "pnum", offsetof(Element2d, pnum)}, { "index", offsetof(Element2d, index) }, { "np", offsetof(Element2d, np) }, - { "refine", offsetof(Element2d, refflag) } + { "refine", offsetof(Element2d, refflag) }, + { "curved", offsetof(Element2d, is_curved)} }); } @@ -464,9 +677,9 @@ namespace netgen /// DLL_HEADER Element2d (ELEMENT_TYPE type); /// - DLL_HEADER Element2d (int pi1, int pi2, int pi3); + DLL_HEADER Element2d (PointIndex pi1, PointIndex pi2, PointIndex pi3); /// - DLL_HEADER Element2d (int pi1, int pi2, int pi3, int pi4); + DLL_HEADER Element2d (PointIndex pi1, PointIndex pi2, PointIndex pi3, PointIndex pi4); /// ELEMENT_TYPE GetType () const { return typ; } /// @@ -552,6 +765,9 @@ namespace netgen /// const PointGeomInfo & GeomInfoPiMod (int i) const { return geominfo[(i-1) % np]; } + auto & NewestVertex() { return newest_vertex; } + auto NewestVertex() const { return newest_vertex; } + void DoArchive (Archive & ar) { short _np, _typ; @@ -574,7 +790,7 @@ namespace netgen } #ifdef PARALLEL - static MPI_Datatype MyGetMPIType(); + static NG_MPI_Datatype MyGetMPIType(); #endif @@ -646,14 +862,14 @@ namespace netgen void Delete () { - deleted = 1; + deleted = true; // for (PointIndex & p : pnum) p.Invalidate(); } bool IsDeleted () const { #ifdef DEBUG - if (pnum[0] < PointIndex::BASE && !deleted) + if ((pnum[0]-IndexBASE() < 0) && !deleted) cerr << "Surfelement has illegal pnum, but not marked as deleted" << endl; #endif return deleted; @@ -721,7 +937,8 @@ namespace netgen ELEMENT_TYPE typ; /// number of points (4..tet, 5..pyramid, 6..prism, 8..hex, 10..quad tet, 12..quad prism) int8_t np; - + int8_t newest_vertex = -1; // from refinement via bisection + /// sub-domain index int index; /// order for hp-FEM @@ -733,7 +950,7 @@ namespace netgen unsigned int levelz:6; */ /// stored shape-badness of element float badness; - bool is_curved:1; // element is (high order) curved + bool is_curved; // element is (high order) curved class flagstruct { public: @@ -759,7 +976,8 @@ namespace netgen { "pnum", offsetof(Element, pnum)}, { "index", offsetof(Element, index) }, { "np", offsetof(Element, np) }, - { "refine", offsetof(Element, flags.refflag) } + { "refine", offsetof(Element, flags.refflag) }, + { "curved", offsetof(Element, is_curved)} }); } @@ -789,7 +1007,7 @@ namespace netgen /// uint8_t GetNV() const { - __assume(typ >= TET && typ <= PYRAMID13); + // __assume(typ >= TET && typ <= PYRAMID13); switch (typ) { case TET: @@ -802,6 +1020,8 @@ namespace netgen case PYRAMID: case PYRAMID13: return 5; + case HEX7: + return 7; case HEX: case HEX20: return 8; @@ -843,6 +1063,9 @@ namespace netgen /// const PointIndex & PNumMod (int i) const { return pnum[(i-1) % np]; } + auto & NewestVertex() { return newest_vertex; } + auto NewestVertex() const { return newest_vertex; } + void DoArchive (Archive & ar) { short _np, _typ; @@ -874,7 +1097,7 @@ namespace netgen } #ifdef PARALLEL - static MPI_Datatype MyGetMPIType(); + static NG_MPI_Datatype MyGetMPIType(); #endif /// @@ -908,6 +1131,7 @@ namespace netgen case PRISM: case PRISM15: case PRISM12: return 5; + case HEX7: return 6; case HEX: case HEX20: return 6; default: @@ -984,7 +1208,10 @@ namespace netgen { return flags.strongrefflag; } int Illegal () const - { return flags.illegal; } + { + NETGEN_CHECK_SAME(flags.illegal_valid, true); + return flags.illegal; + } int IllegalValid () const { return flags.illegal_valid; } void SetIllegal (int aillegal) @@ -997,12 +1224,32 @@ namespace netgen flags.illegal = alegal ? 0 : 1; flags.illegal_valid = 1; } + + bool BadnessValid() + { return flags.badness_valid; } + + float GetBadness() + { + NETGEN_CHECK_SAME(flags.badness_valid, true); + return badness; + } + + void SetBadness(float value) + { + badness = value; + flags.badness_valid = 1; + } + + void Touch() { + flags.illegal_valid = 0; + flags.badness_valid = 0; + } void Delete () { flags.deleted = 1; } bool IsDeleted () const { #ifdef DEBUG - if (pnum[0] < PointIndex::BASE && !flags.deleted) + if (pnum[0]-IndexBASE() < 0 && !flags.deleted) cerr << "Volelement has illegal pnum, but not marked as deleted" << endl; #endif @@ -1102,7 +1349,7 @@ namespace netgen void DoArchive (Archive & ar); #ifdef PARALLEL - static MPI_Datatype MyGetMPIType(); + static NG_MPI_Datatype MyGetMPIType(); #endif }; @@ -1118,7 +1365,13 @@ namespace netgen int index; Element0d () = default; Element0d (PointIndex _pnum, int _index) - : pnum(_pnum), index(_index) { ; } + : pnum(_pnum), index(_index) { ; } + +#ifdef PARALLEL + static NG_MPI_Datatype MyGetMPIType(); +#endif + + void DoArchive (Archive & ar); }; ostream & operator<<(ostream & s, const Element0d & el); @@ -1221,6 +1474,22 @@ namespace netgen }; + struct BoundaryLayerParameters + { + std::variant> thickness; + std::variant> domain; + std::variant> boundary = ".*"; + std::optional>> new_material = nullopt; + std::optional>> project_boundaries = nullopt; + bool outside = false; + bool grow_edges = true; + bool limit_growth_vectors = false; // automatic reduction of layer thickness to avoid intersections + std::optional sides_keep_surfaceindex = nullopt; // !outside by default + bool disable_curving = true; // disable curving affected boundaries/edges (could lead to self-intersecting volume elements) + }; + + + ostream & operator<< (ostream & ost, const BoundaryLayerParameters & mp); class DLL_HEADER MeshingParameters { @@ -1346,6 +1615,8 @@ namespace netgen int nthreads = 4; Flags geometrySpecificParameters; + + Array boundary_layers; /// MeshingParameters (); /// @@ -1364,7 +1635,7 @@ namespace netgen Point<3> pnt; double h; int layer = 1; - MeshSizePoint (Point<3> _pnt, double _h) : pnt(_pnt), h(_h) { ; } + MeshSizePoint (Point<3> pnt_, double h_, int layer_ = 1) : pnt(pnt_), h(h_), layer(layer_) { ; } MeshSizePoint () = default; MeshSizePoint (const MeshSizePoint &) = default; MeshSizePoint (MeshSizePoint &&) = default; @@ -1405,9 +1676,9 @@ namespace netgen /// int haltnode; /// - int haltsegmentp1; + PointIndex haltsegmentp1; /// - int haltsegmentp2; + PointIndex haltsegmentp2; /// int haltexistingline; /// @@ -1487,8 +1758,9 @@ namespace netgen - - + // typedef NgArray idmap_type; + typedef Array idmap_type; + /** @@ -1504,13 +1776,15 @@ namespace netgen class Mesh & mesh; /// identify points (thin layers, periodic b.c.) - INDEX_2_HASHTABLE identifiedpoints; + // INDEX_2_HASHTABLE identifiedpoints; + ClosedHashTable, int> identifiedpoints; /// the same, with info about the id-nr - INDEX_3_HASHTABLE identifiedpoints_nr; + // INDEX_3_HASHTABLE identifiedpoints_nr; + ClosedHashTable, int>, int> identifiedpoints_nr; /// sorted by identification nr - TABLE idpoints_table; + TABLE> idpoints_table; NgArray type; @@ -1546,25 +1820,26 @@ namespace netgen // bool HasIdentifiedPoints() const { return identifiedpoints != nullptr; } /// - INDEX_2_HASHTABLE & GetIdentifiedPoints () + auto & GetIdentifiedPoints () { - return identifiedpoints; + return identifiedpoints_nr; } bool Used (PointIndex pi1, PointIndex pi2) { - return identifiedpoints.Used (INDEX_2 (pi1, pi2)); + // return identifiedpoints.Used (INDEX_2 (pi1, pi2)); + return identifiedpoints.Used (PointIndices<2>(pi1, pi2)); } bool UsedSymmetric (PointIndex pi1, PointIndex pi2) { return - identifiedpoints.Used (INDEX_2 (pi1, pi2)) || - identifiedpoints.Used (INDEX_2 (pi2, pi1)); + identifiedpoints.Used (PointIndices<2>(pi1, pi2)) || + identifiedpoints.Used (PointIndices<2>(pi2, pi1)); } /// - void GetMap (int identnr, NgArray & identmap, bool symmetric = false) const; + void GetMap (int identnr, idmap_type & identmap, bool symmetric = false) const; /// ID_TYPE GetType(int identnr) const { @@ -1582,6 +1857,7 @@ namespace netgen /// DLL_HEADER void GetPairs (int identnr, NgArray & identpairs) const; + DLL_HEADER Array GetPairs () const; /// int GetMaxNr () const { return maxidentnr; } @@ -1591,10 +1867,25 @@ namespace netgen names.Append(name); return names.Pos(name)+1; } + string GetName(int nr) const + { + if (nr <= names.Size()) + return names[nr - 1]; + else + return ""; + } + void SetName(int nr, string name) + { + while(names.Size() < nr) + names.Append(""); + names[nr-1] = name; + } /// remove secondorder void SetMaxPointNr (int maxpnum); + void MapPoints(FlatArray op2np); + DLL_HEADER void Print (ostream & ost) const; void DoArchive (Archive & ar); @@ -1606,25 +1897,28 @@ namespace netgen namespace ngcore { template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_INT; } + static NG_MPI_Datatype MPIType () { return NG_MPI_INT; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return MPI_CHAR; } + static NG_MPI_Datatype MPIType () { return NG_MPI_CHAR; } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return netgen::MeshPoint::MyGetMPIType(); } + static NG_MPI_Datatype MPIType () { return netgen::MeshPoint::MyGetMPIType(); } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return netgen::Element::MyGetMPIType(); } + static NG_MPI_Datatype MPIType () { return netgen::Element::MyGetMPIType(); } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return netgen::Element2d::MyGetMPIType(); } + static NG_MPI_Datatype MPIType () { return netgen::Element2d::MyGetMPIType(); } }; template <> struct MPI_typetrait { - static MPI_Datatype MPIType () { return netgen::Segment::MyGetMPIType(); } + static NG_MPI_Datatype MPIType () { return netgen::Segment::MyGetMPIType(); } + }; + template <> struct MPI_typetrait { + static NG_MPI_Datatype MPIType () { return netgen::Element0d::MyGetMPIType(); } }; } diff --git a/libsrc/meshing/msghandler.hpp b/libsrc/meshing/msghandler.hpp index bab57174..04f0eda9 100644 --- a/libsrc/meshing/msghandler.hpp +++ b/libsrc/meshing/msghandler.hpp @@ -7,6 +7,8 @@ /* Date: 20. Nov. 99 */ /**************************************************************************/ +#include + namespace netgen { diff --git a/libsrc/meshing/parallelmesh.cpp b/libsrc/meshing/parallelmesh.cpp index 185c9eab..c452cec7 100644 --- a/libsrc/meshing/parallelmesh.cpp +++ b/libsrc/meshing/parallelmesh.cpp @@ -53,15 +53,15 @@ namespace ngcore }; // class SurfPointPackage template<> struct MPI_typetrait { - static MPI_Datatype MPIType () { - static MPI_Datatype MPI_T = 0; + static NG_MPI_Datatype MPIType () { + static NG_MPI_Datatype MPI_T = 0; if (!MPI_T) { int block_len[2] = { 2, 2 }; - MPI_Aint displs[3] = { 0, 2*sizeof(int) }; - MPI_Datatype types[2] = { MPI_INT, MPI_DOUBLE }; - MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); - MPI_Type_commit(&MPI_T); + NG_MPI_Aint displs[3] = { 0, 2*sizeof(int) }; + NG_MPI_Datatype types[2] = { NG_MPI_INT, NG_MPI_DOUBLE }; + NG_MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); + NG_MPI_Type_commit(&MPI_T); } return MPI_T; } @@ -119,15 +119,15 @@ namespace ngcore }; // class SelPackage template<> struct MPI_typetrait { - static MPI_Datatype MPIType () { - static MPI_Datatype MPI_T = 0; + static NG_MPI_Datatype MPIType () { + static NG_MPI_Datatype MPI_T = 0; if (!MPI_T) { int block_len[2] = { 3, ELEMENT2D_MAXPOINTS }; - MPI_Aint displs[3] = { 0, 3*sizeof(int) }; - MPI_Datatype types[2] = { MPI_INT, GetMPIType() }; - MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); - MPI_Type_commit(&MPI_T); + NG_MPI_Aint displs[3] = { 0, 3*sizeof(int) }; + NG_MPI_Datatype types[2] = { NG_MPI_INT, GetMPIType() }; + NG_MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); + NG_MPI_Type_commit(&MPI_T); } return MPI_T; } @@ -145,15 +145,15 @@ namespace ngcore }; // class PointElPackage template<> struct MPI_typetrait { - static MPI_Datatype MPIType () { - static MPI_Datatype MPI_T = 0; + static NG_MPI_Datatype MPIType () { + static NG_MPI_Datatype MPI_T = 0; if (!MPI_T) { int block_len[2] = { 1, 1 }; - MPI_Aint displs[3] = { 0, sizeof(netgen::PointIndex) }; - MPI_Datatype types[2] = { GetMPIType(), MPI_INT }; - MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); - MPI_Type_commit(&MPI_T); + NG_MPI_Aint displs[3] = { 0, sizeof(netgen::PointIndex) }; + NG_MPI_Datatype types[2] = { GetMPIType(), NG_MPI_INT }; + NG_MPI_Type_create_struct(2, block_len, displs, types, &MPI_T); + NG_MPI_Type_commit(&MPI_T); } return MPI_T; } @@ -216,14 +216,14 @@ namespace netgen static Timer tbuildelementtable("SendMesh::Build_elementtable"); NgMPI_Comm comm = GetCommunicator(); - int id = comm.Rank(); + // int id = comm.Rank(); int ntasks = comm.Size(); int dim = GetDimension(); comm.Bcast(dim); - Array sendrequests(8*(ntasks-1)); - sendrequests.SetSize0(); + NgMPI_Requests sendrequests; // (8*(ntasks-1)); + // sendrequests.SetSize0(); // If the topology is not already updated, we do not need to // build edges/faces. @@ -329,7 +329,9 @@ namespace netgen /** The same table as per_verts, but TRANSITIVE!! **/ auto iterate_per_verts_trans = [&](auto f){ NgArray allvs; - for (int k = PointIndex::BASE; k < GetNV()+PointIndex::BASE; k++) + // for (int k = PointIndex::BASE; k < GetNV()+PointIndex::BASE; k++) + for (PointIndex k = IndexBASE(); + k < GetNV()+IndexBASE(); k++) { allvs.SetSize(0); allvs.Append(per_verts[k]); @@ -438,7 +440,8 @@ namespace netgen local vertex numbers on distant procs (I think this was only used for debugging??) **/ - for (int vert = 1; vert <= GetNP(); vert++ ) + // for (int vert = 1; vert <= GetNP(); vert++ ) + for (PointIndex vert : Points().Range()) { NgFlatArray procs = procs_of_vert[vert]; for (int j = 0; j < procs.Size(); j++) @@ -446,34 +449,34 @@ namespace netgen int dest = procs[j]; // !! we also use this as offsets for MPI-type, if this is changed, also change ReceiveParallelMesh verts_of_proc.Add (dest, vert - IndexBASE()); - loc_num_of_vert.Add (vert, verts_of_proc[dest].Size()); + loc_num_of_vert.Add (vert, verts_of_proc[dest].Size() -1+IndexBASE()); } } tbuildvertex.Stop(); PrintMessage ( 3, "Sending Vertices - vertices"); - Array point_types(ntasks-1); + Array point_types(ntasks-1); for (int dest = 1; dest < ntasks; dest++) { NgFlatArray verts = verts_of_proc[dest]; - // sendrequests.Append (MyMPI_ISend (verts, dest, MPI_TAG_MESH+1, comm)); - sendrequests.Append (comm.ISend (FlatArray(verts), dest, MPI_TAG_MESH+1)); + // sendrequests.Append (MyMPI_ISend (verts, dest, NG_MPI_TAG_MESH+1, comm)); + sendrequests += comm.ISend (FlatArray(verts), dest, NG_MPI_TAG_MESH+1); - MPI_Datatype mptype = MeshPoint::MyGetMPIType(); + NG_MPI_Datatype mptype = MeshPoint::MyGetMPIType(); int numv = verts.Size(); NgArray blocklen (numv); blocklen = 1; - MPI_Type_indexed (numv, (numv == 0) ? nullptr : &blocklen[0], + NG_MPI_Type_indexed (numv, (numv == 0) ? nullptr : &blocklen[0], (numv == 0) ? nullptr : reinterpret_cast (&verts[0]), mptype, &point_types[dest-1]); - MPI_Type_commit (&point_types[dest-1]); + NG_MPI_Type_commit (&point_types[dest-1]); - MPI_Request request; - MPI_Isend( points.Data(), 1, point_types[dest-1], dest, MPI_TAG_MESH+1, comm, &request); - sendrequests.Append (request); + NG_MPI_Request request; + NG_MPI_Isend( points.Data(), 1, point_types[dest-1], dest, NG_MPI_TAG_MESH+1, comm, &request); + sendrequests += request; } @@ -533,19 +536,19 @@ namespace netgen } } } - Array req_per; + NgMPI_Requests req_per; for(int dest = 1; dest < ntasks; dest++) - // req_per.Append(MyMPI_ISend(pp_data[dest], dest, MPI_TAG_MESH+1, comm)); - req_per.Append(comm.ISend(FlatArray(pp_data[dest]), dest, MPI_TAG_MESH+1)); - MyMPI_WaitAll(req_per); + // req_per.Append(MyMPI_ISend(pp_data[dest], dest, NG_MPI_TAG_MESH+1, comm)); + req_per += comm.ISend(FlatArray(pp_data[dest]), dest, NG_MPI_TAG_MESH+1); + req_per.WaitAll(); PrintMessage ( 3, "Sending Vertices - distprocs"); tbuilddistpnums.Start(); Array num_distpnums(ntasks); num_distpnums = 0; - - for (int vert = 1; vert <= GetNP(); vert++) + // for (int vert = 1; vert <= GetNP(); vert++) + for (PointIndex vert : Points().Range()) { FlatArray procs = procs_of_vert[vert]; for (auto p : procs) @@ -553,8 +556,8 @@ namespace netgen } DynamicTable distpnums (num_distpnums); - - for (int vert = 1; vert <= GetNP(); vert++) + // for (int vert = 1; vert <= GetNP(); vert++) + for (PointIndex vert : Points().Range()) { NgFlatArray procs = procs_of_vert[vert]; for (int j = 0; j < procs.Size(); j++) @@ -570,7 +573,7 @@ namespace netgen tbuilddistpnums.Stop(); for ( int dest = 1; dest < ntasks; dest ++ ) - sendrequests.Append (comm.ISend (distpnums[dest], dest, MPI_TAG_MESH+1)); + sendrequests += comm.ISend (distpnums[dest], dest, NG_MPI_TAG_MESH+1); @@ -579,32 +582,32 @@ namespace netgen tbuildelementtable.Start(); Array elarraysize (ntasks); elarraysize = 0; - for ( int ei = 1; ei <= GetNE(); ei++) + // for (int ei = 1; ei <= GetNE(); ei++) + for (ElementIndex ei : VolumeElements().Range()) { const Element & el = VolumeElement (ei); // int dest = el.GetPartition(); - int dest = vol_partition[ei-1]; + int dest = vol_partition[ei]; elarraysize[dest] += 3 + el.GetNP(); } DynamicTable elementarrays(elarraysize); - - for (int ei = 1; ei <= GetNE(); ei++) + + for (ElementIndex ei : VolumeElements().Range()) { const Element & el = VolumeElement (ei); - // int dest = el.GetPartition(); - int dest = vol_partition[ei-1]; + int dest = vol_partition[ei]; - elementarrays.Add (dest, ei); + elementarrays.Add (dest, int(ei+1)); elementarrays.Add (dest, el.GetIndex()); elementarrays.Add (dest, el.GetNP()); - for (int i = 0; i < el.GetNP(); i++) - elementarrays.Add (dest, el[i]); + for (PointIndex pi : el.PNums()) + elementarrays.Add (dest, pi); } tbuildelementtable.Stop(); for (int dest = 1; dest < ntasks; dest ++ ) - sendrequests.Append (comm.ISend (elementarrays[dest], dest, MPI_TAG_MESH+2)); + sendrequests += comm.ISend (elementarrays[dest], dest, NG_MPI_TAG_MESH+2); PrintMessage ( 3, "Sending Face Descriptors" ); @@ -621,7 +624,7 @@ namespace netgen } for (int dest = 1; dest < ntasks; dest++) - sendrequests.Append (comm.ISend (fddata, dest, MPI_TAG_MESH+3)); + sendrequests += comm.ISend (fddata, dest, NG_MPI_TAG_MESH+3); /** Surface Elements **/ @@ -630,7 +633,7 @@ namespace netgen size_t nse = GetNSE(); NgArray ided_sel(nse); ided_sel = -1; - bool has_ided_sels = false; + [[maybe_unused]] bool has_ided_sels = false; if(GetNE() && has_periodic) //we can only have identified surf-els if we have vol-els (right?) { Array os1, os2; @@ -661,8 +664,8 @@ namespace netgen if(os1.Size()>1) { throw NgException("SurfaceElement identified with more than one other??"); } - const Element2d & sel2 = (*this)[sei]; - auto points2 = sel2.PNums(); + // const Element2d & sel2 = (*this)[sei]; + // auto points2 = sel2.PNums(); has_ided_sels = true; ided_sel[sei] = os1[0]; ided_sel[os1[0]] = sei; @@ -697,7 +700,7 @@ namespace netgen }); // distribute sel data for (int dest = 1; dest < ntasks; dest++) - sendrequests.Append (comm.ISend(selbuf[dest], dest, MPI_TAG_MESH+4)); + sendrequests += comm.ISend(selbuf[dest], dest, NG_MPI_TAG_MESH+4); /** Segments **/ @@ -849,7 +852,7 @@ namespace netgen }); // distribute segment data for (int dest = 1; dest < ntasks; dest++) - sendrequests.Append (comm.ISend(segm_buf[dest], dest, MPI_TAG_MESH+5)); + sendrequests += comm.ISend(segm_buf[dest], dest, NG_MPI_TAG_MESH+5); /** Point-Elements **/ PrintMessage ( 3, "Point-Elements ..."); @@ -870,33 +873,33 @@ namespace netgen iterate_zdes([&](const auto & pack, auto dest) { zde_buf.Add(dest, pack); }); for (int dest = 1; dest < ntasks; dest++) - { sendrequests.Append (comm.ISend(zde_buf[dest], dest, MPI_TAG_MESH+6)); } + sendrequests += comm.ISend(zde_buf[dest], dest, NG_MPI_TAG_MESH+6); PrintMessage ( 3, "now wait ..."); - MyMPI_WaitAll (sendrequests); + sendrequests.WaitAll(); // clean up MPI-datatypes we allocated earlier for (auto t : point_types) - { MPI_Type_free(&t); } + { NG_MPI_Type_free(&t); } paralleltop -> SetNV_Loc2Glob (0); paralleltop -> SetNV (0); paralleltop -> EnumeratePointsGlobally(); PrintMessage ( 3, "Sending names"); - sendrequests.SetSize(3*ntasks); /** Send bc/mat/cd*-names **/ // nr of names - ArrayMem nnames{0,0,0,0}; + std::array nnames{0,0,0,0}; nnames[0] = materials.Size(); nnames[1] = bcnames.Size(); nnames[2] = GetNCD2Names(); nnames[3] = GetNCD3Names(); int tot_nn = nnames[0] + nnames[1] + nnames[2] + nnames[3]; - for( int k = 1; k < ntasks; k++) - sendrequests[k] = comm.ISend(nnames, k, MPI_TAG_MESH+7); - // (void) MPI_Isend(nnames, 4, MPI_INT, k, MPI_TAG_MESH+6, comm, &sendrequests[k]); + + NgMPI_Requests requ; + requ += comm.IBcast (nnames); + auto iterate_names = [&](auto func) { for (int k = 0; k < nnames[0]; k++) func(materials[k]); for (int k = 0; k < nnames[1]; k++) func(bcnames[k]); @@ -904,27 +907,27 @@ namespace netgen for (int k = 0; k < nnames[3]; k++) func(cd3names[k]); }; // sizes of names - NgArray name_sizes(tot_nn); + Array name_sizes(tot_nn); tot_nn = 0; iterate_names([&](auto ptr) { name_sizes[tot_nn++] = (ptr==NULL) ? 0 : ptr->size(); }); - for( int k = 1; k < ntasks; k++) - (void) MPI_Isend(&name_sizes[0], tot_nn, MPI_INT, k, MPI_TAG_MESH+7, comm, &sendrequests[ntasks+k]); + + requ += comm.IBcast (name_sizes); // names int strs = 0; iterate_names([&](auto ptr) { strs += (ptr==NULL) ? 0 : ptr->size(); }); - NgArray compiled_names(strs); + Array compiled_names(strs); strs = 0; iterate_names([&](auto ptr) { if (ptr==NULL) return; auto& name = *ptr; for (int j=0; j < name.size(); j++) compiled_names[strs++] = name[j]; }); - for( int k = 1; k < ntasks; k++) - (void) MPI_Isend(&(compiled_names[0]), strs, MPI_CHAR, k, MPI_TAG_MESH+7, comm, &sendrequests[2*ntasks+k]); + + requ += comm.IBcast (compiled_names); PrintMessage ( 3, "wait for names"); - MyMPI_WaitAll (sendrequests); + requ.WaitAll(); comm.Barrier(); @@ -937,13 +940,13 @@ namespace netgen self.segments = Array(0); self.pointelements = Array(0); self.lockedpoints = Array(0); + /* auto cleanup_ptr = [](auto & ptr) { if (ptr != nullptr) { delete ptr; ptr = nullptr; } }; - /* cleanup_ptr(self.boundaryedges); cleanup_ptr(self.segmentht); cleanup_ptr(self.surfelementht); @@ -955,15 +958,15 @@ namespace netgen self.openelements = NgArray(0); self.opensegments = NgArray(0); self.numvertices = 0; - self.mlbetweennodes = NgArray,PointIndex::BASE> (0); - self.mlparentelement = NgArray(0); - self.mlparentsurfaceelement = NgArray(0); + self.mlbetweennodes = Array,PointIndex> (0); + self.mlparentelement = Array(0); + self.mlparentsurfaceelement = Array(0); self.curvedelems = make_unique (self); self.clusters = make_unique (self); self.ident = make_unique (self); self.topology = MeshTopology(*this); self.topology.Update(); - self.BuildElementSearchTree(); + self.BuildElementSearchTree(3); // const_cast(*this).DeleteMesh(); @@ -991,7 +994,7 @@ namespace netgen NgMPI_Comm comm = GetCommunicator(); int id = comm.Rank(); - int ntasks = comm.Size(); + // int ntasks = comm.Size(); int dim; comm.Bcast(dim); @@ -1006,7 +1009,7 @@ namespace netgen timer_pts.Start(); Array verts; - comm.Recv (verts, 0, MPI_TAG_MESH+1); + comm.Recv (verts, 0, NG_MPI_TAG_MESH+1); int numvert = verts.Size(); paralleltop -> SetNV (numvert); @@ -1017,21 +1020,21 @@ namespace netgen for (int vert = 0; vert < numvert; vert++) { - int globvert = verts[vert] + IndexBASE(); + PointIndex globvert = verts[vert] + IndexBASE(); // paralleltop->SetLoc2Glob_Vert ( vert+1, globvert ); paralleltop->L2G (PointIndex(vert+PointIndex::BASE)) = globvert; - glob2loc_vert_ht.Set (globvert, vert+1); + glob2loc_vert_ht.Set (globvert, vert+PointIndex::BASE); } for (int i = 0; i < numvert; i++) AddPoint (netgen::Point<3> (0,0,0)); - MPI_Datatype mptype = MeshPoint::MyGetMPIType(); - MPI_Status status; - MPI_Recv( points.Data(), numvert, mptype, 0, MPI_TAG_MESH+1, comm, &status); + NG_MPI_Datatype mptype = MeshPoint::MyGetMPIType(); + NG_MPI_Status status; + NG_MPI_Recv( points.Data(), numvert, mptype, 0, NG_MPI_TAG_MESH+1, comm, &status); Array pp_data; - comm.Recv(pp_data, 0, MPI_TAG_MESH+1); + comm.Recv(pp_data, 0, NG_MPI_TAG_MESH+1); int maxidentnr = pp_data[0]; auto & idents = GetIdentifications(); @@ -1052,7 +1055,7 @@ namespace netgen } Array dist_pnums; - comm.Recv (dist_pnums, 0, MPI_TAG_MESH+1); + comm.Recv (dist_pnums, 0, NG_MPI_TAG_MESH+1); for (int hi = 0; hi < dist_pnums.Size(); hi += 3) paralleltop -> @@ -1067,7 +1070,7 @@ namespace netgen RegionTimer reg(timer_els); Array elarray; - comm.Recv (elarray, 0, MPI_TAG_MESH+2); + comm.Recv (elarray, 0, NG_MPI_TAG_MESH+2); for (int ind = 0, elnum = 1; ind < elarray.Size(); elnum++) { @@ -1086,7 +1089,7 @@ namespace netgen { Array fddata; - comm.Recv (fddata, 0, MPI_TAG_MESH+3); + comm.Recv (fddata, 0, NG_MPI_TAG_MESH+3); for (int i = 0; i < fddata.Size(); i += 6) { int faceind = AddFaceDescriptor @@ -1101,7 +1104,7 @@ namespace netgen RegionTimer reg(timer_sels); Array selbuf; - comm.Recv ( selbuf, 0, MPI_TAG_MESH+4); + comm.Recv ( selbuf, 0, NG_MPI_TAG_MESH+4); int nlocsel = selbuf.Size(); paralleltop -> SetNSE ( nlocsel ); @@ -1124,9 +1127,9 @@ namespace netgen { // NgArray segmbuf; - // MyMPI_Recv ( segmbuf, 0, MPI_TAG_MESH+5, comm); + // MyMPI_Recv ( segmbuf, 0, NG_MPI_TAG_MESH+5, comm); Array segmbuf; - comm.Recv (segmbuf, 0, MPI_TAG_MESH+5); + comm.Recv (segmbuf, 0, NG_MPI_TAG_MESH+5); Segment seg; int globsegi; @@ -1158,7 +1161,7 @@ namespace netgen seg.domin = seg.surfnr1; seg.domout = seg.surfnr2; - if ( seg.pnums[0] >0 && seg.pnums[1] > 0 ) + if ( seg.pnums[0].IsValid() && seg.pnums[1].IsValid() ) { paralleltop-> SetLoc2Glob_Segm ( segi, globsegi ); @@ -1170,7 +1173,7 @@ namespace netgen { /** 0d-Elements **/ Array zdes; - comm.Recv ( zdes, 0, MPI_TAG_MESH+6); + comm.Recv ( zdes, 0, NG_MPI_TAG_MESH+6); pointelements.SetSize(zdes.Size()); for (auto k : Range(pointelements)) { auto & el = pointelements[k]; @@ -1182,9 +1185,20 @@ namespace netgen // paralleltop -> SetNV_Loc2Glob (0); paralleltop -> EnumeratePointsGlobally(); /** Recv bc-names **/ + /* ArrayMem nnames{0,0,0,0}; - // MPI_Recv(nnames, 4, MPI_INT, 0, MPI_TAG_MESH+6, comm, MPI_STATUS_IGNORE); - comm.Recv(nnames, 0, MPI_TAG_MESH+7); + // NG_MPI_Recv(nnames, 4, NG_MPI_INT, 0, NG_MPI_TAG_MESH+6, comm, NG_MPI_STATUS_IGNORE); + comm.Recv(nnames, 0, NG_MPI_TAG_MESH+7); + */ + + // Array recvrequests(1); + std::array nnames; + /* + recvrequests[0] = comm.IBcast (nnames); + MyMPI_WaitAll (recvrequests); + */ + comm.IBcast (nnames).Wait(); + // cout << "nnames = " << FlatArray(nnames) << endl; materials.SetSize(nnames[0]); bcnames.SetSize(nnames[1]); @@ -1192,19 +1206,29 @@ namespace netgen cd3names.SetSize(nnames[3]); int tot_nn = nnames[0] + nnames[1] + nnames[2] + nnames[3]; - NgArray name_sizes(tot_nn); - MPI_Recv(&name_sizes[0], tot_nn, MPI_INT, 0, MPI_TAG_MESH+7, comm, MPI_STATUS_IGNORE); + Array name_sizes(tot_nn); + // NG_MPI_Recv(&name_sizes[0], tot_nn, NG_MPI_INT, 0, NG_MPI_TAG_MESH+7, comm, NG_MPI_STATUS_IGNORE); + /* + recvrequests[0] = comm.IBcast (name_sizes); + MyMPI_WaitAll (recvrequests); + */ + comm.IBcast (name_sizes).Wait(); + int tot_size = 0; for (int k = 0; k < tot_nn; k++) tot_size += name_sizes[k]; - NgArray compiled_names(tot_size); - MPI_Recv(&(compiled_names[0]), tot_size, MPI_CHAR, 0, MPI_TAG_MESH+7, comm, MPI_STATUS_IGNORE); - + // NgArray compiled_names(tot_size); + // NG_MPI_Recv(&(compiled_names[0]), tot_size, NG_MPI_CHAR, 0, NG_MPI_TAG_MESH+7, comm, NG_MPI_STATUS_IGNORE); + Array compiled_names(tot_size); + // recvrequests[0] = comm.IBcast (compiled_names); + // MyMPI_WaitAll (recvrequests); + comm.IBcast (compiled_names).Wait(); + tot_nn = tot_size = 0; auto write_names = [&] (auto & array) { for (int k = 0; k < array.Size(); k++) { int s = name_sizes[tot_nn]; - array[k] = new string(&compiled_names[tot_size], s); + array[k] = s ? new string(&compiled_names[tot_size], s) : new string(""); tot_nn++; tot_size += s; } @@ -1294,21 +1318,21 @@ namespace netgen eptr.Append (eind.Size()); const Element & el = VolumeElement(i+1); for (int j = 0; j < el.GetNP(); j++) - eind.Append (el[j]-1); + eind.Append (el[j]-IndexBASE()); } for (int i = 0; i < GetNSE(); i++) { eptr.Append (eind.Size()); const Element2d & el = SurfaceElement(i+1); for (int j = 0; j < el.GetNP(); j++) - eind.Append (el[j]-1); + eind.Append (el[j]-IndexBASE()); } for (int i = 0; i < GetNSeg(); i++) { eptr.Append (eind.Size()); const Segment & el = LineSegment(i+1); - eind.Append (el[0]-1); - eind.Append (el[1]-1); + eind.Append (el[0]-IndexBASE()); + eind.Append (el[1]-IndexBASE()); } eptr.Append (eind.Size()); NgArray epart(ne), npart(nn); @@ -1321,13 +1345,10 @@ namespace netgen if (nparts == 1) { for (int i = 0; i < GetNE(); i++) - // VolumeElement(i+1).SetPartition(1); vol_partition[i]= 1; for (int i = 0; i < GetNSE(); i++) - // SurfaceElement(i+1).SetPartition(1); surf_partition[i] = 1; for (int i = 0; i < GetNSeg(); i++) - // LineSegment(i+1).SetPartition(1); seg_partition[i] = 1; } @@ -1346,23 +1367,14 @@ namespace netgen NULL, NULL, &edgecut, &epart[0], &npart[0]); tm.Stop(); - - /* - METIS_PartMeshNodal (&ne, &nn, &eptr[0], &eind[0], NULL, NULL, &nparts, - NULL, NULL, - &edgecut, &epart[0], &npart[0]); - */ + PrintMessage (3, "metis complete"); - // cout << "done" << endl; for (int i = 0; i < GetNE(); i++) - // VolumeElement(i+1).SetPartition(epart[i] + 1); vol_partition[i]= epart[i] + 1; for (int i = 0; i < GetNSE(); i++) - // SurfaceElement(i+1).SetPartition(epart[i+GetNE()] + 1); surf_partition[i] = epart[i+GetNE()] + 1; for (int i = 0; i < GetNSeg(); i++) - // LineSegment(i+1).SetPartition(epart[i+GetNE()+GetNSE()] + 1); seg_partition[i] = epart[i+GetNE()+GetNSE()] + 1; } @@ -1856,13 +1868,15 @@ namespace netgen void Mesh :: PartHybridMesh () { -#ifdef METIS + throw Exception("PartHybridMesh not supported"); +#ifdef METISxxx int ne = GetNE(); int nn = GetNP(); int nedges = topology.GetNEdges(); - idxtype *xadj, * adjacency, *v_weights = NULL, *e_weights = NULL; + idxtype *xadj, * adjacency; + // idxtype *v_weights = NULL, *e_weights = NULL; int weightflag = 0; int numflag = 0; @@ -1879,10 +1893,11 @@ namespace netgen NgArray cnt(nn+1); cnt = 0; - for ( int edge = 1; edge <= nedges; edge++ ) + for ( int edge = 0; edge < nedges; edge++ ) { - int v1, v2; - topology.GetEdgeVertices ( edge, v1, v2); + // int v1, v2; + // topology.GetEdgeVertices ( edge, v1, v2); + auto [v1,v2] = topology.GetEdgeVertices(edge); cnt[v1-1] ++; cnt[v2-1] ++; } @@ -1896,10 +1911,11 @@ namespace netgen adjacency = new idxtype[xadj[nn]]; cnt = 0; - for ( int edge = 1; edge <= nedges; edge++ ) + for ( int edge = 0; edge < nedges; edge++ ) { - int v1, v2; - topology.GetEdgeVertices ( edge, v1, v2); + // int v1, v2; + // topology.GetEdgeVertices ( edge, v1, v2); + auto [v1,v2] = topology.GetEdgeVertices(edge); adjacency[ xadj[v1-1] + cnt[v1-1] ] = v2-1; adjacency[ xadj[v2-1] + cnt[v2-1] ] = v1-1; cnt[v1-1]++; @@ -1951,6 +1967,8 @@ namespace netgen void Mesh :: PartDualHybridMesh ( ) // NgArray & neloc ) { + throw Exception("PartDualHybridMesh not supported"); +#ifdef OLD #ifdef METIS int ne = GetNE(); @@ -1973,7 +1991,7 @@ namespace netgen facevolels1 = -1; facevolels2 = -1; - NgArray elfaces; + // NgArray elfaces; xadj = new idxtype[ne+1]; part = new idxtype[ne]; @@ -1983,16 +2001,17 @@ namespace netgen for ( int el=1; el <= ne; el++ ) { Element volel = VolumeElement(el); - topology.GetElementFaces(el, elfaces); + // topology.GetElementFaces(el, elfaces); + auto elfaces = topology.GetFaces (ElementIndex(el-1)); for ( int i = 0; i < elfaces.Size(); i++ ) { - if ( facevolels1[elfaces[i]-1] == -1 ) - facevolels1[elfaces[i]-1] = el; + if ( facevolels1[elfaces[i]] == -1 ) + facevolels1[elfaces[i]] = el; else { - facevolels2[elfaces[i]-1] = el; - cnt[facevolels1[elfaces[i]-1]-1]++; - cnt[facevolels2[elfaces[i]-1]-1]++; + facevolels2[elfaces[i]] = el; + cnt[facevolels1[elfaces[i]]-1]++; + cnt[facevolels2[elfaces[i]]-1]++; } } } @@ -2062,7 +2081,8 @@ namespace netgen #else cout << "partdualmesh not available" << endl; #endif - +#endif + } @@ -2128,7 +2148,6 @@ namespace netgen idxtype *v_weights = NULL, *e_weights = NULL; - idxtype weightflag = 0; // int numflag = 0; idxtype nparts = ntasks - 1; @@ -2139,6 +2158,7 @@ namespace netgen BubbleSort (adjacency.Range (xadj[el], xadj[el+1])); #ifdef METIS4 + idxtype weightflag = 0; int options[5]; options[0] = 0; METIS_PartGraphKway ( &ne, &xadj[0], &adjacency[0], v_weights, e_weights, &weightflag, diff --git a/libsrc/meshing/paralleltop.cpp b/libsrc/meshing/paralleltop.cpp index 79e784ec..2352d48a 100644 --- a/libsrc/meshing/paralleltop.cpp +++ b/libsrc/meshing/paralleltop.cpp @@ -1,6 +1,3 @@ -// #ifdef PARALLEL - - #include #include "paralleltop.hpp" @@ -94,9 +91,9 @@ namespace netgen Array first_master_point(comm.Size()); comm.AllGather (num_master_points, first_master_point); - auto max_oldv = comm.AllReduce (Max (glob_vert.Range(0, oldnv)), MPI_MAX); - if (comm.AllReduce (oldnv, MPI_SUM) == 0) - max_oldv = PointIndex::BASE-1; + auto max_oldv = comm.AllReduce (Max (glob_vert.Range(0, oldnv)), NG_MPI_MAX); + if (comm.AllReduce (oldnv, NG_MPI_SUM) == 0) + max_oldv = long(PointIndex::BASE)-1; size_t num_glob_points = max_oldv+1; for (int i = 0; i < comm.Size(); i++) @@ -138,16 +135,17 @@ namespace netgen for (auto p : dps) send_data[p][nsend[p]++] = L2G(pi); - Array requests; + NgMPI_Requests requests; for (int i = 0; i < comm.Size(); i++) { if (nsend[i]) - requests.Append (comm.ISend (send_data[i], i, 200)); + requests += comm.ISend (send_data[i], i, 200); if (nrecv[i]) - requests.Append (comm.IRecv (recv_data[i], i, 200)); + requests += comm.IRecv (recv_data[i], i, 200); } - MyMPI_WaitAll (requests); + // MyMPI_WaitAll (requests); + requests.WaitAll(); Array cnt(comm.Size()); cnt = 0; @@ -186,7 +184,7 @@ namespace netgen if (mesh.mlbetweennodes.Size() == mesh.Points().Size()) { - NgArray,PointIndex::BASE> hml { mesh.mlbetweennodes }; + Array,PointIndex> hml { mesh.mlbetweennodes }; for (PointIndex pi : Range(mesh.Points())) mesh.mlbetweennodes[inv_index[pi]] = hml[pi]; } @@ -292,7 +290,7 @@ namespace netgen - + /* void ParallelMeshTopology :: UpdateCoarseGridGlobal () { @@ -319,7 +317,7 @@ namespace netgen { topology.GetElementFaces (el, faces); topology.GetElementEdges (el, edges); - const Element & volel = mesh.VolumeElement (el); + // const Element & volel = mesh.VolumeElement (el); // NgArray & sendarray = *sendarrays[volel.GetPartition()]; NgArray & sendarray = *sendarrays[mesh.vol_partition[el-1]]; @@ -333,7 +331,7 @@ namespace netgen for (int el = 1; el <= mesh.GetNSE(); el++) { topology.GetSurfaceElementEdges (el, edges); - const Element2d & surfel = mesh.SurfaceElement (el); + // const Element2d & surfel = mesh.SurfaceElement (el); // NgArray & sendarray = *sendarrays[surfel.GetPartition()]; NgArray & sendarray = *sendarrays[mesh.surf_partition[el-1]]; @@ -342,10 +340,10 @@ namespace netgen sendarray.Append (topology.GetSurfaceElementFace (el)); } - Array sendrequests; + Array sendrequests; for (int dest = 1; dest < ntasks; dest++) - // sendrequests.Append (MyMPI_ISend (*sendarrays[dest], dest, MPI_TAG_MESH+10, comm)); - sendrequests.Append (comm.ISend (FlatArray(*sendarrays[dest]), dest, MPI_TAG_MESH+10)); + // sendrequests.Append (MyMPI_ISend (*sendarrays[dest], dest, NG_MPI_TAG_MESH+10, comm)); + sendrequests.Append (comm.ISend (FlatArray(*sendarrays[dest]), dest, NG_MPI_TAG_MESH+10)); MyMPI_WaitAll (sendrequests); for (int dest = 1; dest < ntasks; dest++) @@ -356,9 +354,9 @@ namespace netgen { // NgArray recvarray; - // MyMPI_Recv (recvarray, 0, MPI_TAG_MESH+10, comm); + // MyMPI_Recv (recvarray, 0, NG_MPI_TAG_MESH+10, comm); Array recvarray; - comm.Recv (recvarray, 0, MPI_TAG_MESH+10); // MyMPI_Recv (recvarray, 0, MPI_TAG_MESH+10, comm); + comm.Recv (recvarray, 0, NG_MPI_TAG_MESH+10); // MyMPI_Recv (recvarray, 0, NG_MPI_TAG_MESH+10, comm); int ii = 0; @@ -387,7 +385,8 @@ namespace netgen is_updated = true; } - + */ + void ParallelMeshTopology :: IdentifyVerticesAfterRefinement() { @@ -409,11 +408,11 @@ namespace netgen PrintMessage (1, "update parallel topology"); - const MeshTopology & topology = mesh.GetTopology(); + // const MeshTopology & topology = mesh.GetTopology(); Array cnt_send(ntasks); - int maxsize = comm.AllReduce (mesh.mlbetweennodes.Size(), MPI_MAX); + int maxsize = comm.AllReduce (mesh.mlbetweennodes.Size(), NG_MPI_MAX); // update new vertices after mesh-refinement if (maxsize > 0) { @@ -437,7 +436,7 @@ namespace netgen for (int dist : GetDistantProcs(pi)) dest2vert.Add (dist, pi); - for (PointIndex pi = PointIndex::BASE; pi < newnv+PointIndex::BASE; pi++) + for (PointIndex pi = IndexBASE(); pi < newnv+IndexBASE(); pi++) if (auto [v1,v2] = mesh.mlbetweennodes[pi]; v1.IsValid()) { auto procs1 = GetDistantProcs(v1); @@ -500,8 +499,7 @@ namespace netgen } DynamicTable recv_verts(ntasks); - // MyMPI_ExchangeTable (send_verts, recv_verts, MPI_TAG_MESH+9, comm); - comm.ExchangeTable (send_verts, recv_verts, MPI_TAG_MESH+9); + comm.ExchangeTable (send_verts, recv_verts, NG_MPI_TAG_MESH+9); for (int dest = 0; dest < ntasks; dest++) if (dest != id) @@ -533,7 +531,7 @@ namespace netgen } } - changed = comm.AllReduce (changed, MPI_LOR); + changed = comm.AllReduce (changed, NG_MPI_LOR); } } @@ -542,7 +540,7 @@ namespace netgen // static int timerv = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex vertices"); static int timere = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex edges"); - static int timerf = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex faces"); + // static int timerf = NgProfiler::CreateTimer ("UpdateCoarseGrid - ex faces"); NgProfiler::StartTimer (timere); @@ -558,8 +556,8 @@ namespace netgen for (int dist : GetDistantProcs(pi)) dest2vert.Add (dist, pi); - // MPI_Group_free(&MPI_LocalGroup); - // MPI_Comm_free(&MPI_LocalComm); + // NG_MPI_Group_free(&NG_MPI_LocalGroup); + // NG_MPI_Comm_free(&NG_MPI_LocalComm); } @@ -639,10 +637,11 @@ namespace netgen // exchange edges cnt_send = 0; - int v1, v2; + // int v1, v2; for (int edge = 1; edge <= ned; edge++) { - topology.GetEdgeVertices (edge, v1, v2); + // topology.GetEdgeVertices (edge, v1, v2); + auto [v1,v2] = topology.GetEdgeVertices(edge-1); /* for (int dest = 1; dest < ntasks; dest++) // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) @@ -662,7 +661,8 @@ namespace netgen for (int edge = 1; edge <= ned; edge++) { - topology.GetEdgeVertices (edge, v1, v2); + // topology.GetEdgeVertices (edge, v1, v2); + auto [v1,v2] = topology.GetEdgeVertices(edge-1); for (int dest = 0; dest < ntasks; dest++) // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) if (GetDistantProcs(v1).Contains(dest) && GetDistantProcs(v2).Contains(dest)) @@ -680,7 +680,8 @@ namespace netgen for (int edge : dest2edge[dest]) { - topology.GetEdgeVertices (edge, v1, v2); + // topology.GetEdgeVertices (edge, v1, v2); + auto [v1,v2] = topology.GetEdgeVertices(edge-1); // if (IsExchangeVert (dest, v1) && IsExchangeVert (dest, v2)) if (GetDistantProcs(v1).Contains(dest) && GetDistantProcs(v2).Contains(dest)) { @@ -690,12 +691,8 @@ namespace netgen } } - // cout << "UpdateCoarseGrid - edges mpi-exchange" << endl; - // TABLE recv_edges(ntasks); DynamicTable recv_edges(ntasks); - // MyMPI_ExchangeTable (send_edges, recv_edges, MPI_TAG_MESH+9, comm); - comm.ExchangeTable (send_edges, recv_edges, MPI_TAG_MESH+9); - // cout << "UpdateCoarseGrid - edges mpi-exchange done" << endl; + comm.ExchangeTable (send_edges, recv_edges, NG_MPI_TAG_MESH+9); for (int dest = 0; dest < ntasks; dest++) { @@ -705,7 +702,8 @@ namespace netgen INDEX_2_CLOSED_HASHTABLE vert2edge(2*dest2edge[dest].Size()+10); for (int edge : dest2edge[dest]) { - topology.GetEdgeVertices (edge, v1, v2); + // topology.GetEdgeVertices (edge, v1, v2); + auto [v1,v2] = topology.GetEdgeVertices(edge-1); vert2edge.Set(INDEX_2(v1,v2), edge); } @@ -799,12 +797,8 @@ namespace netgen } } - // cout << "UpdateCoarseGrid - faces mpi-exchange" << endl; - // TABLE recv_faces(ntasks); DynamicTable recv_faces(ntasks); - // MyMPI_ExchangeTable (send_faces, recv_faces, MPI_TAG_MESH+9, comm); - comm.ExchangeTable (send_faces, recv_faces, MPI_TAG_MESH+9); - // cout << "UpdateCoarseGrid - faces mpi-exchange done" << endl; + comm.ExchangeTable (send_faces, recv_faces, NG_MPI_TAG_MESH+9); for (int dest = 0; dest < ntasks; dest++) { @@ -835,10 +829,9 @@ namespace netgen // EnumeratePointsGlobally(); is_updated = true; - // MPI_Group_free(&MPI_LocalGroup); - // MPI_Comm_free(&MPI_LocalComm); + // NG_MPI_Group_free(&NG_MPI_LocalGroup); + // NG_MPI_Comm_free(&NG_MPI_LocalComm); } } -// #endif diff --git a/libsrc/meshing/paralleltop.hpp b/libsrc/meshing/paralleltop.hpp index f9d60497..9c8b61a1 100644 --- a/libsrc/meshing/paralleltop.hpp +++ b/libsrc/meshing/paralleltop.hpp @@ -36,23 +36,23 @@ namespace netgen void UpdateCoarseGrid(); - [[deprecated("should not need it anymore")]] - void UpdateCoarseGridGlobal(); + // [[deprecated("should not need it anymore")]] + // void UpdateCoarseGridGlobal(); void IdentifyVerticesAfterRefinement(); void EnumeratePointsGlobally (); - void AddDistantProc (PointIndex pi, int proc) { loc2distvert.AddUnique (pi-PointIndex::BASE, proc); } + void AddDistantProc (PointIndex pi, int proc) { loc2distvert.AddUnique (pi-IndexBASE(), proc); } void AddDistantFaceProc (int edge, int proc) { loc2distface.AddUnique (edge, proc); } void AddDistantEdgeProc (int face, int proc) { loc2distedge.AddUnique (face, proc); } - FlatArray GetDistantProcs (PointIndex pi) const { return loc2distvert[pi-PointIndex::BASE]; } + FlatArray GetDistantProcs (PointIndex pi) const { return loc2distvert[pi-IndexBASE()]; } FlatArray GetDistantFaceProcs (int locnum) const { return loc2distface[locnum]; } FlatArray GetDistantEdgeProcs (int locnum) const { return loc2distedge[locnum]; } - auto & L2G (PointIndex pi) { return glob_vert[pi-PointIndex::BASE]; } - auto L2G (PointIndex pi) const { return glob_vert[pi-PointIndex::BASE]; } + auto & L2G (PointIndex pi) { return glob_vert[pi-IndexBASE()]; } + auto L2G (PointIndex pi) const { return glob_vert[pi-IndexBASE()]; } /// set number of local vertices, reset sizes of loc2dist_vert, isexchangevert... @@ -78,9 +78,9 @@ namespace netgen [[deprecated("Use L2G(pi) instead!")]] void SetLoc2Glob_Vert (int locnum, int globnum) { glob_vert[locnum-1] = globnum; } - // [[deprecated("Try to avoid global enumration!")]] + [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_Edge (int locnum, int globnum) { glob_edge[locnum-1] = globnum; } - // [[deprecated("Try to avoid global enumration!")]] + [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_Face (int locnum, int globnum) { glob_face[locnum-1] = globnum; } // [[deprecated("Try to avoid global enumration!")]] void SetLoc2Glob_VolEl (int locnum, int globnum) { glob_el[locnum-1] = globnum; } @@ -90,7 +90,7 @@ namespace netgen void SetLoc2Glob_Segm (int locnum, int globnum) { glob_segm[locnum-1] = globnum; } // [[deprecated("Try to avoid global enumration!")]] - int GetGlobalPNum (PointIndex locnum) const { return glob_vert[locnum-PointIndex::BASE]; } + int GetGlobalPNum (PointIndex locnum) const { return glob_vert[locnum-IndexBASE()]; } [[deprecated("Try to avoid global enumration!")]] int GetGlobalEdgeNum (int locnum) const { return glob_edge[locnum-1]; } [[deprecated("Try to avoid global enumration!")]] @@ -102,30 +102,30 @@ namespace netgen - [[deprecated("Use GetDistantPNums(locnum).Size() instead!")]] + // [[deprecated("Use GetDistantPNums(locnum).Size() instead!")]] int GetNDistantPNums (int locpnum) const { return loc2distvert[locpnum-1].Size(); } - [[deprecated("Use GetDistantFaceNums(locnum).Size() instead!")]] + // [[deprecated("Use GetDistantFaceNums(locnum).Size() instead!")]] int GetNDistantFaceNums (int locfacenum) const { return loc2distface[locfacenum-1].Size(); } - [[deprecated("Use GetDistantEdgeNums(locnum).Size() instead!")]] + // [[deprecated("Use GetDistantEdgeNums(locnum).Size() instead!")]] int GetNDistantEdgeNums ( int locedgenum) const { return loc2distedge[locedgenum-1].Size(); } - [[deprecated("Use GetDistantPNums(locnum) -> FlatArray instead!")]] + // [[deprecated("Use GetDistantPNums(locnum) -> FlatArray instead!")]] void GetDistantPNums (int locpnum, int * distpnums ) const { for (int i = 0; i < loc2distvert[locpnum-1].Size(); i++ ) distpnums[i] = loc2distvert[locpnum-1][i]; } - [[deprecated("Use GetDistantFaceNums(locnum) -> FlatArray instead!")]] + // [[deprecated("Use GetDistantFaceNums(locnum) -> FlatArray instead!")]] void GetDistantFaceNums (int locfacenum, int * distfacenums ) const { for ( int i = 0; i < loc2distface[locfacenum-1].Size(); i++ ) distfacenums[i] = loc2distface[locfacenum-1][i]; } - [[deprecated("Use GetDistantFaceNums(locnum) -> FlatArray instead!")]] + // [[deprecated("Use GetDistantFaceNums(locnum) -> FlatArray instead!")]] void GetDistantFaceNums (int locfacenum, NgArray & distfacenums ) const { // distfacenums = loc2distface[locfacenum-1]; @@ -135,14 +135,14 @@ namespace netgen distfacenums[i] = loc[i]; } - [[deprecated("Use GetDistantEdgeNums(locnum) -> FlatArray instead!")]] + // [[deprecated("Use GetDistantEdgeNums(locnum) -> FlatArray instead!")]] void GetDistantEdgeNums (int locedgenum, int * distedgenums ) const { for (int i = 0; i < loc2distedge[locedgenum-1].Size(); i++ ) distedgenums[i] = loc2distedge[locedgenum-1][i]; } - [[deprecated("Use GetDistantEdgeNums(locnum) -> FlatArray instead!")]] + // [[deprecated("Use GetDistantEdgeNums(locnum) -> FlatArray instead!")]] void GetDistantEdgeNums (int locedgenum, NgArray & distedgenums ) const { // distedgenums = loc2distedge[locedgenum-1]; diff --git a/libsrc/meshing/parser2.cpp b/libsrc/meshing/parser2.cpp index 03a4b87e..d1190ea4 100644 --- a/libsrc/meshing/parser2.cpp +++ b/libsrc/meshing/parser2.cpp @@ -334,23 +334,23 @@ void netrule :: LoadRule (istream & ist) { elements.Append (Element2d(TRIG)); - ist >> elements.Last().PNum(1); + ist >> (int&)elements.Last().PNum(1); ist >> ch; // ',' if (ch == COMMASIGN) { - ist >> elements.Last().PNum(2); + ist >> (int&)elements.Last().PNum(2); ist >> ch; // ',' } if (ch == COMMASIGN) { - ist >> elements.Last().PNum(3); + ist >> (int&)elements.Last().PNum(3); ist >> ch; // ',' } if (ch == COMMASIGN) { elements.Last().SetType (QUAD); - ist >> elements.Last().PNum(4); + ist >> (int&)elements.Last().PNum(4); ist >> ch; // ',' // const Element2d & el = elements.Last(); diff --git a/libsrc/meshing/parser3.cpp b/libsrc/meshing/parser3.cpp index 5f5a6365..bb18dad3 100644 --- a/libsrc/meshing/parser3.cpp +++ b/libsrc/meshing/parser3.cpp @@ -177,16 +177,16 @@ void vnetrule :: LoadRule (istream & ist) while (ch == '(') { face.SetType(TRIG); - ist >> face.PNum(1); + ist >> (int&)face.PNum(1); ist >> ch; // ',' - ist >> face.PNum(2); + ist >> (int&)face.PNum(2); ist >> ch; // ',' - ist >> face.PNum(3); + ist >> (int&)face.PNum(3); ist >> ch; // ')' or ',' if (ch == COMMASIGN) { face.SetType(QUAD); - ist >> face.PNum(4); + ist >> (int&)face.PNum(4); ist >> ch; // ')' } faces.Append (face); @@ -285,16 +285,16 @@ void vnetrule :: LoadRule (istream & ist) while (ch == '(') { face.SetType(TRIG); - ist >> face.PNum(1); + ist >> (int&)face.PNum(1); ist >> ch; // ',' - ist >> face.PNum(2); + ist >> (int&)face.PNum(2); ist >> ch; // ',' - ist >> face.PNum(3); + ist >> (int&)face.PNum(3); ist >> ch; // ')' or ',' if (ch == COMMASIGN) { face.SetType(QUAD); - ist >> face.PNum(4); + ist >> (int&)face.PNum(4); ist >> ch; // ')' } faces.Append (face); @@ -494,40 +494,40 @@ void vnetrule :: LoadRule (istream & ist) elements.Append (Element(TET)); // elements.Last().SetNP(1); - ist >> elements.Last().PNum(1); + ist >> (int&)elements.Last().PNum(1); ist >> ch; // ',' if (ch == COMMASIGN) { // elements.Last().SetNP(2); - ist >> elements.Last().PNum(2); + ist >> (int&)elements.Last().PNum(2); ist >> ch; // ',' } if (ch == COMMASIGN) { // elements.Last().SetNP(3); - ist >> elements.Last().PNum(3); + ist >> (int&)elements.Last().PNum(3); ist >> ch; // ',' } if (ch == COMMASIGN) { // elements.Last().SetNP(4); elements.Last().SetType(TET); - ist >> elements.Last().PNum(4); + ist >> (int&)elements.Last().PNum(4); ist >> ch; // ',' } if (ch == COMMASIGN) { // elements.Last().SetNP(5); elements.Last().SetType(PYRAMID); - ist >> elements.Last().PNum(5); + ist >> (int&)elements.Last().PNum(5); ist >> ch; // ',' } if (ch == COMMASIGN) { // elements.Last().SetNP(6); elements.Last().SetType(PRISM); - ist >> elements.Last().PNum(6); + ist >> (int&)elements.Last().PNum(6); ist >> ch; // ',' } @@ -535,14 +535,14 @@ void vnetrule :: LoadRule (istream & ist) { // elements.Last().SetNP(6); elements.Last().SetType(HEX); - ist >> elements.Last().PNum(7); + ist >> (int&)elements.Last().PNum(7); ist >> ch; // ',' } if (ch == COMMASIGN) { // elements.Last().SetNP(6); elements.Last().SetType(HEX); - ist >> elements.Last().PNum(8); + ist >> (int&)elements.Last().PNum(8); ist >> ch; // ',' } @@ -879,16 +879,16 @@ void vnetrule :: LoadRule (istream & ist) // NgArray & freeset = *freesets.Get(fs); NgArray & freesetedges = *freeedges.Last(); NgArray & freesetfaces = *freefaces.Get(fs); - int k,l; - INDEX ind; + // int k,l; + // INDEX ind; - for (k = 1; k <= freesetfaces.Size(); k++) + for (int k = 1; k <= freesetfaces.Size(); k++) { // threeint tr = freesetfaces.Get(k); - for (l = k+1; l <= freesetfaces.Size(); l++) + for (int l = k+1; l <= freesetfaces.Size(); l++) { - ind = NeighbourTrianglePoint(freesetfaces.Get(k), freesetfaces.Get(l)); + INDEX ind = NeighbourTrianglePoint(freesetfaces.Get(k), freesetfaces.Get(l)); if (!ind) continue; INDEX_3 f1(freesetfaces.Get(k).i1, @@ -897,7 +897,7 @@ void vnetrule :: LoadRule (istream & ist) INDEX_3 f2(freesetfaces.Get(l).i1, freesetfaces.Get(l).i2, freesetfaces.Get(l).i3); - INDEX_2 ed(0, 0); + PointIndices<2> ed(PointIndex::INVALID, PointIndex::INVALID); for (int f11 = 1; f11 <= 3; f11++) for (int f12 = 1; f12 <= 3; f12++) if (f11 != f12) @@ -916,8 +916,8 @@ void vnetrule :: LoadRule (istream & ist) { for (int elr = 1; elr <= 4; elr++) { - if (GetPointNrMod (eli, elr) == ed.I(1) && - GetPointNrMod (eli, elr+2) == ed.I(2)) + if (GetPointNrMod (eli, elr) == ed[0] && + GetPointNrMod (eli, elr+2) == ed[1]) { /* (*testout) << "ed is diagonal of rectangle" << endl; @@ -1014,14 +1014,15 @@ void Meshing3 :: LoadRules (const char * filename, const char ** prules) if (strcmp (buf, "rule") == 0) { - vnetrule * rule = new vnetrule; + // vnetrule * rule = new vnetrule; + auto rule = make_unique(); rule -> LoadRule(*ist); - rules.Append (rule); if (!rule->TestOk()) { PrintSysError ("Parser3d: Rule ", rules.Size(), " not ok"); exit (1); } + rules.Append (std::move(rule)); } else if (strcmp (buf, "tolfak") == 0) { diff --git a/libsrc/meshing/python_mesh.cpp b/libsrc/meshing/python_mesh.cpp index 363d6f93..e0e73858 100644 --- a/libsrc/meshing/python_mesh.cpp +++ b/libsrc/meshing/python_mesh.cpp @@ -8,8 +8,10 @@ #include #include "meshing.hpp" +#include "boundarylayer.hpp" // #include // #include +#include <../interface/rw_medit.hpp> #include <../interface/writeuser.hpp> #include <../include/nginterface.h> #include <../general/gzstream.h> @@ -23,52 +25,6 @@ public: }; -#ifdef NG_MPI4PY -#include - -struct mpi4py_comm { - mpi4py_comm() = default; - mpi4py_comm(MPI_Comm value) : value(value) {} - operator MPI_Comm () { return value; } - - MPI_Comm value; -}; - -namespace pybind11 { namespace detail { - template <> struct type_caster { - public: - PYBIND11_TYPE_CASTER(mpi4py_comm, _("mpi4py_comm")); - - // Python -> C++ - bool load(handle src, bool) { - PyObject *py_src = src.ptr(); - // Check that we have been passed an mpi4py communicator - if (PyObject_TypeCheck(py_src, &PyMPIComm_Type)) { - // Convert to regular MPI communicator - value.value = *PyMPIComm_Get(py_src); - } else { - return false; - } - - return !PyErr_Occurred(); - } - - // C++ -> Python - static handle cast(mpi4py_comm src, - return_value_policy /* policy */, - handle /* parent */) - { - // Create an mpi4py handle - return PyMPIComm_New(src.value); - } - }; -}} // namespace pybind11::detail - -#endif // NG_MPI4PY - - - - using namespace netgen; @@ -78,7 +34,11 @@ namespace netgen { extern bool netgen_executable_started; extern shared_ptr ng_geometry; - extern void Optimize2d (Mesh & mesh, MeshingParameters & mp); + extern void Optimize2d (Mesh & mesh, MeshingParameters & mp, int faceindex=0); +#ifdef NG_CGNS + extern tuple, vector, vector>, vector> ReadCGNSFile(const filesystem::path & filename, int base); + extern void WriteCGNSFile(shared_ptr mesh, const filesystem::path & filename, vector fields, vector> values, vector locations); +#endif // NG_CGNS } @@ -96,9 +56,6 @@ static Transformation<3> global_trafo(Vec<3> (0,0,0)); DLL_HEADER void ExportNetgenMeshing(py::module &m) { -#ifdef NG_MPI4PY - import_mpi4py(); -#endif // NG_MPI4PY py::register_exception(m, "NgException"); m.attr("_netgen_executable_started") = py::cast(netgen::netgen_executable_started); string script; @@ -126,51 +83,12 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::implicitly_convertible(); - py::class_ (m, "MPI_Comm") -#ifdef NG_MPI4PY - .def(py::init([] (mpi4py_comm comm) - { - return NgMPI_Comm(comm); - })) - .def_property_readonly ("mpi4py", [] (NgMPI_Comm comm) { return mpi4py_comm(comm); }) -#endif // NG_MPI4PY - .def_property_readonly ("rank", &NgMPI_Comm::Rank) - .def_property_readonly ("size", &NgMPI_Comm::Size) - .def("Barrier", &NgMPI_Comm::Barrier) - -#ifdef PARALLEL - .def("WTime", [](NgMPI_Comm & c) { return MPI_Wtime(); }) -#else - .def("WTime", [](NgMPI_Comm & c) { return -1.0; }) -#endif - .def("Sum", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, MPI_SUM); }) - .def("Min", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, MPI_MIN); }) - .def("Max", [](NgMPI_Comm & c, double x) { return c.AllReduce(x, MPI_MAX); }) - .def("Sum", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, MPI_SUM); }) - .def("Min", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, MPI_MIN); }) - .def("Max", [](NgMPI_Comm & c, int x) { return c.AllReduce(x, MPI_MAX); }) - .def("Sum", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, MPI_SUM); }) - .def("Min", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, MPI_MIN); }) - .def("Max", [](NgMPI_Comm & c, size_t x) { return c.AllReduce(x, MPI_MAX); }) - .def("SubComm", [](NgMPI_Comm & c, std::vector proc_list) { - Array procs(proc_list.size()); - for (int i = 0; i < procs.Size(); i++) - { procs[i] = proc_list[i]; } - if (!procs.Contains(c.Rank())) - { throw Exception("rank "+ToString(c.Rank())+" not in subcomm"); } - return c.SubCommunicator(procs); - }, py::arg("procs")); - ; - - -#ifdef NG_MPI4PY - py::implicitly_convertible(); -#endif // NG_MPI4PY - py::class_(m, "NGDummyArgument") .def("__bool__", []( NGDummyArgument &self ) { return false; } ) ; + + py::class_>(m, "LocalH"); py::class_> (m, "Point2d") .def(py::init()) @@ -183,6 +101,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def(py::self+Vec<2>()) .def(py::self-Vec<2>()) .def("__getitem__", [](Point<2>& self, int index) { return self[index]; }) + .def("__len__", [](Point<2>& /*unused*/) { return 2; }) ; py::implicitly_convertible>(); @@ -198,7 +117,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def(py::self-py::self) .def(py::self+Vec<3>()) .def(py::self-Vec<3>()) - .def("__getitem__", [](Point<2>& self, int index) { return self[index]; }) + .def("__getitem__", [](Point<3>& self, int index) { return self[index]; }) + .def("__len__", [](Point<3>& /*unused*/) { return 3; }) ; py::implicitly_convertible>(); @@ -260,6 +180,34 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::implicitly_convertible>(); + py::class_>(m, "Mat33") + .def(py::init([](py::tuple m) + { + if(m.size() != 9) + throw std::length_error("Invalid dimension of input array!"); + Mat<3,3> mat; + for(int i = 0; i < 3; i++) + for(int j = 0; j < 3; j++) + mat(i,j) = m[i*3+j].cast(); + return mat; + })) + .def("__getitem__", [](Mat<3,3>& mat, py::tuple index) + { + if(index.size() != 2) + throw std::length_error("Invalid dimension of input array!"); + return mat(index[0].cast(), index[1].cast()); + }) + .def("__setitem__", [](Mat<3,3>& mat, py::tuple index, double val) + { + if(index.size() != 2) + throw std::length_error("Invalid dimension of input array!"); + mat(index[0].cast(), index[1].cast()) = val; + }) + .def("__str__", &ToString>) + ; + + py::implicitly_convertible>(); + m.def ("Vec", FunctionPointer ([] (double x, double y, double z) { return global_trafo(Vec<3>(x,y,z)); })); m.def("Vec", [](py::array_t np_array) @@ -284,6 +232,11 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def("__mul__", [](Transformation<3> a, Transformation<3> b)->Transformation<3> { Transformation<3> res; res.Combine(a,b); return res; }) .def("__call__", [] (Transformation<3> trafo, Point<3> p) { return trafo(p); }) + .def_property("mat", &Transformation<3>::GetMatrix, + [](Transformation<3>& self, const Mat<3,3>& mat) + { + self.GetMatrix() = mat; + }) ; m.def ("GetTransformation", [] () { return global_trafo; }); @@ -381,7 +334,10 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) if(index<0 || index>2) throw py::index_error(); self(index) = val; - }) + }) + .def_property("singular", + [](const MeshPoint & pnt) { return pnt.Singularity(); }, + [](MeshPoint & pnt, double sing) { pnt.Singularity(sing); }) ; py::class_(m, "Element3D") @@ -456,7 +412,11 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::detail::field_descriptor { "refine", data_layout["refine"], sizeof(bool), py::format_descriptor::format(), - py::detail::npy_format_descriptor::dtype() } + py::detail::npy_format_descriptor::dtype() }, + py::detail::field_descriptor { + "curved", data_layout["curved"], sizeof(bool), + py::format_descriptor::format(), + py::detail::npy_format_descriptor::dtype()} }); } @@ -502,6 +462,13 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def_property("index", &Element2d::GetIndex, &Element2d::SetIndex) .def_property("curved", &Element2d::IsCurved, &Element2d::SetCurved) .def_property("refine", &Element2d::TestRefinementFlag, &Element2d::SetRefinementFlag) + .def_property_readonly("geominfo", [](const Element2d& self) -> py::list + { + py::list li; + for (const auto &pgi : self.GeomInfo()) + li.append(py::make_tuple(pgi.trignum, pgi.u, pgi.v)); + return li; + }) .def_property_readonly("vertices", FunctionPointer([](const Element2d & self) -> py::list { @@ -540,6 +507,10 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::detail::field_descriptor { "refine", data_layout["refine"], sizeof(bool), py::format_descriptor::format(), + py::detail::npy_format_descriptor::dtype() }, + py::detail::field_descriptor { + "curved", data_layout["curved"], sizeof(bool), + py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() } }); } @@ -552,10 +523,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) for (int i = 0; i < 2; i++) (*newel)[i] = py::extract(vertices[i])(); newel -> si = index; - newel -> edgenr = edgenr; newel -> epgeominfo[0].edgenr = edgenr; newel -> epgeominfo[1].edgenr = edgenr; - // needed for codim2 in 3d newel -> edgenr = index; for(auto i : Range(len(trignums))) newel->geominfo[i].trignum = py::cast(trignums[i]); @@ -598,14 +567,27 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) li.append (py::cast(self.surfnr2)); return li; })) - .def_property_readonly("index", FunctionPointer([](const Segment &self) -> size_t - { - return self.si; - })) - .def_property_readonly("edgenr", FunctionPointer([](const Segment & self) -> size_t - { - return self.edgenr; - })) + .def_property("index", + [](const Segment &self) -> size_t + { + return self.si; + }, + [](Segment& self, int index) + { + self.si = index; + }) + .def_property("edgenr", + [](const Segment & self) -> size_t + { + return self.edgenr; + }, + [](Segment& self, int edgenr) + { + self.edgenr = edgenr; + }) + .def_property("singular", + [](const Segment & seg) { return seg.singedge_left; }, + [](Segment & seg, double sing) { seg.singedge_left = sing; seg.singedge_right=sing; }) ; if(ngcore_have_numpy) @@ -617,7 +599,11 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() }, py::detail::field_descriptor { - "index", offsetof(Segment, edgenr), sizeof(int), + "index", offsetof(Segment, si), sizeof(int), + py::format_descriptor::format(), + py::detail::npy_format_descriptor::dtype() }, + py::detail::field_descriptor { + "edgenr", offsetof(Segment, edgenr), sizeof(int), py::format_descriptor::format(), py::detail::npy_format_descriptor::dtype() }, }); @@ -670,6 +656,9 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def_property("surfnr", &FaceDescriptor::SurfNr, &FaceDescriptor::SetSurfNr) .def_property("domin", &FaceDescriptor::DomainIn, &FaceDescriptor::SetDomainIn) .def_property("domout", &FaceDescriptor::DomainOut, &FaceDescriptor::SetDomainOut) + .def_property("domin_singular", &FaceDescriptor::DomainInSingular, &FaceDescriptor::SetDomainInSingular) + .def_property("domout_singular", &FaceDescriptor::DomainOutSingular, &FaceDescriptor::SetDomainOutSingular) + .def_property("bc", &FaceDescriptor::BCProperty, &FaceDescriptor::SetBCProperty) .def_property("bcname", [](FaceDescriptor & self) -> string { return self.GetBCName(); }, @@ -714,6 +703,20 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) ExportArray(m); ExportArray(m); + string export_docu = "Export mesh to other file format. Supported formats are:\n"; + Array export_formats; + for(auto & e : UserFormatRegister::entries) + if(e.write) { + string s = '\t'+e.format+"\t("+e.extensions[0]; + for(auto & ext : e.extensions.Range(1, e.extensions.Size())) + s += ", "+ext; + s += ")\n"; + export_formats.Append(s); + } + QuickSort(export_formats); + for(const auto & s : export_formats) + export_docu += s; + py::implicitly_convertible< int, PointIndex>(); py::class_> (m, "NetgenGeometry", py::dynamic_attr()) @@ -751,6 +754,11 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def_property_readonly("_timestamp", &Mesh::GetTimeStamp) .def_property_readonly("ne", [](Mesh& m) { return m.GetNE(); }) + .def_property_readonly("bounding_box", [](Mesh& m) { + Point3d pmin, pmax; + m.GetBox(pmin, pmax); + return py::make_tuple( Point<3>(pmin),Point<3>(pmax)); + }) .def("Partition", [](shared_ptr self, int numproc) { self->ParallelMetis(numproc); }, py::arg("numproc")) @@ -916,18 +924,11 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def("Export", [] (Mesh & self, string filename, string format) { - if (WriteUserFormat (format, self, /* *self.GetGeometry(), */ filename)) - { - string err = string ("nothing known about format")+format; - NgArray names, extensions; - RegisterUserFormats (names, extensions); - err += "\navailable formats are:\n"; - for (auto name : names) - err += string("'") + name + "'\n"; - throw NgException (err); - } + if (WriteUserFormat (format, self, filename)) + throw Exception ("Nothing known about format"+format); }, - py::arg("filename"), py::arg("format"),py::call_guard()) + py::arg("filename"), py::arg("format"), export_docu.c_str(), + py::call_guard()) .def_property("dim", &Mesh::GetDimension, &Mesh::SetDimension) @@ -963,11 +964,41 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) { sizeof(self.Points()[PointIndex::BASE]), sizeof(double) } ) ); }) - + .def_property_readonly("parentelements", [](Mesh & self) { + // return FlatArray(self.mlparentelement.Size(), &self.mlparentelement[0]); + return FlatArray(self.mlparentelement); + }, py::keep_alive<0,1>()) + .def_property_readonly("parentsurfaceelements", [](Mesh & self) { + // return FlatArray(self.mlparentsurfaceelement.Size(), + // &self.mlparentsurfaceelement[0]); + return FlatArray(self.mlparentsurfaceelement); + }, py::keep_alive<0,1>()) + .def_property_readonly("macromesh", [](Mesh & self) { + auto coarsemesh = make_shared(); + *coarsemesh = *self.coarsemesh; + return coarsemesh; + }, "mesh before hp-refinement") + .def("MacroElementNr", [](Mesh & self, int elnr, optional dim) { + // cout << "hpels = " << self.hpelements->Size() << endl; + // return self[ElementIndex(elnr)].GetHpElnr(); + if (!dim) dim = self.GetDimension(); + switch (*dim) + { + case 2: + return (*self.hpelements)[self[SurfaceElementIndex(elnr)].GetHpElnr()].coarse_elnr; + case 3: + return (*self.hpelements)[self[ElementIndex(elnr)].GetHpElnr()].coarse_elnr; + } + throw Exception ("MacroElementNr not implemented for dim"); + }, py::arg("elnr"), py::arg("dim")=nullopt, "number of macro element of element number elnr") .def("FaceDescriptor", static_cast (&Mesh::GetFaceDescriptor), py::return_value_policy::reference) .def("GetNFaceDescriptors", &Mesh::GetNFD) - + .def("RestrictLocalH", [](Mesh& self, const Point<3>& pnt, double maxh, + int layer) + { + self.RestrictLocalH(pnt, maxh, layer); + }, py::arg("p"), py::arg("h"), py::arg("layer")=1) .def("FaceDescriptors", // static_cast&(Mesh::*)()> (&Mesh::FaceDescriptors), &Mesh::FaceDescriptors, @@ -1008,10 +1039,22 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) return self.AddSurfaceElement (el); }) - .def ("Add", [](Mesh & self, const Segment & el) + .def ("Add", [](Mesh & self, const Segment & el, bool project_geominfo) { + if (project_geominfo) + { + auto &p1 = self[el[0]]; + auto &p2 = self[el[1]]; + auto geo = self.GetGeometry(); + geo->ProjectPointEdge + (0,0,p1, + const_cast(&el.epgeominfo[0])); + geo->ProjectPointEdge + (0,0,p2, + const_cast(&el.epgeominfo[1])); + } return self.AddSegment (el); - }) + }, py::arg("el"), py::arg("project_geominfo")=false) .def ("Add", [](Mesh & self, const Element0d & el) { @@ -1023,6 +1066,11 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) return self.AddFaceDescriptor (fd); }) + .def ("AddSingularity", [](Mesh & self, PointIndex pi, double factor) + { + self[pi].Singularity(factor); + }) + .def ("AddPoints", [](Mesh & self, py::buffer b1) { static Timer timer("Mesh::AddPoints"); @@ -1046,19 +1094,20 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) self.Points().SetAllocSize(self.Points().Size()+info.shape[0]); if (info.shape[1]==2) - for (auto i : Range(info.shape[0])) + for ([[maybe_unused]] auto i : Range(info.shape[0])) { self.AddPoint (Point<3>(ptr[0], ptr[1], 0)); ptr += 2; } if (info.shape[1]==3) - for (auto i : Range(info.shape[0])) + for ([[maybe_unused]] auto i : Range(info.shape[0])) { self.AddPoint (Point<3>(ptr[0], ptr[1], ptr[2])); ptr += 3; } }) - .def ("AddElements", [](Mesh & self, int dim, int index, py::buffer b1, int base) + .def ("AddElements", [](Mesh & self, int dim, int index, py::buffer b1, int base, + bool project_geometry) { static Timer timer("Mesh::AddElements"); static Timer timercast("Mesh::AddElements casting"); @@ -1077,10 +1126,10 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) int * ptr = static_cast (info.ptr); if (dim == 1) { - ELEMENT_TYPE type; + // ELEMENT_TYPE type; int np = info.shape[1]; self.LineSegments().SetAllocSize(self.LineSegments().Size()+info.shape[0]); - for (auto i : Range(info.shape[0])) + for ([[maybe_unused]] auto i : Range(info.shape[0])) { Segment el; for (int j = 0; j < np; j++) @@ -1104,12 +1153,27 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) throw Exception("unsupported 2D element with "+ToString(np)+" points"); } self.SurfaceElements().SetAllocSize(self.SurfaceElements().Size()+info.shape[0]); - for (auto i : Range(info.shape[0])) + for ([[maybe_unused]] auto i : Range(info.shape[0])) { Element2d el(type); for (int j = 0; j < np; j++) el[j] = ptr[j]+PointIndex::BASE-base; el.SetIndex(index); + if(project_geometry) + { + // find some point in the mid of trig/quad for + // quick + stable uv-projection of all points + auto startp = Center(self[el[0]], self[el[1]], self[el[2]]); + PointGeomInfo gi = self.GetGeometry()->ProjectPoint(index, + startp); + for(auto i : Range(np)) + { + el.GeomInfo()[i] = gi; + self.GetGeometry()->ProjectPointGI(index, + self[el[i]], + el.GeomInfo()[i]); + } + } self.AddSurfaceElement (el); ptr += info.strides[0]/sizeof(int); } @@ -1130,7 +1194,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) throw Exception("unsupported 3D element with "+ToString(np)+" points"); } self.VolumeElements().SetAllocSize(self.VolumeElements().Size()+info.shape[0]); - for (auto i : Range(info.shape[0])) + for ([[maybe_unused]] auto i : Range(info.shape[0])) { Element el(type); for (int j = 0; j < np;j ++) @@ -1141,7 +1205,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) } } - }, py::arg("dim"), py::arg("index"), py::arg("data"), py::arg("base")=0) + }, py::arg("dim"), py::arg("index"), py::arg("data"), py::arg("base")=0, + py::arg("project_geometry")=false) .def ("DeleteSurfaceElement", [](Mesh & self, SurfaceElementIndex i) @@ -1179,7 +1244,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) else throw Exception("either 'dim' or 'codim' must be specified"); - NgArray & codimnames = self.GetRegionNamesCD (codim); + Array & codimnames = self.GetRegionNamesCD (codim); std::vector names; for (auto name : codimnames) @@ -1204,7 +1269,21 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) .def ("GetCD3Name", &Mesh::GetCD3Name) .def ("SetCD3Name", &Mesh::SetCD3Name) - + .def ("SplitFacesByAdjacentDomains", &Mesh::SplitFacesByAdjacentDomains) + .def ("GetSubMesh", &Mesh::GetSubMesh, py::arg("domains")="", py::arg("faces")="") + .def("GetIdentifications", [](Mesh & self) -> py::list + { + py::list points; + for(const auto& pair : self.GetIdentifications().GetIdentifiedPoints()) + { + // py::tuple pnts = py::make_tuple(pair.first.I1(), pair.first.I2()); + + auto [pi1, pi2] = get<0> (pair.first); + py::tuple pnts = py::make_tuple(pi1, pi2); + points.append(pnts); + } + return points; + }) .def ("AddPointIdentification", [](Mesh & self, py::object pindex1, py::object pindex2, int identnr, Identifications::ID_TYPE type) { if(py::extract(pindex1).check() && py::extract(pindex2).check()) @@ -1219,7 +1298,12 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) py::arg("identnr"), py::arg("type")=Identifications::PERIODIC) .def("IdentifyPeriodicBoundaries", &Mesh::IdentifyPeriodicBoundaries, - py::arg("face1"), py::arg("face2"), py::arg("mapping"), py::arg("point_tolerance") = -1.) + py::arg("identification_name"), py::arg("face1"), py::arg("mapping"), +py::arg("point_tolerance") = -1.) + .def("GetCurveOrder", [] (Mesh & self) + { + return self.GetCurvedElements().GetOrder(); + }) .def("GetNrIdentifications", [](Mesh& self) { return self.GetIdentifications().GetMaxNr(); @@ -1238,15 +1322,12 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) { MeshingParameters mp; if(pars) mp = *pars; - { - py::gil_scoped_acquire acquire; - CreateMPfromKwargs(mp, kwargs); - } + CreateMPfromKwargs(mp, kwargs); + py::gil_scoped_release gil_release; MeshVolume (mp, self); OptimizeVolume (mp, self); }, py::arg("mp")=nullptr, - meshingparameter_description.c_str(), - py::call_guard()) + meshingparameter_description.c_str()) .def ("OptimizeVolumeMesh", [](Mesh & self, MeshingParameters* pars) { @@ -1255,8 +1336,12 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) else mp.optsteps3d = 5; OptimizeVolume (mp, self); }, py::arg("mp"), py::call_guard()) - - .def ("OptimizeMesh2d", [](Mesh & self, MeshingParameters* pars) + .def("SetLocalH",[](Mesh& self, shared_ptr localh, int layer) + { + self.SetLocalH(localh, layer); + }, py::arg("localh"), py::arg("layer")=1) + .def("GetLocalH", &Mesh::GetLocalH) + .def ("OptimizeMesh2d", [](Mesh & self, MeshingParameters* pars, int faceindex) { self.CalcLocalH(0.5); MeshingParameters mp; @@ -1264,8 +1349,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) else mp.optsteps2d = 5; if(!self.GetGeometry()) throw Exception("Cannot optimize surface mesh without geometry!"); - Optimize2d (self, mp); - }, py::arg("mp")=nullptr, py::call_guard()) + Optimize2d (self, mp, faceindex); + }, py::arg("mp")=nullptr, py::arg("faceindex")=0, py::call_guard()) .def ("Refine", FunctionPointer ([](Mesh & self, bool adaptive) @@ -1295,14 +1380,97 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) }), py::arg("adaptive")=false, py::call_guard()) .def("ZRefine", &Mesh::ZRefine) - - .def ("SecondOrder", FunctionPointer + .def("Split2Tets", &Mesh::Split2Tets) + .def ("SplitAlfeld", FunctionPointer ([](Mesh & self) { - self.GetGeometry()->GetRefinement().MakeSecondOrder(self); - })) + NgLock meshlock (self.MajorMutex(), true); + Refinement & ref = const_cast (self.GetGeometry()->GetRefinement()); + ::netgen::HPRefinement (self, &ref, SPLIT_ALFELD, 1, 0.5, true, true); + } + ), py::call_guard()) + .def ("SplitPowellSabin", FunctionPointer + ([](Mesh & self) + { + NgLock meshlock (self.MajorMutex(), true); + Refinement & ref = const_cast (self.GetGeometry()->GetRefinement()); + ::netgen::HPRefinement (self, &ref, SPLIT_POWELL, 1, 0.5, true, true); + } + ), py::call_guard()) + .def ("SecondOrder", [](Mesh & self) + { + self.GetGeometry()->GetRefinement().MakeSecondOrder(self); + }) + + .def ("Curve", [](Mesh & self, int order) + { + self.BuildCurvedElements(order); + }) + .def ("CalcElementMapping", [](Mesh & self, py::buffer refpts1, py::buffer physpts1) + { + auto refpts = refpts1.cast>(); + auto physpts = physpts1.cast>(); + + py::buffer_info ref_info = refpts.request(); + py::buffer_info phys_info = physpts.request(); + double * ref_ptr = static_cast (ref_info.ptr); + double * phys_ptr = static_cast (phys_info.ptr); + + if (ref_info.ndim != 2) + throw std::runtime_error("Reference points need buffer of dimension 2"); + if (phys_info.ndim != 3) + throw std::runtime_error("Physical points need buffer of dimension 3"); - .def ("GetGeometry", [] (Mesh& self) { return self.GetGeometry(); }) + /* + cout << "ref_info.shape = " << FlatArray(2, &ref_info.shape[0]) << endl; + cout << "ref_info.stride = " << FlatArray(2, &ref_info.strides[0]) << endl; + cout << "phys_info.shape = " << FlatArray(3, &phys_info.shape[0]) << endl; + cout << "phys_info.stride = " << FlatArray(3, &phys_info.strides[0]) << endl; + */ + + size_t npts = ref_info.shape[0]; + size_t dim = ref_info.shape[1]; + // size_t nel = phys_info.shape[0]; + size_t dim_phys = phys_info.shape[2]; + + size_t stride_refpts = ref_info.strides[0]/sizeof(double); + size_t stride_physels = phys_info.strides[0]/sizeof(double); + size_t stride_physpts = phys_info.strides[1]/sizeof(double); + + auto & curved = self.GetCurvedElements(); + + if (dim == 2) // mapping of 2D elements + { + for (SurfaceElementIndex i = 0; i < self.GetNSE(); i++) + for (size_t j = 0; j < npts; j++) + { + Point<2> xref; + Point<3> xphys; + for (size_t k = 0; k < 2; k++) + xref(k) = ref_ptr[j*stride_refpts+k]; + curved.CalcSurfaceTransformation(xref, i, xphys); + for (size_t k = 0; k < dim_phys; k++) + phys_ptr[i*stride_physels+j*stride_physpts+k] = xphys(k); + } + } + + if (dim == 3) // mapping of 3D elements + { + for (ElementIndex i = 0; i < self.GetNE(); i++) + for (size_t j = 0; j < npts; j++) + { + Point<3> xref; + Point<3> xphys; + for (size_t k = 0; k < 3; k++) + xref(k) = ref_ptr[j*stride_refpts+k]; + curved.CalcElementTransformation(xref, i, xphys); + for (size_t k = 0; k < 3; k++) + phys_ptr[i*stride_physels+j*stride_physpts+k] = xphys(k); + } + } + }) + + .def ("GetGeometry", [](Mesh & self) { return self.GetGeometry(); }) .def ("SetGeometry", [](Mesh & self, shared_ptr geo) { self.SetGeometry(geo); @@ -1316,137 +1484,37 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m) })) */ - .def ("BuildSearchTree", &Mesh::BuildElementSearchTree,py::call_guard()) + .def ("BuildSearchTree", &Mesh::BuildElementSearchTree,py::call_guard(), + py::arg("dim")=3) .def ("BoundaryLayer2", GenerateBoundaryLayer2, py::arg("domain"), py::arg("thicknesses"), py::arg("make_new_domain")=true, py::arg("boundaries")=Array{}) - .def ("BoundaryLayer", [](Mesh & self, variant boundary, - variant thickness, - variant> material, - variant domain, bool outside, - optional project_boundaries, + .def ("BoundaryLayer", [](Mesh & self, variant> boundary, + variant> thickness, + optional>> material, + variant> domain, bool outside, + optional>> project_boundaries, bool grow_edges, bool limit_growth_vectors, - bool sides_keep_surfaceindex) + bool sides_keep_surfaceindex, + bool disable_curving) { + throw Exception("Call syntax has changed! Pass a list of BoundaryLayerParameters to the GenerateMesh call instead: \ngeo.GenerateMesh(..., boundary_layers=[BoundaryLayerParameters(...), BoundaryLayerParameters(...), ...])"); BoundaryLayerParameters blp; - BitArray boundaries(self.GetNFD()+1); - boundaries.Clear(); - if(int* bc = get_if(&boundary); bc) - { - for (int i = 1; i <= self.GetNFD(); i++) - if(self.GetFaceDescriptor(i).BCProperty() == *bc) - boundaries.SetBit(i); - } - else - { - regex pattern(*get_if(&boundary)); - for(int i = 1; i<=self.GetNFD(); i++) - { - auto& fd = self.GetFaceDescriptor(i); - if(regex_match(fd.GetBCName(), pattern)) - { - boundaries.SetBit(i); - auto dom_pattern = get_if(&domain); - // only add if adjacent to domain - if(dom_pattern) - { - regex pattern(*dom_pattern); - bool mat1_match = fd.DomainIn() > 0 && regex_match(self.GetMaterial(fd.DomainIn()), pattern); - bool mat2_match = fd.DomainOut() > 0 && regex_match(self.GetMaterial(fd.DomainOut()), pattern); - // if boundary is inner or outer remove from list - if(mat1_match == mat2_match) - boundaries.Clear(i); - // if((fd.DomainIn() > 0 && regex_match(self.GetMaterial(fd.DomainIn()), pattern)) || (fd.DomainOut() > 0 && regex_match(self.GetMaterial(fd.DomainOut()), pattern))) - // boundaries.Clear(i); - // blp.surfid.Append(i); - } - // else - // blp.surfid.Append(i); - } - } - } - for(int i = 1; i<=self.GetNFD(); i++) - if(boundaries.Test(i)) - blp.surfid.Append(i); - if(string* mat = get_if(&material); mat) - blp.new_mat = { { ".*", *mat } }; - else - blp.new_mat = *get_if>(&material); - - if(project_boundaries.has_value()) - { - regex pattern(*project_boundaries); - for(int i = 1; i<=self.GetNFD(); i++) - if(regex_match(self.GetFaceDescriptor(i).GetBCName(), pattern)) - blp.project_boundaries.Append(i); - } - - if(double* pthickness = get_if(&thickness); pthickness) - { - blp.heights.Append(*pthickness); - } - else - { - auto thicknesses = *get_if(&thickness); - for(auto val : thicknesses) - blp.heights.Append(val.cast()); - } - - int nr_domains = self.GetNDomains(); - blp.domains.SetSize(nr_domains + 1); // one based - blp.domains.Clear(); - if(string* pdomain = get_if(&domain); pdomain) - { - regex pattern(*pdomain); - for(auto i : Range(1, nr_domains+1)) - if(regex_match(self.GetMaterial(i), pattern)) - blp.domains.SetBit(i); - } - else - { - auto idomain = *get_if(&domain); - blp.domains.SetBit(idomain); - } - + blp.boundary = boundary; + blp.thickness = thickness; + blp.new_material = material; + blp.domain = domain; blp.outside = outside; + blp.project_boundaries = project_boundaries; blp.grow_edges = grow_edges; blp.limit_growth_vectors = limit_growth_vectors; blp.sides_keep_surfaceindex = sides_keep_surfaceindex; - + blp.disable_curving = disable_curving; GenerateBoundaryLayer (self, blp); self.UpdateTopology(); - }, py::arg("boundary"), py::arg("thickness"), py::arg("material"), + }, py::arg("boundary"), py::arg("thickness"), py::arg("material")=nullopt, py::arg("domains") = ".*", py::arg("outside") = false, - py::arg("project_boundaries")=nullopt, py::arg("grow_edges")=true, py::arg("limit_growth_vectors") = true, py::arg("sides_keep_surfaceindex")=false, - R"delimiter( -Add boundary layer to mesh. - -Parameters ----------- - -boundary : string or int - Boundary name or number. - -thickness : float or List[float] - Thickness of boundary layer(s). - -material : str or List[str] - Material name of boundary layer(s). - -domain : str or int - Regexp for domain boundarylayer is going into. - -outside : bool = False - If true add the layer on the outside - -grow_edges : bool = False - Grow boundary layer over edges. - -project_boundaries : Optional[str] = None - Project boundarylayer to these boundaries if they meet them. Set - to boundaries that meet boundarylayer at a non-orthogonal edge and - layer-ending should be projected to that boundary. - -)delimiter") + py::arg("project_boundaries")=nullopt, py::arg("grow_edges")=true, py::arg("limit_growth_vectors") = false, py::arg("sides_keep_surfaceindex")=false, + py::arg("disable_curving")=true, "Add boundary layer to mesh. see help(BoundaryLayerParameters) for details.") .def_static ("EnableTableClass", [] (string name, bool set) { @@ -1512,7 +1580,7 @@ project_boundaries : Optional[str] = None { const auto & seg = segs[i]; for(auto k : Range(2)) - output[2*i+k] = seg[k]-PointIndex::BASE; + output[2*i+k] = seg[k]-IndexBASE(); } }); return output; }) @@ -1528,10 +1596,11 @@ project_boundaries : Optional[str] = None ParallelForRange( n, [&](auto myrange) { for(auto i : myrange) { - PointIndex p0,p1; - topo.GetEdgeVertices(i+1, p0, p1); - output[2*i] = p0-PointIndex::BASE; - output[2*i+1] = p1-PointIndex::BASE; + // PointIndex p0,p1; + // topo.GetEdgeVertices(i+1, p0, p1); + auto [p0,p1] = topo.GetEdgeVertices(i); + output[2*i] = p0-IndexBASE(); + output[2*i+1] = p1-IndexBASE(); } }); return output; }) @@ -1549,7 +1618,7 @@ project_boundaries : Optional[str] = None const auto & sel = surfels[i]; auto * trig = &trigs[3*i]; for(auto k : Range(3)) - trig[k] = sel[k]-PointIndex::BASE; + trig[k] = sel[k]-IndexBASE(); // todo: quads (store the second trig in thread-local extra array, merge them at the end (mutex) } }); return trigs; @@ -1567,27 +1636,39 @@ project_boundaries : Optional[str] = None const auto & el = els[i]; auto * trig = &tets[4*i]; for(auto k : Range(4)) - trig[k] = el[k]-PointIndex::BASE; + trig[k] = el[k]-IndexBASE(); // todo: prisms etc (store the extra tets in thread-local extra array, merge them at the end (mutex) } }); return tets; }) ; - m.def("ImportMesh", [](const string& filename) + string import_docu = "Import mesh from other file format. Leaving format parameter empty guesses based on file extension.\nSupported formats are:\n"; + UserFormatRegister::IterateFormats([&](auto & e) { + string s = '\t'+e.format+"\t("+e.extensions[0]; + for(auto & ext : e.extensions.Range(1, e.extensions.Size())) + s += ", "+ext; + s += ")\n"; + import_docu += s; + }, true); + + m.def("ReadMedit", [](const string& filename) { + map, int> index_map; + auto mesh = make_shared(); + ReadMeditFormat(*mesh, filename, index_map); + return py::make_tuple(mesh, index_map); + }); + m.def("WriteMedit", [](const Mesh& mesh, const string& filename) { + map, int> index_map; + WriteMeditFormat(mesh, filename, index_map); + return index_map; + }); + m.def("ImportMesh", [](const string& filename, const string & format) { auto mesh = make_shared(); - ReadFile(*mesh, filename); + ReadUserFormat(*mesh, filename, format); return mesh; - }, py::arg("filename"), - R"delimiter(Import mesh from other file format, supported file formats are: - Neutral format (*.mesh, *.emt) - Surface file (*.surf) - Universal format (*.unv) - Olaf format (*.emt) - Tet format (*.tet) - Pro/ENGINEER format (*.fnf) -)delimiter"); + }, py::arg("filename"), py::arg("format")="", import_docu.c_str()); py::enum_(m,"MeshingStep") .value("ANALYSE", MESHCONST_ANALYSE) .value("MESHEDGES", MESHCONST_MESHEDGES) @@ -1606,25 +1687,25 @@ project_boundaries : Optional[str] = None return mp; }), py::arg("mp")=nullptr, meshingparameter_description.c_str()) .def("__str__", &ToString) - .def("RestrictH", [](MP & mp, double x, double y, double z, double h) + .def("RestrictH", [](MP & mp, double x, double y, double z, double h, int layer) { - mp.meshsize_points.Append ( MeshingParameters::MeshSizePoint(Point<3> (x,y,z), h)); - }, py::arg("x"), py::arg("y"), py::arg("z"), py::arg("h") + mp.meshsize_points.Append ( MeshingParameters::MeshSizePoint(Point<3> (x,y,z), h, layer)); + }, py::arg("x"), py::arg("y"), py::arg("z"), py::arg("h"), py::arg("layer")=1 ) - .def("RestrictH", [](MP & mp, const Point<3>& p, double h) + .def("RestrictH", [](MP & mp, const Point<3>& p, double h, int layer) { - mp.meshsize_points.Append ({p, h}); - }, py::arg("p"), py::arg("h")) + mp.meshsize_points.Append ({p, h, layer}); + }, py::arg("p"), py::arg("h"), py::arg("layer")=1) .def("RestrictHLine", [](MP& mp, const Point<3>& p1, const Point<3>& p2, - double maxh) + double maxh, int layer) { int steps = int(Dist(p1, p2) / maxh) + 2; auto v = p2 - p1; for (int i = 0; i <= steps; i++) { - mp.meshsize_points.Append({p1 + double(i)/steps * v, maxh}); + mp.meshsize_points.Append({p1 + double(i)/steps * v, maxh, layer}); } - }, py::arg("p1"), py::arg("p2"), py::arg("maxh")) + }, py::arg("p1"), py::arg("p2"), py::arg("maxh"), py::arg("layer")=1) ; m.def("SetTestoutFile", FunctionPointer ([] (const string & filename) @@ -1659,6 +1740,93 @@ project_boundaries : Optional[str] = None m.attr("debugparam") = py::cast(&debugparam); + py::class_(m, "BoundaryLayerParameters") + .def(py::init([]( + std::variant> boundary, + std::variant> thickness, + std::optional>> new_material, + std::variant> domain, + bool outside, + std::optional>> project_boundaries, + bool grow_edges, + bool limit_growth_vectors, + std::optional sides_keep_surfaceindex, + bool disable_curving) + { + BoundaryLayerParameters blp; + blp.boundary = boundary; + blp.thickness = thickness; + blp.new_material = new_material; + blp.domain = domain; + blp.outside = outside; + blp.project_boundaries = project_boundaries; + blp.grow_edges = grow_edges; + blp.limit_growth_vectors = limit_growth_vectors; + blp.sides_keep_surfaceindex = sides_keep_surfaceindex; + blp.disable_curving = disable_curving; + return blp; + }), + py::arg("boundary"), py::arg("thickness"), py::arg("new_material")=nullopt, + py::arg("domain") = ".*", py::arg("outside") = false, + py::arg("project_boundaries")=nullopt, py::arg("grow_edges")=true, + py::arg("limit_growth_vectors") = false, py::arg("sides_keep_surfaceindex")=nullopt, + py::arg("disable_curving")=true, + R"delimiter( +Add boundary layer to mesh. + +Parameters +---------- + +boundary : string or int + Boundary name or number. + +thickness : float or List[float] + Thickness of boundary layer(s). + +material : str or List[str] + Material name of boundary layer(s). + +domain : str or int + Regexp for domain boundarylayer is going into. + +outside : bool = False + If true add the layer on the outside + +grow_edges : bool = False + Grow boundary layer over edges. + +project_boundaries : Optional[str] = None + Project boundarylayer to these boundaries if they meet them. Set + to boundaries that meet boundarylayer at a non-orthogonal edge and + layer-ending should be projected to that boundary. + +)delimiter") + .def(py::init([]( const py::dict & d ) { + try { + // Call other constructor with named arguments by unpacking the dictionary + py::object cls = py::type::of(); + return cls(**d).cast(); + } + catch (py::error_already_set & e) { + cerr << "Error creating BoundaryLayerParameters from dict:" << endl; + cerr << e.what() << endl; + throw; + } + })) + .def_readwrite("boundary", &BoundaryLayerParameters::boundary) + .def_readwrite("thickness", &BoundaryLayerParameters::thickness) + .def_readwrite("new_material", &BoundaryLayerParameters::new_material) + .def_readwrite("domain", &BoundaryLayerParameters::domain) + .def_readwrite("outside", &BoundaryLayerParameters::outside) + .def_readwrite("project_boundaries", &BoundaryLayerParameters::project_boundaries) + .def_readwrite("grow_edges", &BoundaryLayerParameters::grow_edges) + .def_readwrite("limit_growth_vectors", &BoundaryLayerParameters::limit_growth_vectors) + .def_readwrite("sides_keep_surfaceindex", &BoundaryLayerParameters::sides_keep_surfaceindex) + .def_readwrite("disable_curving", &BoundaryLayerParameters::disable_curving) + ; + py::implicitly_convertible(); + +#ifdef NG_CGNS m.def("ReadCGNSFile", &ReadCGNSFile, py::arg("filename"), py::arg("base")=1, "Read mesh and solution vectors from CGNS file"); m.def("WriteCGNSFile", &WriteCGNSFile, py::arg("mesh"), py::arg("filename"), py::arg("names"), py::arg("values"), py::arg("locations"), R"(Write mesh and solution vectors to CGNS file, possible values for locations: @@ -1667,6 +1835,7 @@ project_boundaries : Optional[str] = None FaceCenter = 2 CellCenter = 3 )"); +#endif // NG_CGNS py::class_> (m, "SurfaceGeometry") .def(py::init<>()) @@ -1683,14 +1852,14 @@ project_boundaries : Optional[str] = None }), py::arg("mapping")) .def(NGSPickle()) .def("GenerateMesh", [](shared_ptr geo, - bool quads, int nx, int ny, bool flip_triangles, py::list py_bbbpts, py::list py_bbbnames, py::list py_hppts, py::list py_hpbnd) + bool quads, int nx, int ny, bool flip_triangles, py::list py_bbbpts, py::list py_bbbnames, py::list py_hppnts, py::dict/*list*/ py_hpbnd, py::dict py_layers) { if (py::len(py_bbbpts) != py::len(py_bbbnames)) throw Exception("In SurfaceGeometry::GenerateMesh bbbpts and bbbnames do not have same lengths."); Array> bbbpts(py::len(py_bbbpts)); Array bbbname(py::len(py_bbbpts)); - Array> hppts(py::len(py_hppts)); - Array hpptsfac(py::len(py_hppts)); + Array> hppnts(py::len(py_hppnts)); + Array hppntsfac(py::len(py_hppnts)); Array hpbnd(py::len(py_hpbnd)); Array hpbndfac(py::len(py_hpbnd)); for(int i = 0; i(py::extract(pnt[0])(),py::extract(pnt[1])(),py::extract(pnt[2])()); bbbname[i] = py::extract(py_bbbnames[i])(); } - for(int i = 0; i(py_hppts[i])(); - hppts[i] = Point<3>(py::extract(pnt[0])(),py::extract(pnt[1])(),py::extract(pnt[2])()); - //hpptsfac[i] = py::len(pnt) > 3 ? py::extract(pnt[3])() : 0.0; - hpptsfac[i] = py::extract(pnt[3])(); + py::tuple pnt = py::extract(py_hppnts[i])(); + hppnts[i] = Point<3>(py::extract(pnt[0])(),py::extract(pnt[1])(),py::extract(pnt[2])()); + hppntsfac[i] = py::extract(pnt[3])(); } - for(int i = 0; i(py_hpbnd[i])(); - hpbnd[i] = py::extract(bnd[0])(); - hpbndfac[i] = py::extract(bnd[1])(); - } + int ii=0; + for(auto val : py_hpbnd) + { + hpbnd[ii] = py::cast(val.first); + hpbndfac[ii] = py::cast(val.second); + ii++; + } + + + Array layer_thickness[4]; + bool layer_quad = false; + + for(auto val : py_layers) + { + int index = -1; + if (py::cast(val.first) == "left") index = 0; + else if (py::cast(val.first) == "top") index = 3; + else if (py::cast(val.first) == "right") index = 2; + else if (py::cast(val.first) == "bottom") index = 1; + else if (py::cast(val.first) == "quads") layer_quad = py::cast(val.second); + else throw Exception("Unknown parameter " + string(py::cast(val.first))); + if (index < 0) continue; + + auto list = py::cast(val.second); + layer_thickness[index] = Array(py::len(list)); + for (size_t i = 0; i < py::len(list); i++) + layer_thickness[index][i] = py::cast(list[i]); + } + auto mesh = make_shared(); SetGlobalMesh (mesh); mesh->SetGeometry(geo); ng_geometry = geo; - auto result = geo->GenerateStructuredMesh (mesh, quads, nx, ny, flip_triangles, bbbpts, bbbname, hppts, hpptsfac, hpbnd, hpbndfac); + auto result = geo->GenerateStructuredMesh (mesh, quads, nx, ny, flip_triangles, bbbpts, bbbname, hppnts, hppntsfac, hpbnd, hpbndfac, layer_thickness, layer_quad); if(result != 0) throw Exception("SurfaceGeometry: Meshing failed!"); return mesh; - }, py::arg("quads")=true, py::arg("nx")=10, py::arg("ny")=10, py::arg("flip_triangles")=false, py::arg("bbbpts")=py::list(), py::arg("bbbnames")=py::list(), py::arg("hppts")=py::list(), py::arg("hpbnd")=py::list()) - ; + }, py::arg("quads")=true, py::arg("nx")=10, py::arg("ny")=10, py::arg("flip_triangles")=false, py::arg("bbbpts")=py::list(), py::arg("bbbnames")=py::list(), py::arg("hppnts")=py::list(), py::arg("hpbnd")=py::dict(), py::arg("boundarylayer")=py::dict());/*, R"raw_string( + Generate a structured 2D surface mesh + + Parameters: + + quads : bool + If True, a quadrilateral mesh is generated. If False, the quads are split to triangles. + + nx : int + Number of cells in x-direction. + + ny : int + Number of cells in y-direction. + + flip_triangles : bool + If set to True together with quads=False the quads are cut the other way round + + bbbpts : list + List of points which should be handled as BBBND and are named with bbbnames. The mesh must be constructed in such a way that the bbbpts coincide with generated points. + + bbbnames : list + List of bbbnd names as strings. Size must coincide with size of bbbpts. + + hppnts : list + If not None it expects a list of the form [ (px1,py1,pz1, hpref1), (px2,py2,pz2, hpref2), ... ] where px,py,pz are the point coordinates which have to be resolved in the mesh and hpref the refinement factor. + + hpbnd : dict + If not None it expects a dictionary of the form {"boundaryname" : hpref } where boundaryname in [left, right, top, bottom] and hpref the refinement factor. + + boundarylayer : dict + If not None it expects a dictionary of the form { "boundaryname" : [t1,...,tn], "quads" : False } where ti denote the thickness of layer i. The number of layers are included in nx/ny. After the layers are placed the remaining number of cells are used to divide the remaining grid uniformly. If quads are set to True quadrilaterals are used inside the boundarylayer. If set False the value of "quads" of the function call is used. + )raw_string");*/ ; py::class_ (m, "ClearSolutionClass") diff --git a/libsrc/meshing/python_mesh.hpp b/libsrc/meshing/python_mesh.hpp index 4a5db879..d0186a1f 100644 --- a/libsrc/meshing/python_mesh.hpp +++ b/libsrc/meshing/python_mesh.hpp @@ -185,6 +185,14 @@ inline void CreateMPfromKwargs(MeshingParameters& mp, py::kwargs kwargs, bool th mp.nthreads = py::cast(kwargs.attr("pop")("nthreads")); if(kwargs.contains("closeedgefac")) mp.closeedgefac = py::cast>(kwargs.attr("pop")("closeedgefac")); + + if(kwargs.contains("boundary_layers")) + { + auto layers = py::list(kwargs.attr("pop")("boundary_layers")); + for(auto layer : layers) + mp.boundary_layers.Append(py::cast(layer)); + } + if(kwargs.size()) { if(throw_if_not_all_parsed) diff --git a/libsrc/meshing/refine.cpp b/libsrc/meshing/refine.cpp index 7f9ed6ad..77d18052 100644 --- a/libsrc/meshing/refine.cpp +++ b/libsrc/meshing/refine.cpp @@ -1,5 +1,7 @@ #include -#include "meshing.hpp" +#include "meshclass.hpp" +#include "bisect.hpp" +#include "paralleltop.hpp" namespace netgen @@ -31,7 +33,7 @@ namespace netgen if (mesh.mlbetweennodes.Size() < mesh.GetNV()) { mesh.mlbetweennodes.SetSize(mesh.GetNV()); - mesh.mlbetweennodes = INDEX_2(PointIndex::BASE-1,PointIndex::BASE-1); + mesh.mlbetweennodes = PointIndices<2>(PointIndex::INVALID, PointIndex::INVALID); } if (mesh.level_nv.Size() == 0) @@ -189,8 +191,8 @@ namespace netgen mesh.Point(pinew) = pnew; // between.Set (i2, pinew); - if (pinew >= epgi.Size()+PointIndex::BASE) - epgi.SetSize (pinew+1-PointIndex::BASE); + if (pinew >= epgi.Size()+IndexBASE()) + epgi.SetSize (pinew+1-IndexBASE()); epgi[pinew] = ngi; } @@ -208,7 +210,7 @@ namespace netgen PrintMessage (5, "have 1d elements"); // refine surface elements - NgArray surfgi (8*mesh.GetNP()); + Array surfgi (8*mesh.GetNP()); for (int i = PointIndex::BASE; i < surfgi.Size()+PointIndex::BASE; i++) surfgi[i].trignum = -1; @@ -273,9 +275,9 @@ namespace netgen between.Set (i2, pnums.Get(4+j)); } */ - if (surfgi.Size() < pnums.Elem(4+j)) - surfgi.SetSize (pnums.Elem(4+j)); - surfgi.Elem(pnums.Elem(4+j)) = pgis.Elem(4+j); + if (surfgi.Size() < pnums.Elem(4+j)-IndexBASE()+1) + surfgi.SetSize (pnums.Elem(4+j)-IndexBASE()+1); + surfgi[pnums.Elem(4+j)] = pgis.Elem(4+j); } @@ -356,9 +358,9 @@ namespace netgen mesh.Point(pinew) = pb; } - if (surfgi.Size() < pnums[4+j]) - surfgi.SetSize (pnums[4+j]); - surfgi.Elem(pnums[4+j]) = pgis[4+j]; + if (surfgi.Size() < pnums[4+j]-IndexBASE()+1) + surfgi.SetSize (pnums[4+j]-IndexBASE()+1); + surfgi[pnums[4+j]] = pgis[4+j]; } static int reftab[4][4] = @@ -749,17 +751,17 @@ namespace netgen // update identification tables for (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++) { - NgArray identmap; + idmap_type identmap; mesh.GetIdentifications().GetMap (i, identmap); for (int j = 1; j <= between.GetNBags(); j++) for (int k = 1; k <= between.GetBagSize(j); k++) { - INDEX_2 i2; + PointIndices<2> i2; PointIndex newpi; between.GetData (j, k, i2, newpi); - INDEX_2 oi2(identmap.Get(i2.I1()), - identmap.Get(i2.I2())); + PointIndices<2> oi2(identmap[i2[0]], + identmap[i2[1]]); oi2.Sort(); if (between.Used (oi2)) { @@ -790,14 +792,15 @@ namespace netgen int cnttrials = 10; int wrongels = 0; - for (int i = 1; i <= mesh.GetNE(); i++) - if (mesh.VolumeElement(i).Volume(mesh.Points()) < 0) + + for (auto & el : mesh.VolumeElements()) + if (el.Volume(mesh.Points()) < 0) { wrongels++; - mesh.VolumeElement(i).Flags().badel = 1; + el.Flags().badel = 1; } else - mesh.VolumeElement(i).Flags().badel = 0; + el.Flags().badel = 0; if (wrongels) { @@ -820,11 +823,11 @@ namespace netgen can.Elem(parent.I2())); } - NgBitArray boundp(np); + TBitArray boundp(np); boundp.Clear(); for (auto & sel : mesh.SurfaceElements()) for (auto pi : sel.PNums()) - boundp.Set(pi); + boundp.SetBit(pi); double lam = 0.5; @@ -851,28 +854,30 @@ namespace netgen mesh.Point(i) = can.Get(i); - NgBitArray free (mesh.GetNP()), fhelp(mesh.GetNP()); + TBitArray free (mesh.GetNP()), fhelp(mesh.GetNP()); free.Clear(); - for (int i = 1; i <= mesh.GetNE(); i++) + // for (int i = 1; i <= mesh.GetNE(); i++) + for (ElementIndex ei : mesh.VolumeElements().Range()) { - const Element & el = mesh.VolumeElement(i); + const Element & el = mesh.VolumeElement(ei); if (el.Volume(mesh.Points()) < 0) for (int j = 1; j <= el.GetNP(); j++) - free.Set (el.PNum(j)); + free.SetBit (el.PNum(j)); } for (int k = 1; k <= 3; k++) { fhelp.Clear(); - for (int i = 1; i <= mesh.GetNE(); i++) + // for (int i = 1; i <= mesh.GetNE(); i++) + for (const Element & el : mesh.VolumeElements()) { - const Element & el = mesh.VolumeElement(i); + // const Element & el = mesh.VolumeElement(i); int freeel = 0; for (int j = 1; j <= el.GetNP(); j++) if (free.Test(el.PNum(j))) freeel = 1; if (freeel) for (int j = 1; j <= el.GetNP(); j++) - fhelp.Set (el.PNum(j)); + fhelp.SetBit (el.PNum(j)); } free.Or (fhelp); } @@ -895,19 +900,19 @@ namespace netgen wrongels = 0; - for (int i = 1; i <= mesh.GetNE(); i++) + for (ElementIndex ei : mesh.VolumeElements().Range()) { - if (mesh.VolumeElement(i).Volume(mesh.Points()) < 0) + if (mesh.VolumeElement(ei).Volume(mesh.Points()) < 0) { wrongels++; - mesh.VolumeElement(i).Flags().badel = 1; + mesh.VolumeElement(ei).Flags().badel = 1; (*testout) << "wrong el: "; for (int j = 1; j <= 4; j++) - (*testout) << mesh.VolumeElement(i).PNum(j) << " "; + (*testout) << mesh.VolumeElement(ei).PNum(j) << " "; (*testout) << endl; } else - mesh.VolumeElement(i).Flags().badel = 0; + mesh.VolumeElement(ei).Flags().badel = 0; } cout << "wrongels = " << wrongels << endl; } diff --git a/libsrc/meshing/ruler2.hpp b/libsrc/meshing/ruler2.hpp index 3d9ca6af..8e3b3c41 100644 --- a/libsrc/meshing/ruler2.hpp +++ b/libsrc/meshing/ruler2.hpp @@ -1,6 +1,8 @@ #ifndef FILE_NETRULE #define FILE_NETRULE +namespace netgen +{ /// class netrule { @@ -165,5 +167,6 @@ public: /** Draws 2D rules. Visual testing of 2D meshing rules */ extern void DrawRules (); +} // namespace netgen #endif diff --git a/libsrc/meshing/ruler3.cpp b/libsrc/meshing/ruler3.cpp index dd70a8ab..959fe310 100644 --- a/libsrc/meshing/ruler3.cpp +++ b/libsrc/meshing/ruler3.cpp @@ -8,7 +8,7 @@ extern double minother; extern double minwithoutother; - static double CalcElementBadness (const NgArray & points, + static double CalcElementBadness (const Array & points, const Element & elem) { double vol, l, l4, l5, l6; @@ -49,9 +49,9 @@ extern double minwithoutother; int Meshing3 :: ApplyRules ( - NgArray & lpoints, // in: local points, out: old+new local points - NgArray & allowpoint, // in: 2 .. it is allowed to use pointi, 1..will be allowed later, 0..no means - NgArray & lfaces, // in: local faces, out: old+new local faces + Array & lpoints, // in: local points, out: old+new local points + Array & allowpoint, // in: 2 .. it is allowed to use pointi, 1..will be allowed later, 0..no means + Array & lfaces, // in: local faces, out: old+new local faces INDEX lfacesplit, // for local faces in outer radius INDEX_2_HASHTABLE & connectedpairs, // connected pairs for prism-meshing NgArray & elements, // out: new elements @@ -226,16 +226,17 @@ int Meshing3 :: ApplyRules // check each rule: // tstart.Stop(); // tloop.Start(); - for (int ri = 1; ri <= rules.Size(); ri++) + for (int rim = 0; rim < rules.Size(); rim++) { int base = (lfaces[0].GetNP() == 3) ? 100 : 200; NgProfiler::RegionTimer regx1(base); - NgProfiler::RegionTimer regx(base+ri); + NgProfiler::RegionTimer regx(base+rim+1); // sprintf (problems.Elem(ri), ""); - *problems.Elem(ri) = '\0'; + // *problems.Elem(ri) = '\0'; + problems[rim] = ""; - vnetrule * rule = rules.Get(ri); + vnetrule * rule = rules[rim].get(); if (rule->GetNP(1) != lfaces[0].GetNP()) continue; @@ -245,17 +246,17 @@ int Meshing3 :: ApplyRules if (rule->GetQuality() < 100) impossible = 0; if (testmode) - sprintf (problems.Elem(ri), "Quality not ok"); + problems[rim] = "Quality not ok"; continue; } if (testmode) - sprintf (problems.Elem(ri), "no mapping found"); + problems[rim] = "no mapping found"; loktestmode = testmode || rule->TestFlag ('t') || tolerance > 5; if (loktestmode) - (*testout) << "Rule " << ri << " = " << rule->Name() << endl; + (*testout) << "Rule " << rim+1 << " = " << rule->Name() << endl; pmap.SetSize (rule->GetNP()); fmapi.SetSize (rule->GetNF()); @@ -287,7 +288,7 @@ int Meshing3 :: ApplyRules int nfok = 2; NgProfiler::RegionTimer regfa(300); - NgProfiler::RegionTimer regx2(base+50+ri); + NgProfiler::RegionTimer regx2(base+50+rim+1); while (nfok >= 2) { @@ -314,7 +315,7 @@ int Meshing3 :: ApplyRules if (fnearness.Get(locfi) > rule->GetFNearness (nfok) || fused.Get(locfi) || - actfnp != lfaces.Get(locfi).GetNP() ) + actfnp != lfaces[locfi-1].GetNP() ) { // face not feasible in any rotation @@ -325,7 +326,7 @@ int Meshing3 :: ApplyRules ok = 1; - locface = &lfaces.Get(locfi); + locface = &lfaces[locfi-1]; // reference point already mapped differently ? @@ -376,7 +377,7 @@ int Meshing3 :: ApplyRules { PointIndex locpi = locface->PNumMod(j+locfr); - if (rule->GetPointNr (nfok, j) <= 3 && + if (rule->GetPointNr (nfok, j) < IndexBASE()+3 && pmap.Get(rule->GetPointNr(nfok, j)) != locpi) (*testout) << "change face1 point, mark1" << endl; @@ -419,7 +420,7 @@ int Meshing3 :: ApplyRules if (loktestmode) { (*testout) << "Faces Ok" << endl; - sprintf (problems.Elem(ri), "Faces Ok"); + problems[rim] = "Faces Ok"; } int npok = 1; @@ -457,7 +458,7 @@ int Meshing3 :: ApplyRules if (locpi.IsValid()) pused[locpi]--; - while (!ok && locpi < lpoints.Size()-1+PointIndex::BASE) + while (!ok && locpi < lpoints.Size()-1+IndexBASE()) { ok = 1; locpi++; @@ -527,8 +528,8 @@ int Meshing3 :: ApplyRules for (auto pi : pmap) (*testout) << pi << " "; (*testout) << endl; - sprintf (problems.Elem(ri), "mapping found"); - (*testout) << rule->GetNP(1) << " = " << lfaces.Get(1).GetNP() << endl; + problems[rim] = "mapping found"; + (*testout) << rule->GetNP(1) << " = " << lfaces[0].GetNP() << endl; } ok = 1; @@ -594,10 +595,7 @@ int Meshing3 :: ApplyRules if (ok) - { - foundmap.Elem(ri)++; - } - + foundmap[rim]++; @@ -642,7 +640,7 @@ int Meshing3 :: ApplyRules if (!rule->ConvexFreeZone()) { ok = 0; - sprintf (problems.Elem(ri), "Freezone not convex"); + problems[rim] = "Freezone not convex"; if (loktestmode) (*testout) << "Freezone not convex" << endl; @@ -659,11 +657,12 @@ int Meshing3 :: ApplyRules // check freezone: - for (int i = 1; i <= lpoints.Size(); i++) + // for (int i = 1; i <= lpoints.Size(); i++) + for (auto i : lpoints.Range()) { - if ( !pused.Get(i) ) + if ( !pused[i] ) { - const Point3d & lp = lpoints.Get(i); + const Point3d & lp = lpoints[i]; if (rule->fzbox.IsIn (lp)) { @@ -673,8 +672,7 @@ int Meshing3 :: ApplyRules { (*testout) << "Point " << i << " in Freezone" << endl; - sprintf (problems.Elem(ri), - "locpoint %d in Freezone", i); + problems[rim] = "locpoint " + ToString(i) + " in Freezone"; } ok = 0; break; @@ -690,7 +688,7 @@ int Meshing3 :: ApplyRules if (!fused.Get(i)) { int triin; - const MiniElement2d & lfacei = lfaces.Get(i); + const MiniElement2d & lfacei = lfaces[i-1]; if (!triboxes.Elem(i).Intersect (rule->fzbox)) triin = 0; @@ -743,19 +741,19 @@ int Meshing3 :: ApplyRules if (loktestmode) { - (*testout) << "El with " << lfaces.Get(i).GetNP() << " points in freezone: " - << lfaces.Get(i).PNum(1) << " - " - << lfaces.Get(i).PNum(2) << " - " - << lfaces.Get(i).PNum(3) << " - " - << lfaces.Get(i).PNum(4) << endl; - for (int lj = 1; lj <= lfaces.Get(i).GetNP(); lj++) - (*testout) << lpoints[lfaces.Get(i).PNum(lj)] << " "; + (*testout) << "El with " << lfaces[i-1].GetNP() << " points in freezone: " + << lfaces[i-1].PNum(1) << " - " + << lfaces[i-1].PNum(2) << " - " + << lfaces[i-1].PNum(3) << " - " + << lfaces[i-1].PNum(4) << endl; + for (int lj = 1; lj <= lfaces[i-1].GetNP(); lj++) + (*testout) << lpoints[lfaces[i-1].PNum(lj)] << " "; (*testout) << endl; sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone", - lfaces.Get(i).PNum(1), lfaces.Get(i).PNum(2), - lfaces.Get(i).PNum(3)); + lfaces[i-1].PNum(1), lfaces[i-1].PNum(2), + lfaces[i-1].PNum(3)); } #else if (loktestmode) @@ -787,23 +785,22 @@ int Meshing3 :: ApplyRules << lpoints[lfacei.PNum(4)] << endl; - sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone", - int(lfaces.Get(i).PNum(1)), - int(lfaces.Get(i).PNum(2)), - int(lfaces.Get(i).PNum(3))); + problems[rim] = "triangle ("+ToString(lfaces[i-1].PNum(1))+", " + + ToString(lfaces[i-1].PNum(2)) + ", " + + ToString(lfaces[i-1].PNum(3)) + ") in Freezone"; } hc = 0; for (int k = rule->GetNOldF() + 1; k <= rule->GetNF(); k++) { - if (rule->GetPointNr(k, 1) <= rule->GetNOldP() && - rule->GetPointNr(k, 2) <= rule->GetNOldP() && - rule->GetPointNr(k, 3) <= rule->GetNOldP()) + if (rule->GetPointNr(k, 1) < IndexBASE()+rule->GetNOldP() && + rule->GetPointNr(k, 2) < IndexBASE()+rule->GetNOldP() && + rule->GetPointNr(k, 3) < IndexBASE()+rule->GetNOldP()) { for (int j = 1; j <= 3; j++) - if (lfaces.Get(i).PNumMod(j ) == pmap.Get(rule->GetPointNr(k, 1)) && - lfaces.Get(i).PNumMod(j+1) == pmap.Get(rule->GetPointNr(k, 3)) && - lfaces.Get(i).PNumMod(j+2) == pmap.Get(rule->GetPointNr(k, 2))) + if (lfaces[i-1].PNumMod(j ) == pmap.Get(rule->GetPointNr(k, 1)) && + lfaces[i-1].PNumMod(j+1) == pmap.Get(rule->GetPointNr(k, 3)) && + lfaces[i-1].PNumMod(j+2) == pmap.Get(rule->GetPointNr(k, 2))) { fmapi.Elem(k) = i; hc = 1; @@ -816,7 +813,7 @@ int Meshing3 :: ApplyRules // << " - " << pmap.Get (rule->GetPointNr(k, 3)) << " ) " // << endl; - strcpy (problems.Elem(ri), "other"); + problems[rim] = "other"; } } } @@ -826,14 +823,21 @@ int Meshing3 :: ApplyRules if (loktestmode) { (*testout) << "Triangle in freezone: " - << lfaces.Get(i).PNum(1) << " - " - << lfaces.Get(i).PNum(2) << " - " - << lfaces.Get(i).PNum(3) << endl; + << lfaces[i-1].PNum(1) << " - " + << lfaces[i-1].PNum(2) << " - " + << lfaces[i-1].PNum(3) << endl; - sprintf (problems.Elem(ri), "triangle (%d, %d, %d) in Freezone", - int (lfaces.Get(i).PNum(1)), - int (lfaces.Get(i).PNum(2)), - int (lfaces.Get(i).PNum(3))); + /* + snprintf (problems.Elem(ri), 255, "triangle (%d, %d, %d) in Freezone", + int (lfaces[i-1].PNum(1)), + int (lfaces[i-1].PNum(2)), + int (lfaces[i-1].PNum(3))); + */ + problems[rim] = "triangle (" + + ToString(lfaces[i-1].PNum(1))+", " + + ToString(lfaces[i-1].PNum(2)) + ", " + + ToString(lfaces[i-1].PNum(3)) + ") in Freezone"; + } ok = 0; } @@ -857,7 +861,7 @@ int Meshing3 :: ApplyRules if (loktestmode) { (*testout) << "Rule ok" << endl; - sprintf (problems.Elem(ri), "Rule ok, err = %f", err); + problems[rim] = "Rule ok, err = "+ToString(err); } @@ -922,7 +926,7 @@ int Meshing3 :: ApplyRules { if (loktestmode) { - sprintf (problems.Elem(ri), "Orientation wrong"); + problems[rim] = "Orientation wrong"; (*testout) << "Orientation wrong ("<< n*v3 << ")" << endl; } ok = 0; @@ -933,13 +937,13 @@ int Meshing3 :: ApplyRules // new points in free-zone ? for (int i = rule->GetNOldP() + 1; i <= rule->GetNP() && ok; i++) - if (!rule->IsInFreeZone (lpoints.Get(pmap.Get(i)))) + if (!rule->IsInFreeZone (lpoints[pmap.Get(i)])) { if (loktestmode) { - (*testout) << "Newpoint " << lpoints.Get(pmap.Get(i)) + (*testout) << "Newpoint " << lpoints[pmap.Get(i)] << " outside convex hull" << endl; - sprintf (problems.Elem(ri), "newpoint outside convex hull"); + problems[rim] = "newpoint outside convex hull"; } ok = 0; @@ -958,9 +962,9 @@ int Meshing3 :: ApplyRules // Calculate Element badness teterr = 0; - for (int i = 1; i <= elements.Size(); i++) + for (auto i : elements.Range()) { - double hf = CalcElementBadness (lpoints, elements.Get(i)); + double hf = CalcElementBadness (lpoints, elements[i]); if (hf > teterr) teterr = hf; } @@ -1014,7 +1018,7 @@ int Meshing3 :: ApplyRules { ok = 0; if (loktestmode) - sprintf (problems.Elem(ri), "oldlen < newlen"); + problems[rim] = "oldlen < newlen"; } } @@ -1027,7 +1031,7 @@ int Meshing3 :: ApplyRules if (ok && teterr < tolerance) { - canuse.Elem(ri) ++; + canuse[rim] ++; /* (*testout) << "can use rule " << rule->Name() << ", err = " << teterr << endl; @@ -1036,7 +1040,7 @@ int Meshing3 :: ApplyRules (*testout) << endl; */ - if (strcmp (problems.Elem(ri), "other") == 0) + if (problems[rim] == "other") { if (teterr < minother) minother = teterr; @@ -1057,7 +1061,7 @@ int Meshing3 :: ApplyRules if (loktestmode) (*testout) << "use rule" << endl; - found = ri; + found = rim+1; minteterr = teterr; if (testmode) @@ -1066,25 +1070,29 @@ int Meshing3 :: ApplyRules { (*testout) << "P" << i << ": Ref: " << rule->GetPoint (i) << " is: " - << lpoints.Get(pmap.Get(i)) << endl; + << lpoints[pmap.Get(i)] << endl; } } tempnewpoints.SetSize (0); - for (int i = noldlp+1; i <= lpoints.Size(); i++) - tempnewpoints.Append (lpoints.Get(i)); + // for (int i = noldlp+1; i <= lpoints.Size(); i++) + for (auto i : lpoints.Range().Modify(noldlp, 0)) + tempnewpoints.Append (lpoints[i]); tempnewfaces.SetSize (0); - for (int i = noldlf+1; i <= lfaces.Size(); i++) - tempnewfaces.Append (lfaces.Get(i)); + // for (int i = noldlf+1; i <= lfaces.Size(); i++) + for (auto i : lfaces.Range().Modify(noldlf,0)) + tempnewfaces.Append (lfaces[i]); tempdelfaces.SetSize (0); - for (int i = 1; i <= delfaces.Size(); i++) - tempdelfaces.Append (delfaces.Get(i)); + // for (int i = 1; i <= delfaces.Size(); i++) + for (auto i : delfaces.Range()) + tempdelfaces.Append (delfaces[i]); tempelements.SetSize (0); - for (int i = 1; i <= elements.Size(); i++) - tempelements.Append (elements.Get(i)); + // for (int i = 1; i <= elements.Size(); i++) + for (auto i : elements.Range()) + tempelements.Append (elements[i]); } diff --git a/libsrc/meshing/ruler3.hpp b/libsrc/meshing/ruler3.hpp index 91ee4653..a2dfe6e1 100644 --- a/libsrc/meshing/ruler3.hpp +++ b/libsrc/meshing/ruler3.hpp @@ -1,6 +1,8 @@ #ifndef FILE_RULER3 #define FILE_RULER3 +namespace netgen +{ /** 3D element generation rule. @@ -170,10 +172,10 @@ public: int GetNP (int fn) const { return faces.Get(fn).GetNP(); } /// - int GetPointNr (int fn, int endp) const + PointIndex GetPointNr (int fn, int endp) const { return faces.Get(fn).PNum(endp); } /// - int GetPointNrMod (int fn, int endp) const + PointIndex GetPointNrMod (int fn, int endp) const { return faces.Get(fn).PNumMod(endp); } /// const fourint & GetOrientation (int i) { return orientations.Get(i); } @@ -204,7 +206,6 @@ public: // friend void Plot3DRule (const ROT3D & r, char key); }; - - +} // namespace netgen #endif diff --git a/libsrc/meshing/secondorder.cpp b/libsrc/meshing/secondorder.cpp index b69b1474..611a61f3 100644 --- a/libsrc/meshing/secondorder.cpp +++ b/libsrc/meshing/secondorder.cpp @@ -174,8 +174,8 @@ namespace netgen int nnp = newel.GetNP(); for (int j = 0; j < nnp-onp; j++) { - int pi1 = newel[betw[j][0]]; - int pi2 = newel[betw[j][1]]; + PointIndex pi1 = newel[betw[j][0]]; + PointIndex pi2 = newel[betw[j][1]]; INDEX_2 i2 = INDEX_2::Sort (pi1, pi2); @@ -207,9 +207,10 @@ namespace netgen // refine volume elements - for (int i = 1; i <= mesh.GetNE(); i++) + // for (int i = 1; i <= mesh.GetNE(); i++) + for (ElementIndex ei : mesh.VolumeElements().Range()) { - const Element & el = mesh.VolumeElement(i); + const Element & el = mesh.VolumeElement(ei); int onp = 0; Element newel(TET); @@ -342,7 +343,7 @@ namespace netgen } } - mesh.VolumeElement (i) = newel; + mesh.VolumeElement (ei) = newel; } @@ -351,17 +352,17 @@ namespace netgen // update identification tables for (int i = 1; i <= mesh.GetIdentifications().GetMaxNr(); i++) { - NgArray identmap; + idmap_type identmap; mesh.GetIdentifications().GetMap (i, identmap); for (INDEX_2_HASHTABLE::Iterator it = between.Begin(); it != between.End(); it++) { - INDEX_2 i2; + PointIndices<2> i2; PointIndex newpi; between.GetData (it, i2, newpi); - INDEX_2 oi2(identmap.Get(i2.I1()), - identmap.Get(i2.I2())); + PointIndices<2> oi2(identmap[i2[0]], + identmap[i2[1]]); oi2.Sort(); if (between.Used (oi2)) { @@ -423,16 +424,16 @@ namespace netgen { PrintMessage (3, "Validate mesh"); int np = mesh.GetNP(); - int ne = mesh.GetNE(); // int i, j; NgArray parents(np); for (int i = 1; i <= np; i++) parents.Elem(i) = INDEX_2(0,0); - for (int i = 1; i <= ne; i++) + // for (int i = 1; i <= ne; i++) + for (ElementIndex ei : mesh.VolumeElements().Range()) { - const Element & el = mesh.VolumeElement(i); + const Element & el = mesh[ei]; if (el.GetType() == TET10) { static int betweentab[6][3] = @@ -469,19 +470,20 @@ namespace netgen int cnttrials = 100; int wrongels = 0; - for (int i = 1; i <= ne; i++) - if (mesh.VolumeElement(i).CalcJacobianBadness (mesh.Points()) > 1e10) + // for (int i = 1; i <= ne; i++) + for (ElementIndex ei : mesh.VolumeElements().Range()) + if (mesh.VolumeElement(ei).CalcJacobianBadness (mesh.Points()) > 1e10) { wrongels++; - mesh.VolumeElement(i).Flags().badel = 1; + mesh.VolumeElement(ei).Flags().badel = 1; } else - mesh.VolumeElement(i).Flags().badel = 0; + mesh.VolumeElement(ei).Flags().badel = 0; double facok = 0; double factry; - NgBitArray illegalels(ne); + BitArray illegalels(ne+1); illegalels.Clear(); @@ -505,14 +507,17 @@ namespace netgen can.Elem(parents.Get(i).I2())); } - NgBitArray boundp(np); + TBitArray boundp(np); boundp.Clear(); + /* for (int i = 1; i <= mesh.GetNSE(); i++) { const Element2d & sel = mesh.SurfaceElement(i); - for (int j = 1; j <= sel.GetNP(); j++) - boundp.Set(sel.PNum(j)); - } + */ + for (auto & sel : mesh.SurfaceElements()) + for (int j = 1; j <= sel.GetNP(); j++) + boundp.SetBit(sel.PNum(j)); + // } (*testout) << "bpoints:" << endl; @@ -552,6 +557,7 @@ namespace netgen // (*testout) << "bad els: " << endl; wrongels = 0; for (int i = 1; i <= ne; i++) + { if (!illegalels.Test(i) && mesh.VolumeElement(i). @@ -563,7 +569,7 @@ namespace netgen if (lam < 1e-4) - illegalels.Set(i); + illegalels.SetBit(i); /* diff --git a/libsrc/meshing/smoothing2.5.cpp b/libsrc/meshing/smoothing2.5.cpp index 587c8d47..7f175882 100644 --- a/libsrc/meshing/smoothing2.5.cpp +++ b/libsrc/meshing/smoothing2.5.cpp @@ -110,7 +110,7 @@ namespace netgen int np = mesh.GetNP(); int ne = mesh.GetNE(); - NgBitArray badnodes(np); + TBitArray badnodes(np); badnodes.Clear(); for (i = 1; i <= ne; i++) @@ -119,7 +119,7 @@ namespace netgen double bad = el.CalcJacobianBadness (mesh.Points()); if (bad > 1) for (j = 1; j <= el.GetNP(); j++) - badnodes.Set (el.PNum(j)); + badnodes.SetBit (el.PNum(j)); } diff --git a/libsrc/meshing/smoothing2.cpp b/libsrc/meshing/smoothing2.cpp index 0e6db78a..25de92f5 100644 --- a/libsrc/meshing/smoothing2.cpp +++ b/libsrc/meshing/smoothing2.cpp @@ -214,7 +214,7 @@ namespace netgen { } ; - virtual double Func (const Vector & x) const + virtual double Func (const Vector & x) const override { double badness = 0; @@ -243,7 +243,7 @@ namespace netgen } - virtual double FuncGrad (const Vector & x, Vector & g) const + virtual double FuncGrad (const Vector & x, Vector & g) const override { Vec<3> vgrad; Point<3> pp1; @@ -278,7 +278,7 @@ namespace netgen return badness; } - virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const + virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const override { deriv = 0; double badness = 0; @@ -479,8 +479,8 @@ namespace netgen Opti2dLocalData & ald) : mesh(amesh), ld(ald), geo(*amesh.GetGeometry()) { } ; - virtual double FuncGrad (const Vector & x, Vector & g) const; - virtual double Func (const Vector & x) const; + virtual double FuncGrad (const Vector & x, Vector & g) const override; + virtual double Func (const Vector & x) const override; }; double Opti2EdgeMinFunction :: Func (const Vector & x) const @@ -550,9 +550,9 @@ namespace netgen Opti2dLocalData & ald) : mesh(amesh), ld(ald), geo(*amesh.GetGeometry()) { } ; - virtual double FuncGrad (const Vector & x, Vector & g) const; - virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const; - virtual double Func (const Vector & x) const; + virtual double FuncGrad (const Vector & x, Vector & g) const override; + virtual double FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const override; + virtual double Func (const Vector & x) const override; }; double Opti2SurfaceMinFunctionJacobian :: @@ -584,7 +584,7 @@ namespace netgen // meshthis -> ProjectPoint (surfi, pp1); // meshthis -> GetNormalVector (surfi, pp1, n); - static NgArray> pts2d; + static NgArray> pts2d; // better: use hashtable pts2d.SetSize(mesh.GetNP()); grad = 0; @@ -699,7 +699,8 @@ namespace netgen int ncolors; Array colors; bool mixed = false; - auto elementsonpoint = mesh.CreatePoint2SurfaceElementTable( faceindex ); + // auto elementsonpoint = mesh.CreatePoint2SurfaceElementTable( faceindex ); + auto elementsonpoint = mesh.CreateCompressedPoint2SurfaceElementTable( faceindex ); NgArray savepoints(mesh.GetNP()); Table color_table; diff --git a/libsrc/meshing/smoothing3.cpp b/libsrc/meshing/smoothing3.cpp index 321c6704..28d82fec 100644 --- a/libsrc/meshing/smoothing3.cpp +++ b/libsrc/meshing/smoothing3.cpp @@ -91,7 +91,7 @@ namespace netgen } PointFunction1 :: PointFunction1 (Mesh::T_POINTS & apoints, - const NgArray & afaces, + const NgArray> & afaces, const MeshingParameters & amp, double ah) : points(apoints), faces(afaces), mp(amp) @@ -335,6 +335,20 @@ namespace netgen { static Timer tim("PointFunction - build elementsonpoint table"); RegionTimer reg(tim); + Array non_tet_points(points.Size()); + non_tet_points = false; + // Don't optimize if point is adjacent to a non-tet element + ParallelForRange(elements.Range(), [&] (auto myrange) + { + for(auto ei : myrange) + { + const auto & el = elements[ei]; + if(el.NP()!=4) + for(auto pi : el.PNums()) + non_tet_points[pi] = true; + } + }); + elementsonpoint = ngcore::CreateSortedTable( elements.Range(), [&](auto & table, ElementIndex ei) { @@ -344,6 +358,7 @@ namespace netgen return; for (PointIndex pi : el.PNums()) + if(!non_tet_points[pi]) table.Add (pi, ei); }, points.Size()); } @@ -1001,7 +1016,6 @@ void JacobianPointFunction :: SetPointIndex (PointIndex aactpind) double JacobianPointFunction :: Func (const Vector & v) const { - int j; double badness = 0; Point<3> hp = points[actpind]; @@ -1027,7 +1041,7 @@ double JacobianPointFunction :: Func (const Vector & v) const double JacobianPointFunction :: FuncGrad (const Vector & x, Vector & g) const { - int j, k; + int k; int lpi; double badness = 0;//, hbad; @@ -1094,7 +1108,7 @@ FuncGrad (const Vector & x, Vector & g) const double JacobianPointFunction :: FuncDeriv (const Vector & x, const Vector & dir, double & deriv) const { - int j, k; + int k; int lpi; double badness = 0; @@ -1338,7 +1352,7 @@ void Mesh :: ImproveMesh (const MeshingParameters & mp, OPTIMIZEGOAL goal) (*testout) << "Improve Mesh" << "\n"; PrintMessage (3, "ImproveMesh"); - int np = GetNP(); + // int np = GetNP(); int ne = GetNE(); PointFunction pf_glob(*this, mp); @@ -1400,7 +1414,6 @@ void Mesh :: ImproveMesh (const MeshingParameters & mp, OPTIMIZEGOAL goal) multithread.task = "Optimize Volume: Smooth Mesh"; topt.Start(); - int counter = 0; for (auto icolor : Range(ncolors)) { if (multithread.terminate) @@ -1424,8 +1437,6 @@ void Mesh :: ImproveMesh (const MeshingParameters & mp, OPTIMIZEGOAL goal) PointIndex pi = color_table[icolor][i]; if ( (*this)[pi].Type() == INNERPOINT ) { - counter++; - double lh = pointh[pi]; pf.SetLocalH (lh); par.typx = lh; @@ -1474,7 +1485,7 @@ void Mesh :: ImproveMesh (const MeshingParameters & mp, OPTIMIZEGOAL goal) // Improve Condition number of Jacobian, any elements void Mesh :: ImproveMeshJacobian (const MeshingParameters & mp, - OPTIMIZEGOAL goal, const NgBitArray * usepoint) + OPTIMIZEGOAL goal, const TBitArray * usepoint) { // int i, j; @@ -1496,7 +1507,7 @@ void Mesh :: ImproveMeshJacobian (const MeshingParameters & mp, par.maxit_linsearch = 20; par.maxit_bfgs = 20; - NgBitArray badnodes(np); + TBitArray badnodes(np); badnodes.Clear(); for (int i = 1; i <= ne; i++) @@ -1505,10 +1516,10 @@ void Mesh :: ImproveMeshJacobian (const MeshingParameters & mp, double bad = el.CalcJacobianBadness (Points()); if (bad > 1) for (int j = 1; j <= el.GetNP(); j++) - badnodes.Set (el.PNum(j)); + badnodes.SetBit (el.PNum(j)); } - NgArray pointh (points.Size()); + Array pointh (points.Size()); if(HasLocalHFunction()) { @@ -1597,10 +1608,10 @@ void Mesh :: ImproveMeshJacobian (const MeshingParameters & mp, // Improve Condition number of Jacobian, any elements void Mesh :: ImproveMeshJacobianOnSurface (const MeshingParameters & mp, - const NgBitArray & usepoint, + const TBitArray & usepoint, const NgArray< Vec<3>* > & nv, OPTIMIZEGOAL goal, - const NgArray< NgArray* > * idmaps) + const NgArray< idmap_type* > * idmaps) { // int i, j; @@ -1617,8 +1628,8 @@ void Mesh :: ImproveMeshJacobianOnSurface (const MeshingParameters & mp, JacobianPointFunction pf(points, volelements); - NgArray< NgArray* > locidmaps; - const NgArray< NgArray* > * used_idmaps; + NgArray< idmap_type* > locidmaps; + const NgArray< idmap_type* > * used_idmaps; if(idmaps) used_idmaps = idmaps; @@ -1630,7 +1641,7 @@ void Mesh :: ImproveMeshJacobianOnSurface (const MeshingParameters & mp, { if(GetIdentifications().GetType(i) == Identifications::PERIODIC) { - locidmaps.Append(new NgArray); + locidmaps.Append(new idmap_type); GetIdentifications().GetMap(i,*locidmaps.Last(),true); } } @@ -1653,7 +1664,7 @@ void Mesh :: ImproveMeshJacobianOnSurface (const MeshingParameters & mp, par.maxit_linsearch = 20; par.maxit_bfgs = 20; - NgBitArray badnodes(np); + TBitArray badnodes(np); badnodes.Clear(); for (int i = 1; i <= ne; i++) @@ -1662,7 +1673,7 @@ void Mesh :: ImproveMeshJacobianOnSurface (const MeshingParameters & mp, double bad = el.CalcJacobianBadness (Points()); if (bad > 1) for (int j = 1; j <= el.GetNP(); j++) - badnodes.Set (el.PNum(j)); + badnodes.SetBit (el.PNum(j)); } NgArray pointh (points.Size()); @@ -1720,26 +1731,31 @@ void Mesh :: ImproveMeshJacobianOnSurface (const MeshingParameters & mp, pf.SetPointIndex (pi); - PointIndex brother (-1); + constexpr PointIndex state0(PointIndex::INVALID); + constexpr PointIndex statem1 = state0-1; + + PointIndex brother = statem1; if(usesum) { - for(int j=0; brother == -1 && jSize(); j++) + for(int j=0; brother == statem1 && jSize(); j++) { - if(pi < (*used_idmaps)[j]->Size() + PointIndex::BASE) + if(pi < (*used_idmaps)[j]->Size() + IndexBASE()) { brother = (*(*used_idmaps)[j])[pi]; - if(brother == pi || brother == 0) - brother = -1; + if(brother == pi || brother == state0) + brother = statem1; } } - if(brother >= pi) + // if(brother >= pi) + if(brother-pi >= 0) { pf2ptr->SetPointIndex(brother); pf2ptr->SetNV(*nv[brother-1]); } } - if(usesum && brother < pi) + // if(usesum && brother < pi) + if(usesum && (brother-pi < 0)) continue; //pf.UnSetNV(); x = 0; @@ -1748,12 +1764,12 @@ void Mesh :: ImproveMeshJacobianOnSurface (const MeshingParameters & mp, pf.SetNV(*nv[pi-1]); x = 0; - int pok = (brother == -1) ? (pf.Func (x) < 1e10) : (pf_sum.Func (x) < 1e10); + int pok = (brother == statem1) ? (pf.Func (x) < 1e10) : (pf_sum.Func (x) < 1e10); if (pok) { - if(brother == -1) + if(brother == statem1) BFGS (x, pf, par); else BFGS (x, pf_sum, par); @@ -1762,7 +1778,7 @@ void Mesh :: ImproveMeshJacobianOnSurface (const MeshingParameters & mp, for(int j=0; j<3; j++) points[pi](j) += x(j);// - scal*nv[i-1].X(j); - if(brother != -1) + if(brother != statem1) for(int j=0; j<3; j++) points[brother](j) += x(j);// - scal*nv[brother-1].X(j); @@ -1772,8 +1788,8 @@ void Mesh :: ImproveMeshJacobianOnSurface (const MeshingParameters & mp, { cout << "el not ok" << endl; (*testout) << "el not ok" << endl - << " func " << ((brother == -1) ? pf.Func(x) : pf_sum.Func (x)) << endl; - if(brother != -1) + << " func " << ((brother == statem1) ? pf.Func(x) : pf_sum.Func (x)) << endl; + if(brother != statem1) (*testout) << " func1 " << pf.Func(x) << endl << " func2 " << pf2ptr->Func(x) << endl; } diff --git a/libsrc/meshing/specials.cpp b/libsrc/meshing/specials.cpp index a391ee94..edeb2481 100644 --- a/libsrc/meshing/specials.cpp +++ b/libsrc/meshing/specials.cpp @@ -62,13 +62,13 @@ void CutOffAndCombine (Mesh & mesh, const Mesh & othermesh) } cout << endl; - NgBitArray connected(mesh.GetNP()); + TBitArray connected(mesh.GetNP()); connected.Clear(); for (i = 1; i <= mesh.GetNSE(); i++) { const Element2d & el = mesh.SurfaceElement(i); for (j = 1; j <= 3; j++) - connected.Set(el.PNum(j)); + connected.SetBit(el.PNum(j)); } bool changed; @@ -92,7 +92,7 @@ void CutOffAndCombine (Mesh & mesh, const Mesh & othermesh) { changed = 1; for (j = 0; j < 4; j++) - connected.Set (el[j]); + connected.SetBit (el[j]); } } } @@ -120,13 +120,14 @@ void CutOffAndCombine (Mesh & mesh, const Mesh & othermesh) mesh.Compress(); mesh.FindOpenElements(); - NgBitArray locked(mesh.GetNP()); + TBitArray locked(mesh.GetNP()); locked.Set(); for (i = 1; i <= mesh.GetNOpenElements(); i++) for (j = 1; j <= 3; j++) locked.Clear (mesh.OpenElement(i).PNum(j)); - for (PointIndex i (1); i <= locked.Size(); i++) + // for (PointIndex i (1); i <= locked.Size(); i++) + for (PointIndex i : locked.Range()) if (locked.Test(i)) { mesh.AddLockedPoint (i); diff --git a/libsrc/meshing/specials.hpp b/libsrc/meshing/specials.hpp index fd10634d..feed8146 100644 --- a/libsrc/meshing/specials.hpp +++ b/libsrc/meshing/specials.hpp @@ -7,10 +7,11 @@ */ - +namespace netgen { /// DLL_HEADER extern void CutOffAndCombine (Mesh & mesh, const Mesh & othermesh); DLL_HEADER extern void HelmholtzMesh (Mesh & mesh); +} // namespace netgen #endif diff --git a/libsrc/meshing/surfacegeom.cpp b/libsrc/meshing/surfacegeom.cpp index d0f3ceb0..09f57332 100644 --- a/libsrc/meshing/surfacegeom.cpp +++ b/libsrc/meshing/surfacegeom.cpp @@ -120,7 +120,7 @@ namespace netgen Array> tangs(2); Vec<3> diff, f_uu, f_vv, f_uv; Vec<2> r, dx; - double norm_r, det, energy=0.0, new_energy=0.0, alpha=2.0,u=0.0,v=0.0,maxerr=1e-16; + double norm_r, energy=0.0, new_energy=0.0, alpha=2.0,u=0.0,v=0.0,maxerr=1e-16; Mat<2,2> mat, inv; int num=0, maxit=25; double damping=0.5; @@ -197,6 +197,7 @@ namespace netgen return false; } + void SurfaceGeometry :: 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 { newgi.u = ap1.u+secpoint*(ap2.u-ap1.u); @@ -207,6 +208,32 @@ namespace netgen newp = Point<3>(func(Point<2>(newgi.u, newgi.v))); } + + void CheckForBBBPnt(const Array>& bbbpts, const Point<3>& pnt, Array& found, Array& indbbbpts, const Array& pids) + { + for (int k = 0; k < bbbpts.Size(); k++) + { + auto diff = pnt - bbbpts[k]; + if(diff.Length2() < 1e-14) + { + found[k] = true; + indbbbpts[k] = pids[pids.Size()-1]; + } + } + } + + void CheckForSingularity(const Array>& hppoints, const Point<3>& pnt, const Array& hpptsfac, shared_ptr & mesh, const Array& pids) + { + for (int k = 0; k < hppoints.Size(); k++) + { + auto diff = pnt - hppoints[k]; + if(diff.Length2() < 1e-14) + { + (*mesh)[pids[pids.Size()-1]].Singularity(hpptsfac[k]); + } + + } + } void SurfaceGeometry :: PointBetween(const Point<3> & p1, const Point<3> & p2, double secpoint, int surfi, @@ -223,7 +250,7 @@ namespace netgen //ProjectPointGI(surfi, newp, newgi); } - int SurfaceGeometry :: GenerateStructuredMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames, const Array>& hppoints, const Array& hpptsfac, const Array& hpbnd, const Array& hpbndfac) + int SurfaceGeometry :: GenerateStructuredMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames, const Array>& hppoints, const Array& hpptsfac, const Array& hpbnd, const Array& hpbndfac, Array layer_thickness[4], bool layer_quad) { mesh->SetDimension(3); @@ -231,41 +258,87 @@ namespace netgen found = false; Array indbbbpts(bbbpts.Size()); + int numx = nx; + int numy = ny; + + size_t total_layer_el[4] = {layer_thickness[0].Size(), layer_thickness[1].Size(), layer_thickness[2].Size(), layer_thickness[3].Size()}; + + double interior_x = 1.0; + double interior_y = 1.0; + for(double scale : layer_thickness[0]) + interior_x -= scale; + for(double scale : layer_thickness[2]) + interior_x -= scale; + for(double scale : layer_thickness[1]) + interior_y -= scale; + for(double scale : layer_thickness[3]) + interior_y -= scale; + + auto AddPoint = [&] (double offsetx, double offsety, Array & pids, Array & pgis) + { + PointGeomInfo pgi; + pgi.trignum = -1; + pgi.u = offsetx; + pgi.v = offsety; + + + Point<3> pnt = Point<3>(func(Point<2>(pgi.u,pgi.v))); + pids.Append(mesh->AddPoint(pnt)); + pgis.Append(pgi); + + CheckForBBBPnt(bbbpts, pnt, found, indbbbpts, pids); + CheckForSingularity(hppoints, pnt, hpptsfac, mesh, pids); + }; + + auto InternalLoop = [&] (double offsety, Array & pids, Array & pgis) + { + int j = 0; + double offsetx = 0.0; + + for(int l=0; l < layer_thickness[0].Size(); l++,j++) + { + AddPoint(offsetx+layer_thickness[0][l]*double(j-l), offsety, pids, pgis); + offsetx += layer_thickness[0][l]; + } + + + for(;j <= nx-total_layer_el[2]; j++) + AddPoint(offsetx + interior_x*double(j-total_layer_el[0])/(nx-total_layer_el[0]-total_layer_el[2]), offsety, pids, pgis); + offsetx += interior_x; + + int startj = j; + for(int l=0; l < layer_thickness[2].Size(); l++, j++) + { + AddPoint(offsetx+layer_thickness[2][layer_thickness[2].Size()-1-l]*double(j-startj-l+1), offsety, pids, pgis); + + offsetx += layer_thickness[2][layer_thickness[2].Size()-1-l]; + } + }; Array pids; Array pgis; - for(int i=0; i <= ny; i++) - for(int j=0; j <= nx; j++) - { - PointGeomInfo pgi; - pgi.trignum = -1; - pgi.u = double(j)/nx; - pgi.v = double(i)/ny; + + int i = 0; + double offsety = 0.0; - Point<3> pnt = Point<3>(func(Point<2>(pgi.u,pgi.v))); - pids.Append(mesh->AddPoint(pnt)); - pgis.Append(pgi); - - for (int k = 0; k < bbbpts.Size(); k++) - { - auto diff = pnt - bbbpts[k]; - if(diff.Length2() < 1e-14) - { - found[k] = true; - indbbbpts[k] = pids[pids.Size()-1]; - } - } + for(int k=0; k < layer_thickness[1].Size(); k++,i++) + { + InternalLoop(offsety, pids, pgis); + offsety += layer_thickness[1][k]; + } - for (int k = 0; k < hppoints.Size(); k++) - { - auto diff = pnt - hppoints[k]; - if(diff.Length2() < 1e-14) - { - (*mesh)[pids[pids.Size()-1]].Singularity(hpptsfac[k]); - } - - } - } + for(; i <= ny-total_layer_el[3]; i++) + { + InternalLoop(offsety, pids, pgis); + offsety += interior_y/(ny-total_layer_el[1]-total_layer_el[3]); + } + offsety -= interior_y/(ny-total_layer_el[1]-total_layer_el[3]); + + for(int k=0; k < layer_thickness[3].Size(); k++,i++) + { + offsety += layer_thickness[3][layer_thickness[3].Size()-1-k]; + InternalLoop(offsety, pids, pgis); + } for (bool f : found) if (!f) @@ -279,14 +352,14 @@ namespace netgen mesh->AddFaceDescriptor(fd); - for(int i=0; i < ny; i++) + for(int i=0; i < numy; i++) { - for(int j=0; j < nx; j++) + for(int j=0; j < numx; j++) { - int base = i * (nx+1) + j; - if (quads) + int base = i * (numx+1) + j; + if (quads || (layer_quad && i < total_layer_el[1]) || (layer_quad && i > numy-1-total_layer_el[3]) || (layer_quad && j < total_layer_el[0]) || (layer_quad && j > numx-1-total_layer_el[2]) ) { - int pnum[4] = {base,base+1,base+nx+2,base+nx+1}; + int pnum[4] = {base,base+1,base+numx+2,base+numx+1}; Element2d el = Element2d(QUAD); for (int i = 0; i < 4; i++) { @@ -305,19 +378,19 @@ namespace netgen { pnum1[0] = base; pnum1[1] = base+1; - pnum1[2] = base+nx+2; + pnum1[2] = base+numx+2; pnum2[0] = base; - pnum2[1] = base+nx+2; - pnum2[2] = base+nx+1; + pnum2[1] = base+numx+2; + pnum2[2] = base+numx+1; } else { pnum1[0] = base; pnum1[1] = base+1; - pnum1[2] = base+nx+1; + pnum1[2] = base+numx+1; pnum2[0] = base+1; - pnum2[1] = base+nx+2; - pnum2[2] = base+nx+1; + pnum2[1] = base+numx+2; + pnum2[2] = base+numx+1; } Element2d el = Element2d(TRIG); @@ -357,7 +430,7 @@ namespace netgen } // needed for codim2 in 3d seg.edgenr = 1; - for(int i=0; i < nx; i++) + for(int i=0; i < numx; i++) { seg[0] = pids[i]; seg[1] = pids[i+1]; @@ -388,18 +461,18 @@ namespace netgen } } - for(int i=0; iAddSegment(seg); @@ -419,18 +492,18 @@ namespace netgen } } - for(int i=0; iAddSegment(seg); @@ -450,18 +523,18 @@ namespace netgen } - for(int i=0; iAddSegment(seg); diff --git a/libsrc/meshing/surfacegeom.hpp b/libsrc/meshing/surfacegeom.hpp index 6402f103..3829be55 100644 --- a/libsrc/meshing/surfacegeom.hpp +++ b/libsrc/meshing/surfacegeom.hpp @@ -62,7 +62,7 @@ namespace netgen const PointGeomInfo & gi2, Point<3> & newp, PointGeomInfo & newgi) const override; - int GenerateStructuredMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames, const Array>& hppoints, const Array& hpptsfac, const Array& hpbnd, const Array& hpbndfac); + int GenerateStructuredMesh(shared_ptr & mesh, bool quads, int nx, int ny, bool flip_triangles, const Array>& bbbpts, const Array& bbbnames, const Array>& hppoints, const Array& hpptsfac, const Array& hpbnd, const Array& hpbndfac, Array layer_thickness[4], bool layer_quad); }; diff --git a/libsrc/meshing/topology.cpp b/libsrc/meshing/topology.cpp index 00108838..1ba2f461 100644 --- a/libsrc/meshing/topology.cpp +++ b/libsrc/meshing/topology.cpp @@ -5,7 +5,6 @@ namespace netgen { using ngcore::ParallelForRange; using ngcore::ParallelFor; - using ngcore::INT; using ngcore::TasksPerThread; /* @@ -103,11 +102,11 @@ namespace netgen auto eledges = MeshTopology::GetEdges (el.GetType()); for (int k = 0; k < eledges.Size(); k++) { - INDEX_2 edge(el[eledges[k][0]], el[eledges[k][1]]); + PointIndices<2> edge(el[eledges[k][0]], el[eledges[k][1]]); - int edgedir = (edge.I1() > edge.I2()); - if (edgedir) swap (edge.I1(), edge.I2()); - if (edge.I1() != v) continue; + bool edgedir = edge[0] > edge[1]; + if (edgedir) swap (edge[0], edge[1]); + if (edge[0] != v) continue; func (edge, elnr, k, 3); } @@ -120,7 +119,7 @@ namespace netgen auto eledges = MeshTopology::GetEdges (el.GetType()); for (int k = 0; k < eledges.Size(); k++) { - INDEX_2 edge(el[eledges[k][0]], el[eledges[k][1]]); + PointIndices<2> edge(el[eledges[k][0]], el[eledges[k][1]]); int edgedir = (edge.I1() > edge.I2()); if (edgedir) swap (edge.I1(), edge.I2()); @@ -134,7 +133,7 @@ namespace netgen for (SegmentIndex elnr : top.GetVertexSegments(v)) { const Segment & el = mesh[elnr]; - INDEX_2 edge(el[0], el[1]); + PointIndices<2> edge(el[0], el[1]); int edgedir = (edge.I1() > edge.I2()); if (edgedir) swap (edge.I1(), edge.I2()); @@ -160,10 +159,11 @@ namespace netgen if (elfaces[j][3] < 0) { // triangle - INDEX_4 face(el[elfaces[j][0]], el[elfaces[j][1]], - el[elfaces[j][2]], 0); - - int facedir = 0; + PointIndices<4> face(el[elfaces[j][0]], el[elfaces[j][1]], + el[elfaces[j][2]], PointIndex(PointIndex::INVALID)); + + + [[maybe_unused]] int facedir = 0; if (face.I1() > face.I2()) { swap (face.I1(), face.I2()); facedir += 1; } if (face.I2() > face.I3()) @@ -197,27 +197,27 @@ namespace netgen { // quad // int facenum; - INDEX_4 face4(el[elfaces[j][0]], el[elfaces[j][1]], - el[elfaces[j][2]], el[elfaces[j][3]]); + PointIndices<4> face4(el[elfaces[j][0]], el[elfaces[j][1]], + el[elfaces[j][2]], el[elfaces[j][3]]); - int facedir = 0; + // int facedir = 0; if (min2 (face4.I1(), face4.I2()) > min2 (face4.I4(), face4.I3())) { // z - flip - facedir += 1; + // facedir += 1; swap (face4.I1(), face4.I4()); swap (face4.I2(), face4.I3()); } if (min2 (face4.I1(), face4.I4()) > min2 (face4.I2(), face4.I3())) { // x - flip - facedir += 2; + // facedir += 2; swap (face4.I1(), face4.I2()); swap (face4.I3(), face4.I4()); } if (face4.I2() > face4.I4()) { // diagonal flip - facedir += 4; + // facedir += 4; swap (face4.I2(), face4.I4()); } @@ -262,27 +262,27 @@ namespace netgen { // triangle // int facenum; - int facedir; + // int facedir; - INDEX_4 face(el.PNum(elfaces[0][0]), - el.PNum(elfaces[0][1]), - el.PNum(elfaces[0][2]),0); + PointIndices<4> face(el.PNum(elfaces[0][0]), + el.PNum(elfaces[0][1]), + el.PNum(elfaces[0][2]), PointIndex(PointIndex::INVALID)); - facedir = 0; - if (face.I1() > face.I2()) + // facedir = 0; + if (face[0] > face[1]) { - swap (face.I1(), face.I2()); - facedir += 1; + swap (face[0], face[1]); + // facedir += 1; } - if (face.I2() > face.I3()) + if (face[1] > face[2]) { - swap (face.I2(), face.I3()); - facedir += 2; + swap (face[1], face[2]); + // facedir += 2; } - if (face.I1() > face.I2()) + if (face.I1() > face[1]) { - swap (face.I1(), face.I2()); - facedir += 4; + swap (face.I1(), face[1]); + // facedir += 4; } if (face.I1() != v) continue; @@ -311,31 +311,31 @@ namespace netgen { // quad // int facenum; - int facedir; + // int facedir; - INDEX_4 face4(el.PNum(elfaces[0][0]), - el.PNum(elfaces[0][1]), - el.PNum(elfaces[0][2]), - el.PNum(elfaces[0][3])); + PointIndices<4> face4(el.PNum(elfaces[0][0]), + el.PNum(elfaces[0][1]), + el.PNum(elfaces[0][2]), + el.PNum(elfaces[0][3])); - facedir = 0; + // facedir = 0; if (min2 (face4.I1(), face4.I2()) > min2 (face4.I4(), face4.I3())) { // z - orientation - facedir += 1; + // facedir += 1; swap (face4.I1(), face4.I4()); swap (face4.I2(), face4.I3()); } if (min2 (face4.I1(), face4.I4()) > min2 (face4.I2(), face4.I3())) { // x - orientation - facedir += 2; + // facedir += 2; swap (face4.I1(), face4.I2()); swap (face4.I3(), face4.I4()); } if (face4.I2() > face4.I4()) { - facedir += 4; + // facedir += 4; swap (face4.I2(), face4.I4()); } @@ -480,15 +480,15 @@ namespace netgen // for (int i = mesh->mlbetweennodes.Begin(); i < mesh->mlbetweennodes.End(); i++) for (int i : mesh->mlbetweennodes.Range()) { - INDEX_2 parents = Sort (mesh->mlbetweennodes[i]); - if (parents[0] >= PointIndex::BASE) cnt[parents[0]]++; + PointIndices<2> parents = Sort (mesh->mlbetweennodes[i]); + if (parents[0].IsValid()) cnt[parents[0]]++; } TABLE vert2vertcoarse (cnt); // for (int i = mesh->mlbetweennodes.Begin(); i < mesh->mlbetweennodes.End(); i++) for (int i : mesh->mlbetweennodes.Range()) { - INDEX_2 parents = Sort (mesh->mlbetweennodes[i]); - if (parents[0] >= PointIndex::BASE) vert2vertcoarse.AddSave (parents[0], parents[1]); + PointIndices<2> parents = Sort (mesh->mlbetweennodes[i]); + if (parents[0].IsValid()) vert2vertcoarse.AddSave (parents[0], parents[1]); } @@ -513,8 +513,8 @@ namespace netgen auto end = r.Next(); // INDEX_CLOSED_HASHTABLE v2eht(2*max_edge_on_vertex+10); ngcore::ClosedHashTable v2eht(2*max_edge_on_vertex+10); - for (PointIndex v = begin+PointIndex::BASE; - v < end+PointIndex::BASE; v++) + for (PointIndex v = begin+IndexBASE(); + v < end+IndexBASE(); v++) { v2eht.DeleteData(); for (int ednr : vert2edge[v]) @@ -553,7 +553,7 @@ namespace netgen // INDEX_CLOSED_HASHTABLE v2eht(2*max_edge_on_vertex+10); // NgArray vertex2; - // for (PointIndex v = PointIndex::BASE; v < nv+PointIndex::BASE; v++) + // for (PointIndex v = IndexBASE(); v < nv+IndexBASE(); v++) ParallelForRange (mesh->GetNV(), // Points().Size(), @@ -565,8 +565,8 @@ namespace netgen ngcore::ClosedHashTable v2eht(2*max_edge_on_vertex+10); Array vertex2; - for (PointIndex v = begin+PointIndex::BASE; - v < end+PointIndex::BASE; v++) + for (PointIndex v = begin+IndexBASE(); + v < end+IndexBASE(); v++) { int ned = cnt[v]; v2eht.DeleteData(); @@ -659,8 +659,8 @@ namespace netgen { auto verts = edge2vert[i]; // 2 vertices of edge - if (verts[0] >= mesh->mlbetweennodes.Size()+PointIndex::BASE || - verts[1] >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + if (verts[0] >= mesh->mlbetweennodes.Size()+IndexBASE() || + verts[1] >= mesh->mlbetweennodes.Size()+IndexBASE()) continue; auto pa0 = mesh->mlbetweennodes[verts[0]]; // two parent vertices of v0 @@ -698,20 +698,20 @@ namespace netgen // edge is splitting edge in middle of triangle: for (int j = 1; j <= 2; j++) { - INT<2> paedge1, paedge2, paedge3; + IVec<2,PointIndex> paedge1, paedge2, paedge3; int orient_inner = 0; if (j == 1) { - paedge1 = INT<2> (pa0[0], verts[1]); - paedge2 = INT<2> (pa0[1], verts[1]); - paedge3 = INT<2> (pa0[0], pa0[1]); + paedge1 = IVec<2> (pa0[0], verts[1]); + paedge2 = IVec<2> (pa0[1], verts[1]); + paedge3 = IVec<2> (pa0[0], pa0[1]); orient_inner = 0; } else { - paedge1 = INT<2> (pa1[0], verts[0]); - paedge2 = INT<2> (pa1[1], verts[0]); - paedge3 = INT<2> (pa1[0], pa1[1]); + paedge1 = IVec<2> (pa1[0], verts[0]); + paedge2 = IVec<2> (pa1[1], verts[0]); + paedge3 = IVec<2> (pa1[0], pa1[1]); orient_inner = 1; } if (paedge1[0] > paedge1[1]) @@ -722,7 +722,7 @@ namespace netgen Swap (paedge3[0], paedge3[1]); // if first vertex number is -1, then don't try to find entry in node2edge hash table - if ( paedge1[0] == PointIndex::BASE-1 || paedge2[0] == PointIndex::BASE-1 ) + if ( !paedge1[0].IsValid() || !paedge2[0].IsValid() ) continue; int paedgenr1=-1, paedgenr2=-1, paedgenr3=-1, orient1 = 0, orient2 = 0; @@ -751,21 +751,21 @@ namespace netgen if (!bisect_edge) // not a bisect edge (then a red edge) { - INT<2> paedge1, paedge2, paedge3; + IVec<2,PointIndex> paedge1, paedge2, paedge3; int orient1 = 0, orient2 = 0, orient3=0; - int orient_inner = 0; - paedge1 = INT<2> (pa0[0], pa0[1]); - paedge2 = INT<2> (pa1[0], pa1[1]); + // int orient_inner = 0; + paedge1 = IVec<2,PointIndex> (pa0[0], pa0[1]); + paedge2 = IVec<2,PointIndex> (pa1[0], pa1[1]); // find common vertex and the third pa edge if (pa0[0]==pa1[0]){// 00 //orient1 = 0; orient2 = 1; if (pa0[1] (pa0[1], pa1[1]); + paedge3 = IVec<2,PointIndex> (pa0[1], pa1[1]); }else{ //orient3 = 0; - paedge3 = INT<2> (pa1[1], pa0[1]); + paedge3 = IVec<2,PointIndex> (pa1[1], pa0[1]); } } else if (pa0[0]==pa1[1]){//01 @@ -773,10 +773,10 @@ namespace netgen //orient2 = 0; if (pa0[1] (pa0[1], pa1[0]); + paedge3 = IVec<2,PointIndex> (pa0[1], pa1[0]); }else{ //orient3 = 0; - paedge3 = INT<2> (pa1[0], pa0[1]); + paedge3 = IVec<2,PointIndex> (pa1[0], pa0[1]); } } else if (pa0[1]==pa1[0]){//10 @@ -784,10 +784,10 @@ namespace netgen orient2 = 1; if (pa0[0] (pa0[0], pa1[1]); + paedge3 = IVec<2,PointIndex> (pa0[0], pa1[1]); }else{ //orient3 = 0; - paedge3 = INT<2> (pa1[1], pa0[0]); + paedge3 = IVec<2,PointIndex> (pa1[1], pa0[0]); } } else if (pa0[1]==pa1[1]){//11 @@ -795,10 +795,10 @@ namespace netgen //orient2 = 0; if (pa0[0] (pa0[0], pa1[0]); + paedge3 = IVec<2,PointIndex> (pa0[0], pa1[0]); }else{ //orient3 = 0; - paedge3 = INT<2> (pa1[0], pa0[0]); + paedge3 = IVec<2,PointIndex> (pa1[0], pa0[0]); } } @@ -831,16 +831,16 @@ namespace netgen pa1[1] != pa2[1]) for (int j = 1; j <= 2; j++) { - INT<2> paedge1, paedge2; + IVec<2> paedge1, paedge2; if (j == 1) { - paedge1 = INT<2> (pa1[0], pa2[0]); - paedge2 = INT<2> (pa1[1], pa2[1]); + paedge1 = IVec<2> (pa1[0], pa2[0]); + paedge2 = IVec<2> (pa1[1], pa2[1]); } else { - paedge1 = INT<2> (pa1[0], pa2[1]); - paedge2 = INT<2> (pa1[1], pa2[0]); + paedge1 = IVec<2> (pa1[0], pa2[1]); + paedge2 = IVec<2> (pa1[1], pa2[0]); } int paedgenr1 = 0, paedgenr2 = 0; @@ -876,7 +876,7 @@ namespace netgen for (int j = 0; j < 2; j++) for (int k = 0; k < 2; k++) { - INT<2> paedge (pa1[1-j], pa2[1-k]); + IVec<2> paedge (pa1[1-j], pa2[1-k]); int orientpa = 1; if (paedge[0] > paedge[1]) { @@ -908,12 +908,12 @@ namespace netgen // edge hashtable:: needed for getting parent faces - ngcore::ClosedHashTable, int> v2e(nv); + ngcore::ClosedHashTable, int> v2e(nv); if (build_parent_faces) for (auto i : Range(edge2vert)) { auto edge = edge2vert[i]; - INT<2> e2(edge[0], edge[1]); + IVec<2> e2(edge[0], edge[1]); e2.Sort(); v2e[e2] = i; } @@ -946,7 +946,7 @@ namespace netgen vert2oldface.AddSave (face2vert[i][0], i); // find all potential intermediate faces - Array> intermediate_faces; + Array> intermediate_faces; if (build_parent_faces) { for (ElementIndex ei = 0; ei < ne; ei++) @@ -956,11 +956,11 @@ namespace netgen // cout << "element: " << (*mesh)[ei].PNums() << endl; (*mesh)[ei].GetFace(i+1, face); // cout << "face " << face.PNums() << endl; - INT<3,PointIndex> f3 = { face[0], face[1], face[2] }; + IVec<3,PointIndex> f3 = { face[0], face[1], face[2] }; for (int j = 0; j < 3; j++) { PointIndex v = f3[j]; - if (v >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + if (v >= mesh->mlbetweennodes.Size()+IndexBASE()) continue; auto pa = mesh->mlbetweennodes[v]; @@ -969,13 +969,13 @@ namespace netgen { PointIndex v0 = pa[k]; // also in face PointIndex v1 = pa[1-k]; - PointIndex v2 = f3[0]+f3[1]+f3[2] - v - v0; + PointIndex v2 = f3[0]-v+f3[1]-v0+f3[2]; // if there is an edge connecting v1 and v2, accept // the new face - INT<2> parentedge(v1, v2); + IVec<2> parentedge(v1, v2); parentedge.Sort(); if (v2e.Used(parentedge)){ - INT<3> cf3 = { v0, v1, v2 }; + IVec<3> cf3 = { v0, v1, v2 }; cf3.Sort(); // cout << "intermediate: " << cf3 << " of " << f3 << endl; intermediate_faces.Append (cf3); @@ -983,6 +983,38 @@ namespace netgen } } } + + for (SurfaceElementIndex sei = 0; sei < nse; sei++) + { + const Element2d & sel = (*mesh)[sei]; + IVec<3,PointIndex> f3 = { sel[0], sel[1], sel[2] }; + for (int j = 0; j < 3; j++) + { + PointIndex v = f3[j]; + if (v >= mesh->mlbetweennodes.Size()+IndexBASE()) + continue; + + auto pa = mesh->mlbetweennodes[v]; + for (int k = 0; k < 2; k++) + if (f3.Contains(pa[k])) + { + PointIndex v0 = pa[k]; // also in face + PointIndex v1 = pa[1-k]; + PointIndex v2 = f3[0]-v+f3[1]-v0+f3[2]; + // if there is an edge connecting v1 and v2, accept + // the new face + IVec<2> parentedge(v1, v2); + parentedge.Sort(); + if (v2e.Used(parentedge)){ + IVec<3> cf3 = { v0, v1, v2 }; + cf3.Sort(); + // cout << "intermediate: " << cf3 << " of " << f3 << endl; + intermediate_faces.Append (cf3); + } + } + } + } + } cnt = 0; for (int i = 0; i < intermediate_faces.Size(); i++) @@ -999,7 +1031,7 @@ namespace netgen int max_face_on_vertex = 0; - for (int i = PointIndex::BASE; i < nv+PointIndex::BASE; i++) + for (PointIndex i = IndexBASE(); i < nv+IndexBASE(); i++) { int onv = vert2oldface[i].Size() + vert2element[i].Size() + vert2surfelement[i].Size(); max_face_on_vertex = max (onv, max_face_on_vertex); @@ -1026,7 +1058,7 @@ namespace netgen // auto begin = r.First(); // auto end = r.Next(); // INDEX_3_CLOSED_HASHTABLE vert2face(2*max_face_on_vertex+10); - ClosedHashTable vert2face(2*max_face_on_vertex+10); + NgClosedHashTable vert2face(2*max_face_on_vertex+10); // for (PointIndex v = begin+PointIndex::BASE; // v < end+PointIndex::BASE; v++) for (PointIndex v : r+PointIndex::BASE) @@ -1091,7 +1123,7 @@ namespace netgen // auto begin = r.First(); // auto end = r.Next(); // INDEX_3_CLOSED_HASHTABLE vert2face(2*max_face_on_vertex+10); - ClosedHashTable vert2face(2*max_face_on_vertex+10); + NgClosedHashTable vert2face(2*max_face_on_vertex+10); /* for (PointIndex v = begin+PointIndex::BASE; v < end+PointIndex::BASE; v++) @@ -1129,7 +1161,7 @@ namespace netgen size_t pos; if (vert2face.PositionCreate(face, pos)) { - face2vert[nfa] = { face[0], face[1], face[2], 0 }; // i4; + face2vert[nfa] = { face[0], face[1], face[2], PointIndex::BASE-1 }; // i4; vert2face.SetData (pos, face, nfa); nfa++; } @@ -1195,9 +1227,9 @@ namespace netgen face2surfel.SetSize (nfa); - face2surfel = 0; - for (int i = 1; i <= nse; i++) - face2surfel.Elem(GetSurfaceElementFace(i)) = i; + face2surfel = SurfaceElementIndex::INVALID; + for (SurfaceElementIndex sei = 0; sei < nse; sei++) + face2surfel[GetFace(sei)] = sei; /* cout << "build table complete" << endl; @@ -1211,11 +1243,9 @@ namespace netgen surf2volelement.SetSize (nse); - for (int i = 1; i <= nse; i++) - { - surf2volelement.Elem(i)[0] = 0; - surf2volelement.Elem(i)[1] = 0; - } + // surf2volelement = INDEX_2(0,0); + surf2volelement = { ElementIndex::INVALID, ElementIndex::INVALID }; + (*tracer) ("Topology::Update build surf2vol", false); // for (int i = 0; i < ne; i++) ParallelFor (ne, [this](auto i) @@ -1223,13 +1253,12 @@ namespace netgen for (int j = 0; j < 6; j++) { // int fnum = (faces.Get(i)[j]+7) / 8; - int fnum = faces[i][j]+1; - if (fnum > 0 && face2surfel.Elem(fnum)) + int fnum = faces[i][j]; + if (fnum >= 0 && face2surfel[fnum].IsValid()) { - int sel = face2surfel.Elem(fnum); - surf2volelement.Elem(sel)[1] = - surf2volelement.Elem(sel)[0]; - surf2volelement.Elem(sel)[0] = i+1; + SurfaceElementIndex sel = face2surfel[fnum]; + surf2volelement[sel][1] = surf2volelement[sel][0]; + surf2volelement[sel][0] = i; // +1; } }}); (*tracer) ("Topology::Update build surf2vol", true); @@ -1267,8 +1296,12 @@ namespace netgen AsAtomic(face_els[f])++; }, TasksPerThread(4)); + /* for (int i = 1; i <= nse; i++) - face_surfels[GetSurfaceElementFace (i)-1]++; + face_surfels[GetSurfaceElementFace1 (i)-1]++; + */ + for (auto sei : Range(mesh->SurfaceElements())) + face_surfels[GetFace(sei)]++; (*tracer) ("Topology::Update count face_els", true); @@ -1294,7 +1327,7 @@ namespace netgen else #endif { - (*testout) << "illegal face : " << i << endl; + (*testout) << "illegal face : " << i << ", cnt = " << face_els[i]+face_surfels[i] << endl; (*testout) << "points = " << face2vert[i][0] << "," << face2vert[i][1] << "," @@ -1303,7 +1336,7 @@ namespace netgen << endl; (*testout) << "pos = "; for (int j = 0; j < 4; j++) - if (face2vert[i][j] >= 1) + if (face2vert[i][j].IsValid()) (*testout) << (*mesh)[(PointIndex)face2vert[i][j]] << " "; (*testout) << endl; @@ -1315,7 +1348,7 @@ namespace netgen for (int l = 0; l < nf; l++) if (elfaces[l] == i) { - // (*testout) << "is face of element " << vertels[k] << endl; + (*testout) << "is face of element " << vertels[k] << endl; if (mesh->coarsemesh && mesh->hpelements->Size() == mesh->GetNE() ) { @@ -1344,23 +1377,23 @@ namespace netgen // cout << "f2v = " << face2vert << endl; - ngcore::ClosedHashTable, int> v2f(nv); + ngcore::ClosedHashTable, int> v2f(nv); for (auto i : Range(face2vert)) { auto face = face2vert[i]; - INT<3> f3(face[0], face[1], face[2]); + IVec<3> f3(face[0], face[1], face[2]); f3.Sort(); v2f[f3] = i; } // cout << "v2f:" << endl << v2f << endl; - + parent_faces.SetSize (nfa); parent_faces = { -1, { -1, -1, -1, -1 } }; for (auto i : Range(nfa)) { - INT<3,PointIndex> f3(face2vert[i][0], face2vert[i][1], face2vert[i][2]); + IVec<3,PointIndex> f3(face2vert[i][0], face2vert[i][1], face2vert[i][2]); // face on coarses level ? @@ -1368,10 +1401,10 @@ namespace netgen for (int k = 0; k < 3; k++) { PointIndex vb = f3[k]; - if (vb >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + if (vb >= mesh->mlbetweennodes.Size()+IndexBASE()) continue; auto parents = mesh->mlbetweennodes[vb]; - if (parents[0] >= PointIndex::BASE) + if (parents[0] >= IndexBASE()) all_vert_coarse = false; } if (all_vert_coarse) continue; @@ -1383,7 +1416,7 @@ namespace netgen for (int k = 0; k < 3; k++) { PointIndex vb = f3[k]; // assume vb as the new bisect vert - if (vb >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + if (vb >= mesh->mlbetweennodes.Size()+IndexBASE()) continue; auto parents = mesh->mlbetweennodes[vb]; @@ -1396,14 +1429,14 @@ namespace netgen PointIndex v1 = parents[1-j]; // the third one, on the tip - PointIndex v2 = f3[0]+f3[1]+f3[2] - v0 - vb; + PointIndex v2 = f3[0]-v0+f3[1]-vb+f3[2]; // if there is an edge connecting v1 and v2, accept // the new face - INT<2> parentedge(v1, v2); + IVec<2> parentedge(v1, v2); parentedge.Sort(); if (v2e.Used(parentedge)){ - INT<3> parentverts(v0, v1, v2); + IVec<3> parentverts(v0, v1, v2); parentverts.Sort(); int classnr = 0; @@ -1443,13 +1476,13 @@ namespace netgen PointIndex v1 = parents[1]; PointIndex v2 = f3[(k+1)%3]; PointIndex v3 = f3[(k+2)%3]; - INT<3> parentedge1(v0, v2); + IVec<3> parentedge1(v0, v2); parentedge1.Sort(); - INT<3> parentedge2(v0, v3); + IVec<3> parentedge2(v0, v3); parentedge2.Sort(); - INT<3> parentedge3(v1, v2); + IVec<3> parentedge3(v1, v2); parentedge3.Sort(); - INT<3> parentedge4(v1, v3); + IVec<3> parentedge4(v1, v3); parentedge4.Sort(); // if edges [v0,v2], [v0, v3], [v1,v2], [v1,v3] exists // then vb is the bisecting edge @@ -1474,13 +1507,13 @@ namespace netgen // by default v0 < v1 < vb < v2 < v3 classnr=9; } - INT<3> parentverts1(v0, v2, v3); + IVec<3> parentverts1(v0, v2, v3); parentverts1.Sort(); - INT<3> parentverts2(v1, v2, v3); + IVec<3> parentverts2(v1, v2, v3); parentverts2.Sort(); - INT<3> parentverts3(v0, v1, v2); + IVec<3> parentverts3(v0, v1, v2); parentverts3.Sort(); - INT<3> parentverts4(v0, v1, v3); + IVec<3> parentverts4(v0, v1, v3); parentverts4.Sort(); int pafacenr1=-1, pafacenr2=-1, pafacenr3=-1, pafacenr4=-1; if (v2f.Used(parentverts1)) @@ -1520,7 +1553,7 @@ namespace netgen for (int k = 0; k < 3; k++) { PointIndex vb = f3[k]; // assume vb as the new bisect vert - if (vb >= mesh->mlbetweennodes.Size()+PointIndex::BASE) + if (vb >= mesh->mlbetweennodes.Size()+IndexBASE()) continue; auto parents = mesh->mlbetweennodes[vb]; @@ -1528,13 +1561,13 @@ namespace netgen PointIndex v1 = parents[1]; PointIndex v2 = f3[(k+1)%3]; PointIndex v3 = f3[(k+2)%3]; - INT<2> parentedge1(v0, v2); + IVec<2> parentedge1(v0, v2); parentedge1.Sort(); - INT<2> parentedge2(v0, v3); + IVec<2> parentedge2(v0, v3); parentedge2.Sort(); - INT<2> parentedge3(v1, v2); + IVec<2> parentedge3(v1, v2); parentedge3.Sort(); - INT<2> parentedge4(v1, v3); + IVec<2> parentedge4(v1, v3); parentedge4.Sort(); // if edges [v0,v2], [v0, v3], [v1,v2], [v1,v3] exists @@ -1562,13 +1595,13 @@ namespace netgen } // cout << "classnr = " << classnr << endl; - INT<3> parentverts1(v1, v2, v3); + IVec<3> parentverts1(v1, v2, v3); parentverts1.Sort(); - INT<3> parentverts2(v0, v2, v3); + IVec<3> parentverts2(v0, v2, v3); parentverts2.Sort(); - INT<3> parentverts3(v0, v1, v3); + IVec<3> parentverts3(v0, v1, v3); parentverts3.Sort(); - INT<3> parentverts4(v0, v1, v2); + IVec<3> parentverts4(v0, v1, v2); parentverts4.Sort(); if (!v2f.Used(parentverts1) || !v2f.Used(parentverts2) || @@ -1601,17 +1634,17 @@ namespace netgen // v0 is a coarse vertex ==> f3 is a boundary face if (v0==pa1[0] || v0==pa1[1]){ if (pa1[0]==v0){// type 0: bottom left corner - INT<3> parentverts(v0, pa1[1], pa2[1]); + IVec<3> parentverts(v0, pa1[1], pa2[1]); int pafacenr = v2f[parentverts]; parent_faces[i] = { 16, { pafacenr, -1, -1, -1} }; //cout << "f "< parentverts(pa1[0], v0, pa2[1]); + IVec<3> parentverts(pa1[0], v0, pa2[1]); int pafacenr = v2f[parentverts]; parent_faces[i] = { 17, { pafacenr, -1, -1, -1} }; //cout << "f "< parentverts(pa1[0], pa2[0], v0); + IVec<3> parentverts(pa1[0], pa2[0], v0); int pafacenr = v2f[parentverts]; parent_faces[i] = { 18, { pafacenr, -1, -1, -1} }; //cout << "f "< parentverts(pa0[0], pa0[1], pa1[1]); + IVec<3> parentverts(pa0[0], pa0[1], pa1[1]); int pafacenr = v2f[parentverts]; parent_faces[i] = { 19, { pafacenr, -1, -1, -1} }; //cout << "f "< & eledges) const { int ned = GetNEdges (mesh->VolumeElement(elnr).GetType()); + ElementIndex ei = IndexBASE() +(elnr-1); eledges.SetSize (ned); for (int i = 0; i < ned; i++) - eledges[i] = edges.Get(elnr)[i]+1; - // eledges[i] = abs (edges.Get(elnr)[i]); + // eledges[i] = edges.Get(elnr)[i]+1; + eledges[i] = edges[ei][i]+1; } - void MeshTopology :: GetElementFaces (int elnr, NgArray & elfaces, bool withorientation) const + + void MeshTopology :: GetElementFaces (int elnr, NgArray & elfaces) const { int nfa = GetNFaces (mesh->VolumeElement(elnr).GetType()); + ElementIndex ei = IndexBASE() +(elnr-1); + elfaces.SetSize (nfa); for (auto i : Range(nfa)) - elfaces[i] = faces.Get(elnr)[i]+1; + // elfaces[i] = faces.Get(elnr)[i]+1; + elfaces[i] = faces[ei][i]+1; + } + + + void MeshTopology :: GetElementFaces (int elnr, NgArray & elfaces, bool withorientation) const + { + ElementIndex ei = IndexBASE() +(elnr-1); + int nfa = GetNFaces (mesh->VolumeElement(ei).GetType()); + + elfaces.SetSize (nfa); + + for (auto i : Range(nfa)) + // elfaces[i] = faces.Get(elnr)[i]+1; + elfaces[i] = faces[ei][i]+1; if(withorientation) { for(auto & face : elfaces) { auto v = face2vert[face-1]; - if(v[3]!=0) + if(v[3].IsValid()) cerr << "GetElementFaces with orientation currently not supported for quads" << endl; int classnr = 0; @@ -1809,7 +1860,8 @@ namespace netgen void MeshTopology :: GetElementEdgeOrientations (int elnr, NgArray & eorient) const { - int ned = GetNEdges (mesh->VolumeElement(elnr).GetType()); + ElementIndex ei = IndexBASE() +(elnr-1); + int ned = GetNEdges (mesh->VolumeElement(ei).GetType()); eorient.SetSize (ned); for (int i = 1; i <= ned; i++) // eorient.Elem(i) = (edges.Get(elnr)[i-1] > 0) ? 1 : -1; @@ -1819,7 +1871,8 @@ namespace netgen void MeshTopology :: GetElementFaceOrientations (int elnr, NgArray & forient) const { - int nfa = GetNFaces (mesh->VolumeElement(elnr).GetType()); + ElementIndex ei = IndexBASE() +(elnr-1); + int nfa = GetNFaces (mesh->VolumeElement(ei).GetType()); forient.SetSize (nfa); for (int i = 1; i <= nfa; i++) // forient.Elem(i) = faces.Get(elnr)[i-1].forient; @@ -1832,7 +1885,7 @@ namespace netgen int MeshTopology :: GetElementEdges (int elnr, int * eledges, int * orient) const { // int ned = GetNEdges (mesh.VolumeElement(elnr).GetType()); - + ElementIndex ei = IndexBASE() +(elnr-1); if (mesh->GetDimension()==3 || 1) { if (orient) @@ -1844,8 +1897,12 @@ namespace netgen eledges[i] = abs (edges.Get(elnr)[i]); orient[i] = (edges.Get(elnr)[i] > 0 ) ? 1 : -1; */ - if (edges.Get(elnr)[i] == -1) return i; - eledges[i] = edges.Get(elnr)[i]+1; + + // if (edges.Get(elnr)[i] == -1) return i; + // eledges[i] = edges[ei].Get(elnr)[i]+1; + if (edges[ei][i] == -1) return i; + eledges[i] = edges[ei][i]+1; + // orient[i] = edges.Get(elnr)[i].orient ? -1 : 1; orient[i] = GetElementEdgeOrientation(elnr, i) ? -1 : 1; } @@ -1856,8 +1913,11 @@ namespace netgen { // if (!edges.Get(elnr)[i]) return i; // eledges[i] = abs (edges.Get(elnr)[i]); - if (edges.Get(elnr)[i] == -1) return i; - eledges[i] = edges.Get(elnr)[i]+1; + + // if (edges.Get(elnr)[i] == -1) return i; + //eledges[i] = edges.Get(elnr)[i]+1; + if (edges[ei][i] == -1) return i; + eledges[i] = edges[ei][i]+1; } } @@ -1890,6 +1950,8 @@ namespace netgen int MeshTopology :: GetElementFaces (int elnr, int * elfaces, int * orient) const { + ElementIndex ei = IndexBASE() +(elnr-1); + // int nfa = GetNFaces (mesh.VolumeElement(elnr).GetType()); if (orient) { @@ -1900,8 +1962,10 @@ namespace netgen elfaces[i] = (faces.Get(elnr)[i]-1) / 8 + 1; orient[i] = (faces.Get(elnr)[i]-1) % 8; */ - if (faces.Get(elnr)[i] == -1) return i; - elfaces[i] = faces.Get(elnr)[i]+1; + // if (faces.Get(elnr)[i] == -1) return i; + // elfaces[i] = faces.Get(elnr)[i]+1; + if (faces[ei][i] == -1) return i; + elfaces[i] = faces[ei][i]+1; // orient[i] = faces.Get(elnr)[i].forient; orient[i] = GetElementFaceOrientation (elnr, i); } @@ -1912,8 +1976,11 @@ namespace netgen { // if (!faces.Get(elnr)[i]) return i; // elfaces[i] = (faces.Get(elnr)[i]-1) / 8 + 1; - if (faces.Get(elnr)[i] == -1) return i; - elfaces[i] = faces.Get(elnr)[i]+1; + + // if (faces.Get(elnr)[i] == -1) return i; + // elfaces[i] = faces.Get(elnr)[i]+1; + if (faces[ei][i] == -1) return i; + elfaces[i] = faces[ei][i]+1; } } return 6; @@ -1923,9 +1990,11 @@ namespace netgen void MeshTopology :: GetSurfaceElementEdges (int elnr, NgArray & eledges) const { int ned = GetNEdges (mesh->SurfaceElement(elnr).GetType()); + SurfaceElementIndex sei = IndexBASE() +(elnr-1); eledges.SetSize (ned); for (int i = 0; i < ned; i++) - eledges[i] = surfedges.Get(elnr)[i]+1; + // eledges[i] = surfedges.Get(elnr)[i]+1; + eledges[i] = surfedges[sei][i]+1; } void MeshTopology :: GetEdges (SurfaceElementIndex elnr, NgArray & eledges) const @@ -1954,12 +2023,12 @@ namespace netgen */ + /* int MeshTopology :: GetSurfaceElementFace (int elnr) const { - return surffaces.Get(elnr)+1; + return surffaces[elnr-1]+1; } - /* int MeshTopology :: GetFace (SurfaceElementIndex elnr) const { return surffaces[elnr].fnr; @@ -1987,6 +2056,7 @@ namespace netgen int MeshTopology :: GetSurfaceElementEdges (int elnr, int * eledges, int * orient) const { + SurfaceElementIndex sei = IndexBASE() +(elnr-1); int i; if (mesh->GetDimension() == 3 || 1) { @@ -1999,8 +2069,10 @@ namespace netgen eledges[i] = abs (surfedges.Get(elnr)[i]); orient[i] = (surfedges.Get(elnr)[i] > 0 ) ? 1 : -1; */ - if (surfedges.Get(elnr)[i] == -1) return i; - eledges[i] = surfedges.Get(elnr)[i]+1; + // if (surfedges.Get(elnr)[i] == -1) return i; + // eledges[i] = surfedges.Get(elnr)[i]+1; + if (surfedges[sei][i] == -1) return i; + eledges[i] = surfedges[sei][i]+1; // orient[i] = (surfedges.Get(elnr)[i].orient) ? -1 : 1; // orient[i] = GetSurfaceElementEdgeOrientation(elnr, i) ? -1 : 1; orient[i] = 1; @@ -2015,8 +2087,10 @@ namespace netgen if (!surfedges.Get(elnr)[i]) return i; eledges[i] = abs (surfedges.Get(elnr)[i]); */ - if (surfedges.Get(elnr)[i] == -1) return i; - eledges[i] = surfedges.Get(elnr)[i]+1; + // if (surfedges.Get(elnr)[i] == -1) return i; + // eledges[i] = surfedges.Get(elnr)[i]+1; + if (surfedges[sei][i] == -1) return i; + eledges[i] = surfedges[sei][i]+1; } } return 4; @@ -2028,7 +2102,7 @@ namespace netgen if (orient) orient[0] = segedges.Get(elnr) > 0 ? 1 : -1; */ - eledges[0] = segedges.Get(elnr)+1; + eledges[0] = segedges[elnr-1]+1; if (orient) // orient[0] = segedges.Get(elnr).orient ? -1 : 1; // orient[0] = GetSegmentEdgeOrientation(elnr) ? -1 : 1; @@ -2040,7 +2114,9 @@ namespace netgen int MeshTopology :: GetElementEdgeOrientation (int elnr, int locedgenr) const { - const Element & el = mesh->VolumeElement (elnr); + ElementIndex ei = IndexBASE() +(elnr-1); + + const Element & el = mesh->VolumeElement (ei); const ELEMENT_EDGE * eledges = MeshTopology::GetEdges0 (el.GetType()); int k = locedgenr; @@ -2052,7 +2128,8 @@ namespace netgen int MeshTopology :: GetElementFaceOrientation (int elnr, int locfacenr) const { - const Element & el = mesh->VolumeElement (elnr); + ElementIndex ei = IndexBASE() +(elnr-1); + const Element & el = mesh->VolumeElement (ei); const ELEMENT_FACE * elfaces = MeshTopology::GetFaces0 (el.GetType()); @@ -2060,7 +2137,7 @@ namespace netgen if (elfaces[j][3] < 0) { // triangle INDEX_4 face(el[elfaces[j][0]], el[elfaces[j][1]], - el[elfaces[j][2]], 0); + el[elfaces[j][2]], PointIndex::BASE-1 ); int facedir = 0; if (face.I1() > face.I2()) @@ -2127,7 +2204,7 @@ namespace netgen if (elfaces[j][3] < 0) { // triangle INDEX_4 face(el[elfaces[j][0]], el[elfaces[j][1]], - el[elfaces[j][2]], 0); + el[elfaces[j][2]], PointIndex(PointIndex::INVALID)); int facedir = 0; if (face.I1() > face.I2()) @@ -2173,7 +2250,7 @@ namespace netgen void MeshTopology :: GetSegmentEdge (int segnr, int & enr, int & orient) const { - enr = segedges.Get(segnr)+1; + enr = segedges[segnr-1]+1; orient = GetSegmentEdgeOrientation(segnr); } @@ -2196,7 +2273,7 @@ namespace netgen vertices.SetSize(4); for (int i = 0; i < 4; i++) vertices[i] = face2vert[fnr-1][i]; - if (vertices[3] == 0) + if (vertices[3]+1==PointIndex::BASE) vertices.SetSize(3); } @@ -2227,12 +2304,13 @@ namespace netgen void MeshTopology :: GetFaceEdges (int fnr, NgArray & fedges, bool withorientation) const { - NgArrayMem pi(4); - NgArrayMem eledges; + // NgArrayMem pi(4); + // NgArrayMem eledges; fedges.SetSize (0); - GetFaceVertices(fnr, pi); - + // GetFaceVertices(fnr, pi); + auto pi = GetFaceVertices(fnr-1); + // Sort Edges according to global vertex numbers // e1 = fmax, f2 // e2 = fmax, f1 @@ -2279,12 +2357,14 @@ namespace netgen { const ELEMENT_EDGE * fa_ref_edges = GetEdges1 (GetFaceType(fnr)); fedges.SetSize(nfa_ref_edges); - GetElementEdges (els[i]+1, eledges); + // GetElementEdges (els[i]+1, eledges); + auto eledges = GetEdges (els[i]); for (int j = 0; j < eledges.Size(); j++) { - int vi1, vi2; - GetEdgeVertices (eledges[j], vi1, vi2); + // int vi1, vi2; + // GetEdgeVertices (eledges[j]+1, vi1, vi2); + auto [vi1, vi2] = GetEdgeVertices(eledges[j]); bool has1 = 0; bool has2 = 0; @@ -2300,19 +2380,19 @@ namespace netgen // fedges.Append (eledges[j]); for(int k=0;k elementedges; - // Array elements_v1; - // GetVertexElements ( v1, elements_v1); - auto elements_v1 = GetVertexElements ( v1 ); - int edv1, edv2; - - for ( int i = 0; i < elements_v1.Size(); i++ ) - { - // GetElementEdges( elements_v1[i]+1, elementedges ); - auto elementedges = GetEdges(ElementIndex(elements_v1[i])); - for ( int ed = 0; ed < elementedges.Size(); ed ++) - { - GetEdgeVertices( elementedges[ed]+1, edv1, edv2 ); - if ( ( edv1 == v1 && edv2 == v2 ) || ( edv1 == v2 && edv2 == v1 ) ) - return elementedges[ed]; - } + /* + if (vert2element.Size() > 0) + { + auto elements_v1 = GetVertexElements ( v1 ); + // int edv1, edv2; + + for ( int i = 0; i < elements_v1.Size(); i++ ) + { + // GetElementEdges( elements_v1[i]+1, elementedges ); + auto elementedges = GetEdges(ElementIndex(elements_v1[i])); + for ( int ed = 0; ed < elementedges.Size(); ed ++) + { + // GetEdgeVertices( elementedges[ed]+1, edv1, edv2 ); + auto [edv1,edv2] = GetEdgeVertices (elementedges[ed]); + if ( ( edv1 == v1 && edv2 == v2 ) || ( edv1 == v2 && edv2 == v1 ) ) + return elementedges[ed]; + } + } } + */ + + if (vert2element.Size() > 0) + for (auto ei : GetVertexElements ( v1 )) + for (auto ed : GetEdges(ei)) + { + auto [edv1,edv2] = GetEdgeVertices (ed); + if ( ( edv1 == v1 && edv2 == v2 ) || ( edv1 == v2 && edv2 == v1 ) ) + return ed; + } + + + if (vert2surfelement.Size() > 0) + for (auto sei : GetVertexSurfaceElements ( v1 )) + for (auto ed : GetEdges(sei)) + { + auto [edv1,edv2] = GetEdgeVertices (ed); + if ( ( edv1 == v1 && edv2 == v2 ) || ( edv1 == v2 && edv2 == v1 ) ) + return ed; + } return -1; } @@ -2393,9 +2499,10 @@ namespace netgen void MeshTopology :: GetSegmentSurfaceElements (int segnr, NgArray & els) const { - int v1, v2; + // int v1, v2; // GetEdgeVertices ( GetSegmentEdge (segnr), v1, v2 ); - GetEdgeVertices ( GetEdge (segnr-1)+1, v1, v2 ); + // GetEdgeVertices ( GetEdge (segnr-1)+1, v1, v2 ); + auto [v1,v2] = GetEdgeVertices ( GetEdge (segnr-1) ); auto els1 = GetVertexSurfaceElements ( v1 ); auto els2 = GetVertexSurfaceElements ( v2 ); els.SetSize(0); diff --git a/libsrc/meshing/topology.hpp b/libsrc/meshing/topology.hpp index c3cc3ed2..6af79c3b 100644 --- a/libsrc/meshing/topology.hpp +++ b/libsrc/meshing/topology.hpp @@ -12,13 +12,28 @@ (Elements, Faces, Edges, Vertices */ +#include "meshtype.hpp" + namespace netgen { + // typedef int T_EDGE; + // typedef int T_FACE; + + class EdgeIndex : public Index + { + public: + using Index::Index; + }; + + class FaceIndex : public Index + { + public: + using Index::Index; + }; + + typedef EdgeIndex T_EDGE; + typedef FaceIndex T_FACE; - typedef int T_EDGE; - typedef int T_FACE; - - class MeshTopology { const Mesh * mesh; @@ -32,14 +47,16 @@ class MeshTopology Array> edge2vert; Array> face2vert; - NgArray> edges; - NgArray> faces; - NgArray> surfedges; + Array, ElementIndex> edges; + Array, ElementIndex> faces; + Array, SurfaceElementIndex> surfedges; + + Array segedges; + Array surffaces; + // Array surf2volelement; + Array, SurfaceElementIndex> surf2volelement; + Array face2surfel; - NgArray segedges; - NgArray surffaces; - NgArray surf2volelement; - NgArray face2surfel; Array edge2segment; Table vert2element; Table vert2surfelement; @@ -47,12 +64,10 @@ class MeshTopology Table vert2pointelement; int timestamp; public: - int GetNSurfedges() const {return surfedges.Size();} - MeshTopology () = default; MeshTopology (MeshTopology && top) = default; - MeshTopology (const Mesh & amesh); - ~MeshTopology (); + DLL_HEADER MeshTopology (const Mesh & amesh); + DLL_HEADER ~MeshTopology (); MeshTopology & operator= (MeshTopology && top) = default; void SetBuildVertex2Element (bool bv2e) { buildvertex2element = bv2e; } @@ -72,8 +87,8 @@ public: bool NeedsUpdate() const; - int GetNEdges () const { return edge2vert.Size(); } - int GetNFaces () const { return face2vert.Size(); } + size_t GetNEdges () const { return edge2vert.Size(); } + size_t GetNFaces () const { return face2vert.Size(); } static inline short int GetNVertices (ELEMENT_TYPE et); static inline short int GetNPoints (ELEMENT_TYPE et); @@ -88,28 +103,22 @@ public: inline static const ELEMENT_FACE * GetFaces0 (ELEMENT_TYPE et); [[deprecated("use GetEdge(SegmentIndex) instead")]] - int GetSegmentEdge (int segnr) const { return segedges[segnr-1]+1; } + EdgeIndex GetSegmentEdge (int segnr) const { return segedges[segnr-1]+1; } - int GetEdge (SegmentIndex segnr) const { return segedges[segnr]; } + EdgeIndex GetEdge (SegmentIndex segnr) const { return segedges[segnr]; } [[deprecated("use GetEdge(SegmentIndex) instead")]] void GetSegmentEdge (int segnr, int & enr, int & orient) const; - /* - { - enr = segedges.Get(segnr)+1; - // orient = segedges.Get(segnr).orient; - orient = GetSegmentEdgeOrientation(segnr); - } - */ [[deprecated("use GetEdges (ElementIndex) -> FlatArray")]] void GetElementEdges (int elnr, NgArray & edges) const; [[deprecated("use GetFaces (ElementIndex) -> FlatArray")]] - void GetElementFaces (int elnr, NgArray & faces, bool withorientation = false) const; + void GetElementFaces (int elnr, NgArray & faces) const; + void GetElementFaces (int elnr, NgArray & faces, bool withorientation) const; // definition in meshclass.hpp - inline FlatArray GetEdges (ElementIndex elnr) const; - inline FlatArray GetFaces (ElementIndex elnr) const; + inline FlatArray GetEdges (ElementIndex elnr) const; + inline FlatArray GetFaces (ElementIndex elnr) const; // [[deprecated("use GetElementEdge instead")]] @@ -134,22 +143,26 @@ public: // [[deprecated("use GetElementEdge instead")]] int GetSegmentEdgeOrientation (int elnr) const; // old style - DLL_HEADER void GetFaceVertices (int fnr, NgArray & vertices) const; DLL_HEADER void GetFaceVertices (int fnr, int * vertices) const; + auto GetFaceVertices (int fnr) const + { return FlatArray (face2vert[fnr][3].IsValid() ? 4 : 3, &face2vert[fnr][0]); } + [[deprecated("use GetEdgeVertices -> tupe(v0,v1) instead")]] DLL_HEADER void GetEdgeVertices (int enr, int & v1, int & v2) const; + [[deprecated("use GetEdgeVertices -> tupe(v0,v1) instead")]] DLL_HEADER void GetEdgeVertices (int enr, PointIndex & v1, PointIndex & v2) const; - auto GetEdgeVertices (int enr) const { return tuple(edge2vert[enr][0], edge2vert[enr][1]); } + auto GetEdgeVertices (int enr) const { return std::array{edge2vert[enr][0], edge2vert[enr][1]}; } auto GetEdgeVerticesPtr (int enr) const { return &edge2vert[enr][0]; } auto GetFaceVerticesPtr (int fnr) const { return &face2vert[fnr][0]; } DLL_HEADER void GetFaceEdges (int fnr, NgArray & edges, bool withorientation = false) const; ELEMENT_TYPE GetFaceType (int fnr) const - // { return (face2vert.Get(fnr)[3] == 0) ? TRIG : QUAD; } - { return (face2vert[fnr-1][3] == 0) ? TRIG : QUAD; } + { return (!face2vert[fnr-1][3].IsValid()) ? TRIG : QUAD; } + [[deprecated("use GetEdges (SurfaceElementIndex) -> FlatArray")]] void GetSurfaceElementEdges (int elnr, NgArray & edges) const; - int GetSurfaceElementFace (int elnr) const; + [[deprecated("use GetFace(SurfaceElementIndex")]] + int GetSurfaceElementFace1 (int elnr) const { return surffaces[elnr-1]+1; } [[deprecated("orientation is outdated")]] void GetSurfaceElementEdgeOrientations (int elnr, NgArray & eorient) const; // [[deprecated("orientation is outdated")]] @@ -158,29 +171,38 @@ public: [[deprecated("use GetEdge -> FlatArray instead")]] void GetEdges (SurfaceElementIndex elnr, NgArray & edges) const; - inline FlatArray GetEdges (SurfaceElementIndex elnr) const; - // { return FlatArray(GetNEdges ( (*mesh)[elnr].GetType()), &surfedges[elnr][0]); } + inline FlatArray GetEdges (SurfaceElementIndex elnr) const; + // { return FlatArray(GetNEdges ( (*mesh)[elnr].GetType()), &surfedges[elnr][0]); } int GetFace (SurfaceElementIndex elnr) const { return surffaces[elnr]; } int GetSurfaceElementEdges (int elnr, int * edges, int * orient) const; - const T_EDGE * GetElementEdgesPtr (int elnr) const { return &edges[elnr][0]; } - const T_EDGE * GetSurfaceElementEdgesPtr (int selnr) const { return &surfedges[selnr][0]; } - const T_EDGE * GetSegmentElementEdgesPtr (int selnr) const { return &segedges[selnr]; } + int GetNSurfedges() const {return surfedges.Size();} + [[deprecated("use GetEdges(ElementIndex) instead")]] + const EdgeIndex * GetElementEdgesPtr (int elnr) const { return &edges[IndexBASE()+elnr][0]; } + const EdgeIndex * GetSurfaceElementEdgesPtr (int selnr) const { return &surfedges[selnr][0]; } + const EdgeIndex * GetSegmentElementEdgesPtr (int selnr) const { return &segedges[selnr]; } - const T_FACE * GetElementFacesPtr (int elnr) const { return &faces[elnr][0]; } - const T_FACE * GetSurfaceElementFacesPtr (int selnr) const { return &surffaces[selnr]; } + const FaceIndex * GetElementFacesPtr (int elnr) const { return &faces[IndexBASE()+elnr][0]; } + const FaceIndex * GetSurfaceElementFacesPtr (int selnr) const { return &surffaces[selnr]; } void GetSurface2VolumeElement (int selnr, int & elnr1, int & elnr2) const { - elnr1 = surf2volelement.Get(selnr)[0]; - elnr2 = surf2volelement.Get(selnr)[1]; + elnr1 = surf2volelement[SurfaceElementIndex::Base() + selnr-1][0]+1 - ElementIndex::Base(); + elnr2 = surf2volelement[SurfaceElementIndex::Base() + selnr-1][1]+1 - ElementIndex::Base(); } - int GetFace2SurfaceElement (int fnr) const { return face2surfel[fnr-1]; } + std::array GetSurface2VolumeElement (SurfaceElementIndex sei) + { + return surf2volelement[sei]; + } + + [[deprecated("use GetSurfaceEleement -> SurfaceElementIndex")]] + int GetFace2SurfaceElement1 (int fnr) const { return face2surfel[fnr-1]+1 - SurfaceElementIndex::Base(); } + SurfaceElementIndex GetFace2SurfaceElement (int fnr) const { return face2surfel[fnr]; } SegmentIndex GetSegmentOfEdge(int edgenr) const { return edge2segment[edgenr-1]; } @@ -203,7 +225,7 @@ public: FlatArray GetVertexPointElements (PointIndex vnr) const { return vert2pointelement[vnr]; } - int GetVerticesEdge ( int v1, int v2) const; + DLL_HEADER int GetVerticesEdge ( PointIndex v1, PointIndex v2) const; void GetSegmentVolumeElements ( int segnr, NgArray & els ) const; void GetSegmentSurfaceElements ( int segnr, NgArray & els ) const; @@ -260,6 +282,9 @@ inline short int MeshTopology :: GetNVertices (ELEMENT_TYPE et) case PRISM15: return 6; + case HEX7: + return 7; + case HEX: case HEX20: return 8; @@ -309,6 +334,9 @@ inline short int MeshTopology :: GetNPoints (ELEMENT_TYPE et) case PRISM15: return 15; + case HEX7: + return 7; + case HEX: return 8; @@ -317,14 +345,14 @@ inline short int MeshTopology :: GetNPoints (ELEMENT_TYPE et) // default: // cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl; } - return 0; + return -99; } inline short int MeshTopology :: GetNEdges (ELEMENT_TYPE et) { - __assume(et >= SEGMENT && et <= PYRAMID13); + // __assume(et >= SEGMENT && et <= PYRAMID13); switch (et) { case SEGMENT: @@ -353,21 +381,22 @@ inline short int MeshTopology :: GetNEdges (ELEMENT_TYPE et) case PRISM15: return 9; + case HEX7: + return 11; + case HEX: case HEX20: return 12; - default: - return 0; // default: // cerr << "Ng_ME_GetNEdges, illegal element type " << et << endl; } - // return 0; + return -99; } inline short int MeshTopology :: GetNFaces (ELEMENT_TYPE et) { - __assume(et >= SEGMENT && et <= PYRAMID13); + // __assume(et >= SEGMENT && et <= PYRAMID13); switch (et) { case SEGMENT: @@ -398,6 +427,7 @@ inline short int MeshTopology :: GetNFaces (ELEMENT_TYPE et) case HEX: case HEX20: + case HEX7: return 6; default: @@ -458,6 +488,21 @@ const ELEMENT_EDGE * MeshTopology :: GetEdges1 (ELEMENT_TYPE et) { 3, 5 }, { 4, 5 }}; + static ELEMENT_EDGE hex7_edges[11] = + { + { 1, 2 }, + { 3, 4 }, + { 4, 1 }, + { 2, 3 }, + { 5, 6 }, + { 7, 5 }, + { 6, 7 }, + { 1, 5 }, + { 2, 6 }, + { 3, 7 }, + { 4, 7 }, + }; + static ELEMENT_EDGE hex_edges[12] = { { 1, 2 }, @@ -474,6 +519,7 @@ const ELEMENT_EDGE * MeshTopology :: GetEdges1 (ELEMENT_TYPE et) { 4, 8 }, }; + switch (et) { case SEGMENT: @@ -502,6 +548,9 @@ const ELEMENT_EDGE * MeshTopology :: GetEdges1 (ELEMENT_TYPE et) case PRISM15: return prism_edges; + case HEX7: + return hex7_edges; + case HEX: case HEX20: return hex_edges; @@ -559,6 +608,21 @@ const ELEMENT_EDGE * MeshTopology :: GetEdges0 (ELEMENT_TYPE et) { 2, 4 }, { 3, 4 }}; + static ELEMENT_EDGE hex7_edges[11] = + { + { 0, 1 }, + { 2, 3 }, + { 3, 0 }, + { 1, 2 }, + { 4, 5 }, + { 6, 4 }, + { 5, 6 }, + { 0, 4 }, + { 1, 5 }, + { 2, 6 }, + { 3, 6 }, + }; + static ELEMENT_EDGE hex_edges[12] = { { 0, 1 }, @@ -574,6 +638,7 @@ const ELEMENT_EDGE * MeshTopology :: GetEdges0 (ELEMENT_TYPE et) { 2, 6 }, { 3, 7 }, }; + switch (et) { @@ -603,6 +668,9 @@ const ELEMENT_EDGE * MeshTopology :: GetEdges0 (ELEMENT_TYPE et) case PRISM15: return prism_edges; + case HEX7: + return hex7_edges; + case HEX: case HEX20: return hex_edges; @@ -659,6 +727,21 @@ FlatArray MeshTopology :: GetEdges (ELEMENT_TYPE et) { 2, 4 }, { 3, 4 }}; + static ELEMENT_EDGE hex7_edges[11] = + { + { 0, 1 }, + { 2, 3 }, + { 3, 0 }, + { 1, 2 }, + { 4, 5 }, + { 6, 4 }, + { 5, 6 }, + { 0, 4 }, + { 1, 5 }, + { 2, 6 }, + { 3, 6 }, + }; + static ELEMENT_EDGE hex_edges[12] = { { 0, 1 }, @@ -703,6 +786,9 @@ FlatArray MeshTopology :: GetEdges (ELEMENT_TYPE et) case PRISM15: return { 9, prism_edges }; + case HEX7: + return { 11, hex7_edges }; + case HEX: case HEX20: return { 12, hex_edges }; @@ -750,6 +836,17 @@ inline const ELEMENT_FACE * MeshTopology :: GetFaces1 (ELEMENT_TYPE et) { 1, 4, 3, 2 } }; + static const ELEMENT_FACE hex7_faces[6] = + { + { 1, 4, 3, 2 }, + { 5, 6, 7, 0 }, + { 1, 2, 6, 5 }, + { 2, 3, 7, 6 }, + { 3, 4, 7, 0 }, + { 4, 1, 5, 7 } + }; + + static const ELEMENT_FACE hex_faces[6] = { { 1, 4, 3, 2 }, @@ -790,6 +887,9 @@ inline const ELEMENT_FACE * MeshTopology :: GetFaces1 (ELEMENT_TYPE et) case SEGMENT: case SEGMENT3: + case HEX7: + return hex7_faces; + case HEX: case HEX20: return hex_faces; @@ -835,6 +935,16 @@ inline const ELEMENT_FACE * MeshTopology :: GetFaces0 (ELEMENT_TYPE et) { 0, 3, 2, 1 } }; + static const ELEMENT_FACE hex7_faces[6] = + { + { 0, 3, 2, 1 }, + { 4, 5, 6, -1}, + { 0, 1, 5, 4 }, + { 1, 2, 6, 5 }, + { 2, 3, 6, -1}, + { 3, 0, 4, 6 } + }; + static const ELEMENT_FACE hex_faces[6] = { { 0, 3, 2, 1 }, @@ -875,6 +985,9 @@ inline const ELEMENT_FACE * MeshTopology :: GetFaces0 (ELEMENT_TYPE et) case SEGMENT: case SEGMENT3: + case HEX7: + return hex7_faces; + case HEX: case HEX20: return hex_faces; diff --git a/libsrc/meshing/validate.cpp b/libsrc/meshing/validate.cpp index f5fbff75..b6adc4a7 100644 --- a/libsrc/meshing/validate.cpp +++ b/libsrc/meshing/validate.cpp @@ -6,7 +6,7 @@ namespace netgen { void GetPureBadness(Mesh & mesh, NgArray & pure_badness, - const NgBitArray & isnewpoint) + const TBitArray & isnewpoint) { //const int ne = mesh.GetNE(); const int np = mesh.GetNP(); @@ -20,11 +20,11 @@ namespace netgen { backup[i] = new Point<3>(mesh.Point(i+1)); - if(isnewpoint.Test(i+PointIndex::BASE) && - mesh.mlbetweennodes[i+PointIndex::BASE][0] > 0) + if(isnewpoint.Test(i+IndexBASE()) && + mesh.mlbetweennodes[i+IndexBASE()][0].IsValid()) { - mesh.Point(i+1) = Center(mesh.Point(mesh.mlbetweennodes[i+PointIndex::BASE][0]), - mesh.Point(mesh.mlbetweennodes[i+PointIndex::BASE][1])); + mesh.Point(i+1) = Center(mesh.Point(mesh.mlbetweennodes[i+IndexBASE()][0]), + mesh.Point(mesh.mlbetweennodes[i+IndexBASE()][1])); } } for (ElementIndex i = 0; i < mesh.GetNE(); i++) @@ -104,7 +104,7 @@ namespace netgen } - void GetWorkingArea(NgBitArray & working_elements, NgBitArray & working_points, + void GetWorkingArea(BitArray & working_elements, TBitArray & working_points, const Mesh & mesh, const NgArray & bad_elements, const int width) { @@ -113,10 +113,10 @@ namespace netgen for(int i=0; i & bad_elements, - const NgBitArray & isnewpoint, const Refinement & refinement, + const TBitArray & isnewpoint, const Refinement & refinement, const NgArray & pure_badness, double max_worsening, const bool uselocalworsening, - const NgArray< NgArray* > & idmaps) + const NgArray< idmap_type* > & idmaps) { ostringstream ostrstr; @@ -185,39 +185,41 @@ namespace netgen can[i] = new Point<3>; } - NgBitArray isboundarypoint(np),isedgepoint(np); + TBitArray isboundarypoint(np),isedgepoint(np); isboundarypoint.Clear(); isedgepoint.Clear(); for(int i = 1; i <= mesh.GetNSeg(); i++) { const Segment & seg = mesh.LineSegment(i); - isedgepoint.Set(seg[0]); - isedgepoint.Set(seg[1]); + isedgepoint.SetBit(seg[0]); + isedgepoint.SetBit(seg[1]); } NgArray surfaceindex(np); surfaceindex = -1; - + + /* for (int i = 1; i <= mesh.GetNSE(); i++) { const Element2d & sel = mesh.SurfaceElement(i); - for (int j = 1; j <= sel.GetNP(); j++) - if(!isedgepoint.Test(sel.PNum(j))) - { - isboundarypoint.Set(sel.PNum(j)); - surfaceindex[sel.PNum(j) - PointIndex::BASE] = - mesh.GetFaceDescriptor(sel.GetIndex()).SurfNr(); - } - } - + */ + for (auto & sel : mesh.SurfaceElements()) + for (int j = 1; j <= sel.GetNP(); j++) + if(!isedgepoint.Test(sel.PNum(j))) + { + isboundarypoint.SetBit(sel.PNum(j)); + surfaceindex[sel.PNum(j) - IndexBASE()] = + mesh.GetFaceDescriptor(sel.GetIndex()).SurfNr(); + } + Validate(mesh,bad_elements,pure_badness, ((uselocalworsening) ? (0.8*(max_worsening-1.) + 1.) : (0.1*(max_worsening-1.) + 1.)), uselocalworsening); // -> larger working area - NgBitArray working_elements(ne); - NgBitArray working_points(np); + TBitArray working_elements(ne+1); + TBitArray working_points(np); GetWorkingArea(working_elements,working_points,mesh,bad_elements,numbadneighbours); //working_elements.Set(); @@ -240,10 +242,10 @@ namespace netgen PrintMessage(5,ostrstr.str()); - NgBitArray isworkingboundary(np); + TBitArray isworkingboundary(np); for(int i=1; i<=np; i++) if(working_points.Test(i) && isboundarypoint.Test(i)) - isworkingboundary.Set(i); + isworkingboundary.SetBit(i); else isworkingboundary.Clear(i); @@ -252,15 +254,16 @@ namespace netgen *should[i] = mesh.Point(i+1); - for(int i=0; i(); i < IndexBASE()+np; i++) { - if(isnewpoint.Test(i+PointIndex::BASE) && + if(isnewpoint.Test(i) && //working_points.Test(i+PointIndex::BASE) && - mesh.mlbetweennodes[i+PointIndex::BASE][0] > 0) - *can[i] = Center(*can[mesh.mlbetweennodes[i+PointIndex::BASE][0]-PointIndex::BASE], - *can[mesh.mlbetweennodes[i+PointIndex::BASE][1]-PointIndex::BASE]); + mesh.mlbetweennodes[i][0].IsValid()) + *can[i-IndexBASE()] = Center(*can[mesh.mlbetweennodes[i][0]-IndexBASE()], + *can[mesh.mlbetweennodes[i][1]-IndexBASE()]); else - *can[i] = mesh.Point(i+1); + *can[i-IndexBASE()] = mesh[i]; } @@ -306,15 +309,19 @@ namespace netgen { for(int i=0; i(0,0,0); + /* for (int i = 1; i <= mesh.GetNSE(); i++) { const Element2d & sel = mesh.SurfaceElement(i); + */ + for (auto & sel : mesh.SurfaceElements()) + { Vec<3> auxvec = Cross(mesh.Point(sel.PNum(2))-mesh.Point(sel.PNum(1)), mesh.Point(sel.PNum(3))-mesh.Point(sel.PNum(1))); auxvec.Normalize(); for (int j = 1; j <= sel.GetNP(); j++) if(!isedgepoint.Test(sel.PNum(j))) - *nv[sel.PNum(j) - PointIndex::BASE] += auxvec; + *nv[sel.PNum(j) - IndexBASE()] += auxvec; } for(int i=0; iNormalize(); @@ -470,11 +477,11 @@ namespace netgen multithread.terminate != 1) { MeshingParameters dummymp; - MeshOptimize3d optmesh(dummymp); + MeshOptimize3d optmesh(mesh, dummymp, OPT_QUALITY); for(int i=0; i & pure_badness, - const NgBitArray & isnewpoint); + const TBitArray & isnewpoint); double Validate(const Mesh & mesh, NgArray & bad_elements, const NgArray & pure_badness, double max_worsening, const bool uselocalworsening, NgArray * quality_loss = NULL); void RepairBisection(Mesh & mesh, NgArray & bad_elements, - const NgBitArray & isnewpoint, const Refinement & refinement, + const TBitArray & isnewpoint, const Refinement & refinement, const NgArray & pure_badness, double max_worsening, const bool uselocalworsening, - const NgArray< NgArray* > & idmaps); + const NgArray< idmap_type* > & idmaps); } diff --git a/libsrc/meshing/visual_interface.hpp b/libsrc/meshing/visual_interface.hpp index 5f856a24..c1bd03b7 100644 --- a/libsrc/meshing/visual_interface.hpp +++ b/libsrc/meshing/visual_interface.hpp @@ -5,7 +5,7 @@ #include #include -class Ng_SolutionData; +struct Ng_SolutionData; // Function pointers for visualization purposed, all set to nullptr by default and initialized correctly when the GUI library is loaded @@ -15,7 +15,7 @@ DLL_HEADER extern void (*Ptr_Ng_SetSolutionData) (Ng_SolutionData * soldata); DLL_HEADER extern void (*Ptr_Ng_Redraw) (bool blocking); // Tcl wrapper functions -class Tcl_Interp; +struct Tcl_Interp; typedef int (Tcl_CmdProc) (void * clientData, Tcl_Interp *interp, int argc, const char *argv[]); typedef void (Tcl_FreeProc) (char *blockPtr); diff --git a/libsrc/occ/Partition_Inter2d.cxx b/libsrc/occ/Partition_Inter2d.cxx index 7fed573b..88b6f7d8 100644 --- a/libsrc/occ/Partition_Inter2d.cxx +++ b/libsrc/occ/Partition_Inter2d.cxx @@ -516,7 +516,7 @@ static void EdgesPartition(const TopoDS_Face& F, } } - Standard_Boolean AffichPurge = Standard_False; + // Standard_Boolean AffichPurge = Standard_False; if ( LV1.IsEmpty()) return; diff --git a/libsrc/occ/Partition_Loop.cxx b/libsrc/occ/Partition_Loop.cxx index 25af5287..efaf77f7 100644 --- a/libsrc/occ/Partition_Loop.cxx +++ b/libsrc/occ/Partition_Loop.cxx @@ -67,7 +67,7 @@ #include static char* name = new char[100]; -static int nbe = 0; +// static int nbe = 0; #ifdef WIN32 #define M_PI 3.14159265358979323846 @@ -198,7 +198,7 @@ static Standard_Boolean SelectEdge(const TopoDS_Face& F, Cc->D2(uc, PC, CTg1, CTg2); C->D2(u, P, Tg1, Tg2); - Standard_Real angle; + Standard_Real angle = 0.0; if (CE.Orientation () == TopAbs_REVERSED && E.Orientation () == TopAbs_FORWARD) { angle = CTg1.Angle(Tg1.Reversed()); @@ -363,7 +363,7 @@ void Partition_Loop::Perform() } } - int i = 0; + // int i = 0; while (!End) { //------------------------------- // Construction of a wire. diff --git a/libsrc/occ/Partition_Loop3d.hxx b/libsrc/occ/Partition_Loop3d.hxx index e1716691..138b07e1 100644 --- a/libsrc/occ/Partition_Loop3d.hxx +++ b/libsrc/occ/Partition_Loop3d.hxx @@ -29,7 +29,6 @@ #if OCC_VERSION_HEX < 0x070000 #else #include - #include #include #endif diff --git a/libsrc/occ/Partition_Spliter.cxx b/libsrc/occ/Partition_Spliter.cxx index 1263909e..7a1d913a 100644 --- a/libsrc/occ/Partition_Spliter.cxx +++ b/libsrc/occ/Partition_Spliter.cxx @@ -1459,7 +1459,7 @@ void Partition_Spliter::MakeEdges (const TopoDS_Edge& E, if (VOnE.Extent() < 3) { // do not rebuild not cut edge if (( VF.IsSame( VOnE.First() ) && VL.IsSame( VOnE.Last() )) || - VL.IsSame( VOnE.First() ) && VF.IsSame( VOnE.Last() ) ) { + (VL.IsSame( VOnE.First() ) && VF.IsSame( VOnE.Last() )) ) { NE.Append( E ); return; } @@ -1476,7 +1476,7 @@ void Partition_Spliter::MakeEdges (const TopoDS_Edge& E, if (SV.Length() < 3) { // do not rebuild not cut edge if (( VF.IsSame( SV.First() ) && VL.IsSame( SV.Last() )) || - VL.IsSame( SV.First() ) && VF.IsSame( SV.Last() ) ) { + ( VL.IsSame( SV.First() ) && VF.IsSame( SV.Last() )) ) { NE.Append( E ); return; } diff --git a/libsrc/occ/occ_edge.cpp b/libsrc/occ/occ_edge.cpp index a3a2b06e..d0149399 100644 --- a/libsrc/occ/occ_edge.cpp +++ b/libsrc/occ/occ_edge.cpp @@ -1,7 +1,12 @@ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #include #include #include +#pragma clang diagnostic pop + #include "occ_edge.hpp" #include "occgeom.hpp" @@ -48,15 +53,15 @@ namespace netgen throw Exception(ToString("not implemented") + __FILE__ + ":" + ToString(__LINE__)); } - size_t OCCEdge::GetHash() const - { - return edge.HashCode(std::numeric_limits::max()); - } - void OCCEdge::ProjectPoint(Point<3>& p, EdgePointGeomInfo* gi) const { auto pnt = ng2occ(p); - GeomAPI_ProjectPointOnCurve proj(pnt, curve, s0, s1); + // extend the projection parameter range, else projection might fail + // for an endpoint + // see discussion here: https://forum.ngsolve.org/t/how-to-apply-occidentification-correctly/2555 + // I do not see a better way using occ tolerances? + double eps = 1e-7 * (s1-s0); + GeomAPI_ProjectPointOnCurve proj(pnt, curve, s0-eps, s1+eps); pnt = proj.NearestPoint(); if(gi) gi->dist = (proj.LowerDistanceParameter() - s0)/(s1-s0); diff --git a/libsrc/occ/occ_edge.hpp b/libsrc/occ/occ_edge.hpp index 1770e56a..a5f54ebf 100644 --- a/libsrc/occ/occ_edge.hpp +++ b/libsrc/occ/occ_edge.hpp @@ -1,6 +1,10 @@ #ifndef FILE_OCC_EDGE_INCLUDED #define FILE_OCC_EDGE_INCLUDED + +// #pragma clang diagnostic push +// #pragma clang diagnostic ignored "-Wdeprecated-declarations" + #include #include #include @@ -8,6 +12,8 @@ #include #include +// #pragma clang diagnostic pop + #include "occ_vertex.hpp" #include "meshing.hpp" @@ -30,7 +36,6 @@ namespace netgen Point<3> GetCenter() const override; Point<3> GetPoint(double t) const override; double CalcStep(double t, double sag) const override; - size_t GetHash() const override; void ProjectPoint(Point<3>& p, EdgePointGeomInfo* gi) const override; Vec<3> GetTangent(double t) const override; bool IsDegenerated(double) const override { diff --git a/libsrc/occ/occ_face.cpp b/libsrc/occ/occ_face.cpp index 2e60469a..23fb17da 100644 --- a/libsrc/occ/occ_face.cpp +++ b/libsrc/occ/occ_face.cpp @@ -1,8 +1,13 @@ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #include #include #include #include +#pragma clang diagnostic pop + #include "occ_edge.hpp" #include "occ_face.hpp" #include "occgeom.hpp" @@ -25,11 +30,6 @@ namespace netgen return 0; } - size_t OCCFace::GetHash() const - { - return face.HashCode(std::numeric_limits::max()); - } - Point<3> OCCFace::GetCenter() const { return occ2ng( props.CentreOfMass() ); @@ -56,14 +56,20 @@ namespace netgen edge_on_face[FORWARD].SetSize(n_edges); edge_on_face[REVERSED].SetSize(n_edges); - for(auto edge_ : GetEdges(face)) + // In case the face is INTERNAL, we need to orient it to FORWARD to get proper orientation for the edges + // (relative to the face) otherwise, all edges are also INTERNAL + auto oriented_face = TopoDS_Face(face); + if(oriented_face.Orientation() == TopAbs_INTERNAL) + oriented_face.Orientation(TopAbs_FORWARD); + + for(auto edge_ : GetEdges(oriented_face)) { auto edge = TopoDS::Edge(edge_); auto edgenr = geom.GetEdge(edge).nr; auto & orientation = edge_orientation[edgenr]; double s0, s1; - auto cof = BRep_Tool::CurveOnSurface (edge, face, s0, s1); - if(edge.Orientation() == TopAbs_FORWARD) + auto cof = BRep_Tool::CurveOnSurface (edge, oriented_face, s0, s1); + if(edge.Orientation() == TopAbs_FORWARD || edge.Orientation() == TopAbs_INTERNAL) { curve_on_face[FORWARD][edgenr] = cof; orientation += FORWARD; @@ -75,6 +81,15 @@ namespace netgen orientation += REVERSED; edge_on_face[REVERSED][edgenr] = edge; } + if(edge.Orientation() == TopAbs_INTERNAL) + { + // add reversed edge + auto r_edge = TopoDS::Edge(edge.Reversed()); + auto cof = BRep_Tool::CurveOnSurface (r_edge, oriented_face, s0, s1); + curve_on_face[REVERSED][edgenr] = cof; + orientation += REVERSED; + edge_on_face[REVERSED][edgenr] = r_edge; + } if(orientation > BOTH) throw Exception("have edge more than twice in face " + ToString(nr) + " " + properties.GetName() + ", orientation: " + ToString(orientation)); diff --git a/libsrc/occ/occ_face.hpp b/libsrc/occ/occ_face.hpp index 43e66bb6..71e583c7 100644 --- a/libsrc/occ/occ_face.hpp +++ b/libsrc/occ/occ_face.hpp @@ -1,11 +1,16 @@ #ifndef FILE_OCC_FACE_INCLUDED #define FILE_OCC_FACE_INCLUDED +// #pragma clang diagnostic push +// #pragma clang diagnostic ignored "-Wdeprecated-declarations" + #include #include #include #include +// #pragma clang diagnostic pop + #include "occ_vertex.hpp" #include "meshing.hpp" @@ -26,7 +31,6 @@ namespace netgen const TopoDS_Face Shape() const { return face; } - size_t GetHash() const override; Point<3> GetCenter() const override; virtual size_t GetNBoundaries() const override; virtual Array GetBoundary(const Mesh& mesh) const override; diff --git a/libsrc/occ/occ_solid.hpp b/libsrc/occ/occ_solid.hpp index d598de4a..505a1617 100644 --- a/libsrc/occ/occ_solid.hpp +++ b/libsrc/occ/occ_solid.hpp @@ -16,8 +16,7 @@ namespace netgen OCCSolid(TopoDS_Shape dshape) : solid(TopoDS::Solid(dshape)) { } - - size_t GetHash() const override { return solid.HashCode(std::numeric_limits::max()); } + TopoDS_Solid& GetShape() { return solid; } }; } diff --git a/libsrc/occ/occ_utils.cpp b/libsrc/occ/occ_utils.cpp index 97c6f836..c4296192 100644 --- a/libsrc/occ/occ_utils.cpp +++ b/libsrc/occ/occ_utils.cpp @@ -1,8 +1,11 @@ #include #include #include +#include +#include #include "occ_utils.hpp" +#include "occgeom.hpp" namespace netgen { @@ -55,4 +58,24 @@ namespace netgen #endif return {occ2ng(bb.CornerMin()), occ2ng(bb.CornerMax())}; } + + Standard_Integer BuildTriangulation( const TopoDS_Shape & shape ) + { + BRepTools::Clean (shape); + // double deflection = 0.01; + + // https://dev.opencascade.org/doc/overview/html/occt_user_guides__mesh.html + // from Standard_Boolean meshing_imeshtools_parameters() + IMeshTools_Parameters aMeshParams; + aMeshParams.Deflection = 0.01; + aMeshParams.Angle = 0.5; + aMeshParams.Relative = Standard_True; + aMeshParams.InParallel = Standard_True; + aMeshParams.MinSize = Precision::Confusion(); + aMeshParams.InternalVerticesMode = Standard_True; + aMeshParams.ControlSurfaceDeflection = Standard_True; + + BRepMesh_IncrementalMesh aMesher (shape, aMeshParams); + return aMesher.GetStatusFlags(); + } } diff --git a/libsrc/occ/occ_utils.hpp b/libsrc/occ/occ_utils.hpp index 2f55d405..89e7b81c 100644 --- a/libsrc/occ/occ_utils.hpp +++ b/libsrc/occ/occ_utils.hpp @@ -1,8 +1,17 @@ #ifndef FILE_OCC_UTILS_INCLUDED #define FILE_OCC_UTILS_INCLUDED +#define NETGEN_OCC_VERSION_AT_LEAST(MAYOR, MINOR) \ + OCC_VERSION_MAYOR > MAYOR || \ + (OCC_VERSION_MAYOR == MAYOR && OCC_VERSION_MINOR >= MINOR) +#define NETGEN_OCC_VERSION_AT_LEAST_MAYOR(MAYOR) \ + NETGEN_OCC_VERSION_AT_LEAST(MAYOR, 0) + #include +// #pragma clang diagnostic push +// #pragma clang diagnostic ignored "-Wdeprecated-declarations" + #include #include #include @@ -14,9 +23,11 @@ #include #include +// #pragma clang diagnostic pop + #include "meshing.hpp" -#if OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=4 +#if NETGEN_OCC_VERSION_AT_LEAST(7, 4) #define OCC_HAVE_DUMP_JSON #endif @@ -60,17 +71,18 @@ namespace netgen DLL_HEADER Box<3> GetBoundingBox( const TopoDS_Shape & shape ); - class OCCIdentification + struct OCCIdentification { - public: TopoDS_Shape from; TopoDS_Shape to; - Transformation<3> trafo; + optional> trafo = nullopt; string name; Identifications::ID_TYPE type; - bool opposite_direction; + bool opposite_direction = false; }; + Standard_Integer BuildTriangulation( const TopoDS_Shape & shape ); + class MyExplorer { @@ -164,6 +176,17 @@ namespace netgen common.push_back(shape); return common; } + + ListOfShapes GetHighestDimShapes() const + { + for (auto type : {TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX}) + { + auto ret = SubShapes(type); + if (ret.size() > 0) + return ret; + } + return ListOfShapes(); + } }; inline ListOfShapes GetSolids(const TopoDS_Shape & shape) @@ -206,6 +229,16 @@ namespace netgen return sub; } + inline ListOfShapes GetHighestDimShapes(const TopoDS_Shape & shape) + { + auto ret = GetSolids(shape); if(ret.size() > 0) return ret; + ret = GetFaces(shape); if(ret.size() > 0) return ret; + ret = GetEdges(shape); if(ret.size() > 0) return ret; + ret = GetVertices(shape); if(ret.size() > 0) return ret; + return ListOfShapes(); + } + + class DirectionalInterval { public: @@ -310,6 +343,6 @@ namespace netgen { return Properties(shape).Mass(); } - + } #endif // FILE_OCC_UTILS_INCLUDED diff --git a/libsrc/occ/occ_vertex.cpp b/libsrc/occ/occ_vertex.cpp index 6e83c894..f6ba788b 100644 --- a/libsrc/occ/occ_vertex.cpp +++ b/libsrc/occ/occ_vertex.cpp @@ -16,9 +16,4 @@ namespace netgen { return p; } - - size_t OCCVertex::GetHash() const - { - return vertex.HashCode(std::numeric_limits::max()); - } } diff --git a/libsrc/occ/occ_vertex.hpp b/libsrc/occ/occ_vertex.hpp index 9ec3a4e7..7207ac32 100644 --- a/libsrc/occ/occ_vertex.hpp +++ b/libsrc/occ/occ_vertex.hpp @@ -1,9 +1,14 @@ #ifndef FILE_OCC_VERTEX_INCLUDED #define FILE_OCC_VERTEX_INCLUDED +// #pragma clang diagnostic push +// #pragma clang diagnostic ignored "-Wdeprecated-declarations" + #include #include +// #pragma clang diagnostic pop + #include "meshing.hpp" #include "occ_utils.hpp" @@ -19,7 +24,6 @@ namespace netgen OCCVertex( TopoDS_Shape s ); ~OCCVertex() {} Point<3> GetPoint() const override; - size_t GetHash() const override; }; } diff --git a/libsrc/occ/occgenmesh.cpp b/libsrc/occ/occgenmesh.cpp index 517e1ebb..053b8ac9 100644 --- a/libsrc/occ/occgenmesh.cpp +++ b/libsrc/occ/occgenmesh.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -249,7 +248,7 @@ namespace netgen multithread.percent = 100 * k / (mesh.GetNFD() + VSMALL); geom.facemeshstatus[k-1] = -1; - FaceDescriptor & fd = mesh.GetFaceDescriptor(k); + // FaceDescriptor & fd = mesh.GetFaceDescriptor(k); auto face = TopoDS::Face(geom.fmap(k)); const auto& occface = dynamic_cast(geom.GetFace(k-1)); @@ -301,7 +300,7 @@ namespace netgen } for(const auto& vert : geom.GetFaceVertices(geom.GetFace(k-1))) { - PointIndex pi = vert->nr + 1; + PointIndex pi = vert->nr + IndexBASE(); if(glob2loc[pi] == 0) { auto gi = occface.Project(mesh[pi]); @@ -342,7 +341,7 @@ namespace netgen Array gis(2*segments.Size()); gis.SetSize (0); glob2loc = 0; - int cntpt = 0; + // int cntpt = 0; Box<2> uv_box(Box<2>::EMPTY_BOX); for(auto & seg : segments) @@ -399,7 +398,7 @@ namespace netgen } for(const auto& vert : geom.GetFaceVertices(geom.GetFace(k-1))) { - PointIndex pi = vert->nr + 1; + PointIndex pi = vert->nr + IndexBASE(); if(glob2loc[pi] == 0) { auto gi = occface.Project(mesh[pi]); @@ -415,7 +414,7 @@ namespace netgen // Philippose - 15/01/2009 - auto& props = OCCGeometry::GetProperties(geom.fmap(k)); + auto& props = occface.properties; double maxh = min2(geom.face_maxh[k-1], props.maxh); //double maxh = mparam.maxh; // int noldpoints = mesh->GetNP(); @@ -485,14 +484,18 @@ namespace netgen maxhdom = mparam.maxh; int maxlayer = 1; - int dom = 0; - for (TopExp_Explorer e(geom.GetShape(), TopAbs_SOLID); e.More(); e.Next(), dom++) + for(auto dom : Range(geom.GetNSolids())) { - auto& props = OCCGeometry::GetProperties(e.Current()); + auto & props = geom.GetSolid(dom).properties; maxhdom[dom] = min2(maxhdom[dom], props.maxh); maxlayer = max2(maxlayer, props.layer); } + for(auto & f : geom.Faces()) + maxlayer = max2(maxlayer, f->properties.layer); + + for(auto & e : geom.Edges()) + maxlayer = max2(maxlayer, e->properties.layer); mesh.SetMaxHDomain (maxhdom); @@ -507,6 +510,13 @@ namespace netgen for(auto layer : Range(1, maxlayer+1)) mesh.SetLocalH (bb.PMin(), bb.PMax(), mparam.grading, layer); + for(auto& v : geom.Vertices()) + { + auto& props = v->properties; + if(props.maxh < 1e99) + mesh.GetLocalH(props.layer)->SetH(v->GetPoint(), props.maxh); + } + int nedges = geom.emap.Extent(); double mincurvelength = IGNORECURVELENGTH; @@ -521,19 +531,10 @@ namespace netgen multithread.task = "Setting local mesh size (elements per edge)"; - // Philippose - 23/01/2009 - // Find all the parent faces of a given edge - // and limit the mesh size of the edge based on the - // mesh size limit of the face - TopTools_IndexedDataMapOfShapeListOfShape edge_face_map; - edge_face_map.Clear(); - TopExp::MapShapesAndAncestors(geom.shape, TopAbs_EDGE, TopAbs_FACE, edge_face_map); - // setting elements per edge for (int i = 1; i <= nedges && !multithread.terminate; i++) { TopoDS_Edge e = TopoDS::Edge (geom.emap(i)); - int layer = OCCGeometry::GetProperties(e).layer; multithread.percent = 100 * (i-1)/double(nedges); if (BRep_Tool::Degenerated(e)) continue; @@ -566,23 +567,10 @@ namespace netgen double localh = len/mparam.segmentsperedge; double s0, s1; - const TopTools_ListOfShape& parent_faces = edge_face_map.FindFromKey(e); - - TopTools_ListIteratorOfListOfShape parent_face_list; - - for(parent_face_list.Initialize(parent_faces); parent_face_list.More(); parent_face_list.Next()) - { - TopoDS_Face parent_face = TopoDS::Face(parent_face_list.Value()); - - int face_index = geom.fmap.FindIndex(parent_face); - - if(face_index >= 1) localh = min(localh,geom.face_maxh[face_index - 1]); - localh = min2(localh, OCCGeometry::GetProperties(parent_face).maxh); - } - Handle(Geom_Curve) c = BRep_Tool::Curve(e, s0, s1); - localh = min2(localh, OCCGeometry::GetProperties(e).maxh); + const auto & props = gedge.properties; + localh = min2(localh, props.maxh); maxedgelen = max (maxedgelen, len); minedgelen = min (minedgelen, len); int maxj = max((int) ceil(len/localh)*2, 2); @@ -590,7 +578,7 @@ namespace netgen for (int j = 0; j <= maxj; j++) { gp_Pnt pnt = c->Value (s0+double(j)/maxj*(s1-s0)); - mesh.RestrictLocalH (Point3d(pnt.X(), pnt.Y(), pnt.Z()), localh, layer); + mesh.RestrictLocalH (Point3d(pnt.X(), pnt.Y(), pnt.Z()), localh, props.layer); } } @@ -605,12 +593,12 @@ namespace netgen double maxcur = 0; multithread.percent = 100 * (i-1)/double(nedges); TopoDS_Edge edge = TopoDS::Edge (geom.emap(i)); - int layer = OCCGeometry::GetProperties(edge).layer; if (BRep_Tool::Degenerated(edge)) continue; double s0, s1; Handle(Geom_Curve) c = BRep_Tool::Curve(edge, s0, s1); BRepAdaptor_Curve brepc(edge); BRepLProp_CLProps prop(brepc, 2, 1e-5); + auto layer = geom.GetEdge(edge).properties.layer; for (int j = 1; j <= nsections; j++) { @@ -636,26 +624,28 @@ namespace netgen int nfaces = geom.fmap.Extent(); + BuildTriangulation(geom.shape); for (int i = 1; i <= nfaces && !multithread.terminate; i++) { multithread.percent = 100 * (i-1)/double(nfaces); TopoDS_Face face = TopoDS::Face(geom.fmap(i)); - int layer = OCCGeometry::GetProperties(face).layer; TopLoc_Location loc; Handle(Geom_Surface) surf = BRep_Tool::Surface (face); Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc); - if (triangulation.IsNull()) + if(triangulation.IsNull()) { - BRepTools::Clean (geom.shape); - BRepMesh_IncrementalMesh (geom.shape, 0.01, true); - triangulation = BRep_Tool::Triangulation (face, loc); + if (geom.shape.Infinite()) + throw Exception("Cannot generate mesh for an infinite geometry"); + else + throw Exception("OCC-Triangulation could not be built"); } - + BRepAdaptor_Surface sf(face, Standard_True); // one prop for evaluating and one for derivatives BRepLProp_SLProps prop(sf, 0, 1e-5); BRepLProp_SLProps prop2(sf, 2, 1e-5); + auto layer = geom.GetFace(face).properties.layer; int ntriangles = triangulation -> NbTriangles(); for (int j = 1; j <= ntriangles; j++) @@ -706,7 +696,7 @@ namespace netgen for (int i = 1; i <= nedges && !multithread.terminate; i++) { TopoDS_Edge edge = TopoDS::Edge (geom.emap(i)); - int layer = OCCGeometry::GetProperties(edge).layer; + int layer = geom.GetEdge(edge).properties.layer; if (BRep_Tool::Degenerated(edge)) continue; double s0, s1; @@ -717,7 +707,7 @@ namespace netgen gp_Vec d0 = prop.D1().Normalized(); double s_start = s0; - int count = 0; + // int count = 0; for (int j = 1; j <= sections; j++) { double s = s0 + (s1-s0)*(double)j/(double)sections; @@ -726,7 +716,7 @@ namespace netgen double cosalpha = fabs(d0*d1); if ((j == sections) || (cosalpha < cos(10.0/180.0*M_PI))) { - count++; + // count++; gp_Pnt p0 = c->Value (s_start); gp_Pnt p1 = c->Value (s); lines[nlines].p0 = Point<3> (p0.X(), p0.Y(), p0.Z()); diff --git a/libsrc/occ/occgeom.cpp b/libsrc/occ/occgeom.cpp index d53dbf16..303d2af2 100644 --- a/libsrc/occ/occgeom.cpp +++ b/libsrc/occ/occgeom.cpp @@ -14,15 +14,16 @@ #include "occgeom.hpp" #include "Partition_Spliter.hxx" +#include #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -71,6 +72,15 @@ namespace netgen void LoadOCCInto(OCCGeometry* occgeo, const filesystem::path & filename); void PrintContents (OCCGeometry * geom); + // Utility function to apply builder and propagate properties + template + static TopoDS_Shape Apply(T & builder, TopoDS_Shape & shape) { + auto newshape = builder->Apply(shape); + PropagateProperties(*builder, newshape); + return newshape; + }; + + TopTools_IndexedMapOfShape OCCGeometry::global_shape_property_indices; std::vector OCCGeometry::global_shape_properties; TopTools_IndexedMapOfShape OCCGeometry::global_identification_indices; @@ -190,6 +200,11 @@ namespace netgen return *faces[fmap.FindIndex(shape)-1]; } + const GeometrySolid & OCCGeometry :: GetSolid(const TopoDS_Shape & shape) const + { + return *solids[somap.FindIndex(shape)-1]; + } + string STEP_GetEntityName(const TopoDS_Shape & theShape, STEPCAFControl_Reader * aReader) { @@ -406,16 +421,7 @@ namespace netgen } #endif -#ifdef OCC_HAVE_HISTORY - Handle(BRepTools_History) history = aBuilder.History (); - - for (TopExp_Explorer e(shape, TopAbs_SOLID); e.More(); e.Next()) - { - if (auto name = OCCGeometry::GetProperties(e.Current()).name) - for (auto mods : history->Modified(e.Current())) - OCCGeometry::GetProperties(mods).name = *name; - } -#endif // OCC_HAVE_HISTORY + PropagateProperties(aBuilder, shape); // result of the operation shape = aBuilder.Shape(); @@ -443,14 +449,14 @@ namespace netgen { Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; - rebuild->Apply(shape); + Apply(rebuild, shape); for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next()) { TopoDS_Edge edge = TopoDS::Edge(exp1.Current()); if ( BRep_Tool::Degenerated(edge) ) rebuild->Remove(edge); } - shape = rebuild->Apply(shape); + shape = Apply(rebuild, shape); } BuildFMap(); @@ -474,7 +480,7 @@ namespace netgen Handle(ShapeFix_Face) sff; Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; - rebuild->Apply(shape); + Apply(rebuild, shape); for (exp0.Init (shape, TopAbs_FACE); exp0.More(); exp0.Next()) { @@ -512,20 +518,20 @@ namespace netgen // face (after the healing process) // GetProperties(face); } - shape = rebuild->Apply(shape); + shape = Apply(rebuild, shape); } { Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; - rebuild->Apply(shape); + Apply(rebuild, shape); for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next()) { TopoDS_Edge edge = TopoDS::Edge(exp1.Current()); if ( BRep_Tool::Degenerated(edge) ) rebuild->Remove(edge); } - shape = rebuild->Apply(shape); + shape = Apply(rebuild, shape); } @@ -535,7 +541,7 @@ namespace netgen Handle(ShapeFix_Wire) sfw; Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; - rebuild->Apply(shape); + Apply(rebuild, shape); for (exp0.Init (shape, TopAbs_FACE); exp0.More(); exp0.Next()) @@ -595,14 +601,14 @@ namespace netgen } } - shape = rebuild->Apply(shape); + shape = Apply(rebuild, shape); { BuildFMap(); Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; - rebuild->Apply(shape); + Apply(rebuild, shape); for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next()) { @@ -621,7 +627,7 @@ namespace netgen } } } - shape = rebuild->Apply(shape); + shape = Apply(rebuild, shape); //delete rebuild; rebuild = NULL; } @@ -630,14 +636,14 @@ namespace netgen { Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; - rebuild->Apply(shape); + Apply(rebuild, shape); for (exp1.Init (shape, TopAbs_EDGE); exp1.More(); exp1.Next()) { TopoDS_Edge edge = TopoDS::Edge(exp1.Current()); if ( BRep_Tool::Degenerated(edge) ) rebuild->Remove(edge); } - shape = rebuild->Apply(shape); + shape = Apply(rebuild, shape); } @@ -684,7 +690,9 @@ namespace netgen - shape = sfwf->Shape(); + auto newshape = sfwf->Shape(); + PropagateProperties(*sfwf->Context(), newshape); + shape = newshape; //delete sfwf; sfwf = NULL; //delete rebuild; rebuild = NULL; @@ -716,7 +724,9 @@ namespace netgen sffsm -> SetPrecision (tolerance); sffsm -> Perform(); - shape = sffsm -> FixShape(); + auto newshape = sffsm -> FixShape(); + PropagateProperties(*sffsm->Context(), newshape); + shape = newshape; //delete sffsm; sffsm = NULL; } @@ -745,6 +755,7 @@ namespace netgen } sewedObj.Perform(); + PropagateProperties(sewedObj, shape); if (!sewedObj.SewedShape().IsNull()) shape = sewedObj.SewedShape(); @@ -763,7 +774,7 @@ namespace netgen if ( BRep_Tool::Degenerated(edge) ) rebuild->Remove(edge); } - shape = rebuild->Apply(shape); + shape = Apply(rebuild, shape); } @@ -896,6 +907,30 @@ namespace netgen } + // For 2d geometries, make sure all faces have a normal vector with positive z-component + void OCCGeometry :: FixFaceOrientation() + { + if(dimension!=2) return; + + bool needs_fix = false; + Handle(ShapeBuild_ReShape) rebuild = new ShapeBuild_ReShape; + for (auto face : GetFaces(shape)) + { + auto occface = OCCFace(face); + auto normal = occface.GetNormal(occ2ng(GetVertices(face)[0])); + if(normal[2] < 0) { + needs_fix = true; + // Need do copy the face, otherwise replace is ignored + BRepBuilderAPI_Copy copy(face); + auto newface = copy.Shape().Reversed(); + GetProperties(newface).Merge(GetProperties(face)); + rebuild->Replace(face, newface); + } + } + + if(needs_fix ) + shape = Apply(rebuild, shape); + } void OCCGeometry :: BuildFMap() { @@ -908,6 +943,9 @@ namespace netgen TopExp_Explorer exp0, exp1, exp2, exp3, exp4, exp5; + // Check face orientation in 2d geometries + FixFaceOrientation(); + for (exp0.Init(shape, TopAbs_COMPOUND); exp0.More(); exp0.Next()) { @@ -1094,6 +1132,21 @@ namespace netgen } } */ + + std::map> free_edges_in_solid; + for(auto i1 : Range(1, somap.Extent()+1)) + { + auto s = somap(i1); + for (auto edge : MyExplorer(s, TopAbs_EDGE, TopAbs_WIRE)) + if (!emap.Contains(edge)) + { + free_edges_in_solid[i1].Append(emap.Add (edge)); + for (auto vertex : MyExplorer(edge, TopAbs_VERTEX)) + if (!vmap.Contains(vertex)) + vmap.Add (vertex); + } + } + for (auto edge : MyExplorer(shape, TopAbs_EDGE, TopAbs_WIRE)) if (!emap.Contains(edge)) { @@ -1166,6 +1219,8 @@ namespace netgen auto e = emap(i1); auto edge = TopoDS::Edge(e); auto verts = GetVertices(e); + if(verts.size() == 0) + continue; auto occ_edge = make_unique(edge, GetVertex(verts[0]), GetVertex(verts[1]) ); occ_edge->properties = GetProperties(e); edges.Append(std::move(occ_edge)); @@ -1204,18 +1259,37 @@ namespace netgen auto occ_solid = make_unique(s); if(HaveProperties(s)) occ_solid->properties = GetProperties(s); - solids.Append(std::move(occ_solid)); - for(auto f : GetFaces(s)) { - auto & face = GetFace(f); + auto & face = static_cast(GetFace(f)); + face.properties.maxh = min2(face.properties.maxh, occ_solid->properties.maxh); + if(face.domin==-1) face.domin = k; else face.domout = k; + if(face.Shape().Orientation() == TopAbs_INTERNAL) + face.domout = k; } + + if(free_edges_in_solid.count(i1)) + for(auto ei : free_edges_in_solid[i1]) + { + auto & edge = GetEdge(emap(ei)); + edge.properties.maxh = min(edge.properties.maxh, occ_solid->properties.maxh); + edge.domin = k; + edge.domout = k; + occ_solid->free_edges.Append(&GetEdge(emap(ei))); + } + solids.Append(std::move(occ_solid)); } + // Propagate maxh to children + for(auto& face : faces) + for(auto& edge : face->edges) + edge->properties.maxh = min2(edge->properties.maxh, + face->properties.maxh); + // Add identifications auto add_identifications = [&](auto & shapes, auto & shape_map) { @@ -1335,18 +1409,15 @@ namespace netgen const auto& occface = dynamic_cast(face); for(auto& vert : GetVertices(occface.Shape())) verts.Append(&GetVertex(vert)); - return std::move(verts); + return verts; } void OCCGeometry :: BuildVisualizationMesh (double deflection) { - cout << "Preparing visualization (deflection = " << deflection << ") ... " << flush; - - BRepTools::Clean (shape); - // BRepMesh_IncrementalMesh:: - BRepMesh_IncrementalMesh (shape, deflection, true); - cout << "done" << endl; + // cout << IM(5) << "Preparing visualization (deflection = " << deflection << ") ... " << flush; + BuildTriangulation(shape); + // cout << IM(5) << "done" << endl; } @@ -1467,6 +1538,7 @@ namespace netgen // Enable transfer of colours reader.SetColorMode(Standard_True); + reader.SetNameMode(Standard_True); reader.Transfer(iges_doc); @@ -1478,22 +1550,66 @@ namespace netgen iges_shape_contents->GetShapes(iges_shapes); // List out the available colours in the IGES File as Colour Names - TDF_LabelSequence all_colours; - iges_colour_contents->GetColors(all_colours); - PrintMessage(1,"Number of colours in IGES File: ",all_colours.Length()); - for(int i = 1; i <= all_colours.Length(); i++) - { - Quantity_Color col; - stringstream col_rgb; - iges_colour_contents->GetColor(all_colours.Value(i),col); - col_rgb << " : (" << col.Red() << "," << col.Green() << "," << col.Blue() << ")"; - PrintMessage(1, "Colour [", i, "] = ",col.StringName(col.Name()),col_rgb.str()); - } + // TDF_LabelSequence all_colours; + // iges_colour_contents->GetColors(all_colours); + // PrintMessage(1,"Number of colours in IGES File: ",all_colours.Length()); + // for(int i = 1; i <= all_colours.Length(); i++) + // { + // Quantity_Color col; + // stringstream col_rgb; + // iges_colour_contents->GetColor(all_colours.Value(i),col); + // col_rgb << " : (" << col.Red() << "," << col.Green() << "," << col.Blue() << ")"; + // PrintMessage(1, "Colour [", i, "] = ",col.StringName(col.Name()),col_rgb.str()); + // } // For the IGES Reader, all the shapes can be exported as one compound shape // using the "OneShape" member - occgeo->shape = reader.OneShape(); + auto shape = reader.OneShape(); + auto shapeTool = XCAFDoc_DocumentTool::ShapeTool(iges_doc->Main()); + // load colors + for (auto typ : {TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) + for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) + { + TDF_Label label; + shapeTool->Search(e.Current(), label); + + if(label.IsNull()) + continue; + + XCAFPrs_IndexedDataMapOfShapeStyle set; + TopLoc_Location loc; + XCAFPrs::CollectStyleSettings(label, loc, set); + XCAFPrs_Style aStyle; + set.FindFromKey(e.Current(), aStyle); + + auto & prop = OCCGeometry::GetProperties(e.Current()); + if(aStyle.IsSetColorSurf()) + prop.col = step_utils::ReadColor(aStyle.GetColorSurfRGBA()); + } + + // load names + auto workSession = reader.WS(); + auto model = workSession->Model(); + auto transProc = workSession->TransferReader()->TransientProcess(); + Standard_Integer nb = model->NbEntities(); + for (Standard_Integer i = 1; i <= nb; i++) + { + Handle(Standard_Transient) entity = model->Value(i); + auto item = Handle(StepRepr_RepresentationItem)::DownCast(entity); + + if(item.IsNull()) + continue; + + TopoDS_Shape shape = TransferBRep::ShapeResult(transProc->Find(item)); + string name = item->Name()->ToCString(); + if (!transProc->IsBound(item)) + continue; + + OCCGeometry::GetProperties(shape).name = name; + } + + occgeo->shape = shape; occgeo->changed = 1; occgeo->BuildFMap(); @@ -1533,8 +1649,12 @@ namespace netgen if(!result) { - delete occgeo; - return NULL; + result = BinTools::Read(occgeo->shape, filename.string().c_str()); + if (!result) + { + delete occgeo; + throw Exception("Could not read BREP file " + filename.string()); + } } occgeo->changed = 1; @@ -1623,16 +1743,14 @@ namespace netgen BRepTools::Read(shape, ss, builder); } - // enumerate shapes and archive only integers - auto my_hash = [](const TopoDS_Shape & key) { - auto occ_hash = key.HashCode(1<<31UL); - return std::hash()(occ_hash); - }; TopTools_IndexedMapOfShape shape_map; Array shape_list; ar & dimension; - for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) + auto types = Array{ TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }; + if(ar.GetVersion("netgen") >= "v6.2.2406-22") + types.Append(TopAbs_VERTEX); + for (auto typ : types) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto ds = e.Current(); @@ -1654,8 +1772,19 @@ namespace netgen ar & has_identifications; if(has_identifications) { - auto & idents = GetIdentifications(s); - auto n_idents = idents.size(); + int n_idents; + std::vector used_idents; + if(ar.Output()) + { + // only use identifications that are used within the geometry + for(auto& id : GetIdentifications(s)) + { + if(shape_map.Contains(id.from) && shape_map.Contains(id.to)) + used_idents.push_back(id); + } + n_idents = used_idents.size(); + } + auto & idents = ar.Output() ? used_idents : GetIdentifications(s); ar & n_idents; idents.resize(n_idents); for(auto i : Range(n_idents)) @@ -1667,7 +1796,18 @@ namespace netgen id_from = shape_map.FindIndex(id.from)-1; id_to = shape_map.FindIndex(id.to)-1; } - ar & id_from & id_to & id.trafo & id.name; + ar & id_from & id_to; + + // trafo is now optional -> special treatment necessary for backward compatibility + if(ar.Output() || netgen_version >= "v6.2.2403-34-g571cbbe4") + ar & id.trafo; + else + { + auto trafo = Transformation<3>(); + ar & trafo; + id.trafo = trafo; + } + ar & id.name; if(ar.Input()) { id.from = shape_list[id_from]; @@ -1695,7 +1835,7 @@ namespace netgen "Face", "Wire", "Edge", "Vertex"}; const char * orientationstring[] = - {"+", "-"}; + {"+", "-", "i", "e"}; @@ -1754,6 +1894,16 @@ namespace netgen } str << "{" << shapename[l] << " " << count2; + if(HaveProperties(e.Current())) + { + const auto& props = GetProperties(e.Current()); + if(props.name || props.maxh < 1e99) + str << " - "; + if(props.name) + str << props.GetName(); + if(props.maxh < 1e99) + str << " maxh(" << props.maxh << ")"; + } if (l <= TopAbs_EDGE) { @@ -2138,10 +2288,22 @@ namespace netgen XCAFPrs::CollectStyleSettings(label, loc, set); XCAFPrs_Style aStyle; set.FindFromKey(e.Current(), aStyle); - - auto & prop = OCCGeometry::GetProperties(e.Current()); if(aStyle.IsSetColorSurf()) - prop.col = step_utils::ReadColor(aStyle.GetColorSurfRGBA()); + { + for(TopExp_Explorer e2(e.Current(), TopAbs_FACE); e2.More(); e2.Next()) + { + auto & prop = OCCGeometry::GetProperties(e2.Current()); + prop.col = step_utils::ReadColor(aStyle.GetColorSurfRGBA()); + } + } + if(aStyle.IsSetColorCurv()) + { + for(TopExp_Explorer e2(e.Current(), TopAbs_EDGE); e2.More(); e2.Next()) + { + auto & prop = OCCGeometry::GetProperties(e2.Current()); + prop.col = step_utils::ReadColor(aStyle.GetColorSurfRGBA()); + } + } } // load names @@ -2243,27 +2405,33 @@ namespace netgen auto & identifications = OCCGeometry::GetIdentifications(shape); if(identifications.size()==0) return; - auto n = identifications.size(); + // auto n = identifications.size(); Array ident_items; ident_items.Append(item); for(auto & ident : identifications) { + const auto& to = STEPConstruct::FindEntity(finder, ident.from == shape ? ident.to : ident.from); + if(to.IsNull()) + continue; Array items; - // items.Append(STEPConstruct::FindEntity(finder, ident.other)); // TODO! - auto & m = ident.trafo.GetMatrix(); + items.Append(MakeReal(ident.from == shape ? 1 : 0)); + items.Append(to); + Transformation<3> trafo; + if(ident.trafo) trafo = *ident.trafo; + auto & m = trafo.GetMatrix(); for(auto i : Range(9)) items.Append(MakeReal(m(i))); - auto & v = ident.trafo.GetVector(); + auto & v = trafo.GetVector(); for(auto i : Range(3)) items.Append(MakeReal(v(i))); - for(auto & item : items.Range(1,items.Size())) + items.Append(MakeInt(ident.type)); + for(auto & item : items.Range(0, items.Size())) model->AddEntity(item); ident_items.Append(MakeCompound(items, ident.name)); } - - for(auto & item : ident_items.Range(1,ident_items.Size())) - model->AddEntity(item); + for(auto & item : ident_items.Range(1, ident_items.Size())) + model->AddEntity(item); auto comp = MakeCompound(ident_items, "netgen_geometry_identification"); model->AddEntity(comp); } @@ -2280,15 +2448,29 @@ namespace netgen auto id_item = Handle(StepRepr_CompoundRepresentationItem)::DownCast(idents->ItemElementValue(i)); OCCIdentification ident; ident.name = id_item->Name()->ToCString(); - // ident.other = TransferBRep::ShapeResult(transProc->Find(id_item->ItemElementValue(1))); /TODO! + auto is_from = ReadReal(id_item->ItemElementValue(1)); + if(is_from) + { + ident.from = shape_origin; + ident.to = TransferBRep::ShapeResult(transProc->Find(id_item->ItemElementValue(2))); + } + else + { + ident.from = TransferBRep::ShapeResult( + transProc->Find(id_item->ItemElementValue(2))); + ident.to = shape_origin; + } - auto & m = ident.trafo.GetMatrix(); + Transformation<3> trafo; + auto & m = trafo.GetMatrix(); for(auto i : Range(9)) m(i) = ReadReal(id_item->ItemElementValue(3+i)); - auto & v = ident.trafo.GetVector(); + auto & v = trafo.GetVector(); for(auto i : Range(3)) v(i) = ReadReal(id_item->ItemElementValue(12+i)); - + if(FlatVector(9, &trafo.GetMatrix()(0,0)).L2Norm() != .0 && trafo.GetVector().Length2() != .0) + ident.trafo = trafo; + ident.type = Identifications::ID_TYPE(ReadInt(id_item->ItemElementValue(15))); result.push_back(ident); } OCCGeometry::GetIdentifications(shape_origin) = result; diff --git a/libsrc/occ/occgeom.hpp b/libsrc/occ/occgeom.hpp index 1162fab3..6d2abbc8 100644 --- a/libsrc/occ/occgeom.hpp +++ b/libsrc/occ/occgeom.hpp @@ -15,6 +15,10 @@ #include "occ_utils.hpp" #include "occmeshsurf.hpp" +#include +#include +#include +#include #include #include #include @@ -228,6 +232,7 @@ namespace netgen using NetgenGeometry::GetVertex; using NetgenGeometry::GetEdge; using NetgenGeometry::GetFace; + using NetgenGeometry::GetSolid; GeometryShape & GetShape(const TopoDS_Shape & shape) { @@ -248,10 +253,16 @@ namespace netgen return const_cast(as_const(*this).GetFace(shape)); } + GeometrySolid & GetSolid(const TopoDS_Shape & shape) + { + return const_cast(as_const(*this).GetSolid(shape)); + } + const GeometryShape & GetShape(const TopoDS_Shape & shape) const; const GeometryVertex & GetVertex(const TopoDS_Shape & shape) const; const GeometryEdge & GetEdge(const TopoDS_Shape & shape) const; const GeometryFace & GetFace(const TopoDS_Shape & shape) const; + const GeometrySolid & GetSolid(const TopoDS_Shape & shape) const; void Analyse(Mesh& mesh, const MeshingParameters& mparam) const override; @@ -311,6 +322,7 @@ namespace netgen Array GetFaceVertices(const GeometryFace& face) const override; + void FixFaceOrientation(); void HealGeometry(); void GlueGeometry(); @@ -415,8 +427,8 @@ namespace netgen //bool FastProject (int surfi, Point<3> & ap, double& u, double& v) const; }; - void Identify(const ListOfShapes & me, const ListOfShapes & you, string name, Identifications::ID_TYPE type, Transformation<3> trafo); - void Identify(const TopoDS_Shape & me, const TopoDS_Shape & you, string name, Identifications::ID_TYPE type, std::optional> opt_trafo); + DLL_HEADER void Identify(const ListOfShapes & me, const ListOfShapes & you, string name, Identifications::ID_TYPE type, Transformation<3> trafo); + DLL_HEADER void Identify(const TopoDS_Shape & me, const TopoDS_Shape & you, string name, Identifications::ID_TYPE type, std::optional> opt_trafo); void PrintContents (OCCGeometry * geom); @@ -434,6 +446,14 @@ namespace netgen DLL_HEADER extern bool OCCMeshFace (const OCCGeometry & geom, Mesh & mesh, FlatArray glob2loc, const MeshingParameters & mparam, int nr, int projecttype, bool delete_on_failure); + inline auto GetModified(BRepBuilderAPI_MakeShape & builder, TopoDS_Shape shape) { return builder.Modified(shape); } + inline auto GetModified(BRepTools_History & history, TopoDS_Shape shape) { return history.Modified(shape); } + inline auto GetModified(BOPAlgo_BuilderShape & builder, TopoDS_Shape shape) { return builder.Modified(shape); } + inline ArrayMem GetModified(BRepBuilderAPI_Sewing& builder, TopoDS_Shape shape) { return {builder.Modified(shape)}; } + inline auto GetModified(BRepTools_ReShape& reshape, TopoDS_Shape shape) { + auto history = reshape.History(); + return history->Modified(shape); + } template void PropagateIdentifications (TBuilder & builder, TopoDS_Shape shape, std::optional> trafo = nullopt) @@ -459,7 +479,7 @@ namespace netgen for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto s = e.Current(); - for (auto mods : builder.Modified(s)) + for (auto mods : GetModified(builder, s)) { auto index = mod_indices.FindIndex(s)-1; modifications[index].Add(mods); @@ -479,7 +499,7 @@ namespace netgen continue; auto& identifications = OCCGeometry::GetIdentifications(s); - auto& shape_mapped = modifications[mod_indices.FindIndex(s)-1]; + // auto& shape_mapped = modifications[mod_indices.FindIndex(s)-1]; for(auto ident : identifications) { @@ -503,11 +523,13 @@ namespace netgen if(from.IsSame(from_mapped) && to.IsSame(to_mapped)) continue; - Transformation<3> trafo_mapped = ident.trafo; + if(!ident.trafo) continue; + Transformation<3> trafo_mapped = *ident.trafo; + if(trafo) { Transformation<3> trafo_temp; - trafo_temp.Combine(ident.trafo, trafo_inv); + trafo_temp.Combine(*ident.trafo, trafo_inv); trafo_mapped.Combine(*trafo, trafo_temp); } @@ -530,7 +552,7 @@ namespace netgen { bool have_identifications = false; - for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE }) + for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }) for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) { auto s = e.Current(); @@ -538,7 +560,7 @@ namespace netgen if(!OCCGeometry::HaveProperties(s)) continue; auto prop = OCCGeometry::GetProperties(s); - for (auto mods : builder.Modified(s)) + for (auto mods : GetModified(builder, s)) OCCGeometry::GetProperties(mods).Merge(prop); } if(have_identifications) diff --git a/libsrc/occ/occmeshsurf.cpp b/libsrc/occ/occmeshsurf.cpp index a4eaff83..16a0e427 100644 --- a/libsrc/occ/occmeshsurf.cpp +++ b/libsrc/occ/occmeshsurf.cpp @@ -5,9 +5,14 @@ #include #include "occgeom.hpp" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #include #include +#pragma clang diagnostic pop + #include "occmeshsurf.hpp" namespace netgen @@ -32,7 +37,7 @@ namespace netgen double setu=geominfo.u,setv=geominfo.v; double ustep = 0.01*(umax-umin); - double vstep = 0.01*(vmax-vmin); + // double vstep = 0.01*(vmax-vmin); n=0; @@ -291,6 +296,8 @@ namespace netgen Point<2> & pplane, double h, int & zone) const { + // static Timer t("ToPlane"); RegionTimer reg(t); + if (projecttype == PLANESPACE) { Vec<3> p1p, n; @@ -333,7 +340,7 @@ namespace netgen PointGeomInfo & gi, double h) { - static Timer t("FromPlane"); RegionTimer reg(t); + // static Timer t("FromPlane"); RegionTimer reg(t); if (projecttype == PLANESPACE) { @@ -360,6 +367,9 @@ namespace netgen void OCCSurface :: Project (Point<3> & ap, PointGeomInfo & gi) { static Timer t("OccSurface::Project"); RegionTimer reg(t); + static Timer tanal("OccSurface::Project analysis"); + static Timer ttol("OccSurface::Project approximation"); + static Timer t2("OccSurface::Project actual"); @@ -465,9 +475,14 @@ namespace netgen */ // double u,v; + // JS : shouldn't we move these 2 lines to the constructor ? + // tanal.Start(); Handle( ShapeAnalysis_Surface ) su = new ShapeAnalysis_Surface( occface ); + // ShapeAnalysis_Surface su( occface ); + // tanal.Stop(); + ttol.Start(); auto toltool = BRep_Tool::Tolerance( topods_face ); - + ttol.Stop(); // gp_Pnt2d suval = su->ValueOfUV ( pnt, toltool); t2.Start(); gp_Pnt2d suval = su->NextValueOfUV (gp_Pnt2d(u,v), pnt, toltool); diff --git a/libsrc/occ/occmeshsurf.hpp b/libsrc/occ/occmeshsurf.hpp index b4c4b06e..c045da69 100644 --- a/libsrc/occ/occmeshsurf.hpp +++ b/libsrc/occ/occmeshsurf.hpp @@ -5,10 +5,13 @@ #include "occgeom.hpp" #include "mydefs.hpp" - +#include #include #include #include +#include +#include + #define PARAMETERSPACE -1 #define PLANESPACE 1 @@ -30,7 +33,8 @@ public: Handle(Geom_Surface) occface; TopAbs_Orientation orient; int projecttype; - + ShapeAnalysis_Surface su; + Standard_Real toltool; protected: Point<3> p1; Point<3> p2; @@ -60,10 +64,15 @@ protected: public: OCCSurface (const TopoDS_Face & aface, int aprojecttype) + : topods_face(aface), + occface(BRep_Tool::Surface(topods_face)), + su( occface ), + toltool(BRep_Tool::Tolerance(topods_face)) + { static Timer t("occurface ctor"); RegionTimer r(t); topods_face = aface; - occface = BRep_Tool::Surface(topods_face); + // occface = BRep_Tool::Surface(topods_face); orient = topods_face.Orientation(); projecttype = aprojecttype; ShapeAnalysis::GetFaceUVBounds (topods_face, umin, umax, vmin, vmax); @@ -72,6 +81,8 @@ public: umax += fabs(umax-umin)/100.0; vmax += fabs(vmax-vmin)/100.0; // projecttype = PLANESPACE; + + // su = ShapeAnalysis_Surface( occface ); /* TopExp_Explorer exp1; exp1.Init (topods_face, TopAbs_WIRE); diff --git a/libsrc/occ/occpkg.cpp b/libsrc/occ/occpkg.cpp index ecc11af8..57b1b78e 100644 --- a/libsrc/occ/occpkg.cpp +++ b/libsrc/occ/occpkg.cpp @@ -817,21 +817,29 @@ namespace netgen if(strcmp(argv[1], "showall") == 0) { + /* for(int i = 1; i <= mesh->GetNSE(); i++) { - mesh->SurfaceElement(i).Visible(1); + mesh->SurfaceElement(i).Visible(1); } - - mesh->SetNextTimeStamp(); + */ + for (auto & el : mesh->SurfaceElements()) + el.Visible(1); + + mesh->SetNextTimeStamp(); } if(strcmp(argv[1], "hideall") == 0) { + /* for(int i = 1; i <= mesh->GetNSE(); i++) { - mesh->SurfaceElement(i).Visible(0); + mesh->SurfaceElement(i).Visible(0); } - + */ + for (auto & el : mesh->SurfaceElements()) + el.Visible(0); + mesh->SetNextTimeStamp(); } diff --git a/libsrc/occ/python_occ.cpp b/libsrc/occ/python_occ.cpp index 48089571..9924e341 100644 --- a/libsrc/occ/python_occ.cpp +++ b/libsrc/occ/python_occ.cpp @@ -1,6 +1,7 @@ #ifdef NG_PYTHON #ifdef OCCGEOMETRY + #include #include @@ -20,6 +21,9 @@ #include #include #include +#include +#include +#include using namespace netgen; @@ -85,7 +89,11 @@ DLL_HEADER void ExportNgOCC(py::module &m) try { if(p) std::rethrow_exception(p); } catch (const Standard_Failure& e) { +#if (PYBIND11_VERSION_MAJOR == 2 && PYBIND11_VERSION_MINOR < 12) exc((string(e.DynamicType()->Name()) + ": " + e.GetMessageString()).c_str()); +#else + py::set_error(PyExc_RuntimeError, (string(e.DynamicType()->Name()) + ": " + e.GetMessageString()).c_str()); +#endif } }); @@ -160,10 +168,40 @@ DLL_HEADER void ExportNgOCC(py::module &m) { ng_geometry = geo; }) + .def_property_readonly("solids", [](shared_ptr geo) + { + ListOfShapes solids; + for (int i = 1; i <= geo->somap.Extent(); i++) + solids.push_back(geo->somap(i)); + return solids; + }, "Get solids in order that they will be in the mesh") + .def_property_readonly("faces", [](shared_ptr geo) + { + ListOfShapes faces; + for (int i = 1; i <= geo->fmap.Extent(); i++) + faces.push_back(geo->fmap(i)); + return faces; + }, "Get faces in order that they will be in the mesh") + .def_property_readonly("edges", [](shared_ptr geo) + { + ListOfShapes edges; + for (int i = 1; i <= geo->emap.Extent(); i++) + edges.push_back(geo->emap(i)); + return edges; + }, "Get edges in order that they will be in the mesh") + .def_property_readonly("vertices", [](shared_ptr geo) + { + ListOfShapes vertices; + for (int i = 1; i <= geo->vmap.Extent(); i++) + vertices.push_back(geo->vmap(i)); + return vertices; + }, "Get vertices in order that they will be in the mesh") .def("_visualizationData", [] (shared_ptr occ_geo) { std::vector vertices; - std::vector trigs; + std::vector indices; + std::vector edges; + std::vector edge_indices; std::vector normals; std::vector min = {std::numeric_limits::max(), std::numeric_limits::max(), @@ -171,7 +209,8 @@ DLL_HEADER void ExportNgOCC(py::module &m) std::vector max = {std::numeric_limits::lowest(), std::numeric_limits::lowest(), std::numeric_limits::lowest()}; - std::vector surfnames; + std::vector face_colors; + std::vector edge_colors; auto box = occ_geo->GetBoundingBox(); for(int i = 0; i < 3; i++) { @@ -183,11 +222,67 @@ DLL_HEADER void ExportNgOCC(py::module &m) gp_Pnt pnt; gp_Vec n; gp_Pnt p[3]; - int count = 0; + for(int edge_index = 1; edge_index <= occ_geo->emap.Extent(); + edge_index++) + { + auto edge = TopoDS::Edge(occ_geo->emap(edge_index)); + if(OCCGeometry::HaveProperties(edge)) + { + const auto& props = OCCGeometry::GetProperties(edge); + if(props.col) + edge_colors.insert(edge_colors.end(), + {float((*props.col)[0]), + float((*props.col)[1]), + float((*props.col)[2]), + float((*props.col)[3])}); + else + edge_colors.insert(edge_colors.end(),{0.f,0.f,0.f,1.f}); + } + else + { + edge_colors.insert(edge_colors.end(),{0.f,0.f,0.f,1.f}); + } + BRepAdaptor_Curve adapt_crv = BRepAdaptor_Curve(edge); + GCPnts_TangentialDeflection discretizer; + discretizer.Initialize(adapt_crv, 0.09, 0.01); + if (discretizer.NbPoints() > 1) + { + for (int j = 1; j <= discretizer.NbPoints()-1; ++j) + { + gp_Pnt p_0 = discretizer.Value(j); + gp_Pnt p_1 = discretizer.Value(j+1); + edges.insert(edges.end(), + {float(p_0.X()), + float(p_0.Y()), + float(p_0.Z()), + float(p_1.X()), + float(p_1.Y()), + float(p_1.Z())}); + edge_indices.push_back(uint32_t(edge_index-1)); + } + } + } for (int i = 1; i <= occ_geo->fmap.Extent(); i++) { - surfnames.push_back("occ_surface" + to_string(i)); auto face = TopoDS::Face(occ_geo->fmap(i)); + if (OCCGeometry::HaveProperties(face)) + { + const auto& props = OCCGeometry::GetProperties(face); + if(props.col) + face_colors.insert(face_colors.end(), + {float((*props.col)[0]), + float((*props.col)[1]), + float((*props.col)[2]), + float((*props.col)[3])}); + else + { + face_colors.insert(face_colors.end(),{0.7,0.7,0.7,1.}); + } + } + else + { + face_colors.insert(face_colors.end(),{0.7,0.7,0.7,1.}); + } auto surf = BRep_Tool::Surface(face); TopLoc_Location loc; BRepAdaptor_Surface sf(face, Standard_False); @@ -195,7 +290,7 @@ DLL_HEADER void ExportNgOCC(py::module &m) Handle(Poly_Triangulation) triangulation = BRep_Tool::Triangulation (face, loc); if (triangulation.IsNull()) cout << "cannot visualize face " << i << endl; - trigs.reserve(trigs.size() + triangulation->NbTriangles()*4); + indices.reserve(indices.size() + triangulation->NbTriangles()); vertices.reserve(vertices.size() + triangulation->NbTriangles()*3*3); normals.reserve(normals.size() + triangulation->NbTriangles()*3*3); for (int j = 1; j < triangulation->NbTriangles()+1; j++) @@ -203,11 +298,13 @@ DLL_HEADER void ExportNgOCC(py::module &m) auto triangle = triangulation->Triangle(j); for (int k = 1; k < 4; k++) p[k-1] = triangulation->Node(triangle(k)).Transformed(loc); + indices.push_back(uint32_t(i-1)); for (int k = 1; k < 4; k++) { - vertices.insert(vertices.end(),{float(p[k-1].X()), float(p[k-1].Y()), float(p[k-1].Z())}); - trigs.insert(trigs.end(),{count, count+1, count+2,i}); - count += 3; + vertices.insert(vertices.end(),{ + float(p[k-1].X()), + float(p[k-1].Y()), + float(p[k-1].Z())}); uv = triangulation->UVNode(triangle(k)); prop.SetParameters(uv.X(), uv.Y()); if (prop.IsNormalDefined()) @@ -226,12 +323,13 @@ DLL_HEADER void ExportNgOCC(py::module &m) py::gil_scoped_acquire ac; py::dict res; py::list snames; - for(auto name : surfnames) - snames.append(py::cast(name)); res["vertices"] = MoveToNumpy(vertices); - res["triangles"] = MoveToNumpy(trigs); + res["edges"] = MoveToNumpy(edges); + res["edge_indices"] = MoveToNumpy(edge_indices); + res["edge_colors"] = MoveToNumpy(edge_colors); + res["indices"] = MoveToNumpy(indices); res["normals"] = MoveToNumpy(normals); - res["surfnames"] = snames; + res["face_colors"] = MoveToNumpy(face_colors); res["min"] = MoveToNumpy(min); res["max"] = MoveToNumpy(max); return res; @@ -242,17 +340,15 @@ DLL_HEADER void ExportNgOCC(py::module &m) { MeshingParameters mp; OCCParameters occparam; - { - py::gil_scoped_acquire aq; - if(pars) - { - auto mp_kwargs = CreateDictFromFlags(pars->geometrySpecificParameters); - CreateOCCParametersFromKwargs(occparam, mp_kwargs); - mp = *pars; - } - CreateOCCParametersFromKwargs(occparam, kwargs); - CreateMPfromKwargs(mp, kwargs); - } + if(pars) + { + auto mp_kwargs = CreateDictFromFlags(pars->geometrySpecificParameters); + CreateOCCParametersFromKwargs(occparam, mp_kwargs); + mp = *pars; + } + CreateOCCParametersFromKwargs(occparam, kwargs); + CreateMPfromKwargs(mp, kwargs); + py::gil_scoped_release gil_release; geo->SetOCCParameters(occparam); if(!mesh) mesh = make_shared(); @@ -278,7 +374,7 @@ DLL_HEADER void ExportNgOCC(py::module &m) } return mesh; }, py::arg("mp") = nullptr, py::arg("comm")=NgMPI_Comm{}, - py::arg("mesh")=nullptr, py::call_guard(), + py::arg("mesh")=nullptr, (meshingparameter_description + occparameter_description).c_str()) .def_property_readonly("shape", [](const OCCGeometry & self) { return self.GetShape(); }) ; diff --git a/libsrc/occ/python_occ_basic.cpp b/libsrc/occ/python_occ_basic.cpp index 9768a22d..bf5cd64e 100644 --- a/libsrc/occ/python_occ_basic.cpp +++ b/libsrc/occ/python_occ_basic.cpp @@ -25,7 +25,7 @@ DLL_HEADER void ExportNgOCCBasic(py::module &m) .def(py::init([] (py::tuple pnt) { if (py::len(pnt) != 3) - throw Exception("need 3-tuple to create gp_Pnt"); + throw std::length_error("need 3-tuple to create gp_Pnt"); return gp_Pnt(py::cast(pnt[0]), py::cast(pnt[1]), @@ -73,6 +73,7 @@ DLL_HEADER void ExportNgOCCBasic(py::module &m) .def(py::init([] (double x, double y, double z) { return gp_Vec(x, y, z); }), py::arg("x"), py::arg("y"), py::arg("z")) + .def(py::init([](gp_Dir d) { return gp_Vec(d); })) .def_property("x", [](gp_Vec&p) { return p.X(); }, [](gp_Vec&p,double x) { p.SetX(x); }) .def_property("y", [](gp_Vec&p) { return p.Y(); }, [](gp_Vec&p,double y) { p.SetY(y); }) .def_property("z", [](gp_Vec&p) { return p.Z(); }, [](gp_Vec&p,double z) { p.SetZ(z); }) @@ -132,6 +133,12 @@ DLL_HEADER void ExportNgOCCBasic(py::module &m) return str.str(); }) ; + + + py::class_(m, "gp_Mat", "3d OCC matrix") + .def("__getitem__", [](const gp_Mat& mat, tuple index) + { return mat.Row(get<0>(index)+1).Coord(get<1>(index)+1); }) + ; py::class_(m, "Axis", "an OCC axis in 3d") .def(py::init([](gp_Pnt p, gp_Dir d) { @@ -151,18 +158,18 @@ DLL_HEADER void ExportNgOCCBasic(py::module &m) .def(py::init([](gp_Pnt p, gp_Dir N, gp_Dir Vx) { return gp_Ax3(p,N, Vx); }), py::arg("p")=gp_Pnt(0,0,0), py::arg("n")=gp_Vec(0,0,1), py::arg("h")=gp_Vec(1,0,0)) + .def(py::init([](gp_Ax1 ax1) { + return gp_Ax3(ax1.Location(), ax1.Direction()); + }), py::arg("axis")) .def(py::init()) .def_property("p", [](gp_Ax3 & ax) { return ax.Location(); }, [](gp_Ax3&ax, gp_Pnt p) { ax.SetLocation(p); }) ; py::class_(m, "gp_Pnt2d", "2d OCC point") - .def(py::init([] (py::tuple pnt) + .def(py::init([] (std::tuple pnt) { - if (py::len(pnt) != 2) - throw Exception("need 2-tuple to create gp_Pnt2d"); - return gp_Pnt2d(py::cast(pnt[0]), - py::cast(pnt[1])); + return gp_Pnt2d(get<0>(pnt), get<1>(pnt)); })) .def(py::init([] (double x, double y) { return gp_Pnt2d(x, y); @@ -359,10 +366,14 @@ DLL_HEADER void ExportNgOCCBasic(py::module &m) py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); - py::implicitly_convertible(); + py::implicitly_convertible(); + py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); py::implicitly_convertible(); + + py::implicitly_convertible(); + py::implicitly_convertible(); py::implicitly_convertible(); diff --git a/libsrc/occ/python_occ_shapes.cpp b/libsrc/occ/python_occ_shapes.cpp index 29c3320c..1a487aa6 100644 --- a/libsrc/occ/python_occ_shapes.cpp +++ b/libsrc/occ/python_occ_shapes.cpp @@ -9,7 +9,14 @@ #include #include "occgeom.hpp" +#include "occ_utils.hpp" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +#if NETGEN_OCC_VERSION_AT_LEAST(7, 6) +#include +#endif // NETGEN_OCC_VERSION_AT_LEAST(7, 6) #include #include #include @@ -18,16 +25,18 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#include #include #include #include -#include #include #include #include @@ -43,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -66,12 +76,15 @@ #include #include #include +#include #include #include #include #include #include +#pragma clang diagnostic pop + using namespace netgen; void ExtractEdgeData( const TopoDS_Edge & edge, int index, std::vector * p, Box<3> & box ) @@ -417,7 +430,7 @@ public: return shared_from_this(); } - auto ArcTo (double h, double v, const gp_Vec2d t) + auto ArcTo (double h, double v, const gp_Vec2d t, optional name=nullopt) { gp_Pnt2d P1 = localpos.Location(); @@ -482,6 +495,8 @@ public: auto edge = BRepBuilderAPI_MakeEdge(curve2d, surf, lastvertex, endv).Edge(); lastvertex = endv; BRepLib::BuildCurves3d(edge); + if(name.has_value()) + OCCGeometry::GetProperties(edge).name = name; wire_builder.Add(edge); //compute angle of rotation @@ -502,7 +517,7 @@ public: return shared_from_this(); } - auto Arc(double radius, double angle) + auto Arc(double radius, double angle, optional name) { double newAngle = fmod(angle,360)*M_PI/180; @@ -533,29 +548,29 @@ public: cout << IM(6) << "t = (" << t.X() << ", " << t.Y() << ")" << endl; //add arc - return ArcTo (oldp.X(), oldp.Y(), t); + return ArcTo (oldp.X(), oldp.Y(), t, name); } - auto Rectangle (double l, double w) + auto Rectangle (double l, double w, optional name) { - Line (l); + Line (l, name); Rotate (90); - Line(w); + Line(w, name); Rotate (90); - Line (l); + Line (l, name); Rotate (90); - Line(w); + Line(w, name); Rotate (90); return shared_from_this(); } - auto RectangleCentered (double l, double w) + auto RectangleCentered (double l, double w, optional name) { Move(-l/2); Rotate(-90); Move(w/2); Rotate(90); - Rectangle(l,w); + Rectangle(l,w, name); Rotate(-90); Move(-w/2); Rotate(90); @@ -588,6 +603,19 @@ public: return shared_from_this(); } + auto Ellipse(double major, double minor) + { + Handle(Geom2d_Ellipse) ell_curve = GCE2d_MakeEllipse(localpos, major, minor).Value(); + + auto edge = BRepBuilderAPI_MakeEdge(ell_curve, surf).Edge(); + BRepLib::BuildCurves3d(edge); + + wire_builder.Add(edge); + wires.push_back (wire_builder.Wire()); + wire_builder = BRepBuilderAPI_MakeWire(); + return shared_from_this(); + } + auto NameVertex (string name) { if (!lastvertex.IsNull()) @@ -601,11 +629,11 @@ public: return Circle (pos.X(), pos.Y(), r); } - shared_ptr Close () + shared_ptr Close (optional name = nullopt) { if (startpnt.Distance(localpos.Location()) > 1e-10) { - LineTo (startpnt.X(), startpnt.Y()); + LineTo (startpnt.X(), startpnt.Y(), name); return shared_from_this(); } @@ -622,13 +650,18 @@ public: auto Offset(double d) { + Finish(); TopoDS_Wire wire = wires.back(); wires.pop_back(); - BRepOffsetAPI_MakeOffset builder; - builder.AddWire(wire); + + // handle wires containing a single edge correctly, see + // https://dev.opencascade.org/content/brepoffsetapimakeoffset-open-topodswire + BRepBuilderAPI_MakeFace makeFace{gp_Pln{axes}}; + makeFace.Add(wire); + BRepOffsetAPI_MakeOffset builder(makeFace.Face()); builder.Perform(d); auto shape = builder.Shape(); - wires.push_back (TopoDS::Wire(shape.Reversed())); + wires.push_back (TopoDS::Wire(shape)); return shared_from_this(); } @@ -670,6 +703,36 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) .export_values() ; + m.def("ResetGlobalShapeProperties", [] () { + OCCGeometry::global_shape_properties.clear(); + OCCGeometry::global_shape_property_indices.Clear(); + }); + + struct SwigTypeInfo + { + const char* name; // SWIG's type name string + // Other fields... + }; + + struct SwigPyObject{ + PyObject_HEAD + void *ptr; + SwigTypeInfo* ty; // SWIG type information + int own; // ownership flag + }; + + m.def("From_PyOCC", [](py::object shape) + { + py::object py_this = shape.attr("this"); + PyObject* obj = py_this.ptr(); + SwigPyObject* swig_obj = reinterpret_cast(obj); + if (!swig_obj->ptr || !swig_obj->ty || !swig_obj->ty->name) { + throw std::runtime_error("SWIG object does not contain a valid pointer"); + } + if(strcmp(swig_obj->ty->name, "_p_TopoDS_Shape") != 0) + throw std::runtime_error("Does not contain TopoDS_Shape from pyocc!"); + return py::cast(static_cast(swig_obj->ptr)); + }, py::return_value_policy::reference, py::keep_alive<0,1>()); py::class_ (m, "TopoDS_Shape") .def("__str__", [] (const TopoDS_Shape & shape) @@ -713,6 +776,14 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) return py::make_tuple( ng2occ(box.PMin()), ng2occ(box.PMax()) ); }, "returns bounding box (pmin, pmax)") + .def("LimitTolerance", [](TopoDS_Shape& self, double tmin, + double tmax, TopAbs_ShapeEnum type) + { + ShapeFix_ShapeTolerance fix; + fix.LimitTolerance(self, tmin, tmax, type); + }, py::arg("tmin"), py::arg("tmax")=0., py::arg("type")=TopAbs_SHAPE, + "limit tolerance of shape to range [tmin, tmax]") + .def("Properties", [] (const TopoDS_Shape & shape) { auto props = Properties(shape); @@ -727,6 +798,10 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) return Mass(shape); }, "returns mass of shape, what is length, face, or volume") + .def_property_readonly("inertia", [](const TopoDS_Shape & shape) { + return Properties(shape).MatrixOfInertia(); + }, "returns matrix of inertia of shape") + .def("Move", [](const TopoDS_Shape & shape, const gp_Vec v) { // which one to choose ? @@ -759,7 +834,7 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) PropagateProperties(builder, shape, occ2ng(trafo)); return builder.Shape(); }, py::arg("axes"), - "copy shape, and mirror over plane defined by 'axes'") + "copy shape, and mirror over XY - plane defined by 'axes'") .def("Mirror", [] (const TopoDS_Shape & shape, const gp_Ax1 & ax) { @@ -769,7 +844,7 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) PropagateProperties(builder, shape, occ2ng(trafo)); return builder.Shape(); }, py::arg("axes"), - "copy shape, and mirror around axis 'axis'") + "copy shape, and rotate by 180 deg around axis 'axis'") .def("Scale", [](const TopoDS_Shape & shape, const gp_Pnt p, double s) { @@ -784,7 +859,33 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) .def("WriteStep", [](const TopoDS_Shape & shape, string & filename) { step_utils::WriteSTEP(shape, filename); } , py::arg("filename"), "export shape in STEP - format") - + .def("WriteBrep", [](const TopoDS_Shape & shape, const string& filename, + bool withTriangles, bool withNormals, + optional version, bool binary) + { + if(binary) + { +#if NETGEN_OCC_VERSION_AT_LEAST(7, 6) + BinTools_FormatVersion v = version ? BinTools_FormatVersion(*version) : BinTools_FormatVersion_CURRENT; + BinTools::Write(shape, filename.c_str(), withTriangles, withNormals, v); +# else // NETGEN_OCC_VERSION_AT_LEAST(7, 6) + throw Exception("Binary BREP export not supported in this version of OpenCascade"); +#endif // NETGEN_OCC_VERSION_AT_LEAST(7, 6) + } + else + { +#if NETGEN_OCC_VERSION_AT_LEAST(7, 6) + TopTools_FormatVersion v = version ? (TopTools_FormatVersion)(*version) : TopTools_FormatVersion_CURRENT; + BRepTools::Write(shape, filename.c_str(), withTriangles, withNormals, v); +#else // OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=6 + BRepTools::Write(shape, filename.c_str()); +#endif // OCC_VERSION_MAJOR>=7 && OCC_VERSION_MINOR>=6 + } + }, py::arg("filename"), py::arg("withTriangles")=true, + py::arg("withNormals")=false, + py::arg("version")=py::none(), + py::arg("binary")=false, + "export shape in BREP - format") .def("bc", [](const TopoDS_Shape & shape, const string & name) { for (TopExp_Explorer e(shape, TopAbs_FACE); e.More(); e.Next()) @@ -806,6 +907,8 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) return nullopt; }, [](const TopoDS_Shape & self, optional name) { OCCGeometry::GetProperties(self).name = name; + for (auto & s : GetHighestDimShapes(self)) + OCCGeometry::GetProperties(s).name = name; }, "'name' of shape") .def_property("maxh", @@ -815,12 +918,9 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) }, [](TopoDS_Shape& self, double val) { - for (auto typ : { TopAbs_SOLID, TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }) - for (TopExp_Explorer e(self, typ); e.More(); e.Next()) - { - auto & maxh = OCCGeometry::GetProperties(e.Current()).maxh; - maxh = min2(val, maxh); - } + OCCGeometry::GetProperties(self).maxh = val; + for(auto & s : GetHighestDimShapes(self)) + OCCGeometry::GetProperties(s).maxh = val; }, "maximal mesh-size for shape") .def_property("hpref", @@ -830,21 +930,36 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) }, [](TopoDS_Shape& self, double val) { - auto & hpref = OCCGeometry::GetProperties(self).hpref; - hpref = max2(val, hpref); + OCCGeometry::GetProperties(self).hpref = val; + for(auto & s : GetHighestDimShapes(self)) + OCCGeometry::GetProperties(s).hpref = val; }, "number of refinement levels for geometric refinement") - .def_property("col", [](const TopoDS_Shape & self) { + .def_property("col", [](const TopoDS_Shape & self) -> py::object { if(!OCCGeometry::HaveProperties(self) || !OCCGeometry::GetProperties(self).col) - return std::vector({ 0.2, 0.2, 0.2, 1. }); + return py::none(); auto col = *OCCGeometry::GetProperties(self).col; - return std::vector({ col(0), col(1), col(2), col(3) }); - }, [](const TopoDS_Shape & self, std::vector c) { - Vec<4> col(c[0], c[1], c[2], 1.0); - if(c.size() == 4) - col[3] = c[3]; - OCCGeometry::GetProperties(self).col = col; + return py::cast(std::vector({ col(0), col(1), col(2), col(3) })); + }, [](const TopoDS_Shape & self, std::optional> c) { + if(c.has_value()) + { + Vec<4> col((*c)[0], (*c)[1], (*c)[2], 1.0); + if(c->size() == 4) + col[3] = (*c)[3]; + OCCGeometry::GetProperties(self).col = col; + } + else + OCCGeometry :: GetProperties(self).col = nullopt; }, "color of shape as RGB - tuple") + .def_property("layer", [](const TopoDS_Shape& self) { + if (!OCCGeometry::HaveProperties(self)) + return 1; + return OCCGeometry::GetProperties(self).layer; + }, [](const TopoDS_Shape& self, int layer) { + OCCGeometry::GetProperties(self).layer = layer; + for(auto & s : GetHighestDimShapes(self)) + OCCGeometry::GetProperties(s).layer = layer; + }, "layer of shape") .def("UnifySameDomain", [](const TopoDS_Shape& shape, bool edges, bool faces, bool concatBSplines) @@ -1044,8 +1159,38 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) } // throw Exception("no face found for revolve"); }, py::arg("axis"), py::arg("ang"), "revolve shape around 'axis' by 'ang' degrees") - - .def("MakeFillet", [](const TopoDS_Shape & shape, std::vector edges, double r) { + .def("MakeFillet", [](const TopoDS_Shape& shape, const std::vector>& fillets) -> TopoDS_Shape + { + if (shape.ShapeType() == TopAbs_FACE) { + BRepFilletAPI_MakeFillet2d mkFillet2d(TopoDS::Face(shape)); + for (auto [v, r] : fillets) + mkFillet2d.AddFillet(TopoDS::Vertex(v), r); + mkFillet2d.Build(); + // TODO: CL I think we shouldn't do this here but, double check + // PropagateProperties (mkFillet2d, shape); + return mkFillet2d.Shape(); + } + BRepFilletAPI_MakeFillet mkFillet(shape); + for (auto [e, r] : fillets) + mkFillet.Add(r, TopoDS::Edge(e)); + mkFillet.Build(); + PropagateProperties (mkFillet, shape); + for (auto [e, r] : fillets) + for (auto gen : mkFillet.Generated(e)) + OCCGeometry::GetProperties(gen).name = "fillet"; + return mkFillet.Shape(); + }, py::arg("fillets"), "make fillets for shapes of radius 'r'") + .def("MakeFillet", [](const TopoDS_Shape & shape, std::vector edges, double r) -> TopoDS_Shape { + if(shape.ShapeType() == TopAbs_FACE) + { + BRepFilletAPI_MakeFillet2d mkFillet(TopoDS::Face(shape)); + for (auto e : edges) + mkFillet.AddFillet (TopoDS::Vertex(e), r); + mkFillet.Build(); + // TODO: CL I think we shouldn't do this here but, double check + // PropagateProperties (mkFillet, shape); + return mkFillet.Shape(); + } BRepFilletAPI_MakeFillet mkFillet(shape); for (auto e : edges) mkFillet.Add (r, TopoDS::Edge(e)); @@ -1096,12 +1241,63 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) py::arg("intersection") = false,py::arg("joinType")="arc", py::arg("removeIntersectingEdges") = false, "makes shell-like solid from faces") + + .def("Offset", [](const TopoDS_Shape & shape, + double offset, double tol, bool intersection, + string joinT, bool removeIntEdges, optional identification_name) { + BRepOffsetAPI_MakeOffsetShape maker; + GeomAbs_JoinType joinType; + if(joinT == "arc") + joinType = GeomAbs_Arc; + else if(joinT == "intersection") + joinType = GeomAbs_Intersection; + else if(joinT == "tangent") + joinType = GeomAbs_Tangent; + else + throw Exception("Only joinTypes 'arc', 'intersection' and 'tangent' exist!"); + + maker.PerformByJoin(shape, offset, tol, + BRepOffset_Skin, intersection, + false, joinType, removeIntEdges); + + // PropagateProperties (maker, shape); + for (auto typ : { TopAbs_FACE, TopAbs_EDGE, TopAbs_VERTEX }) + for (TopExp_Explorer e(shape, typ); e.More(); e.Next()) + { + auto s = e.Current(); + auto prop = OCCGeometry::GetProperties(s); + for (auto mods : maker.Generated(s)) + { + if(OCCGeometry::HaveProperties(s)) + { + auto & new_props = OCCGeometry::GetProperties(mods); + new_props.Merge(prop); + if (prop.name) new_props.name = string("offset_")+(*prop.name); + } + if(identification_name) + { + OCCIdentification ident; + ident.from = s; + ident.to = mods; + ident.name = *identification_name; + ident.type = Identifications::CLOSESURFACES; + OCCGeometry::GetIdentifications(s).push_back(ident); + } + } + } + + return maker.Shape(); + }, py::arg("offset"), py::arg("tol"), + py::arg("intersection") = false,py::arg("joinType")="arc", + py::arg("removeIntersectingEdges") = false, + py::arg("identification_name") = nullopt, + "makes shell-like solid from faces") + + .def("MakeTriangulation", [](const TopoDS_Shape & shape) { - BRepTools::Clean (shape); - double deflection = 0.01; - BRepMesh_IncrementalMesh (shape, deflection, true); + BuildTriangulation(shape); }) @@ -1130,12 +1326,6 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) throw NgException ("Triangulation: shape is not a face"); } - /* - BRepTools::Clean (shape); - double deflection = 0.01; - BRepMesh_IncrementalMesh (shape, deflection, true); - */ - Handle(Geom_Surface) surf = BRep_Tool::Surface (face); TopLoc_Location loc; @@ -1143,9 +1333,7 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) if (triangulation.IsNull()) { - BRepTools::Clean (shape); - double deflection = 0.01; - BRepMesh_IncrementalMesh (shape, deflection, true); + BuildTriangulation(shape); triangulation = BRep_Tool::Triangulation (face, loc); } // throw Exception("Don't have a triangulation, call 'MakeTriangulation' first"); @@ -1166,11 +1354,9 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) }) .def("_webgui_data", [](const TopoDS_Shape & shape) { - BRepTools::Clean (shape); - double deflection = 0.01; - BRepMesh_IncrementalMesh (shape, deflection, true); - // triangulation = BRep_Tool::Triangulation (face, loc); - + [[maybe_unused]] auto status = BuildTriangulation(shape); + // cout << "status = " << aStatus << endl; + std::vector p[3]; std::vector n[3]; py::list names, colors, solid_names; @@ -1187,20 +1373,14 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) // Handle(TopoDS_Face) face = e.Current(); fmap.Add(face); ExtractFaceData(face, index, p, n, box); - auto & props = OCCGeometry::GetProperties(face); - if(props.col) - { - auto & c = *props.col; - colors.append(py::make_tuple(c[0], c[1], c[2])); - } - else - colors.append(py::make_tuple(0.0, 1.0, 0.0)); - if(props.name) - { - names.append(*props.name); - } - else - names.append(""); + + ShapeProperties props; + if(OCCGeometry::HaveProperties(face)) + props = OCCGeometry::GetProperties(face); + + auto c = props.GetColor(); + colors.append(py::make_tuple(c[0], c[1], c[2], c[3])); + names.append(props.GetName()); index++; } @@ -1309,6 +1489,9 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) BRepLib::BuildCurves3d(edge); return edge; })) + .def(py::init([] (const TopoDS_Vertex & v1, const TopoDS_Vertex & v2) { + return BRepBuilderAPI_MakeEdge(v1, v2).Edge(); + })) .def("Value", [](const TopoDS_Edge & e, double s) { double s0, s1; auto curve = BRep_Tool::Curve(e, s0, s1); @@ -1362,7 +1545,20 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) return tuple(s0, s1); }, "parameter interval of curve") - + .def_property("partition", + [](TopoDS_Shape & self) -> optional> + { + if (OCCGeometry::HaveProperties(self)) + return OCCGeometry::GetProperties(self).partition; + return nullopt; + }, + [](TopoDS_Shape &self, py::array_t val) + { + Array partition(val.size()); + for(auto i : Range(partition)) + partition[i] = val.at(i); + OCCGeometry::GetProperties(self).partition = std::move(partition); + }) .def("Split", [](const TopoDS_Edge& self, py::args args) { @@ -1431,6 +1627,24 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) throw NgException("error in wire builder: "+errstr.str()); } })) + .def("Offset", [](const TopoDS_Wire & wire, const TopoDS_Face & face, double dist, + string joinT, bool openresult) + { + GeomAbs_JoinType joinType; + if(joinT == "arc") + joinType = GeomAbs_Arc; + else if(joinT == "intersection") + joinType = GeomAbs_Intersection; + else if(joinT == "tangent") + joinType = GeomAbs_Tangent; + else + throw Exception("Only joinTypes 'arc', 'tangent', and 'intersection' exist!"); + BRepOffsetAPI_MakeOffset builder(face, joinType, openresult); + builder.AddWire(wire); + builder.Perform(dist); + auto shape = builder.Shape(); + return shape; + }) ; py::class_ (m, "Face") @@ -1543,8 +1757,14 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) py::implicitly_convertible(); py::implicitly_convertible(); - + m.def("MakePolygon", [](std::vector verts) + { + BRepBuilderAPI_MakePolygon builder; + for(auto& v : verts) + builder.Add(v); + return builder.Wire(); + }); class ListOfShapesIterator { @@ -1694,17 +1914,8 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) }, [](ListOfShapes& shapes, double maxh) { - for(auto& shape : shapes) - { - for(auto& s : GetSolids(shape)) - OCCGeometry::GetProperties(s).maxh = maxh; - for(auto& s : GetFaces(shape)) - OCCGeometry::GetProperties(s).maxh = maxh; - for(auto& s : GetEdges(shape)) - OCCGeometry::GetProperties(s).maxh = maxh; - for(auto& s : GetVertices(shape)) - OCCGeometry::GetProperties(s).maxh = maxh; - } + for(auto & s : shapes) + OCCGeometry::GetProperties(s).maxh = maxh; }, "set maxh for all elements of list") .def_property("hpref", [](ListOfShapes& shapes) { @@ -1713,10 +1924,7 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) [](ListOfShapes& shapes, double hpref) { for(auto& shape : shapes) - { - auto& val = OCCGeometry::GetProperties(shape).hpref; - val = max2(hpref, val); - } + OCCGeometry::GetProperties(shape).hpref = hpref; }, "set hpref for all elements of list") .def_property("quad_dominated", [](ListOfShapes& shapes) { @@ -1768,21 +1976,21 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) }) .def("Edge", [](Handle(Geom2d_Curve) curve) { // static Geom_Plane surf{gp_Ax3()}; // crashes in nbconvert ??? - static auto surf = new Geom_Plane{gp_Ax3()}; + static auto surf = Handle(Geom_Plane)(new Geom_Plane{gp_Ax3()}); auto edge = BRepBuilderAPI_MakeEdge(curve, surf).Edge(); BRepLib::BuildCurves3d(edge); return edge; }) .def("Wire", [](Handle(Geom2d_Curve) curve) { // static Geom_Plane surf{gp_Ax3()}; // crashes in nbconvert ??? - static auto surf = new Geom_Plane{gp_Ax3()}; + static auto surf = Handle(Geom_Plane)(new Geom_Plane{gp_Ax3()}); auto edge = BRepBuilderAPI_MakeEdge(curve, surf).Edge(); BRepLib::BuildCurves3d(edge); return BRepBuilderAPI_MakeWire(edge).Wire(); }) .def("Face", [](Handle(Geom2d_Curve) curve) { // static Geom_Plane surf{gp_Ax3()}; // crashes in nbconvert ??? - static auto surf = new Geom_Plane{gp_Ax3()}; + static auto surf = Handle(Geom_Plane)(new Geom_Plane{gp_Ax3()}); auto edge = BRepBuilderAPI_MakeEdge(curve, surf).Edge(); BRepLib::BuildCurves3d(edge); auto wire = BRepBuilderAPI_MakeWire(edge).Wire(); @@ -1815,9 +2023,32 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) BRepPrimAPI_MakeHalfSpace builder(face, refpnt); return builder.Shape(); }, py::arg("p"), py::arg("n"), "Create a half space threw point p normal to n"); + m.def("Sphere", [] (gp_Pnt cc, double r) { return BRepPrimAPI_MakeSphere (cc, r).Solid(); }, py::arg("c"), py::arg("r"), "create sphere with center 'c' and radius 'r'"); + + m.def("Ellipsoid", [] (gp_Ax3 ax, double r1, double r2, optional hr3) { + auto sp = BRepPrimAPI_MakeSphere (gp_Pnt(0,0,0), 1).Solid(); + + gp_GTrsf gtrafo; + double r3 = hr3.value_or(r2); + gtrafo.SetVectorialPart({ r2, 0, 0, 0, r3, 0, 0, 0, r1 }); + gtrafo.SetTranslationPart( { 0.0, 0.0, 0.0 } ); + + BRepBuilderAPI_GTransform gbuilder(sp, gtrafo, true); + PropagateProperties(gbuilder, sp, occ2ng(gtrafo)); + + auto gsp = gbuilder.Shape(); + + gp_Trsf trafo; + trafo.SetTransformation(ax, gp_Ax3()); + BRepBuilderAPI_Transform builder(gsp, trafo, true); + PropagateProperties(builder, gsp, occ2ng(trafo)); + return builder.Shape(); + }, py::arg("axes"), py::arg("r1"), py::arg("r2"), py::arg("r3")=std::nullopt, + "create ellipsoid with local coordinates given by axes, radi 'r1', 'r2', 'r3'"); + m.def("Cylinder", [] (gp_Pnt cpnt, gp_Dir cdir, double r, double h, optional bot, optional top, optional mantle) { @@ -1866,7 +2097,7 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) optional auxspine) { if (twist) { - auto [pnt, angle] = *twist; + // auto [pnt, angle] = *twist; /* cyl = Cylinder((0,0,0), Z, r=1, h=1).faces[0] @@ -1893,14 +2124,19 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) return BRepOffsetAPI_MakePipe (spine, profile).Shape(); }, py::arg("spine"), py::arg("profile"), py::arg("twist")=nullopt, py::arg("auxspine")=nullopt); - m.def("PipeShell", [] (const TopoDS_Wire & spine, const TopoDS_Shape & profile, const TopoDS_Wire & auxspine) { + m.def("PipeShell", [] (const TopoDS_Wire & spine, variant> profile, std::optional auxspine) { try { BRepOffsetAPI_MakePipeShell builder(spine); - builder.SetMode (auxspine, Standard_True); - builder.Add (profile); - // builder.Build(); - // builder.MakeSolid(); + if(auxspine) + builder.SetMode (*auxspine, Standard_True); + if(std::holds_alternative(profile)) + builder.Add (std::get(profile)); + else + { + for(auto s : std::get>(profile)) + builder.Add(s); + } return builder.Shape(); } catch (Standard_Failure & e) @@ -1909,13 +2145,13 @@ DLL_HEADER void ExportNgOCCShapes(py::module &m) e.Print(errstr); throw NgException("cannot create PipeShell: "+errstr.str()); } - }, py::arg("spine"), py::arg("profile"), py::arg("auxspine")); + }, py::arg("spine"), py::arg("profile"), py::arg("auxspine")=nullopt); // Handle(Geom2d_Ellipse) anEllipse1 = new Geom2d_Ellipse(anAx2d, aMajor, aMinor); m.def("Ellipse", [] (const gp_Ax2d & ax, double major, double minor) -> Handle(Geom2d_Curve) { - return new Geom2d_Ellipse(ax, major, minor); + return Handle(Geom2d_Ellipse) (GCE2d_MakeEllipse(ax, major, minor)); }, py::arg("axes"), py::arg("major"), py::arg("minor"), "create 2d ellipse curve"); m.def("Segment", [](gp_Pnt2d p1, gp_Pnt2d p2) -> Handle(Geom2d_Curve) { @@ -2161,7 +2397,7 @@ tangents : Dict[int, gp_Vec2d] TColgp_Array1OfPnt poles(0, vpoles.size()-1); TColStd_Array1OfReal knots(0, vpoles.size()+degree); TColStd_Array1OfInteger mult(0, vpoles.size()+degree); - int cnt = 0; + // int cnt = 0; for (int i = 0; i < vpoles.size(); i++) { @@ -2467,8 +2703,9 @@ degen_tol : double // .def("LineTo", &WorkPlane::LineTo) .def("LineTo", [](WorkPlane&wp, double x, double y, optional name) { return wp.LineTo(x, y, name); }, py::arg("h"), py::arg("v"), py::arg("name")=nullopt, "draw line to position (h,v)") - .def("ArcTo", &WorkPlane::ArcTo) - .def("Arc", &WorkPlane::Arc, py::arg("r"), py::arg("ang"), "draw arc tangential to current pos/dir, of radius 'r' and angle 'ang', draw to the left/right if ang is positive/negative") + .def("ArcTo", &WorkPlane::ArcTo, py::arg("h"), py::arg("v"), + py::arg("t"), py::arg("name")=nullopt) + .def("Arc", &WorkPlane::Arc, py::arg("r"), py::arg("ang"), py::arg("name")=nullopt, "draw arc tangential to current pos/dir, of radius 'r' and angle 'ang', draw to the left/right if ang is positive/negative") .def("Rotate", &WorkPlane::Rotate, py::arg("ang"), "rotate current direction by 'ang' degrees") .def("Line", [](WorkPlane&wp,double l, optional name) { return wp.Line(l, name); }, py::arg("l"), py::arg("name")=nullopt) @@ -2477,15 +2714,18 @@ degen_tol : double .def("Spline", &WorkPlane::Spline, py::arg("points"), py::arg("periodic")=false, py::arg("tol")=1e-8, py::arg("tangents")=std::map{}, py::arg("start_from_localpos")=true, "draw spline (default: starting from current position, which is implicitly added to given list of points), tangents can be specified for each point (0 refers to starting point)") - .def("Rectangle", &WorkPlane::Rectangle, py::arg("l"), py::arg("w"), "draw rectangle, with current position as corner, use current direction") - .def("RectangleC", &WorkPlane::RectangleCentered, py::arg("l"), py::arg("w"), "draw rectangle, with current position as center, use current direction") + .def("Rectangle", &WorkPlane::Rectangle, py::arg("l"), py::arg("w"), py::arg("name")=nullopt, "draw rectangle, with current position as corner, use current direction") + .def("RectangleC", &WorkPlane::RectangleCentered, py::arg("l"), py::arg("w"), py::arg("name")=nullopt, "draw rectangle, with current position as center, use current direction") .def("Circle", [](WorkPlane&wp, double x, double y, double r) { return wp.Circle(x,y,r); }, py::arg("h"), py::arg("v"), py::arg("r"), "draw circle with center (h,v) and radius 'r'") .def("Circle", [](WorkPlane&wp, double r) { return wp.Circle(r); }, py::arg("r"), "draw circle with center in current position") + .def("Ellipse", [](WorkPlane& wp, double major, double minor) + { return wp.Ellipse(major, minor); }, py::arg("major"), py::arg("minor"), "draw ellipse with current position as center") .def("NameVertex", &WorkPlane::NameVertex, py::arg("name"), "name vertex at current position") .def("Offset", &WorkPlane::Offset, py::arg("d"), "replace current wire by offset curve of distance 'd'") .def("Reverse", &WorkPlane::Reverse, "revert orientation of current wire") - .def("Close", &WorkPlane::Close, "draw line to start point of wire, and finish wire") + .def("Close", &WorkPlane::Close, py::arg("name")=nullopt, + "draw line to start point of wire, and finish wire") .def("Finish", &WorkPlane::Finish, "finish current wire without closing") .def("Last", &WorkPlane::Last, "(deprecated) returns current wire") .def("Wire", &WorkPlane::Last, "returns current wire") diff --git a/libsrc/occ/vsocc.cpp b/libsrc/occ/vsocc.cpp index d4631da7..d3b84092 100644 --- a/libsrc/occ/vsocc.cpp +++ b/libsrc/occ/vsocc.cpp @@ -2,6 +2,7 @@ #ifdef OCCGEOMETRY + #include #include #include diff --git a/libsrc/occ/vsocc.hpp b/libsrc/occ/vsocc.hpp index 777028f4..a96e4378 100644 --- a/libsrc/occ/vsocc.hpp +++ b/libsrc/occ/vsocc.hpp @@ -14,7 +14,7 @@ namespace netgen { NgArray trilists; NgArray linelists; - int selsurf; + // int selsurf; class OCCGeometry * occgeometry; public: VisualSceneOCCGeometry (); diff --git a/libsrc/stlgeom/python_stl.cpp b/libsrc/stlgeom/python_stl.cpp index 6bda1953..a56c0eed 100644 --- a/libsrc/stlgeom/python_stl.cpp +++ b/libsrc/stlgeom/python_stl.cpp @@ -188,17 +188,16 @@ NGCORE_API_EXPORT void ExportSTL(py::module & m) { MeshingParameters mp; STLParameters stlparam; - { py::gil_scoped_acquire aq; - if(pars) - { - auto mp_flags = pars->geometrySpecificParameters; - auto mp_kwargs = CreateDictFromFlags(mp_flags); - CreateSTLParametersFromKwargs(stlparam, mp_kwargs); - mp = *pars; - } - CreateSTLParametersFromKwargs(stlparam, kwargs); - CreateMPfromKwargs(mp, kwargs); // this will throw if any kwargs are not passed + if(pars) + { + auto mp_flags = pars->geometrySpecificParameters; + auto mp_kwargs = CreateDictFromFlags(mp_flags); + CreateSTLParametersFromKwargs(stlparam, mp_kwargs); + mp = *pars; } + CreateSTLParametersFromKwargs(stlparam, kwargs); + CreateMPfromKwargs(mp, kwargs); // this will throw if any kwargs are not passed + py::gil_scoped_release gil_release; if(!mesh) { mesh = make_shared(); @@ -215,7 +214,6 @@ NGCORE_API_EXPORT void ExportSTL(py::module & m) return mesh; }, py::arg("mp") = nullptr, py::arg("mesh") = nullptr, - py::call_guard(), (meshingparameter_description + stlparameter_description).c_str()) .def("Draw", FunctionPointer ([] (shared_ptr self) @@ -223,6 +221,65 @@ NGCORE_API_EXPORT void ExportSTL(py::module & m) ng_geometry = self; }) ) + .def("GetVicinity", [] (shared_ptr self, int node, int size, string type) { + NgArray vic; + + int trig=-1; + if(type == "trig") + trig = node; + + if(type == "point") + trig = self->TrigPerPoint(node, 1); + + self->GetVicinity(trig, size, vic); + auto geo = make_shared(); + NgArray trigs; + + for(auto i : Range(vic.Size())) { + int trigi = vic[i]; + STLReadTriangle t; + Vec<3> normal = self->GetTriangle(trigi).Normal(); + Point<3> pts[3]; + auto trig = self->GetTriangle(trigi); + for(auto pi : Range(3)) + pts[pi] = self->GetPoint(trig[pi]); + trigs.Append(STLReadTriangle(pts, normal)); + } + + geo->SetSurfaceSTL(true); + geo->InitSTLGeometry(trigs); + return geo; + }, py::arg("node"), py::arg("size"), py::arg("node_type") = "trig") + .def("SmoothDirtyTrigs", [] (shared_ptr self, py::kwargs kwargs) { + STLParameters stlparam; + CreateSTLParametersFromKwargs(stlparam, kwargs); + self->SmoothDirtyTrigs(stlparam); + }) + .def("GetDirtyTrigs", [] (shared_ptr self, py::kwargs kwargs) { + STLParameters stlparam; + CreateSTLParametersFromKwargs(stlparam, kwargs); + self->MarkDirtyTrigs(stlparam); + py::list dirty; + for(auto i : Range(self->GetNT())) + if(self->IsMarkedTrig(i+1)) + dirty.append(i); + }) + .def("MovePointToMiddle", [] (shared_ptr self, int node, int count) { + auto trignr = self->TrigPerPoint(node, 1); + auto trig = self->GetTriangle(trignr); + int point_in_trig = -1; + for(auto i : Range(3)) + if(trig[i] == node) + point_in_trig = i; + + if(point_in_trig == -1) + throw Exception("Point not found in triangle"); + self->SetSelectTrig(trignr); + self->SetNodeOfSelTrig(point_in_trig); + for([[maybe_unused]] auto i : Range(count)) + self->MoveSelectedPointToMiddle(); + }) + .def("Save", &STLGeometry::Save) ; m.def("LoadSTLGeometry", [] (const string & filename) { diff --git a/libsrc/stlgeom/stlgeom.cpp b/libsrc/stlgeom/stlgeom.cpp index 0a8496e8..f02495fd 100644 --- a/libsrc/stlgeom/stlgeom.cpp +++ b/libsrc/stlgeom/stlgeom.cpp @@ -536,7 +536,7 @@ void STLGeometry :: SmoothNormals(const STLParameters& stlparam) area2 += area; } - } + } (*testout) << "area1 = " << area1 << " area2 = " << area2 << endl; if (area1 < 0.1 * area2) @@ -2630,10 +2630,10 @@ void STLGeometry :: FindEdgesFromAngles(const STLParameters& stlparam) if (stlparam.contyangle < stlparam.yangle) { int changed = 1; - int its = 0; + [[maybe_unused]] int its = 0; while (changed && stlparam.contyangle < stlparam.yangle) { - its++; + its++; //(*mycout) << "." << flush; changed = 0; for (int i = 1; i <= edgedata->Size(); i++) @@ -3659,7 +3659,7 @@ void STLGeometry :: WriteChartToFile( ChartId chartnumber, filesystem::path file pts[k] = GetPoint(trig[k]); box.Add(pts[k]); } - Vec3d normal = Cross( pts[1]-pts[0], pts[2]-pts[0] ); + // Vec3d normal = Cross( pts[1]-pts[0], pts[2]-pts[0] ); readtrigs.Append(STLReadTriangle(pts, trig.Normal())); } auto dist = box.PMax() - box.PMin(); @@ -3756,5 +3756,5 @@ void STLGeometry :: WriteChartToFile( ChartId chartnumber, filesystem::path file STLInit stlinit; -static RegisterClassForArchive stlgeo; +static RegisterClassForArchive> stlgeo; } diff --git a/libsrc/stlgeom/stlgeomchart.cpp b/libsrc/stlgeom/stlgeomchart.cpp index a3a22f89..e4bceffe 100644 --- a/libsrc/stlgeom/stlgeomchart.cpp +++ b/libsrc/stlgeom/stlgeomchart.cpp @@ -749,7 +749,7 @@ void STLGeometry :: GetDirtyChartTrigs(int chartnum, STLChart& chart, dirtytrigs.SetSize(0); - int cnt = 0; + // int cnt = 0; for (int j = 1; j <= chart.GetNChartT(); j++) { @@ -766,13 +766,13 @@ void STLGeometry :: GetDirtyChartTrigs(int chartnum, STLChart& chart, if (!IsEdge(np1,np2)) { dirtytrigs.Append(j); //local numbers!!! - cnt++; + // cnt++; break; //only once per trig!!! } } } } - cnt = 0; + // cnt = 0; STLPointId ap1, ap2, pn; Array trigsaroundp; @@ -832,7 +832,7 @@ void STLGeometry :: GetDirtyChartTrigs(int chartnum, STLChart& chart, if (problem && !dirtytrigs.Contains(j)) { dirtytrigs.Append(j); - cnt++; + // cnt++; break; //only once per triangle } } diff --git a/libsrc/stlgeom/stlgeommesh.cpp b/libsrc/stlgeom/stlgeommesh.cpp index 00e38724..67b1598d 100644 --- a/libsrc/stlgeom/stlgeommesh.cpp +++ b/libsrc/stlgeom/stlgeommesh.cpp @@ -536,11 +536,11 @@ int STLGeometry :: Project(Point<3> & p3d) const { Point<3> p, pf; - int j; + // int j; int fi = 0; - int cnt = 0; + // int cnt = 0; int different = 0; - const double lamtol = 1e-6; + // const double lamtol = 1e-6; const STLChart& chart = GetChart(meshchart); diff --git a/libsrc/stlgeom/stlpkg.cpp b/libsrc/stlgeom/stlpkg.cpp index 6ca94118..7dc7b3ab 100644 --- a/libsrc/stlgeom/stlpkg.cpp +++ b/libsrc/stlgeom/stlpkg.cpp @@ -1,4 +1,5 @@ #include + #include #include #include @@ -6,7 +7,11 @@ #include + #include + + + #include #include diff --git a/libsrc/stlgeom/stltool.cpp b/libsrc/stlgeom/stltool.cpp index d2377cb1..98dcfdc0 100644 --- a/libsrc/stlgeom/stltool.cpp +++ b/libsrc/stlgeom/stltool.cpp @@ -1172,7 +1172,7 @@ bool STLBoundary :: TestSeg(const Point<3>& p1, const Point<3> & p2, const Vec<3 } #endif - int i,j,k; + int i,k; Point<3> seg1p/*, seg2p*/; Point<3> sp1,sp2; double lambda1, lambda2, vlen2; @@ -1369,7 +1369,7 @@ bool STLBoundary :: TestSegChartNV(const Point3d & p1, const Point3d& p2, Line2d l2 (sp1, sp2); double lam1, lam2; - int err = CrossPointBarycentric (l1, l2, lam1, lam2); + int err = CrossPointBarycentric (l1, l2, lam1, lam2, eps); bool in1 = (lam1 > eps) && (lam1 < 1-eps); bool on1 = (lam1 > -eps) && (lam1 < 1 + eps); bool in2 = (lam2 > eps) && (lam2 < 1-eps); diff --git a/libsrc/stlgeom/stltool.hpp b/libsrc/stlgeom/stltool.hpp index e3e57385..dc654815 100644 --- a/libsrc/stlgeom/stltool.hpp +++ b/libsrc/stlgeom/stltool.hpp @@ -190,13 +190,13 @@ private: STLGeometry * geometry; const STLChart * chart; // NgArray boundary; - ClosedHashTable boundary_ht; + NgClosedHashTable boundary_ht; unique_ptr> searchtree; public: STLBoundary(STLGeometry * ageometry); ~STLBoundary() {} - void Clear() { /* boundary.SetSize(0); */ boundary_ht = ClosedHashTable(); } + void Clear() { /* boundary.SetSize(0); */ boundary_ht = NgClosedHashTable(); } void SetChart (const STLChart * achart) { chart = achart; } //don't check, if already exists! // void AddNewSegment(const STLBoundarySeg & seg) {boundary.Append(seg);}; diff --git a/libsrc/stlgeom/stltopology.cpp b/libsrc/stlgeom/stltopology.cpp index 2ef61885..55d17bad 100644 --- a/libsrc/stlgeom/stltopology.cpp +++ b/libsrc/stlgeom/stltopology.cpp @@ -353,7 +353,7 @@ STLGeometry * STLTopology ::Load (istream & ist, bool surface) if(std::isblank(buf[istart])==0) break; - for (auto i : Range(buflen)) + for ([[maybe_unused]] auto i : Range(buflen)) ist.unget(); // does not start with "solid" -> binary file @@ -374,7 +374,7 @@ STLGeometry * STLTopology ::Load (istream & ist, bool surface) Point<3> pts[3]; Vec<3> normal; - int cntface = 0; + [[maybe_unused]] int cntface = 0; int vertex = 0; bool badnormals = false; ist >> buf; // skip first line diff --git a/libsrc/stlgeom/stltopology.hpp b/libsrc/stlgeom/stltopology.hpp index a14dc5bd..ac16a28d 100644 --- a/libsrc/stlgeom/stltopology.hpp +++ b/libsrc/stlgeom/stltopology.hpp @@ -327,6 +327,7 @@ public: void SaveSTLE (const filesystem::path & filename) const; // stores trigs and edges bool IsSurfaceSTL() const { return surface; } + void SetSurfaceSTL( bool surface_ ) { surface = surface_; } virtual void DoArchive(Archive& ar) { diff --git a/libsrc/visualization/CMakeLists.txt b/libsrc/visualization/CMakeLists.txt index d1b8b184..1e7a2938 100644 --- a/libsrc/visualization/CMakeLists.txt +++ b/libsrc/visualization/CMakeLists.txt @@ -7,7 +7,7 @@ target_sources(nggui PRIVATE vssolution.cpp visualpkg.cpp ) -target_link_libraries( nggui PUBLIC "$" ${MPI_CXX_LIBRARIES} ${OPENGL_LIBRARIES} nglib) +target_link_libraries( nggui PUBLIC "$" ${OPENGL_LIBRARIES} nglib) install(FILES meshdoc.hpp mvdraw.hpp visual_api.hpp diff --git a/libsrc/visualization/meshdoc.cpp b/libsrc/visualization/meshdoc.cpp index d0993272..1a2fb5c5 100644 --- a/libsrc/visualization/meshdoc.cpp +++ b/libsrc/visualization/meshdoc.cpp @@ -94,7 +94,7 @@ void VisualSceneMeshDoctor :: DrawScene () glPopName(); - if (selpoint > 0 && selpoint <= mesh->GetNP()) + if (selpoint-IndexBASE() >= 0 && selpoint-IndexBASE() < mesh->GetNP()) { GLfloat matcolblue[] = { 0, 0, 1, 1 }; @@ -376,8 +376,8 @@ void VisualSceneMeshDoctor :: BuildScene (int zoomall) const Point3d & p1 = mesh->Point(seg[0]); const Point3d & p2 = mesh->Point(seg[1]); - if (edgedist.Get(seg[0]) <= markedgedist && - edgedist.Get(seg[1]) <= markedgedist) + if (edgedist[seg[0]] <= markedgedist && + edgedist[seg[1]] <= markedgedist) { glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, matcolseledge); @@ -518,8 +518,7 @@ void VisualSceneMeshDoctor :: UpdateTables () edgedist.SetSize(mesh->GetNP()); int i, changed; - for (i = 1; i <= mesh->GetNP(); i++) - edgedist.Elem(i) = 10000; + edgedist = 10000; for (i = 1; i <= mesh->GetNSeg(); i++) { @@ -527,8 +526,8 @@ void VisualSceneMeshDoctor :: UpdateTables () if ( (seg[0] == selpoint && seg[1] == selpoint2) || (seg[1] == selpoint && seg[0] == selpoint2) ) { - edgedist.Elem(selpoint) = 1; - edgedist.Elem(selpoint2) = 1; + edgedist[selpoint] = 1; + edgedist[selpoint2] = 1; } } @@ -540,17 +539,17 @@ void VisualSceneMeshDoctor :: UpdateTables () { const Segment & seg = mesh->LineSegment(i); - int edist = min2 (edgedist.Get(seg[0]), edgedist.Get(seg[1])); + int edist = min2 (edgedist[seg[0]], edgedist[seg[1]]); edist++; - if (edgedist.Get(seg[0]) > edist) + if (edgedist[seg[0]] > edist) { - edgedist.Elem(seg[0]) = edist; + edgedist[seg[0]] = edist; changed = 1; } - if (edgedist.Get(seg[1]) > edist) + if (edgedist[seg[1]] > edist) { - edgedist.Elem(seg[1]) = edist; + edgedist[seg[1]] = edist; changed = 1; } } @@ -561,8 +560,8 @@ void VisualSceneMeshDoctor :: UpdateTables () int VisualSceneMeshDoctor :: IsSegmentMarked (int segnr) const { const Segment & seg = mesh->LineSegment(segnr); - return (edgedist.Get(seg[0]) <= markedgedist && - edgedist.Get(seg[1]) <= markedgedist); + return (edgedist[seg[0]] <= markedgedist && + edgedist[seg[1]] <= markedgedist); } } diff --git a/libsrc/visualization/meshdoc.hpp b/libsrc/visualization/meshdoc.hpp index 7fce2772..9e3bd9de 100644 --- a/libsrc/visualization/meshdoc.hpp +++ b/libsrc/visualization/meshdoc.hpp @@ -9,10 +9,10 @@ class VisualSceneMeshDoctor : public VisualScene int edgelist; int selelement, locpi; - int selpoint, selpoint2; + PointIndex selpoint, selpoint2; // for edgemarking: - NgArray edgedist; + Array edgedist; int markedgedist; diff --git a/libsrc/visualization/mvdraw.cpp b/libsrc/visualization/mvdraw.cpp index b6f70627..250eacd6 100644 --- a/libsrc/visualization/mvdraw.cpp +++ b/libsrc/visualization/mvdraw.cpp @@ -57,6 +57,13 @@ namespace netgen return opengl_text_width; } + void MyOpenGLLines(FlatArray> points) + { + glBegin(GL_LINES); + for (auto p : points) + glVertex3dv(&p[0]); + glEnd(); + } // texture for color decoding // GLubyte * VisualScene :: colortexture = NULL; @@ -497,7 +504,8 @@ namespace netgen { ntexcols = ncols; - GLubyte colortexture[4*32]; + ArrayMem colortexture; + colortexture.SetSize(4*ncols); const double colp[][3] = { @@ -532,8 +540,8 @@ namespace netgen // glPixelStorei (GL_UNPACK_ALIGNMENT, 1); - glTexImage1D (GL_TEXTURE_1D, 0, 4, ncols, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture); - glTexImage2D (GL_TEXTURE_2D, 0, 4, ncols, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture); + glTexImage1D (GL_TEXTURE_1D, 0, 4, ncols, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture.Data()); + glTexImage2D (GL_TEXTURE_2D, 0, 4, ncols, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, colortexture.Data()); glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, typ); // DECAL or MODULATE @@ -950,7 +958,7 @@ namespace netgen // glEnable (GL_LIGHTING); double shine = vispar.shininess; - double transp = vispar.transp; + // double transp = vispar.transp; glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, shine); glLogicOp (GL_COPY); diff --git a/libsrc/visualization/mvdraw.hpp b/libsrc/visualization/mvdraw.hpp index e750edb1..201572a5 100644 --- a/libsrc/visualization/mvdraw.hpp +++ b/libsrc/visualization/mvdraw.hpp @@ -90,6 +90,7 @@ namespace netgen NGGUI_API extern void Set_OpenGLText_Callback ( void (*fun) (const char * text), int width ); NGGUI_API extern VisualScene visual_scene_cross; NGGUI_API extern VisualScene *visual_scene; + NGGUI_API extern void MyOpenGLLines (FlatArray> points); @@ -145,16 +146,16 @@ namespace netgen int filledtimestamp = -1; int linetimestamp = -1; int edgetimestamp = -1; - int pointnumbertimestamp = -1; + // int pointnumbertimestamp = -1; int tettimestamp = -1; int prismtimestamp = -1; int pyramidtimestamp = -1; int hextimestamp = -1; - int badeltimestamp = -1; - int identifiedtimestamp = -1; - int domainsurftimestamp = -1; + // int badeltimestamp = -1; + // int identifiedtimestamp = -1; + // int domainsurftimestamp = -1; struct { unsigned texture = -1; @@ -228,10 +229,10 @@ namespace netgen void BuildEdgeList(); void BuildPointNumberList(); - void BuildTetList(); - void BuildPrismList(); - void BuildPyramidList(); - void BuildHexList(); + void BuildTetList(const BitArray & shownode); + void BuildPrismList(const BitArray & shownode); + void BuildPyramidList(const BitArray & shownode); + void BuildHexList(const BitArray & shownode); void BuildBadelList(); void BuildIdentifiedList(); @@ -239,7 +240,7 @@ namespace netgen bool SelectSurfaceElement (int px, int py, Point<3> &p, bool select_on_clipping_plane); bool Unproject(int px, int py, Point<3> &p); - ngcore::INT<2> Project(Point<3> p); + ngcore::IVec<2> Project(Point<3> p); }; NGGUI_API extern VisualSceneMesh vsmesh; diff --git a/libsrc/visualization/vispar.hpp b/libsrc/visualization/vispar.hpp index 93d4425d..de2e3ccc 100644 --- a/libsrc/visualization/vispar.hpp +++ b/libsrc/visualization/vispar.hpp @@ -58,6 +58,8 @@ public: int drawedgenumbers; int drawfacenumbers; int drawelementnumbers; + int drawsurfaceelementnumbers; + int drawsegmentnumbers; int drawdomainsurf; int drawtets; int drawtetsdomain; diff --git a/libsrc/visualization/visual.hpp b/libsrc/visualization/visual.hpp index 94dcf87d..83425fa4 100644 --- a/libsrc/visualization/visual.hpp +++ b/libsrc/visualization/visual.hpp @@ -13,10 +13,6 @@ Visualization */ -// #ifdef PARALLEL -// #define PARALLELGL -// #endif - #include "visual_api.hpp" #include "../include/incopengl.hpp" diff --git a/libsrc/visualization/visualpkg.cpp b/libsrc/visualization/visualpkg.cpp index 11881159..21d4668e 100644 --- a/libsrc/visualization/visualpkg.cpp +++ b/libsrc/visualization/visualpkg.cpp @@ -1,6 +1,5 @@ #include // #include -#include #include @@ -8,7 +7,7 @@ #include #include - +#include // #include #include diff --git a/libsrc/visualization/vsmesh.cpp b/libsrc/visualization/vsmesh.cpp index c63a8e0a..392cd0d8 100644 --- a/libsrc/visualization/vsmesh.cpp +++ b/libsrc/visualization/vsmesh.cpp @@ -134,27 +134,46 @@ namespace netgen if (vispar.drawbadels) glCallList (badellist); + BitArray shownode(mesh->GetNP()+1); + if (vispar.clipping.enable) + { + shownode.Clear(); + for (PointIndex pi : mesh->Points().Range()) + { + Point<3> p = (*mesh)[pi]; + + double val = + p[0] * clipplane[0] + + p[1] * clipplane[1] + + p[2] * clipplane[2] + + clipplane[3]; + + if (val > 0) shownode.SetBit (pi); + } + } + else + shownode.Set(); if (vispar.drawprisms) { - BuildPrismList (); + BuildPrismList (shownode); glCallList (prismlist); } if (vispar.drawpyramids) { - BuildPyramidList (); + BuildPyramidList (shownode); glCallList (pyramidlist); } if (vispar.drawhexes) { - BuildHexList (); + BuildHexList (shownode); glCallList (hexlist); } if (vispar.drawtets) { - BuildTetList (); + BuildTetList (shownode); glCallList (tetlist); } @@ -209,6 +228,8 @@ namespace netgen if (vispar.drawpointnumbers || vispar.drawedgenumbers || vispar.drawfacenumbers || + vispar.drawsegmentnumbers || + vispar.drawsurfaceelementnumbers || vispar.drawelementnumbers) glCallList (pointnumberlist); @@ -245,7 +266,7 @@ namespace netgen } - catch (bad_weak_ptr e) + catch (const bad_weak_ptr & e) { // cout << "don't have a mesh to visualize" << endl; VisualScene::DrawScene(); @@ -271,11 +292,11 @@ namespace netgen center.Y() = vispar.centery; center.Z() = vispar.centerz; } - else if (selpoint >= 1 && zoomall==2) + else if (selpoint-IndexBASE() >= 1 && zoomall==2) center = mesh->Point (selpoint); else if (marker && zoomall==2) center = *marker; - else if (vispar.centerpoint >= 1 && zoomall==2) + else if (vispar.centerpoint-IndexBASE() >= 0 && zoomall==2) center = mesh->Point (vispar.centerpoint); else center = Center (pmin, pmax); @@ -366,6 +387,8 @@ namespace netgen if (vispar.drawpointnumbers || vispar.drawedgenumbers || vispar.drawfacenumbers || + vispar.drawsegmentnumbers || + vispar.drawsurfaceelementnumbers || vispar.drawelementnumbers) { // glEnable (GL_COLOR_MATERIAL); @@ -411,8 +434,9 @@ namespace netgen const MeshTopology & top = mesh->GetTopology(); for (int i = 1; i <= top.GetNEdges(); i++) { - int v1, v2; - top.GetEdgeVertices (i, v1, v2); + // int v1, v2; + // top.GetEdgeVertices (i, v1, v2); + auto [v1,v2] = top.GetEdgeVertices(i-1); const Point3d & p1 = mesh->Point(v1); const Point3d & p2 = mesh->Point(v2); const Point3d p = Center (p1, p2); @@ -426,8 +450,18 @@ namespace netgen } + if (vispar.drawsegmentnumbers) + { + for (auto si : Range(mesh->LineSegments())) { + const auto& seg = (*mesh)[si]; + Point<3> c = Center((*mesh)[seg[0]], (*mesh)[seg[1]]); + glRasterPos3d (c[0], c[1], c[2]); + snprintf (buf, size(buf), "%d", int(si)); + MyOpenGLText (buf); + } + } - if (vispar.drawfacenumbers) + if (vispar.drawfacenumbers) { const MeshTopology & top = mesh->GetTopology(); NgArray v; @@ -438,7 +472,7 @@ namespace netgen const Point3d & p2 = mesh->Point(v.Elem(2)); const Point3d & p3 = mesh->Point(v.Elem(3)); Point3d p; - if (v.Elem(4) == 0) + if (v.Size() == 3) { p = Center (p1, p2, p3); } @@ -457,25 +491,45 @@ namespace netgen } } + if (vispar.drawsurfaceelementnumbers) + { + for (auto sei : Range(mesh->SurfaceElements())) + { + const auto & sel = (*mesh)[sei]; + Point<3> c; + if(sel.GetNV() == 3) + c = Center((*mesh)[sel[0]], + (*mesh)[sel[1]], + (*mesh)[sel[2]]); + else + c = Center((*mesh)[sel[0]], + (*mesh)[sel[1]], + (*mesh)[sel[2]], + (*mesh)[sel[3]]); + glRasterPos3d (c[0], c[1], c[2]); + snprintf (buf, size(buf), "%d", int(sei)); + MyOpenGLText (buf); + } + } - - if (vispar.drawelementnumbers) + if (vispar.drawelementnumbers) { NgArray v; - for (int i = 1; i <= mesh->GetNE(); i++) + // for (int i = 1; i <= mesh->GetNE(); i++) + for (ElementIndex ei : Range(mesh->VolumeElements())) { // const ELEMENTTYPE & eltype = mesh->ElementType(i); NgArray pnums; Point3d p; - const Element & el = mesh->VolumeElement (i); + const Element & el = mesh->VolumeElement (ei); if ( ! el.PNum(5)) // eltype == TET ) { pnums.SetSize(4); for( int j = 0; j < pnums.Size(); j++) - pnums[j] = mesh->VolumeElement(i).PNum(j+1); + pnums[j] = mesh->VolumeElement(ei).PNum(j+1); const Point3d & p1 = mesh->Point(pnums[0]); @@ -488,7 +542,7 @@ namespace netgen { pnums.SetSize(5); for( int j = 0; j < pnums.Size(); j++) - pnums[j] = mesh->VolumeElement(i).PNum(j+1); + pnums[j] = mesh->VolumeElement(ei).PNum(j+1); const Point3d & p1 = mesh->Point(pnums[0]); @@ -506,7 +560,7 @@ namespace netgen { pnums.SetSize(6); for( int j = 0; j < pnums.Size(); j++) - pnums[j] = mesh->VolumeElement(i).PNum(j+1); + pnums[j] = mesh->VolumeElement(ei).PNum(j+1); const Point3d & p1 = mesh->Point(pnums[0]); const Point3d & p2 = mesh->Point(pnums[1]); @@ -521,7 +575,7 @@ namespace netgen { pnums.SetSize(8); for( int j = 0; j < pnums.Size(); j++) - pnums[j] = mesh->VolumeElement(i).PNum(j+1); + pnums[j] = mesh->VolumeElement(ei).PNum(j+1); const Point3d & p1 = mesh->Point(pnums[0]); const Point3d & p2 = mesh->Point(pnums[1]); @@ -536,7 +590,7 @@ namespace netgen } glRasterPos3d (p.X(), p.Y(), p.Z()); - snprintf (buf, size(buf), "%d", i); + snprintf (buf, size(buf), "%d", ei-IndexBASE(ei)); // glCallLists (strlen (buf), GL_UNSIGNED_BYTE, buf); MyOpenGLText (buf); @@ -564,14 +618,15 @@ namespace netgen static float badelcol[] = { 1.0f, 0.0f, 1.0f, 1.0f }; glLineWidth (1.0f); - for (int i = 1; i <= mesh->GetNE(); i++) + //for (int i = 1; i <= mesh->GetNE(); i++) + for (ElementIndex ei : Range(mesh->VolumeElements())) { - if (mesh->VolumeElement(i).Flags().badel || - mesh->VolumeElement(i).Flags().illegal || - (i == vispar.drawelement)) + if (mesh->VolumeElement(ei).Flags().badel || + mesh->VolumeElement(ei).Flags().illegal || + (ei-IndexBASE(ei) == vispar.drawelement)) { // copy to be thread-safe - Element el = mesh->VolumeElement (i); + Element el = mesh->VolumeElement (ei); el.GetSurfaceTriangles (faces); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, badelcol); @@ -621,9 +676,9 @@ namespace netgen } - for (int i = 1; i <= mesh->GetNE(); i++) + for (ElementIndex ei : Range(mesh->VolumeElements())) { - Element el = mesh->VolumeElement (i); + Element el = mesh->VolumeElement (ei); int hascp = 0; for (int j = 1; j <= el.GetNP(); j++) if (el.PNum(j) == vispar.centerpoint) @@ -631,7 +686,7 @@ namespace netgen if (hascp) { - (*testout) << "draw el " << i << " : "; + (*testout) << "draw el " << ei << " : "; for (int j = 1; j <= el.GetNP(); j++) (*testout) << el.PNum(j) << " "; (*testout) << endl; @@ -798,37 +853,42 @@ namespace netgen GLfloat identifiedcol[] = { 1, 0, 1, 1 }; glLineWidth (3); - - // for (i = 1; i <= mesh->GetNSeg(); i++) + glEnable (GL_COLOR_MATERIAL); + glDisable (GL_LIGHTING); if (mesh -> HasIdentifications() ) { - // if (mesh->GetIdentifications().HasIdentifiedPoints()) { - INDEX_2_HASHTABLE & idpts = + auto & idpts = mesh->GetIdentifications().GetIdentifiedPoints(); - - for (int i = 1; i <= idpts.GetNBags(); i++) - for (int j = 1; j <= idpts.GetBagSize(i); j++) - { - INDEX_2 pts; - int val; - - idpts.GetData (i, j, pts, val); - const Point3d & p1 = mesh->Point(pts.I1()); - const Point3d & p2 = mesh->Point(pts.I2()); + for (auto [hash, val] : idpts) + { + auto [hash_pts, hash_nr] = hash; + auto [pi1, pi2] = hash_pts; + // val = pts[2]; + Point<3> p1 = mesh->Point(pi1); + Point<3> p2 = mesh->Point(pi2); + Point<3> c = Center(p1, p2); + if (vispar.shrink < 1) + { + p1 = c + vispar.shrink * (p1 - c); + p2 = c + vispar.shrink * (p2 - c); + } + glColor3fv (identifiedcol); glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, identifiedcol); glBegin (GL_LINES); - glVertex3f (p1.X(), p1.Y(), p1.Z()); - glVertex3f (p2.X(), p2.Y(), p2.Z()); + glVertex3dv(p1); + glVertex3dv(p2); glEnd(); } } } + glDisable (GL_COLOR_MATERIAL); + glEnable (GL_LIGHTING); glEndList (); } @@ -841,7 +901,7 @@ namespace netgen vstimestamp = meshtimestamp; } - catch (bad_weak_ptr e) + catch (const bad_weak_ptr & e) { PrintMessage (3, "vsmesh::buildscene: don't have a mesh to visualize"); VisualScene::BuildScene (zoomall); @@ -870,9 +930,9 @@ namespace netgen data.Append(cf); } int n = data.Size()/4; - colors.width = min2(n, 1024); + colors.width = max2(1,min2(n, 1024)); colors.height = (n+colors.width-1)/colors.width; - for(auto i: Range(n, colors.width*colors.height)) + for([[maybe_unused]] auto i: Range(n, colors.width*colors.height)) data.Append({0.0f, 0.0f, 0.0f, 0.0f}); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, colors.width, colors.height, 0, GL_RGBA, GL_FLOAT, data.Data()); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); @@ -928,7 +988,7 @@ namespace netgen timestamp = NextTimeStamp(); - if(!build_select && !vispar.colormeshsize && colors.texture==-1) + if(!build_select && !vispar.colormeshsize) BuildColorTexture(); if (list) @@ -985,8 +1045,8 @@ namespace netgen glBindTexture(GL_TEXTURE_2D, colors.texture); } - GLfloat matcol[] = { 0, 1, 0, 1 }; - GLfloat matcolsel[] = { 1, 0, 0, 1 }; + // GLfloat matcol[] = { 0, 1, 0, 1 }; + // GLfloat matcolsel[] = { 1, 0, 0, 1 }; GLint rendermode; glGetIntegerv (GL_RENDER_MODE, &rendermode); @@ -1020,7 +1080,7 @@ namespace netgen SurfaceElementIndex sei = seia[hi]; const Element2d & el = (*mesh)[sei]; - bool drawel = (!el.IsDeleted() & el.IsVisible()); + bool drawel = (!el.IsDeleted() && el.IsVisible()); #ifdef STLGEOM if (checkvicinity) @@ -1363,7 +1423,7 @@ namespace netgen { const Element2d & el = (*mesh)[sei]; - bool drawel = (!el.IsDeleted() & el.IsVisible()); + bool drawel = (!el.IsDeleted() && el.IsVisible()); #ifdef STLGEOM if (checkvicinity) @@ -1755,7 +1815,7 @@ namespace netgen - void VisualSceneMesh :: BuildTetList() + void VisualSceneMesh :: BuildTetList(const BitArray & shownode) { shared_ptr mesh = GetMesh(); @@ -1810,27 +1870,6 @@ namespace netgen NgArray faces; - NgBitArray shownode(mesh->GetNP()); - if (vispar.clipping.enable) - { - shownode.Clear(); - for (int i = 1; i <= shownode.Size(); i++) - { - Point<3> p = mesh->Point(i); - - double val = - p[0] * clipplane[0] + - p[1] * clipplane[1] + - p[2] * clipplane[2] + - clipplane[3]; - - if (val > 0) shownode.Set (i); - } - } - else - shownode.Set(); - - static float tetcols[][4] = { { 1.0f, 1.0f, 0.0f, 1.0f }, @@ -1873,12 +1912,11 @@ namespace netgen if ((el.GetType() == TET || el.GetType() == TET10) && !el.IsDeleted()) { - - bool drawtet = 1; - for (int j = 0; j < 4; j++) - if (!shownode.Test(el[j])) - drawtet = 0; - if (!drawtet) continue; + bool visible = true; + for (auto pi: el.PNums()) + if (!shownode[pi]) + visible = false; + if(!visible) continue; int ind = el.GetIndex() % 4; @@ -2107,7 +2145,7 @@ namespace netgen - void VisualSceneMesh :: BuildPrismList() + void VisualSceneMesh :: BuildPrismList(const BitArray & shownode) { shared_ptr mesh = GetMesh(); @@ -2145,6 +2183,12 @@ namespace netgen const Element & el = (*mesh)[ei]; if (el.GetType() == PRISM && !el.IsDeleted()) { + bool visible = true; + for (auto pi: el.PNums()) + if (!shownode[pi]) + visible = false; + if(!visible) continue; + int j; int i = ei + 1; @@ -2438,7 +2482,7 @@ namespace netgen - void VisualSceneMesh :: BuildHexList() + void VisualSceneMesh :: BuildHexList(const BitArray & shownode) { shared_ptr mesh = GetMesh(); @@ -2473,6 +2517,11 @@ namespace netgen const Element & el = (*mesh)[ei]; if (el.GetType() == HEX && !el.IsDeleted()) { + bool visible = true; + for (auto pi: el.PNums()) + if (!shownode[pi]) + visible = false; + if(!visible) continue; CurvedElements & curv = mesh->GetCurvedElements(); if (curv.IsHighOrder()) // && curv.IsElementCurved(ei)) { @@ -2638,6 +2687,121 @@ namespace netgen } } } + + static float hex7col[] = { 1.0f, 0.65f, 0.0f, 1.0f }; + glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, hex7col); + + for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++) + { + const Element & el = (*mesh)[ei]; + if (el.GetType() == HEX7 && !el.IsDeleted()) + { + /* + CurvedElements & curv = mesh->GetCurvedElements(); + if (curv.IsHighOrder()) + { + const ELEMENT_FACE * faces = MeshTopology :: GetFaces1 (HEX); + const Point3d * vertices = MeshTopology :: GetVertices (HEX); + + Point<3> grid[11][11]; + Point<3> fpts[4]; + int order = subdivisions+1; + + for (int quad = 0; quad<6; quad++) + { + for (int j = 0; j < 4; j++) + fpts[j] = vertices[faces[quad][j]-1]; + + static Point<3> c(0.5, 0.5, 0.5); + if (vispar.shrink < 1) + for (int j = 0; j < 4; j++) + fpts[j] += (1-vispar.shrink) * (c-fpts[j]); + + for (int ix = 0; ix <= order; ix++) + for (int iy = 0; iy <= order; iy++) + { + double lami[4] = + { (1-double(ix)/order) * (1-double(iy)/order), + ( double(ix)/order) * (1-double(iy)/order), + ( double(ix)/order) * ( double(iy)/order), + (1-double(ix)/order) * ( double(iy)/order) }; + + Point<3> xl; + for (int l = 0; l < 3; l++) + xl(l) = lami[0] * fpts[0](l) + lami[1] * fpts[1](l) + + lami[2] * fpts[2](l) + lami[3] * fpts[3](l); + + curv.CalcElementTransformation (xl, ei, grid[ix][iy]); + } + + for (int j = 0; j <= order; j++) + ToBernstein (order, &grid[j][0], &grid[0][1]-&grid[0][0]); + for (int j = 0; j <= order; j++) + ToBernstein (order, &grid[0][j], &grid[1][0]-&grid[0][0]); + + glMap2d(GL_MAP2_VERTEX_3, + 0.0, 1.0, &grid[0][1](0)-&grid[0][0](0), order+1, + 0.0, 1.0, &grid[1][0](0)-&grid[0][0](0), order+1, + &grid[0][0](0)); + glEnable(GL_MAP2_VERTEX_3); + glEnable(GL_AUTO_NORMAL); + + glMapGrid2f(8, 0.0, 1.0, 8, 0.0, 1.0); + glEvalMesh2(GL_FILL, 0, 8, 0, 8); + + glDisable (GL_AUTO_NORMAL); + glDisable (GL_MAP2_VERTEX_3); + } + } + else + */ + { + Point3d c(0,0,0); + if (vispar.shrink < 1) + { + for (int j = 1; j <= 7; j++) + { + Point3d p = mesh->Point(el.PNum(j)); + c.X() += p.X(); + c.Y() += p.Y(); + c.Z() += p.Z(); + } + c.X() /= 7; + c.Y() /= 7; + c.Z() /= 7; + } + + glBegin (GL_TRIANGLES); + + el.GetSurfaceTriangles (faces); + for (int j = 1; j <= faces.Size(); j++) + { + Element2d & face = faces.Elem(j); + Point<3> lp1 = mesh->Point (el.PNum(face.PNum(1))); + Point<3> lp2 = mesh->Point (el.PNum(face.PNum(2))); + Point<3> lp3 = mesh->Point (el.PNum(face.PNum(3))); + Vec<3> n = Cross (lp3-lp1, lp2-lp1); + n.Normalize(); + glNormal3dv (n); + + if (vispar.shrink < 1) + { + lp1 = c + vispar.shrink * (lp1 - c); + lp2 = c + vispar.shrink * (lp2 - c); + lp3 = c + vispar.shrink * (lp3 - c); + } + + glVertex3dv (lp1); + glVertex3dv (lp2); + glVertex3dv (lp3); + } + + glEnd(); + } + } + } + + glEndList (); } @@ -2649,7 +2813,7 @@ namespace netgen - void VisualSceneMesh :: BuildPyramidList() + void VisualSceneMesh :: BuildPyramidList(const BitArray & shownode) { shared_ptr mesh = GetMesh(); @@ -2685,6 +2849,12 @@ namespace netgen const Element & el = (*mesh)[ei]; if ((el.GetType() == PYRAMID || el.GetType() == PYRAMID13) && !el.IsDeleted()) { + bool visible = true; + for (auto pi: el.PNums()) + if (!shownode[pi]) + visible = false; + if(!visible) continue; + int i = ei + 1; CurvedElements & curv = mesh->GetCurvedElements(); @@ -3134,7 +3304,7 @@ namespace netgen } glGetIntegerv (GL_VIEWPORT, select.viewport); - GLenum err; + // GLenum err; if(select.framebuffer == 0 || select.viewport[2] != select.width || select.viewport[3] != select.height) { select.width = select.viewport[2]; @@ -3242,13 +3412,13 @@ namespace netgen return pz<1 && pz>0; } - ngcore::INT<2> VisualSceneMesh :: Project(Point<3> p) + ngcore::IVec<2> VisualSceneMesh :: Project(Point<3> p) { Point<3> pwin; gluProject(p[0], p[1], p[2], transformationmat, select.projmat, select.viewport, &pwin[0], &pwin[1], &pwin[2]); - return ngcore::INT<2>(pwin[0]+0.5, select.viewport[3]-pwin[1]+0.5); + return ngcore::IVec<2>(pwin[0]+0.5, select.viewport[3]-pwin[1]+0.5); } @@ -3285,10 +3455,24 @@ namespace netgen cout << endl << "select element " << selelement << " on face " << sel.GetIndex(); // output face name - auto name = GetMesh()->GetFaceDescriptor(sel.GetIndex()).GetBCName(); + auto mesh = GetMesh(); + string name; + if(mesh->GetDimension() == 3) + name = mesh->GetFaceDescriptor(sel.GetIndex()).GetBCName(); + else + name = mesh->GetMaterial(sel.GetIndex()); + if(name != "") cout << " with name " << name; cout << endl; + if(mesh->GetDimension() == 3) { + auto & fd = mesh->GetFaceDescriptor(sel.GetIndex()); + auto domin = fd.DomainIn(); + auto domout = fd.DomainOut(); + string name_in = domin >0 ? mesh->GetMaterial(domin) : ""; + string name_out = domout >0 ? mesh->GetMaterial(domout) : ""; + cout << "\tadjacent domains " << domin << ": " << name_in << ", " << domout << ": " << name_out << endl; + } cout << "\tpoint: " << p << endl;; cout << "\tnodes: "; for (int i = 1; i <= sel.GetNP(); i++) diff --git a/libsrc/visualization/vssolution.cpp b/libsrc/visualization/vssolution.cpp index baaaf448..75b65c66 100644 --- a/libsrc/visualization/vssolution.cpp +++ b/libsrc/visualization/vssolution.cpp @@ -232,7 +232,7 @@ namespace netgen << "DATASET UNSTRUCTURED_GRID\n\n"; surf_ost << "POINTS " << mesh->GetNP() << " float\n"; - for (PointIndex pi = PointIndex::BASE; pi < mesh->GetNP()+PointIndex::BASE; pi++) + for (PointIndex pi = IndexBASE(); pi < mesh->GetNP()+IndexBASE(); pi++) { const MeshPoint & mp = (*mesh)[pi]; surf_ost << mp(0) << " " << mp(1) << " " << mp(2) << "\n"; @@ -248,7 +248,7 @@ namespace netgen const Element2d & el = (*mesh)[sei]; surf_ost << el.GetNP(); for (int j = 0; j < el.GetNP(); j++) - surf_ost << " " << el[j] - PointIndex::BASE; + surf_ost << " " << el[j] - IndexBASE(); surf_ost << "\n"; } surf_ost << "\nCELL_TYPES " << mesh->GetNSE() << "\n"; @@ -275,7 +275,7 @@ namespace netgen << "DATASET UNSTRUCTURED_GRID\n\n"; ost << "POINTS " << mesh->GetNP() << " float\n"; - for (PointIndex pi = PointIndex::BASE; pi < mesh->GetNP()+PointIndex::BASE; pi++) + for (PointIndex pi = IndexBASE(); pi < mesh->GetNP()+IndexBASE(); pi++) { const MeshPoint & mp = (*mesh)[pi]; ost << mp(0) << " " << mp(1) << " " << mp(2) << "\n"; @@ -291,7 +291,7 @@ namespace netgen const Element & el = (*mesh)[ei]; ost << el.GetNP(); for (int j = 0; j < el.GetNP(); j++) - ost << " " << el[j] - PointIndex::BASE; + ost << " " << el[j] - IndexBASE(); ost << "\n"; } ost << "\nCELL_TYPES " << mesh->GetNE() << "\n"; @@ -641,7 +641,7 @@ namespace netgen // delete lock; // mem_lock.UnLock(); } - catch (bad_weak_ptr e) + catch (const bad_weak_ptr & e) { // cout << "don't have a mesh to visualize" << endl; VisualScene::DrawScene(); @@ -801,7 +801,7 @@ namespace netgen if (mesh->GetTimeStamp() > surfellinetimestamp || subdivision_timestamp > surfellinetimestamp || - (deform && solutiontimestamp > surfellinetimestamp) || + (solutiontimestamp > surfellinetimestamp) || zoomall) { DrawSurfaceElementLines(); @@ -841,7 +841,7 @@ namespace netgen if (vispar.clipping.enable && clipsolution == 2) { mesh->Mutex().unlock(); - mesh->BuildElementSearchTree(); + mesh->BuildElementSearchTree(3); mesh->Mutex().lock(); } @@ -922,7 +922,7 @@ namespace netgen { pointcurvelist = glGenLists(1); glNewList(pointcurvelist,GL_COMPILE); - //glColor3f (1.0f, 0.f, 0.f); + SetTextureMode(0); // disable all textures for(int i=0; iGetNumPointCurves(); i++) { @@ -1090,7 +1090,7 @@ namespace netgen NgArray cpt; NgArray pts; - GetClippingPlaneTrigs (cpt, pts); + GetClippingPlaneTrigs (sol, cpt, pts); bool drawelem; glNormal3d (-clipplane[0], -clipplane[1], -clipplane[2]); @@ -1120,7 +1120,7 @@ namespace netgen clipplanetimestamp = max2 (vispar.clipping.timestamp, solutiontimestamp); } - catch (bad_weak_ptr e) + catch (const bad_weak_ptr & e) { PrintMessage (3, "vssolution::buildscene: don't have a mesh to visualize"); VisualScene::BuildScene (zoomall); @@ -1229,7 +1229,7 @@ namespace netgen MyMPI_SendCmd ("solsurfellist"); for ( int dest = 1; dest < ntasks; dest++ ) - MyMPI_Recv (par_surfellists[dest], dest, MPI_TAG_VIS); + MyMPI_Recv (par_surfellists[dest], dest, NG_MPI_TAG_VIS); if (surfellist) glDeleteLists (surfellist, 1); @@ -1342,21 +1342,8 @@ namespace netgen { const Element2d & el = (*mesh)[sei]; - if (vispar.drawdomainsurf > 0) - { - if (mesh->GetDimension() == 3) - { - if (vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainIn() && - vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainOut()) - continue; - } - else - { - if (el.GetIndex() != vispar.drawdomainsurf) continue; - } - } - - + if(!SurfaceElementActive(sol, *mesh, el)) + continue; if ( el.GetType() == QUAD || el.GetType() == QUAD6 || el.GetType() == QUAD8 ) { @@ -1526,20 +1513,8 @@ namespace netgen const Element2d & el = (*mesh)[sei]; // if (el.GetIndex() <= 1) continue; - if(vispar.drawdomainsurf > 0) - { - if (mesh->GetDimension() == 3) - { - if (vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainIn() && - vispar.drawdomainsurf != mesh->GetFaceDescriptor(el.GetIndex()).DomainOut()) - continue; - } - else - { - if (el.GetIndex() != vispar.drawdomainsurf) - continue; - } - } + if(!SurfaceElementActive(sol, *mesh, el)) + continue; if ( el.GetType() == TRIG || el.GetType() == TRIG6 ) { @@ -1785,7 +1760,7 @@ namespace netgen #ifdef PARALLELGL glFinish(); if (id > 0) - MyMPI_Send (surfellist, 0, MPI_TAG_VIS); + MyMPI_Send (surfellist, 0, NG_MPI_TAG_VIS); #endif } @@ -1805,7 +1780,7 @@ namespace netgen MyMPI_SendCmd ("solsurfellinelist"); for ( int dest = 1; dest < ntasks; dest++ ) - MyMPI_Recv (par_surfellists[dest], dest, MPI_TAG_VIS); + MyMPI_Recv (par_surfellists[dest], dest, NG_MPI_TAG_VIS); if (linelist) glDeleteLists (linelist, 1); @@ -1846,6 +1821,10 @@ namespace netgen { Element2d & el = (*mesh)[sei]; + if(scalfunction != -1) + if(!SurfaceElementActive(soldata[scalfunction], *mesh, el)) + continue; + int nv = (el.GetType() == TRIG || el.GetType() == TRIG6) ? 3 : 4; for (int k = 0; k < nv; k++) { @@ -1885,7 +1864,7 @@ namespace netgen #ifdef PARALLELGL glFinish(); if (id > 0) - MyMPI_Send (linelist, 0, MPI_TAG_VIS); + MyMPI_Send (linelist, 0, NG_MPI_TAG_VIS); #endif } @@ -1946,11 +1925,13 @@ namespace netgen // if(vispar.clipdomain > 0 && vispar.clipdomain != (*mesh)[ei].GetIndex()) continue; // if(vispar.donotclipdomain > 0 && vispar.donotclipdomain == (*mesh)[ei].GetIndex()) continue; - ELEMENT_TYPE type = (*mesh)[ei].GetType(); + const Element & el = (*mesh)[ei]; + if(!VolumeElementActive(sol, *mesh, el)) + continue; + + ELEMENT_TYPE type = el.GetType(); if (type == HEX || type == PRISM || type == TET || type == PYRAMID) { - const Element & el = (*mesh)[ei]; - int ii = 0; int cnt_valid = 0; @@ -2327,6 +2308,8 @@ namespace netgen for (sei = 0; sei < nse; sei++) { const Element2d & el = (*mesh)[sei]; + if(!SurfaceElementActive(vsol, *mesh, el)) + continue; if (el.GetType() == TRIG || el.GetType() == TRIG6) { @@ -2684,6 +2667,8 @@ namespace netgen for (int i=first; iSurfaceElements().Range()) { + if(!SurfaceElementActive(sol, *mesh, (*mesh)[i])) + continue; ELEMENT_TYPE type = (*mesh)[i].GetType(); double val; bool considerElem = (type == QUAD) @@ -2742,8 +2729,8 @@ namespace netgen if (ntasks > 1) { double hmin, hmax; - MPI_Reduce (&minv, &hmin, 1, MPI_DOUBLE, MPI_MIN, 0, MPI_COMM_WORLD); - MPI_Reduce (&maxv, &hmax, 1, MPI_DOUBLE, MPI_MAX, 0, MPI_COMM_WORLD); + NG_MPI_Reduce (&minv, &hmin, 1, NG_MPI_DOUBLE, NG_MPI_MIN, 0, NG_MPI_COMM_WORLD); + NG_MPI_Reduce (&maxv, &hmax, 1, NG_MPI_DOUBLE, NG_MPI_MAX, 0, NG_MPI_COMM_WORLD); minv = hmin; maxv = hmax; } @@ -3908,12 +3895,13 @@ namespace netgen return def; } - void VisualSceneSolution :: GetPointDeformation (int pnum, Point<3> & p, + void VisualSceneSolution :: GetPointDeformation (PointIndex pnum, Point<3> & p, SurfaceElementIndex elnr) const { shared_ptr mesh = GetMesh(); - - p = mesh->Point (pnum+1); + auto pnum_ = pnum-IndexBASE(); + + p = mesh->Point (pnum); if (deform && vecfunction != -1) { const SolData * vsol = soldata[vecfunction]; @@ -3921,15 +3909,15 @@ namespace netgen Vec<3> v(0,0,0); if (vsol->soltype == SOL_NODAL) { - v = Vec3d(vsol->data[pnum * vsol->dist], - vsol->data[pnum * vsol->dist+1], - vsol->data[pnum * vsol->dist+2]); + v = Vec3d(vsol->data[pnum_ * vsol->dist], + vsol->data[pnum_ * vsol->dist+1], + vsol->data[pnum_ * vsol->dist+2]); } else if (vsol->soltype == SOL_SURFACE_NONCONTINUOUS) { const Element2d & el = (*mesh)[elnr]; for (int j = 0; j < el.GetNP(); j++) - if (el[j] == pnum+1) + if (el[j] == pnum) { int base = (4*elnr+j-1) * vsol->dist; v = Vec3d(vsol->data[base], @@ -3948,7 +3936,8 @@ namespace netgen - void VisualSceneSolution :: GetClippingPlaneTrigs (NgArray & trigs, + void VisualSceneSolution :: GetClippingPlaneTrigs (SolData * sol, + NgArray & trigs, NgArray & pts) { shared_ptr mesh = GetMesh(); @@ -4014,6 +4003,11 @@ namespace netgen for (ElementIndex ei = 0; ei < ne; ei++) { // NgProfiler::RegionTimer reg1a (timer1a); + + const Element & el = (*mesh)[ei]; + if(!VolumeElementActive(sol, *mesh, el)) + continue; + int first_point_of_element = pts.Size(); locgrid.SetSize(n3); @@ -4021,10 +4015,8 @@ namespace netgen if(vispar.donotclipdomain > 0 && vispar.donotclipdomain == (*mesh)[ei].GetIndex()) continue; ELEMENT_TYPE type = (*mesh)[ei].GetType(); - if (type == HEX || type == PRISM || type == TET || type == TET10 || type == PYRAMID || type == PYRAMID13 || type == PRISM15 || type == HEX20) + if (type == HEX || type == PRISM || type == TET || type == TET10 || type == PYRAMID || type == PYRAMID13 || type == PRISM15 || type == HEX20 || type == HEX7) { - const Element & el = (*mesh)[ei]; - int ii = 0; int cnt_valid = 0; @@ -4074,6 +4066,10 @@ namespace netgen for (int iy = 0; iy <= n; iy++) for (int iz = 0; iz <= n; iz++, ii++) { + double x = double(ix)/n; + double y = double(iy)/n; + double z = double(iz)/n; + Point<3> ploc; compress[ii] = ii; @@ -4102,6 +4098,14 @@ namespace netgen double(iz)/n); if (iz == n) ploc = Point<3> (0,0,1-1e-8); break; + case HEX7: + { + if (iz == n && iy==n) + { y -= 1e-7, z -= 1e-7; } + ploc = Point<3> (x * (1-y*z), y, z); + // if (iz == n && iy==n) ploc = Point<3> (0,1-1e-8,1-1e-8); + break; + } default: cerr << "clip plane trigs not implemented" << endl; ploc = Point<3> (0,0,0); @@ -4337,7 +4341,7 @@ namespace netgen } double lami[3]; - int elnr = mesh->GetElementOfPoint (hp, lami,0,cindex,allowindex)-1; + int elnr = mesh->GetElementOfPoint (hp, lami,0,cindex,allowindex); if (elnr != -1) { @@ -4371,7 +4375,7 @@ namespace netgen MyMPI_SendCmd ("clipplanetrigs"); for ( int dest = 1; dest < ntasks; dest++ ) - MyMPI_Recv (parlists[dest], dest, MPI_TAG_VIS); + MyMPI_Recv (parlists[dest], dest, NG_MPI_TAG_VIS); if (clipplanelist_scal) glDeleteLists (clipplanelist_scal, 1); @@ -4400,7 +4404,6 @@ namespace netgen NgArray trigs; NgArray points; - GetClippingPlaneTrigs (trigs, points); glNormal3d (-clipplane[0], -clipplane[1], -clipplane[2]); glColor3d (1.0, 1.0, 1.0); @@ -4412,6 +4415,7 @@ namespace netgen if (scalfunction != -1) sol = soldata[scalfunction]; + GetClippingPlaneTrigs (sol, trigs, points); if (sol -> draw_volume) { glBegin (GL_TRIANGLES); @@ -4442,7 +4446,7 @@ namespace netgen for (int i = 0; i < trigs.Size(); i++) { const ClipPlaneTrig & trig = trigs[i]; - if (trig.elnr != lastelnr) + if (trig.elnr != ElementIndex(lastelnr)) { lastelnr = trig.elnr; nlp = -1; @@ -4516,7 +4520,7 @@ namespace netgen #ifdef PARALLELGLGL glFinish(); if (id > 0) - MyMPI_Send (clipplanelist_scal, 0, MPI_TAG_VIS); + MyMPI_Send (clipplanelist_scal, 0, NG_MPI_TAG_VIS); #endif } @@ -4722,7 +4726,40 @@ namespace netgen } + bool VisualSceneSolution :: + SurfaceElementActive(const SolData *data, const Mesh & mesh, const Element2d & el) const + { + if(data == nullptr) return true; + bool is_active = true; + if (vispar.drawdomainsurf > 0) + { + if (mesh.GetDimension() == 3) + { + if (vispar.drawdomainsurf != mesh.GetFaceDescriptor(el.GetIndex()).DomainIn() && + vispar.drawdomainsurf != mesh.GetFaceDescriptor(el.GetIndex()).DomainOut()) + is_active = false; + } + else + { + if (el.GetIndex() != vispar.drawdomainsurf) + is_active = false; + } + } + if(data->draw_surfaces) + is_active = is_active && (*data->draw_surfaces)[el.GetIndex()-1]; + + return is_active; + } + + bool VisualSceneSolution :: + VolumeElementActive(const SolData *data, const Mesh & mesh, const Element & el) const + { + bool is_active = true; + if(data->draw_volumes) + is_active = is_active && (*data->draw_volumes)[el.GetIndex()-1]; + return is_active; + } @@ -4736,7 +4773,7 @@ namespace netgen void VisualSceneSolution :: MouseDblClick (int px, int py) { auto mesh = GetMesh(); - auto dim = mesh->GetDimension(); + // auto dim = mesh->GetDimension(); marker = nullopt; auto formatComplex = [](double real, double imag) @@ -4806,10 +4843,6 @@ namespace netgen // check if we look at the clipping plane from the right direction if(n*view > 1e-8) { - double lam = vispar.clipping.dist - Vec<3>{eye}*n; - lam /= n*view; - p = eye + lam*view; - double lami[3]; if(auto el3d = mesh->GetElementOfPoint( p, lami )) { @@ -4817,7 +4850,7 @@ namespace netgen // marker = p; bool have_scal_func = scalfunction!=-1 && soldata[scalfunction]->draw_volume; - bool have_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_volume; + // bool have_vec_func = vecfunction!=-1 && soldata[vecfunction]->draw_volume; if(have_scal_func) { @@ -4829,18 +4862,18 @@ namespace netgen if(sol.iscomplex && rcomponent != 0) { rcomponent = 2 * ((rcomponent-1)/2) + 1; - GetValue(&sol, el3d-1, lami[0], lami[1], lami[2], rcomponent+1, + GetValue(&sol, el3d, lami[0], lami[1], lami[2], rcomponent+1, imag); comp = (scalcomp-1)/2 + 1; } - GetValue(&sol, el3d-1, lami[0], lami[1], lami[2], rcomponent, val); + GetValue(&sol, el3d, lami[0], lami[1], lami[2], rcomponent, val); printScalValue(sol, comp, val, imag, sol.iscomplex && comp > 0); } if(vecfunction!=-1 && soldata[vecfunction]->draw_volume) { auto & sol = *soldata[vecfunction]; ArrayMem values(sol.components); - GetValues(&sol, el3d-1, lami[0], lami[1], lami[2], &values[0]); + GetValues(&sol, el3d, lami[0], lami[1], lami[2], &values[0]); printVecValue(sol, values); } return; @@ -4851,7 +4884,7 @@ namespace netgen double lami[3] = {0.0, 0.0, 0.0}; // Check if unprojected Point is close to surface element (eps of 1e-3 due to z-Buffer accuracy) bool found_2del = false; - if(selelement>0 && mesh->PointContainedIn2DElement(p, lami, selelement, false && fabs(lami[2])<1e-3)) + if(selelement>0 && mesh->PointContainedIn2DElement(p, lami, selelement-1, false && fabs(lami[2])<1e-3)) { // Found it, use coordinates of point projected to surface element mesh->GetCurvedElements().CalcSurfaceTransformation({1.0-lami[0]-lami[1], lami[0]}, selelement-1, p); @@ -4896,7 +4929,7 @@ namespace netgen void VisualSceneSolution :: Broadcast () { - MPI_Datatype type; + NG_MPI_Datatype type; int blocklen[] = { 1, 1, 1, 1, @@ -4905,7 +4938,7 @@ namespace netgen 1, 4, 1, 1, 1 }; - MPI_Aint displ[] = { (char*)&usetexture - (char*)this, + NG_MPI_Aint displ[] = { (char*)&usetexture - (char*)this, (char*)&clipsolution - (char*)this, (char*)&scalfunction - (char*)this, (char*)&scalcomp - (char*)this, @@ -4929,19 +4962,19 @@ namespace netgen }; - MPI_Datatype types[] = { - MPI_INT, MPI_INT, MPI_INT, MPI_INT, - MPI_INT, MPI_INT, MPI_INT, MPI_INT, - MPI_DOUBLE, MPI_DOUBLE, MPI_INT, MPI_INT, - MPI_INT, MPI_DOUBLE, MPI_INT, MPI_INT, - MPI_DOUBLE + NG_MPI_Datatype types[] = { + NG_MPI_INT, NG_MPI_INT, NG_MPI_INT, NG_MPI_INT, + NG_MPI_INT, NG_MPI_INT, NG_MPI_INT, NG_MPI_INT, + NG_MPI_DOUBLE, NG_MPI_DOUBLE, NG_MPI_INT, NG_MPI_INT, + NG_MPI_INT, NG_MPI_DOUBLE, NG_MPI_INT, NG_MPI_INT, + NG_MPI_DOUBLE }; - MPI_Type_create_struct (17, blocklen, displ, types, &type); - MPI_Type_commit ( &type ); + NG_MPI_Type_create_struct (17, blocklen, displ, types, &type); + NG_MPI_Type_commit ( &type ); - MPI_Bcast (this, 1, type, 0, MPI_COMM_WORLD); - MPI_Type_free (&type); + NG_MPI_Bcast (this, 1, type, 0, NG_MPI_COMM_WORLD); + NG_MPI_Type_free (&type); } #endif @@ -4970,6 +5003,8 @@ void Impl_Ng_InitSolutionData (Ng_SolutionData * soldata) soldata -> iscomplex = 0; soldata -> draw_surface = 1; soldata -> draw_volume = 1; + soldata -> draw_surfaces = nullptr; + soldata -> draw_volumes = nullptr; soldata -> soltype = NG_SOLUTION_NODAL; soldata -> solclass = 0; } @@ -4994,6 +5029,8 @@ void Impl_Ng_SetSolutionData (Ng_SolutionData * soldata) vss->iscomplex = bool(soldata->iscomplex); vss->draw_surface = soldata->draw_surface; vss->draw_volume = soldata->draw_volume; + vss->draw_surfaces = soldata->draw_surfaces; + vss->draw_volumes = soldata->draw_volumes; vss->soltype = netgen::VisualSceneSolution::SolType (soldata->soltype); vss->solclass = soldata->solclass; // netgen::vssolution.AddSolutionData (vss); diff --git a/libsrc/visualization/vssolution.hpp b/libsrc/visualization/vssolution.hpp index 66684ed4..97fbbc66 100644 --- a/libsrc/visualization/vssolution.hpp +++ b/libsrc/visualization/vssolution.hpp @@ -151,6 +151,7 @@ public: bool iscomplex; bool draw_volume; bool draw_surface; + std::shared_ptr draw_volumes, draw_surfaces; SolType soltype; SolutionData * solclass; @@ -247,11 +248,13 @@ public: } private: - void GetClippingPlaneTrigs (NgArray & trigs, NgArray & pts); + void GetClippingPlaneTrigs (SolData * sol, NgArray & trigs, NgArray & pts); void GetClippingPlaneGrid (NgArray & pts); void DrawCone (const Point<3> & p1, const Point<3> & p2, double r); void DrawCylinder (const Point<3> & p1, const Point<3> & p2, double r); + bool SurfaceElementActive(const SolData *data, const Mesh & mesh, const Element2d & sei) const; + bool VolumeElementActive(const SolData *data, const Mesh & mesh, const Element & ei) const; // Get Function Value, local coordinates lam1, lam2, lam3, bool GetValue (const SolData * data, ElementIndex elnr, @@ -316,7 +319,7 @@ private: Vec<3> GetDeformation (ElementIndex elnr, const Point<3> & p) const; Vec<3> GetSurfDeformation (SurfaceElementIndex selnr, int facetnr, double lam1, double lam2) const; - void GetPointDeformation (int pnum, Point<3> & p, SurfaceElementIndex elnr = -1) const; + void GetPointDeformation (PointIndex pnum, Point<3> & p, SurfaceElementIndex elnr = -1) const; public: /// draw elements (build lists) diff --git a/ng/CMakeLists.txt b/ng/CMakeLists.txt index 3ad3d8be..b5a1985b 100644 --- a/ng/CMakeLists.txt +++ b/ng/CMakeLists.txt @@ -28,7 +28,7 @@ if(USE_GUI) if(APPLE) set_target_properties(netgen PROPERTIES OUTPUT_NAME netgen) endif(APPLE) - target_link_libraries( netgen ${PYTHON_LIBRARIES} ${TCL_LIBRARY} ${TK_LIBRARY}) + target_link_libraries( netgen ${Python3_LIBRARIES} ${TCL_LIBRARY} ${TK_LIBRARY}) endif(NOT BUILD_FOR_CONDA) install(TARGETS nggui ${NG_INSTALL_DIR}) @@ -37,6 +37,7 @@ endif(USE_GUI) if(USE_PYTHON) add_library(ngpy SHARED netgenpy.cpp) target_link_libraries( ngpy PUBLIC nglib PRIVATE "$" ) + target_link_libraries( ngpy PRIVATE ${CMAKE_THREAD_LIBS_INIT} ${JPEG_LIBRARIES} ${MKL_LIBRARIES} ${ZLIB_LIBRARIES} occ_libs netgen_cgns ) if(APPLE) set_target_properties( ngpy PROPERTIES SUFFIX ".so") elseif(WIN32) @@ -44,7 +45,7 @@ if(USE_PYTHON) set_target_properties( ngpy PROPERTIES OUTPUT_NAME "libngpy") endif() set_target_properties(ngpy PROPERTIES INSTALL_RPATH "${NG_RPATH_TOKEN}/../${NETGEN_PYTHON_RPATH}") - install(TARGETS ngpy DESTINATION ${NG_INSTALL_DIR_PYTHON}/${NG_INSTALL_SUFFIX} COMPONENT netgen) + install(TARGETS ngpy DESTINATION ${NG_INSTALL_DIR_PYTHON}/${NG_INSTALL_SUFFIX} COMPONENT netgen EXPORT netgen-targets) if(USE_GUI) add_library(ngguipy SHARED ngguipy.cpp) @@ -56,7 +57,7 @@ if(USE_PYTHON) set_target_properties( ngguipy PROPERTIES OUTPUT_NAME "libngguipy") endif() set_target_properties(ngguipy PROPERTIES INSTALL_RPATH "${NG_RPATH_TOKEN}/../${NETGEN_PYTHON_RPATH}") - install(TARGETS ngguipy DESTINATION ${NG_INSTALL_DIR_PYTHON}/${NG_INSTALL_SUFFIX} COMPONENT netgen) + install(TARGETS ngguipy DESTINATION ${NG_INSTALL_DIR_PYTHON}/${NG_INSTALL_SUFFIX} COMPONENT netgen EXPORT netgen-targets) endif(USE_GUI) endif(USE_PYTHON) diff --git a/ng/Togl-1.7/.indent.pro b/ng/Togl-1.7/.indent.pro deleted file mode 100644 index 365338e4..00000000 --- a/ng/Togl-1.7/.indent.pro +++ /dev/null @@ -1,72 +0,0 @@ ---blank-before-sizeof ---blank-lines-after-declarations ---blank-lines-after-procedures ---blank-lines-before-block-comments ---braces-after-struct-decl-line ---braces-on-if-line ---break-before-boolean-operator ---case-brace-indentation0 ---case-indentation2 ---comment-line-length80 ---continuation-indentation8 ---cuddle-do-while ---cuddle-else ---declaration-indentation8 ---dont-line-up-parentheses ---format-all-comments ---format-first-column-comments ---indent-level4 ---leave-optional-blank-lines ---line-length80 ---no-space-after-function-call-names ---no-space-after-parentheses ---no-tabs ---parameter-indentation8 ---preprocessor-indentation2 ---procnames-start-lines ---space-after-cast ---space-after-for ---space-after-if ---space-after-while ---space-special-semicolon ---start-left-side-of-comments ---struct-brace-indentation0 ---tab-size8 --T AGLContext --T CALLBACK --T ClientData --T Colormap --T Display --T GLXContext --T GLbitfield --T GLboolean --T GLenum --T GLfloat --T GLint --T GLuint --T HDC --T HGLRC --T HWND --T LPARAM --T PIXELFORMATDESCRIPTOR --T Tcl_Command --T Tcl_Interp --T TkClassCreateProc --T TkClassGeometryProc --T TkClassModalProc --T TkClassProcs --T TkWinColormap --T Tk_ConfigSpec --T Tk_Cursor --T Tk_Window --T Togl_Callback --T Togl_CmdProc --T UINT --T WPARAM --T WinFont --T Window --T XColor --T XEvent --T XVisualInfo --T TOGL_EXTERN --T Togl diff --git a/ng/Togl-1.7/CMakeLists.txt b/ng/Togl-1.7/CMakeLists.txt deleted file mode 100644 index 8ca9e0f4..00000000 --- a/ng/Togl-1.7/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -add_definitions("-DPACKAGE_NAME=\"Togl\" -DPACKAGE_TARNAME=\"togl\" -DPACKAGE_VERSION=\"1.7\" -DPACKAGE_STRING=\"Togl\ 1.7\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_PARAM_H=1 -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 -DTCL_THREADS=1 -D_LARGEFILE64_SOURCE=1 -DTCL_WIDE_INT_IS_LONG=1 -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1") - -# include_directories("/usr/include/tcl8.5" "/usr/include/tcl8.5/tk-private/generic" "/usr/include/tcl8.5/tk-private/unix") -# SET(CMAKE_CXX_FLAGS "-O2 -fomit-frame-pointer -Wall -Wno-implicit-int -fPIC -c") -include_directories("${TCL_INCLUDE_PATH}/tk-private/generic" "${TCL_INCLUDE_PATH}/tk-private/unix") -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -fomit-frame-pointer -Wall -Wno-implicit-int") -set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -fomit-frame-pointer -Wall -Wno-implicit-int") -add_library(togl togl.c) -target_link_libraries(togl ${OPENGL_LIBRARIES}) -set_target_properties(togl PROPERTIES POSITION_INDEPENDENT_CODE ON ) -# -# gcc -DPACKAGE_NAME=\"Togl\" -DPACKAGE_TARNAME=\"togl\" -DPACKAGE_VERSION=\"1.7\" -DPACKAGE_STRING=\"Togl\ 1.7\" -DPACKAGE_BUGREPORT=\"\" -DSTDC_HEADERS=1 -DHAVE_SYS_TYPES_H=1 -DHAVE_SYS_STAT_H=1 -DHAVE_STDLIB_H=1 -DHAVE_STRING_H=1 -DHAVE_MEMORY_H=1 -DHAVE_STRINGS_H=1 -DHAVE_INTTYPES_H=1 -DHAVE_STDINT_H=1 -DHAVE_UNISTD_H=1 -DHAVE_LIMITS_H=1 -DHAVE_SYS_PARAM_H=1 -DUSE_THREAD_ALLOC=1 -D_REENTRANT=1 -D_THREAD_SAFE=1 -DTCL_THREADS=1 -D_LARGEFILE64_SOURCE=1 -DTCL_WIDE_INT_IS_LONG=1 -DUSE_TCL_STUBS=1 -DUSE_TK_STUBS=1 -# -I"/usr/include/tcl8.6" -I"/usr/include/tcl8.6/tk-private/generic" -I"/usr/include/tcl8.6/tk-private/unix" -# -O2 -fomit-frame-pointer -Wall -Wno-implicit-int -fPIC -c `echo togl.c` -o togl.o -# rm -f libTogl1.7.so -# gcc -pipe -shared -o libTogl1.7.so togl.o -lX11 -lGL -lXmu -L/usr/lib/x86_64-linux-gnu -ltclstub8.6 -L/usr/lib/x86_64-linux-gnu -ltkstub8.6 -# : libTogl1.7.so - - diff --git a/ng/Togl-1.7/LICENSE b/ng/Togl-1.7/LICENSE deleted file mode 100644 index e9badb74..00000000 --- a/ng/Togl-1.7/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -This software is copyrighted by Brian Paul (brian@mesa3d.org) -and Benjamin Bederson (bederson@cs.umd.edu). The following -terms apply to all files associated with the software unless explicitly -disclaimed in individual files. - -The authors hereby grant permission to use, copy, modify, distribute, -and license this software and its documentation for any purpose, provided -that existing copyright notices are retained in all copies and that this -notice is included verbatim in any distributions. No written agreement, -license, or royalty fee is required for any of the authorized uses. -Modifications to this software may be copyrighted by their authors -and need not follow the licensing terms described here, provided that -the new terms are clearly indicated on the first page of each file where -they apply. - -IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY -FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES -ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY -DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - -THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE -IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE -NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR -MODIFICATIONS. diff --git a/ng/Togl-1.7/README.stubs b/ng/Togl-1.7/README.stubs deleted file mode 100644 index 4c1b8186..00000000 --- a/ng/Togl-1.7/README.stubs +++ /dev/null @@ -1,21 +0,0 @@ -This version of Togl is entirely free from -dependencies on Tcl/Tk's internal functions. It uses the public stubs -interface, witch means that the same binary works with any stubs-aware -wish (i.e. version >= 8.1) - -It has been tested on Windows NT/2000 and Linux for several Tcl/Tk versions up -to 8.4a3. I haven't been able to test the Mac port, it probably needs mending -but I can't see why it shouldn't work in principle. - -Implementation wise, what differs from Togl 1.5 is that Togl_MakeWindowExist() -is replaced by Togl_CreateWindow(), a function that gets registered in Tk as a callback for window creation. In Tk/Tk 8.4a3, there is a new public API call -Tk_SetClassProcs() to register this callback, but for earlier versions of Tk -one needs to do this using some pointer magic. -There is a run-time check to determine which method to use, hence the -same binary runs on all versions of Wish from 8.1 and up. For this to -work you need to compile against the headers from Tcl/Tk 8.4a3 or later, or -the binary will only work for Tcl/Tk 8.1-8.4a2. -The tk8.4a3 public headers (tk8.4a3.h + tkDecls.h) are included for -convenience, and they are used if the flag -DUSE_LOCAL_TK_H is specified. - -Jonas Beskow, December 2001 \ No newline at end of file diff --git a/ng/Togl-1.7/TODO b/ng/Togl-1.7/TODO deleted file mode 100644 index c525ddac..00000000 --- a/ng/Togl-1.7/TODO +++ /dev/null @@ -1,20 +0,0 @@ -In no particular order: ------------------------ - -stubify C API. - -replace EPS support with TK photo image support - -Add command arguments for create, destroy, etc. so there would be a --createcommand option to the togl command (etc.) (and phase out -Togl_*Func from the C API) - -multisampling support (can be worked-around by passing in a pixelformat) - -add vertical sync control - -update documentation - - update build instructions - - update stereo documentation - - separate Tcl API from C API - - say togl hides window system dependent (glX/wgl/agl) calls diff --git a/ng/Togl-1.7/Togl.html b/ng/Togl-1.7/Togl.html deleted file mode 100644 index 5df48136..00000000 --- a/ng/Togl-1.7/Togl.html +++ /dev/null @@ -1,1081 +0,0 @@ - - - - - - - Togl - - - - -
-

Togl — a Tk OpenGL widget

-

Copyright (C) 1996-2002 Brian Paul and Ben Bederson

-
- - -
-

Contents

- - - - -
-

Introduction

- - Togl is a Tk widget for OpenGL rendering. - Togl was originally based on OGLTK, written by Benjamin Bederson at - the University of New Mexico. - Togl adds the new features: - -
    -
  • color-index mode support including color allocation functions -
  • support for requesting stencil, accumulation, alpha buffers, etc -
  • multiple OpenGL drawing widgets -
  • OpenGL extension testing from Tcl -
  • simple, portable font support -
  • overlay plane support -
- -

- Togl allows one to create and manage a special Tk/OpenGL widget - with Tcl and render into it with a C program. That is, - a typical Togl program will have Tcl code for managing the user interface - and a C program for computations and OpenGL rendering. - -

- Togl is copyrighted by - Brian Paul - (brian_e_paul@yahoo.com) and - Benjamin Bederson - (bederson@cs.umd.edu). - See the LICENSE file for details. - -

- The - Togl project and - home page are - hosted by SourceForge. - - -
-

Prerequisites

- -

- You should have - Tcl and Tk - installed on your computer. Togl works with Tcl/Tk - version 8.0 and up. The Mac OS X version requires version 8.4. - -

- You must also have - OpenGL or - Mesa - (a free alternative to OpenGL) installed on your computer. - -

- One should be familiar with Tcl, Tk, OpenGL, and C programming to use Togl - effectively. - - -
-

Getting Togl

- -

- The current version of Togl is 1.7. - Togl can be downloaded from - - SourceForge. - - -
-

Mailing list

- -

- See the - Togl project at SourceForge for mailing list information. - - -
-

Using Togl With Your Application

- -

- There are basically two ways of using Togl with your application: -

    -
  • - Link or "compile in" Togl with your executable or shared library. In this - case you must call Togl_Init() from your C code to initialize Togl. This - is the way the included Togl examples are built. - -
  • - Install the Togl shared library and pkgIndex.tcl file - (using make install) and then load it into wish using - package require Togl. - Then, before creating the Togl widget, call functions in your application - code (also a compiled into a shared library and loaded into wish) - to setup the Togl widget for the OpenGL rendering. - Create the blank Togl widget, - and then you're managing redraws and buffer swapping from the Tcl level. -
- Since Togl is compiled into a shared library using the Tcl/Tk stubs-interface, - the same binary can be used with any version of Tck/Tk from 8.06 and up. - See README.stubs for more info. - -

Unix/X11 usage

- -

- Unix/X systems only need the togl.c, togl.h - and the public Tcl/Tk include files. - -

Windows 95/NT/2000/XP usage

- -

- Windows platforms need tkWinInt.h - and other internal Tk header files. So you need a Tcl/Tk - source distribution in addition to the Togl distribution - (or copy over the various include files). -

- Here's the minimal way to build Togl with Tcl/Tk - using the gcc that is distributed - as part of the cygwin tools - (Microsoft's compilers work too): -

-VER=8.4.12
-SRCDIR=`pwd`
-
-cd $SRCDIR/tcl$VER/win
-env 'CC=gcc -mno-cygwin' ./configure --enable-threads
-make libtclstub84.a
-
-cd $SRCDIR/tk$VER/win
-env 'CC=gcc -mno-cygwin' ./configure --enable-threads
-make libtkstub84.a
-
-cd $SRCDIR/Togl
-env 'CC=gcc -mno-cygwin' ./configure --with-tcl=../tcl$VER/win --with-tk=../tk$VER/win
-
-make
-
- The resulting Togl17.dll and pkgIndex.tcl - should be installed into your Tcl distribution just like any other package. - -

Mac OS X usage

- -

- These special instructions are for building the Aqua version of Togl. - Mac OS X needs tkMacOSXInt.h - and other internal Tk header files. Unfortunately, the Tcl and Tk - frameworks that Apple distributes are missing the internal headers. - So you need a Tcl/Tk source distribution in addition to the Togl - distribution (or copy over the various include files). - You would probably want a newer version of Tcl and Tk anyway - because each minor revision of 8.4 has many Aqua bug fixes. -

- Here's one way to build Tcl, Tk, and Togl on Mac OS X (assuming they - are all in the same directory) to install in your home directory: -

-VER=8.4.12
-
-mkdir -p ~/bin
-make -C tcl$VER/macosx install PREFIX="${HOME}" INSTALL_PATH="${HOME}/Library/Frameworks"
-make -C tk$VER/macosx install PREFIX="${HOME}" INSTALL_PATH="${HOME}/Library/Frameworks"
-
-(cd Togl; ./configure --prefix="${HOME}")
-make -C Togl install
-
- - -
-

C Togl Functions

- -

- These are the Togl functions one may call from a C program. - -

- - #include "togl.h" - -
- -

- For portability, you should include the togl.h header - before any other OpenGL header so that various - Windows 95/NT/2000/XP stuff falls into place. - - -

Setup and Initialization Functions

- -
-
int Togl_Init(Tcl_Interp *interp) -
- Initializes the Togl module. This is typically called from the - Tk_Main() function - or via Tcl's package require command. -
- -
-
void Togl_CreateFunc(Togl_Callback *proc) -
- void Togl_DisplayFunc(Togl_Callback *proc) -
- void Togl_ReshapeFunc(Togl_Callback *proc) -
- void Togl_DestroyFunc(Togl_Callback *proc) -
-
- Register C functions to be called by Tcl/Tk when a widget is realized, - must be redrawn, is resized, or is destroyed respectively. -

- Each C callback must be of the form: -

-	void callback(Togl *togl)
-	{
-	   ...your code...
-	}
-
-
- -
-
void Togl_TimerFunc(Togl_Callback *proc) -
- Register a C timer callback function which will be called every - n milliseconds. The interval n is specified - by the -time option to the Togl Tcl command. -

- The C callback must be of the form: -

-	void my_timer_callback(Togl *togl)
-	{
-	   ...your code...
-	}
-
-
- -
-
void Togl_ResetDefaultCallbacks(void) -
- Reset all default callback pointers to NULL. -
- -
-
void Togl_CreateCommand(char *cmd_name, Togl_CmdProc *cmd_proc) -
- Used to create a new Togl sub-command. The C function which implements - the command must be of the form: -

-

-	int callback(Togl *togl, int argc, char *argv[])
-	{
-	   ...your code...
-	   return TCL_OK or TCL_ERROR;
-	}
-
-
- -

Drawing-related Commands

- -
-
void Togl_PostRedisplay(Togl *togl) -
- Signals that the widget should be redrawn. When Tk is next idle the - user's C render callback will be invoked. This is typically called - from within a Togl sub-command which was registered with - Togl_CreateCommand(). -
- -
-
void Togl_SwapBuffers(const Togl *togl) -
- Swaps the front and back color buffers for a double-buffered widget. - glFlush() is executed if the window is single-buffered. This is - typically called in the rendering function which was registered with - Togl_DisplayFunc(). -
- -
-
void Togl_MakeCurrent(const Togl *togl) -
- Sets the current rendering context to the given widget. This is done - automatically before the Togl callback functions are called. So the - call is only needed if you have multiple widgets with separate OpenGL - contexts. If the argument is NULL, then the rendering context is cleared - and subsequent OpenGL commands will fail. -
- -

Query Functions

- -
-
char *Togl_Ident(const Togl *togl) -
- Returns a pointer to the identification string associated with a Togl - widget or NULL if there's no identifier string. -
- -
-
int Togl_Width(const Togl *togl) -
- Returns the width of the given Togl widget. Typically called in the - function registered with Togl_ReshapeFunc(). -
- -
-
int Togl_Height(const Togl *togl) -
- Returns the height of the given Togl widget. Typically called in the - function registered with Togl_ReshapeFunc(). -
- -
-
Tcl_Interp *Togl_Interp(const Togl *togl) -
- Returns the Tcl interpreter associated with the given Togl widget. -
-
-
- Tk_Window Togl_TkWin(const Togl *togl) -
- Returns the Tk window associated with the given Togl widget. -
- -

Color Index Mode Functions

- -

- These functions are only used for color index mode. - -

-
unsigned long Togl_AllocColor(Togl *togl, float red, float green, float blue) -
- Allocate a color from a read-only colormap. Given a color specified - by red, green, and blue return a colormap index (aka pixel value) - whose entry most closely matches the red, green, blue color. Red, - green, and blue are values in [0,1]. This function is only used in - color index mode when the -privatecmap option is false. -
- -
-
void Togl_FreeColor(Togl *togl, unsigned long index) -
- Free a color in a read-only colormap. Index is a value which was - returned by the Togl_AllocColor() function. This function is only - used in color index mode when the -privatecmap option - is false. -
- -
-
void Togl_SetColor(Togl *togl, - int index, float red, float green, float blue) -
- Load the colormap entry specified by index with the given red, green - and blue values. Red, green, and blue are values in [0,1]. This - function is only used in color index mode when the - -privatecmap option is true. -
- - -

Font Functions

- -
-
GLuint Togl_LoadBitmapFont(Togl *togl, - const char *fontname) -
- Load the named font as a set of glBitmap display lists. - fontname may be one of - -
    -
  • TOGL_BITMAP_8_BY_13 -
  • TOGL_BITMAP_9_BY_15 -
  • TOGL_BITMAP_TIMES_ROMAN_10 -
  • TOGL_BITMAP_TIMES_ROMAN_24 -
  • TOGL_BITMAP_HELVETICA_10 -
  • TOGL_BITMAP_HELVETICA_12 -
  • TOGL_BITMAP_HELVETICA_18 - -
  • or any X11 font name -
- Zero is returned if this function fails. -
- After Togl_LoadBitmapFont() has been called, returning fontbase, - you can render a string s with: -
- - glListBase(fontbase); -
- glCallLists(strlen(s), GL_BYTE, s); -
-
- To maximize the portability of your application it is best to use one - of the predefined TOGL_BITMAP_* fonts. -
- -
-
void Togl_UnloadBitmapFont(Togl *togl, GLuint fontbase) - -
- Destroys the bitmap display lists created by by Togl_LoadBitmapFont(). -
- -

Client Data Functions

- -
-
void Togl_SetClientData(Togl *togl, ClientData clientData) -
- clientData is a pointer to an arbitrary user data structure. - Each Togl struct has such a pointer. - This function sets the Togl widget's client data pointer. -
- -
-
ClientData Togl_GetClientData(const Togl *togl) -
- clientData is a pointer to an arbitrary user data structure. - Each Togl struct has such a pointer. - This function returns the Togl widget's client data pointer. -
- -
-
void Togl_ClientData(ClientData clientData) -
- clientData is a pointer to an arbitrary user data structure. - Set default client data pointer for subsequent new Togl widgets. - Default value is NULL. -
- - -

Overlay Functions

- -

- These functions are modelled after GLUT's overlay sub-API. - -

-
void Togl_UseLayer(Togl *togl, int layer) -
- Select the layer into which subsequent OpenGL rendering will be - directed. layer may be either TOGL_OVERLAY or - TOGL_NORMAL. -
- -
-
void Togl_ShowOverlay(Togl *togl) -
- Display the overlay planes, if any. -
- -
-
void Togl_HideOverlay(Togl *togl) -
- Hide the overlay planes, if any. -
- -
-
void Togl_PostOverlayRedisplay(Togl *togl) -
- Signal that the overlay planes should be redraw. - When Tk is next idle the user's C overlay display callback will be invoked. - This is typically called from within a Togl sub-command which was - registered with Togl_CreateCommand(). -
- -
-
void Togl_OverlayDisplayFunc(Togl_Callback *proc) -
- Registers the C callback function which should be called to redraw the - overlay planes. This is the function which will be called in - response to Togl_PostOverlayRedisplay(). - The callback must be of the form: -

-

-	void RedrawOverlay(Togl *togl)
-	{
-	   ...your code...
-	}
-
-
- -
-
int Togl_ExistsOverlay(Togl *togl) -
- Returns 1 if overlay planes exist, 0 otherwise. -
- -
-
int Togl_GetOverlayTransparentValue(const Togl *togl) -
- Returns the color index of the overlay's transparent pixel value. -
- -
-
int Togl_IsMappedOverlay(const Togl *togl) -
- Returns 1 if the overlay planes are currently displayed, 0 otherwise. -
- -
-
unsigned long Togl_AllocColorOverlay(const Togl *togl, - float red, float green, float blue) -
- Allocate a color in the overlay planes. Red, green, and blue are - values in [0,1]. Return the color index or -1 if the allocation - fails. -
- -
-
void Togl_FreeColorOverlay(const Togl *togl, unsigned long index) -
- Free a color which was allocated with Togl_AllocColorOverlay(). -
- - -

X11-only Functions

- -

- These functions are only implemented on systems using the X Window System. - We recommend that you avoid using these functions in your application since - they are not portable to other operating/window systems - (use Togl_TkWin() and normal Tk functions instead). -

- -

-
Display *Togl_Display(const Togl *togl) -
- Returns the X Display of a Togl widget. -
- -
-
Screen *Togl_Screen(const Togl *togl) -
- Returns the X Screen of a Togl widget. -
- -
-
int Togl_ScreenNumber(const Togl *togl) -
- Returns the X screen number of a Togl widget. -
- -
-
Colormap Togl_Colormap(const Togl *togl) -
- Returns the X Colormap used by a Togl widget. -
- - -

Postscript Output

-

- -

-
int Togl_DumpToEpsFile(const Togl *togl, - const char *filename, int rgbFlag, void (*user_redraw)()) -
- Generate an encapsulated Postscript file of the image in a Togl widget. - filename is the name of the file to generate. - If rgbFlag is non-zero then an RGB image file is written, - else a grayscale image file is written. - user_redraw is a pointer to the function which will render the - desired image. This will typically be the same as the function passed - to Togl_DisplayFunc(). -
- - -
-

Tcl Togl commands

- -

- These are the Togl commands one may call from a Tcl program. - -

-
togl pathName [options] -
- Creates a new togl widget with name pathName and - an optional list of configuration options. Options include: -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Option Default Comments
-width 400 - Width of widget in pixels.
-height 400 - Height of widget in pixels.
 
-ident "" - A user identification string. This is used match widgets - for the -sharecontext - and the -sharelist options (see below). - This is also useful in your callback functions - to determine which Togl widget is the caller. -
 
-rgba true - If true, use RGB(A) mode, otherwise use Color Index mode.
-redsize 1 - Minimum number of bits in red component.
-greensize 1 - Minimum number of bits in green component.
-bluesize 1 - Minimum number of bits in blue component.
-alpha 1 - If true and -rgba is true, request an alpha channel.
-alphasize 1 - Minimum number of bits in alpha component.
 
-double false - If true, request a double-buffered window, otherwise - request a single-buffered window.
 
-depth false - If true, request a depth buffer.
-depthsize 1 - Minimum number of bits in depth buffer.
 
-accum false - If true, request an accumulation buffer.
-accumredsize 1 - Minimum number of bits in accumulation buffer red component.
-accumgreensize 1 - Minimum number of bits in accumulation buffer green component.
-accumbluesize 1 - Minimum number of bits in accumulation buffer blue component.
-accumalphasize 1 - Minimum number of bits in accumulation buffer alpha component.
 
-stencil false - If true, request a stencil buffer.
-stencilsize 1 - Minimum number of bits in stencil component.
 
-auxbuffers 0 - Desired number of auxiliary buffers.
 
-privatecmap false - Only applicable in color index mode. - If false, use a shared read-only colormap. - If true, use a private read/write colormap. -
 
-overlay false - If true, request overlay planes.
 
-stereo false - If true, request a stereo-capable window.
-oldstereo false - On SGI workstations only: if true, request divided-screen stereo. -
 
-time 1 - Specifies the interval, in milliseconds, for - calling the C timer callback function which - was registered with Togl_TimerFunc.
 
-sharelist "" - Name of an existing Togl widget with which to - share display lists. -
-sharecontext "" - Name of an existing Togl widget with which to - share the OpenGL context. NOTE: most other - attributes such as double buffering, RGBA vs CI, - ancillary buffer specs, etc are then ignored. -
 
-indirect false - If present, request an indirect rendering context. - A direct rendering context is normally requested. - Only significant on Unix/X11. -
 
-cursor "" - Set the cursor in the widget window.
 
-pixelformat 0 - Set the pixel format to the (platform-dependent) given value.
-

- - -
-
pathName configure -
- Returns all configuration records for the named togl widget. -
- -
-
pathName configure -option -
- Returns configuration information for the specified option - which may be one of: -
-
-width -
- Returns the width configuration of the widget in the form: -
- -width width Width W w -
- where W is the default width in pixels - and w is the current width in pixels -
-
-
-height -
- Returns the height configuration of the widget in the form: -
- -height height Height H h -
- where H is the default height in pixels - and h is the current height in pixels -
-
-
-extensions -
- Returns a list of OpenGL extensions available. For example: - GL_EXT_polygon_offset GL_EXT_vertex_array -
-
- -
-
pathName configure -option value -
- Reconfigure a Togl widget. option may be any one of the - options listed in the togl command above. -
- -
-
pathName render -
- Causes the render callback function to be called for pathName. -
- -
-
pathName swapbuffers -
- Causes front/back buffers to be swapped if in double buffer mode. - And flushes the OpenGL command buffer if in single buffer mode. - (So this is appropriate to call after every frame is drawn.) -
- -
-
pathName makecurrent -
- Make the widget specified by pathName and its OpenGL context - the current ones. -
- - -
-

Demo Programs

- -

- There are six demo programs: - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
double.tcl— compares single vs double buffering with two Togl widgets
texture.tcl— lets you play with texture mapping options
index.tcl— demo of using color index mode
overlay.tcl— example of using overlay planes (requires overlay hardware)
stereo.tcl— stereo example
gears.tcl— spinning gears demo
-
- -

- To compile the demos, edit the Makefile to suit your system, then - type make demos. - The demos are compiled into shared libraries, - that can are loaded into the Tcl interpreter as Tcl/Tk-extensions. - Demos are started by running the corresponding Tcl script. - To run a demo just type ./double.tcl or ./texture.tcl etc. - - -
-

Stereo Rendering

- -

- Quad-buffered stereo-in-a-window is supported. Quad-buffer stereo - is only available on workstation-class graphics cards - (3Dlabs Wildcat series, - ATI FireGL series, - NVidia Quadro series, - and SGI workstations). - Legacy support for divided-screen stereo on SGI workstations is - available via the -oldstereo option. - Developers for SGI workstations might also like the - - autostereo package to automatically switch the display - in and out of stereo (other systems already do it automatically). -

- Full-screen stereo that gaming graphics cards support (ATI Radeon, - NVidia GeForce) is not supported. - -
-

Common Questions and Problems

- -

- If you have something to add to this section please let us know. - -

Bad Match X errors on Sun systems

-

- There's a bug in Sun's XmuLookupStandardColormap X library function. - If you compile togl.c with the SOLARIS_BUG symbol defined (-DSOLARIS_BUG) - this function call will be omitted. - - -
-

Reporting Bugs

- -

- There is a bug database on the - Togl Project Page. - You may also discuss bugs on the mailing list. -

- When reporting bugs please provide as much information as possible. - Also, it's very helpful to us if you can provide an example program - which demonstrates the problem. - - -
-

Version History

- -

Version 1.0 — March, 1996

-
    -
  • Initial version -
- -

Version 1.1 (never officially released)

-
    -
  • Added Togl_LoadBitmapFont function -
  • Fixed a few bugs -
- -

Version 1.2 — November, 1996

-
    -
  • added swapbuffers and makecurrent Tcl commands -
  • More bug fixes -
  • Upgraded to support Tcl 7.6 and Tk 4.2 -
  • Added stereo and overlay plane support -
  • Added Togl_Get/SetClientData() functions -
  • Added Togl_DestroyFunc() -
- -

Version 1.3 — May 2, 1997

-
    -
  • fixed a bug in Togl_Configure() -
  • fixed a compilation problem in using Tcl_PkgProvide() with Tcl < 7.4 -
  • new overlay functions: Togl_ExistsOverlay, Togl_GetOverlayTransparentValue, - Togl_IsMappedOverlay, Togl_AllocColorOverlay, Togl_FreeColorOverlay -
  • added X11 functions: Togl_Display, Togl_Screen, Togl_ScreenNumber, - Togl_Colormap -
  • added Togl_DumpToEpsFile function -
  • fixed a C++ compilation problem -
  • more robust overlay code -
  • added timers (Togl_TimerFunc) from Peter Dern and Elmar Gerwalin -
- -

Version 1.4 — September 17, 1997

-
    -
  • Ported to Windows NT (Robert Casto) -
  • Updated for Tcl/Tk 8.0 -
  • Added many config flags (-redsize, -depthsize, etc) (Matthias Ott) -
  • Added Togl_Set*Func() functions to reassign callback functions (Matthias Ott) -
  • Added Togl_ResetDefaultCallbacks() and Togl_ClientData() functions (Greg Couch) -
- -

Version 1.5 — September 18, 1998

-
    -
  • Fixed a few Unix and Windows compilation bugs -
  • Added Ben Evan's SGI stereo functions -
  • Multiple expose events now reduced to one redraw -
  • Destroying Togl widgets caused problems, patched by Adrian J. Chung -
  • Added Togl_TkWin() function -
  • Updated for Tcl/Tk 8.0p2 -
  • Added gears demo from Philip Quaife -
  • Added -sharelist and -sharecontext config flags -
  • Fixed a few overlay update bugs -
  • Added -indirect config flag -
- -

Version 1.6 — May 7, 2003

-
    -
  • Added Togl_SetTimerFunc function -
  • Updated for Tcl/Tk 8.0.5 and 8.1 -
  • Context sharing added for Windows -
  • Macintosh support (by Paul Thiessen) -
  • Tcl/Tk stubs support — see README.tcl (by Jonas Beskow) -
- -

Version 1.7 — Jan 2006

-
    -
  • Added Mac OS X support -
  • Enabled asking for quad-buffered stereo pixel formats on all platforms - (use -oldstereo on SGIs for splitscreen stereo — C API changed too) -
  • Configuring the cursor is no longer slow -
  • Added -pixelformat config flag -
  • Added setgrid support (unfortunately many window managers can't cope with 1x1 pixel grid) -
  • Only free context when last reference is gone -
  • Switched to TEA-based configure (instead of editing make files) -
- -

Version 2.0 — ??? 2006

- - -
-

Future plans

-
    -
  • add callback command options for create/display/reshape/destroy -
  • add vertical sync control -
  • multisampling support (can be worked-around by passing in a pixelformat) -
  • replace EPS support with TK photo image support -
  • simplify C API by requiring callback command options -
  • stubify C API -
  • Use Tcl object interface for callbacks -
  • allow (require?) private colormap to given with TK photo image -
- - -
-

Contributors

- -

- Several people have contributed new features to Togl. Among them are: - -

    -
  • Ramon Ramsan — overlay plane support -
  • Miguel A. De Riera Pasenau — more overlay functions, X11 functions - and EPS output -
  • Peter Dern and Elmar Gerwalin — Togl_TimerFunc and related code -
  • Robert Casto — Windows NT port -
  • Geza Groma — Windows 95/NT patches -
  • Ben Evans — SGI stereo support -
  • Paul Thiessen — Macintosh support -
  • Jonas Beskow — Tcl/Tk stubs support -
  • Paul Kienzle — TEA debugging and patches -
  • Greg Couch — version 1.7 -
- - Many others have contributed bug fixes. Thanks for your contributions! - -
-
- Last edited on 25 October 2005 by Greg Couch. - - - diff --git a/ng/Togl-1.7/aclocal.m4 b/ng/Togl-1.7/aclocal.m4 deleted file mode 100644 index 0b057391..00000000 --- a/ng/Togl-1.7/aclocal.m4 +++ /dev/null @@ -1,9 +0,0 @@ -# -# Include the TEA standard macro set -# - -builtin(include,tclconfig/tcl.m4) - -# -# Add here whatever m4 macros you want to define for your package -# diff --git a/ng/Togl-1.7/ben.rgb b/ng/Togl-1.7/ben.rgb deleted file mode 100644 index 4eb067a2..00000000 Binary files a/ng/Togl-1.7/ben.rgb and /dev/null differ diff --git a/ng/Togl-1.7/configure.in b/ng/Togl-1.7/configure.in deleted file mode 100644 index 5a89c64a..00000000 --- a/ng/Togl-1.7/configure.in +++ /dev/null @@ -1,222 +0,0 @@ -#!/bin/bash -norc -dnl This file is an input file used by the GNU "autoconf" program to -dnl generate the file "configure", which is run during Tcl installation -dnl to configure the system for the local environment. -# -# RCS: @(#) $Id: configure.in,v 1.6 2006/01/06 00:09:00 gregcouch Exp $ - -#----------------------------------------------------------------------- -# Sample configure.in for Tcl Extensions. The only places you should -# need to modify this file are marked by the string __CHANGE__ -#----------------------------------------------------------------------- - -#----------------------------------------------------------------------- -# __CHANGE__ -# Set your package name and version numbers here. -# -# This initializes the environment with PACKAGE_NAME and PACKAGE_VERSION -# set as provided. These will also be added as -D defs in your Makefile -# so you can encode the package version directly into the source files. -#----------------------------------------------------------------------- - -AC_INIT([Togl], [1.7]) - -#-------------------------------------------------------------------- -# Call TEA_INIT as the first TEA_ macro to set up initial vars. -# This will define a ${TEA_PLATFORM} variable == "unix" or "windows" -# as well as PKG_LIB_FILE and PKG_STUB_LIB_FILE. -#-------------------------------------------------------------------- - -TEA_INIT([3.4]) - -AC_CONFIG_AUX_DIR(tclconfig) - -#-------------------------------------------------------------------- -# Load the tclConfig.sh file -#-------------------------------------------------------------------- - -TEA_PATH_TCLCONFIG -TEA_LOAD_TCLCONFIG - -#-------------------------------------------------------------------- -# Load the tkConfig.sh file if necessary (Tk extension) -#-------------------------------------------------------------------- - -TEA_PATH_TKCONFIG -TEA_LOAD_TKCONFIG - -#----------------------------------------------------------------------- -# Handle the --prefix=... option by defaulting to what Tcl gave. -# Must be called after TEA_LOAD_TCLCONFIG and before TEA_SETUP_COMPILER. -#----------------------------------------------------------------------- - -TEA_PREFIX - -#----------------------------------------------------------------------- -# Standard compiler checks. -# This sets up CC by using the CC env var, or looks for gcc otherwise. -# This also calls AC_PROG_CC, AC_PROG_INSTALL and a few others to create -# the basic setup necessary to compile executables. -#----------------------------------------------------------------------- - -TEA_SETUP_COMPILER - -#----------------------------------------------------------------------- -# __CHANGE__ -# Specify the C source files to compile in TEA_ADD_SOURCES, -# public headers that need to be installed in TEA_ADD_HEADERS, -# stub library C source files to compile in TEA_ADD_STUB_SOURCES, -# and runtime Tcl library files in TEA_ADD_TCL_SOURCES. -# This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS -# and PKG_TCL_SOURCES. -#----------------------------------------------------------------------- - -TEA_ADD_SOURCES([togl.c]) -# togl_ws.h is added in Makefile.in because it is generated -TEA_ADD_HEADERS([togl.h]) -TEA_ADD_INCLUDES([]) -TEA_ADD_LIBS([]) -TEA_ADD_CFLAGS([]) -TEA_ADD_STUB_SOURCES([]) -TEA_ADD_TCL_SOURCES([]) - -#-------------------------------------------------------------------- -# __CHANGE__ -# A few miscellaneous platform-specific items: -# -# Define a special symbol for Windows (BUILD_sample in this case) so -# that we create the export library with the dll. -# -# Windows creates a few extra files that need to be cleaned up. -# You can add more files to clean if your extension creates any extra -# files. -# -# TEA_ADD_* any platform specific compiler/build info here. -#-------------------------------------------------------------------- - -if test "${TEA_PLATFORM}" = "windows" ; then - AC_DEFINE(BUILD_togl, 1, [Build windows export dll]) - CLEANFILES="pkgIndex.tcl togl_ws.h *.lib *.dll *.exp *.ilk *.pdb vc*.pch" - #TEA_ADD_SOURCES([win/winFile.c]) - #TEA_ADD_INCLUDES([-I\"$(${CYGPATH} ${srcdir}/win)\"]) -else - CLEANFILES="pkgIndex.tcl togl_ws.h so_locations" - #TEA_ADD_SOURCES([unix/unixFile.c]) - #TEA_ADD_LIBS([-lsuperfly]) -fi -AC_SUBST(CLEANFILES) - -#-------------------------------------------------------------------- -# __CHANGE__ -# Choose which headers you need. Extension authors should try very -# hard to only rely on the Tcl public header files. Internal headers -# contain private data structures and are subject to change without -# notice. -# This MUST be called after TEA_LOAD_TCLCONFIG / TEA_LOAD_TKCONFIG -#-------------------------------------------------------------------- - -TEA_PUBLIC_TCL_HEADERS -#TEA_PRIVATE_TCL_HEADERS - -#TEA_PUBLIC_TK_HEADERS -TEA_PRIVATE_TK_HEADERS -TEA_PATH_X - -#-------------------------------------------------------------------- -# __CHANGE__ -# Choose OpenGL platform -#-------------------------------------------------------------------- - -case "${TEA_WINDOWINGSYSTEM}" in - aqua) - AC_SUBST(TOGL_WINDOWINGSYSTEM,TOGL_AGL) - TEA_ADD_LIBS([-framework AGL -framework OpenGL -framework ApplicationServices]) - # libGLU is implicit in OpenGL framework - LIBGLU= - ;; - x11) - AC_SUBST(TOGL_WINDOWINGSYSTEM,TOGL_X11) - TEA_ADD_LIBS([-lGL -lXmu]) - LIBGLU=-lGLU - ;; - win32) - AC_SUBST(TOGL_WINDOWINGSYSTEM,TOGL_WGL) - TEA_ADD_LIBS([opengl32.lib user32.lib gdi32.lib]) - if test "$GCC" = "yes" ; then - LIBGLU=-lglu32 - else - LIBGLU=glu32.lib - fi - ;; - *) - AC_MSG_ERROR([Unsupported windowing system: ${TEA_WINDOWINGSYSTEM}]) - ;; -esac -AC_SUBST(LIBGLU) - -#-------------------------------------------------------------------- -# Check whether --enable-threads or --disable-threads was given. -# This auto-enables if Tcl was compiled threaded. -#-------------------------------------------------------------------- - -TEA_ENABLE_THREADS - -#-------------------------------------------------------------------- -# The statement below defines a collection of symbols related to -# building as a shared library instead of a static library. -#-------------------------------------------------------------------- - -TEA_ENABLE_SHARED - -#-------------------------------------------------------------------- -# This macro figures out what flags to use with the compiler/linker -# when building shared/static debug/optimized objects. This information -# can be taken from the tclConfig.sh file, but this figures it all out. -#-------------------------------------------------------------------- - -TEA_CONFIG_CFLAGS -# should be part of TEA_CONFIG_CFLAGS, but more visible modification here -AC_SUBST(SHLIB_SUFFIX) - -#-------------------------------------------------------------------- -# Set the default compiler switches based on the --enable-symbols option. -#-------------------------------------------------------------------- - -TEA_ENABLE_SYMBOLS - -#-------------------------------------------------------------------- -# Everyone should be linking against the Tcl stub library. If you -# can't for some reason, remove this definition. If you aren't using -# stubs, you also need to modify the SHLIB_LD_LIBS setting below to -# link against the non-stubbed Tcl library. Add Tk too if necessary. -#-------------------------------------------------------------------- - -AC_DEFINE(USE_TCL_STUBS, 1, [Use Tcl stubs]) -AC_DEFINE(USE_TK_STUBS, 1, [Use Tk stubs]) - -#-------------------------------------------------------------------- -# This macro generates a line to use when building a library. It -# depends on values set by the TEA_ENABLE_SHARED, TEA_ENABLE_SYMBOLS, -# and TEA_LOAD_TCLCONFIG macros above. -#-------------------------------------------------------------------- - -TEA_MAKE_LIB - -#-------------------------------------------------------------------- -# Determine the name of the tclsh and/or wish executables in the -# Tcl and Tk build directories or the location they were installed -# into. These paths are used to support running test cases only, -# the Makefile should not be making use of these paths to generate -# a pkgIndex.tcl file or anything else at extension build time. -#-------------------------------------------------------------------- - -TEA_PROG_TCLSH -TEA_PROG_WISH - -#-------------------------------------------------------------------- -# Finally, substitute all of the various values into the Makefile. -# You may alternatively have a special pkgIndex.tcl.in or other files -# which require substituting th AC variables in. Include these here. -#-------------------------------------------------------------------- - -AC_OUTPUT([Makefile pkgIndex.tcl togl_ws.h]) diff --git a/ng/Togl-1.7/double.c b/ng/Togl-1.7/double.c deleted file mode 100644 index ba072570..00000000 --- a/ng/Togl-1.7/double.c +++ /dev/null @@ -1,280 +0,0 @@ -/* $Id: double.c,v 1.14 2005/04/23 07:49:13 gregcouch Exp $ */ - -/* - * Togl - a Tk OpenGL widget - * Copyright (C) 1996-1997 Brian Paul and Ben Bederson - * See the LICENSE file for copyright details. - */ - -#include "togl.h" -#include -#include - -/* - * The following variable is a special hack that is needed in order for - * Sun shared libraries to be used for Tcl. - */ -#ifdef SUN -extern int matherr(); -int *tclDummyMathPtr = (int *) matherr; -#endif - -static GLuint FontBase; -static float xAngle = 0.0, yAngle = 0.0, zAngle = 0.0; -static GLfloat CornerX, CornerY, CornerZ; /* where to print strings */ - - -/* - * Togl widget create callback. This is called by Tcl/Tk when the widget has - * been realized. Here's where one may do some one-time context setup or - * initializations. - */ -void -create_cb(Togl *togl) -{ - - FontBase = Togl_LoadBitmapFont(togl, TOGL_BITMAP_8_BY_13); - if (!FontBase) { - printf("Couldn't load font!\n"); - exit(1); - } -} - - -/* - * Togl widget reshape callback. This is called by Tcl/Tk when the widget - * has been resized. Typically, we call glViewport and perhaps setup the - * projection matrix. - */ -void -reshape_cb(Togl *togl) -{ - int width = Togl_Width(togl); - int height = Togl_Height(togl); - float aspect = (float) width / (float) height; - - glViewport(0, 0, width, height); - - /* Set up projection transform */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(-aspect, aspect, -1.0, 1.0, 1.0, 10.0); - - CornerX = -aspect; - CornerY = -1.0; - CornerZ = -1.1; - - /* Change back to model view transform for rendering */ - glMatrixMode(GL_MODELVIEW); -} - - - -static void -print_string(const char *s) -{ - glCallLists(strlen(s), GL_UNSIGNED_BYTE, s); -} - - -/* - * Togl widget display callback. This is called by Tcl/Tk when the widget's - * contents have to be redrawn. Typically, we clear the color and depth - * buffers, render our objects, then swap the front/back color buffers. - */ -void -display_cb(Togl *togl) -{ - static GLuint cubeList = 0; - const char *ident; - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glLoadIdentity(); /* Reset modelview matrix to the identity - * matrix */ - glTranslatef(0.0, 0.0, -3.0); /* Move the camera back three units */ - glRotatef(xAngle, 1.0, 0.0, 0.0); /* Rotate by X, Y, and Z angles */ - glRotatef(yAngle, 0.0, 1.0, 0.0); - glRotatef(zAngle, 0.0, 0.0, 1.0); - - glEnable(GL_DEPTH_TEST); - - if (!cubeList) { - cubeList = glGenLists(1); - glNewList(cubeList, GL_COMPILE); - - /* Front face */ - glBegin(GL_QUADS); - glColor3f(0.0, 0.7, 0.1); /* Green */ - glVertex3f(-1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - glVertex3f(-1.0, -1.0, 1.0); - /* Back face */ - glColor3f(0.9, 1.0, 0.0); /* Yellow */ - glVertex3f(-1.0, 1.0, -1.0); - glVertex3f(1.0, 1.0, -1.0); - glVertex3f(1.0, -1.0, -1.0); - glVertex3f(-1.0, -1.0, -1.0); - /* Top side face */ - glColor3f(0.2, 0.2, 1.0); /* Blue */ - glVertex3f(-1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, -1.0); - glVertex3f(-1.0, 1.0, -1.0); - /* Bottom side face */ - glColor3f(0.7, 0.0, 0.1); /* Red */ - glVertex3f(-1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, -1.0); - glVertex3f(-1.0, -1.0, -1.0); - glEnd(); - - glEndList(); - - } - glCallList(cubeList); - - glDisable(GL_DEPTH_TEST); - glLoadIdentity(); - glColor3f(1.0, 1.0, 1.0); - glRasterPos3f(CornerX, CornerY, CornerZ); - glListBase(FontBase); - ident = Togl_Ident(togl); - if (strcmp(ident, "Single") == 0) { - print_string("Single buffered"); - } else { - print_string("Double buffered"); - } - Togl_SwapBuffers(togl); -} - - - - -int -setXrot_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName setXrot ?angle?\"", - TCL_STATIC); - return TCL_ERROR; - } - - xAngle = atof(argv[2]); - - /* printf( "before %f ", xAngle ); */ - - if (xAngle < 0.0) { - xAngle += 360.0; - } else if (xAngle > 360.0) { - xAngle -= 360.0; - } - - /* printf( "after %f \n", xAngle ); */ - - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - - -int -setYrot_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName setYrot ?angle?\"", - TCL_STATIC); - return TCL_ERROR; - } - - yAngle = atof(argv[2]); - - if (yAngle < 0.0) { - yAngle += 360.0; - } else if (yAngle > 360.0) { - yAngle -= 360.0; - } - - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - -int -getXrot_cb(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) -{ - sprintf(interp->result, "%d", (int) xAngle); - return TCL_OK; -} - -int -getYrot_cb(ClientData clientData, Tcl_Interp *interp, int argc, char *argv[]) -{ - sprintf(interp->result, "%d", (int) yAngle); - return TCL_OK; -} - -/* - * Called by Tk_Main() to let me initialize the modules (Togl) I will need. - */ -TOGL_EXTERN int -Double_Init(Tcl_Interp *interp) -{ -#ifdef USE_TCL_STUBS - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif -#ifdef USE_TK_STUBS - if (Tk_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif - - if (Togl_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } -#ifdef macintosh - Togl_MacSetupMainInterp(interp); -#endif - - /* - * Specify the C callback functions for widget creation, display, - * and reshape. - */ - Togl_CreateFunc(create_cb); - Togl_DisplayFunc(display_cb); - Togl_ReshapeFunc(reshape_cb); - - /* - * Make a new Togl widget command so the Tcl code can set a C variable. - */ - - Togl_CreateCommand("setXrot", setXrot_cb); - Togl_CreateCommand("setYrot", setYrot_cb); - - /* - * Call Tcl_CreateCommand for application-specific commands, if - * they weren't already created by the init procedures called above. - */ - - Tcl_CreateCommand(interp, "getXrot", (Tcl_CmdProc *) getXrot_cb, - (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateCommand(interp, "getYrot", (Tcl_CmdProc *) getYrot_cb, - (ClientData) NULL, (Tcl_CmdDeleteProc *) NULL); - return TCL_OK; -} diff --git a/ng/Togl-1.7/double.tcl b/ng/Togl-1.7/double.tcl deleted file mode 100644 index 88987f7c..00000000 --- a/ng/Togl-1.7/double.tcl +++ /dev/null @@ -1,103 +0,0 @@ -#!/bin/sh -# the next line restarts using wish \ -exec wish "$0" "$@" - -# $Id: double.tcl,v 1.5 2001/12/20 13:59:31 beskow Exp $ - -# Togl - a Tk OpenGL widget -# Copyright (C) 1996 Brian Paul and Ben Bederson -# See the LICENSE file for copyright details. - - -# $Log: double.tcl,v $ -# Revision 1.5 2001/12/20 13:59:31 beskow -# Improved error-handling in togl.c in case of window creation failure -# Added pkgIndex target to makefile -# Updated documentation to reflect stubs-interface (Togl.html + new README.stubs) -# Added tk8.4a3 headers -# Removed obsolete Tk internal headers -# -# Revision 1.4 2001/01/29 18:11:53 brianp -# Jonas Beskow's changes to use Tcl/Tk stub interface -# -# Revision 1.3 1998/03/12 03:52:31 brianp -# now sharing display lists between the widgets -# -# Revision 1.2 1996/10/23 23:31:56 brianp -# added -ident options to togl calls -# -# Revision 1.1 1996/10/23 23:17:22 brianp -# Initial revision -# - - -# An Tk/OpenGL widget demo with two windows, one single buffered and the -# other double buffered. - -load [file dirname [info script]]/double[info sharedlibextension] - -proc setup {} { - wm title . "Single vs Double Buffering" - - frame .f1 - - # create first Togl widget - togl .f1.o1 -width 200 -height 200 -rgba true -double false -depth true -ident Single - - # create second Togl widget, share display lists with first widget - togl .f1.o2 -width 200 -height 200 -rgba true -double true -depth true -ident Double -sharelist Single - - scale .sx -label {X Axis} -from 0 -to 360 -command {setAngle x} -orient horizontal - scale .sy -label {Y Axis} -from 0 -to 360 -command {setAngle y} -orient horizontal - button .btn -text Quit -command exit - - bind .f1.o1 { - motion_event [lindex [%W config -width] 4] \ - [lindex [%W config -height] 4] \ - %x %y - } - - bind .f1.o2 { - motion_event [lindex [%W config -width] 4] \ - [lindex [%W config -height] 4] \ - %x %y - } - - pack .f1.o1 .f1.o2 -side left -padx 3 -pady 3 -fill both -expand t - pack .f1 -fill both -expand t - pack .sx -fill x - pack .sy -fill x - pack .btn -fill x -} - - - -# This is called when mouse button 1 is pressed and moved in either of -# the OpenGL windows. -proc motion_event { width height x y } { - .f1.o1 setXrot [expr 360.0 * $y / $height] - .f1.o2 setXrot [expr 360.0 * $y / $height] - .f1.o1 setYrot [expr 360.0 * ($width - $x) / $width] - .f1.o2 setYrot [expr 360.0 * ($width - $x) / $width] - -# .sx set [expr 360.0 * $y / $height] -# .sy set [expr 360.0 * ($width - $x) / $width] - - .sx set [getXrot] - .sy set [getYrot] -} - -# This is called when a slider is changed. -proc setAngle {axis value} { - global xAngle yAngle zAngle - - switch -exact $axis { - x {.f1.o1 setXrot $value - .f1.o2 setXrot $value} - y {.f1.o1 setYrot $value - .f1.o2 setYrot $value} - } -} - -# Execution starts here! -setup diff --git a/ng/Togl-1.7/gears.c b/ng/Togl-1.7/gears.c deleted file mode 100644 index 9999a720..00000000 --- a/ng/Togl-1.7/gears.c +++ /dev/null @@ -1,402 +0,0 @@ -/* gears.c */ - -/* - * 3-D gear wheels. This program is in the public domain. - * - * Brian Paul - * - * - * Modified to work under Togl as a widget for TK 1997 - * - * Philip Quaife - * - */ - -#include "togl.h" -#include -#include -#include - -#ifndef M_PI -# define M_PI 3.14159265 -#endif - -struct WHIRLYGIZMO -{ - GLint Gear1, Gear2, Gear3; - GLfloat Rotx, Roty, Rotz; - GLfloat Angle; - int Height, Width; -}; - -/* - * Draw a gear wheel. You'll probably want to call this function when - * building a display list since we do a lot of trig here. - * - * Input: inner_radius - radius of hole at center - * outer_radius - radius at center of teeth - * width - width of gear - * teeth - number of teeth - * tooth_depth - depth of tooth - */ -static void -gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, - GLint teeth, GLfloat tooth_depth) -{ - GLint i; - GLfloat r0, r1, r2; - GLfloat angle, da; - GLfloat u, v, len; - - r0 = inner_radius; - r1 = outer_radius - tooth_depth / 2.0; - r2 = outer_radius + tooth_depth / 2.0; - - da = 2.0 * M_PI / teeth / 4.0; - - glShadeModel(GL_FLAT); - - glNormal3f(0.0, 0.0, 1.0); - - /* draw front face */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.0 * M_PI / teeth; - glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); - glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); - glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), - width * 0.5); - } - glEnd(); - - /* draw front sides of teeth */ - glBegin(GL_QUADS); - da = 2.0 * M_PI / teeth / 4.0; - for (i = 0; i < teeth; i++) { - angle = i * 2.0 * M_PI / teeth; - - glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); - glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); - glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), - width * 0.5); - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), - width * 0.5); - } - glEnd(); - - - glNormal3f(0.0, 0.0, -1.0); - - /* draw back face */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.0 * M_PI / teeth; - glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); - glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), - -width * 0.5); - glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); - } - glEnd(); - - /* draw back sides of teeth */ - glBegin(GL_QUADS); - da = 2.0 * M_PI / teeth / 4.0; - for (i = 0; i < teeth; i++) { - angle = i * 2.0 * M_PI / teeth; - - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), - -width * 0.5); - glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), - -width * 0.5); - glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); - glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); - } - glEnd(); - - - /* draw outward faces of teeth */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i < teeth; i++) { - angle = i * 2.0 * M_PI / teeth; - - glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); - glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); - u = r2 * cos(angle + da) - r1 * cos(angle); - v = r2 * sin(angle + da) - r1 * sin(angle); - len = sqrt(u * u + v * v); - u /= len; - v /= len; - glNormal3f(v, -u, 0.0); - glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); - glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); - glNormal3f(cos(angle), sin(angle), 0.0); - glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), - width * 0.5); - glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), - -width * 0.5); - u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da); - v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da); - glNormal3f(v, -u, 0.0); - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), - width * 0.5); - glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), - -width * 0.5); - glNormal3f(cos(angle), sin(angle), 0.0); - } - - glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5); - glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5); - - glEnd(); - - - glShadeModel(GL_SMOOTH); - - /* draw inside radius cylinder */ - glBegin(GL_QUAD_STRIP); - for (i = 0; i <= teeth; i++) { - angle = i * 2.0 * M_PI / teeth; - glNormal3f(-cos(angle), -sin(angle), 0.0); - glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); - glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); - } - glEnd(); - -} - -/* - * static GLfloat view_rotx=20.0, view_roty=30.0, view_rotz=0.0; static GLint - * gear1, gear2, gear3; static GLfloat angle = 0.0; */ -static GLuint limit; -static GLuint count = 1; - -static GLubyte polycolor[4] = { 255, 255, 255, 255 }; - -static void -draw(Togl *togl) -{ - struct WHIRLYGIZMO *Wg; - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - Wg = Togl_GetClientData(togl); - glDisable(GL_TEXTURE_2D); - glPushMatrix(); - glRotatef(Wg->Rotx, 1.0, 0.0, 0.0); - glRotatef(Wg->Roty, 0.0, 1.0, 0.0); - glRotatef(Wg->Rotz, 0.0, 0.0, 1.0); - - glPushMatrix(); - glTranslatef(-3.0, -2.0, 0.0); - glRotatef(Wg->Angle, 0.0, 0.0, 1.0); - glEnable(GL_DEPTH_TEST); - glCallList(Wg->Gear1); - glEnable(GL_DEPTH_TEST); - glPopMatrix(); - - glPushMatrix(); - glTranslatef(3.1, -2.0, 0.0); - glRotatef(-2.0 * Wg->Angle - 9.0, 0.0, 0.0, 1.0); - glCallList(Wg->Gear2); - glPopMatrix(); - - glPushMatrix(); - glTranslatef(-3.1, 4.2, 0.0); - glRotatef(-2.0 * Wg->Angle - 25.0, 0.0, 0.0, 1.0); - glCallList(Wg->Gear3); - glPopMatrix(); - - glPopMatrix(); - - Togl_SwapBuffers(togl); - -} - - -static void -zap(Togl *togl) -{ - struct WHIRLYGIZMO *Wg; - - Wg = Togl_GetClientData(togl); - free(Wg); -} - - -static void -idle(Togl *togl) -{ - struct WHIRLYGIZMO *Wg; - - Wg = Togl_GetClientData(togl); - Wg->Angle += 2.0; - Togl_PostRedisplay(togl); -} - - -/* change view angle, exit upon ESC */ -/* - * static GLenum key(int k, GLenum mask) { switch (k) { case TK_UP: view_rotx - * += 5.0; return GL_TRUE; case TK_DOWN: view_rotx -= 5.0; return GL_TRUE; case - * TK_LEFT: view_roty += 5.0; return GL_TRUE; case TK_RIGHT: view_roty -= 5.0; - * return GL_TRUE; case TK_z: view_rotz += 5.0; return GL_TRUE; case TK_Z: - * view_rotz -= 5.0; return GL_TRUE; } return GL_FALSE; } */ - -/* new window size or exposure */ -static void -reshape(Togl *togl) -{ - int width, height; - - width = Togl_Width(togl); - height = Togl_Height(togl); - glViewport(0, 0, (GLint) width, (GLint) height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - if (width > height) { - GLfloat w = (GLfloat) width / (GLfloat) height; - - glFrustum(-w, w, -1.0, 1.0, 5.0, 60.0); - } else { - GLfloat h = (GLfloat) height / (GLfloat) width; - - glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0); - } - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.0, 0.0, -40.0); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - -} - - -static void -init(Togl *togl) -{ - struct WHIRLYGIZMO *Wg; - - static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 }; - static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 }; - static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 }; - static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 }; - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glEnable(GL_CULL_FACE); - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_DEPTH_TEST); - /* make the gears */ - Wg = malloc(sizeof (*Wg)); - if (!Wg) { - Tcl_SetResult(Togl_Interp(togl), - "\"Cannot allocate client data for widget\"", TCL_STATIC); - } - Wg->Gear1 = glGenLists(1); - glNewList(Wg->Gear1, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); - gear(1.0, 4.0, 1.0, 20, 0.7); - glEndList(); - - Wg->Gear2 = glGenLists(1); - glNewList(Wg->Gear2, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); - gear(0.5, 2.0, 2.0, 10, 0.7); - glEndList(); - - Wg->Gear3 = glGenLists(1); - glNewList(Wg->Gear3, GL_COMPILE); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); - gear(1.3, 2.0, 0.5, 10, 0.7); - glEndList(); - - glEnable(GL_NORMALIZE); - Wg->Height = Togl_Height(togl); - Wg->Width = Togl_Width(togl); - Wg->Angle = 0.0; - Wg->Rotx = 0.0; - Wg->Roty = 0.0; - Wg->Rotz = 0.0; - Togl_SetClientData(togl, (ClientData) Wg); -} - -int -position(Togl *togl, int argc, CONST84 char *argv[]) -{ - struct WHIRLYGIZMO *Wg; - Tcl_Interp *interp = Togl_Interp(togl); - char Result[100]; - - Wg = Togl_GetClientData(togl); - /* error checking */ - if (argc != 2) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName \"", TCL_STATIC); - return TCL_ERROR; - } - - /* Let result string equal value */ - sprintf(Result, "%g %g", Wg->Roty, Wg->Rotx); - - Tcl_SetResult(interp, Result, TCL_VOLATILE); - return TCL_OK; -} - -int -rotate(Togl *togl, int argc, CONST84 char *argv[]) -{ - struct WHIRLYGIZMO *Wg; - Tcl_Interp *interp = Togl_Interp(togl); - - Wg = Togl_GetClientData(togl); - /* error checking */ - if (argc != 4) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName xrot yrot\"", TCL_STATIC); - return TCL_ERROR; - } - - Wg->Roty = atof(argv[2]); - Wg->Rotx = atof(argv[3]); - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - -TOGL_EXTERN int -Gears_Init(Tcl_Interp *interp) -{ - /* - * Initialize Tcl, Tk, and the Togl widget module. - */ -#ifdef USE_TCL_STUBS - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif -#ifdef USE_TK_STUBS - if (Tk_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif - - if (Togl_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } - - /* - * Specify the C callback functions for widget creation, display, - * and reshape. - */ - Togl_CreateFunc(init); - Togl_DestroyFunc(zap); - Togl_DisplayFunc(draw); - Togl_ReshapeFunc(reshape); - Togl_TimerFunc(idle); - Togl_CreateCommand("rotate", rotate); - Togl_CreateCommand("position", position); - return TCL_OK; -} diff --git a/ng/Togl-1.7/gears.tcl b/ng/Togl-1.7/gears.tcl deleted file mode 100755 index ddb2729d..00000000 --- a/ng/Togl-1.7/gears.tcl +++ /dev/null @@ -1,76 +0,0 @@ -#!/bin/sh -# the next line restarts using wish \ -exec wish "$0" "$@" - -# Togl - a Tk OpenGL widget -# Copyright (C) 1996-1997 Brian Paul and Ben Bederson -# See the LICENSE file for copyright details. - - -# -# Test Togl using GL Gears Demo -# -# Copyright (C) 1997 Philip Quaife -# - -load [file dirname [info script]]/gears[info sharedlibextension] - -proc setup {} { - global startx starty xangle0 yangle0 xangle yangle RotCnt - global vTime - set RotCnt 1 - set xangle 0.0 - set yangle 0.0 - set vTime 100 - wm title . "Rotating Gear Widget Test" - - label .t -text "Click and drag to rotate image" - pack .t -side top -padx 2 -pady 10 - frame .f - pack .f -side top - button .f.n1 -text " Add " -command AutoRot - button .f.r1 -text "Remove" -command DelRot - button .f.b1 -text " Quit " -command exit - entry .f.t -width 4 -textvariable vTime - pack .f.n1 .f.t .f.r1 .f.b1 -side left -anchor w -padx 5 - newRot .w0 10 - -} -proc AutoRot {} { - global RotCnt vTime - newRot .w$RotCnt $vTime - set RotCnt [expr $RotCnt + 1] -} - -proc DelRot {} { - global RotCnt vTime - if { $RotCnt != 0 } { - set RotCnt [expr $RotCnt - 1] - destroy .w$RotCnt - } -} - -proc newRot {win {tick 100} } { - togl $win -width 200 -height 200 -rgba true -double true -depth true -privatecmap false -time $tick - bind $win {RotStart %x %y %W} - bind $win {RotMove %x %y %W} - pack $win -expand true -fill both -} - -proc RotStart {x y W } { - global startx starty xangle0 yangle0 xangle yangle - set startx $x - set starty $y - set vPos [$W position] - set xangle0 [lindex $vPos 0] - set yangle0 [lindex $vPos 1] - } - -proc RotMove {x y W} { - global startx starty xangle0 yangle0 xangle yangle - set xangle [expr $xangle0 + ($x - $startx) ] - set yangle [expr $yangle0 + ($y - $starty) ] - $W rotate $xangle $yangle - } - -setup diff --git a/ng/Togl-1.7/image.c b/ng/Togl-1.7/image.c deleted file mode 100644 index a4027ce7..00000000 --- a/ng/Togl-1.7/image.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * SGI rgb file reader borrowed from gltk library - */ - -#include "togl.h" /* added by GG to include windows.h */ -#include -#include -#include -#include "image.h" - -#ifndef SEEK_SET -# define SEEK_SET 0 -#endif - - -static void -tkQuit(void) -{ - exit(0); -} - - -/******************************************************************************/ - -typedef struct _rawImageRec -{ - unsigned short imagic; - unsigned short type; - unsigned short dim; - unsigned short sizeX, sizeY, sizeZ; - unsigned long min, max; - unsigned long wasteBytes; - char name[80]; - unsigned long colorMap; - FILE *file; - unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA; - unsigned long rleEnd; - GLuint *rowStart; - GLint *rowSize; -} rawImageRec; - - -/******************************************************************************/ - -static void -ConvertShort(unsigned short *array, long length) -{ - unsigned long b1, b2; - unsigned char *ptr; - - ptr = (unsigned char *) array; - while (length--) { - b1 = *ptr++; - b2 = *ptr++; - *array++ = (b1 << 8) | (b2); - } -} - -static void -ConvertLong(GLuint *array, long length) -{ - unsigned long b1, b2, b3, b4; - unsigned char *ptr; - - ptr = (unsigned char *) array; - while (length--) { - b1 = *ptr++; - b2 = *ptr++; - b3 = *ptr++; - b4 = *ptr++; - *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4); - } -} - -static rawImageRec * -RawImageOpen(char *fileName) -{ - union - { - int testWord; - char testByte[4]; - } endianTest; - rawImageRec *raw; - GLenum swapFlag; - int x; - - endianTest.testWord = 1; - if (endianTest.testByte[0] == 1) { - swapFlag = GL_TRUE; - } else { - swapFlag = GL_FALSE; - } - - raw = (rawImageRec *) malloc(sizeof (rawImageRec)); - if (raw == NULL) { - fprintf(stderr, "Out of memory!\n"); - tkQuit(); - } - if ((raw->file = fopen(fileName, "rb")) == NULL) { - perror(fileName); - tkQuit(); - } - - fread(raw, 1, 12, raw->file); - - if (swapFlag) { - ConvertShort(&raw->imagic, 6); - } - - raw->tmp = (unsigned char *) malloc(raw->sizeX * 256); - raw->tmpR = (unsigned char *) malloc(raw->sizeX * 256); - raw->tmpG = (unsigned char *) malloc(raw->sizeX * 256); - raw->tmpB = (unsigned char *) malloc(raw->sizeX * 256); - raw->tmpA = (unsigned char *) malloc(raw->sizeX * 256); - if (raw->tmp == NULL || raw->tmpR == NULL || raw->tmpG == NULL || - raw->tmpB == NULL || raw->tmpA == NULL) { - fprintf(stderr, "Out of memory!\n"); - tkQuit(); - } - - if ((raw->type & 0xFF00) == 0x0100) { - x = raw->sizeY * raw->sizeZ * sizeof (GLuint); - raw->rowStart = (GLuint *) malloc(x); - raw->rowSize = (GLint *) malloc(x); - if (raw->rowStart == NULL || raw->rowSize == NULL) { - fprintf(stderr, "Out of memory!\n"); - tkQuit(); - } - raw->rleEnd = 512 + (2 * x); - fseek(raw->file, 512, SEEK_SET); - fread(raw->rowStart, 1, x, raw->file); - fread(raw->rowSize, 1, x, raw->file); - if (swapFlag) { - ConvertLong(raw->rowStart, x / sizeof (GLuint)); - ConvertLong((GLuint *) raw->rowSize, x / sizeof (GLint)); - } - } - return raw; -} - -static void -RawImageClose(rawImageRec * raw) -{ - - fclose(raw->file); - free(raw->tmp); - free(raw->tmpR); - free(raw->tmpG); - free(raw->tmpB); - free(raw->tmpA); - free(raw); -} - -static void -RawImageGetRow(rawImageRec * raw, unsigned char *buf, int y, int z) -{ - unsigned char *iPtr, *oPtr, pixel; - int count; - - if ((raw->type & 0xFF00) == 0x0100) { - fseek(raw->file, raw->rowStart[y + z * raw->sizeY], SEEK_SET); - fread(raw->tmp, 1, (unsigned int) raw->rowSize[y + z * raw->sizeY], - raw->file); - - iPtr = raw->tmp; - oPtr = buf; - while (1) { - pixel = *iPtr++; - count = (int) (pixel & 0x7F); - if (!count) { - return; - } - if (pixel & 0x80) { - while (count--) { - *oPtr++ = *iPtr++; - } - } else { - pixel = *iPtr++; - while (count--) { - *oPtr++ = pixel; - } - } - } - } else { - fseek(raw->file, 512 + (y * raw->sizeX) + (z * raw->sizeX * raw->sizeY), - SEEK_SET); - fread(buf, 1, raw->sizeX, raw->file); - } -} - -static void -RawImageGetData(rawImageRec * raw, TK_RGBImageRec * final) -{ - unsigned char *ptr; - int i, j; - - final->data = - (unsigned char *) malloc((raw->sizeX + 1) * (raw->sizeY + 1) * 4); - if (final->data == NULL) { - fprintf(stderr, "Out of memory!\n"); - tkQuit(); - } - - ptr = final->data; - for (i = 0; i < (int) (raw->sizeY); i++) { - RawImageGetRow(raw, raw->tmpR, i, 0); - RawImageGetRow(raw, raw->tmpG, i, 1); - RawImageGetRow(raw, raw->tmpB, i, 2); - if (raw->sizeZ == 4) { - /* 4 components */ - RawImageGetRow(raw, raw->tmpA, i, 3); - for (j = 0; j < (int) (raw->sizeX); j++) { - *ptr++ = *(raw->tmpR + j); - *ptr++ = *(raw->tmpG + j); - *ptr++ = *(raw->tmpB + j); - *ptr++ = *(raw->tmpA + j); - } - } else { - /* 3 components */ - for (j = 0; j < (int) (raw->sizeX); j++) { - *ptr++ = *(raw->tmpR + j); - *ptr++ = *(raw->tmpG + j); - *ptr++ = *(raw->tmpB + j); - } - } - } -} - -TK_RGBImageRec * -tkRGBImageLoad(char *fileName) -{ - rawImageRec *raw; - TK_RGBImageRec *final; - - raw = RawImageOpen(fileName); - final = (TK_RGBImageRec *) malloc(sizeof (TK_RGBImageRec)); - if (final == NULL) { - fprintf(stderr, "Out of memory!\n"); - tkQuit(); - } - final->sizeX = raw->sizeX; - final->sizeY = raw->sizeY; - final->sizeZ = raw->sizeZ; - RawImageGetData(raw, final); - RawImageClose(raw); - return final; -} - -/******************************************************************************/ diff --git a/ng/Togl-1.7/image.h b/ng/Togl-1.7/image.h deleted file mode 100644 index 47babb74..00000000 --- a/ng/Togl-1.7/image.h +++ /dev/null @@ -1,14 +0,0 @@ -/* image.h */ - -#ifndef IMAGE_H -# define IMAGE_H - -typedef struct _TK_RGBImageRec -{ - int sizeX, sizeY, sizeZ; - unsigned char *data; -} TK_RGBImageRec; - -extern TK_RGBImageRec *tkRGBImageLoad(char *fileName); - -#endif diff --git a/ng/Togl-1.7/index.c b/ng/Togl-1.7/index.c deleted file mode 100644 index 8e26e26c..00000000 --- a/ng/Togl-1.7/index.c +++ /dev/null @@ -1,184 +0,0 @@ -/* $Id: index.c,v 1.10 2005/04/23 07:49:13 gregcouch Exp $ */ - -/* - * Togl - a Tk OpenGL widget - * Copyright (C) 1996-1997 Brian Paul and Ben Bederson - * See the LICENSE file for copyright details. - */ - - -/* - * An example Togl program using color-index mode. - */ - - -#include "togl.h" -#include -#include - - -/* - * The following variable is a special hack that is needed in order for - * Sun shared libraries to be used for Tcl. - */ -#ifdef SUN -extern int matherr(); -int *tclDummyMathPtr = (int *) matherr; -#endif - - -/* Our color indexes: */ -static unsigned long black, red, green, blue; - -/* Rotation angle */ -static float Angle = 0.0; - - -/* - * Togl widget create callback. This is called by Tcl/Tk when the widget has - * been realized. Here's where one may do some one-time context setup or - * initializations. - */ -void -create_cb(Togl *togl) -{ - /* allocate color indexes */ - black = Togl_AllocColor(togl, 0.0, 0.0, 0.0); - red = Togl_AllocColor(togl, 1.0, 0.0, 0.0); - green = Togl_AllocColor(togl, 0.0, 1.0, 0.0); - blue = Togl_AllocColor(togl, 0.0, 0.0, 1.0); - - /* If we were using a private read/write colormap we'd setup our color - * table with something like this: */ - /* - * black = 1; Togl_SetColor( togl, black, 0.0, 0.0, 0.0 ); red = 2; - * Togl_SetColor( togl, red, 1.0, 0.0, 0.0 ); green = 3; Togl_SetColor( - * togl, green, 0.0, 1.0, 0.0 ); blue = 4; Togl_SetColor( togl, blue, 0.0, - * 0.0, 1.0 ); */ - - glShadeModel(GL_FLAT); - glDisable(GL_DITHER); -} - - -/* - * Togl widget reshape callback. This is called by Tcl/Tk when the widget - * has been resized. Typically, we call glViewport and perhaps setup the - * projection matrix. - */ -void -reshape_cb(Togl *togl) -{ - int width = Togl_Width(togl); - int height = Togl_Height(togl); - float aspect = (float) width / (float) height; - - glViewport(0, 0, width, height); - - /* Set up projection transform */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(-aspect, aspect, -1.0, 1.0, -1.0, 1.0); - - /* Change back to model view transform for rendering */ - glMatrixMode(GL_MODELVIEW); -} - - -/* - * Togl widget display callback. This is called by Tcl/Tk when the widget's - * contents have to be redrawn. Typically, we clear the color and depth - * buffers, render our objects, then swap the front/back color buffers. - */ -void -display_cb(Togl *togl) -{ - glClearIndex(black); - glClear(GL_COLOR_BUFFER_BIT); - - glPushMatrix(); - glTranslatef(0.3, -0.3, 0.0); - glRotatef(Angle, 0.0, 0.0, 1.0); - glIndexi(red); - glBegin(GL_TRIANGLES); - glVertex2f(-0.5, -0.3); - glVertex2f(0.5, -0.3); - glVertex2f(0.0, 0.6); - glEnd(); - glPopMatrix(); - - glPushMatrix(); - glRotatef(Angle, 0.0, 0.0, 1.0); - glIndexi(green); - glBegin(GL_TRIANGLES); - glVertex2f(-0.5, -0.3); - glVertex2f(0.5, -0.3); - glVertex2f(0.0, 0.6); - glEnd(); - glPopMatrix(); - - glPushMatrix(); - glTranslatef(-0.3, 0.3, 0.0); - glRotatef(Angle, 0.0, 0.0, 1.0); - glIndexi(blue); - glBegin(GL_TRIANGLES); - glVertex2f(-0.5, -0.3); - glVertex2f(0.5, -0.3); - glVertex2f(0.0, 0.6); - glEnd(); - glPopMatrix(); - - glFlush(); - Togl_SwapBuffers(togl); -} - - -void -timer_cb(Togl *togl) -{ - Angle += 5.0; - Togl_PostRedisplay(togl); -} - - -TOGL_EXTERN int -Index_Init(Tcl_Interp *interp) -{ - /* - * Initialize Tcl, Tk, and the Togl widget module. - */ -#ifdef USE_TCL_STUBS - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif -#ifdef USE_TK_STUBS - if (Tk_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif - - if (Togl_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } - - /* - * Specify the C callback functions for widget creation, display, - * and reshape. - */ - Togl_CreateFunc(create_cb); - Togl_DisplayFunc(display_cb); - Togl_ReshapeFunc(reshape_cb); - Togl_TimerFunc(timer_cb); - - /* - * Make a new Togl widget command so the Tcl code can set a C variable. - */ - /* NONE */ - - /* - * Call Tcl_CreateCommand for application-specific commands, if - * they weren't already created by the init procedures called above. - */ - return TCL_OK; -} diff --git a/ng/Togl-1.7/index.tcl b/ng/Togl-1.7/index.tcl deleted file mode 100644 index ce6b7a7f..00000000 --- a/ng/Togl-1.7/index.tcl +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/sh -# the next line restarts using wish \ -exec wish "$0" "$@" - -# $Id: index.tcl,v 1.5 2001/12/20 13:59:31 beskow Exp $ - -# Togl - a Tk OpenGL widget -# Copyright (C) 1996 Brian Paul and Ben Bederson -# See the LICENSE file for copyright details. - - -# $Log: index.tcl,v $ -# Revision 1.5 2001/12/20 13:59:31 beskow -# Improved error-handling in togl.c in case of window creation failure -# Added pkgIndex target to makefile -# Updated documentation to reflect stubs-interface (Togl.html + new README.stubs) -# Added tk8.4a3 headers -# Removed obsolete Tk internal headers -# -# Revision 1.4 2001/01/29 18:11:53 brianp -# Jonas Beskow's changes to use Tcl/Tk stub interface -# -# Revision 1.3 1998/01/24 14:05:50 brianp -# added quit button (Ben Bederson) -# -# Revision 1.2 1997/04/11 01:37:34 brianp -# added a timer to rotate the triangles -# -# Revision 1.1 1996/10/23 23:18:11 brianp -# Initial revision -# - - -# A Tk/OpenGL widget demo using color-index mode. - -load [file dirname [info script]]/index[info sharedlibextension] - -proc setup {} { - wm title . "Color index demo" - - togl .win -width 200 -height 200 -rgba false -double true -privatecmap false -time 10 - button .btn -text Quit -command exit - - pack .win -expand true -fill both - pack .btn -expand true -fill both -} - - - -# Execution starts here! -setup diff --git a/ng/Togl-1.7/overlay.c b/ng/Togl-1.7/overlay.c deleted file mode 100644 index c4f403ff..00000000 --- a/ng/Togl-1.7/overlay.c +++ /dev/null @@ -1,194 +0,0 @@ -/* $Id: overlay.c,v 1.7 2005/04/23 07:49:13 gregcouch Exp $ */ - -/* - * Togl - a Tk OpenGL widget - * Copyright (C) 1996-1997 Brian Paul and Ben Bederson - * See the LICENSE file for copyright details. - */ - - -/* - * An example Togl program using an overlay. - */ - - -#include "togl.h" -#include -#include - - -/* - * The following variable is a special hack that is needed in order for - * Sun shared libraries to be used for Tcl. - */ -#ifdef SUN -extern int matherr(); -int *tclDummyMathPtr = (int *) matherr; -#endif - - -/* Overlay color indexes: */ -static unsigned long Red, Green; - - -/* - * Togl widget create callback. This is called by Tcl/Tk when the widget has - * been realized. Here's where one may do some one-time context setup or - * initializations. - */ -void -create_cb(Togl *togl) -{ - /* allocate overlay color indexes */ - Red = Togl_AllocColorOverlay(togl, 1.0, 0.0, 0.0); - Green = Togl_AllocColorOverlay(togl, 0.0, 1.0, 0.0); - - /* in this demo we always show the overlay */ - if (Togl_ExistsOverlay(togl)) { - Togl_ShowOverlay(togl); - printf("Red and green lines are in the overlay\n"); - } else { - printf("Sorry, this display doesn't support overlays\n"); - } -} - - -/* - * Togl widget reshape callback. This is called by Tcl/Tk when the widget - * has been resized. Typically, we call glViewport and perhaps setup the - * projection matrix. - */ -void -reshape_cb(Togl *togl) -{ - int width = Togl_Width(togl); - int height = Togl_Height(togl); - float aspect = (float) width / (float) height; - - /* Set up viewing for normal plane's context */ - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(-aspect, aspect, -1.0, 1.0, -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - - /* Set up viewing for overlay plane's context */ - if (Togl_ExistsOverlay(togl)) { - Togl_UseLayer(togl, TOGL_OVERLAY); - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); - glMatrixMode(GL_MODELVIEW); - Togl_UseLayer(togl, TOGL_NORMAL); - } -} - - -/* - * Togl widget overlay display callback. This is called by Tcl/Tk when the - * overlay has to be redrawn. - */ -void -overlay_display_cb(Togl *togl) -{ - glClear(GL_COLOR_BUFFER_BIT); - - glIndexi(Red); - glBegin(GL_LINES); - glVertex2f(-1.0, -1.0); - glVertex2f(1.0, 1.0); - glVertex2f(-1.0, 1.0); - glVertex2f(1.0, -1.0); - glEnd(); - - glIndexi(Green); - glBegin(GL_LINE_LOOP); - glVertex2f(-0.5, -0.5); - glVertex2f(0.5, -0.5); - glVertex2f(0.5, 0.5); - glVertex2f(-0.5, 0.5); - glEnd(); - glFlush(); -} - - -/* - * Togl widget display callback. This is called by Tcl/Tk when the widget's - * contents have to be redrawn. Typically, we clear the color and depth - * buffers, render our objects, then swap the front/back color buffers. - */ -void -display_cb(Togl *togl) -{ - glClear(GL_COLOR_BUFFER_BIT); - - glLoadIdentity(); - - glBegin(GL_TRIANGLES); - - glColor3f(1.0, 0.0, 1.0); - glVertex2f(-0.5, -0.3); - glVertex2f(0.5, -0.3); - glVertex2f(0.0, 0.6); - - glColor3f(1.0, 1.0, 0.0); - glVertex2f(-0.5 + 0.2, -0.3 - 0.2); - glVertex2f(0.5 + 0.2, -0.3 - 0.2); - glVertex2f(0.0 + 0.2, 0.6 - 0.2); - - glColor3f(0.0, 1.0, 1.0); - glVertex2f(-0.5 + 0.4, -0.3 - 0.4); - glVertex2f(0.5 + 0.4, -0.3 - 0.4); - glVertex2f(0.0 + 0.4, 0.6 - 0.4); - - glEnd(); - - glFlush(); -} - - -/* - * Called by Tk_Main() to let me initialize the modules (Togl) I will need. - */ -TOGL_EXTERN int -Overlay_Init(Tcl_Interp *interp) -{ - /* - * Initialize Tcl, Tk, and the Togl widget module. - */ -#ifdef USE_TCL_STUBS - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif -#ifdef USE_TK_STUBS - if (Tk_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif - if (Togl_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } - - /* - * Specify the C callback functions for widget creation, display, - * and reshape. - */ - Togl_CreateFunc(create_cb); - Togl_DisplayFunc(display_cb); - Togl_ReshapeFunc(reshape_cb); - - Togl_OverlayDisplayFunc(overlay_display_cb); - - /* - * Make a new Togl widget command so the Tcl code can set a C variable. - */ - /* NONE */ - - /* - * Call Tcl_CreateCommand for application-specific commands, if - * they weren't already created by the init procedures called above. - */ - return TCL_OK; -} diff --git a/ng/Togl-1.7/overlay.tcl b/ng/Togl-1.7/overlay.tcl deleted file mode 100644 index 0be48bc6..00000000 --- a/ng/Togl-1.7/overlay.tcl +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh -# the next line restarts using wish \ -exec wish "$0" "$@" - -# $Id: overlay.tcl,v 1.4 2001/12/20 13:59:31 beskow Exp $ - -# Togl - a Tk OpenGL widget -# Copyright (C) 1996 Brian Paul and Ben Bederson -# See the LICENSE file for copyright details. - - -# $Log: overlay.tcl,v $ -# Revision 1.4 2001/12/20 13:59:31 beskow -# Improved error-handling in togl.c in case of window creation failure -# Added pkgIndex target to makefile -# Updated documentation to reflect stubs-interface (Togl.html + new README.stubs) -# Added tk8.4a3 headers -# Removed obsolete Tk internal headers -# -# Revision 1.3 2001/01/29 18:11:53 brianp -# Jonas Beskow's changes to use Tcl/Tk stub interface -# -# Revision 1.2 1998/01/24 14:05:50 brianp -# added quit button (Ben Bederson) -# -# Revision 1.1 1997/03/07 01:26:38 brianp -# Initial revision -# -# - - -# A Tk/OpenGL widget demo using an overlay. - -load [file dirname [info script]]/overlay[info sharedlibextension] - -proc setup {} { - wm title . "Overlay demo" - - togl .win -width 200 -height 200 -rgba true -double false -overlay true - button .btn -text Quit -command exit - - pack .win -expand true -fill both - pack .btn -expand true -fill both -} - - - -# Execution starts here! -setup diff --git a/ng/Togl-1.7/pkgIndex.tcl.in b/ng/Togl-1.7/pkgIndex.tcl.in deleted file mode 100644 index af071e36..00000000 --- a/ng/Togl-1.7/pkgIndex.tcl.in +++ /dev/null @@ -1,5 +0,0 @@ -# -# Tcl package index file -# -package ifneeded @PACKAGE_NAME@ @PACKAGE_VERSION@ \ - [list load [file join $dir @PKG_LIB_FILE@]] diff --git a/ng/Togl-1.7/stereo.c b/ng/Togl-1.7/stereo.c deleted file mode 100644 index 0a33f1ee..00000000 --- a/ng/Togl-1.7/stereo.c +++ /dev/null @@ -1,352 +0,0 @@ -/* $Id: stereo.c,v 1.6 2005/04/23 07:49:13 gregcouch Exp $ */ - -/* - * Togl - a Tk OpenGL widget - * Copyright (C) 1996-1997 Brian Paul and Ben Bederson - * See the LICENSE file for copyright details. - */ - -#include "togl.h" -#include -#include - -/* - * The following variable is a special hack that is needed in order for - * Sun shared libraries to be used for Tcl. - */ -#ifdef SUN -extern int matherr(); -int *tclDummyMathPtr = (int *) matherr; -#endif - - -static GLuint FontBase; -static float xAngle = 0.0, yAngle = 0.0, zAngle = 0.0; -static GLfloat CornerX, CornerY, CornerZ; /* where to print strings */ -static GLfloat scale = 1.0; - - - -/* - * Togl widget create callback. This is called by Tcl/Tk when the widget has - * been realized. Here's where one may do some one-time context setup or - * initializations. - */ -void -create_cb(Togl *togl) -{ - FontBase = Togl_LoadBitmapFont(togl, TOGL_BITMAP_8_BY_13); - if (!FontBase) { - printf("Couldn't load font!\n"); - exit(1); - } -} - - -/* - * Togl widget reshape callback. This is called by Tcl/Tk when the widget - * has been resized. Typically, we call glViewport and perhaps setup the - * projection matrix. - */ -void -reshape_cb(Togl *togl) -{ - int width = Togl_Width(togl); - int height = Togl_Height(togl); - float aspect = (float) width / (float) height; - - glViewport(0, 0, width, height); - - /* Set up projection transform */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(-aspect, aspect, -1.0, 1.0, 1.0, 10.0); - - CornerX = -aspect; - CornerY = -1.0; - CornerZ = -1.1; - - /* Change back to model view transform for rendering */ - glMatrixMode(GL_MODELVIEW); -} - - - -static void -print_string(const char *s) -{ - glCallLists(strlen(s), GL_UNSIGNED_BYTE, s); -} - - -/* - * Togl widget display callback. This is called by Tcl/Tk when the widget's - * contents have to be redrawn. Typically, we clear the color and depth - * buffers, render our objects, then swap the front/back color buffers. - */ -void -display_cb(Togl *togl) -{ - const char *ident; - GLfloat eyeDist = 2.0; - GLfloat eyeOffset = 0.05; - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glLoadIdentity(); /* Reset modelview matrix to the identity - * matrix */ - glTranslatef(0.0, 0.0, -3.0); /* Move the camera back three units */ - glScalef(scale, scale, scale); /* Zoom in and out */ - glRotatef(xAngle, 1.0, 0.0, 0.0); /* Rotate by X, Y, and Z angles */ - glRotatef(yAngle, 0.0, 1.0, 0.0); - glRotatef(zAngle, 0.0, 0.0, 1.0); - - glEnable(GL_DEPTH_TEST); - - /* stereo right eye */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - Togl_StereoFrustum(-1, 1, -1, 1, 1, 10, eyeDist, eyeOffset); - glMatrixMode(GL_MODELVIEW); -#ifdef OLD_STEREO - Togl_OldStereoDrawBuffer(GL_BACK_RIGHT); - Togl_OldStereoClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -#else - glDrawBuffer(GL_BACK_RIGHT); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -#endif - - /* Front face */ - glBegin(GL_QUADS); - glColor3f(0.0, 0.7, 0.1); /* Green */ - glVertex3f(-1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - glVertex3f(-1.0, -1.0, 1.0); - /* Back face */ - glColor3f(0.9, 1.0, 0.0); /* Yellow */ - glVertex3f(-1.0, 1.0, -1.0); - glVertex3f(1.0, 1.0, -1.0); - glVertex3f(1.0, -1.0, -1.0); - glVertex3f(-1.0, -1.0, -1.0); - /* Top side face */ - glColor3f(0.2, 0.2, 1.0); /* Blue */ - glVertex3f(-1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, -1.0); - glVertex3f(-1.0, 1.0, -1.0); - /* Bottom side face */ - glColor3f(0.7, 0.0, 0.1); /* Red */ - glVertex3f(-1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, -1.0); - glVertex3f(-1.0, -1.0, -1.0); - glEnd(); - - /* stereo left eye */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - Togl_StereoFrustum(-1, 1, -1, 1, 1, 10, eyeDist, -eyeOffset); - glMatrixMode(GL_MODELVIEW); - -#ifdef OLD_STEREO - Togl_OldStereoDrawBuffer(GL_BACK_LEFT); - Togl_OldStereoClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -#else - glDrawBuffer(GL_BACK_LEFT); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -#endif - - /* Front face */ - glBegin(GL_QUADS); - glColor3f(0.0, 0.7, 0.1); /* Green */ - glVertex3f(-1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - glVertex3f(-1.0, -1.0, 1.0); - /* Back face */ - glColor3f(0.9, 1.0, 0.0); /* Yellow */ - glVertex3f(-1.0, 1.0, -1.0); - glVertex3f(1.0, 1.0, -1.0); - glVertex3f(1.0, -1.0, -1.0); - glVertex3f(-1.0, -1.0, -1.0); - /* Top side face */ - glColor3f(0.2, 0.2, 1.0); /* Blue */ - glVertex3f(-1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, 1.0); - glVertex3f(1.0, 1.0, -1.0); - glVertex3f(-1.0, 1.0, -1.0); - /* Bottom side face */ - glColor3f(0.7, 0.0, 0.1); /* Red */ - glVertex3f(-1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, 1.0); - glVertex3f(1.0, -1.0, -1.0); - glVertex3f(-1.0, -1.0, -1.0); - glEnd(); - - - glDisable(GL_DEPTH_TEST); - glLoadIdentity(); - glColor3f(1.0, 1.0, 1.0); - glRasterPos3f(CornerX, CornerY, CornerZ); - glListBase(FontBase); - /* ident = Togl_Ident( togl ); if (strcmp(ident,"Single")==0) { - * print_string( "Single buffered" ); } else { print_string( "Double - * buffered" ); } */ - print_string(Togl_Ident(togl)); - Togl_SwapBuffers(togl); -} - - -int -setXrot_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName setXrot ?angle?\"", - TCL_STATIC); - return TCL_ERROR; - } - - xAngle = atof(argv[2]); - - /* printf( "before %f ", xAngle ); */ - - if (xAngle < 0.0) { - xAngle += 360.0; - } else if (xAngle > 360.0) { - xAngle -= 360.0; - } - - /* printf( "after %f \n", xAngle ); */ - - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -int -setYrot_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName setYrot ?angle?\"", - TCL_STATIC); - return TCL_ERROR; - } - - yAngle = atof(argv[2]); - - if (yAngle < 0.0) { - yAngle += 360.0; - } else if (yAngle > 360.0) { - yAngle -= 360.0; - } - - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -int -getXrot_cb(ClientData clientData, Tcl_Interp *interp, - int argc, CONST84 char *argv[]) -{ - sprintf(interp->result, "%d", (int) xAngle); - return TCL_OK; -} - - -int -getYrot_cb(ClientData clientData, Tcl_Interp *interp, - int argc, CONST84 char *argv[]) -{ - sprintf(interp->result, "%d", (int) yAngle); - return TCL_OK; -} - - -int -scale_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName scale ?value?\"", - TCL_STATIC); - return TCL_ERROR; - } - - scale = atof(argv[2]); - - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -TOGL_EXTERN int -Stereo_Init(Tcl_Interp *interp) -{ - /* - * Initialize Tcl, Tk, and the Togl widget module. - */ -#ifdef USE_TCL_STUBS - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif -#ifdef USE_TK_STUBS - if (Tk_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif - - if (Togl_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } - - /* - * Specify the C callback functions for widget creation, display, - * and reshape. - */ - Togl_CreateFunc(create_cb); - Togl_DisplayFunc(display_cb); - Togl_ReshapeFunc(reshape_cb); - - /* - * Make a new Togl widget command so the Tcl code can set a C variable. - */ - - Togl_CreateCommand("setXrot", setXrot_cb); - Togl_CreateCommand("setYrot", setYrot_cb); - Togl_CreateCommand("scale", scale_cb); - - /* - * Call Tcl_CreateCommand for application-specific commands, if - * they weren't already created by the init procedures called above. - */ - - Tcl_CreateCommand(interp, "getXrot", getXrot_cb, (ClientData) NULL, - (Tcl_CmdDeleteProc *) NULL); - Tcl_CreateCommand(interp, "getYrot", getYrot_cb, (ClientData) NULL, - (Tcl_CmdDeleteProc *) NULL); - - return TCL_OK; -} diff --git a/ng/Togl-1.7/stereo.tcl b/ng/Togl-1.7/stereo.tcl deleted file mode 100644 index ea5fc89f..00000000 --- a/ng/Togl-1.7/stereo.tcl +++ /dev/null @@ -1,108 +0,0 @@ -#!/bin/sh -# the next line restarts using wish \ -exec wish "$0" "$@" - -# $Id: stereo.tcl,v 1.4 2004/12/21 05:28:39 gregcouch Exp $ - -# Togl - a Tk OpenGL widget -# Copyright (C) 1996 Brian Paul and Ben Bederson -# See the LICENSE file for copyright details. - - -# $Log: stereo.tcl,v $ -# Revision 1.4 2004/12/21 05:28:39 gregcouch -# Apply outstanding patches and Mac OS X support. -# -# Revision 1.3 2001/12/20 13:59:31 beskow -# Improved error-handling in togl.c in case of window creation failure -# Added pkgIndex target to makefile -# Updated documentation to reflect stubs-interface (Togl.html + new README.stubs) -# Added tk8.4a3 headers -# Removed obsolete Tk internal headers -# -# Revision 1.2 2001/01/29 18:11:53 brianp -# Jonas Beskow's changes to use Tcl/Tk stub interface -# -# Revision 1.1 1997/10/01 02:53:12 brianp -# Initial revision -# -# -# Revision 1.1 1997/9/28 18:54:46 Ben Evans -# Initial revision. Based on double.tcl -# - - -# An Tk/OpenGL widget demo with two windows, one single buffered and the -# other double buffered. - -load [file dirname [info script]]/stereo[info sharedlibextension] - -proc setup {} { - global scale - set scale 1.0 - wm title . "Full Screen Stereo Buffering" - - frame .f1 - togl .f1.o1 -width 200 -height 200 -rgba true -stereo true -double true -depth true -ident "stereo buffer" - - scale .sx -label {X Axis} -from 0 -to 360 -command {setAngle x} -orient horizontal - scale .sy -label {Y Axis} -from 0 -to 360 -command {setAngle y} -orient horizontal - button .btn -text Quit -command exit - - bind .f1.o1 { - motion_event [lindex [%W config -width] 4] \ - [lindex [%W config -height] 4] \ - %x %y - } - - bind .f1.o1 { - set startx %x - set starty %y - set scale0 $scale - } - - bind .f1.o1 { - set q [ expr ($starty - %y) / 400.0 ] - set scale [expr $scale0 * exp($q)] - .f1.o1 scale $scale - } - - pack .f1.o1 -side left -padx 3 -pady 3 -fill both -expand t - pack .f1 -fill both -expand t - pack .sx -fill x - pack .sy -fill x - pack .btn -fill x - - if {[string first $::tcl_platform(os) IRIX] != -1} { - puts "use /usr/gfx/setmon -n 60 to reset display and /usr/gfx/setmon -n STR_RECT to put in display in stereo mode" - } - -} - - - -# This is called when mouse button 1 is pressed and moved in either of -# the OpenGL windows. -proc motion_event { width height x y } { - .f1.o1 setXrot [expr 360.0 * $y / $height] - .f1.o1 setYrot [expr 360.0 * ($width - $x) / $width] - -# .sx set [expr 360.0 * $y / $height] -# .sy set [expr 360.0 * ($width - $x) / $width] - - .sx set [getXrot] - .sy set [getYrot] -} - -# This is called when a slider is changed. -proc setAngle {axis value} { - global xAngle yAngle zAngle - - switch -exact $axis { - x {.f1.o1 setXrot $value} - y {.f1.o1 setYrot $value} - } -} - -# Execution starts here! -setup diff --git a/ng/Togl-1.7/tclconfig/README.txt b/ng/Togl-1.7/tclconfig/README.txt deleted file mode 100644 index 59b5a3e8..00000000 --- a/ng/Togl-1.7/tclconfig/README.txt +++ /dev/null @@ -1,26 +0,0 @@ -These files comprise the basic building blocks for a Tcl Extension -Architecture (TEA) extension. For more information on TEA see: - - http://www.tcl.tk/doc/tea/ - -This package is part of the Tcl project at SourceForge, and latest -sources should be available there: - - http://tcl.sourceforge.net/ - -This package is a freely available open source package. You can do -virtually anything you like with it, such as modifying it, redistributing -it, and selling it either in whole or in part. - -CONTENTS -======== -The following is a short description of the files you will find in -the sample extension. - -README.txt This file - -install-sh Program used for copying binaries and script files - to their install locations. - -tcl.m4 Collection of Tcl autoconf macros. Included by a package's - aclocal.m4 to define TEA_* macros. diff --git a/ng/Togl-1.7/tclconfig/install-sh b/ng/Togl-1.7/tclconfig/install-sh deleted file mode 100644 index 0ff4b6a0..00000000 --- a/ng/Togl-1.7/tclconfig/install-sh +++ /dev/null @@ -1,119 +0,0 @@ -#!/bin/sh - -# -# install - install a program, script, or datafile -# This comes from X11R5; it is not part of GNU. -# -# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $ -# -# This script is compatible with the BSD install script, but was written -# from scratch. -# - - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit="${DOITPROG-}" - - -# put in absolute paths if you don't have them in your path; or use env. vars. - -mvprog="${MVPROG-mv}" -cpprog="${CPPROG-cp}" -chmodprog="${CHMODPROG-chmod}" -chownprog="${CHOWNPROG-chown}" -chgrpprog="${CHGRPPROG-chgrp}" -stripprog="${STRIPPROG-strip}" -rmprog="${RMPROG-rm}" - -instcmd="$mvprog" -chmodcmd="" -chowncmd="" -chgrpcmd="" -stripcmd="" -rmcmd="$rmprog -f" -mvcmd="$mvprog" -src="" -dst="" - -while [ x"$1" != x ]; do - case $1 in - -c) instcmd="$cpprog" - shift - continue;; - - -m) chmodcmd="$chmodprog $2" - shift - shift - continue;; - - -o) chowncmd="$chownprog $2" - shift - shift - continue;; - - -g) chgrpcmd="$chgrpprog $2" - shift - shift - continue;; - - -s) stripcmd="$stripprog" - shift - continue;; - - *) if [ x"$src" = x ] - then - src=$1 - else - dst=$1 - fi - shift - continue;; - esac -done - -if [ x"$src" = x ] -then - echo "install: no input file specified" - exit 1 -fi - -if [ x"$dst" = x ] -then - echo "install: no destination specified" - exit 1 -fi - - -# If destination is a directory, append the input filename; if your system -# does not like double slashes in filenames, you may need to add some logic - -if [ -d $dst ] -then - dst="$dst"/`basename $src` -fi - -# Make a temp file name in the proper directory. - -dstdir=`dirname $dst` -dsttmp=$dstdir/#inst.$$# - -# Move or copy the file name to the temp name - -$doit $instcmd $src $dsttmp - -# and set any options; do chmod last to preserve setuid bits - -if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi -if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi -if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi -if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi - -# Now rename the file to the real destination. - -$doit $rmcmd $dst -$doit $mvcmd $dsttmp $dst - - -exit 0 diff --git a/ng/Togl-1.7/tclconfig/tcl.m4 b/ng/Togl-1.7/tclconfig/tcl.m4 deleted file mode 100644 index 2862ae18..00000000 --- a/ng/Togl-1.7/tclconfig/tcl.m4 +++ /dev/null @@ -1,3959 +0,0 @@ -# tcl.m4 -- -# -# This file provides a set of autoconf macros to help TEA-enable -# a Tcl extension. -# -# Copyright (c) 1999-2000 Ajuba Solutions. -# Copyright (c) 2002-2005 ActiveState Corporation. -# -# See the file "license.terms" for information on usage and redistribution -# of this file, and for a DISCLAIMER OF ALL WARRANTIES. -# -# RCS: @(#) $Id: tcl.m4,v 1.4 2006/01/06 00:09:00 gregcouch Exp $ - -AC_PREREQ(2.50) - -# Possible values for key variables defined: -# -# TEA_WINDOWINGSYSTEM - win32 aqua x11 (mirrors 'tk windowingsystem') -# TEA_PLATFORM - windows unix -# - -#------------------------------------------------------------------------ -# TEA_PATH_TCLCONFIG -- -# -# Locate the tclConfig.sh file and perform a sanity check on -# the Tcl compile flags -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --with-tcl=... -# -# Defines the following vars: -# TCL_BIN_DIR Full path to the directory containing -# the tclConfig.sh file -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_PATH_TCLCONFIG, [ - dnl Make sure we are initialized - AC_REQUIRE([TEA_INIT]) - # - # Ok, lets find the tcl configuration - # First, look for one uninstalled. - # the alternative search directory is invoked by --with-tcl - # - - if test x"${no_tcl}" = x ; then - # we reset no_tcl in case something fails here - no_tcl=true - AC_ARG_WITH(tcl, [ --with-tcl directory containing tcl configuration (tclConfig.sh)], with_tclconfig=${withval}) - AC_MSG_CHECKING([for Tcl configuration]) - AC_CACHE_VAL(ac_cv_c_tclconfig,[ - - # First check to see if --with-tcl was specified. - if test x"${with_tclconfig}" != x ; then - case ${with_tclconfig} in - */tclConfig.sh ) - if test -f ${with_tclconfig}; then - AC_MSG_WARN([--with-tcl argument should refer to directory containing tclConfig.sh, not to tclConfig.sh itself]) - with_tclconfig=`echo ${with_tclconfig} | sed 's!/tclConfig\.sh$!!'` - fi ;; - esac - if test -f "${with_tclconfig}/tclConfig.sh" ; then - ac_cv_c_tclconfig=`(cd ${with_tclconfig}; pwd)` - else - AC_MSG_ERROR([${with_tclconfig} directory doesn't contain tclConfig.sh]) - fi - fi - - # then check for a private Tcl installation - if test x"${ac_cv_c_tclconfig}" = x ; then - for i in \ - ../tcl \ - `ls -dr ../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../tcl[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ - ../../tcl \ - `ls -dr ../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../tcl[[8-9]].[[0-9]]* 2>/dev/null` \ - ../../../tcl \ - `ls -dr ../../../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../../../tcl[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do - if test -f "$i/unix/tclConfig.sh" ; then - ac_cv_c_tclconfig=`(cd $i/unix; pwd)` - break - fi - done - fi - - # on Darwin, check in Framework installation locations - if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tclconfig}" = x ; then - for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ - `ls -d /Library/Frameworks 2>/dev/null` \ - `ls -d /Network/Library/Frameworks 2>/dev/null` \ - `ls -d /System/Library/Frameworks 2>/dev/null` \ - ; do - if test -f "$i/Tcl.framework/tclConfig.sh" ; then - ac_cv_c_tclconfig=`(cd $i/Tcl.framework; pwd)` - break - fi - done - fi - - # check in a few common install locations - if test x"${ac_cv_c_tclconfig}" = x ; then - for i in `ls -d ${libdir} 2>/dev/null` \ - `ls -d ${exec_prefix}/lib 2>/dev/null` \ - `ls -d ${prefix}/lib 2>/dev/null` \ - `ls -d /usr/local/lib 2>/dev/null` \ - `ls -d /usr/contrib/lib 2>/dev/null` \ - `ls -d /usr/lib 2>/dev/null` \ - ; do - if test -f "$i/tclConfig.sh" ; then - ac_cv_c_tclconfig=`(cd $i; pwd)` - break - fi - done - fi - - # check in a few other private locations - if test x"${ac_cv_c_tclconfig}" = x ; then - for i in \ - ${srcdir}/../tcl \ - `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ${srcdir}/../tcl[[8-9]].[[0-9]]* 2>/dev/null` ; do - if test -f "$i/unix/tclConfig.sh" ; then - ac_cv_c_tclconfig=`(cd $i/unix; pwd)` - break - fi - done - fi - ]) - - if test x"${ac_cv_c_tclconfig}" = x ; then - TCL_BIN_DIR="# no Tcl configs found" - AC_MSG_WARN("Cannot find Tcl configuration definitions") - exit 0 - else - no_tcl= - TCL_BIN_DIR=${ac_cv_c_tclconfig} - AC_MSG_RESULT([found $TCL_BIN_DIR/tclConfig.sh]) - fi - fi -]) - -#------------------------------------------------------------------------ -# TEA_PATH_TKCONFIG -- -# -# Locate the tkConfig.sh file -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --with-tk=... -# -# Defines the following vars: -# TK_BIN_DIR Full path to the directory containing -# the tkConfig.sh file -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_PATH_TKCONFIG, [ - # - # Ok, lets find the tk configuration - # First, look for one uninstalled. - # the alternative search directory is invoked by --with-tk - # - - if test x"${no_tk}" = x ; then - # we reset no_tk in case something fails here - no_tk=true - AC_ARG_WITH(tk, [ --with-tk directory containing tk configuration (tkConfig.sh)], with_tkconfig=${withval}) - AC_MSG_CHECKING([for Tk configuration]) - AC_CACHE_VAL(ac_cv_c_tkconfig,[ - - # First check to see if --with-tkconfig was specified. - if test x"${with_tkconfig}" != x ; then - case ${with_tkconfig} in - */tkConfig.sh ) - if test -f ${with_tkconfig}; then - AC_MSG_WARN([--with-tk argument should refer to directory containing tkConfig.sh, not to tkConfig.sh itself]) - with_tkconfig=`echo ${with_tkconfig} | sed 's!/tkConfig\.sh$!!'` - fi ;; - esac - if test -f "${with_tkconfig}/tkConfig.sh" ; then - ac_cv_c_tkconfig=`(cd ${with_tkconfig}; pwd)` - else - AC_MSG_ERROR([${with_tkconfig} directory doesn't contain tkConfig.sh]) - fi - fi - - # then check for a private Tk library - if test x"${ac_cv_c_tkconfig}" = x ; then - for i in \ - ../tk \ - `ls -dr ../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../tk[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../tk[[8-9]].[[0-9]]* 2>/dev/null` \ - ../../tk \ - `ls -dr ../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../../tk[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../tk[[8-9]].[[0-9]]* 2>/dev/null` \ - ../../../tk \ - `ls -dr ../../../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ../../../tk[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do - if test -f "$i/unix/tkConfig.sh" ; then - ac_cv_c_tkconfig=`(cd $i/unix; pwd)` - break - fi - done - fi - - # on Darwin, check in Framework installation locations - if test "`uname -s`" = "Darwin" -a x"${ac_cv_c_tkconfig}" = x ; then - for i in `ls -d ~/Library/Frameworks 2>/dev/null` \ - `ls -d /Library/Frameworks 2>/dev/null` \ - `ls -d /Network/Library/Frameworks 2>/dev/null` \ - `ls -d /System/Library/Frameworks 2>/dev/null` \ - ; do - if test -f "$i/Tk.framework/tkConfig.sh" ; then - ac_cv_c_tkconfig=`(cd $i/Tk.framework; pwd)` - break - fi - done - fi - - # check in a few common install locations - if test x"${ac_cv_c_tkconfig}" = x ; then - for i in `ls -d ${libdir} 2>/dev/null` \ - `ls -d ${exec_prefix}/lib 2>/dev/null` \ - `ls -d ${prefix}/lib 2>/dev/null` \ - `ls -d /usr/local/lib 2>/dev/null` \ - `ls -d /usr/contrib/lib 2>/dev/null` \ - `ls -d /usr/lib 2>/dev/null` \ - ; do - if test -f "$i/tkConfig.sh" ; then - ac_cv_c_tkconfig=`(cd $i; pwd)` - break - fi - done - fi - # check in a few other private locations - if test x"${ac_cv_c_tkconfig}" = x ; then - for i in \ - ${srcdir}/../tk \ - `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]].[[0-9]]* 2>/dev/null` \ - `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ${srcdir}/../tk[[8-9]].[[0-9]]* 2>/dev/null` ; do - if test -f "$i/unix/tkConfig.sh" ; then - ac_cv_c_tkconfig=`(cd $i/unix; pwd)` - break - fi - done - fi - ]) - - if test x"${ac_cv_c_tkconfig}" = x ; then - TK_BIN_DIR="# no Tk configs found" - AC_MSG_WARN("Cannot find Tk configuration definitions") - exit 0 - else - no_tk= - TK_BIN_DIR=${ac_cv_c_tkconfig} - AC_MSG_RESULT([found $TK_BIN_DIR/tkConfig.sh]) - fi - fi -]) - -#------------------------------------------------------------------------ -# TEA_LOAD_TCLCONFIG -- -# -# Load the tclConfig.sh file -# -# Arguments: -# -# Requires the following vars to be set: -# TCL_BIN_DIR -# -# Results: -# -# Subst the following vars: -# TCL_BIN_DIR -# TCL_SRC_DIR -# TCL_LIB_FILE -# -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_LOAD_TCLCONFIG, [ - AC_MSG_CHECKING([for existence of $TCL_BIN_DIR/tclConfig.sh]) - - if test -f "$TCL_BIN_DIR/tclConfig.sh" ; then - AC_MSG_RESULT([loading]) - . $TCL_BIN_DIR/tclConfig.sh - else - AC_MSG_RESULT([file not found]) - fi - - # - # If the TCL_BIN_DIR is the build directory (not the install directory), - # then set the common variable name to the value of the build variables. - # For example, the variable TCL_LIB_SPEC will be set to the value - # of TCL_BUILD_LIB_SPEC. An extension should make use of TCL_LIB_SPEC - # instead of TCL_BUILD_LIB_SPEC since it will work with both an - # installed and uninstalled version of Tcl. - # - - if test -f $TCL_BIN_DIR/Makefile ; then - TCL_LIB_SPEC=${TCL_BUILD_LIB_SPEC} - TCL_STUB_LIB_SPEC=${TCL_BUILD_STUB_LIB_SPEC} - TCL_STUB_LIB_PATH=${TCL_BUILD_STUB_LIB_PATH} - fi - - # - # eval is required to do the TCL_DBGX substitution - # - - eval "TCL_LIB_FILE=\"${TCL_LIB_FILE}\"" - eval "TCL_LIB_FLAG=\"${TCL_LIB_FLAG}\"" - eval "TCL_LIB_SPEC=\"${TCL_LIB_SPEC}\"" - - eval "TCL_STUB_LIB_FILE=\"${TCL_STUB_LIB_FILE}\"" - eval "TCL_STUB_LIB_FLAG=\"${TCL_STUB_LIB_FLAG}\"" - eval "TCL_STUB_LIB_SPEC=\"${TCL_STUB_LIB_SPEC}\"" - - AC_SUBST(TCL_VERSION) - AC_SUBST(TCL_BIN_DIR) - AC_SUBST(TCL_SRC_DIR) - - AC_SUBST(TCL_LIB_FILE) - AC_SUBST(TCL_LIB_FLAG) - AC_SUBST(TCL_LIB_SPEC) - - AC_SUBST(TCL_STUB_LIB_FILE) - AC_SUBST(TCL_STUB_LIB_FLAG) - AC_SUBST(TCL_STUB_LIB_SPEC) - - AC_SUBST(TCL_LIBS) - AC_SUBST(TCL_DEFS) - AC_SUBST(TCL_EXTRA_CFLAGS) - AC_SUBST(TCL_LD_FLAGS) - AC_SUBST(TCL_SHLIB_LD_LIBS) - #AC_SUBST(TCL_BUILD_LIB_SPEC) - #AC_SUBST(TCL_BUILD_STUB_LIB_SPEC) -]) - -#------------------------------------------------------------------------ -# TEA_LOAD_TKCONFIG -- -# -# Load the tkConfig.sh file -# -# Arguments: -# -# Requires the following vars to be set: -# TK_BIN_DIR -# -# Results: -# -# Sets the following vars that should be in tkConfig.sh: -# TK_BIN_DIR -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_LOAD_TKCONFIG, [ - AC_MSG_CHECKING([for existence of ${TK_BIN_DIR}/tkConfig.sh]) - - if test -f "${TK_BIN_DIR}/tkConfig.sh" ; then - AC_MSG_RESULT([loading]) - . $TK_BIN_DIR/tkConfig.sh - else - AC_MSG_RESULT([could not find ${TK_BIN_DIR}/tkConfig.sh]) - fi - - # - # If the TK_BIN_DIR is the build directory (not the install directory), - # then set the common variable name to the value of the build variables. - # For example, the variable TK_LIB_SPEC will be set to the value - # of TK_BUILD_LIB_SPEC. An extension should make use of TK_LIB_SPEC - # instead of TK_BUILD_LIB_SPEC since it will work with both an - # installed and uninstalled version of Tcl. - # - - if test -f $TK_BIN_DIR/Makefile ; then - TK_LIB_SPEC=${TK_BUILD_LIB_SPEC} - TK_STUB_LIB_SPEC=${TK_BUILD_STUB_LIB_SPEC} - TK_STUB_LIB_PATH=${TK_BUILD_STUB_LIB_PATH} - fi - - # Ensure windowingsystem is defined - if test "${TEA_PLATFORM}" = "unix" ; then - case ${TK_DEFS} in - *MAC_OSX_TK*) - AC_DEFINE(MAC_OSX_TK, 1, [Are we building against Mac OS X TkAqua?]) - TEA_WINDOWINGSYSTEM="aqua" - ;; - *) - TEA_WINDOWINGSYSTEM="x11" - ;; - esac - elif test "${TEA_PLATFORM}" = "windows" ; then - TEA_WINDOWINGSYSTEM="win32" - fi - - # - # eval is required to do the TK_DBGX substitution - # - - eval "TK_LIB_FILE=\"${TK_LIB_FILE}\"" - eval "TK_LIB_FLAG=\"${TK_LIB_FLAG}\"" - eval "TK_LIB_SPEC=\"${TK_LIB_SPEC}\"" - - eval "TK_STUB_LIB_FILE=\"${TK_STUB_LIB_FILE}\"" - eval "TK_STUB_LIB_FLAG=\"${TK_STUB_LIB_FLAG}\"" - eval "TK_STUB_LIB_SPEC=\"${TK_STUB_LIB_SPEC}\"" - - AC_SUBST(TK_VERSION) - AC_SUBST(TK_BIN_DIR) - AC_SUBST(TK_SRC_DIR) - - AC_SUBST(TK_LIB_FILE) - AC_SUBST(TK_LIB_FLAG) - AC_SUBST(TK_LIB_SPEC) - - AC_SUBST(TK_STUB_LIB_FILE) - AC_SUBST(TK_STUB_LIB_FLAG) - AC_SUBST(TK_STUB_LIB_SPEC) - - AC_SUBST(TK_LIBS) - AC_SUBST(TK_XINCLUDES) -]) - -#------------------------------------------------------------------------ -# TEA_ENABLE_SHARED -- -# -# Allows the building of shared libraries -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --enable-shared=yes|no -# -# Defines the following vars: -# STATIC_BUILD Used for building import/export libraries -# on Windows. -# -# Sets the following vars: -# SHARED_BUILD Value of 1 or 0 -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_ENABLE_SHARED, [ - AC_MSG_CHECKING([how to build libraries]) - AC_ARG_ENABLE(shared, - [ --enable-shared build and link with shared libraries [--enable-shared]], - [tcl_ok=$enableval], [tcl_ok=yes]) - - if test "${enable_shared+set}" = set; then - enableval="$enable_shared" - tcl_ok=$enableval - else - tcl_ok=yes - fi - - if test "$tcl_ok" = "yes" ; then - AC_MSG_RESULT([shared]) - SHARED_BUILD=1 - else - AC_MSG_RESULT([static]) - SHARED_BUILD=0 - AC_DEFINE(STATIC_BUILD, 1, [Is this a static build?]) - fi - AC_SUBST(SHARED_BUILD) -]) - -#------------------------------------------------------------------------ -# TEA_ENABLE_THREADS -- -# -# Specify if thread support should be enabled. If "yes" is specified -# as an arg (optional), threads are enabled by default, "no" means -# threads are disabled. "yes" is the default. -# -# TCL_THREADS is checked so that if you are compiling an extension -# against a threaded core, your extension must be compiled threaded -# as well. -# -# Note that it is legal to have a thread enabled extension run in a -# threaded or non-threaded Tcl core, but a non-threaded extension may -# only run in a non-threaded Tcl core. -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --enable-threads -# -# Sets the following vars: -# THREADS_LIBS Thread library(s) -# -# Defines the following vars: -# TCL_THREADS -# _REENTRANT -# -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_ENABLE_THREADS, [ - AC_ARG_ENABLE(threads, [ --enable-threads build with threads], - [tcl_ok=$enableval], [tcl_ok=yes]) - - if test "${enable_threads+set}" = set; then - enableval="$enable_threads" - tcl_ok=$enableval - else - tcl_ok=yes - fi - - if test "$tcl_ok" = "yes" -o "${TCL_THREADS}" = 1; then - TCL_THREADS=1 - - if test "${TEA_PLATFORM}" != "windows" ; then - # We are always OK on Windows, so check what this platform wants. - AC_DEFINE(USE_THREAD_ALLOC, 1, - [Do we want to use the threaded memory allocator?]) - AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) - AC_DEFINE(_THREAD_SAFE, 1, [Do we want the thread-safe OS API?]) - AC_CHECK_LIB(pthread,pthread_mutex_init,tcl_ok=yes,tcl_ok=no) - if test "$tcl_ok" = "no"; then - # Check a little harder for __pthread_mutex_init in the - # same library, as some systems hide it there until - # pthread.h is defined. We could alternatively do an - # AC_TRY_COMPILE with pthread.h, but that will work with - # libpthread really doesn't exist, like AIX 4.2. - # [Bug: 4359] - AC_CHECK_LIB(pthread, __pthread_mutex_init, - tcl_ok=yes, tcl_ok=no) - fi - - if test "$tcl_ok" = "yes"; then - # The space is needed - THREADS_LIBS=" -lpthread" - else - AC_CHECK_LIB(pthreads, pthread_mutex_init, - tcl_ok=yes, tcl_ok=no) - if test "$tcl_ok" = "yes"; then - # The space is needed - THREADS_LIBS=" -lpthreads" - else - AC_CHECK_LIB(c, pthread_mutex_init, - tcl_ok=yes, tcl_ok=no) - if test "$tcl_ok" = "no"; then - AC_CHECK_LIB(c_r, pthread_mutex_init, - tcl_ok=yes, tcl_ok=no) - if test "$tcl_ok" = "yes"; then - # The space is needed - THREADS_LIBS=" -pthread" - else - TCL_THREADS=0 - AC_MSG_WARN("Don t know how to find pthread lib on your system - thread support disabled") - fi - fi - fi - fi - -dnl # Not needed in TEA -dnl # Does the pthread-implementation provide -dnl # 'pthread_attr_setstacksize' ? -dnl -dnl ac_saved_libs=$LIBS -dnl LIBS="$LIBS $THREADS_LIBS" -dnl AC_CHECK_FUNCS(pthread_attr_setstacksize) -dnl LIBS=$ac_saved_libs - fi - else - TCL_THREADS=0 - fi - # Do checking message here to not mess up interleaved configure output - AC_MSG_CHECKING([for building with threads]) - if test "${TCL_THREADS}" = "1"; then - AC_DEFINE(TCL_THREADS, 1, [Are we building with threads enabled?]) - #LIBS="$LIBS $THREADS_LIBS" - AC_MSG_RESULT([yes (default)]) - else - AC_MSG_RESULT([no]) - fi - # TCL_THREADS sanity checking. See if our request for building with - # threads is the same as the way Tcl was built. If not, warn the user. - case ${TCL_DEFS} in - *THREADS=1*) - if test "${TCL_THREADS}" = "0"; then - AC_MSG_WARN([ - Building ${PACKAGE_NAME} without threads enabled, but building against Tcl - that IS thread-enabled. It is recommended to use --enable-threads.]) - fi - ;; - *) - if test "${TCL_THREADS}" = "1"; then - AC_MSG_WARN([ - --enable-threads requested, but building against a Tcl that is NOT - thread-enabled. This is an OK configuration that will also run in - a thread-enabled core.]) - fi - ;; - esac - AC_SUBST(TCL_THREADS) -]) - -#------------------------------------------------------------------------ -# TEA_ENABLE_SYMBOLS -- -# -# Specify if debugging symbols should be used -# Memory (TCL_MEM_DEBUG) debugging can also be enabled. -# -# Arguments: -# none -# -# Requires the following vars to be set: -# CFLAGS_DEBUG -# CFLAGS_OPTIMIZE -# LDFLAGS_DEBUG -# LDFLAGS_OPTIMIZE -# -# Results: -# -# Adds the following arguments to configure: -# --enable-symbols -# -# Defines the following vars: -# CFLAGS_DEFAULT Sets to CFLAGS_DEBUG if true -# Sets to CFLAGS_OPTIMIZE if false -# LDFLAGS_DEFAULT Sets to LDFLAGS_DEBUG if true -# Sets to LDFLAGS_OPTIMIZE if false -# DBGX Formerly used as debug library extension; -# always blank now. -# -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_ENABLE_SYMBOLS, [ - dnl Make sure we are initialized - AC_REQUIRE([TEA_CONFIG_CFLAGS]) - - DBGX="" - - AC_MSG_CHECKING([for build with symbols]) - AC_ARG_ENABLE(symbols, [ --enable-symbols build with debugging symbols [--disable-symbols]], [tcl_ok=$enableval], [tcl_ok=no]) - if test "$tcl_ok" = "no"; then - CFLAGS_DEFAULT="${CFLAGS_OPTIMIZE}" - LDFLAGS_DEFAULT="${LDFLAGS_OPTIMIZE}" - AC_MSG_RESULT([no]) - else - CFLAGS_DEFAULT="${CFLAGS_DEBUG}" - LDFLAGS_DEFAULT="${LDFLAGS_DEBUG}" - if test "$tcl_ok" = "yes"; then - AC_MSG_RESULT([yes (standard debugging)]) - fi - fi - if test "${TEA_PLATFORM}" != "windows" ; then - LDFLAGS_DEFAULT="${LDFLAGS}" - fi - - AC_SUBST(TCL_DBGX) - AC_SUBST(CFLAGS_DEFAULT) - AC_SUBST(LDFLAGS_DEFAULT) - - if test "$tcl_ok" = "mem" -o "$tcl_ok" = "all"; then - AC_DEFINE(TCL_MEM_DEBUG, 1, [Is memory debugging enabled?]) - fi - - if test "$tcl_ok" != "yes" -a "$tcl_ok" != "no"; then - if test "$tcl_ok" = "all"; then - AC_MSG_RESULT([enabled symbols mem debugging]) - else - AC_MSG_RESULT([enabled $tcl_ok debugging]) - fi - fi -]) - -#------------------------------------------------------------------------ -# TEA_ENABLE_LANGINFO -- -# -# Allows use of modern nl_langinfo check for better l10n. -# This is only relevant for Unix. -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --enable-langinfo=yes|no (default is yes) -# -# Defines the following vars: -# HAVE_LANGINFO Triggers use of nl_langinfo if defined. -# -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_ENABLE_LANGINFO, [ - AC_ARG_ENABLE(langinfo, - [ --enable-langinfo use nl_langinfo if possible to determine - encoding at startup, otherwise use old heuristic], - [langinfo_ok=$enableval], [langinfo_ok=yes]) - - HAVE_LANGINFO=0 - if test "$langinfo_ok" = "yes"; then - AC_CHECK_HEADER(langinfo.h,[langinfo_ok=yes],[langinfo_ok=no]) - fi - AC_MSG_CHECKING([whether to use nl_langinfo]) - if test "$langinfo_ok" = "yes"; then - AC_CACHE_VAL(tcl_cv_langinfo_h, - AC_TRY_COMPILE([#include ], [nl_langinfo(CODESET);], - [tcl_cv_langinfo_h=yes],[tcl_cv_langinfo_h=no])) - AC_MSG_RESULT($tcl_cv_langinfo_h) - if test $tcl_cv_langinfo_h = yes; then - AC_DEFINE(HAVE_LANGINFO, 1, [Do we have nl_langinfo()?]) - fi - else - AC_MSG_RESULT([$langinfo_ok]) - fi -]) - -#-------------------------------------------------------------------- -# TEA_CONFIG_CFLAGS -# -# Try to determine the proper flags to pass to the compiler -# for building shared libraries and other such nonsense. -# -# Arguments: -# none -# -# Results: -# -# Defines the following vars: -# -# DL_OBJS - Name of the object file that implements dynamic -# loading for Tcl on this system. -# DL_LIBS - Library file(s) to include in tclsh and other base -# applications in order for the "load" command to work. -# LDFLAGS - Flags to pass to the compiler when linking object -# files into an executable application binary such -# as tclsh. -# LD_SEARCH_FLAGS-Flags to pass to ld, such as "-R /usr/local/tcl/lib", -# that tell the run-time dynamic linker where to look -# for shared libraries such as libtcl.so. Depends on -# the variable LIB_RUNTIME_DIR in the Makefile. -# SHLIB_CFLAGS - Flags to pass to cc when compiling the components -# of a shared library (may request position-independent -# code, among other things). -# SHLIB_LD - Base command to use for combining object files -# into a shared library. -# SHLIB_LD_LIBS - Dependent libraries for the linker to scan when -# creating shared libraries. This symbol typically -# goes at the end of the "ld" commands that build -# shared libraries. The value of the symbol is -# "${LIBS}" if all of the dependent libraries should -# be specified when creating a shared library. If -# dependent libraries should not be specified (as on -# SunOS 4.x, where they cause the link to fail, or in -# general if Tcl and Tk aren't themselves shared -# libraries), then this symbol has an empty string -# as its value. -# SHLIB_SUFFIX - Suffix to use for the names of dynamically loadable -# extensions. An empty string means we don't know how -# to use shared libraries on this platform. -# TCL_LIB_FILE - Name of the file that contains the Tcl library, such -# as libtcl7.8.so or libtcl7.8.a. -# TCL_LIB_SUFFIX -Specifies everything that comes after the "libtcl" -# in the shared library name, using the -# ${PACKAGE_VERSION} variable to put the version in -# the right place. This is used by platforms that -# need non-standard library names. -# Examples: ${PACKAGE_VERSION}.so.1.1 on NetBSD, -# since it needs to have a version after the .so, and -# ${PACKAGE_VERSION}.a on AIX, since the Tcl shared -# library needs to have a .a extension whereas shared -# objects for loadable extensions have a .so -# extension. Defaults to -# ${PACKAGE_VERSION}${SHLIB_SUFFIX}. -# TCL_NEEDS_EXP_FILE - -# 1 means that an export file is needed to link to a -# shared library. -# TCL_EXP_FILE - The name of the installed export / import file which -# should be used to link to the Tcl shared library. -# Empty if Tcl is unshared. -# TCL_BUILD_EXP_FILE - -# The name of the built export / import file which -# should be used to link to the Tcl shared library. -# Empty if Tcl is unshared. -# CFLAGS_DEBUG - -# Flags used when running the compiler in debug mode -# CFLAGS_OPTIMIZE - -# Flags used when running the compiler in optimize mode -# CFLAGS - We add CFLAGS to pass to the compiler -# -# Subst's the following vars: -# DL_LIBS -# CFLAGS_DEBUG -# CFLAGS_OPTIMIZE -# CFLAGS_WARNING -# -# STLIB_LD -# SHLIB_LD -# SHLIB_CFLAGS -# LDFLAGS_DEBUG -# LDFLAGS_OPTIMIZE -#-------------------------------------------------------------------- - -AC_DEFUN(TEA_CONFIG_CFLAGS, [ - dnl Make sure we are initialized - AC_REQUIRE([TEA_INIT]) - - # Step 0: Enable 64 bit support? - - AC_MSG_CHECKING([if 64bit support is enabled]) - AC_ARG_ENABLE(64bit,[ --enable-64bit enable 64bit support (where applicable)], [do64bit=$enableval], [do64bit=no]) - AC_MSG_RESULT([$do64bit]) - - # Step 0.b: Enable Solaris 64 bit VIS support? - - AC_MSG_CHECKING([if 64bit Sparc VIS support is requested]) - AC_ARG_ENABLE(64bit-vis,[ --enable-64bit-vis enable 64bit Sparc VIS support], [do64bitVIS=$enableval], [do64bitVIS=no]) - AC_MSG_RESULT([$do64bitVIS]) - - if test "$do64bitVIS" = "yes"; then - # Force 64bit on with VIS - do64bit=yes - fi - - # Step 0.c: Cross-compiling options for Windows/CE builds? - - if test "${TEA_PLATFORM}" = "windows" ; then - AC_MSG_CHECKING([if Windows/CE build is requested]) - AC_ARG_ENABLE(wince,[ --enable-wince enable Win/CE support (where applicable)], [doWince=$enableval], [doWince=no]) - AC_MSG_RESULT($doWince) - fi - - # Step 1: set the variable "system" to hold the name and version number - # for the system. This can usually be done via the "uname" command, but - # there are a few systems, like Next, where this doesn't work. - - AC_MSG_CHECKING([system version (for dynamic loading)]) - if test -f /usr/lib/NextStep/software_version; then - system=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` - else - system=`uname -s`-`uname -r` - if test "$?" -ne 0 ; then - AC_MSG_RESULT([unknown (can't find uname command)]) - system=unknown - else - # Special check for weird MP-RAS system (uname returns weird - # results, and the version is kept in special file). - - if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then - system=MP-RAS-`awk '{print $3}' /etc/.relid` - fi - if test "`uname -s`" = "AIX" ; then - system=AIX-`uname -v`.`uname -r` - fi - if test "${TEA_PLATFORM}" = "windows" ; then - system=windows - fi - AC_MSG_RESULT([$system]) - fi - fi - - # Step 2: check for existence of -ldl library. This is needed because - # Linux can use either -ldl or -ldld for dynamic loading. - - AC_CHECK_LIB(dl, dlopen, have_dl=yes, have_dl=no) - - # Step 3: set configuration options based on system name and version. - # This is similar to Tcl's unix/tcl.m4 except that we've added a - # "windows" case and CC_SEARCH_FLAGS becomes LD_SEARCH_FLAGS for us - # (and we have no CC_SEARCH_FLAGS). - - do64bit_ok=no - LDFLAGS_ORIG="$LDFLAGS" - TCL_EXPORT_FILE_SUFFIX="" - UNSHARED_LIB_SUFFIX="" - TCL_TRIM_DOTS='`echo ${PACKAGE_VERSION} | tr -d .`' - ECHO_VERSION='`echo ${PACKAGE_VERSION}`' - TCL_LIB_VERSIONS_OK=ok - CFLAGS_DEBUG=-g - if test "$GCC" = "yes" ; then - CFLAGS_OPTIMIZE=-O2 - CFLAGS_WARNING="-Wall -Wno-implicit-int" - else - CFLAGS_OPTIMIZE=-O - CFLAGS_WARNING="" - fi - TCL_NEEDS_EXP_FILE=0 - TCL_BUILD_EXP_FILE="" - TCL_EXP_FILE="" -dnl FIXME: Replace AC_CHECK_PROG with AC_CHECK_TOOL once cross compiling is fixed. -dnl AC_CHECK_TOOL(AR, ar, :) - AC_CHECK_PROG(AR, ar, ar) - STLIB_LD='${AR} cr' - LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH" - case $system in - windows) - # This is a 2-stage check to make sure we have the 64-bit SDK - # We have to know where the SDK is installed. - # This magic is based on MS Platform SDK for Win2003 SP1 - hobbs - # MACHINE is IX86 for LINK, but this is used by the manifest, - # which requires x86|amd64|ia64. - MACHINE="X86" - if test "$do64bit" != "no" ; then - if test "x${MSSDK}x" = "xx" ; then - MSSDK="C:/Progra~1/Microsoft Platform SDK" - fi - MSSDK=`echo "$MSSDK" | sed -e 's!\\\!/!g'` - PATH64="" - case "$do64bit" in - amd64|x64|yes) - MACHINE="AMD64" ; # default to AMD64 64-bit build - PATH64="${MSSDK}/Bin/Win64/x86/AMD64" - ;; - ia64) - MACHINE="IA64" - PATH64="${MSSDK}/Bin/Win64" - ;; - esac - if test ! -d "${PATH64}" ; then - AC_MSG_WARN([Could not find 64-bit $MACHINE SDK to enable 64bit mode]) - AC_MSG_WARN([Ensure latest Platform SDK is installed]) - do64bit="no" - else - AC_MSG_RESULT([ Using 64-bit $MACHINE mode]) - do64bit_ok="yes" - fi - fi - - if test "$doWince" != "no" ; then - if test "$do64bit" != "no" ; then - AC_MSG_ERROR([Windows/CE and 64-bit builds incompatible]) - fi - if test "$GCC" = "yes" ; then - AC_MSG_ERROR([Windows/CE and GCC builds incompatible]) - fi - TEA_PATH_CELIB - # Set defaults for common evc4/PPC2003 setup - # Currently Tcl requires 300+, possibly 420+ for sockets - CEVERSION=420; # could be 211 300 301 400 420 ... - TARGETCPU=ARMV4; # could be ARMV4 ARM MIPS SH3 X86 ... - ARCH=ARM; # could be ARM MIPS X86EM ... - PLATFORM="Pocket PC 2003"; # or "Pocket PC 2002" - if test "$doWince" != "yes"; then - # If !yes then the user specified something - # Reset ARCH to allow user to skip specifying it - ARCH= - eval `echo $doWince | awk -F, '{ \ - if (length([$]1)) { printf "CEVERSION=\"%s\"\n", [$]1; \ - if ([$]1 < 400) { printf "PLATFORM=\"Pocket PC 2002\"\n" } }; \ - if (length([$]2)) { printf "TARGETCPU=\"%s\"\n", toupper([$]2) }; \ - if (length([$]3)) { printf "ARCH=\"%s\"\n", toupper([$]3) }; \ - if (length([$]4)) { printf "PLATFORM=\"%s\"\n", [$]4 }; \ - }'` - if test "x${ARCH}" = "x" ; then - ARCH=$TARGETCPU; - fi - fi - OSVERSION=WCE$CEVERSION; - if test "x${WCEROOT}" = "x" ; then - WCEROOT="C:/Program Files/Microsoft eMbedded C++ 4.0" - if test ! -d "${WCEROOT}" ; then - WCEROOT="C:/Program Files/Microsoft eMbedded Tools" - fi - fi - if test "x${SDKROOT}" = "x" ; then - SDKROOT="C:/Program Files/Windows CE Tools" - if test ! -d "${SDKROOT}" ; then - SDKROOT="C:/Windows CE Tools" - fi - fi - WCEROOT=`echo "$WCEROOT" | sed -e 's!\\\!/!g'` - SDKROOT=`echo "$SDKROOT" | sed -e 's!\\\!/!g'` - if test ! -d "${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" \ - -o ! -d "${WCEROOT}/EVC/${OSVERSION}/bin"; then - AC_MSG_ERROR([could not find PocketPC SDK or target compiler to enable WinCE mode [$CEVERSION,$TARGETCPU,$ARCH,$PLATFORM]]) - doWince="no" - else - # We could PATH_NOSPACE these, but that's not important, - # as long as we quote them when used. - CEINCLUDE="${SDKROOT}/${OSVERSION}/${PLATFORM}/include" - if test -d "${CEINCLUDE}/${TARGETCPU}" ; then - CEINCLUDE="${CEINCLUDE}/${TARGETCPU}" - fi - CELIBPATH="${SDKROOT}/${OSVERSION}/${PLATFORM}/Lib/${TARGETCPU}" - fi - fi - - if test "$GCC" != "yes" ; then - if test "${SHARED_BUILD}" = "0" ; then - runtime=-MT - else - runtime=-MD - fi - - if test "$do64bit" != "no" ; then - # All this magic is necessary for the Win64 SDK RC1 - hobbs - CC="\"${PATH64}/cl.exe\"" - CFLAGS="${CFLAGS} -I\"${MSSDK}/Include\" -I\"${MSSDK}/Include/crt\" -I\"${MSSDK}/Include/crt/sys\"" - RC="\"${MSSDK}/bin/rc.exe\"" - lflags="-nologo -MACHINE:${MACHINE} -LIBPATH:\"${MSSDK}/Lib/${MACHINE}\"" - LINKBIN="\"${PATH64}/link.exe\"" - CFLAGS_DEBUG="-nologo -Zi -Od -W3 ${runtime}d" - CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" - # Avoid 'unresolved external symbol __security_cookie' - # errors, c.f. http://support.microsoft.com/?id=894573 - TEA_ADD_LIBS([bufferoverflowU.lib]) - elif test "$doWince" != "no" ; then - CEBINROOT="${WCEROOT}/EVC/${OSVERSION}/bin" - if test "${TARGETCPU}" = "X86"; then - CC="\"${CEBINROOT}/cl.exe\"" - else - CC="\"${CEBINROOT}/cl${ARCH}.exe\"" - fi - CFLAGS="$CFLAGS -I\"${CELIB_DIR}/inc\" -I\"${CEINCLUDE}\"" - RC="\"${WCEROOT}/Common/EVC/bin/rc.exe\"" - arch=`echo ${ARCH} | awk '{print tolower([$]0)}'` - defs="${ARCH} _${ARCH}_ ${arch} PALM_SIZE _MT _WINDOWS" - if test "${SHARED_BUILD}" = "1" ; then - # Static CE builds require static celib as well - defs="${defs} _DLL" - fi - for i in $defs ; do - AC_DEFINE_UNQUOTED($i, 1, [WinCE def ]$i) - done - AC_DEFINE_UNQUOTED(_WIN32_WCE, $CEVERSION, [_WIN32_WCE version]) - AC_DEFINE_UNQUOTED(UNDER_CE, $CEVERSION, [UNDER_CE version]) - CFLAGS_DEBUG="-nologo -Zi -Od" - CFLAGS_OPTIMIZE="-nologo -Ox" - lversion=`echo ${CEVERSION} | sed -e 's/\(.\)\(..\)/\1\.\2/'` - lflags="-MACHINE:${ARCH} -LIBPATH:\"${CELIBPATH}\" -subsystem:windowsce,${lversion} -nologo" - LINKBIN="\"${CEBINROOT}/link.exe\"" - AC_SUBST(CELIB_DIR) - else - RC="rc" - lflags="-nologo" - LINKBIN="link" - CFLAGS_DEBUG="-nologo -Z7 -Od -W3 -WX ${runtime}d" - CFLAGS_OPTIMIZE="-nologo -O2 -W2 ${runtime}" - fi - fi - - if test "$GCC" = "yes"; then - # mingw gcc mode - RC="windres" - CFLAGS_DEBUG="-g" - CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" - SHLIB_LD="$CC -shared" - UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' - LDFLAGS_CONSOLE="-wl,--subsystem,console ${lflags}" - LDFLAGS_WINDOW="-wl,--subsystem,windows ${lflags}" - else - SHLIB_LD="${LINKBIN} -dll ${lflags}" - # link -lib only works when -lib is the first arg - STLIB_LD="${LINKBIN} -lib ${lflags}" - UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.lib' - PATHTYPE=-w - # For information on what debugtype is most useful, see: - # http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp - # This essentially turns it all on. - LDFLAGS_DEBUG="-debug:full -debugtype:both -warn:2" - LDFLAGS_OPTIMIZE="-release" - if test "$doWince" != "no" ; then - LDFLAGS_CONSOLE="-link ${lflags}" - LDFLAGS_WINDOW=${LDFLAGS_CONSOLE} - else - LDFLAGS_CONSOLE="-link -subsystem:console ${lflags}" - LDFLAGS_WINDOW="-link -subsystem:windows ${lflags}" - fi - fi - - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".dll" - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.dll' - - TCL_LIB_VERSIONS_OK=nodots - # Bogus to avoid getting this turned off - DL_OBJS="tclLoadNone.obj" - ;; - AIX-*) - if test "${TCL_THREADS}" = "1" -a "$GCC" != "yes" ; then - # AIX requires the _r compiler when gcc isn't being used - case "${CC}" in - *_r) - # ok ... - ;; - *) - CC=${CC}_r - ;; - esac - AC_MSG_RESULT([Using $CC for compiling with threads]) - fi - LIBS="$LIBS -lc" - SHLIB_CFLAGS="" - SHLIB_SUFFIX=".so" - SHLIB_LD_LIBS='${LIBS}' - - DL_OBJS="tclLoadDl.o" - LD_LIBRARY_PATH_VAR="LIBPATH" - - # AIX v<=4.1 has some different flags than 4.2+ - if test "$system" = "AIX-4.1" -o "`uname -v`" -lt "4" ; then - #LIBOBJS="$LIBOBJS tclLoadAix.o" - AC_LIBOBJ([tclLoadAix]) - DL_LIBS="-lld" - fi - - # Check to enable 64-bit flags for compiler/linker on AIX 4+ - if test "$do64bit" = "yes" -a "`uname -v`" -gt "3" ; then - if test "$GCC" = "yes" ; then - AC_MSG_WARN("64bit mode not supported with GCC on $system") - else - do64bit_ok=yes - CFLAGS="$CFLAGS -q64" - LDFLAGS="$LDFLAGS -q64" - RANLIB="${RANLIB} -X64" - AR="${AR} -X64" - SHLIB_LD_FLAGS="-b64" - fi - fi - - if test "`uname -m`" = "ia64" ; then - # AIX-5 uses ELF style dynamic libraries on IA-64, but not PPC - SHLIB_LD="/usr/ccs/bin/ld -G -z text" - # AIX-5 has dl* in libc.so - DL_LIBS="" - if test "$GCC" = "yes" ; then - LD_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' - else - LD_SEARCH_FLAGS='-R${LIB_RUNTIME_DIR}' - fi - else - if test "$GCC" = "yes" ; then - SHLIB_LD="gcc -shared" - else - SHLIB_LD="/bin/ld -bhalt:4 -bM:SRE -bE:lib.exp -H512 -T512 -bnoentry" - fi - SHLIB_LD="${TCL_SRC_DIR}/unix/ldAix ${SHLIB_LD} ${SHLIB_LD_FLAGS}" - DL_LIBS="-ldl" - LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' - TCL_NEEDS_EXP_FILE=1 - TCL_EXPORT_FILE_SUFFIX='${PACKAGE_VERSION}.exp' - fi - - # On AIX <=v4 systems, libbsd.a has to be linked in to support - # non-blocking file IO. This library has to be linked in after - # the MATH_LIBS or it breaks the pow() function. The way to - # insure proper sequencing, is to add it to the tail of MATH_LIBS. - # This library also supplies gettimeofday. - # - # AIX does not have a timezone field in struct tm. When the AIX - # bsd library is used, the timezone global and the gettimeofday - # methods are to be avoided for timezone deduction instead, we - # deduce the timezone by comparing the localtime result on a - # known GMT value. - - AC_CHECK_LIB(bsd, gettimeofday, libbsd=yes, libbsd=no) - if test $libbsd = yes; then - MATH_LIBS="$MATH_LIBS -lbsd" - AC_DEFINE(USE_DELTA_FOR_TZ, 1, [Do we need a special AIX hack for timezones?]) - fi - ;; - BeOS*) - SHLIB_CFLAGS="-fPIC" - SHLIB_LD="${CC} -nostart" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - ;; - BSD/OS-2.1*|BSD/OS-3*) - SHLIB_CFLAGS="" - SHLIB_LD="shlicc -r" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - LD_SEARCH_FLAGS="" - ;; - BSD/OS-4.*) - SHLIB_CFLAGS="-export-dynamic -fPIC" - SHLIB_LD="cc -shared" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - LDFLAGS="$LDFLAGS -export-dynamic" - LD_SEARCH_FLAGS="" - ;; - dgux*) - SHLIB_CFLAGS="-K PIC" - SHLIB_LD="cc -G" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - LD_SEARCH_FLAGS="" - ;; - HP-UX-*.11.*) - # Use updated header definitions where possible - AC_DEFINE(_XOPEN_SOURCE_EXTENDED, 1, [Do we want to use the XOPEN network library?]) - - SHLIB_SUFFIX=".sl" - AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) - if test "$tcl_ok" = yes; then - SHLIB_CFLAGS="+z" - SHLIB_LD="ld -b" - SHLIB_LD_LIBS='${LIBS}' - DL_OBJS="tclLoadShl.o" - DL_LIBS="-ldld" - LDFLAGS="$LDFLAGS -Wl,-E" - LD_SEARCH_FLAGS='+s +b ${LIB_RUNTIME_DIR}:.' - LD_LIBRARY_PATH_VAR="SHLIB_PATH" - fi - if test "$GCC" = "yes" ; then - SHLIB_LD="gcc -shared" - SHLIB_LD_LIBS='${LIBS}' - LD_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' - fi - - # Users may want PA-RISC 1.1/2.0 portable code - needs HP cc - #CFLAGS="$CFLAGS +DAportable" - - # Check to enable 64-bit flags for compiler/linker - if test "$do64bit" = "yes" ; then - if test "$GCC" = "yes" ; then - hpux_arch=`${CC} -dumpmachine` - case $hpux_arch in - hppa64*) - # 64-bit gcc in use. Fix flags for GNU ld. - do64bit_ok=yes - SHLIB_LD="${CC} -shared" - SHLIB_LD_LIBS='${LIBS}' - ;; - *) - AC_MSG_WARN("64bit mode not supported with GCC on $system") - ;; - esac - else - do64bit_ok=yes - CFLAGS="$CFLAGS +DD64" - LDFLAGS="$LDFLAGS +DD64" - fi - fi - ;; - HP-UX-*.08.*|HP-UX-*.09.*|HP-UX-*.10.*) - SHLIB_SUFFIX=".sl" - AC_CHECK_LIB(dld, shl_load, tcl_ok=yes, tcl_ok=no) - if test "$tcl_ok" = yes; then - SHLIB_CFLAGS="+z" - SHLIB_LD="ld -b" - SHLIB_LD_LIBS="" - DL_OBJS="tclLoadShl.o" - DL_LIBS="-ldld" - LDFLAGS="$LDFLAGS -Wl,-E" - LD_SEARCH_FLAGS='-Wl,+s,+b,${LIB_RUNTIME_DIR}:.' - fi - LD_LIBRARY_PATH_VAR="SHLIB_PATH" - ;; - IRIX-4.*) - SHLIB_CFLAGS="-G 0" - SHLIB_SUFFIX=".a" - SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" - SHLIB_LD_LIBS='${LIBS}' - DL_OBJS="tclLoadAout.o" - DL_LIBS="" - LDFLAGS="$LDFLAGS -Wl,-D,08000000" - LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' - SHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' - ;; - IRIX-5.*) - SHLIB_CFLAGS="" - SHLIB_LD="ld -shared -rdata_shared" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="" - LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' - ;; - IRIX-6.*|IRIX64-6.5*) - SHLIB_CFLAGS="" - SHLIB_LD="ld -n32 -shared -rdata_shared" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="" - LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' - if test "$GCC" = "yes" ; then - CFLAGS="$CFLAGS -mabi=n32" - LDFLAGS="$LDFLAGS -mabi=n32" - else - case $system in - IRIX-6.3) - # Use to build 6.2 compatible binaries on 6.3. - CFLAGS="$CFLAGS -n32 -D_OLD_TERMIOS" - ;; - *) - CFLAGS="$CFLAGS -n32" - ;; - esac - LDFLAGS="$LDFLAGS -n32" - fi - ;; - IRIX64-6.*) - SHLIB_CFLAGS="" - SHLIB_LD="ld -n32 -shared -rdata_shared" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="" - LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' - - # Check to enable 64-bit flags for compiler/linker - - if test "$do64bit" = "yes" ; then - if test "$GCC" = "yes" ; then - AC_MSG_WARN([64bit mode not supported by gcc]) - else - do64bit_ok=yes - SHLIB_LD="ld -64 -shared -rdata_shared" - CFLAGS="$CFLAGS -64" - LDFLAGS="$LDFLAGS -64" - fi - fi - ;; - Linux*) - SHLIB_CFLAGS="-fPIC" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - - CFLAGS_OPTIMIZE="-O2 -fomit-frame-pointer" - # egcs-2.91.66 on Redhat Linux 6.0 generates lots of warnings - # when you inline the string and math operations. Turn this off to - # get rid of the warnings. - - #CFLAGS_OPTIMIZE="${CFLAGS_OPTIMIZE} -D__NO_STRING_INLINES -D__NO_MATH_INLINES" - - if test "$have_dl" = yes; then - SHLIB_LD="${CC} -shared" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - LDFLAGS="$LDFLAGS -Wl,--export-dynamic" - LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' - else - AC_CHECK_HEADER(dld.h, [ - SHLIB_LD="ld -shared" - DL_OBJS="tclLoadDld.o" - DL_LIBS="-ldld" - LD_SEARCH_FLAGS=""]) - fi - if test "`uname -m`" = "alpha" ; then - CFLAGS="$CFLAGS -mieee" - fi - - # The combo of gcc + glibc has a bug related - # to inlining of functions like strtod(). The - # -fno-builtin flag should address this problem - # but it does not work. The -fno-inline flag - # is kind of overkill but it works. - # Disable inlining only when one of the - # files in compat/*.c is being linked in. - if test x"${USE_COMPAT}" != x ; then - CFLAGS="$CFLAGS -fno-inline" - fi - - ;; - GNU*) - SHLIB_CFLAGS="-fPIC" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - - if test "$have_dl" = yes; then - SHLIB_LD="${CC} -shared" - DL_OBJS="" - DL_LIBS="-ldl" - LDFLAGS="$LDFLAGS -Wl,--export-dynamic" - LD_SEARCH_FLAGS="" - else - AC_CHECK_HEADER(dld.h, [ - SHLIB_LD="ld -shared" - DL_OBJS="" - DL_LIBS="-ldld" - LD_SEARCH_FLAGS=""]) - fi - if test "`uname -m`" = "alpha" ; then - CFLAGS="$CFLAGS -mieee" - fi - ;; - MP-RAS-02*) - SHLIB_CFLAGS="-K PIC" - SHLIB_LD="cc -G" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - LD_SEARCH_FLAGS="" - ;; - MP-RAS-*) - SHLIB_CFLAGS="-K PIC" - SHLIB_LD="cc -G" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - LDFLAGS="$LDFLAGS -Wl,-Bexport" - LD_SEARCH_FLAGS="" - ;; - NetBSD-*|FreeBSD-[[1-2]].*) - # Not available on all versions: check for include file. - AC_CHECK_HEADER(dlfcn.h, [ - # NetBSD/SPARC needs -fPIC, -fpic will not do. - SHLIB_CFLAGS="-fPIC" - SHLIB_LD="ld -Bshareable -x" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="" - LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' - AC_MSG_CHECKING([for ELF]) - AC_EGREP_CPP(yes, [ -#ifdef __ELF__ - yes -#endif - ], - AC_MSG_RESULT([yes]) - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so', - AC_MSG_RESULT([no]) - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' - ) - ], [ - SHLIB_CFLAGS="" - SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".a" - DL_OBJS="tclLoadAout.o" - DL_LIBS="" - LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' - ]) - - # FreeBSD doesn't handle version numbers with dots. - - UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' - TCL_LIB_VERSIONS_OK=nodots - ;; - OpenBSD-*) - SHLIB_LD="${CC} -shared" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="" - LD_SEARCH_FLAGS="" - AC_MSG_CHECKING(for ELF) - AC_EGREP_CPP(yes, [ -#ifdef __ELF__ - yes -#endif - ], - [AC_MSG_RESULT(yes) - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0'], - [AC_MSG_RESULT(no) - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0'] - ) - - # OpenBSD doesn't do version numbers with dots. - UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' - TCL_LIB_VERSIONS_OK=nodots - ;; - FreeBSD-*) - # FreeBSD 3.* and greater have ELF. - SHLIB_CFLAGS="-fPIC" - SHLIB_LD="ld -Bshareable -x" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="" - LDFLAGS="$LDFLAGS -export-dynamic" - LD_SEARCH_FLAGS='-Wl,-rpath,${LIB_RUNTIME_DIR}' - if test "${TCL_THREADS}" = "1" ; then - # The -pthread needs to go in the CFLAGS, not LIBS - LIBS=`echo $LIBS | sed s/-pthread//` - CFLAGS="$CFLAGS -pthread" - LDFLAGS="$LDFLAGS -pthread" - fi - case $system in - FreeBSD-3.*) - # FreeBSD-3 doesn't handle version numbers with dots. - UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so' - TCL_LIB_VERSIONS_OK=nodots - ;; - esac - ;; - Darwin-*) - CFLAGS_OPTIMIZE="-Os" - SHLIB_CFLAGS="-fno-common" - if test $do64bit = yes; then - do64bit_ok=yes - CFLAGS="$CFLAGS -arch ppc64 -mpowerpc64 -mcpu=G5" - fi - SHLIB_LD='${CC} -dynamiclib ${CFLAGS} ${LDFLAGS}' - AC_CACHE_CHECK([if ld accepts -single_module flag], tcl_cv_ld_single_module, [ - hold_ldflags=$LDFLAGS - LDFLAGS="$LDFLAGS -dynamiclib -Wl,-single_module" - AC_TRY_LINK(, [int i;], tcl_cv_ld_single_module=yes, tcl_cv_ld_single_module=no) - LDFLAGS=$hold_ldflags]) - if test $tcl_cv_ld_single_module = yes; then - SHLIB_LD="${SHLIB_LD} -Wl,-single_module" - fi - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".dylib" - DL_OBJS="tclLoadDyld.o" - DL_LIBS="" - # Don't use -prebind when building for Mac OS X 10.4 or later only: - test -z "${MACOSX_DEPLOYMENT_TARGET}" || \ - test "`echo "${MACOSX_DEPLOYMENT_TARGET}" | awk -F. '{print [$]2}'`" -lt 4 && \ - LDFLAGS="$LDFLAGS -prebind" - LDFLAGS="$LDFLAGS -headerpad_max_install_names" - AC_CACHE_CHECK([if ld accepts -search_paths_first flag], tcl_cv_ld_search_paths_first, [ - hold_ldflags=$LDFLAGS - LDFLAGS="$LDFLAGS -Wl,-search_paths_first" - AC_TRY_LINK(, [int i;], tcl_cv_ld_search_paths_first=yes, tcl_cv_ld_search_paths_first=no) - LDFLAGS=$hold_ldflags]) - if test $tcl_cv_ld_search_paths_first = yes; then - LDFLAGS="$LDFLAGS -Wl,-search_paths_first" - fi - LD_SEARCH_FLAGS="" - LD_LIBRARY_PATH_VAR="DYLD_LIBRARY_PATH" - ;; - NEXTSTEP-*) - SHLIB_CFLAGS="" - SHLIB_LD="cc -nostdlib -r" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadNext.o" - DL_LIBS="" - LD_SEARCH_FLAGS="" - ;; - OS/390-*) - CFLAGS_OPTIMIZE="" # Optimizer is buggy - AC_DEFINE(_OE_SOCKETS, 1, # needed in sys/socket.h - [Should OS/390 do the right thing with sockets?]) - ;; - OSF1-1.0|OSF1-1.1|OSF1-1.2) - # OSF/1 1.[012] from OSF, and derivatives, including Paragon OSF/1 - SHLIB_CFLAGS="" - # Hack: make package name same as library name - SHLIB_LD='ld -R -export $@:' - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadOSF.o" - DL_LIBS="" - LD_SEARCH_FLAGS="" - ;; - OSF1-1.*) - # OSF/1 1.3 from OSF using ELF, and derivatives, including AD2 - SHLIB_CFLAGS="-fPIC" - if test "$SHARED_BUILD" = "1" ; then - SHLIB_LD="ld -shared" - else - SHLIB_LD="ld -non_shared" - fi - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="" - LD_SEARCH_FLAGS="" - ;; - OSF1-V*) - # Digital OSF/1 - SHLIB_CFLAGS="" - if test "$SHARED_BUILD" = "1" ; then - SHLIB_LD="${CC} -shared" - else - SHLIB_LD="${CC} -non_shared" - fi - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="" - LD_SEARCH_FLAGS='-rpath ${LIB_RUNTIME_DIR}' - if test "$GCC" = "yes" ; then - CFLAGS="$CFLAGS -mieee" - else - CFLAGS="$CFLAGS -DHAVE_TZSET -std1 -ieee" - fi - # see pthread_intro(3) for pthread support on osf1, k.furukawa - if test "${TCL_THREADS}" = "1" ; then - CFLAGS="$CFLAGS -DHAVE_PTHREAD_ATTR_SETSTACKSIZE" - CFLAGS="$CFLAGS -DTCL_THREAD_STACK_MIN=PTHREAD_STACK_MIN*64" - LIBS=`echo $LIBS | sed s/-lpthreads//` - if test "$GCC" = "yes" ; then - LIBS="$LIBS -lpthread -lmach -lexc" - else - CFLAGS="$CFLAGS -pthread" - LDFLAGS="$LDFLAGS -pthread" - fi - fi - - ;; - QNX-6*) - # QNX RTP - # This may work for all QNX, but it was only reported for v6. - SHLIB_CFLAGS="-fPIC" - SHLIB_LD="ld -Bshareable -x" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - # dlopen is in -lc on QNX - DL_LIBS="" - LD_SEARCH_FLAGS="" - ;; - RISCos-*) - SHLIB_CFLAGS="-G 0" - SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".a" - DL_OBJS="tclLoadAout.o" - DL_LIBS="" - LDFLAGS="$LDFLAGS -Wl,-D,08000000" - LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' - ;; - SCO_SV-3.2*) - # Note, dlopen is available only on SCO 3.2.5 and greater. However, - # this test works, since "uname -s" was non-standard in 3.2.4 and - # below. - if test "$GCC" = "yes" ; then - SHLIB_CFLAGS="-fPIC -melf" - LDFLAGS="$LDFLAGS -melf -Wl,-Bexport" - else - SHLIB_CFLAGS="-Kpic -belf" - LDFLAGS="$LDFLAGS -belf -Wl,-Bexport" - fi - SHLIB_LD="ld -G" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="" - LD_SEARCH_FLAGS="" - ;; - SINIX*5.4*) - SHLIB_CFLAGS="-K PIC" - SHLIB_LD="cc -G" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - LD_SEARCH_FLAGS="" - ;; - SunOS-4*) - SHLIB_CFLAGS="-PIC" - SHLIB_LD="ld" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' - - # SunOS can't handle version numbers with dots in them in library - # specs, like -ltcl7.5, so use -ltcl75 instead. Also, it - # requires an extra version number at the end of .so file names. - # So, the library has to have a name like libtcl75.so.1.0 - - SHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.so.1.0' - UNSHARED_LIB_SUFFIX='${TCL_TRIM_DOTS}.a' - TCL_LIB_VERSIONS_OK=nodots - ;; - SunOS-5.[[0-6]]) - # Careful to not let 5.10+ fall into this case - - # Note: If _REENTRANT isn't defined, then Solaris - # won't define thread-safe library routines. - - AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) - AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, - [Do we really want to follow the standard? Yes we do!]) - - SHLIB_CFLAGS="-KPIC" - - # Note: need the LIBS below, otherwise Tk won't find Tcl's - # symbols when dynamically loaded into tclsh. - - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - if test "$GCC" = "yes" ; then - SHLIB_LD="$CC -shared" - LD_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' - else - SHLIB_LD="/usr/ccs/bin/ld -G -z text" - LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' - fi - ;; - SunOS-5*) - - # Note: If _REENTRANT isn't defined, then Solaris - # won't define thread-safe library routines. - - AC_DEFINE(_REENTRANT, 1, [Do we want the reentrant OS API?]) - AC_DEFINE(_POSIX_PTHREAD_SEMANTICS, 1, - [Do we really want to follow the standard? Yes we do!]) - - SHLIB_CFLAGS="-KPIC" - - # Check to enable 64-bit flags for compiler/linker - if test "$do64bit" = "yes" ; then - arch=`isainfo` - if test "$arch" = "sparcv9 sparc" ; then - if test "$GCC" = "yes" ; then - if test "`gcc -dumpversion` | awk -F. '{print $1}'" -lt "3" ; then - AC_MSG_WARN([64bit mode not supported with GCC < 3.2 on $system]) - else - do64bit_ok=yes - CFLAGS="$CFLAGS -m64 -mcpu=v9" - LDFLAGS="$LDFLAGS -m64 -mcpu=v9" - SHLIB_CFLAGS="-fPIC" - fi - else - do64bit_ok=yes - if test "$do64bitVIS" = "yes" ; then - CFLAGS="$CFLAGS -xarch=v9a" - LDFLAGS="$LDFLAGS -xarch=v9a" - else - CFLAGS="$CFLAGS -xarch=v9" - LDFLAGS="$LDFLAGS -xarch=v9" - fi - # Solaris 64 uses this as well - #LD_LIBRARY_PATH_VAR="LD_LIBRARY_PATH_64" - fi - elif test "$arch" = "amd64 i386" ; then - if test "$GCC" = "yes" ; then - AC_MSG_WARN([64bit mode not supported with GCC on $system]) - else - do64bit_ok=yes - CFLAGS="$CFLAGS -xarch=amd64" - LDFLAGS="$LDFLAGS -xarch=amd64" - fi - else - AC_MSG_WARN([64bit mode not supported for $arch]) - fi - fi - - # Note: need the LIBS below, otherwise Tk won't find Tcl's - # symbols when dynamically loaded into tclsh. - - SHLIB_LD_LIBS='${LIBS}' - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - if test "$GCC" = "yes" ; then - SHLIB_LD="$CC -shared" - LD_SEARCH_FLAGS='-Wl,-R,${LIB_RUNTIME_DIR}' - if test "$do64bit" = "yes" ; then - # We need to specify -static-libgcc or we need to - # add the path to the sparv9 libgcc. - # JH: static-libgcc is necessary for core Tcl, but may - # not be necessary for extensions. - SHLIB_LD="$SHLIB_LD -m64 -mcpu=v9 -static-libgcc" - # for finding sparcv9 libgcc, get the regular libgcc - # path, remove so name and append 'sparcv9' - #v9gcclibdir="`gcc -print-file-name=libgcc_s.so` | ..." - #LD_SEARCH_FLAGS="${LD_SEARCH_FLAGS},-R,$v9gcclibdir" - fi - else - SHLIB_LD="/usr/ccs/bin/ld -G -z text" - LD_SEARCH_FLAGS='-R ${LIB_RUNTIME_DIR}' - fi - ;; - ULTRIX-4.*) - SHLIB_CFLAGS="-G 0" - SHLIB_SUFFIX=".a" - SHLIB_LD="echo tclLdAout $CC \{$SHLIB_CFLAGS\} | `pwd`/tclsh -r -G 0" - SHLIB_LD_LIBS='${LIBS}' - DL_OBJS="tclLoadAout.o" - DL_LIBS="" - LDFLAGS="$LDFLAGS -Wl,-D,08000000" - LD_SEARCH_FLAGS='-L${LIB_RUNTIME_DIR}' - if test "$GCC" != "yes" ; then - CFLAGS="$CFLAGS -DHAVE_TZSET -std1" - fi - ;; - UNIX_SV* | UnixWare-5*) - SHLIB_CFLAGS="-KPIC" - SHLIB_LD="cc -G" - SHLIB_LD_LIBS="" - SHLIB_SUFFIX=".so" - DL_OBJS="tclLoadDl.o" - DL_LIBS="-ldl" - # Some UNIX_SV* systems (unixware 1.1.2 for example) have linkers - # that don't grok the -Bexport option. Test that it does. - hold_ldflags=$LDFLAGS - AC_MSG_CHECKING(for ld accepts -Bexport flag) - LDFLAGS="$LDFLAGS -Wl,-Bexport" - AC_TRY_LINK(, [int i;], [found=yes], - [LDFLAGS=$hold_ldflags found=no]) - AC_MSG_RESULT([$found]) - LD_SEARCH_FLAGS="" - ;; - esac - - if test "$do64bit" != "no" -a "$do64bit_ok" = "no" ; then - AC_MSG_WARN([64bit support being disabled -- don't know magic for this platform]) - fi - - # Step 4: If pseudo-static linking is in use (see K. B. Kenny, "Dynamic - # Loading for Tcl -- What Became of It?". Proc. 2nd Tcl/Tk Workshop, - # New Orleans, LA, Computerized Processes Unlimited, 1994), then we need - # to determine which of several header files defines the a.out file - # format (a.out.h, sys/exec.h, or sys/exec_aout.h). At present, we - # support only a file format that is more or less version-7-compatible. - # In particular, - # - a.out files must begin with `struct exec'. - # - the N_TXTOFF on the `struct exec' must compute the seek address - # of the text segment - # - The `struct exec' must contain a_magic, a_text, a_data, a_bss - # and a_entry fields. - # The following compilation should succeed if and only if either sys/exec.h - # or a.out.h is usable for the purpose. - # - # Note that the modified COFF format used on MIPS Ultrix 4.x is usable; the - # `struct exec' includes a second header that contains information that - # duplicates the v7 fields that are needed. - - if test "x$DL_OBJS" = "xtclLoadAout.o" ; then - AC_MSG_CHECKING([sys/exec.h]) - AC_TRY_COMPILE([#include ],[ - struct exec foo; - unsigned long seek; - int flag; -#if defined(__mips) || defined(mips) - seek = N_TXTOFF (foo.ex_f, foo.ex_o); -#else - seek = N_TXTOFF (foo); -#endif - flag = (foo.a_magic == OMAGIC); - return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; - ], tcl_ok=usable, tcl_ok=unusable) - AC_MSG_RESULT([$tcl_ok]) - if test $tcl_ok = usable; then - AC_DEFINE(USE_SYS_EXEC_H, 1, - [Should we use when doing dynamic loading?]) - else - AC_MSG_CHECKING([a.out.h]) - AC_TRY_COMPILE([#include ],[ - struct exec foo; - unsigned long seek; - int flag; -#if defined(__mips) || defined(mips) - seek = N_TXTOFF (foo.ex_f, foo.ex_o); -#else - seek = N_TXTOFF (foo); -#endif - flag = (foo.a_magic == OMAGIC); - return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; - ], tcl_ok=usable, tcl_ok=unusable) - AC_MSG_RESULT([$tcl_ok]) - if test $tcl_ok = usable; then - AC_DEFINE(USE_A_OUT_H, 1, - [Should we use when doing dynamic loading?]) - else - AC_MSG_CHECKING([sys/exec_aout.h]) - AC_TRY_COMPILE([#include ],[ - struct exec foo; - unsigned long seek; - int flag; -#if defined(__mips) || defined(mips) - seek = N_TXTOFF (foo.ex_f, foo.ex_o); -#else - seek = N_TXTOFF (foo); -#endif - flag = (foo.a_midmag == OMAGIC); - return foo.a_text + foo.a_data + foo.a_bss + foo.a_entry; - ], tcl_ok=usable, tcl_ok=unusable) - AC_MSG_RESULT([$tcl_ok]) - if test $tcl_ok = usable; then - AC_DEFINE(USE_SYS_EXEC_AOUT_H, 1, - [Should we use when doing dynamic loading?]) - else - DL_OBJS="" - fi - fi - fi - fi - - # Step 5: disable dynamic loading if requested via a command-line switch. - - AC_ARG_ENABLE(load, [ --disable-load disallow dynamic loading and "load" command], - [tcl_ok=$enableval], [tcl_ok=yes]) - if test "$tcl_ok" = "no"; then - DL_OBJS="" - fi - - if test "x$DL_OBJS" != "x" ; then - BUILD_DLTEST="\$(DLTEST_TARGETS)" - else - echo "Can't figure out how to do dynamic loading or shared libraries" - echo "on this system." - SHLIB_CFLAGS="" - SHLIB_LD="" - SHLIB_SUFFIX="" - DL_OBJS="tclLoadNone.o" - DL_LIBS="" - LDFLAGS="$LDFLAGS_ORIG" - LD_SEARCH_FLAGS="" - BUILD_DLTEST="" - fi - - # If we're running gcc, then change the C flags for compiling shared - # libraries to the right flags for gcc, instead of those for the - # standard manufacturer compiler. - - if test "$DL_OBJS" != "tclLoadNone.o" ; then - if test "$GCC" = "yes" ; then - case $system in - AIX-*) - ;; - BSD/OS*) - ;; - IRIX*) - ;; - NetBSD-*|FreeBSD-*) - ;; - Darwin-*) - ;; - RISCos-*) - ;; - SCO_SV-3.2*) - ;; - ULTRIX-4.*) - ;; - windows) - ;; - *) - SHLIB_CFLAGS="-fPIC" - ;; - esac - fi - fi - - if test "$SHARED_LIB_SUFFIX" = "" ; then - SHARED_LIB_SUFFIX='${PACKAGE_VERSION}${SHLIB_SUFFIX}' - fi - if test "$UNSHARED_LIB_SUFFIX" = "" ; then - UNSHARED_LIB_SUFFIX='${PACKAGE_VERSION}.a' - fi - - AC_SUBST(DL_LIBS) - AC_SUBST(CFLAGS_DEBUG) - AC_SUBST(CFLAGS_OPTIMIZE) - AC_SUBST(CFLAGS_WARNING) - - AC_SUBST(STLIB_LD) - AC_SUBST(SHLIB_LD) - AC_SUBST(SHLIB_CFLAGS) - AC_SUBST(SHLIB_LD_LIBS) - AC_SUBST(LDFLAGS_DEBUG) - AC_SUBST(LDFLAGS_OPTIMIZE) - AC_SUBST(LD_LIBRARY_PATH_VAR) - - # These must be called after we do the basic CFLAGS checks and - # verify any possible 64-bit or similar switches are necessary - TEA_TCL_EARLY_FLAGS - TEA_TCL_64BIT_FLAGS -]) - -#-------------------------------------------------------------------- -# TEA_SERIAL_PORT -# -# Determine which interface to use to talk to the serial port. -# Note that #include lines must begin in leftmost column for -# some compilers to recognize them as preprocessor directives, -# and some build environments have stdin not pointing at a -# pseudo-terminal (usually /dev/null instead.) -# -# Arguments: -# none -# -# Results: -# -# Defines only one of the following vars: -# HAVE_SYS_MODEM_H -# USE_TERMIOS -# USE_TERMIO -# USE_SGTTY -# -#-------------------------------------------------------------------- - -AC_DEFUN(TEA_SERIAL_PORT, [ - AC_CHECK_HEADERS(sys/modem.h) - AC_MSG_CHECKING([termios vs. termio vs. sgtty]) - AC_CACHE_VAL(tcl_cv_api_serial, [ - AC_TRY_RUN([ -#include - -int main() { - struct termios t; - if (tcgetattr(0, &t) == 0) { - cfsetospeed(&t, 0); - t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; - return 0; - } - return 1; -}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) - if test $tcl_cv_api_serial = no ; then - AC_TRY_RUN([ -#include - -int main() { - struct termio t; - if (ioctl(0, TCGETA, &t) == 0) { - t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; - return 0; - } - return 1; -}], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) - fi - if test $tcl_cv_api_serial = no ; then - AC_TRY_RUN([ -#include - -int main() { - struct sgttyb t; - if (ioctl(0, TIOCGETP, &t) == 0) { - t.sg_ospeed = 0; - t.sg_flags |= ODDP | EVENP | RAW; - return 0; - } - return 1; -}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) - fi - if test $tcl_cv_api_serial = no ; then - AC_TRY_RUN([ -#include -#include - -int main() { - struct termios t; - if (tcgetattr(0, &t) == 0 - || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { - cfsetospeed(&t, 0); - t.c_cflag |= PARENB | PARODD | CSIZE | CSTOPB; - return 0; - } - return 1; -}], tcl_cv_api_serial=termios, tcl_cv_api_serial=no, tcl_cv_api_serial=no) - fi - if test $tcl_cv_api_serial = no; then - AC_TRY_RUN([ -#include -#include - -int main() { - struct termio t; - if (ioctl(0, TCGETA, &t) == 0 - || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { - t.c_cflag |= CBAUD | PARENB | PARODD | CSIZE | CSTOPB; - return 0; - } - return 1; - }], tcl_cv_api_serial=termio, tcl_cv_api_serial=no, tcl_cv_api_serial=no) - fi - if test $tcl_cv_api_serial = no; then - AC_TRY_RUN([ -#include -#include - -int main() { - struct sgttyb t; - if (ioctl(0, TIOCGETP, &t) == 0 - || errno == ENOTTY || errno == ENXIO || errno == EINVAL) { - t.sg_ospeed = 0; - t.sg_flags |= ODDP | EVENP | RAW; - return 0; - } - return 1; -}], tcl_cv_api_serial=sgtty, tcl_cv_api_serial=none, tcl_cv_api_serial=none) - fi]) - case $tcl_cv_api_serial in - termios) AC_DEFINE(USE_TERMIOS, 1, [Use the termios API for serial lines]);; - termio) AC_DEFINE(USE_TERMIO, 1, [Use the termio API for serial lines]);; - sgtty) AC_DEFINE(USE_SGTTY, 1, [Use the sgtty API for serial lines]);; - esac - AC_MSG_RESULT([$tcl_cv_api_serial]) -]) - -#-------------------------------------------------------------------- -# TEA_MISSING_POSIX_HEADERS -# -# Supply substitutes for missing POSIX header files. Special -# notes: -# - stdlib.h doesn't define strtol, strtoul, or -# strtod insome versions of SunOS -# - some versions of string.h don't declare procedures such -# as strstr -# -# Arguments: -# none -# -# Results: -# -# Defines some of the following vars: -# NO_DIRENT_H -# NO_ERRNO_H -# NO_VALUES_H -# HAVE_LIMITS_H or NO_LIMITS_H -# NO_STDLIB_H -# NO_STRING_H -# NO_SYS_WAIT_H -# NO_DLFCN_H -# HAVE_SYS_PARAM_H -# -# HAVE_STRING_H ? -# -# tkUnixPort.h checks for HAVE_LIMITS_H, so do both HAVE and -# CHECK on limits.h -#-------------------------------------------------------------------- - -AC_DEFUN(TEA_MISSING_POSIX_HEADERS, [ - AC_MSG_CHECKING([dirent.h]) - AC_CACHE_VAL(tcl_cv_dirent_h, - AC_TRY_LINK([#include -#include ], [ -#ifndef _POSIX_SOURCE -# ifdef __Lynx__ - /* - * Generate compilation error to make the test fail: Lynx headers - * are only valid if really in the POSIX environment. - */ - - missing_procedure(); -# endif -#endif -DIR *d; -struct dirent *entryPtr; -char *p; -d = opendir("foobar"); -entryPtr = readdir(d); -p = entryPtr->d_name; -closedir(d); -], tcl_cv_dirent_h=yes, tcl_cv_dirent_h=no)) - - if test $tcl_cv_dirent_h = no; then - AC_DEFINE(NO_DIRENT_H, 1, [Do we have ?]) - fi - - AC_MSG_RESULT([$tcl_ok]) - AC_CHECK_HEADER(errno.h, , [AC_DEFINE(NO_ERRNO_H, 1, [Do we have ?])]) - AC_CHECK_HEADER(float.h, , [AC_DEFINE(NO_FLOAT_H, 1, [Do we have ?])]) - AC_CHECK_HEADER(values.h, , [AC_DEFINE(NO_VALUES_H, 1, [Do we have ?])]) - AC_CHECK_HEADER(limits.h, - [AC_DEFINE(HAVE_LIMITS_H, 1, [Do we have ?])], - [AC_DEFINE(NO_LIMITS_H, 1, [Do we have ?])]) - AC_CHECK_HEADER(stdlib.h, tcl_ok=1, tcl_ok=0) - AC_EGREP_HEADER(strtol, stdlib.h, , tcl_ok=0) - AC_EGREP_HEADER(strtoul, stdlib.h, , tcl_ok=0) - AC_EGREP_HEADER(strtod, stdlib.h, , tcl_ok=0) - if test $tcl_ok = 0; then - AC_DEFINE(NO_STDLIB_H, 1, [Do we have ?]) - fi - AC_CHECK_HEADER(string.h, tcl_ok=1, tcl_ok=0) - AC_EGREP_HEADER(strstr, string.h, , tcl_ok=0) - AC_EGREP_HEADER(strerror, string.h, , tcl_ok=0) - - # See also memmove check below for a place where NO_STRING_H can be - # set and why. - - if test $tcl_ok = 0; then - AC_DEFINE(NO_STRING_H, 1, [Do we have ?]) - fi - - AC_CHECK_HEADER(sys/wait.h, , [AC_DEFINE(NO_SYS_WAIT_H, 1, [Do we have ?])]) - AC_CHECK_HEADER(dlfcn.h, , [AC_DEFINE(NO_DLFCN_H, 1, [Do we have ?])]) - - # OS/390 lacks sys/param.h (and doesn't need it, by chance). - AC_HAVE_HEADERS(sys/param.h) - -]) - -#-------------------------------------------------------------------- -# TEA_PATH_X -# -# Locate the X11 header files and the X11 library archive. Try -# the ac_path_x macro first, but if it doesn't find the X stuff -# (e.g. because there's no xmkmf program) then check through -# a list of possible directories. Under some conditions the -# autoconf macro will return an include directory that contains -# no include files, so double-check its result just to be safe. -# -# This should be called after TEA_CONFIG_CFLAGS as setting the -# LIBS line can confuse some configure macro magic. -# -# Arguments: -# none -# -# Results: -# -# Sets the following vars: -# XINCLUDES -# XLIBSW -# LIBS (appends to) -# TEA_WINDOWINGSYSTEM -# -#-------------------------------------------------------------------- - -AC_DEFUN(TEA_PATH_X, [ - if test "${TEA_WINDOWINGSYSTEM}" = "x11" ; then - TEA_PATH_UNIX_X - fi -]) - -AC_DEFUN(TEA_PATH_UNIX_X, [ - AC_PATH_X - not_really_there="" - if test "$no_x" = ""; then - if test "$x_includes" = ""; then - AC_TRY_CPP([#include ], , not_really_there="yes") - else - if test ! -r $x_includes/X11/Intrinsic.h; then - not_really_there="yes" - fi - fi - fi - if test "$no_x" = "yes" -o "$not_really_there" = "yes"; then - AC_MSG_CHECKING([for X11 header files]) - XINCLUDES="# no special path needed" - AC_TRY_CPP([#include ], , XINCLUDES="nope") - if test "$XINCLUDES" = nope; then - dirs="/usr/unsupported/include /usr/local/include /usr/X386/include /usr/X11R6/include /usr/X11R5/include /usr/include/X11R5 /usr/include/X11R4 /usr/openwin/include /usr/X11/include /usr/sww/include" - for i in $dirs ; do - if test -r $i/X11/Intrinsic.h; then - AC_MSG_RESULT([$i]) - XINCLUDES=" -I$i" - break - fi - done - fi - else - if test "$x_includes" != ""; then - XINCLUDES=-I$x_includes - else - XINCLUDES="# no special path needed" - fi - fi - if test "$XINCLUDES" = nope; then - AC_MSG_RESULT([could not find any!]) - XINCLUDES="# no include files found" - fi - - if test "$no_x" = yes; then - AC_MSG_CHECKING([for X11 libraries]) - XLIBSW=nope - dirs="/usr/unsupported/lib /usr/local/lib /usr/X386/lib /usr/X11R6/lib /usr/X11R5/lib /usr/lib/X11R5 /usr/lib/X11R4 /usr/openwin/lib /usr/X11/lib /usr/sww/X11/lib" - for i in $dirs ; do - if test -r $i/libX11.a -o -r $i/libX11.so -o -r $i/libX11.sl; then - AC_MSG_RESULT([$i]) - XLIBSW="-L$i -lX11" - x_libraries="$i" - break - fi - done - else - if test "$x_libraries" = ""; then - XLIBSW=-lX11 - else - XLIBSW="-L$x_libraries -lX11" - fi - fi - if test "$XLIBSW" = nope ; then - AC_CHECK_LIB(Xwindow, XCreateWindow, XLIBSW=-lXwindow) - fi - if test "$XLIBSW" = nope ; then - AC_MSG_RESULT([could not find any! Using -lX11.]) - XLIBSW=-lX11 - fi - if test x"${XLIBSW}" != x ; then - PKG_LIBS="${PKG_LIBS} ${XLIBSW}" - fi -]) - -#-------------------------------------------------------------------- -# TEA_BLOCKING_STYLE -# -# The statements below check for systems where POSIX-style -# non-blocking I/O (O_NONBLOCK) doesn't work or is unimplemented. -# On these systems (mostly older ones), use the old BSD-style -# FIONBIO approach instead. -# -# Arguments: -# none -# -# Results: -# -# Defines some of the following vars: -# HAVE_SYS_IOCTL_H -# HAVE_SYS_FILIO_H -# USE_FIONBIO -# O_NONBLOCK -# -#-------------------------------------------------------------------- - -AC_DEFUN(TEA_BLOCKING_STYLE, [ - AC_CHECK_HEADERS(sys/ioctl.h) - AC_CHECK_HEADERS(sys/filio.h) - AC_MSG_CHECKING([FIONBIO vs. O_NONBLOCK for nonblocking I/O]) - if test -f /usr/lib/NextStep/software_version; then - system=NEXTSTEP-`awk '/3/,/3/' /usr/lib/NextStep/software_version` - else - system=`uname -s`-`uname -r` - if test "$?" -ne 0 ; then - system=unknown - else - # Special check for weird MP-RAS system (uname returns weird - # results, and the version is kept in special file). - - if test -r /etc/.relid -a "X`uname -n`" = "X`uname -s`" ; then - system=MP-RAS-`awk '{print $3}' /etc/.relid` - fi - if test "`uname -s`" = "AIX" ; then - system=AIX-`uname -v`.`uname -r` - fi - fi - fi - case $system in - # There used to be code here to use FIONBIO under AIX. However, it - # was reported that FIONBIO doesn't work under AIX 3.2.5. Since - # using O_NONBLOCK seems fine under AIX 4.*, I removed the FIONBIO - # code (JO, 5/31/97). - - OSF*) - AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) - AC_MSG_RESULT([FIONBIO]) - ;; - SunOS-4*) - AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) - AC_MSG_RESULT([FIONBIO]) - ;; - ULTRIX-4.*) - AC_DEFINE(USE_FIONBIO, 1, [Should we use FIONBIO?]) - AC_MSG_RESULT([FIONBIO]) - ;; - *) - AC_MSG_RESULT([O_NONBLOCK]) - ;; - esac -]) - -#-------------------------------------------------------------------- -# TEA_TIME_HANLDER -# -# Checks how the system deals with time.h, what time structures -# are used on the system, and what fields the structures have. -# -# Arguments: -# none -# -# Results: -# -# Defines some of the following vars: -# USE_DELTA_FOR_TZ -# HAVE_TM_GMTOFF -# HAVE_TM_TZADJ -# HAVE_TIMEZONE_VAR -# -#-------------------------------------------------------------------- - -AC_DEFUN(TEA_TIME_HANDLER, [ - AC_CHECK_HEADERS(sys/time.h) - AC_HEADER_TIME - AC_STRUCT_TIMEZONE - - AC_CHECK_FUNCS(gmtime_r localtime_r) - - AC_MSG_CHECKING([tm_tzadj in struct tm]) - AC_CACHE_VAL(tcl_cv_member_tm_tzadj, - AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_tzadj;], - tcl_cv_member_tm_tzadj=yes, tcl_cv_member_tm_tzadj=no)) - AC_MSG_RESULT([$tcl_cv_member_tm_tzadj]) - if test $tcl_cv_member_tm_tzadj = yes ; then - AC_DEFINE(HAVE_TM_TZADJ, 1, [Should we use the tm_tzadj field of struct tm?]) - fi - - AC_MSG_CHECKING([tm_gmtoff in struct tm]) - AC_CACHE_VAL(tcl_cv_member_tm_gmtoff, - AC_TRY_COMPILE([#include ], [struct tm tm; tm.tm_gmtoff;], - tcl_cv_member_tm_gmtoff=yes, tcl_cv_member_tm_gmtoff=no)) - AC_MSG_RESULT([$tcl_cv_member_tm_gmtoff]) - if test $tcl_cv_member_tm_gmtoff = yes ; then - AC_DEFINE(HAVE_TM_GMTOFF, 1, [Should we use the tm_gmtoff field of struct tm?]) - fi - - # - # Its important to include time.h in this check, as some systems - # (like convex) have timezone functions, etc. - # - AC_MSG_CHECKING([long timezone variable]) - AC_CACHE_VAL(tcl_cv_timezone_long, - AC_TRY_COMPILE([#include ], - [extern long timezone; - timezone += 1; - exit (0);], - tcl_cv_timezone_long=yes, tcl_cv_timezone_long=no)) - AC_MSG_RESULT([$tcl_cv_timezone_long]) - if test $tcl_cv_timezone_long = yes ; then - AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) - else - # - # On some systems (eg IRIX 6.2), timezone is a time_t and not a long. - # - AC_MSG_CHECKING([time_t timezone variable]) - AC_CACHE_VAL(tcl_cv_timezone_time, - AC_TRY_COMPILE([#include ], - [extern time_t timezone; - timezone += 1; - exit (0);], - tcl_cv_timezone_time=yes, tcl_cv_timezone_time=no)) - AC_MSG_RESULT([$tcl_cv_timezone_time]) - if test $tcl_cv_timezone_time = yes ; then - AC_DEFINE(HAVE_TIMEZONE_VAR, 1, [Should we use the global timezone variable?]) - fi - fi -]) - -#-------------------------------------------------------------------- -# TEA_BUGGY_STRTOD -# -# Under Solaris 2.4, strtod returns the wrong value for the -# terminating character under some conditions. Check for this -# and if the problem exists use a substitute procedure -# "fixstrtod" (provided by Tcl) that corrects the error. -# Also, on Compaq's Tru64 Unix 5.0, -# strtod(" ") returns 0.0 instead of a failure to convert. -# -# Arguments: -# none -# -# Results: -# -# Might defines some of the following vars: -# strtod (=fixstrtod) -# -#-------------------------------------------------------------------- - -AC_DEFUN(TEA_BUGGY_STRTOD, [ - AC_CHECK_FUNC(strtod, tcl_strtod=1, tcl_strtod=0) - if test "$tcl_strtod" = 1; then - AC_MSG_CHECKING([for Solaris2.4/Tru64 strtod bugs]) - AC_CACHE_VAL(tcl_cv_strtod_buggy,[ - AC_TRY_RUN([ - extern double strtod(); - int main() - { - char *string = "NaN", *spaceString = " "; - char *term; - double value; - value = strtod(string, &term); - if ((term != string) && (term[-1] == 0)) { - exit(1); - } - value = strtod(spaceString, &term); - if (term == (spaceString+1)) { - exit(1); - } - exit(0); - }], tcl_cv_strtod_buggy=1, tcl_cv_strtod_buggy=0, tcl_cv_strtod_buggy=0)]) - if test "$tcl_cv_strtod_buggy" = 1; then - AC_MSG_RESULT([ok]) - else - AC_MSG_RESULT([buggy]) - #LIBOBJS="$LIBOBJS fixstrtod.o" - AC_LIBOBJ([fixstrtod]) - USE_COMPAT=1 - AC_DEFINE(strtod, fixstrtod, [Do we want to use the strtod() in compat?]) - fi - fi -]) - -#-------------------------------------------------------------------- -# TEA_TCL_LINK_LIBS -# -# Search for the libraries needed to link the Tcl shell. -# Things like the math library (-lm) and socket stuff (-lsocket vs. -# -lnsl) are dealt with here. -# -# Arguments: -# Requires the following vars to be set in the Makefile: -# DL_LIBS -# LIBS -# MATH_LIBS -# -# Results: -# -# Subst's the following var: -# TCL_LIBS -# MATH_LIBS -# -# Might append to the following vars: -# LIBS -# -# Might define the following vars: -# HAVE_NET_ERRNO_H -# -#-------------------------------------------------------------------- - -AC_DEFUN(TEA_TCL_LINK_LIBS, [ - #-------------------------------------------------------------------- - # On a few very rare systems, all of the libm.a stuff is - # already in libc.a. Set compiler flags accordingly. - # Also, Linux requires the "ieee" library for math to work - # right (and it must appear before "-lm"). - #-------------------------------------------------------------------- - - AC_CHECK_FUNC(sin, MATH_LIBS="", MATH_LIBS="-lm") - AC_CHECK_LIB(ieee, main, [MATH_LIBS="-lieee $MATH_LIBS"]) - - #-------------------------------------------------------------------- - # Interactive UNIX requires -linet instead of -lsocket, plus it - # needs net/errno.h to define the socket-related error codes. - #-------------------------------------------------------------------- - - AC_CHECK_LIB(inet, main, [LIBS="$LIBS -linet"]) - AC_CHECK_HEADER(net/errno.h, [ - AC_DEFINE(HAVE_NET_ERRNO_H, 1, [Do we have ?])]) - - #-------------------------------------------------------------------- - # Check for the existence of the -lsocket and -lnsl libraries. - # The order here is important, so that they end up in the right - # order in the command line generated by make. Here are some - # special considerations: - # 1. Use "connect" and "accept" to check for -lsocket, and - # "gethostbyname" to check for -lnsl. - # 2. Use each function name only once: can't redo a check because - # autoconf caches the results of the last check and won't redo it. - # 3. Use -lnsl and -lsocket only if they supply procedures that - # aren't already present in the normal libraries. This is because - # IRIX 5.2 has libraries, but they aren't needed and they're - # bogus: they goof up name resolution if used. - # 4. On some SVR4 systems, can't use -lsocket without -lnsl too. - # To get around this problem, check for both libraries together - # if -lsocket doesn't work by itself. - #-------------------------------------------------------------------- - - tcl_checkBoth=0 - AC_CHECK_FUNC(connect, tcl_checkSocket=0, tcl_checkSocket=1) - if test "$tcl_checkSocket" = 1; then - AC_CHECK_FUNC(setsockopt, , [AC_CHECK_LIB(socket, setsockopt, - LIBS="$LIBS -lsocket", tcl_checkBoth=1)]) - fi - if test "$tcl_checkBoth" = 1; then - tk_oldLibs=$LIBS - LIBS="$LIBS -lsocket -lnsl" - AC_CHECK_FUNC(accept, tcl_checkNsl=0, [LIBS=$tk_oldLibs]) - fi - AC_CHECK_FUNC(gethostbyname, , [AC_CHECK_LIB(nsl, gethostbyname, - [LIBS="$LIBS -lnsl"])]) - - # Don't perform the eval of the libraries here because DL_LIBS - # won't be set until we call TEA_CONFIG_CFLAGS - - TCL_LIBS='${DL_LIBS} ${LIBS} ${MATH_LIBS}' - AC_SUBST(TCL_LIBS) - AC_SUBST(MATH_LIBS) -]) - -#-------------------------------------------------------------------- -# TEA_TCL_EARLY_FLAGS -# -# Check for what flags are needed to be passed so the correct OS -# features are available. -# -# Arguments: -# None -# -# Results: -# -# Might define the following vars: -# _ISOC99_SOURCE -# _LARGEFILE64_SOURCE -# -#-------------------------------------------------------------------- - -AC_DEFUN(TEA_TCL_EARLY_FLAG,[ - AC_CACHE_VAL([tcl_cv_flag_]translit($1,[A-Z],[a-z]), - AC_TRY_COMPILE([$2], $3, [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no, - AC_TRY_COMPILE([[#define ]$1[ 1 -]$2], $3, - [tcl_cv_flag_]translit($1,[A-Z],[a-z])=yes, - [tcl_cv_flag_]translit($1,[A-Z],[a-z])=no))) - if test ["x${tcl_cv_flag_]translit($1,[A-Z],[a-z])[}" = "xyes"] ; then - AC_DEFINE($1, 1, [Add the ]$1[ flag when building]) - tcl_flags="$tcl_flags $1" - fi -]) - -AC_DEFUN(TEA_TCL_EARLY_FLAGS,[ - AC_MSG_CHECKING([for required early compiler flags]) - tcl_flags="" - TEA_TCL_EARLY_FLAG(_ISOC99_SOURCE,[#include ], - [char *p = (char *)strtoll; char *q = (char *)strtoull;]) - TEA_TCL_EARLY_FLAG(_LARGEFILE64_SOURCE,[#include ], - [struct stat64 buf; int i = stat64("/", &buf);]) - if test "x${tcl_flags}" = "x" ; then - AC_MSG_RESULT([none]) - else - AC_MSG_RESULT([${tcl_flags}]) - fi -]) - -#-------------------------------------------------------------------- -# TEA_TCL_64BIT_FLAGS -# -# Check for what is defined in the way of 64-bit features. -# -# Arguments: -# None -# -# Results: -# -# Might define the following vars: -# TCL_WIDE_INT_IS_LONG -# TCL_WIDE_INT_TYPE -# HAVE_STRUCT_DIRENT64 -# HAVE_STRUCT_STAT64 -# HAVE_TYPE_OFF64_T -# -#-------------------------------------------------------------------- - -AC_DEFUN(TEA_TCL_64BIT_FLAGS, [ - AC_MSG_CHECKING([for 64-bit integer type]) - AC_CACHE_VAL(tcl_cv_type_64bit,[ - tcl_cv_type_64bit=none - # See if the compiler knows natively about __int64 - AC_TRY_COMPILE(,[__int64 value = (__int64) 0;], - tcl_type_64bit=__int64, tcl_type_64bit="long long") - # See if we should use long anyway Note that we substitute in the - # type that is our current guess for a 64-bit type inside this check - # program, so it should be modified only carefully... - AC_TRY_COMPILE(,[switch (0) { - case 1: case (sizeof(]${tcl_type_64bit}[)==sizeof(long)): ; - }],tcl_cv_type_64bit=${tcl_type_64bit})]) - if test "${tcl_cv_type_64bit}" = none ; then - AC_DEFINE(TCL_WIDE_INT_IS_LONG, 1, [Are wide integers to be implemented with C 'long's?]) - AC_MSG_RESULT([using long]) - elif test "${tcl_cv_type_64bit}" = "__int64" \ - -a "${TEA_PLATFORM}" = "windows" ; then - # We actually want to use the default tcl.h checks in this - # case to handle both TCL_WIDE_INT_TYPE and TCL_LL_MODIFIER* - AC_MSG_RESULT([using Tcl header defaults]) - else - AC_DEFINE_UNQUOTED(TCL_WIDE_INT_TYPE,${tcl_cv_type_64bit}, - [What type should be used to define wide integers?]) - AC_MSG_RESULT([${tcl_cv_type_64bit}]) - - # Now check for auxiliary declarations - AC_MSG_CHECKING([for struct dirent64]) - AC_CACHE_VAL(tcl_cv_struct_dirent64,[ - AC_TRY_COMPILE([#include -#include ],[struct dirent64 p;], - tcl_cv_struct_dirent64=yes,tcl_cv_struct_dirent64=no)]) - if test "x${tcl_cv_struct_dirent64}" = "xyes" ; then - AC_DEFINE(HAVE_STRUCT_DIRENT64, 1, [Is 'struct dirent64' in ?]) - fi - AC_MSG_RESULT([${tcl_cv_struct_dirent64}]) - - AC_MSG_CHECKING([for struct stat64]) - AC_CACHE_VAL(tcl_cv_struct_stat64,[ - AC_TRY_COMPILE([#include ],[struct stat64 p; -], - tcl_cv_struct_stat64=yes,tcl_cv_struct_stat64=no)]) - if test "x${tcl_cv_struct_stat64}" = "xyes" ; then - AC_DEFINE(HAVE_STRUCT_STAT64, 1, [Is 'struct stat64' in ?]) - fi - AC_MSG_RESULT([${tcl_cv_struct_stat64}]) - - AC_MSG_CHECKING([for off64_t]) - AC_CACHE_VAL(tcl_cv_type_off64_t,[ - AC_TRY_COMPILE([#include ],[off64_t offset; -], - tcl_cv_type_off64_t=yes,tcl_cv_type_off64_t=no)]) - if test "x${tcl_cv_type_off64_t}" = "xyes" ; then - AC_DEFINE(HAVE_TYPE_OFF64_T, 1, [Is off64_t in ?]) - fi - AC_MSG_RESULT([${tcl_cv_type_off64_t}]) - fi -]) - -## -## Here ends the standard Tcl configuration bits and starts the -## TEA specific functions -## - -#------------------------------------------------------------------------ -# TEA_INIT -- -# -# Init various Tcl Extension Architecture (TEA) variables. -# This should be the first called TEA_* macro. -# -# Arguments: -# none -# -# Results: -# -# Defines and substs the following vars: -# CYGPATH -# EXEEXT -# Defines only: -# TEA_INITED -# TEA_PLATFORM (windows or unix) -# -# "cygpath" is used on windows to generate native path names for include -# files. These variables should only be used with the compiler and linker -# since they generate native path names. -# -# EXEEXT -# Select the executable extension based on the host type. This -# is a lightweight replacement for AC_EXEEXT that doesn't require -# a compiler. -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_INIT, [ - # TEA extensions pass this us the version of TEA they think they - # are compatible with. - TEA_VERSION="3.4" - - AC_MSG_CHECKING([for correct TEA configuration]) - if test x"${PACKAGE_NAME}" = x ; then - AC_MSG_ERROR([ -The PACKAGE_NAME variable must be defined by your TEA configure.in]) - fi - if test x"$1" = x ; then - AC_MSG_ERROR([ -TEA version not specified.]) - elif test "$1" != "${TEA_VERSION}" ; then - AC_MSG_RESULT([warning: requested TEA version "$1", have "${TEA_VERSION}"]) - else - AC_MSG_RESULT([ok (TEA ${TEA_VERSION})]) - fi - case "`uname -s`" in - *win32*|*WIN32*|*CYGWIN_NT*|*CYGWIN_9*|*CYGWIN_ME*|*MINGW32_*) - AC_CHECK_PROG(CYGPATH, cygpath, cygpath -w, echo) - EXEEXT=".exe" - TEA_PLATFORM="windows" - ;; - *) - CYGPATH=echo - EXEEXT="" - TEA_PLATFORM="unix" - ;; - esac - - # Check if exec_prefix is set. If not use fall back to prefix. - # Note when adjusted, so that TEA_PREFIX can correct for this. - # This is needed for recursive configures, since autoconf propagates - # $prefix, but not $exec_prefix (doh!). - if test x$exec_prefix = xNONE ; then - exec_prefix_default=yes - exec_prefix=$prefix - fi - - AC_SUBST(EXEEXT) - AC_SUBST(CYGPATH) - - # This package name must be replaced statically for AC_SUBST to work - AC_SUBST(PKG_LIB_FILE) - # Substitute STUB_LIB_FILE in case package creates a stub library too. - AC_SUBST(PKG_STUB_LIB_FILE) - - # We AC_SUBST these here to ensure they are subst'ed, - # in case the user doesn't call TEA_ADD_... - AC_SUBST(PKG_STUB_SOURCES) - AC_SUBST(PKG_STUB_OBJECTS) - AC_SUBST(PKG_TCL_SOURCES) - AC_SUBST(PKG_HEADERS) - AC_SUBST(PKG_INCLUDES) - AC_SUBST(PKG_LIBS) - AC_SUBST(PKG_CFLAGS) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_SOURCES -- -# -# Specify one or more source files. Users should check for -# the right platform before adding to their list. -# It is not important to specify the directory, as long as it is -# in the generic, win or unix subdirectory of $(srcdir). -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_SOURCES -# PKG_OBJECTS -#------------------------------------------------------------------------ -AC_DEFUN(TEA_ADD_SOURCES, [ - vars="$@" - for i in $vars; do - case $i in - [\$]*) - # allow $-var names - PKG_SOURCES="$PKG_SOURCES $i" - PKG_OBJECTS="$PKG_OBJECTS $i" - ;; - *) - # check for existence - allows for generic/win/unix VPATH - if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ - -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ - ; then - AC_MSG_ERROR([could not find source file '$i']) - fi - PKG_SOURCES="$PKG_SOURCES $i" - # this assumes it is in a VPATH dir - i=`basename $i` - # handle user calling this before or after TEA_SETUP_COMPILER - if test x"${OBJEXT}" != x ; then - j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" - else - j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" - fi - PKG_OBJECTS="$PKG_OBJECTS $j" - ;; - esac - done - AC_SUBST(PKG_SOURCES) - AC_SUBST(PKG_OBJECTS) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_STUB_SOURCES -- -# -# Specify one or more source files. Users should check for -# the right platform before adding to their list. -# It is not important to specify the directory, as long as it is -# in the generic, win or unix subdirectory of $(srcdir). -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_STUB_SOURCES -# PKG_STUB_OBJECTS -#------------------------------------------------------------------------ -AC_DEFUN(TEA_ADD_STUB_SOURCES, [ - vars="$@" - for i in $vars; do - # check for existence - allows for generic/win/unix VPATH - if test ! -f "${srcdir}/$i" -a ! -f "${srcdir}/generic/$i" \ - -a ! -f "${srcdir}/win/$i" -a ! -f "${srcdir}/unix/$i" \ - ; then - AC_MSG_ERROR([could not find stub source file '$i']) - fi - PKG_STUB_SOURCES="$PKG_STUB_SOURCES $i" - # this assumes it is in a VPATH dir - i=`basename $i` - # handle user calling this before or after TEA_SETUP_COMPILER - if test x"${OBJEXT}" != x ; then - j="`echo $i | sed -e 's/\.[[^.]]*$//'`.${OBJEXT}" - else - j="`echo $i | sed -e 's/\.[[^.]]*$//'`.\${OBJEXT}" - fi - PKG_STUB_OBJECTS="$PKG_STUB_OBJECTS $j" - done - AC_SUBST(PKG_STUB_SOURCES) - AC_SUBST(PKG_STUB_OBJECTS) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_TCL_SOURCES -- -# -# Specify one or more Tcl source files. These should be platform -# independent runtime files. -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_TCL_SOURCES -#------------------------------------------------------------------------ -AC_DEFUN(TEA_ADD_TCL_SOURCES, [ - vars="$@" - for i in $vars; do - # check for existence, be strict because it is installed - if test ! -f "${srcdir}/$i" ; then - AC_MSG_ERROR([could not find tcl source file '${srcdir}/$i']) - fi - PKG_TCL_SOURCES="$PKG_TCL_SOURCES $i" - done - AC_SUBST(PKG_TCL_SOURCES) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_HEADERS -- -# -# Specify one or more source headers. Users should check for -# the right platform before adding to their list. -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_HEADERS -#------------------------------------------------------------------------ -AC_DEFUN(TEA_ADD_HEADERS, [ - vars="$@" - for i in $vars; do - # check for existence, be strict because it is installed - if test ! -f "${srcdir}/$i" ; then - AC_MSG_ERROR([could not find header file '${srcdir}/$i']) - fi - PKG_HEADERS="$PKG_HEADERS $i" - done - AC_SUBST(PKG_HEADERS) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_INCLUDES -- -# -# Specify one or more include dirs. Users should check for -# the right platform before adding to their list. -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_INCLUDES -#------------------------------------------------------------------------ -AC_DEFUN(TEA_ADD_INCLUDES, [ - vars="$@" - for i in $vars; do - PKG_INCLUDES="$PKG_INCLUDES $i" - done - AC_SUBST(PKG_INCLUDES) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_LIBS -- -# -# Specify one or more libraries. Users should check for -# the right platform before adding to their list. For Windows, -# libraries provided in "foo.lib" format will be converted to -# "-lfoo" when using GCC (mingw). -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_LIBS -#------------------------------------------------------------------------ -AC_DEFUN(TEA_ADD_LIBS, [ - vars="$@" - for i in $vars; do - if test "${TEA_PLATFORM}" = "windows" -a "$GCC" = "yes" ; then - # Convert foo.lib to -lfoo for GCC. No-op if not *.lib - i=`echo "$i" | sed -e 's/^\([[^-]].*\)\.lib[$]/-l\1/i'` - fi - PKG_LIBS="$PKG_LIBS $i" - done - AC_SUBST(PKG_LIBS) -]) - -#------------------------------------------------------------------------ -# TEA_ADD_CFLAGS -- -# -# Specify one or more CFLAGS. Users should check for -# the right platform before adding to their list. -# -# Arguments: -# one or more file names -# -# Results: -# -# Defines and substs the following vars: -# PKG_CFLAGS -#------------------------------------------------------------------------ -AC_DEFUN(TEA_ADD_CFLAGS, [ - PKG_CFLAGS="$PKG_CFLAGS $@" - AC_SUBST(PKG_CFLAGS) -]) - -#------------------------------------------------------------------------ -# TEA_PREFIX -- -# -# Handle the --prefix=... option by defaulting to what Tcl gave -# -# Arguments: -# none -# -# Results: -# -# If --prefix or --exec-prefix was not specified, $prefix and -# $exec_prefix will be set to the values given to Tcl when it was -# configured. -#------------------------------------------------------------------------ -AC_DEFUN(TEA_PREFIX, [ - if test "${prefix}" = "NONE"; then - prefix_default=yes - if test x"${TCL_PREFIX}" != x; then - AC_MSG_NOTICE([--prefix defaulting to TCL_PREFIX ${TCL_PREFIX}]) - prefix=${TCL_PREFIX} - else - AC_MSG_NOTICE([--prefix defaulting to /usr/local]) - prefix=/usr/local - fi - fi - if test "${exec_prefix}" = "NONE" -a x"${prefix_default}" = x"yes" \ - -o x"${exec_prefix_default}" = x"yes" ; then - if test x"${TCL_EXEC_PREFIX}" != x; then - AC_MSG_NOTICE([--exec-prefix defaulting to TCL_EXEC_PREFIX ${TCL_EXEC_PREFIX}]) - exec_prefix=${TCL_EXEC_PREFIX} - else - AC_MSG_NOTICE([--exec-prefix defaulting to ${prefix}]) - exec_prefix=$prefix - fi - fi -]) - -#------------------------------------------------------------------------ -# TEA_SETUP_COMPILER_CC -- -# -# Do compiler checks the way we want. This is just a replacement -# for AC_PROG_CC in TEA configure.in files to make them cleaner. -# -# Arguments: -# none -# -# Results: -# -# Sets up CC var and other standard bits we need to make executables. -#------------------------------------------------------------------------ -AC_DEFUN(TEA_SETUP_COMPILER_CC, [ - # Don't put any macros that use the compiler (e.g. AC_TRY_COMPILE) - # in this macro, they need to go into TEA_SETUP_COMPILER instead. - - # If the user did not set CFLAGS, set it now to keep - # the AC_PROG_CC macro from adding "-g -O2". - if test "${CFLAGS+set}" != "set" ; then - CFLAGS="" - fi - - AC_PROG_CC - AC_PROG_CPP - - AC_PROG_INSTALL - - #-------------------------------------------------------------------- - # Checks to see if the make program sets the $MAKE variable. - #-------------------------------------------------------------------- - - AC_PROG_MAKE_SET - - #-------------------------------------------------------------------- - # Find ranlib - #-------------------------------------------------------------------- - - AC_PROG_RANLIB - - #-------------------------------------------------------------------- - # Determines the correct binary file extension (.o, .obj, .exe etc.) - #-------------------------------------------------------------------- - - AC_OBJEXT - AC_EXEEXT -]) - -#------------------------------------------------------------------------ -# TEA_SETUP_COMPILER -- -# -# Do compiler checks that use the compiler. This must go after -# TEA_SETUP_COMPILER_CC, which does the actual compiler check. -# -# Arguments: -# none -# -# Results: -# -# Sets up CC var and other standard bits we need to make executables. -#------------------------------------------------------------------------ -AC_DEFUN(TEA_SETUP_COMPILER, [ - # Any macros that use the compiler (e.g. AC_TRY_COMPILE) have to go here. - AC_REQUIRE([TEA_SETUP_COMPILER_CC]) - - #------------------------------------------------------------------------ - # If we're using GCC, see if the compiler understands -pipe. If so, use it. - # It makes compiling go faster. (This is only a performance feature.) - #------------------------------------------------------------------------ - - if test -z "$no_pipe" -a -n "$GCC"; then - AC_MSG_CHECKING([if the compiler understands -pipe]) - OLDCC="$CC" - CC="$CC -pipe" - AC_TRY_COMPILE(,, AC_MSG_RESULT([yes]), CC="$OLDCC" - AC_MSG_RESULT([no])) - fi - - #-------------------------------------------------------------------- - # Common compiler flag setup - #-------------------------------------------------------------------- - - AC_C_BIGENDIAN - if test "${TEA_PLATFORM}" = "unix" ; then - TEA_TCL_LINK_LIBS - TEA_MISSING_POSIX_HEADERS - # Let the user call this, because if it triggers, they will - # need a compat/strtod.c that is correct. Users can also - # use Tcl_GetDouble(FromObj) instead. - #TEA_BUGGY_STRTOD - fi -]) - -#------------------------------------------------------------------------ -# TEA_MAKE_LIB -- -# -# Generate a line that can be used to build a shared/unshared library -# in a platform independent manner. -# -# Arguments: -# none -# -# Requires: -# -# Results: -# -# Defines the following vars: -# CFLAGS - Done late here to note disturb other AC macros -# MAKE_LIB - Command to execute to build the Tcl library; -# differs depending on whether or not Tcl is being -# compiled as a shared library. -# MAKE_SHARED_LIB Makefile rule for building a shared library -# MAKE_STATIC_LIB Makefile rule for building a static library -# MAKE_STUB_LIB Makefile rule for building a stub library -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_MAKE_LIB, [ - if test "${TEA_PLATFORM}" = "windows" -a "$GCC" != "yes"; then - MAKE_STATIC_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_OBJECTS)" - MAKE_SHARED_LIB="\${SHLIB_LD} \${SHLIB_LD_LIBS} \${LDFLAGS_DEFAULT} -out:\[$]@ \$(PKG_OBJECTS)" - MAKE_STUB_LIB="\${STLIB_LD} -out:\[$]@ \$(PKG_STUB_OBJECTS)" - else - MAKE_STATIC_LIB="\${STLIB_LD} \[$]@ \$(PKG_OBJECTS)" - MAKE_SHARED_LIB="\${SHLIB_LD} -o \[$]@ \$(PKG_OBJECTS) \${SHLIB_LD_LIBS}" - MAKE_STUB_LIB="\${STLIB_LD} \[$]@ \$(PKG_STUB_OBJECTS)" - fi - - if test "${SHARED_BUILD}" = "1" ; then - MAKE_LIB="${MAKE_SHARED_LIB} " - else - MAKE_LIB="${MAKE_STATIC_LIB} " - fi - - #-------------------------------------------------------------------- - # Shared libraries and static libraries have different names. - # Use the double eval to make sure any variables in the suffix is - # substituted. (@@@ Might not be necessary anymore) - #-------------------------------------------------------------------- - - if test "${TEA_PLATFORM}" = "windows" ; then - if test "${SHARED_BUILD}" = "1" ; then - # We force the unresolved linking of symbols that are really in - # the private libraries of Tcl and Tk. - SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TCL_BIN_DIR}/${TCL_STUB_LIB_FILE}`\"" - if test x"${TK_BIN_DIR}" != x ; then - SHLIB_LD_LIBS="${SHLIB_LD_LIBS} \"`${CYGPATH} ${TK_BIN_DIR}/${TK_STUB_LIB_FILE}`\"" - fi - eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" - else - eval eval "PKG_LIB_FILE=${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" - fi - # Some packages build there own stubs libraries - eval eval "PKG_STUB_LIB_FILE=${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" - # These aren't needed on Windows (either MSVC or gcc) - RANLIB=: - RANLIB_STUB=: - else - RANLIB_STUB="${RANLIB}" - if test "${SHARED_BUILD}" = "1" ; then - SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TCL_STUB_LIB_SPEC}" - if test x"${TK_BIN_DIR}" != x ; then - SHLIB_LD_LIBS="${SHLIB_LD_LIBS} ${TK_STUB_LIB_SPEC}" - fi - eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${SHARED_LIB_SUFFIX}" - RANLIB=: - else - eval eval "PKG_LIB_FILE=lib${PACKAGE_NAME}${UNSHARED_LIB_SUFFIX}" - fi - # Some packages build there own stubs libraries - eval eval "PKG_STUB_LIB_FILE=lib${PACKAGE_NAME}stub${UNSHARED_LIB_SUFFIX}" - fi - - # These are escaped so that only CFLAGS is picked up at configure time. - # The other values will be substituted at make time. - CFLAGS="${CFLAGS} \${CFLAGS_DEFAULT} \${CFLAGS_WARNING}" - if test "${SHARED_BUILD}" = "1" ; then - CFLAGS="${CFLAGS} \${SHLIB_CFLAGS}" - fi - - AC_SUBST(MAKE_LIB) - AC_SUBST(MAKE_SHARED_LIB) - AC_SUBST(MAKE_STATIC_LIB) - AC_SUBST(MAKE_STUB_LIB) - AC_SUBST(RANLIB_STUB) -]) - -#------------------------------------------------------------------------ -# TEA_LIB_SPEC -- -# -# Compute the name of an existing object library located in libdir -# from the given base name and produce the appropriate linker flags. -# -# Arguments: -# basename The base name of the library without version -# numbers, extensions, or "lib" prefixes. -# extra_dir Extra directory in which to search for the -# library. This location is used first, then -# $prefix/$exec-prefix, then some defaults. -# -# Requires: -# TEA_INIT and TEA_PREFIX must be called first. -# -# Results: -# -# Defines the following vars: -# ${basename}_LIB_NAME The computed library name. -# ${basename}_LIB_SPEC The computed linker flags. -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_LIB_SPEC, [ - AC_MSG_CHECKING([for $1 library]) - - # Look in exec-prefix for the library (defined by TEA_PREFIX). - - tea_lib_name_dir="${exec_prefix}/lib" - - # Or in a user-specified location. - - if test x"$2" != x ; then - tea_extra_lib_dir=$2 - else - tea_extra_lib_dir=NONE - fi - - for i in \ - `ls -dr ${tea_extra_lib_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ - `ls -dr ${tea_extra_lib_dir}/lib$1[[0-9]]* 2>/dev/null ` \ - `ls -dr ${tea_lib_name_dir}/$1[[0-9]]*.lib 2>/dev/null ` \ - `ls -dr ${tea_lib_name_dir}/lib$1[[0-9]]* 2>/dev/null ` \ - `ls -dr /usr/lib/$1[[0-9]]*.lib 2>/dev/null ` \ - `ls -dr /usr/lib/lib$1[[0-9]]* 2>/dev/null ` \ - `ls -dr /usr/local/lib/$1[[0-9]]*.lib 2>/dev/null ` \ - `ls -dr /usr/local/lib/lib$1[[0-9]]* 2>/dev/null ` ; do - if test -f "$i" ; then - tea_lib_name_dir=`dirname $i` - $1_LIB_NAME=`basename $i` - $1_LIB_PATH_NAME=$i - break - fi - done - - if test "${TEA_PLATFORM}" = "windows"; then - $1_LIB_SPEC=\"`${CYGPATH} ${$1_LIB_PATH_NAME} 2>/dev/null`\" - else - # Strip off the leading "lib" and trailing ".a" or ".so" - - tea_lib_name_lib=`echo ${$1_LIB_NAME}|sed -e 's/^lib//' -e 's/\.[[^.]]*$//' -e 's/\.so.*//'` - $1_LIB_SPEC="-L${tea_lib_name_dir} -l${tea_lib_name_lib}" - fi - - if test "x${$1_LIB_NAME}" = x ; then - AC_MSG_ERROR([not found]) - else - AC_MSG_RESULT([${$1_LIB_SPEC}]) - fi -]) - -#------------------------------------------------------------------------ -# TEA_PRIVATE_TCL_HEADERS -- -# -# Locate the private Tcl include files -# -# Arguments: -# -# Requires: -# TCL_SRC_DIR Assumes that TEA_LOAD_TCLCONFIG has -# already been called. -# -# Results: -# -# Substs the following vars: -# TCL_TOP_DIR_NATIVE -# TCL_GENERIC_DIR_NATIVE -# TCL_UNIX_DIR_NATIVE -# TCL_WIN_DIR_NATIVE -# TCL_BMAP_DIR_NATIVE -# TCL_TOOL_DIR_NATIVE -# TCL_PLATFORM_DIR_NATIVE -# TCL_BIN_DIR_NATIVE -# TCL_INCLUDES -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_PRIVATE_TCL_HEADERS, [ - AC_MSG_CHECKING([for Tcl private include files]) - - TCL_SRC_DIR_NATIVE=`${CYGPATH} ${TCL_SRC_DIR}` - TCL_TOP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}\" - TCL_GENERIC_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/generic\" - TCL_UNIX_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/unix\" - TCL_WIN_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/win\" - TCL_BMAP_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/bitmaps\" - TCL_TOOL_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/tools\" - TCL_COMPAT_DIR_NATIVE=\"${TCL_SRC_DIR_NATIVE}/compat\" - - if test "${TEA_PLATFORM}" = "windows"; then - TCL_PLATFORM_DIR_NATIVE=${TCL_WIN_DIR_NATIVE} - else - TCL_PLATFORM_DIR_NATIVE=${TCL_UNIX_DIR_NATIVE} - fi - # We want to ensure these are substituted so as not to require - # any *_NATIVE vars be defined in the Makefile - TCL_INCLUDES="-I${TCL_GENERIC_DIR_NATIVE} -I${TCL_PLATFORM_DIR_NATIVE}" - if test "`uname -s`" = "Darwin"; then - # If Tcl was built as a framework, attempt to use - # the framework's Headers and PrivateHeaders directories - case ${TCL_DEFS} in - *TCL_FRAMEWORK*) - if test -d "${TCL_BIN_DIR}/Headers" -a -d "${TCL_BIN_DIR}/PrivateHeaders"; then - TCL_INCLUDES="-I\"${TCL_BIN_DIR}/Headers\" -I\"${TCL_BIN_DIR}/PrivateHeaders\" ${TCL_INCLUDES}"; else - TCL_INCLUDES="${TCL_INCLUDES} ${TCL_INCLUDE_SPEC} `echo "${TCL_INCLUDE_SPEC}" | sed -e 's/Headers/PrivateHeaders/'`"; fi - ;; - esac - fi - - AC_SUBST(TCL_TOP_DIR_NATIVE) - AC_SUBST(TCL_GENERIC_DIR_NATIVE) - AC_SUBST(TCL_UNIX_DIR_NATIVE) - AC_SUBST(TCL_WIN_DIR_NATIVE) - AC_SUBST(TCL_BMAP_DIR_NATIVE) - AC_SUBST(TCL_TOOL_DIR_NATIVE) - AC_SUBST(TCL_PLATFORM_DIR_NATIVE) - - AC_SUBST(TCL_INCLUDES) - AC_MSG_RESULT([Using srcdir found in tclConfig.sh: ${TCL_SRC_DIR}]) -]) - -#------------------------------------------------------------------------ -# TEA_PUBLIC_TCL_HEADERS -- -# -# Locate the installed public Tcl header files -# -# Arguments: -# None. -# -# Requires: -# CYGPATH must be set -# -# Results: -# -# Adds a --with-tclinclude switch to configure. -# Result is cached. -# -# Substs the following vars: -# TCL_INCLUDES -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_PUBLIC_TCL_HEADERS, [ - AC_MSG_CHECKING([for Tcl public headers]) - - AC_ARG_WITH(tclinclude, [ --with-tclinclude directory containing the public Tcl header files], with_tclinclude=${withval}) - - AC_CACHE_VAL(ac_cv_c_tclh, [ - # Use the value from --with-tclinclude, if it was given - - if test x"${with_tclinclude}" != x ; then - if test -f "${with_tclinclude}/tcl.h" ; then - ac_cv_c_tclh=${with_tclinclude} - else - AC_MSG_ERROR([${with_tclinclude} directory does not contain tcl.h]) - fi - else - # If Tcl was built as a framework, attempt to use - # the framework's Headers directory - case ${TCL_DEFS} in - *TCL_FRAMEWORK*) - list="`ls -d ${TCL_BIN_DIR}/Headers 2>/dev/null`" - ;; - *) - list="" - ;; - esac - - # Look in the source dir only if Tcl is not installed, - # and in that situation, look there before installed locations. - if test -f "$TCL_BIN_DIR/Makefile" ; then - list="$list `ls -d ${TCL_SRC_DIR}/generic 2>/dev/null`" - fi - - # Check order: pkg --prefix location, Tcl's --prefix location, - # relative to directory of tclConfig.sh. - - eval "temp_includedir=${includedir}" - list="$list \ - `ls -d ${temp_includedir} 2>/dev/null` \ - `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ - `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" - if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then - list="$list /usr/local/include /usr/include" - if test x"${TCL_INCLUDE_SPEC}" != x ; then - d=`echo "${TCL_INCLUDE_SPEC}" | sed -e 's/^-I//'` - list="$list `ls -d ${d} 2>/dev/null`" - fi - fi - for i in $list ; do - if test -f "$i/tcl.h" ; then - ac_cv_c_tclh=$i - break - fi - done - fi - ]) - - # Print a message based on how we determined the include path - - if test x"${ac_cv_c_tclh}" = x ; then - AC_MSG_ERROR([tcl.h not found. Please specify its location with --with-tclinclude]) - else - AC_MSG_RESULT([${ac_cv_c_tclh}]) - fi - - # Convert to a native path and substitute into the output files. - - INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tclh}` - - TCL_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" - - AC_SUBST(TCL_INCLUDES) -]) - -#------------------------------------------------------------------------ -# TEA_PRIVATE_TK_HEADERS -- -# -# Locate the private Tk include files -# -# Arguments: -# -# Requires: -# TK_SRC_DIR Assumes that TEA_LOAD_TKCONFIG has -# already been called. -# -# Results: -# -# Substs the following vars: -# TK_INCLUDES -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_PRIVATE_TK_HEADERS, [ - AC_MSG_CHECKING([for Tk private include files]) - - TK_SRC_DIR_NATIVE=`${CYGPATH} ${TK_SRC_DIR}` - TK_TOP_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}\" - TK_UNIX_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/unix\" - TK_WIN_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/win\" - TK_GENERIC_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/generic\" - TK_XLIB_DIR_NATIVE=\"${TK_SRC_DIR_NATIVE}/xlib\" - if test "${TEA_PLATFORM}" = "windows"; then - TK_PLATFORM_DIR_NATIVE=${TK_WIN_DIR_NATIVE} - else - TK_PLATFORM_DIR_NATIVE=${TK_UNIX_DIR_NATIVE} - fi - # We want to ensure these are substituted so as not to require - # any *_NATIVE vars be defined in the Makefile - TK_INCLUDES="-I${TK_GENERIC_DIR_NATIVE} -I${TK_PLATFORM_DIR_NATIVE}" - if test "${TEA_WINDOWINGSYSTEM}" = "win32" \ - -o "${TEA_WINDOWINGSYSTEM}" = "aqua"; then - TK_INCLUDES="${TK_INCLUDES} -I${TK_XLIB_DIR_NATIVE}" - fi - if test "${TEA_WINDOWINGSYSTEM}" = "aqua"; then - TK_INCLUDES="${TK_INCLUDES} -I${TK_SRC_DIR_NATIVE}/macosx" - fi - if test "`uname -s`" = "Darwin"; then - # If Tk was built as a framework, attempt to use - # the framework's Headers and PrivateHeaders directories - case ${TK_DEFS} in - *TK_FRAMEWORK*) - if test -d "${TK_BIN_DIR}/Headers" -a -d "${TK_BIN_DIR}/PrivateHeaders"; then - TK_INCLUDES="-I\"${TK_BIN_DIR}/Headers\" -I\"${TK_BIN_DIR}/PrivateHeaders\" ${TK_INCLUDES}"; fi - ;; - esac - fi - - AC_SUBST(TK_TOP_DIR_NATIVE) - AC_SUBST(TK_UNIX_DIR_NATIVE) - AC_SUBST(TK_WIN_DIR_NATIVE) - AC_SUBST(TK_GENERIC_DIR_NATIVE) - AC_SUBST(TK_XLIB_DIR_NATIVE) - AC_SUBST(TK_PLATFORM_DIR_NATIVE) - - AC_SUBST(TK_INCLUDES) - AC_MSG_RESULT([Using srcdir found in tkConfig.sh: ${TK_SRC_DIR}]) -]) - -#------------------------------------------------------------------------ -# TEA_PUBLIC_TK_HEADERS -- -# -# Locate the installed public Tk header files -# -# Arguments: -# None. -# -# Requires: -# CYGPATH must be set -# -# Results: -# -# Adds a --with-tkinclude switch to configure. -# Result is cached. -# -# Substs the following vars: -# TK_INCLUDES -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_PUBLIC_TK_HEADERS, [ - AC_MSG_CHECKING([for Tk public headers]) - - AC_ARG_WITH(tkinclude, [ --with-tkinclude directory containing the public Tk header files.], with_tkinclude=${withval}) - - AC_CACHE_VAL(ac_cv_c_tkh, [ - # Use the value from --with-tkinclude, if it was given - - if test x"${with_tkinclude}" != x ; then - if test -f "${with_tkinclude}/tk.h" ; then - ac_cv_c_tkh=${with_tkinclude} - else - AC_MSG_ERROR([${with_tkinclude} directory does not contain tk.h]) - fi - else - # If Tk was built as a framework, attempt to use - # the framework's Headers directory. - case ${TK_DEFS} in - *TK_FRAMEWORK*) - list="`ls -d ${TK_BIN_DIR}/Headers 2>/dev/null`" - ;; - *) - list="" - ;; - esac - - # Look in the source dir only if Tk is not installed, - # and in that situation, look there before installed locations. - if test -f "$TK_BIN_DIR/Makefile" ; then - list="$list `ls -d ${TK_SRC_DIR}/generic 2>/dev/null`" - fi - - # Check order: pkg --prefix location, Tk's --prefix location, - # relative to directory of tkConfig.sh, Tcl's --prefix location, - # relative to directory of tclConfig.sh. - - eval "temp_includedir=${includedir}" - list="$list \ - `ls -d ${temp_includedir} 2>/dev/null` \ - `ls -d ${TK_PREFIX}/include 2>/dev/null` \ - `ls -d ${TK_BIN_DIR}/../include 2>/dev/null` \ - `ls -d ${TCL_PREFIX}/include 2>/dev/null` \ - `ls -d ${TCL_BIN_DIR}/../include 2>/dev/null`" - if test "${TEA_PLATFORM}" != "windows" -o "$GCC" = "yes"; then - list="$list /usr/local/include /usr/include" - fi - for i in $list ; do - if test -f "$i/tk.h" ; then - ac_cv_c_tkh=$i - break - fi - done - fi - ]) - - # Print a message based on how we determined the include path - - if test x"${ac_cv_c_tkh}" = x ; then - AC_MSG_ERROR([tk.h not found. Please specify its location with --with-tkinclude]) - else - AC_MSG_RESULT([${ac_cv_c_tkh}]) - fi - - # Convert to a native path and substitute into the output files. - - INCLUDE_DIR_NATIVE=`${CYGPATH} ${ac_cv_c_tkh}` - - TK_INCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" - - AC_SUBST(TK_INCLUDES) - - if test "${TEA_WINDOWINGSYSTEM}" = "win32" \ - -o "${TEA_WINDOWINGSYSTEM}" = "aqua"; then - # On Windows and Aqua, we need the X compat headers - AC_MSG_CHECKING([for X11 header files]) - if test ! -r "${INCLUDE_DIR_NATIVE}/X11/Xlib.h"; then - INCLUDE_DIR_NATIVE="`${CYGPATH} ${TK_SRC_DIR}/xlib`" - TK_XINCLUDES=-I\"${INCLUDE_DIR_NATIVE}\" - AC_SUBST(TK_XINCLUDES) - fi - AC_MSG_RESULT([${INCLUDE_DIR_NATIVE}]) - fi -]) - -#------------------------------------------------------------------------ -# TEA_PROG_TCLSH -# Determine the fully qualified path name of the tclsh executable -# in the Tcl build directory or the tclsh installed in a bin -# directory. This macro will correctly determine the name -# of the tclsh executable even if tclsh has not yet been -# built in the build directory. The tclsh found is always -# associated with a tclConfig.sh file. This tclsh should be used -# only for running extension test cases. It should never be -# or generation of files (like pkgIndex.tcl) at build time. -# -# Arguments -# none -# -# Results -# Subst's the following values: -# TCLSH_PROG -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_PROG_TCLSH, [ - AC_MSG_CHECKING([for tclsh]) - if test -f "${TCL_BIN_DIR}/Makefile" ; then - # tclConfig.sh is in Tcl build directory - if test "${TEA_PLATFORM}" = "windows"; then - TCLSH_PROG="${TCL_BIN_DIR}/tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" - else - TCLSH_PROG="${TCL_BIN_DIR}/tclsh" - fi - else - # tclConfig.sh is in install location - if test "${TEA_PLATFORM}" = "windows"; then - TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}${TCL_MINOR_VERSION}${TCL_DBGX}${EXEEXT}" - else - TCLSH_PROG="tclsh${TCL_MAJOR_VERSION}.${TCL_MINOR_VERSION}${TCL_DBGX}" - fi - list="`ls -d ${TCL_PREFIX}/bin 2>/dev/null` \ - `ls -d ${TCL_BIN_DIR}/../bin 2>/dev/null`" - for i in $list ; do - if test -f "$i/${TCLSH_PROG}" ; then - REAL_TCL_BIN_DIR="`cd "$i"; pwd`" - break - fi - done - TCLSH_PROG="${REAL_TCL_BIN_DIR}/${TCLSH_PROG}" - fi - AC_MSG_RESULT(${TCLSH_PROG}) - AC_SUBST(TCLSH_PROG) -]) - -#------------------------------------------------------------------------ -# TEA_PROG_WISH -# Determine the fully qualified path name of the wish executable -# in the Tk build directory or the wish installed in a bin -# directory. This macro will correctly determine the name -# of the wish executable even if wish has not yet been -# built in the build directory. The wish found is always -# associated with a tkConfig.sh file. This wish should be used -# only for running extension test cases. It should never be -# or generation of files (like pkgIndex.tcl) at build time. -# -# Arguments -# none -# -# Results -# Subst's the following values: -# WISH_PROG -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_PROG_WISH, [ - AC_MSG_CHECKING([for wish]) - if test -f "${TK_BIN_DIR}/Makefile" ; then - # tkConfig.sh is in Tk build directory - if test "${TEA_PLATFORM}" = "windows"; then - WISH_PROG="${TK_BIN_DIR}/wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" - else - WISH_PROG="${TK_BIN_DIR}/wish" - fi - else - # tkConfig.sh is in install location - if test "${TEA_PLATFORM}" = "windows"; then - WISH_PROG="wish${TK_MAJOR_VERSION}${TK_MINOR_VERSION}${TK_DBGX}${EXEEXT}" - else - WISH_PROG="wish${TK_MAJOR_VERSION}.${TK_MINOR_VERSION}${TK_DBGX}" - fi - list="`ls -d ${TK_PREFIX}/bin 2>/dev/null` \ - `ls -d ${TK_BIN_DIR}/../bin 2>/dev/null`" - for i in $list ; do - if test -f "$i/${WISH_PROG}" ; then - REAL_TK_BIN_DIR="`cd "$i"; pwd`" - break - fi - done - WISH_PROG="${REAL_TK_BIN_DIR}/${WISH_PROG}" - fi - AC_MSG_RESULT(${WISH_PROG}) - AC_SUBST(WISH_PROG) -]) - -#------------------------------------------------------------------------ -# TEA_PATH_CONFIG -- -# -# Locate the ${1}Config.sh file and perform a sanity check on -# the ${1} compile flags. These are used by packages like -# [incr Tk] that load *Config.sh files from more than Tcl and Tk. -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --with-$1=... -# -# Defines the following vars: -# $1_BIN_DIR Full path to the directory containing -# the $1Config.sh file -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_PATH_CONFIG, [ - # - # Ok, lets find the $1 configuration - # First, look for one uninstalled. - # the alternative search directory is invoked by --with-$1 - # - - if test x"${no_$1}" = x ; then - # we reset no_$1 in case something fails here - no_$1=true - AC_ARG_WITH($1, [ --with-$1 directory containing $1 configuration ($1Config.sh)], with_$1config=${withval}) - AC_MSG_CHECKING([for $1 configuration]) - AC_CACHE_VAL(ac_cv_c_$1config,[ - - # First check to see if --with-$1 was specified. - if test x"${with_$1config}" != x ; then - case ${with_$1config} in - */$1Config.sh ) - if test -f ${with_$1config}; then - AC_MSG_WARN([--with-$1 argument should refer to directory containing $1Config.sh, not to $1Config.sh itself]) - with_$1config=`echo ${with_$1config} | sed 's!/$1Config\.sh$!!'` - fi;; - esac - if test -f "${with_$1config}/$1Config.sh" ; then - ac_cv_c_$1config=`(cd ${with_$1config}; pwd)` - else - AC_MSG_ERROR([${with_$1config} directory doesn't contain $1Config.sh]) - fi - fi - - # then check for a private $1 installation - if test x"${ac_cv_c_$1config}" = x ; then - for i in \ - ../$1 \ - `ls -dr ../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ - `ls -dr ../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ - `ls -dr ../$1*[[0-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ - ../../$1 \ - `ls -dr ../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ - `ls -dr ../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ - `ls -dr ../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ - ../../../$1 \ - `ls -dr ../../../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ - `ls -dr ../../../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ - `ls -dr ../../../$1*[[0-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ../../../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ - ${srcdir}/../$1 \ - `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]*.[[0-9]]* 2>/dev/null` \ - `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]][[0-9]] 2>/dev/null` \ - `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]] 2>/dev/null` \ - `ls -dr ${srcdir}/../$1*[[0-9]].[[0-9]]* 2>/dev/null` \ - ; do - if test -f "$i/$1Config.sh" ; then - ac_cv_c_$1config=`(cd $i; pwd)` - break - fi - if test -f "$i/unix/$1Config.sh" ; then - ac_cv_c_$1config=`(cd $i/unix; pwd)` - break - fi - done - fi - - # check in a few common install locations - if test x"${ac_cv_c_$1config}" = x ; then - for i in `ls -d ${libdir} 2>/dev/null` \ - `ls -d ${exec_prefix}/lib 2>/dev/null` \ - `ls -d ${prefix}/lib 2>/dev/null` \ - `ls -d /usr/local/lib 2>/dev/null` \ - `ls -d /usr/contrib/lib 2>/dev/null` \ - `ls -d /usr/lib 2>/dev/null` \ - ; do - if test -f "$i/$1Config.sh" ; then - ac_cv_c_$1config=`(cd $i; pwd)` - break - fi - done - fi - ]) - - if test x"${ac_cv_c_$1config}" = x ; then - $1_BIN_DIR="# no $1 configs found" - AC_MSG_WARN("Cannot find $1 configuration definitions") - exit 0 - else - no_$1= - $1_BIN_DIR=${ac_cv_c_$1config} - AC_MSG_RESULT([found $$1_BIN_DIR/$1Config.sh]) - fi - fi -]) - -#------------------------------------------------------------------------ -# TEA_LOAD_CONFIG -- -# -# Load the $1Config.sh file -# -# Arguments: -# -# Requires the following vars to be set: -# $1_BIN_DIR -# -# Results: -# -# Subst the following vars: -# $1_SRC_DIR -# $1_LIB_FILE -# $1_LIB_SPEC -# -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_LOAD_CONFIG, [ - AC_MSG_CHECKING([for existence of ${$1_BIN_DIR}/$1Config.sh]) - - if test -f "${$1_BIN_DIR}/$1Config.sh" ; then - AC_MSG_RESULT([loading]) - . ${$1_BIN_DIR}/$1Config.sh - else - AC_MSG_RESULT([file not found]) - fi - - # - # If the $1_BIN_DIR is the build directory (not the install directory), - # then set the common variable name to the value of the build variables. - # For example, the variable $1_LIB_SPEC will be set to the value - # of $1_BUILD_LIB_SPEC. An extension should make use of $1_LIB_SPEC - # instead of $1_BUILD_LIB_SPEC since it will work with both an - # installed and uninstalled version of Tcl. - # - - if test -f ${$1_BIN_DIR}/Makefile ; then - AC_MSG_WARN([Found Makefile - using build library specs for $1]) - $1_LIB_SPEC=${$1_BUILD_LIB_SPEC} - $1_STUB_LIB_SPEC=${$1_BUILD_STUB_LIB_SPEC} - $1_STUB_LIB_PATH=${$1_BUILD_STUB_LIB_PATH} - fi - - AC_SUBST($1_VERSION) - AC_SUBST($1_BIN_DIR) - AC_SUBST($1_SRC_DIR) - - AC_SUBST($1_LIB_FILE) - AC_SUBST($1_LIB_SPEC) - - AC_SUBST($1_STUB_LIB_FILE) - AC_SUBST($1_STUB_LIB_SPEC) - AC_SUBST($1_STUB_LIB_PATH) -]) - -#------------------------------------------------------------------------ -# TEA_PATH_CELIB -- -# -# Locate Keuchel's celib emulation layer for targeting Win/CE -# -# Arguments: -# none -# -# Results: -# -# Adds the following arguments to configure: -# --with-celib=... -# -# Defines the following vars: -# CELIB_DIR Full path to the directory containing -# the include and platform lib files -#------------------------------------------------------------------------ - -AC_DEFUN(TEA_PATH_CELIB, [ - # First, look for one uninstalled. - # the alternative search directory is invoked by --with-celib - - if test x"${no_celib}" = x ; then - # we reset no_celib in case something fails here - no_celib=true - AC_ARG_WITH(celib,[ --with-celib=DIR use Windows/CE support library from DIR], with_celibconfig=${withval}) - AC_MSG_CHECKING([for Windows/CE celib directory]) - AC_CACHE_VAL(ac_cv_c_celibconfig,[ - # First check to see if --with-celibconfig was specified. - if test x"${with_celibconfig}" != x ; then - if test -d "${with_celibconfig}/inc" ; then - ac_cv_c_celibconfig=`(cd ${with_celibconfig}; pwd)` - else - AC_MSG_ERROR([${with_celibconfig} directory doesn't contain inc directory]) - fi - fi - - # then check for a celib library - if test x"${ac_cv_c_celibconfig}" = x ; then - for i in \ - ../celib-palm-3.0 \ - ../celib \ - ../../celib-palm-3.0 \ - ../../celib \ - `ls -dr ../celib-*3.[[0-9]]* 2>/dev/null` \ - ${srcdir}/../celib-palm-3.0 \ - ${srcdir}/../celib \ - `ls -dr ${srcdir}/../celib-*3.[[0-9]]* 2>/dev/null` \ - ; do - if test -d "$i/inc" ; then - ac_cv_c_celibconfig=`(cd $i; pwd)` - break - fi - done - fi - ]) - if test x"${ac_cv_c_celibconfig}" = x ; then - AC_MSG_ERROR([Cannot find celib support library directory]) - else - no_celib= - CELIB_DIR=${ac_cv_c_celibconfig} - CELIB_DIR=`echo "$CELIB_DIR" | sed -e 's!\\\!/!g'` - AC_MSG_RESULT([found $CELIB_DIR]) - fi - fi -]) diff --git a/ng/Togl-1.7/texture.c b/ng/Togl-1.7/texture.c deleted file mode 100644 index 6a6f39f9..00000000 --- a/ng/Togl-1.7/texture.c +++ /dev/null @@ -1,608 +0,0 @@ -/* $Id: texture.c,v 1.10 2005/04/23 07:49:14 gregcouch Exp $ */ - -/* - * Togl - a Tk OpenGL widget - * Copyright (C) 1996-1997 Brian Paul and Ben Bederson - * See the LICENSE file for copyright details. - */ - - -/* - * An example Togl program demonstrating texture mapping - */ - - -#include "togl.h" -#include -#include -#if defined(TOGL_AGL) || defined(TOGL_AGL_CLASSIC) -# include -#else -# include -#endif -#include "image.h" - - -/* - * The following variable is a special hack that is needed in order for - * Sun shared libraries to be used for Tcl. - */ -#ifdef SUN -extern int matherr(); -int *tclDummyMathPtr = (int *) matherr; -#endif - -#define CHECKER 0 -#define FACE 1 -#define TREE 2 - - -static GLenum minfilter = GL_NEAREST_MIPMAP_LINEAR; -static GLenum magfilter = GL_LINEAR; -static GLenum swrap = GL_REPEAT; -static GLenum twrap = GL_REPEAT; -static GLenum envmode = GL_MODULATE; -static GLubyte polycolor[4] = { 255, 255, 255, 255 }; -static int image = CHECKER; -static GLfloat coord_scale = 1.0; -static GLfloat xrot = 0.0; -static GLfloat yrot = 0.0; -static GLfloat scale = 1.0; - -static GLint width, height; - -static GLboolean blend = GL_FALSE; - - -/* - * Load a texture image. n is one of CHECKER, FACE or TREE. - */ -void -texture_image(int n) -{ - if (n == CHECKER) { -#define WIDTH 64 -#define HEIGHT 64 - GLubyte teximage[WIDTH * HEIGHT][4]; - int i, j; - - for (i = 0; i < HEIGHT; i++) { - for (j = 0; j < WIDTH; j++) { - GLubyte value; - - value = ((i / 4 + j / 4) % 2) ? 0xff : 0x00; - teximage[i * WIDTH + j][0] = value; - teximage[i * WIDTH + j][1] = value; - teximage[i * WIDTH + j][2] = value; - teximage[i * WIDTH + j][3] = value; - } - } - - glEnable(GL_TEXTURE_2D); - gluBuild2DMipmaps(GL_TEXTURE_2D, 4, WIDTH, HEIGHT, - GL_RGBA, GL_UNSIGNED_BYTE, teximage); - blend = GL_FALSE; - -#undef WIDTH -#undef HEIGHT - } else if (n == FACE) { - TK_RGBImageRec *img = tkRGBImageLoad("ben.rgb"); - - if (img) { - glEnable(GL_TEXTURE_2D); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - gluBuild2DMipmaps(GL_TEXTURE_2D, img->sizeZ, img->sizeX, img->sizeY, - img->sizeZ == 3 ? GL_RGB : GL_RGBA, - GL_UNSIGNED_BYTE, img->data); - - blend = GL_TRUE; - } - } else if (n == TREE) { - TK_RGBImageRec *img = tkRGBImageLoad("tree2.rgba"); - - if (img) { - glEnable(GL_TEXTURE_2D); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - gluBuild2DMipmaps(GL_TEXTURE_2D, img->sizeZ, img->sizeX, img->sizeY, - img->sizeZ == 3 ? GL_RGB : GL_RGBA, - GL_UNSIGNED_BYTE, img->data); - - blend = GL_TRUE; - } - } else { - abort(); - } -} - - -/* - * Togl widget create callback. This is called by Tcl/Tk when the widget has - * been realized. Here's where one may do some one-time context setup or - * initializations. - */ -void -create_cb(Togl *togl) -{ - glEnable(GL_DEPTH_TEST); /* Enable depth buffering */ - - texture_image(CHECKER); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magfilter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter); -} - - -/* - * Togl widget reshape callback. This is called by Tcl/Tk when the widget - * has been resized. Typically, we call glViewport and perhaps setup the - * projection matrix. - */ -void -reshape_cb(Togl *togl) -{ - width = Togl_Width(togl); - height = Togl_Height(togl); - - glViewport(0, 0, width, height); - -} - - -static void -check_error(char *where) -{ - GLenum error; - - while (1) { - error = glGetError(); - if (error == GL_NO_ERROR) { - break; - } - printf("OpenGL error near %s: %s\n", where, gluErrorString(error)); - } -} - - - -/* - * Togl widget display callback. This is called by Tcl/Tk when the widget's - * contents have to be redrawn. Typically, we clear the color and depth - * buffers, render our objects, then swap the front/back color buffers. - */ -void -display_cb(Togl *togl) -{ - float aspect = (float) width / (float) height; - - check_error("begin display\n"); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - /* Draw background image */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glDisable(GL_TEXTURE_2D); - glDisable(GL_DEPTH_TEST); - glBegin(GL_POLYGON); - glColor3f(0.0, 0.0, 0.3); - glVertex2f(-1.0, -1.0); - glColor3f(0.0, 0.0, 0.3); - glVertex2f(1.0, -1.0); - glColor3f(0.0, 0.0, 0.9); - glVertex2f(1.0, 1.0); - glColor3f(0.0, 0.0, 0.9); - glVertex2f(-1.0, 1.0); - glEnd(); - - /* draw textured object */ - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(-aspect, aspect, -1.0, 1.0, 2.0, 10.0); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - glTranslatef(0.0, 0.0, -5.0); - glScalef(scale, scale, scale); - glRotatef(yrot, 0.0, 1.0, 0.0); - glRotatef(xrot, 1.0, 0.0, 0.0); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_TEXTURE_2D); - glColor4ubv(polycolor); - - if (blend) { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_BLEND); - } - - glBegin(GL_POLYGON); - glTexCoord2f(0.0, 0.0); - glVertex2f(-1.0, -1.0); - glTexCoord2f(coord_scale, 0.0); - glVertex2f(1.0, -1.0); - glTexCoord2f(coord_scale, coord_scale); - glVertex2f(1.0, 1.0); - glTexCoord2f(0.0, coord_scale); - glVertex2f(-1.0, 1.0); - glEnd(); - - glDisable(GL_BLEND); - - Togl_SwapBuffers(togl); -} - - -/* - * Called when a magnification filter radio button is pressed. - */ -int -magfilter_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - if (strcmp(argv[2], "GL_NEAREST") == 0) { - magfilter = GL_NEAREST; - } else if (strcmp(argv[2], "GL_LINEAR") == 0) { - magfilter = GL_LINEAR; - } else { - Tcl_SetResult(interp, "unknown magnification filter type", TCL_STATIC); - return TCL_ERROR; - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magfilter); - Togl_PostRedisplay(togl); - - return TCL_OK; -} - - -/* - * Called when a minification filter radio button is pressed. - */ -int -minfilter_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - if (strcmp(argv[2], "GL_NEAREST") == 0) { - minfilter = GL_NEAREST; - } else if (strcmp(argv[2], "GL_LINEAR") == 0) { - minfilter = GL_LINEAR; - } else if (strcmp(argv[2], "GL_NEAREST_MIPMAP_NEAREST") == 0) { - minfilter = GL_NEAREST_MIPMAP_NEAREST; - } else if (strcmp(argv[2], "GL_LINEAR_MIPMAP_NEAREST") == 0) { - minfilter = GL_LINEAR_MIPMAP_NEAREST; - } else if (strcmp(argv[2], "GL_NEAREST_MIPMAP_LINEAR") == 0) { - minfilter = GL_NEAREST_MIPMAP_LINEAR; - } else if (strcmp(argv[2], "GL_LINEAR_MIPMAP_LINEAR") == 0) { - minfilter = GL_LINEAR_MIPMAP_LINEAR; - } else { - Tcl_SetResult(interp, "unknown minification filter type", TCL_STATIC); - return TCL_ERROR; - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter); - Togl_PostRedisplay(togl); - - return TCL_OK; -} - - -int -xrot_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName setXrot ?angle?\"", - TCL_STATIC); - return TCL_ERROR; - } - - xrot = atof(argv[2]); - - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -int -yrot_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName setYrot ?angle?\"", - TCL_STATIC); - return TCL_ERROR; - } - - yrot = atof(argv[2]); - - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -int -scale_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName scale ?value?\"", - TCL_STATIC); - return TCL_ERROR; - } - - scale = atof(argv[2]); - - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -/* - * Called when S texture coordinate wrapping is changed. - */ -int -swrap_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName swrap ?mode?\"", - TCL_STATIC); - return TCL_ERROR; - } - - if (strcmp(argv[2], "GL_CLAMP") == 0) { - swrap = GL_CLAMP; - } else if (strcmp(argv[2], "GL_REPEAT") == 0) { - swrap = GL_REPEAT; - } else { - Tcl_SetResult(interp, "unknown wrap value", TCL_STATIC); - return TCL_ERROR; - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, swrap); - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -/* - * Called when T texture coordinate wrapping is changed. - */ -int -twrap_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName twrap ?mode?\"", - TCL_STATIC); - return TCL_ERROR; - } - - if (strcmp(argv[2], "GL_CLAMP") == 0) { - twrap = GL_CLAMP; - } else if (strcmp(argv[2], "GL_REPEAT") == 0) { - twrap = GL_REPEAT; - } else { - Tcl_SetResult(interp, "unknown wrap value", TCL_STATIC); - return TCL_ERROR; - } - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, twrap); - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -/* - * Called when the texture environment mode is changed. - */ -int -envmode_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName envmode ?mode?\"", - TCL_STATIC); - return TCL_ERROR; - } - - if (strcmp(argv[2], "GL_MODULATE") == 0) { - envmode = GL_MODULATE; - } else if (strcmp(argv[2], "GL_DECAL") == 0) { - envmode = GL_DECAL; - } else if (strcmp(argv[2], "GL_BLEND") == 0) { - envmode = GL_BLEND; - } else { - Tcl_SetResult(interp, "unknown texture env mode", TCL_STATIC); - return TCL_ERROR; - } - - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, envmode); - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -/* - * Called when the polygon color is changed. - */ -int -polycolor_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 5) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName polycolor ?r? ?g? ?b?\"", - TCL_STATIC); - return TCL_ERROR; - } - - polycolor[0] = atoi(argv[2]); - polycolor[1] = atoi(argv[3]); - polycolor[2] = atoi(argv[4]); - - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -/* - * Called when the texture image is to be changed - */ -int -image_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName image ?name?\"", - TCL_STATIC); - return TCL_ERROR; - } - - if (strcmp(argv[2], "CHECKER") == 0) { - texture_image(CHECKER); - } else if (strcmp(argv[2], "FACE") == 0) { - texture_image(FACE); - } else if (strcmp(argv[2], "TREE") == 0) { - texture_image(TREE); - } else { - Tcl_SetResult(interp, "unknown texture image", TCL_STATIC); - return TCL_ERROR; - } - - Togl_PostRedisplay(togl); - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -/* - * Called when the texture coordinate scale is changed. - */ -int -coord_scale_cb(Togl *togl, int argc, CONST84 char *argv[]) -{ - Tcl_Interp *interp = Togl_Interp(togl); - float s; - - /* error checking */ - if (argc != 3) { - Tcl_SetResult(interp, - "wrong # args: should be \"pathName coord_scale ?scale?\"", - TCL_STATIC); - return TCL_ERROR; - } - - s = atof(argv[2]); - if (s > 0.0 && s < 10.0) { - coord_scale = s; - Togl_PostRedisplay(togl); - } - - /* Let result string equal value */ - strcpy(interp->result, argv[2]); - return TCL_OK; -} - - -TOGL_EXTERN int -Texture_Init(Tcl_Interp *interp) -{ - /* - * Initialize Tcl, Tk, and the Togl widget module. - */ -#ifdef USE_TCL_STUBS - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif -#ifdef USE_TK_STUBS - if (Tk_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif - - if (Togl_Init(interp) == TCL_ERROR) { - return TCL_ERROR; - } - - /* - * Specify the C callback functions for widget creation, display, - * and reshape. - */ - Togl_CreateFunc(create_cb); - Togl_DisplayFunc(display_cb); - Togl_ReshapeFunc(reshape_cb); - - /* - * Make a new Togl widget command so the Tcl code can set a C variable. - */ - Togl_CreateCommand("min_filter", minfilter_cb); - Togl_CreateCommand("mag_filter", magfilter_cb); - Togl_CreateCommand("xrot", xrot_cb); - Togl_CreateCommand("yrot", yrot_cb); - Togl_CreateCommand("scale", scale_cb); - Togl_CreateCommand("swrap", swrap_cb); - Togl_CreateCommand("twrap", twrap_cb); - Togl_CreateCommand("envmode", envmode_cb); - Togl_CreateCommand("polycolor", polycolor_cb); - Togl_CreateCommand("image", image_cb); - Togl_CreateCommand("coord_scale", coord_scale_cb); - - /* - * Call Tcl_CreateCommand for application-specific commands, if - * they weren't already created by the init procedures called above. - */ - - return TCL_OK; -} diff --git a/ng/Togl-1.7/texture.tcl b/ng/Togl-1.7/texture.tcl deleted file mode 100644 index 6333c069..00000000 --- a/ng/Togl-1.7/texture.tcl +++ /dev/null @@ -1,283 +0,0 @@ -#!/bin/sh -# the next line restarts using wish \ -exec wish "$0" "$@" - -# $Id: texture.tcl,v 1.5 2001/12/20 13:59:31 beskow Exp $ - -# Togl - a Tk OpenGL widget -# Copyright (C) 1996 Brian Paul and Ben Bederson -# See the LICENSE file for copyright details. - - -# $Log: texture.tcl,v $ -# Revision 1.5 2001/12/20 13:59:31 beskow -# Improved error-handling in togl.c in case of window creation failure -# Added pkgIndex target to makefile -# Updated documentation to reflect stubs-interface (Togl.html + new README.stubs) -# Added tk8.4a3 headers -# Removed obsolete Tk internal headers -# -# Revision 1.4 2001/01/29 18:11:53 brianp -# Jonas Beskow's changes to use Tcl/Tk stub interface -# -# Revision 1.3 1998/01/24 14:05:50 brianp -# added quit button (Ben Bederson) -# -# Revision 1.2 1997/09/30 23:54:46 brianp -# new layout -# -# Revision 1.1 1996/10/23 23:18:36 brianp -# Initial revision -# - - -# Togl texture map demo - -load [file dirname [info script]]/texture[info sharedlibextension] - - -# Called magnification filter changes -proc new_magfilter {} { - global magfilter - .f1.view mag_filter $magfilter -} - - -# Called minification filter changes -proc new_minfilter {} { - global minfilter - .f1.view min_filter $minfilter -} - - -# Called when texture image radio button changes -proc new_image {} { - global teximage - .f1.view image $teximage -} - - -# Called when texture S wrap button changes -proc new_swrap {} { - global swrap - .f1.view swrap $swrap -} - - -# Called when texture T wrap button changes -proc new_twrap {} { - global twrap - .f1.view twrap $twrap -} - - -# Called when texture environment radio button selected -proc new_env {} { - global envmode - .f1.view envmode $envmode -} - - -# Called when polygon color sliders change -proc new_color { foo } { - global poly_red poly_green poly_blue - .f1.view polycolor $poly_red $poly_green $poly_blue -} - - -proc new_coord_scale { name element op } { - global coord_scale - .f1.view coord_scale $coord_scale -} - - - - -# Make the widgets -proc setup {} { - global magfilter - global minfilter - global teximage - global swrap - global twrap - global envmode - global poly_red - global poly_green - global poly_blue - global coord_scale - global startx starty # location of mouse when button pressed - global xangle yangle - global xangle0 yangle0 - global scale scale0 - - wm title . "Texture Map Options" - - ### Two frames: top half and bottom half - frame .f1 - frame .f2 - - ### The OpenGL window - togl .f1.view -width 250 -height 250 -rgba true -double true -depth true - - - ### Filter radio buttons - frame .f1.filter -relief ridge -borderwidth 3 - - frame .f1.filter.mag -relief ridge -borderwidth 2 - - label .f1.filter.mag.label -text "Magnification Filter" -anchor w - radiobutton .f1.filter.mag.nearest -text GL_NEAREST -anchor w -variable magfilter -value GL_NEAREST -command new_magfilter - radiobutton .f1.filter.mag.linear -text GL_LINEAR -anchor w -variable magfilter -value GL_LINEAR -command new_magfilter - - frame .f1.filter.min -relief ridge -borderwidth 2 - - label .f1.filter.min.label -text "Minification Filter" -anchor w - radiobutton .f1.filter.min.nearest -text GL_NEAREST -anchor w -variable minfilter -value GL_NEAREST -command new_minfilter - radiobutton .f1.filter.min.linear -text GL_LINEAR -anchor w -variable minfilter -value GL_LINEAR -command new_minfilter - radiobutton .f1.filter.min.nearest_mipmap_nearest -text GL_NEAREST_MIPMAP_NEAREST -anchor w -variable minfilter -value GL_NEAREST_MIPMAP_NEAREST -command new_minfilter - radiobutton .f1.filter.min.linear_mipmap_nearest -text GL_LINEAR_MIPMAP_NEAREST -anchor w -variable minfilter -value GL_LINEAR_MIPMAP_NEAREST -command new_minfilter - radiobutton .f1.filter.min.nearest_mipmap_linear -text GL_NEAREST_MIPMAP_LINEAR -anchor w -variable minfilter -value GL_NEAREST_MIPMAP_LINEAR -command new_minfilter - radiobutton .f1.filter.min.linear_mipmap_linear -text GL_LINEAR_MIPMAP_LINEAR -anchor w -variable minfilter -value GL_LINEAR_MIPMAP_LINEAR -command new_minfilter - - pack .f1.filter.mag -fill x - pack .f1.filter.mag.label -fill x - pack .f1.filter.mag.nearest -side top -fill x - pack .f1.filter.mag.linear -side top -fill x - - pack .f1.filter.min -fill both -expand true - pack .f1.filter.min.label -side top -fill x - pack .f1.filter.min.nearest -side top -fill x - pack .f1.filter.min.linear -side top -fill x - pack .f1.filter.min.nearest_mipmap_nearest -side top -fill x - pack .f1.filter.min.linear_mipmap_nearest -side top -fill x - pack .f1.filter.min.nearest_mipmap_linear -side top -fill x - pack .f1.filter.min.linear_mipmap_linear -side top -fill x - - - ### Texture coordinate scale and wrapping - frame .f2.coord -relief ridge -borderwidth 3 - frame .f2.coord.scale -relief ridge -borderwidth 2 - label .f2.coord.scale.label -text "Max Texture Coord" -anchor w - entry .f2.coord.scale.entry -textvariable coord_scale - trace variable coord_scale w new_coord_scale - - frame .f2.coord.s -relief ridge -borderwidth 2 - label .f2.coord.s.label -text "GL_TEXTURE_WRAP_S" -anchor w - radiobutton .f2.coord.s.repeat -text "GL_REPEAT" -anchor w -variable swrap -value GL_REPEAT -command new_swrap - radiobutton .f2.coord.s.clamp -text "GL_CLAMP" -anchor w -variable swrap -value GL_CLAMP -command new_swrap - - frame .f2.coord.t -relief ridge -borderwidth 2 - label .f2.coord.t.label -text "GL_TEXTURE_WRAP_T" -anchor w - radiobutton .f2.coord.t.repeat -text "GL_REPEAT" -anchor w -variable twrap -value GL_REPEAT -command new_twrap - radiobutton .f2.coord.t.clamp -text "GL_CLAMP" -anchor w -variable twrap -value GL_CLAMP -command new_twrap - - pack .f2.coord.scale -fill both -expand true - pack .f2.coord.scale.label -side top -fill x - pack .f2.coord.scale.entry -side top -fill x - - pack .f2.coord.s -fill x - pack .f2.coord.s.label -side top -fill x - pack .f2.coord.s.repeat -side top -fill x - pack .f2.coord.s.clamp -side top -fill x - - pack .f2.coord.t -fill x - pack .f2.coord.t.label -side top -fill x - pack .f2.coord.t.repeat -side top -fill x - pack .f2.coord.t.clamp -side top -fill x - - - ### Texture image radio buttons (just happens to fit into the coord frame) - frame .f2.env -relief ridge -borderwidth 3 - frame .f2.env.image -relief ridge -borderwidth 2 - label .f2.env.image.label -text "Texture Image" -anchor w - radiobutton .f2.env.image.checker -text "Checker" -anchor w -variable teximage -value CHECKER -command new_image - radiobutton .f2.env.image.tree -text "Tree" -anchor w -variable teximage -value TREE -command new_image - radiobutton .f2.env.image.face -text "Face" -anchor w -variable teximage -value FACE -command new_image - pack .f2.env.image -fill x - pack .f2.env.image.label -side top -fill x - pack .f2.env.image.checker -side top -fill x - pack .f2.env.image.tree -side top -fill x - pack .f2.env.image.face -side top -fill x - - - ### Texture Environment - label .f2.env.label -text "GL_TEXTURE_ENV_MODE" -anchor w - radiobutton .f2.env.modulate -text "GL_MODULATE" -anchor w -variable envmode -value GL_MODULATE -command new_env - radiobutton .f2.env.decal -text "GL_DECAL" -anchor w -variable envmode -value GL_DECAL -command new_env - radiobutton .f2.env.blend -text "GL_BLEND" -anchor w -variable envmode -value GL_BLEND -command new_env - pack .f2.env.label -fill x - pack .f2.env.modulate -side top -fill x - pack .f2.env.decal -side top -fill x - pack .f2.env.blend -side top -fill x - - ### Polygon color - frame .f2.color -relief ridge -borderwidth 3 - label .f2.color.label -text "Polygon color" -anchor w - scale .f2.color.red -label Red -from 0 -to 255 -orient horizontal -variable poly_red -command new_color - scale .f2.color.green -label Green -from 0 -to 255 -orient horizontal -variable poly_green -command new_color - scale .f2.color.blue -label Blue -from 0 -to 255 -orient horizontal -variable poly_blue -command new_color - pack .f2.color.label -fill x - pack .f2.color.red -side top -fill x - pack .f2.color.green -side top -fill x - pack .f2.color.blue -side top -fill x - - - ### Main widgets - pack .f1.view -side left -fill both -expand true - pack .f1.filter -side left -fill y - pack .f1 -side top -fill both -expand true - - pack .f2.coord .f2.env -side left -fill both - pack .f2.color -fill x - pack .f2 -side top -fill x - - button .btn -text Quit -command exit - pack .btn -expand true -fill both - - bind .f1.view { - set startx %x - set starty %y - set xangle0 $xangle - set yangle0 $yangle - } - - bind .f1.view { - set xangle [expr $xangle0 + (%x - $startx) / 3.0 ] - set yangle [expr $yangle0 + (%y - $starty) / 3.0 ] - .f1.view yrot $xangle - .f1.view xrot $yangle - } - - bind .f1.view { - set startx %x - set starty %y - set scale0 $scale - } - - bind .f1.view { - set q [ expr ($starty - %y) / 400.0 ] - set scale [expr $scale0 * exp($q)] - .f1.view scale $scale - } - - # set default values: - set minfilter GL_NEAREST_MIPMAP_LINEAR - set magfilter GL_LINEAR - set swrap GL_REPEAT - set twrap GL_REPEAT - set envmode GL_MODULATE - set teximage CHECKER - set poly_red 255 - set poly_green 255 - set poly_blue 255 - set coord_scale 1.0 - - set xangle 0.0 - set yangle 0.0 - set scale 1.0 -} - - -# Execution starts here! -setup - diff --git a/ng/Togl-1.7/tkMacOSX.h b/ng/Togl-1.7/tkMacOSX.h deleted file mode 100644 index 25e677e2..00000000 --- a/ng/Togl-1.7/tkMacOSX.h +++ /dev/null @@ -1,35 +0,0 @@ -/* This file isn't installed by default */ -/* - * tkMacOSXInt.h -- - * - * Declarations of Macintosh specific exported variables and procedures. - * - * Copyright (c) 1995-1997 Sun Microsystems, Inc. - * Copyright 2001, Apple Computer, Inc. - * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. - * - * RCS: @(#) $Id: tkMacOSX.h,v 1.1 2005/04/22 02:00:07 gregcouch Exp $ - */ - -#ifndef _TKMAC -#define _TKMAC - -#include -#include "tkInt.h" - -/* - * Structures and function types for handling Netscape-type in process - * embedding where Tk does not control the top-level - */ - -typedef int (Tk_MacOSXEmbedRegisterWinProc) (int winID, Tk_Window window); -typedef GWorldPtr (Tk_MacOSXEmbedGetGrafPortProc) (Tk_Window window); -typedef int (Tk_MacOSXEmbedMakeContainerExistProc) (Tk_Window window); -typedef void (Tk_MacOSXEmbedGetClipProc) (Tk_Window window, RgnHandle rgn); -typedef void (Tk_MacOSXEmbedGetOffsetInParentProc) (Tk_Window window, Point *ulCorner); - -#include "tkPlatDecls.h" - -#endif /* _TKMAC */ diff --git a/ng/Togl-1.7/togl.c b/ng/Togl-1.7/togl.c deleted file mode 100644 index a1b75d1e..00000000 --- a/ng/Togl-1.7/togl.c +++ /dev/null @@ -1,4033 +0,0 @@ -/* $Id: togl.c,v 1.73 2005/10/26 07:40:22 gregcouch Exp $ */ - -/* vi:set sw=4: */ - -/* - * Togl - a Tk OpenGL widget - * - * Copyright (C) 1996-2002 Brian Paul and Ben Bederson - * See the LICENSE file for copyright details. - */ - -/* - * Currently we support X11, Win32 and Macintosh only - */ - -#include "togl.h" - -/* Use TCL_STUPID to cast (const char *) to (char *) where the Tcl function - * prototype argument should really be const */ -#define TCL_STUPID (char *) - -/* Use WIDGREC to cast widgRec arguments */ -#define WIDGREC (char *) - -/*** Windows headers ***/ -#if defined(TOGL_WGL) -# define WIN32_LEAN_AND_MEAN -# include -# undef WIN32_LEAN_AND_MEAN -# include - -/*** X Window System headers ***/ -#elif defined(TOGL_X11) -# include -# include -# include /* for XA_RGB_DEFAULT_MAP atom */ -# if defined(__vms) -# include /* for XmuLookupStandardColormap */ -# else -# include /* for XmuLookupStandardColormap */ -# endif -# include - -/*** Mac headers ***/ -#elif defined(TOGL_AGL_CLASSIC) -# include -# include -# include -# include - -#elif defined(TOGL_AGL) -# define Cursor QDCursor -# include -# undef Cursor -# include "tkMacOSX.h" -# include /* usa MacDrawable */ -# include - -#else /* make sure only one platform defined */ -# error Unsupported platform, or confused platform defines... -#endif - -/*** Standard C headers ***/ -#include -#include -#include - -#ifdef TOGL_WGL -# include -#endif - -#if TK_MAJOR_VERSION < 8 -# error Sorry Togl requires Tcl/Tk ver 8.0 or higher. -#endif - -#if defined(TOGL_AGL_CLASSIC) -# if TK_MAJOR_VERSION < 8 || (TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION < 3) -# error Sorry Mac classic version requires Tcl/Tk ver 8.3.0 or higher. -# endif -#endif /* TOGL_AGL_CLASSIC */ - -#if defined(TOGL_AGL) -# if TK_MAJOR_VERSION < 8 || (TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION < 4) -# error Sorry Mac Aqua version requires Tcl/Tk ver 8.4.0 or higher. -# endif -#endif /* TOGL_AGL */ - -/* workaround for bug #123153 in tcl ver8.4a2 (tcl.h) */ -#if defined(Tcl_InitHashTable) && defined(USE_TCL_STUBS) -# undef Tcl_InitHashTable -# define Tcl_InitHashTable (tclStubsPtr->tcl_InitHashTable) -#endif -#if TK_MAJOR_VERSION > 8 || (TK_MAJOR_VERSION == 8 && TK_MINOR_VERSION >= 4) -# define HAVE_TK_SETCLASSPROCS -/* pointer to Tk_SetClassProcs function in the stub table */ - -static void (*SetClassProcsPtr) - _ANSI_ARGS_((Tk_Window, Tk_ClassProcs *, ClientData)); -#endif - -/* - * Copy of TkClassProcs declarations form tkInt.h - * (this is needed for Tcl ver =< 8.4a3) - */ - -typedef Window (TkClassCreateProc) _ANSI_ARGS_((Tk_Window tkwin, - Window parent, ClientData instanceData)); -typedef void (TkClassGeometryProc) _ANSI_ARGS_((ClientData instanceData)); -typedef void (TkClassModalProc) _ANSI_ARGS_((Tk_Window tkwin, - XEvent *eventPtr)); -typedef struct TkClassProcs -{ - TkClassCreateProc *createProc; - TkClassGeometryProc *geometryProc; - TkClassModalProc *modalProc; -} TkClassProcs; - - -/* Defaults */ -#define DEFAULT_WIDTH "400" -#define DEFAULT_HEIGHT "400" -#define DEFAULT_IDENT "" -#define DEFAULT_FONTNAME "fixed" -#define DEFAULT_TIME "1" - - -#ifdef TOGL_WGL -/* Maximum size of a logical palette corresponding to a colormap in color index - * mode. */ -# define MAX_CI_COLORMAP_SIZE 4096 - -# if TOGL_USE_FONTS != 1 -/* - * copy of TkWinColormap from tkWinInt.h - */ - -typedef struct -{ - HPALETTE palette; /* Palette handle used when drawing. */ - UINT size; /* Number of entries in the palette. */ - int stale; /* 1 if palette needs to be realized, otherwise - * 0. If the palette is stale, then an idle - * handler is scheduled to realize the palette. */ - Tcl_HashTable refCounts; /* Hash table of palette entry reference counts - * indexed by pixel value. */ -} TkWinColormap; -# else -# include "tkWinInt.h" -# endif - -static LRESULT(CALLBACK *tkWinChildProc) (HWND hwnd, UINT message, - WPARAM wParam, LPARAM lParam) = NULL; - -# define TK_WIN_CHILD_CLASS_NAME "TkChild" - -#endif /* TOGL_WGL */ - - -#define MAX(a,b) (((a)>(b))?(a):(b)) - -#define TCL_ERR(interp, string) \ - do { \ - Tcl_ResetResult(interp); \ - Tcl_AppendResult(interp, string, NULL); \ - return TCL_ERROR; \ - } while (0) - -/* The constant DUMMY_WINDOW is used to signal window creation failure from the - * Togl_CreateWindow() */ -#define DUMMY_WINDOW ((Window) -1) - -#define ALL_EVENTS_MASK \ - (KeyPressMask | \ - KeyReleaseMask | \ - ButtonPressMask | \ - ButtonReleaseMask | \ - EnterWindowMask | \ - LeaveWindowMask | \ - PointerMotionMask | \ - ExposureMask | \ - VisibilityChangeMask | \ - FocusChangeMask | \ - PropertyChangeMask | \ - ColormapChangeMask) - -struct Togl -{ - Togl *Next; /* next in linked list */ - -#if defined(TOGL_WGL) - HDC tglGLHdc; /* Device context of device that OpenGL calls - * will be drawn on */ - HGLRC tglGLHglrc; /* OpenGL rendering context to be made current */ - int CiColormapSize; /* (Maximum) size of colormap in color index - * mode */ -#elif defined(TOGL_X11) - GLXContext GlCtx; /* Normal planes GLX context */ -#elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - AGLContext aglCtx; -#endif /* TOGL_WGL */ - - Display *display; /* X's token for the window's display. */ - Tk_Window TkWin; /* Tk window structure */ - Tcl_Interp *Interp; /* Tcl interpreter */ - Tcl_Command widgetCmd; /* Token for togl's widget command */ -#ifndef NO_TK_CURSOR - Tk_Cursor Cursor; /* The widget's cursor */ -#endif - int Width, Height; /* Dimensions of window */ - int SetGrid; /* positive is grid size for window manager */ - int TimerInterval; /* Time interval for timer in milliseconds */ -#if (TCL_MAJOR_VERSION * 100 + TCL_MINOR_VERSION) >= 705 - Tcl_TimerToken timerHandler; /* Token for togl's timer handler */ -#else - Tk_TimerToken timerHandler; /* Token for togl's timer handler */ -#endif - Bool RgbaFlag; /* configuration flags (ala GLX parameters) */ - int RgbaRed; - int RgbaGreen; - int RgbaBlue; - Bool DoubleFlag; - Bool DepthFlag; - int DepthSize; - Bool AccumFlag; - int AccumRed; - int AccumGreen; - int AccumBlue; - int AccumAlpha; - Bool AlphaFlag; - int AlphaSize; - Bool StencilFlag; - int StencilSize; - Bool PrivateCmapFlag; - Bool OverlayFlag; - Bool StereoFlag; -#ifdef __sgi - Bool OldStereoFlag; -#endif - int AuxNumber; - Bool Indirect; - int PixelFormat; - const char *ShareList; /* name (ident) of Togl to share dlists with */ - const char *ShareContext; /* name (ident) to share OpenGL context with */ - - const char *Ident; /* User's identification string */ - ClientData Client_Data; /* Pointer to user data */ - - Bool UpdatePending; /* Should normal planes be redrawn? */ - - Togl_Callback *CreateProc; /* Callback when widget is created */ - Togl_Callback *DisplayProc; /* Callback when widget is rendered */ - Togl_Callback *ReshapeProc; /* Callback when window size changes */ - Togl_Callback *DestroyProc; /* Callback when widget is destroyed */ - Togl_Callback *TimerProc; /* Callback when widget is idle */ - - /* Overlay stuff */ -#if defined(TOGL_X11) - GLXContext OverlayCtx; /* Overlay planes OpenGL context */ -#elif defined(TOGL_WGL) - HGLRC tglGLOverlayHglrc; -#endif /* TOGL_X11 */ - - Window OverlayWindow; /* The overlay window, or 0 */ - Togl_Callback *OverlayDisplayProc; /* Overlay redraw proc */ - Bool OverlayUpdatePending; /* Should overlay be redrawn? */ - Colormap OverlayCmap; /* colormap for overlay is created */ - int OverlayTransparentPixel; /* transparent pixel */ - Bool OverlayIsMapped; - - /* for DumpToEpsFile: Added by Miguel A. de Riera Pasenau 10.01.1997 */ - XVisualInfo *VisInfo; /* Visual info of the current */ - /* context needed for DumpToEpsFile */ - GLfloat *EpsRedMap; /* Index2RGB Maps for Color index modes */ - GLfloat *EpsGreenMap; - GLfloat *EpsBlueMap; - GLint EpsMapSize; /* = Number of indices in our Togl */ -}; - - -/* NTNTNT need to change to handle Windows Data Types */ -/* - * Prototypes for functions local to this file - */ -static int Togl_Cmd(ClientData clientData, Tcl_Interp *interp, - int argc, CONST84 char **argv); -static void Togl_EventProc(ClientData clientData, XEvent *eventPtr); -static Window Togl_CreateWindow(Tk_Window, Window, ClientData); -static void Togl_WorldChanged(ClientData); - -#ifdef MESA_COLOR_HACK -static int get_free_color_cells(Display *display, int screen, - Colormap colormap); -static void free_default_color_cells(Display *display, Colormap colormap); -#endif -static void ToglCmdDeletedProc(ClientData); - - - -#if defined(__sgi) -/* SGI-only stereo */ -static void oldStereoMakeCurrent(Display *dpy, Window win, GLXContext ctx); -static void oldStereoInit(Togl *togl, int stereoEnabled); -#endif - -#if defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) -static void SetMacBufRect(Togl *togl); -#endif - - -/* - * Setup Togl widget configuration options: - */ - -static Tk_ConfigSpec configSpecs[] = { - {TK_CONFIG_PIXELS, TCL_STUPID "-height", "height", "Height", - DEFAULT_HEIGHT, Tk_Offset(Togl, Height), 0, NULL}, - - {TK_CONFIG_PIXELS, TCL_STUPID "-width", "width", "Width", - DEFAULT_WIDTH, Tk_Offset(Togl, Width), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-setgrid", "setGrid", "SetGrid", - "0", Tk_Offset(Togl, SetGrid), 0}, - - {TK_CONFIG_BOOLEAN, TCL_STUPID "-rgba", "rgba", "Rgba", - "true", Tk_Offset(Togl, RgbaFlag), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-redsize", "redsize", "RedSize", - "1", Tk_Offset(Togl, RgbaRed), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-greensize", "greensize", "GreenSize", - "1", Tk_Offset(Togl, RgbaGreen), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-bluesize", "bluesize", "BlueSize", - "1", Tk_Offset(Togl, RgbaBlue), 0, NULL}, - - {TK_CONFIG_BOOLEAN, TCL_STUPID "-double", "double", "Double", - "false", Tk_Offset(Togl, DoubleFlag), 0, NULL}, - - {TK_CONFIG_BOOLEAN, TCL_STUPID "-depth", "depth", "Depth", - "false", Tk_Offset(Togl, DepthFlag), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-depthsize", "depthsize", "DepthSize", - "1", Tk_Offset(Togl, DepthSize), 0, NULL}, - - {TK_CONFIG_BOOLEAN, TCL_STUPID "-accum", "accum", "Accum", - "false", Tk_Offset(Togl, AccumFlag), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-accumredsize", "accumredsize", "AccumRedSize", - "1", Tk_Offset(Togl, AccumRed), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-accumgreensize", "accumgreensize", - "AccumGreenSize", - "1", Tk_Offset(Togl, AccumGreen), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-accumbluesize", "accumbluesize", - "AccumBlueSize", - "1", Tk_Offset(Togl, AccumBlue), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-accumalphasize", "accumalphasize", - "AccumAlphaSize", - "1", Tk_Offset(Togl, AccumAlpha), 0, NULL}, - - {TK_CONFIG_BOOLEAN, TCL_STUPID "-alpha", "alpha", "Alpha", - "false", Tk_Offset(Togl, AlphaFlag), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-alphasize", "alphasize", "AlphaSize", - "1", Tk_Offset(Togl, AlphaSize), 0, NULL}, - - {TK_CONFIG_BOOLEAN, TCL_STUPID "-stencil", "stencil", "Stencil", - "false", Tk_Offset(Togl, StencilFlag), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-stencilsize", "stencilsize", "StencilSize", - "1", Tk_Offset(Togl, StencilSize), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-auxbuffers", "auxbuffers", "AuxBuffers", - "0", Tk_Offset(Togl, AuxNumber), 0, NULL}, - - {TK_CONFIG_BOOLEAN, TCL_STUPID "-privatecmap", "privateCmap", "PrivateCmap", - "false", Tk_Offset(Togl, PrivateCmapFlag), 0, NULL}, - - {TK_CONFIG_BOOLEAN, TCL_STUPID "-overlay", "overlay", "Overlay", - "false", Tk_Offset(Togl, OverlayFlag), 0, NULL}, - - {TK_CONFIG_BOOLEAN, TCL_STUPID "-stereo", "stereo", "Stereo", - "false", Tk_Offset(Togl, StereoFlag), 0, NULL}, - -#ifdef __sgi - {TK_CONFIG_BOOLEAN, TCL_STUPID "-oldstereo", "oldstereo", "OldStereo", - "false", Tk_Offset(Togl, OldStereoFlag), 0, NULL}, -#endif - -#ifndef NO_TK_CURSOR - {TK_CONFIG_ACTIVE_CURSOR, TCL_STUPID "-cursor", "cursor", "Cursor", - "", Tk_Offset(Togl, Cursor), TK_CONFIG_NULL_OK}, -#endif - - {TK_CONFIG_INT, TCL_STUPID "-time", "time", "Time", - DEFAULT_TIME, Tk_Offset(Togl, TimerInterval), 0, NULL}, - - {TK_CONFIG_STRING, TCL_STUPID "-sharelist", "sharelist", "ShareList", - NULL, Tk_Offset(Togl, ShareList), 0, NULL}, - - {TK_CONFIG_STRING, TCL_STUPID "-sharecontext", "sharecontext", - "ShareContext", NULL, Tk_Offset(Togl, ShareContext), 0, NULL}, - - {TK_CONFIG_STRING, TCL_STUPID "-ident", "ident", "Ident", - DEFAULT_IDENT, Tk_Offset(Togl, Ident), 0, NULL}, - - {TK_CONFIG_BOOLEAN, TCL_STUPID "-indirect", "indirect", "Indirect", - "false", Tk_Offset(Togl, Indirect), 0, NULL}, - - {TK_CONFIG_INT, TCL_STUPID "-pixelformat", "pixelFormat", "PixelFormat", - "0", Tk_Offset(Togl, PixelFormat), 0, NULL}, - - {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0, NULL} -}; - - -/* - * Default callback pointers. When a new Togl widget is created it - * will be assigned these initial callbacks. - */ -static Togl_Callback *DefaultCreateProc = NULL; -static Togl_Callback *DefaultDisplayProc = NULL; -static Togl_Callback *DefaultReshapeProc = NULL; -static Togl_Callback *DefaultDestroyProc = NULL; -static Togl_Callback *DefaultOverlayDisplayProc = NULL; -static Togl_Callback *DefaultTimerProc = NULL; -static ClientData DefaultClientData = NULL; -static Tcl_HashTable CommandTable; - -/* - * Head of linked list of all Togl widgets - */ -static Togl *ToglHead = NULL; - -/* - * Add given togl widget to linked list. - */ -static void -AddToList(Togl *t) -{ - t->Next = ToglHead; - ToglHead = t; -} - -/* - * Remove given togl widget from linked list. - */ -static void -RemoveFromList(Togl *t) -{ - Togl *prev = NULL; - Togl *pos = ToglHead; - - while (pos) { - if (pos == t) { - if (prev) { - prev->Next = pos->Next; - } else { - ToglHead = pos->Next; - } - return; - } - prev = pos; - pos = pos->Next; - } -} - -/* - * Return pointer to togl widget given a user identifier string. - */ -static Togl * -FindTogl(const char *ident) -{ - Togl *t = ToglHead; - - while (t) { - if (strcmp(t->Ident, ident) == 0) - return t; - t = t->Next; - } - return NULL; -} - - -#if defined(TOGL_X11) -/* - * Return pointer to another togl widget with same OpenGL context. - */ -static Togl * -FindToglWithSameContext(Togl *togl) -{ - Togl *t; - - for (t = ToglHead; t != NULL; t = t->Next) { - if (t == togl) - continue; -# if defined(TOGL_WGL) - if (t->tglGLHglrc == togl->tglGLHglrc) -# elif defined(TOGL_X11) - if (t->GlCtx == togl->GlCtx) -# elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - if (t->aglCtx == togl->aglCtx) -# endif - return t; - } - return NULL; -} -#endif - -#ifdef USE_OVERLAY -/* - * Return pointer to another togl widget with same OpenGL overlay context. - */ -static Togl * -FindToglWithSameOverlayContext(Togl *togl) -{ - Togl *t; - - for (t = ToglHead; t != NULL; t = t->Next) { - if (t == togl) - continue; -# if defined(TOGL_X11) - if (t->OverlayCtx == togl->OverlayCtx) -# elif defined(TOGL_WGL) - if (t->tglGLOverlayHglrc == togl->tglGLOverlayHglrc) -# endif - return t; - } - return NULL; -} -#endif - -#if defined(TOGL_X11) -/* - * Return an X colormap to use for OpenGL RGB-mode rendering. - * Input: dpy - the X display - * scrnum - the X screen number - * visinfo - the XVisualInfo as returned by glXChooseVisual() - * Return: an X Colormap or 0 if there's a _serious_ error. - */ -static Colormap -get_rgb_colormap(Display *dpy, - int scrnum, const XVisualInfo *visinfo, Tk_Window tkwin) -{ - Atom hp_cr_maps; - Status status; - int numCmaps; - int i; - XStandardColormap *standardCmaps; - Window root = XRootWindow(dpy, scrnum); - Bool using_mesa; - - /* - * First check if visinfo's visual matches the default/root visual. - */ - if (visinfo->visual == Tk_Visual(tkwin)) { - /* use the default/root colormap */ - Colormap cmap; - - cmap = Tk_Colormap(tkwin); -# ifdef MESA_COLOR_HACK - (void) get_free_color_cells(dpy, scrnum, cmap); -# endif - return cmap; - } - - /* - * Check if we're using Mesa. - */ - if (strstr(glXQueryServerString(dpy, scrnum, GLX_VERSION), "Mesa")) { - using_mesa = True; - } else { - using_mesa = False; - } - - /* - * Next, if we're using Mesa and displaying on an HP with the "Color - * Recovery" feature and the visual is 8-bit TrueColor, search for a - * special colormap initialized for dithering. Mesa will know how to - * dither using this colormap. - */ - if (using_mesa) { - hp_cr_maps = XInternAtom(dpy, "_HP_RGB_SMOOTH_MAP_LIST", True); - if (hp_cr_maps -# ifdef __cplusplus - && visinfo->visual->c_class == TrueColor -# else - && visinfo->visual->class == TrueColor -# endif - && visinfo->depth == 8) { - status = XGetRGBColormaps(dpy, root, &standardCmaps, - &numCmaps, hp_cr_maps); - if (status) { - for (i = 0; i < numCmaps; i++) { - if (standardCmaps[i].visualid == visinfo->visual->visualid) { - Colormap cmap = standardCmaps[i].colormap; - - (void) XFree(standardCmaps); - return cmap; - } - } - (void) XFree(standardCmaps); - } - } - } - - /* - * Next, try to find a standard X colormap. - */ -# if !HP && !SUN -# ifndef SOLARIS_BUG - status = XmuLookupStandardColormap(dpy, visinfo->screen, - visinfo->visualid, visinfo->depth, XA_RGB_DEFAULT_MAP, - /* replace */ False, /* retain */ True); - if (status == 1) { - status = XGetRGBColormaps(dpy, root, &standardCmaps, - &numCmaps, XA_RGB_DEFAULT_MAP); - if (status == 1) { - for (i = 0; i < numCmaps; i++) { - if (standardCmaps[i].visualid == visinfo->visualid) { - Colormap cmap = standardCmaps[i].colormap; - - (void) XFree(standardCmaps); - return cmap; - } - } - (void) XFree(standardCmaps); - } - } -# endif -# endif - - /* - * If we get here, give up and just allocate a new colormap. - */ - return XCreateColormap(dpy, root, visinfo->visual, AllocNone); -} -#elif defined(TOGL_WGL) - -/* Code to create RGB palette is taken from the GENGL sample program of Win32 - * SDK */ - -static unsigned char threeto8[8] = { - 0, 0111 >> 1, 0222 >> 1, 0333 >> 1, 0444 >> 1, 0555 >> 1, 0666 >> 1, 0377 -}; - -static unsigned char twoto8[4] = { - 0, 0x55, 0xaa, 0xff -}; - -static unsigned char oneto8[2] = { - 0, 255 -}; - -static int defaultOverride[13] = { - 0, 3, 24, 27, 64, 67, 88, 173, 181, 236, 247, 164, 91 -}; - -static PALETTEENTRY defaultPalEntry[20] = { - {0, 0, 0, 0}, - {0x80, 0, 0, 0}, - {0, 0x80, 0, 0}, - {0x80, 0x80, 0, 0}, - {0, 0, 0x80, 0}, - {0x80, 0, 0x80, 0}, - {0, 0x80, 0x80, 0}, - {0xC0, 0xC0, 0xC0, 0}, - - {192, 220, 192, 0}, - {166, 202, 240, 0}, - {255, 251, 240, 0}, - {160, 160, 164, 0}, - - {0x80, 0x80, 0x80, 0}, - {0xFF, 0, 0, 0}, - {0, 0xFF, 0, 0}, - {0xFF, 0xFF, 0, 0}, - {0, 0, 0xFF, 0}, - {0xFF, 0, 0xFF, 0}, - {0, 0xFF, 0xFF, 0}, - {0xFF, 0xFF, 0xFF, 0} -}; - -static unsigned char -ComponentFromIndex(int i, UINT nbits, UINT shift) -{ - unsigned char val; - - val = (unsigned char) (i >> shift); - switch (nbits) { - - case 1: - val &= 0x1; - return oneto8[val]; - - case 2: - val &= 0x3; - return twoto8[val]; - - case 3: - val &= 0x7; - return threeto8[val]; - - default: - return 0; - } -} - -static Colormap -Win32CreateRgbColormap(PIXELFORMATDESCRIPTOR pfd) -{ - TkWinColormap *cmap = (TkWinColormap *) ckalloc(sizeof (TkWinColormap)); - LOGPALETTE *pPal; - int n, i; - - n = 1 << pfd.cColorBits; - pPal = (PLOGPALETTE) LocalAlloc(LMEM_FIXED, sizeof (LOGPALETTE) - + n * sizeof (PALETTEENTRY)); - pPal->palVersion = 0x300; - pPal->palNumEntries = n; - for (i = 0; i < n; i++) { - pPal->palPalEntry[i].peRed = - ComponentFromIndex(i, pfd.cRedBits, pfd.cRedShift); - pPal->palPalEntry[i].peGreen = - ComponentFromIndex(i, pfd.cGreenBits, pfd.cGreenShift); - pPal->palPalEntry[i].peBlue = - ComponentFromIndex(i, pfd.cBlueBits, pfd.cBlueShift); - pPal->palPalEntry[i].peFlags = 0; - } - - /* fix up the palette to include the default GDI palette */ - if ((pfd.cColorBits == 8) - && (pfd.cRedBits == 3) && (pfd.cRedShift == 0) - && (pfd.cGreenBits == 3) && (pfd.cGreenShift == 3) - && (pfd.cBlueBits == 2) && (pfd.cBlueShift == 6)) { - for (i = 1; i <= 12; i++) - pPal->palPalEntry[defaultOverride[i]] = defaultPalEntry[i]; - } - - cmap->palette = CreatePalette(pPal); - LocalFree(pPal); - cmap->size = n; - cmap->stale = 0; - - /* Since this is a private colormap of a fix size, we do not need a valid - * hash table, but a dummy one */ - - Tcl_InitHashTable(&cmap->refCounts, TCL_ONE_WORD_KEYS); - return (Colormap) cmap; -} - -static Colormap -Win32CreateCiColormap(Togl *togl) -{ - /* Create a colormap with size of togl->CiColormapSize and set all entries - * to black */ - - LOGPALETTE logPalette; - TkWinColormap *cmap = (TkWinColormap *) ckalloc(sizeof (TkWinColormap)); - - logPalette.palVersion = 0x300; - logPalette.palNumEntries = 1; - logPalette.palPalEntry[0].peRed = 0; - logPalette.palPalEntry[0].peGreen = 0; - logPalette.palPalEntry[0].peBlue = 0; - logPalette.palPalEntry[0].peFlags = 0; - - cmap->palette = CreatePalette(&logPalette); - cmap->size = togl->CiColormapSize; - ResizePalette(cmap->palette, cmap->size); /* sets new entries to black */ - cmap->stale = 0; - - /* Since this is a private colormap of a fix size, we do not need a valid - * hash table, but a dummy one */ - - Tcl_InitHashTable(&cmap->refCounts, TCL_ONE_WORD_KEYS); - return (Colormap) cmap; -} -#endif /* TOGL_X11 */ - - - -/* - * Togl_Init - * - * Called upon system startup to create Togl command. - */ -int -Togl_Init(Tcl_Interp *interp) -{ - int major, minor, patchLevel, releaseType; - -#ifdef USE_TCL_STUBS - if (Tcl_InitStubs(interp, "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif -#ifdef USE_TK_STUBS - if (Tk_InitStubs(interp, TCL_STUPID "8.1", 0) == NULL) { - return TCL_ERROR; - } -#endif - - /* Skip all this on Tcl/Tk 8.0 or older. Seems to work */ -#if TCL_MAJOR_VERSION * 100 + TCL_MINOR_VERSION > 800 - Tcl_GetVersion(&major, &minor, &patchLevel, &releaseType); - -# ifdef HAVE_TK_SETCLASSPROCS - if (major > 8 - || (major == 8 - && (minor > 4 - || (minor == 4 && (releaseType > 0 - || patchLevel >= 2))))) { -# ifdef USE_TK_STUBS - SetClassProcsPtr = tkStubsPtr->tk_SetClassProcs; -# else - SetClassProcsPtr = Tk_SetClassProcs; -# endif - } else { - SetClassProcsPtr = NULL; - } -# else - if (major > 8 - || (major == 8 - && (minor > 4 - || (minor == 4 && (releaseType > 0 - || patchLevel >= 2))))) { - TCL_ERR(interp, - "Sorry, this instance of Togl was not compiled to work with Tcl/Tk 8.4a2 or higher."); - } -# endif - -#endif - - if (Tcl_PkgProvide(interp, "Togl", TOGL_VERSION) != TCL_OK) { - return TCL_ERROR; - } - - if (Tcl_CreateCommand(interp, "togl", Togl_Cmd, - (ClientData) Tk_MainWindow(interp), NULL) == NULL) - return TCL_ERROR; - - Tcl_InitHashTable(&CommandTable, TCL_STRING_KEYS); - - return TCL_OK; -} - - -/* - * Register a C function to be called when an Togl widget is realized. - */ -void -Togl_CreateFunc(Togl_Callback *proc) -{ - DefaultCreateProc = proc; -} - - -/* - * Register a C function to be called when an Togl widget must be redrawn. - */ -void -Togl_DisplayFunc(Togl_Callback *proc) -{ - DefaultDisplayProc = proc; -} - - -/* - * Register a C function to be called when an Togl widget is resized. - */ -void -Togl_ReshapeFunc(Togl_Callback *proc) -{ - DefaultReshapeProc = proc; -} - - -/* - * Register a C function to be called when an Togl widget is destroyed. - */ -void -Togl_DestroyFunc(Togl_Callback *proc) -{ - DefaultDestroyProc = proc; -} - - -/* - * Register a C function to be called from TimerEventHandler. - */ -void -Togl_TimerFunc(Togl_Callback *proc) -{ - DefaultTimerProc = proc; -} - - -/* - * Reset default callback pointers to NULL. - */ -void -Togl_ResetDefaultCallbacks(void) -{ - DefaultCreateProc = NULL; - DefaultDisplayProc = NULL; - DefaultReshapeProc = NULL; - DefaultDestroyProc = NULL; - DefaultOverlayDisplayProc = NULL; - DefaultTimerProc = NULL; - DefaultClientData = NULL; -} - - -/* - * Change the create callback for a specific Togl widget. - */ -void -Togl_SetCreateFunc(Togl *togl, Togl_Callback *proc) -{ - togl->CreateProc = proc; -} - - -/* - * Change the display/redraw callback for a specific Togl widget. - */ -void -Togl_SetDisplayFunc(Togl *togl, Togl_Callback *proc) -{ - togl->DisplayProc = proc; -} - - -/* - * Change the reshape callback for a specific Togl widget. - */ -void -Togl_SetReshapeFunc(Togl *togl, Togl_Callback *proc) -{ - togl->ReshapeProc = proc; -} - - -/* - * Change the destroy callback for a specific Togl widget. - */ -void -Togl_SetDestroyFunc(Togl *togl, Togl_Callback *proc) -{ - togl->DestroyProc = proc; -} - - -/* - * Togl_Timer - * - * Gets called from Tk_CreateTimerHandler. - */ -static void -Togl_Timer(ClientData clientData) -{ - Togl *togl = (Togl *) clientData; - - if (togl->TimerProc) { - togl->TimerProc(togl); - - /* Re-register this callback since Tcl/Tk timers are "one-shot". That - * is, after the timer callback is called it not normally called again. - * * * * * * * * * That's not the behavior we want for Togl. */ -#if (TK_MAJOR_VERSION * 100 + TK_MINOR_VERSION) >= 401 - togl->timerHandler = - Tcl_CreateTimerHandler(togl->TimerInterval, Togl_Timer, - (ClientData) togl); -#else - togl->timerHandler = - Tk_CreateTimerHandler(togl->TimeInterval, Togl_Timer, - (ClientData) togl); -#endif - } -} - - -/* - * Change the timer callback for a specific Togl widget. - * Pass NULL to disable the callback. - */ -void -Togl_SetTimerFunc(Togl *togl, Togl_Callback *proc) -{ - togl->TimerProc = proc; - if (proc) { -#if (TK_MAJOR_VERSION * 100 + TK_MINOR_VERSION) >= 401 - togl->timerHandler = - Tcl_CreateTimerHandler(togl->TimerInterval, Togl_Timer, - (ClientData) togl); -#else - togl->timerHandler = - Tk_CreateTimerHandler(togl->TimeInterval, Togl_Timer, - (ClientData) togl); -#endif - } -} - - - -/* - * Togl_CreateCommand - * - * Declares a new C sub-command of Togl callable from Tcl. - * Every time the sub-command is called from Tcl, the - * C routine will be called with all the arguments from Tcl. - */ -void -Togl_CreateCommand(char *cmd_name, Togl_CmdProc *cmd_proc) -{ - int new_item; - Tcl_HashEntry *entry; - - entry = Tcl_CreateHashEntry(&CommandTable, cmd_name, &new_item); - Tcl_SetHashValue(entry, cmd_proc); -} - - -/* - * Togl_MakeCurrent - * - * Bind the OpenGL rendering context to the specified - * Togl widget. - */ -void -Togl_MakeCurrent(const Togl *togl) -{ -#if defined(TOGL_WGL) - int res = wglMakeCurrent(togl->tglGLHdc, togl->tglGLHglrc); - - assert(res == TRUE); - -#elif defined(TOGL_X11) - if (!togl->GlCtx) - return; - (void) glXMakeCurrent(togl->display, - togl->TkWin ? Tk_WindowId(togl->TkWin) : None, togl->GlCtx); -# if defined(__sgi) - if (togl->OldStereoFlag) - oldStereoMakeCurrent(togl->display, - togl->TkWin ? Tk_WindowId(togl->TkWin) : None, togl->GlCtx); - -# endif /*__sgi STEREO */ - -#elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - if (!togl->aglCtx) - return; - aglSetCurrentContext(togl->aglCtx); -#endif -} - - -#ifdef TOGL_AGL_CLASSIC -/* tell OpenGL which part of the Mac window to render to */ -static void -SetMacBufRect(Togl *togl) -{ - GLint wrect[4]; - - /* set wrect[0,1] to lower left corner of widget */ - wrect[2] = ((TkWindow *) (togl->TkWin))->changes.width; - wrect[3] = ((TkWindow *) (togl->TkWin))->changes.height; - wrect[0] = ((TkWindow *) (togl->TkWin))->privatePtr->xOff; - wrect[1] = - ((TkWindow *) (togl->TkWin))->privatePtr->toplevel->portPtr-> - portRect.bottom - wrect[3] - - ((TkWindow *) (togl->TkWin))->privatePtr->yOff; - aglSetInteger(togl->aglCtx, AGL_BUFFER_RECT, wrect); - aglEnable(togl->aglCtx, AGL_BUFFER_RECT); - aglUpdateContext(togl->aglCtx); -} -#elif defined(TOGL_AGL) -/* tell OpenGL which part of the Mac window to render to */ -static void -SetMacBufRect(Togl *togl) -{ - GLint wrect[4]; - - /* set wrect[0,1] to lower left corner of widget */ - wrect[2] = Tk_Width(togl->TkWin); - wrect[3] = Tk_Height(togl->TkWin); - wrect[0] = ((TkWindow *) (togl->TkWin))->privatePtr->xOff; - - Rect r; - - GetPortBounds(((TkWindow *) (togl->TkWin))->privatePtr->toplevel->grafPtr, - &r); - - wrect[1] = r.bottom - - wrect[3] - ((TkWindow *) (togl->TkWin))->privatePtr->yOff; - - aglSetInteger(togl->aglCtx, AGL_BUFFER_RECT, wrect); - aglEnable(togl->aglCtx, AGL_BUFFER_RECT); - aglUpdateContext(togl->aglCtx); -} -#endif - -/* - * Called when the widget's contents must be redrawn. Basically, we - * just call the user's render callback function. - * - * Note that the parameter type is ClientData so this function can be - * passed to Tk_DoWhenIdle(). - */ -static void -Togl_Render(ClientData clientData) -{ - Togl *togl = (Togl *) clientData; - - if (togl->DisplayProc) { - -#ifdef TOGL_AGL_CLASSIC - /* Mac is complicated here because OpenGL needs to know what part of - * the parent window to render into, and it seems that region need to - * be invalidated before drawing, so that QuickDraw will allow OpenGL - * to transfer pixels into that part of the window. I'm not even - * totally sure how or why this works as it does, since this aspect of - * Mac OpenGL seems to be totally undocumented. This was put together - * by trial and error! (thiessen) */ - MacRegion r; - RgnPtr rp = &r; - GrafPtr curPort, parentWin; - - parentWin = (GrafPtr) - (((MacDrawable *) (Tk_WindowId(togl->TkWin)))->toplevel-> - portPtr); - if (!parentWin) - return; -#endif - - Togl_MakeCurrent(togl); - -#ifdef TOGL_AGL_CLASSIC - /* Set QuickDraw port and clipping region */ - GetPort(&curPort); - SetPort(parentWin); - r.rgnBBox.left = ((TkWindow *) (togl->TkWin))->privatePtr->xOff; - r.rgnBBox.right = - r.rgnBBox.left + ((TkWindow *) (togl->TkWin))->changes.width - - 1; - r.rgnBBox.top = ((TkWindow *) (togl->TkWin))->privatePtr->yOff; - r.rgnBBox.bottom = - r.rgnBBox.top + ((TkWindow *) (togl->TkWin))->changes.height - - 1; - r.rgnSize = sizeof (Region); - InvalRgn(&rp); - SetClip(&rp); - /* this may seem an odd place to put this, with possibly redundant - * calls to aglSetInteger(AGL_BUFFER_RECT...), but for some reason - * performance is actually a lot better if this is called before every - * render... */ - SetMacBufRect(togl); -#endif - -#ifdef TOGL_AGL - SetMacBufRect(togl); -#endif - - togl->DisplayProc(togl); - -#ifdef TOGL_AGL_CLASSIC - SetPort(curPort); /* restore previous port */ -#endif - - } -#if defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - else { - /* Always need to update on resize */ - SetMacBufRect(togl); - } -#endif - togl->UpdatePending = False; -} - - -static void -RenderOverlay(ClientData clientData) -{ - Togl *togl = (Togl *) clientData; - - if (togl->OverlayFlag && togl->OverlayDisplayProc) { - -#if defined(TOGL_WGL) - int res = wglMakeCurrent(togl->tglGLHdc, togl->tglGLHglrc); - - assert(res == TRUE); - -#elif defined(TOGL_X11) - (void) glXMakeCurrent(Tk_Display(togl->TkWin), - togl->OverlayWindow, togl->OverlayCtx); -# if defined(__sgi) - if (togl->OldStereoFlag) - oldStereoMakeCurrent(Tk_Display(togl->TkWin), - togl->OverlayWindow, togl->OverlayCtx); - -# endif /*__sgi STEREO */ - -#endif /* TOGL_WGL */ - - togl->OverlayDisplayProc(togl); - } - togl->OverlayUpdatePending = False; -} - - -/* - * It's possible to change with this function or in a script some - * options like RGBA - ColorIndex ; Z-buffer and so on - */ -int -Togl_Configure(Tcl_Interp *interp, Togl *togl, - int argc, const char *argv[], int flags) -{ - Bool oldRgbaFlag = togl->RgbaFlag; - int oldRgbaRed = togl->RgbaRed; - int oldRgbaGreen = togl->RgbaGreen; - int oldRgbaBlue = togl->RgbaBlue; - Bool oldDoubleFlag = togl->DoubleFlag; - Bool oldDepthFlag = togl->DepthFlag; - int oldDepthSize = togl->DepthSize; - Bool oldAccumFlag = togl->AccumFlag; - int oldAccumRed = togl->AccumRed; - int oldAccumGreen = togl->AccumGreen; - int oldAccumBlue = togl->AccumBlue; - int oldAccumAlpha = togl->AccumAlpha; - Bool oldAlphaFlag = togl->AlphaFlag; - int oldAlphaSize = togl->AlphaSize; - Bool oldStencilFlag = togl->StencilFlag; - int oldStencilSize = togl->StencilSize; - int oldAuxNumber = togl->AuxNumber; - int oldWidth = togl->Width; - int oldHeight = togl->Height; - int oldSetGrid = togl->SetGrid; - - if (Tk_ConfigureWidget(interp, togl->TkWin, configSpecs, - argc, argv, WIDGREC togl, flags) == TCL_ERROR) { - return (TCL_ERROR); - } -#ifndef USE_OVERLAY - if (togl->OverlayFlag) { - TCL_ERR(interp, "Sorry, overlay was disabled"); - } -#endif - - - if (togl->Width != oldWidth || togl->Height != oldHeight - || togl->SetGrid != oldSetGrid) { - Togl_WorldChanged((ClientData) togl); - /* this added per Lou Arata */ - Tk_ResizeWindow(togl->TkWin, togl->Width, togl->Height); - - if (togl->ReshapeProc && -#if defined(TOGL_WGL) - togl->tglGLHglrc -#elif defined(TOGL_X11) - togl->GlCtx -#elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - togl->aglCtx -#endif - ) { - Togl_MakeCurrent(togl); - togl->ReshapeProc(togl); - } - } - - if (togl->RgbaFlag != oldRgbaFlag - || togl->RgbaRed != oldRgbaRed - || togl->RgbaGreen != oldRgbaGreen - || togl->RgbaBlue != oldRgbaBlue - || togl->DoubleFlag != oldDoubleFlag - || togl->DepthFlag != oldDepthFlag - || togl->DepthSize != oldDepthSize - || togl->AccumFlag != oldAccumFlag - || togl->AccumRed != oldAccumRed - || togl->AccumGreen != oldAccumGreen - || togl->AccumBlue != oldAccumBlue - || togl->AccumAlpha != oldAccumAlpha - || togl->AlphaFlag != oldAlphaFlag - || togl->AlphaSize != oldAlphaSize - || togl->StencilFlag != oldStencilFlag - || togl->StencilSize != oldStencilSize - || togl->AuxNumber != oldAuxNumber) { -#ifdef MESA_COLOR_HACK - free_default_color_cells(Tk_Display(togl->TkWin), - Tk_Colormap(togl->TkWin)); -#endif - } -#if defined(__sgi) - oldStereoInit(togl, togl->OldStereoFlag); -#endif - - return TCL_OK; -} - - -static int -Togl_Widget(ClientData clientData, Tcl_Interp *interp, int argc, - CONST84 char *argv[]) -{ - Togl *togl = (Togl *) clientData; - int result = TCL_OK; - Tcl_HashEntry *entry; - Tcl_HashSearch search; - Togl_CmdProc *cmd_proc; - - if (argc < 2) { - Tcl_AppendResult(interp, "wrong # args: should be \"", - argv[0], " ?options?\"", NULL); - return TCL_ERROR; - } - - Tk_Preserve((ClientData) togl); - - if (!strncmp(argv[1], "configure", MAX(1, strlen(argv[1])))) { - if (argc == 2) { - /* Return list of all configuration parameters */ - result = Tk_ConfigureInfo(interp, togl->TkWin, configSpecs, - WIDGREC togl, (char *) NULL, 0); - } else if (argc == 3) { - if (strcmp(argv[2], "-extensions") == 0) { - /* Return a list of OpenGL extensions available */ - const char *extensions; - - extensions = (const char *) glGetString(GL_EXTENSIONS); - Tcl_SetResult(interp, TCL_STUPID extensions, TCL_STATIC); - result = TCL_OK; - } else { - /* Return a specific configuration parameter */ - result = Tk_ConfigureInfo(interp, togl->TkWin, configSpecs, - WIDGREC togl, argv[2], 0); - } - } else { - /* Execute a configuration change */ - result = Togl_Configure(interp, togl, argc - 2, argv + 2, - TK_CONFIG_ARGV_ONLY); - } - } else if (!strncmp(argv[1], "render", MAX(1, strlen(argv[1])))) { - /* force the widget to be redrawn */ - Togl_Render((ClientData) togl); - } else if (!strncmp(argv[1], "swapbuffers", MAX(1, strlen(argv[1])))) { - /* force the widget to be redrawn */ - Togl_SwapBuffers(togl); - } else if (!strncmp(argv[1], "makecurrent", MAX(1, strlen(argv[1])))) { - /* force the widget to be redrawn */ - Togl_MakeCurrent(togl); - } -#if TOGL_USE_FONTS == 1 - else if (!strncmp(argv[1], "loadbitmapfont", MAX(1, strlen(argv[1])))) { - if (argc == 3) { - GLuint fontbase; - Tcl_Obj *fontbaseAsTclObject; - - fontbase = Togl_LoadBitmapFont(togl, argv[2]); - if (fontbase) { - fontbaseAsTclObject = Tcl_NewIntObj(fontbase); - Tcl_SetObjResult(interp, fontbaseAsTclObject); - result = TCL_OK; - } else { - Tcl_AppendResult(interp, "Could not allocate font", NULL); - result = TCL_ERROR; - } - } else { - Tcl_AppendResult(interp, "wrong # args", NULL); - result = TCL_ERROR; - } - } else if (!strncmp(argv[1], "unloadbitmapfont", MAX(1, strlen(argv[1])))) { - if (argc == 3) { - Togl_UnloadBitmapFont(togl, atoi(argv[2])); - result = TCL_OK; - } else { - Tcl_AppendResult(interp, "wrong # args", NULL); - result = TCL_ERROR; - } - } -#endif /* TOGL_USE_FONTS */ - else { - /* Probably a user-defined function */ - entry = Tcl_FindHashEntry(&CommandTable, argv[1]); - if (entry != NULL) { - cmd_proc = (Togl_CmdProc *) Tcl_GetHashValue(entry); - result = cmd_proc(togl, argc, argv); - } else { - Tcl_AppendResult(interp, "Togl: Unknown option: ", argv[1], "\n", - "Try: configure or render\n", - "or one of the user-defined commands:\n", NULL); - entry = Tcl_FirstHashEntry(&CommandTable, &search); - while (entry) { - Tcl_AppendResult(interp, " ", - Tcl_GetHashKey(&CommandTable, entry), "\n", NULL); - entry = Tcl_NextHashEntry(&search); - } - result = TCL_ERROR; - } - } - - Tk_Release((ClientData) togl); - return result; -} - - - -/* - * Togl_Cmd - * - * Called when Togl is executed - creation of a Togl widget. - * * Creates a new window - * * Creates an 'Togl' data structure - * * Creates an event handler for this window - * * Creates a command that handles this object - * * Configures this Togl for the given arguments - */ -static int -Togl_Cmd(ClientData clientData, Tcl_Interp *interp, int argc, - CONST84 char **argv) -{ - const char *name; - Tk_Window mainwin = (Tk_Window) clientData; - Tk_Window tkwin; - Togl *togl; - - if (argc <= 1) { - TCL_ERR(interp, "wrong # args: should be \"pathName read filename\""); - } - - /* Create the window. */ - name = argv[1]; - tkwin = Tk_CreateWindowFromPath(interp, mainwin, name, (char *) NULL); - if (tkwin == NULL) { - return TCL_ERROR; - } - - Tk_SetClass(tkwin, "Togl"); - - /* Create Togl data structure */ - togl = (Togl *) malloc(sizeof (Togl)); - if (!togl) { - return TCL_ERROR; - } - - togl->Next = NULL; -#if defined(TOGL_WGL) - togl->tglGLHdc = NULL; - togl->tglGLHglrc = NULL; -#elif defined(TOGL_X11) - togl->GlCtx = NULL; - togl->OverlayCtx = NULL; -#elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - togl->aglCtx = NULL; -#endif /* TOGL_WGL */ - togl->display = Tk_Display(tkwin); - togl->TkWin = tkwin; - togl->Interp = interp; -#ifndef NO_TK_CURSOR - togl->Cursor = None; -#endif - togl->Width = 0; - togl->Height = 0; - togl->SetGrid = 0; - togl->TimerInterval = 0; - togl->RgbaFlag = True; - togl->RgbaRed = 1; - togl->RgbaGreen = 1; - togl->RgbaBlue = 1; - togl->DoubleFlag = False; - togl->DepthFlag = False; - togl->DepthSize = 1; - togl->AccumFlag = False; - togl->AccumRed = 1; - togl->AccumGreen = 1; - togl->AccumBlue = 1; - togl->AccumAlpha = 1; - togl->AlphaFlag = False; - togl->AlphaSize = 1; - togl->StencilFlag = False; - togl->StencilSize = 1; - togl->OverlayFlag = False; - togl->StereoFlag = False; -#ifdef __sgi - togl->OldStereoFlag = False; -#endif - togl->AuxNumber = 0; - togl->Indirect = False; - togl->PixelFormat = 0; - togl->UpdatePending = False; - togl->OverlayUpdatePending = False; - togl->CreateProc = DefaultCreateProc; - togl->DisplayProc = DefaultDisplayProc; - togl->ReshapeProc = DefaultReshapeProc; - togl->DestroyProc = DefaultDestroyProc; - togl->TimerProc = DefaultTimerProc; - togl->OverlayDisplayProc = DefaultOverlayDisplayProc; - togl->ShareList = NULL; - togl->ShareContext = NULL; - togl->Ident = NULL; - togl->Client_Data = DefaultClientData; - - /* for EPS Output */ - togl->EpsRedMap = togl->EpsGreenMap = togl->EpsBlueMap = NULL; - togl->EpsMapSize = 0; - - /* Create command event handler */ - togl->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(tkwin), - Togl_Widget, (ClientData) togl, - (Tcl_CmdDeleteProc *) ToglCmdDeletedProc); - /* - * Setup the Tk_ClassProcs callbacks to point at our own window creation - * function - * - * We need to check at runtime if we should use the new Tk_SetClassProcs() - * API or if we need to modify the window structure directly */ - - -#ifdef HAVE_TK_SETCLASSPROCS - - if (SetClassProcsPtr != NULL) { /* use public API (Tk 8.4+) */ - Tk_ClassProcs *procsPtr; - - procsPtr = (Tk_ClassProcs *) Tcl_Alloc(sizeof (Tk_ClassProcs)); - procsPtr->size = sizeof (Tk_ClassProcs); - procsPtr->createProc = Togl_CreateWindow; - procsPtr->worldChangedProc = Togl_WorldChanged; - procsPtr->modalProc = NULL; - /* Tk_SetClassProcs(togl->TkWin,procsPtr,(ClientData)togl); */ - (SetClassProcsPtr) (togl->TkWin, procsPtr, (ClientData) togl); - } else -#endif - { /* use private API */ - /* - * We need to set these fields in the Tk_FakeWin structure: dummy17 = - * classProcsPtr dummy18 = instanceData */ - TkClassProcs *procsPtr; - Tk_FakeWin *winPtr = (Tk_FakeWin *) (togl->TkWin); - - procsPtr = (TkClassProcs *) Tcl_Alloc(sizeof (TkClassProcs)); - procsPtr->createProc = Togl_CreateWindow; - procsPtr->geometryProc = Togl_WorldChanged; - procsPtr->modalProc = NULL; - winPtr->dummy17 = (char *) procsPtr; - winPtr->dummy18 = (ClientData) togl; - } - - Tk_CreateEventHandler(tkwin, - ExposureMask | StructureNotifyMask, Togl_EventProc, - (ClientData) togl); - - /* Configure Togl widget */ - if (Togl_Configure(interp, togl, argc - 2, argv + 2, 0) == TCL_ERROR) { - Tk_DestroyWindow(tkwin); - Tcl_AppendResult(interp, "Couldn't configure togl widget\n", NULL); - goto error; - } - - /* - * If OpenGL window wasn't already created by Togl_Configure() we - * create it now. We can tell by checking if the GLX context has - * been initialized. - */ - if (! -#if defined(TOGL_WGL) - togl->tglGLHdc -#elif defined(TOGL_X11) - togl->GlCtx -#elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - togl->aglCtx -#endif - ) { - Tk_MakeWindowExist(togl->TkWin); - if (Tk_WindowId(togl->TkWin) == DUMMY_WINDOW) { - return TCL_ERROR; - } - Togl_MakeCurrent(togl); - } - - /* If defined, call create callback */ - if (togl->CreateProc) { - togl->CreateProc(togl); - } - - /* If defined, call reshape proc */ - if (togl->ReshapeProc) { - togl->ReshapeProc(togl); - } - - /* If defined, setup timer */ - if (togl->TimerProc) { - (void) Tk_CreateTimerHandler(togl->TimerInterval, Togl_Timer, - (ClientData) togl); - } - - Tcl_AppendResult(interp, Tk_PathName(tkwin), NULL); - - /* Add to linked list */ - AddToList(togl); - - return TCL_OK; - - error: - (void) Tcl_DeleteCommand(interp, "togl"); - /* free(togl); Don't free it, if we do a crash occurs later... */ - return TCL_ERROR; -} - - -#ifdef USE_OVERLAY - -/* - * Do all the setup for overlay planes - * Return: TCL_OK or TCL_ERROR - */ -static int -SetupOverlay(Togl *togl) -{ -# if defined(TOGL_X11) - -# ifdef GLX_TRANSPARENT_TYPE_EXT - static int ovAttributeList[] = { - GLX_BUFFER_SIZE, 2, - GLX_LEVEL, 1, - GLX_TRANSPARENT_TYPE_EXT, GLX_TRANSPARENT_INDEX_EXT, - None - }; -# else - static int ovAttributeList[] = { - GLX_BUFFER_SIZE, 2, - GLX_LEVEL, 1, - None - }; -# endif - - Display *dpy; - XVisualInfo *visinfo; - TkWindow *winPtr = (TkWindow *) togl->TkWin; - - XSetWindowAttributes swa; - Tcl_HashEntry *hPtr; - int new_flag; - - dpy = Tk_Display(togl->TkWin); - - visinfo = glXChooseVisual(dpy, Tk_ScreenNumber(winPtr), ovAttributeList); - if (!visinfo) { - Tcl_AppendResult(togl->Interp, Tk_PathName(winPtr), - ": No suitable overlay index visual available", (char *) NULL); - togl->OverlayCtx = 0; - togl->OverlayWindow = 0; - togl->OverlayCmap = 0; - return TCL_ERROR; - } -# ifdef GLX_TRANSPARENT_INDEX_EXT - { - int fail = - glXGetConfig(dpy, visinfo, GLX_TRANSPARENT_INDEX_VALUE_EXT, - &togl->OverlayTransparentPixel); - - if (fail) - togl->OverlayTransparentPixel = 0; /* maybe, maybe ... */ - } -# else - togl->OverlayTransparentPixel = 0; /* maybe, maybe ... */ -# endif - - /* share display lists with normal layer context */ - togl->OverlayCtx = - glXCreateContext(dpy, visinfo, togl->GlCtx, !togl->Indirect); - - swa.colormap = XCreateColormap(dpy, XRootWindow(dpy, visinfo->screen), - visinfo->visual, AllocNone); - togl->OverlayCmap = swa.colormap; - - swa.border_pixel = 0; - swa.event_mask = ALL_EVENTS_MASK; - togl->OverlayWindow = XCreateWindow(dpy, Tk_WindowId(togl->TkWin), 0, 0, - togl->Width, togl->Height, 0, - visinfo->depth, InputOutput, - visinfo->visual, CWBorderPixel | CWColormap | CWEventMask, &swa); - - hPtr = Tcl_CreateHashEntry(&winPtr->dispPtr->winTable, - (char *) togl->OverlayWindow, &new_flag); - Tcl_SetHashValue(hPtr, winPtr); - - /* XMapWindow( dpy, togl->OverlayWindow ); */ - togl->OverlayIsMapped = False; - - /* Make sure window manager installs our colormap */ - XSetWMColormapWindows(dpy, togl->OverlayWindow, &togl->OverlayWindow, 1); - - return TCL_OK; - -# elif defined(TOGL_WGL) || defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - /* not yet implemented on these */ - return TCL_ERROR; -# endif -} - -#endif /* USE_OVERLAY */ - - - -#ifdef TOGL_WGL -# define TOGL_CLASS_NAME "Togl Class" -static Bool ToglClassInitialized = False; - -static LRESULT CALLBACK -Win32WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - LONG result; - Togl *togl = (Togl *) GetWindowLong(hwnd, 0); - WNDCLASS childClass; - - switch (message) { - case WM_WINDOWPOSCHANGED: - /* Should be processed by DefWindowProc, otherwise a double buffered - * context is not properly resized when the corresponding window is - * resized. */ - break; - case WM_DESTROY: - if (togl->tglGLHglrc) { - wglDeleteContext(togl->tglGLHglrc); - } - if (togl->tglGLHdc) { - ReleaseDC(hwnd, togl->tglGLHdc); - } - free(togl); - break; - default: -# if USE_STATIC_LIB - return TkWinChildProc(hwnd, message, wParam, lParam); -# else - /* - * OK, since TkWinChildProc is not explicitly exported in the - * dynamic libraries, we have to retrieve it from the class info - * registered with windows. - * - */ - if (tkWinChildProc == NULL) { - GetClassInfo(Tk_GetHINSTANCE(), TK_WIN_CHILD_CLASS_NAME, - &childClass); - tkWinChildProc = childClass.lpfnWndProc; - } - return tkWinChildProc(hwnd, message, wParam, lParam); -# endif - } - result = DefWindowProc(hwnd, message, wParam, lParam); - Tcl_ServiceAll(); - return result; -} -#endif /* TOGL_WGL */ - - - -/* - * Togl_CreateWindow - * - * Window creation function, invoked as a callback from Tk_MakeWindowExist. - * Creates an OpenGL window for the Togl widget. - */ -static Window -Togl_CreateWindow(Tk_Window tkwin, Window parent, ClientData instanceData) -{ - - Togl *togl = (Togl *) instanceData; - XVisualInfo *visinfo = NULL; - Display *dpy; - Colormap cmap; - int scrnum; - Window window; - -#if defined(TOGL_X11) - Bool directCtx = True; - int attrib_list[1000]; - int attrib_count; - int dummy; - XSetWindowAttributes swa; - -# define MAX_ATTEMPTS 12 - static int ci_depths[MAX_ATTEMPTS] = { - 8, 4, 2, 1, 12, 16, 8, 4, 2, 1, 12, 16 - }; - static int dbl_flags[MAX_ATTEMPTS] = { - 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1 - }; -#elif defined(TOGL_WGL) - HWND hwnd, parentWin; - int pixelformat; - HANDLE hInstance; - WNDCLASS ToglClass; - PIXELFORMATDESCRIPTOR pfd; - XVisualInfo VisInf; -#elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - GLint attribs[20]; - int na; - AGLPixelFormat fmt; - XVisualInfo VisInf; -#endif /* TOGL_X11 */ - - - dpy = Tk_Display(togl->TkWin); - -#if defined(TOGL_X11) - /* Make sure OpenGL's GLX extension supported */ - if (!glXQueryExtension(dpy, &dummy, &dummy)) { - Tcl_SetResult(togl->Interp, - TCL_STUPID "Togl: X server has no OpenGL GLX extension", - TCL_STATIC); - return DUMMY_WINDOW; - } - - if (togl->ShareContext && FindTogl(togl->ShareContext)) { - /* share OpenGL context with existing Togl widget */ - Togl *shareWith = FindTogl(togl->ShareContext); - - assert(shareWith != NULL); - assert(shareWith->GlCtx != NULL); - togl->GlCtx = shareWith->GlCtx; - togl->VisInfo = shareWith->VisInfo; - visinfo = togl->VisInfo; - } else { - if (togl->PixelFormat) { - XVisualInfo template; - int count = 1; - - template.visualid = togl->PixelFormat; - visinfo = XGetVisualInfo(dpy, VisualIDMask, &template, &count); - if (visinfo == NULL) { - Tcl_SetResult(togl->Interp, - TCL_STUPID "Togl: couldn't choose pixel format", - TCL_STATIC); - - return DUMMY_WINDOW; - } - /* fill in flags normally passed in that affect behavior */ - (void) glXGetConfig(dpy, visinfo, GLX_RGBA, &togl->RgbaFlag); - (void) glXGetConfig(dpy, visinfo, GLX_DOUBLEBUFFER, - &togl->DoubleFlag); - (void) glXGetConfig(dpy, visinfo, GLX_STEREO, &togl->StereoFlag); - } else { - int attempt; - - /* It may take a few tries to get a visual */ - for (attempt = 0; attempt < MAX_ATTEMPTS; attempt++) { - attrib_count = 0; - attrib_list[attrib_count++] = GLX_USE_GL; - if (togl->RgbaFlag) { - /* RGB[A] mode */ - attrib_list[attrib_count++] = GLX_RGBA; - attrib_list[attrib_count++] = GLX_RED_SIZE; - attrib_list[attrib_count++] = togl->RgbaRed; - attrib_list[attrib_count++] = GLX_GREEN_SIZE; - attrib_list[attrib_count++] = togl->RgbaGreen; - attrib_list[attrib_count++] = GLX_BLUE_SIZE; - attrib_list[attrib_count++] = togl->RgbaBlue; - if (togl->AlphaFlag) { - attrib_list[attrib_count++] = GLX_ALPHA_SIZE; - attrib_list[attrib_count++] = togl->AlphaSize; - } - - /* for EPS Output */ - if (togl->EpsRedMap) - free(togl->EpsRedMap); - if (togl->EpsGreenMap) - free(togl->EpsGreenMap); - if (togl->EpsBlueMap) - free(togl->EpsBlueMap); - togl->EpsRedMap = togl->EpsGreenMap = togl->EpsBlueMap = - NULL; - togl->EpsMapSize = 0; - } else { - /* Color index mode */ - int depth; - - attrib_list[attrib_count++] = GLX_BUFFER_SIZE; - depth = ci_depths[attempt]; - attrib_list[attrib_count++] = depth; - } - if (togl->DepthFlag) { - attrib_list[attrib_count++] = GLX_DEPTH_SIZE; - attrib_list[attrib_count++] = togl->DepthSize; - } - if (togl->DoubleFlag || dbl_flags[attempt]) { - attrib_list[attrib_count++] = GLX_DOUBLEBUFFER; - } - if (togl->StencilFlag) { - attrib_list[attrib_count++] = GLX_STENCIL_SIZE; - attrib_list[attrib_count++] = togl->StencilSize; - } - if (togl->AccumFlag) { - attrib_list[attrib_count++] = GLX_ACCUM_RED_SIZE; - attrib_list[attrib_count++] = togl->AccumRed; - attrib_list[attrib_count++] = GLX_ACCUM_GREEN_SIZE; - attrib_list[attrib_count++] = togl->AccumGreen; - attrib_list[attrib_count++] = GLX_ACCUM_BLUE_SIZE; - attrib_list[attrib_count++] = togl->AccumBlue; - if (togl->AlphaFlag) { - attrib_list[attrib_count++] = GLX_ACCUM_ALPHA_SIZE; - attrib_list[attrib_count++] = togl->AccumAlpha; - } - } - if (togl->AuxNumber != 0) { - attrib_list[attrib_count++] = GLX_AUX_BUFFERS; - attrib_list[attrib_count++] = togl->AuxNumber; - } - if (togl->Indirect) { - directCtx = False; - } - - if (togl->StereoFlag) { - attrib_list[attrib_count++] = GLX_STEREO; - } - attrib_list[attrib_count++] = None; - - visinfo = glXChooseVisual(dpy, Tk_ScreenNumber(togl->TkWin), - attrib_list); - if (visinfo) { - /* found a GLX visual! */ - break; - } - } - - togl->VisInfo = visinfo; - - if (visinfo == NULL) { - Tcl_SetResult(togl->Interp, - TCL_STUPID "Togl: couldn't get visual", TCL_STATIC); - return DUMMY_WINDOW; - } - - /* - * Create a new OpenGL rendering context. - */ - if (togl->ShareList) { - /* share display lists with existing togl widget */ - Togl *shareWith = FindTogl(togl->ShareList); - GLXContext shareCtx; - - if (shareWith) - shareCtx = shareWith->GlCtx; - else - shareCtx = None; - togl->GlCtx = - glXCreateContext(dpy, visinfo, shareCtx, directCtx); - } else { - /* don't share display lists */ - togl->GlCtx = glXCreateContext(dpy, visinfo, None, directCtx); - } - - if (togl->GlCtx == NULL) { - Tcl_SetResult(togl->Interp, - TCL_STUPID "could not create rendering context", - TCL_STATIC); - return DUMMY_WINDOW; - } - - } - } - - -#endif /* TOGL_X11 */ - -#ifdef TOGL_WGL - parentWin = Tk_GetHWND(parent); - hInstance = Tk_GetHINSTANCE(); - if (!ToglClassInitialized) { - ToglClassInitialized = True; - ToglClass.style = CS_HREDRAW | CS_VREDRAW; - ToglClass.cbClsExtra = 0; - ToglClass.cbWndExtra = 4; /* to save struct Togl* */ - ToglClass.hInstance = hInstance; - ToglClass.hbrBackground = NULL; - ToglClass.lpszMenuName = NULL; - ToglClass.lpszClassName = TOGL_CLASS_NAME; - ToglClass.lpfnWndProc = Win32WinProc; - ToglClass.hIcon = NULL; - ToglClass.hCursor = NULL; - if (!RegisterClass(&ToglClass)) { - Tcl_SetResult(togl->Interp, - TCL_STUPID "unable register Togl window class", TCL_STATIC); - return DUMMY_WINDOW; - } - } - - hwnd = CreateWindow(TOGL_CLASS_NAME, NULL, - WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, - togl->Width, togl->Height, parentWin, NULL, hInstance, NULL); - SetWindowLong(hwnd, 0, (LONG) togl); - SetWindowPos(hwnd, HWND_TOP, 0, 0, 0, 0, - SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE); - - togl->tglGLHdc = GetDC(hwnd); - - pfd.nSize = sizeof (PIXELFORMATDESCRIPTOR); - pfd.nVersion = 1; - pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL; - if (togl->DoubleFlag) { - pfd.dwFlags |= PFD_DOUBLEBUFFER; - } - /* The stereo flag is not supported in the current generic OpenGL - * implementation, but may be supported by specific hardware devices. */ - if (togl->StereoFlag) { - pfd.dwFlags |= PFD_STEREO; - } - - if (togl->PixelFormat) { - pixelformat = togl->PixelFormat; - } else { - pfd.cColorBits = togl->RgbaRed + togl->RgbaGreen + togl->RgbaBlue; - pfd.iPixelType = togl->RgbaFlag ? PFD_TYPE_RGBA : PFD_TYPE_COLORINDEX; - /* Alpha bitplanes are not supported in the current generic OpenGL - * implementation, but may be supported by specific hardware devices. */ - pfd.cAlphaBits = togl->AlphaFlag ? togl->AlphaSize : 0; - pfd.cAccumBits = togl->AccumFlag ? (togl->AccumRed + togl->AccumGreen + - togl->AccumBlue + togl->AccumAlpha) : 0; - pfd.cDepthBits = togl->DepthFlag ? togl->DepthSize : 0; - pfd.cStencilBits = togl->StencilFlag ? togl->StencilSize : 0; - /* Auxiliary buffers are not supported in the current generic OpenGL - * implementation, but may be supported by specific hardware devices. */ - pfd.cAuxBuffers = togl->AuxNumber; - pfd.iLayerType = PFD_MAIN_PLANE; - - if ((pixelformat = ChoosePixelFormat(togl->tglGLHdc, &pfd)) == 0) { - Tcl_SetResult(togl->Interp, - TCL_STUPID "Togl: couldn't choose pixel format", - TCL_STATIC); - return DUMMY_WINDOW; - } - } - if (SetPixelFormat(togl->tglGLHdc, pixelformat, &pfd) == FALSE) { - Tcl_SetResult(togl->Interp, - TCL_STUPID "Togl: couldn't choose pixel format", TCL_STATIC); - return DUMMY_WINDOW; - } - - /* Get the actual pixel format */ - DescribePixelFormat(togl->tglGLHdc, pixelformat, sizeof (pfd), &pfd); - if (togl->PixelFormat) { - /* fill in flags normally passed in that affect behavior */ - togl->RgbaFlag = pfd.iPixelType == PFD_TYPE_RGBA; - togl->DoubleFlag = pfd.cDepthBits > 0; - togl->StereoFlag = (pfd.dwFlags & PFD_STEREO) != 0; - // TODO: set depth flag, and more - } else if (togl->StereoFlag && (pfd.dwFlags & PFD_STEREO) == 0) { - Tcl_SetResult(togl->Interp, - TCL_STUPID "Togl: couldn't choose stereo pixel format", - TCL_STATIC); - return DUMMY_WINDOW; - } - - if (togl->ShareContext && FindTogl(togl->ShareContext)) { - /* share OpenGL context with existing Togl widget */ - Togl *shareWith = FindTogl(togl->ShareContext); - - assert(shareWith); - assert(shareWith->tglGLHglrc); - togl->tglGLHglrc = shareWith->tglGLHglrc; - togl->VisInfo = shareWith->VisInfo; - visinfo = togl->VisInfo; - } else { - /* - * Create a new OpenGL rendering context. And check to share lists. - */ - togl->tglGLHglrc = wglCreateContext(togl->tglGLHdc); - - if (togl->ShareList) { - /* share display lists with existing togl widget */ - Togl *shareWith = FindTogl(togl->ShareList); - - if (shareWith) - wglShareLists(shareWith->tglGLHglrc, togl->tglGLHglrc); - } - - if (!togl->tglGLHglrc) { - Tcl_SetResult(togl->Interp, - TCL_STUPID "could not create rendering context", - TCL_STATIC); - return DUMMY_WINDOW; - } - - /* Just for portability, define the simplest visinfo */ - visinfo = &VisInf; - visinfo->visual = DefaultVisual(dpy, DefaultScreen(dpy)); - visinfo->depth = visinfo->visual->bits_per_rgb; - togl->VisInfo = visinfo; - } - -#endif /* TOGL_WGL */ - - - /* - * find a colormap - */ - scrnum = Tk_ScreenNumber(togl->TkWin); - if (togl->RgbaFlag) { - /* Colormap for RGB mode */ -#if defined(TOGL_X11) - cmap = get_rgb_colormap(dpy, scrnum, visinfo, togl->TkWin); - -#elif defined(TOGL_WGL) - if (pfd.dwFlags & PFD_NEED_PALETTE) { - cmap = Win32CreateRgbColormap(pfd); - } else { - cmap = DefaultColormap(dpy, scrnum); - } - /* for EPS Output */ - if (togl->EpsRedMap) - free(togl->EpsRedMap); - if (togl->EpsGreenMap) - free(togl->EpsGreenMap); - if (togl->EpsBlueMap) - free(togl->EpsBlueMap); - togl->EpsRedMap = togl->EpsGreenMap = togl->EpsBlueMap = NULL; - togl->EpsMapSize = 0; - -#elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - cmap = DefaultColormap(dpy, scrnum); - /* for EPS Output */ - if (togl->EpsRedMap) - free(togl->EpsRedMap); - if (togl->EpsGreenMap) - free(togl->EpsGreenMap); - if (togl->EpsBlueMap) - free(togl->EpsBlueMap); - togl->EpsRedMap = togl->EpsGreenMap = togl->EpsBlueMap = NULL; - togl->EpsMapSize = 0; -#endif /* TOGL_X11 */ - } else { - /* Colormap for CI mode */ -#ifdef TOGL_WGL - togl->CiColormapSize = 1 << pfd.cColorBits; - togl->CiColormapSize = togl->CiColormapSize < MAX_CI_COLORMAP_SIZE ? - togl->CiColormapSize : MAX_CI_COLORMAP_SIZE; - -#endif /* TOGL_WGL */ - if (togl->PrivateCmapFlag) { - /* need read/write colormap so user can store own color entries */ -#if defined(TOGL_X11) - cmap = XCreateColormap(dpy, XRootWindow(dpy, visinfo->screen), - visinfo->visual, AllocAll); -#elif defined(TOGL_WGL) - cmap = Win32CreateCiColormap(togl); -#elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - /* need to figure out how to do this correctly on Mac... */ - cmap = DefaultColormap(dpy, scrnum); -#endif /* TOGL_X11 */ - } else { - if (visinfo->visual == DefaultVisual(dpy, scrnum)) { - /* share default/root colormap */ - cmap = Tk_Colormap(togl->TkWin); - } else { - /* make a new read-only colormap */ - cmap = XCreateColormap(dpy, XRootWindow(dpy, visinfo->screen), - visinfo->visual, AllocNone); - } - } - } - -#if !defined(TOGL_AGL) - /* Make sure Tk knows to switch to the new colormap when the cursor is over - * this window when running in color index mode. */ - (void) Tk_SetWindowVisual(togl->TkWin, visinfo->visual, visinfo->depth, - cmap); -#endif - -#ifdef TOGL_WGL - /* Install the colormap */ - SelectPalette(togl->tglGLHdc, ((TkWinColormap *) cmap)->palette, TRUE); - RealizePalette(togl->tglGLHdc); -#endif /* TOGL_WGL */ - -#if defined(TOGL_X11) - swa.colormap = cmap; - swa.border_pixel = 0; - swa.event_mask = ALL_EVENTS_MASK; - window = XCreateWindow(dpy, parent, - 0, 0, togl->Width, togl->Height, - 0, visinfo->depth, - InputOutput, visinfo->visual, - CWBorderPixel | CWColormap | CWEventMask, &swa); - /* Make sure window manager installs our colormap */ - (void) XSetWMColormapWindows(dpy, window, &window, 1); - -#elif defined(TOGL_WGL) - window = Tk_AttachHWND(togl->TkWin, hwnd); - -#elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - { - TkWindow *winPtr = (TkWindow *) togl->TkWin; - - window = TkpMakeWindow(winPtr, parent); - } -#endif /* TOGL_X11 */ - -#ifdef USE_OVERLAY - if (togl->OverlayFlag) { - if (SetupOverlay(togl) == TCL_ERROR) { - fprintf(stderr, "Warning: couldn't setup overlay.\n"); - togl->OverlayFlag = False; - } - } -#endif /* USE_OVERLAY */ - - /* Request the X window to be displayed */ - (void) XMapWindow(dpy, window); - -#if defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - if (togl->ShareContext && FindTogl(togl->ShareContext)) { - /* share OpenGL context with existing Togl widget */ - Togl *shareWith = FindTogl(togl->ShareContext); - - assert(shareWith); - assert(shareWith->aglCtx); - togl->aglCtx = shareWith->aglCtx; - togl->VisInfo = shareWith->VisInfo; - visinfo = togl->VisInfo; - - } else { - AGLContext shareCtx = NULL; - - if (togl->PixelFormat) { - /* fill in RgbaFlag, DoubleFlag, and StereoFlag */ - fmt = (AGLPixelFormat) togl->PixelFormat; - GLint has_rgba, has_doublebuf, has_stereo; - - if (aglDescribePixelFormat(fmt, AGL_RGBA, &has_rgba) && - aglDescribePixelFormat(fmt, AGL_DOUBLEBUFFER, - &has_doublebuf) - && aglDescribePixelFormat(fmt, AGL_STEREO, &has_stereo)) { - togl->RgbaFlag = (has_rgba ? True : False); - togl->DoubleFlag = (has_doublebuf ? True : False); - togl->StereoFlag = (has_stereo ? True : False); - } else { - Tcl_SetResult(togl->Interp, - TCL_STUPID - "Togl: failed querying pixel format attributes", - TCL_STATIC); - return DUMMY_WINDOW; - } - } else { - - /* Need to do this after mapping window, so MacDrawable structure - * is more completely filled in */ - na = 0; - attribs[na++] = AGL_MINIMUM_POLICY; - attribs[na++] = AGL_ROBUST; - if (togl->RgbaFlag) { - /* RGB[A] mode */ - attribs[na++] = AGL_RGBA; - attribs[na++] = AGL_RED_SIZE; - attribs[na++] = togl->RgbaRed; - attribs[na++] = AGL_GREEN_SIZE; - attribs[na++] = togl->RgbaGreen; - attribs[na++] = AGL_BLUE_SIZE; - attribs[na++] = togl->RgbaBlue; - if (togl->AlphaFlag) { - attribs[na++] = AGL_ALPHA_SIZE; - attribs[na++] = togl->AlphaSize; - } - } else { - /* Color index mode */ - attribs[na++] = AGL_BUFFER_SIZE; - attribs[na++] = 8; - } - if (togl->DepthFlag) { - attribs[na++] = AGL_DEPTH_SIZE; - attribs[na++] = togl->DepthSize; - } - if (togl->DoubleFlag) { - attribs[na++] = AGL_DOUBLEBUFFER; - } - if (togl->StencilFlag) { - attribs[na++] = AGL_STENCIL_SIZE; - attribs[na++] = togl->StencilSize; - } - if (togl->AccumFlag) { - attribs[na++] = AGL_ACCUM_RED_SIZE; - attribs[na++] = togl->AccumRed; - attribs[na++] = AGL_ACCUM_GREEN_SIZE; - attribs[na++] = togl->AccumGreen; - attribs[na++] = AGL_ACCUM_BLUE_SIZE; - attribs[na++] = togl->AccumBlue; - if (togl->AlphaFlag) { - attribs[na++] = AGL_ACCUM_ALPHA_SIZE; - attribs[na++] = togl->AccumAlpha; - } - } - if (togl->AuxNumber != 0) { - attribs[na++] = AGL_AUX_BUFFERS; - attribs[na++] = togl->AuxNumber; - } - attribs[na++] = AGL_NONE; - - if ((fmt = aglChoosePixelFormat(NULL, 0, attribs)) == NULL) { - Tcl_SetResult(togl->Interp, - TCL_STUPID "Togl: couldn't choose pixel format", - TCL_STATIC); - return DUMMY_WINDOW; - } - } - - /* - * Check whether to share lists. - */ - if (togl->ShareList) { - /* share display lists with existing togl widget */ - Togl *shareWith = FindTogl(togl->ShareList); - - if (shareWith) - shareCtx = shareWith->aglCtx; - } - if ((togl->aglCtx = aglCreateContext(fmt, shareCtx)) == NULL) { - GLenum err = aglGetError(); - - aglDestroyPixelFormat(fmt); - if (err == AGL_BAD_MATCH) - Tcl_SetResult(togl->Interp, - TCL_STUPID - "Togl: couldn't create context, shared context doesn't match", - TCL_STATIC); - else if (err == AGL_BAD_CONTEXT) - Tcl_SetResult(togl->Interp, - TCL_STUPID - "Togl: couldn't create context, bad shared context", - TCL_STATIC); - else if (err == AGL_BAD_PIXELFMT) - Tcl_SetResult(togl->Interp, - TCL_STUPID - "Togl: couldn't create context, bad pixel format", - TCL_STATIC); - else - Tcl_SetResult(togl->Interp, - TCL_STUPID - "Togl: couldn't create context, unknown reason", - TCL_STATIC); - return DUMMY_WINDOW; - } - - aglDestroyPixelFormat(fmt); - if (!aglSetDrawable(togl->aglCtx, -# if defined(TOGL_AGL) - ((MacDrawable *) (window))->toplevel->grafPtr -# else - ((MacDrawable *) (window))->toplevel->portPtr -# endif - )) { - aglDestroyContext(togl->aglCtx); - Tcl_SetResult(togl->Interp, - TCL_STUPID "Togl: couldn't set drawable", TCL_STATIC); - return DUMMY_WINDOW; - } - - /* Just for portability, define the simplest visinfo */ - visinfo = &VisInf; - visinfo->visual = DefaultVisual(dpy, DefaultScreen(dpy)); - visinfo->depth = visinfo->visual->bits_per_rgb; - - Tk_SetWindowVisual(togl->TkWin, visinfo->visual, visinfo->depth, cmap); - } -#endif /* TOGL_AGL_CLASSIC || TOGL_AGL */ - -#if defined(TOGL_X11) - /* Check for a single/double buffering snafu */ - { - int dbl_flag; - - if (glXGetConfig(dpy, visinfo, GLX_DOUBLEBUFFER, &dbl_flag)) { - if (!togl->DoubleFlag && dbl_flag) { - /* We requested single buffering but had to accept a */ - /* double buffered visual. Set the GL draw buffer to */ - /* be the front buffer to simulate single buffering. */ - glDrawBuffer(GL_FRONT); - } - } - } -#endif /* TOGL_X11 */ - - /* for EPS Output */ - if (!togl->RgbaFlag) { - int index_size; - -#if defined(TOGL_X11) || defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - GLint index_bits; - - glGetIntegerv(GL_INDEX_BITS, &index_bits); - index_size = 1 << index_bits; -#elif defined(TOGL_WGL) - index_size = togl->CiColormapSize; -#endif /* TOGL_X11 */ - if (togl->EpsMapSize != index_size) { - if (togl->EpsRedMap) - free(togl->EpsRedMap); - if (togl->EpsGreenMap) - free(togl->EpsGreenMap); - if (togl->EpsBlueMap) - free(togl->EpsBlueMap); - togl->EpsMapSize = index_size; - togl->EpsRedMap = (GLfloat *) calloc(index_size, sizeof (GLfloat)); - togl->EpsGreenMap = - (GLfloat *) calloc(index_size, sizeof (GLfloat)); - togl->EpsBlueMap = (GLfloat *) calloc(index_size, sizeof (GLfloat)); - } - } - - return window; -} - -/* - * Togl_WorldChanged - * - * Add support for setgrid option. - */ -static void -Togl_WorldChanged(ClientData instanceData) -{ - Togl *togl = (Togl *) instanceData; - - Tk_GeometryRequest(togl->TkWin, togl->Width, togl->Height); - Tk_SetInternalBorder(togl->TkWin, 0); - if (togl->SetGrid > 0) { - Tk_SetGrid(togl->TkWin, togl->Width / togl->SetGrid, - togl->Height / togl->SetGrid, togl->SetGrid, togl->SetGrid); - } else { - Tk_UnsetGrid(togl->TkWin); - } -} - -/* - * ToglCmdDeletedProc - * - * This procedure is invoked when a widget command is deleted. If - * the widget isn't already in the process of being destroyed, - * this command destroys it. - * - * Results: - * None. - * - * Side effects: - * The widget is destroyed. - * - *---------------------------------------------------------------------- - */ -static void -ToglCmdDeletedProc(ClientData clientData) -{ - Togl *togl = (Togl *) clientData; - Tk_Window tkwin = togl->TkWin; - - /* - * This procedure could be invoked either because the window was - * destroyed and the command was then deleted (in which case tkwin - * is NULL) or because the command was deleted, and then this procedure - * destroys the widget. - */ - - if (togl && tkwin) { - Tk_DeleteEventHandler(tkwin, - ExposureMask | StructureNotifyMask, - Togl_EventProc, (ClientData) togl); - } -#if defined(TOGL_X11) - if (togl->GlCtx) { - if (FindToglWithSameContext(togl) == NULL) - glXDestroyContext(togl->display, togl->GlCtx); - togl->GlCtx = NULL; - } -# ifdef USE_OVERLAY - if (togl->OverlayCtx) { - Tcl_HashEntry *entryPtr; - TkWindow *winPtr = (TkWindow *) togl->TkWin; - - if (winPtr) { - entryPtr = Tcl_FindHashEntry(&winPtr->dispPtr->winTable, - (char *) togl->OverlayWindow); - Tcl_DeleteHashEntry(entryPtr); - } - if (FindToglWithSameOverlayContext(togl) == NULL) - glXDestroyContext(togl->display, togl->OverlayCtx); - togl->OverlayCtx = NULL; - } -# endif /* USE_OVERLAY */ -#endif - /* TODO: delete contexts on other platforms */ - - if (tkwin != NULL) { - if (togl->SetGrid > 0) { - Tk_UnsetGrid(tkwin); - } - togl->TkWin = NULL; - Tk_DestroyWindow(tkwin); - } -} - - -/* - * Togl_Destroy - * - * Gets called when an Togl widget is destroyed. - */ -static void -Togl_Destroy( -#if (TK_MAJOR_VERSION * 100 + TK_MINOR_VERSION) >= 401 - char * -#else - ClientData -#endif - clientData) -{ - Togl *togl = (Togl *) clientData; - - Tk_FreeOptions(configSpecs, WIDGREC togl, togl->display, 0); - -#ifndef NO_TK_CURSOR - if (togl->Cursor != None) { - Tk_FreeCursor(togl->display, togl->Cursor); - } -#endif - if (togl->DestroyProc) { - togl->DestroyProc(togl); - } - - /* remove from linked list */ - RemoveFromList(togl); - -#if !defined(TOGL_WGL) - /* TODO: why not on Windows? */ - free(togl); -#endif -} - - - -/* - * This gets called to handle Togl window configuration events - */ -static void -Togl_EventProc(ClientData clientData, XEvent *eventPtr) -{ - Togl *togl = (Togl *) clientData; - - switch (eventPtr->type) { - case Expose: - if (eventPtr->xexpose.count == 0) { - if (!togl->UpdatePending - && eventPtr->xexpose.window == Tk_WindowId(togl->TkWin)) { - Togl_PostRedisplay(togl); - } -#if defined(TOGL_X11) - if (!togl->OverlayUpdatePending && togl->OverlayFlag - && togl->OverlayIsMapped - && eventPtr->xexpose.window == togl->OverlayWindow) { - Togl_PostOverlayRedisplay(togl); - } -#endif /* TOGL_X11 */ - } - break; - case ConfigureNotify: - if (togl->Width != Tk_Width(togl->TkWin) - || togl->Height != Tk_Height(togl->TkWin)) { - togl->Width = Tk_Width(togl->TkWin); - togl->Height = Tk_Height(togl->TkWin); - (void) XResizeWindow(Tk_Display(togl->TkWin), - Tk_WindowId(togl->TkWin), togl->Width, togl->Height); -#if defined(TOGL_X11) - if (togl->OverlayFlag) { - (void) XResizeWindow(Tk_Display(togl->TkWin), - togl->OverlayWindow, togl->Width, togl->Height); - (void) XRaiseWindow(Tk_Display(togl->TkWin), - togl->OverlayWindow); - } -#endif /* TOGL_X11 */ - Togl_MakeCurrent(togl); - if (togl->ReshapeProc) { - togl->ReshapeProc(togl); - } else { - glViewport(0, 0, togl->Width, togl->Height); -#if defined(TOGL_X11) - if (togl->OverlayFlag) { - Togl_UseLayer(togl, TOGL_OVERLAY); - glViewport(0, 0, togl->Width, togl->Height); - Togl_UseLayer(togl, TOGL_NORMAL); - } -#endif /* TOGL_X11 */ - } -#ifndef TOGL_WGL /* causes double redisplay on Win32 platform */ - Togl_PostRedisplay(togl); -#endif /* TOGL_WGL */ - } - break; - case MapNotify: -#if defined(TOGL_AGL) - { - /* - * See comment for the UnmapNotify case below. - */ - AGLDrawable d = TkMacOSXGetDrawablePort(Tk_WindowId(togl->TkWin)); - - aglSetDrawable(togl->aglCtx, d); - } -#endif /* TOGL_AGL */ - break; - case UnmapNotify: -#if defined(TOGL_AGL) - { - /* - * For Mac OS X Aqua, Tk subwindows are not implemented as - * separate Aqua windows. They are just different regions of - * a single Aqua window. To unmap them they are just not drawn. - * Have to disconnect the AGL context otherwise they will continue - * to be displayed directly by Aqua. - */ - aglSetDrawable(togl->aglCtx, NULL); - } -#endif /* TOGL_AGL */ - break; - case DestroyNotify: - if (togl->TkWin != NULL) { - if (togl->SetGrid > 0) { - Tk_UnsetGrid(togl->TkWin); - } - togl->TkWin = NULL; -#if (TCL_MAJOR_VERSION * 100 + TCL_MINOR_VERSION) >= 800 - /* This function new in Tcl/Tk 8.0 */ - (void) Tcl_DeleteCommandFromToken(togl->Interp, togl->widgetCmd); -#endif - } - if (togl->TimerProc != NULL) { -#if (TK_MAJOR_VERSION * 100 + TK_MINOR_VERSION) >= 401 - Tcl_DeleteTimerHandler(togl->timerHandler); -#else - Tk_DeleteTimerHandler(togl->timerHandler); -#endif - - } - if (togl->UpdatePending) { -#if (TCL_MAJOR_VERSION * 100 + TCL_MINOR_VERSION) >= 705 - Tcl_CancelIdleCall(Togl_Render, (ClientData) togl); -#else - Tk_CancelIdleCall(Togl_Render, (ClientData) togl); -#endif - } -#if (TK_MAJOR_VERSION * 100 + TK_MINOR_VERSION) >= 401 - Tcl_EventuallyFree((ClientData) togl, Togl_Destroy); -#else - Tk_EventuallyFree((ClientData) togl, Togl_Destroy); -#endif - - break; - default: - /* nothing */ - ; - } -} - - - -void -Togl_PostRedisplay(Togl *togl) -{ - if (!togl->UpdatePending) { - togl->UpdatePending = True; - Tk_DoWhenIdle(Togl_Render, (ClientData) togl); - } -} - - - -void -Togl_SwapBuffers(const Togl *togl) -{ - if (togl->DoubleFlag) { -#if defined(TOGL_WGL) - int res = SwapBuffers(togl->tglGLHdc); - - assert(res == TRUE); -#elif defined(TOGL_X11) - glXSwapBuffers(Tk_Display(togl->TkWin), Tk_WindowId(togl->TkWin)); -#elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - aglSwapBuffers(togl->aglCtx); -#endif /* TOGL_WGL */ - } else { - glFlush(); - } -} - - - -const char * -Togl_Ident(const Togl *togl) -{ - return togl->Ident; -} - - -int -Togl_Width(const Togl *togl) -{ - return togl->Width; -} - - -int -Togl_Height(const Togl *togl) -{ - return togl->Height; -} - - -Tcl_Interp * -Togl_Interp(const Togl *togl) -{ - return togl->Interp; -} - - -Tk_Window -Togl_TkWin(const Togl *togl) -{ - return togl->TkWin; -} - - -#if defined(TOGL_X11) -/* - * A replacement for XAllocColor. This function should never - * fail to allocate a color. When XAllocColor fails, we return - * the nearest matching color. If we have to allocate many colors - * this function isn't too efficient; the XQueryColors() could be - * done just once. - * Written by Michael Pichler, Brian Paul, Mark Kilgard - * Input: dpy - X display - * cmap - X colormap - * cmapSize - size of colormap - * In/Out: color - the XColor struct - * Output: exact - 1=exact color match, 0=closest match - */ -static void -noFaultXAllocColor(Display *dpy, Colormap cmap, int cmapSize, - XColor *color, int *exact) -{ - XColor *ctable, subColor; - int i, bestmatch; - double mindist; /* 3*2^16^2 exceeds long int precision. */ - - /* First try just using XAllocColor. */ - if (XAllocColor(dpy, cmap, color)) { - *exact = 1; - return; - } - - /* Retrieve color table entries. */ - /* XXX alloca candidate. */ - ctable = (XColor *) malloc(cmapSize * sizeof (XColor)); - for (i = 0; i < cmapSize; i++) { - ctable[i].pixel = i; - } - (void) XQueryColors(dpy, cmap, ctable, cmapSize); - - /* Find best match. */ - bestmatch = -1; - mindist = 0; - for (i = 0; i < cmapSize; i++) { - double dr = (double) color->red - (double) ctable[i].red; - double dg = (double) color->green - (double) ctable[i].green; - double db = (double) color->blue - (double) ctable[i].blue; - double dist = dr * dr + dg * dg + db * db; - - if (bestmatch < 0 || dist < mindist) { - bestmatch = i; - mindist = dist; - } - } - - /* Return result. */ - subColor.red = ctable[bestmatch].red; - subColor.green = ctable[bestmatch].green; - subColor.blue = ctable[bestmatch].blue; - free(ctable); - /* Try to allocate the closest match color. This should only fail if the - * cell is read/write. Otherwise, we're incrementing the cell's reference - * count. */ - if (!XAllocColor(dpy, cmap, &subColor)) { - /* do this to work around a problem reported by Frank Ortega */ - subColor.pixel = (unsigned long) bestmatch; - subColor.red = ctable[bestmatch].red; - subColor.green = ctable[bestmatch].green; - subColor.blue = ctable[bestmatch].blue; - subColor.flags = DoRed | DoGreen | DoBlue; - } - *color = subColor; -} - -#elif defined(TOGL_WGL) - -static UINT -Win32AllocColor(const Togl *togl, float red, float green, float blue) -{ - /* Modified version of XAllocColor emulation of Tk. - returns index, - * instead of color itself - allocates logical palette entry even for - * non-palette devices */ - - TkWinColormap *cmap = (TkWinColormap *) Tk_Colormap(togl->TkWin); - UINT index; - COLORREF newColor, closeColor; - PALETTEENTRY entry, closeEntry; - int new, refCount; - Tcl_HashEntry *entryPtr; - - entry.peRed = (unsigned char) (red * 255 + .5); - entry.peGreen = (unsigned char) (green * 255 + .5); - entry.peBlue = (unsigned char) (blue * 255 + .5); - entry.peFlags = 0; - - /* - * Find the nearest existing palette entry. - */ - - newColor = RGB(entry.peRed, entry.peGreen, entry.peBlue); - index = GetNearestPaletteIndex(cmap->palette, newColor); - GetPaletteEntries(cmap->palette, index, 1, &closeEntry); - closeColor = RGB(closeEntry.peRed, closeEntry.peGreen, closeEntry.peBlue); - - /* - * If this is not a duplicate and colormap is not full, allocate a new entry. - */ - - if (newColor != closeColor) { - if (cmap->size == (unsigned int) togl->CiColormapSize) { - entry = closeEntry; - } else { - cmap->size++; - ResizePalette(cmap->palette, cmap->size); - index = cmap->size - 1; - SetPaletteEntries(cmap->palette, index, 1, &entry); - SelectPalette(togl->tglGLHdc, cmap->palette, TRUE); - RealizePalette(togl->tglGLHdc); - } - } - newColor = PALETTERGB(entry.peRed, entry.peGreen, entry.peBlue); - entryPtr = Tcl_CreateHashEntry(&cmap->refCounts, (char *) newColor, &new); - if (new) { - refCount = 1; - } else { - refCount = ((int) Tcl_GetHashValue(entryPtr)) + 1; - } - Tcl_SetHashValue(entryPtr, (ClientData) refCount); - - /* for EPS output */ - togl->EpsRedMap[index] = (GLfloat) (entry.peRed / 255.0); - togl->EpsGreenMap[index] = (GLfloat) (entry.peGreen / 255.0); - togl->EpsBlueMap[index] = (GLfloat) (entry.peBlue / 255.0); - return index; -} - -static void -Win32FreeColor(const Togl *togl, unsigned long index) -{ - TkWinColormap *cmap = (TkWinColormap *) Tk_Colormap(togl->TkWin); - COLORREF cref; - UINT count, refCount; - PALETTEENTRY entry, *entries; - Tcl_HashEntry *entryPtr; - - if (index >= cmap->size) { - panic("Tried to free a color that isn't allocated."); - } - GetPaletteEntries(cmap->palette, index, 1, &entry); - cref = PALETTERGB(entry.peRed, entry.peGreen, entry.peBlue); - entryPtr = Tcl_FindHashEntry(&cmap->refCounts, (char *) cref); - if (!entryPtr) { - panic("Tried to free a color that isn't allocated."); - } - refCount = (int) Tcl_GetHashValue(entryPtr) - 1; - if (refCount == 0) { - count = cmap->size - index; - entries = (PALETTEENTRY *) ckalloc(sizeof (PALETTEENTRY) * count); - GetPaletteEntries(cmap->palette, index + 1, count, entries); - SetPaletteEntries(cmap->palette, index, count, entries); - SelectPalette(togl->tglGLHdc, cmap->palette, TRUE); - RealizePalette(togl->tglGLHdc); - ckfree((char *) entries); - cmap->size--; - Tcl_DeleteHashEntry(entryPtr); - } else { - Tcl_SetHashValue(entryPtr, (ClientData) refCount); - } -} - -static void -Win32SetColor(const Togl *togl, - unsigned long index, float red, float green, float blue) -{ - TkWinColormap *cmap = (TkWinColormap *) Tk_Colormap(togl->TkWin); - PALETTEENTRY entry; - - entry.peRed = (unsigned char) (red * 255 + .5); - entry.peGreen = (unsigned char) (green * 255 + .5); - entry.peBlue = (unsigned char) (blue * 255 + .5); - entry.peFlags = 0; - SetPaletteEntries(cmap->palette, index, 1, &entry); - SelectPalette(togl->tglGLHdc, cmap->palette, TRUE); - RealizePalette(togl->tglGLHdc); - - /* for EPS output */ - togl->EpsRedMap[index] = (GLfloat) (entry.peRed / 255.0); - togl->EpsGreenMap[index] = (GLfloat) (entry.peGreen / 255.0); - togl->EpsBlueMap[index] = (GLfloat) (entry.peBlue / 255.0); -} -#endif /* TOGL_X11 */ - - -unsigned long -Togl_AllocColor(const Togl *togl, float red, float green, float blue) -{ - if (togl->RgbaFlag) { - (void) fprintf(stderr, - "Error: Togl_AllocColor illegal in RGBA mode.\n"); - return 0; - } - /* TODO: maybe not... */ - if (togl->PrivateCmapFlag) { - (void) fprintf(stderr, - "Error: Togl_FreeColor illegal with private colormap\n"); - return 0; - } -#if defined(TOGL_X11) - { - XColor xcol; - int exact; - - xcol.red = (short) (red * 65535.0); - xcol.green = (short) (green * 65535.0); - xcol.blue = (short) (blue * 65535.0); - - noFaultXAllocColor(Tk_Display(togl->TkWin), Tk_Colormap(togl->TkWin), - Tk_Visual(togl->TkWin)->map_entries, &xcol, &exact); - /* for EPS output */ - togl->EpsRedMap[xcol.pixel] = (float) xcol.red / 65535.0; - togl->EpsGreenMap[xcol.pixel] = (float) xcol.green / 65535.0; - togl->EpsBlueMap[xcol.pixel] = (float) xcol.blue / 65535.0; - - return xcol.pixel; - } - -#elif defined(TOGL_WGL) - return Win32AllocColor(togl, red, green, blue); - -#elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - /* still need to implement this on Mac... */ - return 0; - -#endif /* TOGL_X11 */ -} - - - -void -Togl_FreeColor(const Togl *togl, unsigned long pixel) -{ - if (togl->RgbaFlag) { - (void) fprintf(stderr, - "Error: Togl_AllocColor illegal in RGBA mode.\n"); - return; - } - /* TODO: maybe not... */ - if (togl->PrivateCmapFlag) { - (void) fprintf(stderr, - "Error: Togl_FreeColor illegal with private colormap\n"); - return; - } -#if defined(TOGL_X11) - (void) XFreeColors(Tk_Display(togl->TkWin), Tk_Colormap(togl->TkWin), - &pixel, 1, 0); -#elif defined(TOGL_WGL) - Win32FreeColor(togl, pixel); -#endif /* TOGL_X11 */ -} - - - -void -Togl_SetColor(const Togl *togl, - unsigned long index, float red, float green, float blue) -{ - - if (togl->RgbaFlag) { - (void) fprintf(stderr, - "Error: Togl_AllocColor illegal in RGBA mode.\n"); - return; - } - if (!togl->PrivateCmapFlag) { - (void) fprintf(stderr, - "Error: Togl_SetColor requires a private colormap\n"); - return; - } -#if defined(TOGL_X11) - { - XColor xcol; - - xcol.pixel = index; - xcol.red = (short) (red * 65535.0); - xcol.green = (short) (green * 65535.0); - xcol.blue = (short) (blue * 65535.0); - xcol.flags = DoRed | DoGreen | DoBlue; - - (void) XStoreColor(Tk_Display(togl->TkWin), Tk_Colormap(togl->TkWin), - &xcol); - - /* for EPS output */ - togl->EpsRedMap[xcol.pixel] = (float) xcol.red / 65535.0; - togl->EpsGreenMap[xcol.pixel] = (float) xcol.green / 65535.0; - togl->EpsBlueMap[xcol.pixel] = (float) xcol.blue / 65535.0; - } -#elif defined(TOGL_WGL) - Win32SetColor(togl, index, red, green, blue); -#endif /* TOGL_X11 */ -} - - -#if TOGL_USE_FONTS == 1 - -# if defined(TOGL_WGL) -# include "tkWinInt.h" -# include "tkFont.h" - -/* - * The following structure represents Windows' implementation of a font. - */ - -typedef struct WinFont -{ - TkFont font; /* Stuff used by generic font package. Must be - * first in structure. */ - HFONT hFont; /* Windows information about font. */ - HWND hwnd; /* Toplevel window of application that owns - * this font, used for getting HDC. */ - int widths[256]; /* Widths of first 256 chars in this font. */ -} WinFont; -# endif /* TOGL_WGL */ - - -# define MAX_FONTS 1000 -static GLuint ListBase[MAX_FONTS]; -static GLuint ListCount[MAX_FONTS]; - - - -/* - * Load the named bitmap font as a sequence of bitmaps in a display list. - * fontname may be one of the predefined fonts like TOGL_BITMAP_8_BY_13 - * or an X font name, or a Windows font name, etc. - */ -GLuint -Togl_LoadBitmapFont(const Togl *togl, const char *fontname) -{ - static Bool FirstTime = True; - -# if defined(TOGL_X11) - XFontStruct *fontinfo; -# elif defined(TOGL_WGL) - WinFont *winfont; - HFONT oldFont; - TEXTMETRIC tm; -# endif - /* TOGL_X11 */ - int first, last, count; - GLuint fontbase; - const char *name; - - /* Initialize the ListBase and ListCount arrays */ - if (FirstTime) { - int i; - - for (i = 0; i < MAX_FONTS; i++) { - ListBase[i] = ListCount[i] = 0; - } - FirstTime = False; - } - - /* - * This method of selecting X fonts according to a TOGL_ font name - * is a kludge. To be fixed when I find time... - */ - if (fontname == TOGL_BITMAP_8_BY_13) { - name = "8x13"; - } else if (fontname == TOGL_BITMAP_9_BY_15) { - name = "9x15"; - } else if (fontname == TOGL_BITMAP_TIMES_ROMAN_10) { - name = "-adobe-times-medium-r-normal--10-100-75-75-p-54-iso8859-1"; - } else if (fontname == TOGL_BITMAP_TIMES_ROMAN_24) { - name = "-adobe-times-medium-r-normal--24-240-75-75-p-124-iso8859-1"; - } else if (fontname == TOGL_BITMAP_HELVETICA_10) { - name = "-adobe-helvetica-medium-r-normal--10-100-75-75-p-57-iso8859-1"; - } else if (fontname == TOGL_BITMAP_HELVETICA_12) { - name = "-adobe-helvetica-medium-r-normal--12-120-75-75-p-67-iso8859-1"; - } else if (fontname == TOGL_BITMAP_HELVETICA_18) { - name = "-adobe-helvetica-medium-r-normal--18-180-75-75-p-98-iso8859-1"; - } else if (!fontname) { - name = DEFAULT_FONTNAME; - } else { - name = (const char *) fontname; - } - - assert(name); - -# if defined(TOGL_X11) - fontinfo = (XFontStruct *) XLoadQueryFont(Tk_Display(togl->TkWin), name); - if (!fontinfo) { - return 0; - } - first = fontinfo->min_char_or_byte2; - last = fontinfo->max_char_or_byte2; -# elif defined(TOGL_WGL) - winfont = (WinFont *) Tk_GetFont(togl->Interp, togl->TkWin, name); - if (!winfont) { - return 0; - } - oldFont = SelectObject(togl->tglGLHdc, winfont->hFont); - GetTextMetrics(togl->tglGLHdc, &tm); - first = tm.tmFirstChar; - last = tm.tmLastChar; -# elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - first = 10; /* don't know how to determine font range on - * Mac... */ - last = 127; -# endif - /* TOGL_X11 */ - - count = last - first + 1; - fontbase = glGenLists((GLuint) (last + 1)); - if (fontbase == 0) { -# ifdef TOGL_WGL - SelectObject(togl->tglGLHdc, oldFont); - Tk_FreeFont((Tk_Font) winfont); -# endif - /* TOGL_WGL */ - return 0; - } -# if defined(TOGL_WGL) - wglUseFontBitmaps(togl->tglGLHdc, first, count, (int) fontbase + first); - SelectObject(togl->tglGLHdc, oldFont); - Tk_FreeFont((Tk_Font) winfont); -# elif defined(TOGL_X11) - glXUseXFont(fontinfo->fid, first, count, (int) fontbase + first); -# elif defined(TOGL_AGL_CLASSIC) || defined(TOGL_AGL) - aglUseFont(togl->aglCtx, 1, 0, 14, /* for now, only app font, regular - * 14-point */ - 10, 118, fontbase + first); -# endif - - /* Record the list base and number of display lists for - * Togl_UnloadBitmapFont(). */ - { - int i; - - for (i = 0; i < MAX_FONTS; i++) { - if (ListBase[i] == 0) { - ListBase[i] = fontbase; - ListCount[i] = last + 1; - break; - } - } - } - - return fontbase; -} - - - -/* - * Release the display lists which were generated by Togl_LoadBitmapFont(). - */ -void -Togl_UnloadBitmapFont(const Togl *togl, GLuint fontbase) -{ - int i; - - (void) togl; - for (i = 0; i < MAX_FONTS; i++) { - if (ListBase[i] == fontbase) { - glDeleteLists(ListBase[i], ListCount[i]); - ListBase[i] = ListCount[i] = 0; - return; - } - } -} - -#endif /* TOGL_USE_FONTS */ - - -/* - * Overlay functions - */ - - -void -Togl_UseLayer(Togl *togl, int layer) -{ - if (!togl->OverlayWindow) - return; - if (layer == TOGL_OVERLAY) { -#if defined(TOGL_WGL) - int res = wglMakeCurrent(togl->tglGLHdc, togl->tglGLOverlayHglrc); - - assert(res == TRUE); -#elif defined(TOGL_X11) - (void) glXMakeCurrent(Tk_Display(togl->TkWin), - togl->OverlayWindow, togl->OverlayCtx); -# if defined(__sgi) - if (togl->OldStereoFlag) - oldStereoMakeCurrent(Tk_Display(togl->TkWin), - togl->OverlayWindow, togl->OverlayCtx); -# endif - /* __sgi STEREO */ -#endif /* TOGL_WGL */ - } else if (layer == TOGL_NORMAL) { -#if defined(TOGL_WGL) - int res = wglMakeCurrent(togl->tglGLHdc, togl->tglGLHglrc); - - assert(res == TRUE); -#elif defined(TOGL_X11) - (void) glXMakeCurrent(Tk_Display(togl->TkWin), - Tk_WindowId(togl->TkWin), togl->GlCtx); -# if defined(__sgi) - if (togl->OldStereoFlag) - oldStereoMakeCurrent(Tk_Display(togl->TkWin), - Tk_WindowId(togl->TkWin), togl->GlCtx); -# endif - /* __sgi STEREO */ -#endif /* TOGL_WGL */ - } else { - /* error */ - } -} - - -void -Togl_ShowOverlay(Togl *togl) -{ -#if defined(TOGL_X11) /* not yet implemented on Windows */ - if (togl->OverlayWindow) { - (void) XMapWindow(Tk_Display(togl->TkWin), togl->OverlayWindow); - (void) XInstallColormap(Tk_Display(togl->TkWin), togl->OverlayCmap); - togl->OverlayIsMapped = True; - } -#endif /* TOGL_X11 */ -} - - -void -Togl_HideOverlay(Togl *togl) -{ - if (togl->OverlayWindow && togl->OverlayIsMapped) { - (void) XUnmapWindow(Tk_Display(togl->TkWin), togl->OverlayWindow); - togl->OverlayIsMapped = False; - } -} - - -void -Togl_PostOverlayRedisplay(Togl *togl) -{ - if (!togl->OverlayUpdatePending - && togl->OverlayWindow && togl->OverlayDisplayProc) { - Tk_DoWhenIdle(RenderOverlay, (ClientData) togl); - togl->OverlayUpdatePending = True; - } -} - - -void -Togl_OverlayDisplayFunc(Togl_Callback *proc) -{ - DefaultOverlayDisplayProc = proc; -} - - -int -Togl_ExistsOverlay(const Togl *togl) -{ - return togl->OverlayFlag; -} - - -int -Togl_GetOverlayTransparentValue(const Togl *togl) -{ - return togl->OverlayTransparentPixel; -} - - -int -Togl_IsMappedOverlay(const Togl *togl) -{ - return togl->OverlayFlag && togl->OverlayIsMapped; -} - - -unsigned long -Togl_AllocColorOverlay(const Togl *togl, float red, float green, float blue) -{ -#if defined(TOGL_X11) /* not yet implemented on Windows */ - if (togl->OverlayFlag && togl->OverlayCmap) { - XColor xcol; - - xcol.red = (short) (red * 65535.0); - xcol.green = (short) (green * 65535.0); - xcol.blue = (short) (blue * 65535.0); - if (!XAllocColor(Tk_Display(togl->TkWin), togl->OverlayCmap, &xcol)) - return (unsigned long) -1; - return xcol.pixel; - } -#endif /* TOGL_X11 */ - return (unsigned long) -1; -} - - -void -Togl_FreeColorOverlay(const Togl *togl, unsigned long pixel) -{ -#if defined(TOGL_X11) /* not yet implemented on Windows */ - if (togl->OverlayFlag && togl->OverlayCmap) { - (void) XFreeColors(Tk_Display(togl->TkWin), togl->OverlayCmap, &pixel, - 1, 0); - } -#endif /* TOGL_X11 */ -} - - -/* - * User client data - */ - -void -Togl_ClientData(ClientData clientData) -{ - DefaultClientData = clientData; -} - - -ClientData -Togl_GetClientData(const Togl *togl) -{ - return togl->Client_Data; -} - - -void -Togl_SetClientData(Togl *togl, ClientData clientData) -{ - togl->Client_Data = clientData; -} - - -/* - * X11-only functions - * Contributed by Miguel A. De Riera Pasenau (miguel@DALILA.UPC.ES) - */ - -Display * -Togl_Display(const Togl *togl) -{ - return Tk_Display(togl->TkWin); -} - -Screen * -Togl_Screen(const Togl *togl) -{ - return Tk_Screen(togl->TkWin); -} - -int -Togl_ScreenNumber(const Togl *togl) -{ - return Tk_ScreenNumber(togl->TkWin); -} - -Colormap -Togl_Colormap(const Togl *togl) -{ - return Tk_Colormap(togl->TkWin); -} - - - -#ifdef MESA_COLOR_HACK -/* - * Let's know how many free colors do we have - */ -# if 0 -static unsigned char rojo[] = { 4, 39, 74, 110, 145, 181, 216, 251 }, verde[] = { -4, 39, 74, 110, 145, 181, 216, 251}, azul[] = { -4, 39, 74, 110, 145, 181, 216, 251}; - -unsigned char rojo[] = { 4, 36, 72, 109, 145, 182, 218, 251 }, verde[] = { -4, 36, 72, 109, 145, 182, 218, 251}, azul[] = { -4, 36, 72, 109, 145, 182, 218, 251}; - -azul[] = { -0, 85, 170, 255}; -# endif - -# define RLEVELS 5 -# define GLEVELS 9 -# define BLEVELS 5 - -/* to free dithered_rgb_colormap pixels allocated by Mesa */ -static unsigned long *ToglMesaUsedPixelCells = NULL; -static int ToglMesaUsedFreeCells = 0; - -static int -get_free_color_cells(Display *display, int screen, Colormap colormap) -{ - if (!ToglMesaUsedPixelCells) { - XColor xcol; - int i; - int colorsfailed, ncolors = XDisplayCells(display, screen); - - long r, g, b; - - ToglMesaUsedPixelCells = - (unsigned long *) calloc(ncolors, sizeof (unsigned long)); - - /* Allocate X colors and initialize color_table[], red_table[], etc */ - /* de Mesa 2.1: xmesa1.c setup_dithered_(...) */ - i = colorsfailed = 0; - for (r = 0; r < RLEVELS; r++) - for (g = 0; g < GLEVELS; g++) - for (b = 0; b < BLEVELS; b++) { - int exact; - - xcol.red = (r * 65535) / (RLEVELS - 1); - xcol.green = (g * 65535) / (GLEVELS - 1); - xcol.blue = (b * 65535) / (BLEVELS - 1); - noFaultXAllocColor(display, colormap, ncolors, - &xcol, &exact); - ToglMesaUsedPixelCells[i++] = xcol.pixel; - if (!exact) { - colorsfailed++; - } - } - ToglMesaUsedFreeCells = i; - - XFreeColors(display, colormap, ToglMesaUsedPixelCells, - ToglMesaUsedFreeCells, 0x00000000); - } - return ToglMesaUsedFreeCells; -} - - -static void -free_default_color_cells(Display *display, Colormap colormap) -{ - if (ToglMesaUsedPixelCells) { - XFreeColors(display, colormap, ToglMesaUsedPixelCells, - ToglMesaUsedFreeCells, 0x00000000); - free(ToglMesaUsedPixelCells); - ToglMesaUsedPixelCells = NULL; - ToglMesaUsedFreeCells = 0; - } -} -#endif - - -/* - * Generate EPS file. - * Contributed by Miguel A. De Riera Pasenau (miguel@DALILA.UPC.ES) - */ - -/* Function that creates a EPS File from a created pixmap on the current - * context. Based on the code from Copyright (c) Mark J. Kilgard, 1996. - * Parameters: name_file, b&w / Color flag, redraw function. The redraw - * function is needed in order to draw things into the new created pixmap. */ - -/* Copyright (c) Mark J. Kilgard, 1996. */ - -static GLvoid * -grabPixels(int inColor, unsigned int width, unsigned int height) -{ - GLvoid *buffer; - GLint swapbytes, lsbfirst, rowlength; - GLint skiprows, skippixels, alignment; - GLenum format; - unsigned int size; - - if (inColor) { - format = GL_RGB; - size = width * height * 3; - } else { - format = GL_LUMINANCE; - size = width * height * 1; - } - - buffer = (GLvoid *) malloc(size); - if (buffer == NULL) - return NULL; - - /* Save current modes. */ - glGetIntegerv(GL_PACK_SWAP_BYTES, &swapbytes); - glGetIntegerv(GL_PACK_LSB_FIRST, &lsbfirst); - glGetIntegerv(GL_PACK_ROW_LENGTH, &rowlength); - glGetIntegerv(GL_PACK_SKIP_ROWS, &skiprows); - glGetIntegerv(GL_PACK_SKIP_PIXELS, &skippixels); - glGetIntegerv(GL_PACK_ALIGNMENT, &alignment); - /* Little endian machines (DEC Alpha for example) could benefit from - * setting GL_PACK_LSB_FIRST to GL_TRUE instead of GL_FALSE, but this would - * * * * * * * * * require changing the generated bitmaps too. */ - glPixelStorei(GL_PACK_SWAP_BYTES, GL_FALSE); - glPixelStorei(GL_PACK_LSB_FIRST, GL_FALSE); - glPixelStorei(GL_PACK_ROW_LENGTH, 0); - glPixelStorei(GL_PACK_SKIP_ROWS, 0); - glPixelStorei(GL_PACK_SKIP_PIXELS, 0); - glPixelStorei(GL_PACK_ALIGNMENT, 1); - - /* Actually read the pixels. */ - glReadPixels(0, 0, width, height, format, - GL_UNSIGNED_BYTE, (GLvoid *) buffer); - - /* Restore saved modes. */ - glPixelStorei(GL_PACK_SWAP_BYTES, swapbytes); - glPixelStorei(GL_PACK_LSB_FIRST, lsbfirst); - glPixelStorei(GL_PACK_ROW_LENGTH, rowlength); - glPixelStorei(GL_PACK_SKIP_ROWS, skiprows); - glPixelStorei(GL_PACK_SKIP_PIXELS, skippixels); - glPixelStorei(GL_PACK_ALIGNMENT, alignment); - return buffer; -} - - -static int -generateEPS(const char *filename, int inColor, - unsigned int width, unsigned int height) -{ - FILE *fp; - GLvoid *pixels; - unsigned char *curpix; - unsigned int components, i; - int pos; - unsigned int bitpixel; - - pixels = grabPixels(inColor, width, height); - if (pixels == NULL) - return 1; - if (inColor) - components = 3; /* Red, green, blue. */ - else - components = 1; /* Luminance. */ - - fp = fopen(filename, "w"); - if (fp == NULL) { - return 2; - } - (void) fprintf(fp, "%%!PS-Adobe-2.0 EPSF-1.2\n"); - (void) fprintf(fp, "%%%%Creator: OpenGL pixmap render output\n"); - (void) fprintf(fp, "%%%%BoundingBox: 0 0 %d %d\n", width, height); - (void) fprintf(fp, "%%%%EndComments\n"); - - i = (((width * height) + 7) / 8) / 40; /* # of lines, 40 bytes per - * line */ - (void) fprintf(fp, "%%%%BeginPreview: %d %d %d %d\n%%", width, height, 1, - i); - pos = 0; - curpix = (unsigned char *) pixels; - for (i = 0; i < width * height * components;) { - bitpixel = 0; - if (inColor) { - double pix = 0; - - pix = 0.30 * (double) curpix[i] + 0.59 * (double) curpix[i + 1] + - 0.11 * (double) curpix[i + 2]; - i += 3; - if (pix > 127.0) - bitpixel |= 0x80; - pix = 0.30 * (double) curpix[i] + 0.59 * (double) curpix[i + 1] + - 0.11 * (double) curpix[i + 2]; - i += 3; - if (pix > 127.0) - bitpixel |= 0x40; - pix = 0.30 * (double) curpix[i] + 0.59 * (double) curpix[i + 1] + - 0.11 * (double) curpix[i + 2]; - i += 3; - if (pix > 127.0) - bitpixel |= 0x20; - pix = 0.30 * (double) curpix[i] + 0.59 * (double) curpix[i + 1] + - 0.11 * (double) curpix[i + 2]; - i += 3; - if (pix > 127.0) - bitpixel |= 0x10; - pix = 0.30 * (double) curpix[i] + 0.59 * (double) curpix[i + 1] + - 0.11 * (double) curpix[i + 2]; - i += 3; - if (pix > 127.0) - bitpixel |= 0x08; - pix = 0.30 * (double) curpix[i] + 0.59 * (double) curpix[i + 1] + - 0.11 * (double) curpix[i + 2]; - i += 3; - if (pix > 127.0) - bitpixel |= 0x04; - pix = 0.30 * (double) curpix[i] + 0.59 * (double) curpix[i + 1] + - 0.11 * (double) curpix[i + 2]; - i += 3; - if (pix > 127.0) - bitpixel |= 0x02; - pix = 0.30 * (double) curpix[i] + 0.59 * (double) curpix[i + 1] + - 0.11 * (double) curpix[i + 2]; - i += 3; - if (pix > 127.0) - bitpixel |= 0x01; - } else { - if (curpix[i++] > 0x7f) - bitpixel |= 0x80; - if (curpix[i++] > 0x7f) - bitpixel |= 0x40; - if (curpix[i++] > 0x7f) - bitpixel |= 0x20; - if (curpix[i++] > 0x7f) - bitpixel |= 0x10; - if (curpix[i++] > 0x7f) - bitpixel |= 0x08; - if (curpix[i++] > 0x7f) - bitpixel |= 0x04; - if (curpix[i++] > 0x7f) - bitpixel |= 0x02; - if (curpix[i++] > 0x7f) - bitpixel |= 0x01; - } - (void) fprintf(fp, "%02x", bitpixel); - if (++pos >= 40) { - (void) fprintf(fp, "\n%%"); - pos = 0; - } - } - if (pos) - (void) fprintf(fp, "\n%%%%EndPreview\n"); - else - (void) fprintf(fp, "%%EndPreview\n"); - - (void) fprintf(fp, "gsave\n"); - (void) fprintf(fp, "/bwproc {\n"); - (void) fprintf(fp, " rgbproc\n"); - (void) fprintf(fp, " dup length 3 idiv string 0 3 0\n"); - (void) fprintf(fp, " 5 -1 roll {\n"); - (void) fprintf(fp, " add 2 1 roll 1 sub dup 0 eq\n"); - (void) fprintf(fp, " { pop 3 idiv 3 -1 roll dup 4 -1 roll dup\n"); - (void) fprintf(fp, " 3 1 roll 5 -1 roll put 1 add 3 0 }\n"); - (void) fprintf(fp, " { 2 1 roll } ifelse\n"); - (void) fprintf(fp, " } forall\n"); - (void) fprintf(fp, " pop pop pop\n"); - (void) fprintf(fp, "} def\n"); - (void) fprintf(fp, "systemdict /colorimage known not {\n"); - (void) fprintf(fp, " /colorimage {\n"); - (void) fprintf(fp, " pop\n"); - (void) fprintf(fp, " pop\n"); - (void) fprintf(fp, " /rgbproc exch def\n"); - (void) fprintf(fp, " { bwproc } image\n"); - (void) fprintf(fp, " } def\n"); - (void) fprintf(fp, "} if\n"); - (void) fprintf(fp, "/picstr %d string def\n", width * components); - (void) fprintf(fp, "%d %d scale\n", width, height); - (void) fprintf(fp, "%d %d %d\n", width, height, 8); - (void) fprintf(fp, "[%d 0 0 %d 0 0]\n", width, height); - (void) fprintf(fp, "{currentfile picstr readhexstring pop}\n"); - (void) fprintf(fp, "false %d\n", components); - (void) fprintf(fp, "colorimage\n"); - - curpix = (unsigned char *) pixels; - pos = 0; - for (i = width * height * components; i != 0; i--) { - (void) fprintf(fp, "%02hx", *curpix++); - if (++pos >= 40) { - (void) fprintf(fp, "\n"); - pos = 0; - } - } - if (pos) - (void) fprintf(fp, "\n"); - - (void) fprintf(fp, "grestore\n"); - free(pixels); - if (fclose(fp) != 0) - return 1; - return 0; -} - - -/* int Togl_DumpToEpsFile( const Togl *togl, const char *filename, int inColor, - * void (*user_redraw)(void)) */ -/* changed by GG */ -int -Togl_DumpToEpsFile(const Togl *togl, const char *filename, - int inColor, void (*user_redraw) (const Togl *)) -{ - Bool using_mesa = False; - -#if 0 - Pixmap eps_pixmap; - GLXPixmap eps_glxpixmap; - XVisualInfo *vi = togl->VisInfo; - Window win = Tk_WindowId(togl->TkWin); -#endif - int retval; - unsigned int width = togl->Width, height = togl->Height; - -#if defined(TOGL_X11) - Display *dpy = Tk_Display(togl->TkWin); - int scrnum = Tk_ScreenNumber(togl->TkWin); - - if (strstr(glXQueryServerString(dpy, scrnum, GLX_VERSION), "Mesa")) - using_mesa = True; - else -#endif /* TOGL_X11 */ - using_mesa = False; - /* I don't use Pixmap do drawn into, because the code should link with Mesa - * libraries and OpenGL libraries, and the which library we use at run time - * should not matter, but the name of the calls differs one from another: - * MesaGl: glXCreateGLXPixmapMESA( dpy, vi, eps_pixmap, - * Tk_Colormap(togl->TkWin)) OpenGl: glXCreateGLXPixmap( dpy, vi, - * eps_pixmap); instead of this I read direct from back buffer of the - * screeen. */ -#if 0 - eps_pixmap = XCreatePixmap(dpy, win, width, height, vi->depth); - if (using_mesa) - eps_glxpixmap = - glXCreateGLXPixmapMESA(dpy, vi, eps_pixmap, - Tk_Colormap(togl->TkWin)); - else - eps_glxpixmap = glXCreateGLXPixmap(dpy, vi, eps_pixmap); - - glXMakeCurrent(dpy, eps_glxpixmap, togl->GlCtx); - user_redraw(); -#endif - if (!togl->RgbaFlag) { - -#if defined(TOGL_WGL) - /* Due to the lack of a unique inverse mapping from the frame buffer to - * the logical palette we need a translation map from the complete - * logical palette. */ - { - int n, i; - TkWinColormap *cmap = (TkWinColormap *) Tk_Colormap(togl->TkWin); - LPPALETTEENTRY entry = - malloc(togl->EpsMapSize * sizeof (PALETTEENTRY)); - n = GetPaletteEntries(cmap->palette, 0, togl->EpsMapSize, entry); - for (i = 0; i < n; i++) { - togl->EpsRedMap[i] = (GLfloat) (entry[i].peRed / 255.0); - togl->EpsGreenMap[i] = (GLfloat) (entry[i].peGreen / 255.0); - togl->EpsBlueMap[i] = (GLfloat) (entry[i].peBlue / 255.0); - } - free(entry); - } -#endif /* TOGL_WGL */ - - glPixelMapfv(GL_PIXEL_MAP_I_TO_R, togl->EpsMapSize, togl->EpsRedMap); - glPixelMapfv(GL_PIXEL_MAP_I_TO_G, togl->EpsMapSize, togl->EpsGreenMap); - glPixelMapfv(GL_PIXEL_MAP_I_TO_B, togl->EpsMapSize, togl->EpsBlueMap); - } - /* user_redraw(); */ - user_redraw(togl); /* changed by GG */ - /* glReadBuffer( GL_FRONT); */ - /* by default it read GL_BACK in double buffer mode */ - glFlush(); - retval = generateEPS(filename, inColor, width, height); -#if 0 - glXMakeCurrent(dpy, win, togl->GlCtx); - glXDestroyGLXPixmap(dpy, eps_glxpixmap); - XFreePixmap(dpy, eps_pixmap); -#endif - return retval; -} - -/* - * Full screen stereo for SGI graphics - * Contributed by Ben Evans (Ben.Evans@anusf.anu.edu.au) - * This code was based on SGI's /usr/share/src/OpenGL/teach/stereo - */ - -#if defined(__sgi) - -static struct stereoStateRec -{ - Bool useSGIStereo; - Display *currentDisplay; - Window currentWindow; - GLXContext currentContext; - GLenum currentDrawBuffer; - int currentStereoBuffer; - Bool enabled; - char *stereoCommand; - char *restoreCommand; -} stereo; - -/* call instead of glDrawBuffer */ -void -Togl_OldStereoDrawBuffer(GLenum mode) -{ - if (stereo.useSGIStereo) { - stereo.currentDrawBuffer = mode; - switch (mode) { - case GL_FRONT: - case GL_BACK: - case GL_FRONT_AND_BACK: - /* - ** Simultaneous drawing to both left and right buffers isn't - ** really possible if we don't have a stereo capable visual. - ** For now just fall through and use the left buffer. - */ - case GL_LEFT: - case GL_FRONT_LEFT: - case GL_BACK_LEFT: - stereo.currentStereoBuffer = STEREO_BUFFER_LEFT; - break; - case GL_RIGHT: - case GL_FRONT_RIGHT: - stereo.currentStereoBuffer = STEREO_BUFFER_RIGHT; - mode = GL_FRONT; - break; - case GL_BACK_RIGHT: - stereo.currentStereoBuffer = STEREO_BUFFER_RIGHT; - mode = GL_BACK; - break; - default: - break; - } - if (stereo.currentDisplay && stereo.currentWindow) { - glXWaitGL(); /* sync with GL command stream before calling X - */ - XSGISetStereoBuffer(stereo.currentDisplay, - stereo.currentWindow, stereo.currentStereoBuffer); - glXWaitX(); /* sync with X command stream before calling GL - */ - } - } - glDrawBuffer(mode); -} - -/* call instead of glClear */ -void -Togl_OldStereoClear(GLbitfield mask) -{ - GLenum drawBuffer; - - if (stereo.useSGIStereo) { - drawBuffer = stereo.currentDrawBuffer; - switch (drawBuffer) { - case GL_FRONT: - Togl_OldStereoDrawBuffer(GL_FRONT_RIGHT); - glClear(mask); - Togl_OldStereoDrawBuffer(drawBuffer); - break; - case GL_BACK: - Togl_OldStereoDrawBuffer(GL_BACK_RIGHT); - glClear(mask); - Togl_OldStereoDrawBuffer(drawBuffer); - break; - case GL_FRONT_AND_BACK: - Togl_OldStereoDrawBuffer(GL_RIGHT); - glClear(mask); - Togl_OldStereoDrawBuffer(drawBuffer); - break; - case GL_LEFT: - case GL_FRONT_LEFT: - case GL_BACK_LEFT: - case GL_RIGHT: - case GL_FRONT_RIGHT: - case GL_BACK_RIGHT: - default: - break; - } - } - glClear(mask); -} - -static void -oldStereoMakeCurrent(Display *dpy, Window win, GLXContext ctx) -{ - - if (dpy && (dpy != stereo.currentDisplay)) { - int event, error; - - /* Make sure new Display supports SGIStereo */ - if (XSGIStereoQueryExtension(dpy, &event, &error) == False) { - dpy = NULL; - } - } - if (dpy && win && (win != stereo.currentWindow)) { - /* Make sure new Window supports SGIStereo */ - if (XSGIQueryStereoMode(dpy, win) == X_STEREO_UNSUPPORTED) { - win = None; - } - } - if (ctx && (ctx != stereo.currentContext)) { - GLint drawBuffer; - - glGetIntegerv(GL_DRAW_BUFFER, &drawBuffer); - Togl_OldStereoDrawBuffer((GLenum) drawBuffer); - } - stereo.currentDisplay = dpy; - stereo.currentWindow = win; - stereo.currentContext = ctx; -} - - -/* call before using stereo */ -static void -oldStereoInit(Togl *togl, int stereoEnabled) -{ - stereo.useSGIStereo = stereoEnabled; - stereo.currentDisplay = NULL; - stereo.currentWindow = None; - stereo.currentContext = NULL; - stereo.currentDrawBuffer = GL_NONE; - stereo.currentStereoBuffer = STEREO_BUFFER_NONE; - stereo.enabled = False; -} - -#endif /* __sgi STEREO */ - - -void -Togl_StereoFrustum(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, - GLfloat zNear, GLfloat zFar, GLfloat eyeDist, GLfloat eyeOffset) -{ - GLfloat eyeShift = (eyeDist - zNear) * (eyeOffset / eyeDist); - - glFrustum(left + eyeShift, right + eyeShift, bottom, top, zNear, zFar); - glTranslatef(-eyeShift, 0, 0); -} - - -#ifdef TOGL_AGL_CLASSIC -/* needed to make shared library on Mac with CodeWarrior; should be overridden - * by user app */ -/* - * int main(int argc, char *argv[]) { return -1; } */ - -/* the following code is borrowed from tkMacAppInit.c */ - -/* - *---------------------------------------------------------------------- - * - * MacintoshInit -- - * - * This procedure calls Mac specific initialization calls. Most of - * these calls must be made as soon as possible in the startup - * process. - * - * Results: - * Returns TCL_OK if everything went fine. If it didn't the - * application should probably fail. - * - * Side effects: - * Inits the application. - * - *---------------------------------------------------------------------- - */ - -int -Togl_MacInit(void) -{ - int i; - long result, mask = 0x0700; /* mask = system 7.x */ - -# if GENERATING68K && !GENERATINGCFM - SetApplLimit(GetApplLimit() - (TK_MAC_68K_STACK_GROWTH)); -# endif - MaxApplZone(); - for (i = 0; i < 4; i++) { - (void) MoreMasters(); - } - - /* - * Tk needs us to set the qd pointer it uses. This is needed - * so Tk doesn't have to assume the availability of the qd global - * variable. Which in turn allows Tk to be used in code resources. - */ - tcl_macQdPtr = &qd; - - /* - * If appearance is present, then register Tk as an Appearance client - * This means that the mapping from non-Appearance to Appearance cdefs - * will be done for Tk regardless of the setting in the Appearance - * control panel. - */ - if (TkMacHaveAppearance()) { - RegisterAppearanceClient(); - } - - InitGraf(&tcl_macQdPtr->thePort); - InitFonts(); - InitWindows(); - InitMenus(); - InitDialogs((long) NULL); - InitCursor(); - - /* - * Make sure we are running on system 7 or higher - */ - if ((NGetTrapAddress(_Gestalt, ToolTrap) == - NGetTrapAddress(_Unimplemented, ToolTrap)) - || (((Gestalt(gestaltSystemVersion, &result) != noErr) - || (result < mask)))) { - panic("Tcl/Tk requires System 7 or higher."); - } - - /* - * Make sure we have color quick draw - * (this means we can't run on 68000 macs) - */ - if (((Gestalt(gestaltQuickdrawVersion, &result) != noErr) - || (result < gestalt32BitQD13))) { - panic("Tk requires Color QuickDraw."); - } - - FlushEvents(everyEvent, 0); - SetEventMask(everyEvent); - - Tcl_MacSetEventProc(TkMacConvertEvent); - return TCL_OK; -} - -int -Togl_MacSetupMainInterp(Tcl_Interp *interp) -{ - TkMacInitAppleEvents(interp); - TkMacInitMenus(interp); - return TCL_OK; -} - -#endif /* TOGL_AGL_CLASSIC */ diff --git a/ng/Togl-1.7/togl.h b/ng/Togl-1.7/togl.h deleted file mode 100644 index 0135c99f..00000000 --- a/ng/Togl-1.7/togl.h +++ /dev/null @@ -1,244 +0,0 @@ -/* $Id: togl.h,v 1.28 2005/10/27 07:45:48 gregcouch Exp $ */ - -/* vi:set sw=4: */ - -/* - * Togl - a Tk OpenGL widget - * - * Copyright (C) 1996-1998 Brian Paul and Ben Bederson - * See the LICENSE file for copyright details. - */ - - -#ifndef TOGL_H -# define TOGL_H - -#if !defined TOGL_X11 && !defined TOGL_WGL && !defined TOGL_AGL_CLASSIC && !defined TOGL_AGL -# include "togl_ws.h" -#endif - -# ifdef TOGL_WGL -# define WIN32_LEAN_AND_MEAN -# include -# undef WIN32_LEAN_AND_MEAN -# if defined(_MSC_VER) -# define DllEntryPoint DllMain -# endif -# endif - -# ifdef _WIN32 -# define TOGL_EXTERN __declspec(dllexport) extern -# else -# define TOGL_EXTERN extern -# endif /* _WIN32 */ - -# ifdef TOGL_AGL_CLASSIC -# ifndef MAC_TCL -# define MAC_TCL 1 -# endif -# endif - -# ifdef TOGL_AGL -# ifndef MAC_OSX_TCL -# define MAC_OSX_TCL 1 -# endif -# ifndef MAC_OSX_TK -# define MAC_OSX_TK 1 -# endif -# endif - -# include -# include -# if defined(TOGL_AGL) || defined(TOGL_AGL_CLASSIC) -# include -# else -# include -# endif - -# ifdef __sgi -# include -# include -# endif - -# ifndef CONST84 -# define CONST84 -# endif - -# ifndef NULL -# define NULL 0 -# endif - -# ifndef TOGL_USE_FONTS -# define TOGL_USE_FONTS 1 /* needed for demos */ -# endif - -# ifdef __cplusplus -/* *INDENT-OFF* */ -extern "C" { -/* *INDENT-ON* */ -# endif - -# define TOGL_VERSION "1.7" -# define TOGL_MAJOR_VERSION 1 -# define TOGL_MINOR_VERSION 7 - -/* - * "Standard" fonts which can be specified to Togl_LoadBitmapFont() - */ -# define TOGL_BITMAP_8_BY_13 ((char *) 1) -# define TOGL_BITMAP_9_BY_15 ((char *) 2) -# define TOGL_BITMAP_TIMES_ROMAN_10 ((char *) 3) -# define TOGL_BITMAP_TIMES_ROMAN_24 ((char *) 4) -# define TOGL_BITMAP_HELVETICA_10 ((char *) 5) -# define TOGL_BITMAP_HELVETICA_12 ((char *) 6) -# define TOGL_BITMAP_HELVETICA_18 ((char *) 7) - -/* - * Normal and overlay plane constants - */ -# define TOGL_NORMAL 1 -# define TOGL_OVERLAY 2 - -struct Togl; -typedef struct Togl Togl; - -typedef void (Togl_Callback) (Togl *togl); -typedef int (Togl_CmdProc) (Togl *togl, int argc, CONST84 char *argv[]); - -TOGL_EXTERN int Togl_Init(Tcl_Interp *interp); - -/* - * Default/initial callback setup functions - */ - -TOGL_EXTERN void Togl_CreateFunc(Togl_Callback *proc); -TOGL_EXTERN void Togl_DisplayFunc(Togl_Callback *proc); -TOGL_EXTERN void Togl_ReshapeFunc(Togl_Callback *proc); -TOGL_EXTERN void Togl_DestroyFunc(Togl_Callback *proc); -TOGL_EXTERN void Togl_TimerFunc(Togl_Callback *proc); -TOGL_EXTERN void Togl_ResetDefaultCallbacks(void); - -/* - * Change callbacks for existing widget - */ - -TOGL_EXTERN void Togl_SetCreateFunc(Togl *togl, Togl_Callback *proc); -TOGL_EXTERN void Togl_SetDisplayFunc(Togl *togl, Togl_Callback *proc); -TOGL_EXTERN void Togl_SetReshapeFunc(Togl *togl, Togl_Callback *proc); -TOGL_EXTERN void Togl_SetDestroyFunc(Togl *togl, Togl_Callback *proc); -TOGL_EXTERN void Togl_SetTimerFunc(Togl *togl, Togl_Callback *proc); - -/* - * Miscellaneous - */ - -TOGL_EXTERN int Togl_Configure(Tcl_Interp *interp, Togl *togl, - int argc, const char *argv[], int flags); -TOGL_EXTERN void Togl_MakeCurrent(const Togl *togl); -TOGL_EXTERN void Togl_CreateCommand(char *cmd_name, Togl_CmdProc *cmd_proc); -TOGL_EXTERN void Togl_PostRedisplay(Togl *togl); -TOGL_EXTERN void Togl_SwapBuffers(const Togl *togl); - -/* - * Query functions - */ - -TOGL_EXTERN const char *Togl_Ident(const Togl *togl); -TOGL_EXTERN int Togl_Width(const Togl *togl); -TOGL_EXTERN int Togl_Height(const Togl *togl); -TOGL_EXTERN Tcl_Interp *Togl_Interp(const Togl *togl); -TOGL_EXTERN Tk_Window Togl_TkWin(const Togl *togl); - -/* - * Color Index mode - */ - -TOGL_EXTERN unsigned long Togl_AllocColor(const Togl *togl, float red, - float green, float blue); -TOGL_EXTERN void Togl_FreeColor(const Togl *togl, unsigned long index); -TOGL_EXTERN void Togl_SetColor(const Togl *togl, unsigned long index, - float red, float green, float blue); - -# if TOGL_USE_FONTS == 1 -/* - * Bitmap fonts - */ - -TOGL_EXTERN GLuint Togl_LoadBitmapFont(const Togl *togl, const char *fontname); -TOGL_EXTERN void Togl_UnloadBitmapFont(const Togl *togl, GLuint fontbase); - -# endif -/* - * Overlay functions - */ - -TOGL_EXTERN void Togl_UseLayer(Togl *togl, int layer); -TOGL_EXTERN void Togl_ShowOverlay(Togl *togl); -TOGL_EXTERN void Togl_HideOverlay(Togl *togl); -TOGL_EXTERN void Togl_PostOverlayRedisplay(Togl *togl); -TOGL_EXTERN void Togl_OverlayDisplayFunc(Togl_Callback *proc); -TOGL_EXTERN int Togl_ExistsOverlay(const Togl *togl); -TOGL_EXTERN int Togl_GetOverlayTransparentValue(const Togl *togl); -TOGL_EXTERN int Togl_IsMappedOverlay(const Togl *togl); -TOGL_EXTERN unsigned long Togl_AllocColorOverlay(const Togl *togl, - float red, float green, float blue); -TOGL_EXTERN void Togl_FreeColorOverlay(const Togl *togl, unsigned long index); - -/* - * User client data - */ - -TOGL_EXTERN void Togl_ClientData(ClientData clientData); -TOGL_EXTERN ClientData Togl_GetClientData(const Togl *togl); -TOGL_EXTERN void Togl_SetClientData(Togl *togl, ClientData clientData); - -# ifdef TOGL_X11 -/* - * X11-only commands. - * Contributed by Miguel A. De Riera Pasenau (miguel@DALILA.UPC.ES) - */ - -TOGL_EXTERN Display *Togl_Display(const Togl *togl); -TOGL_EXTERN Screen *Togl_Screen(const Togl *togl); -TOGL_EXTERN int Togl_ScreenNumber(const Togl *togl); -TOGL_EXTERN Colormap Togl_Colormap(const Togl *togl); - -# endif -# ifdef __sgi -/* - * SGI stereo-only commands. - * Contributed by Ben Evans (Ben.Evans@anusf.anu.edu.au) - */ - -TOGL_EXTERN void Togl_OldStereoDrawBuffer(GLenum mode); -TOGL_EXTERN void Togl_OldStereoClear(GLbitfield mask); -# endif - -TOGL_EXTERN void Togl_StereoFrustum(GLfloat left, GLfloat right, GLfloat bottom, - GLfloat top, GLfloat near, GLfloat far, GLfloat eyeDist, - GLfloat eyeOffset); - -/* - * Generate EPS file. - * Contributed by Miguel A. De Riera Pasenau (miguel@DALILA.UPC.ES) - */ - -TOGL_EXTERN int Togl_DumpToEpsFile(const Togl *togl, const char *filename, - int inColor, void (*user_redraw) (const Togl *)); - -# ifdef TOGL_AGL_CLASSIC -/* - * Mac-specific setup functions - */ -extern int Togl_MacInit(void); -extern int Togl_MacSetupMainInterp(Tcl_Interp *interp); -# endif - -# ifdef __cplusplus -/* *INDENT-OFF* */ -} -/* *INDENT-ON* */ -# endif - - -#endif diff --git a/ng/Togl-1.7/togl_ws.h.in b/ng/Togl-1.7/togl_ws.h.in deleted file mode 100644 index 3a01a9c3..00000000 --- a/ng/Togl-1.7/togl_ws.h.in +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef TOGL_WS_H -# define TOGL_WS_H - -/* define windowing system togl is compiled with */ -# define @TOGL_WINDOWINGSYSTEM@ - -#endif diff --git a/ng/Togl-1.7/tree2.rgba b/ng/Togl-1.7/tree2.rgba deleted file mode 100644 index 67b02799..00000000 Binary files a/ng/Togl-1.7/tree2.rgba and /dev/null differ diff --git a/ng/Togl2.1/togl.c b/ng/Togl2.1/togl.c index 35ab8356..78faa6c1 100644 --- a/ng/Togl2.1/togl.c +++ b/ng/Togl2.1/togl.c @@ -22,6 +22,8 @@ # endif #endif +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + #define USE_TOGL_STUB_PROCS #include "togl.h" diff --git a/ng/Togl2.1/toglProcAddr.c b/ng/Togl2.1/toglProcAddr.c index 2e72fbea..500ffa1b 100644 --- a/ng/Togl2.1/toglProcAddr.c +++ b/ng/Togl2.1/toglProcAddr.c @@ -10,6 +10,9 @@ * See the LICENSE file for copyright details. */ +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + + #include "togl.h" #if defined(TOGL_OSMESA) || defined(TOGL_WGL) diff --git a/ng/dialog.tcl b/ng/dialog.tcl index 3d118574..482e333d 100644 --- a/ng/dialog.tcl +++ b/ng/dialog.tcl @@ -1214,6 +1214,12 @@ proc viewingoptionsdialog { } { ttk::checkbutton $f.showelementnumbers -text "Show Element-numbers" \ -variable viewoptions.drawelementnumbers \ -command { Ng_SetVisParameters; redraw } + ttk::checkbutton $f.showsegmentnumbers -text "Show Segment-numbers" \ + -variable viewoptions.drawsegmentnumbers \ + -command { Ng_SetVisParameters; redraw } + ttk::checkbutton $f.showsurfaceelementnumbers -text "Show Surfaceelement-numbers" \ + -variable viewoptions.drawsurfaceelementnumbers \ + -command { Ng_SetVisParameters; redraw } # label $f.showdomainlab -text "Domain Surface" # scale $f.showdomain -orient horizontal -length 100 -from 0 -to 50 \ @@ -1281,7 +1287,8 @@ proc viewingoptionsdialog { } { grid $f.showfilledtrigs $f.showoutline -sticky nw grid $f.showedges $f.showbadels -sticky nw grid $f.showpointnumbers $f.showedgenumbers -sticky nw - grid $f.showfacenumbers $f.showelementnumbers -sticky nw + grid $f.showfacenumbers $f.showelementnumbers -sticky nw + grid $f.showsurfaceelementnumbers $f.showsegmentnumbers -sticky nw grid $f.showmetispartition $f.showidentified -sticky nw grid $f.showcolor $f.showpyramids -sticky nw grid $f.showprisms $f.showhexes -sticky nw diff --git a/ng/drawing.tcl b/ng/drawing.tcl index 3bc7c652..14d5d33b 100644 --- a/ng/drawing.tcl +++ b/ng/drawing.tcl @@ -27,14 +27,6 @@ if { [Ng_GetToglVersion] == 2 } { # puts "have Togl 2.1" set toglok 1 } -} { - # Togl 1.7 - if {[catch {togl .ndraw -width 400 -height 300 -rgba true -double true -depth true -privatecmap false -stereo false -indirect false }] } { - puts "no OpenGL" - } { - # puts "have Togl 1.7" - set toglok 1 - } } if { $toglok == 1} { diff --git a/ng/gui.cpp b/ng/gui.cpp index 88927aad..8b702376 100644 --- a/ng/gui.cpp +++ b/ng/gui.cpp @@ -1,8 +1,13 @@ #include -#include #include +#include #include +using std::string; +using std::endl; +using std::cout; +using std::cerr; + namespace netgen { NGCORE_API_EXPORT Flags parameters; diff --git a/ng/menustat.tcl b/ng/menustat.tcl index 5be804c2..cd5d3a02 100644 --- a/ng/menustat.tcl +++ b/ng/menustat.tcl @@ -222,9 +222,15 @@ loadmeshinifile; +set meshimportformats [Ng_GetImportFormats] .ngmenu.file add command -label "Import Mesh..." \ -command { + foreach importformat $meshimportformats { + if { [lindex $importformat 0] == $importfiletype } { + set extension [lindex $importformat 1] + } + } set types { {"Neutral format" {.mesh .emt} } {"Surface mesh format" {.surf} } @@ -235,9 +241,9 @@ loadmeshinifile; {"Pro/ENGINEER neutral format" {.fnf} } {"CFD General Notation System" {.cgns} } } - set file [tk_getOpenFile -filetypes $types ] + set file [tk_getOpenFile -filetypes $meshimportformats -typevariable importfiletype] if {$file != ""} { - Ng_ImportMesh $file + Ng_ImportMesh $file $importfiletype set selectvisual mesh Ng_SetVisParameters redraw diff --git a/ng/ngappinit.cpp b/ng/ngappinit.cpp index 5fa8c248..f6b4be0a 100644 --- a/ng/ngappinit.cpp +++ b/ng/ngappinit.cpp @@ -9,15 +9,14 @@ #include #include #include - -#ifdef PARALLEL -#include - -// extern void ParallelRun(); -#endif +#include #include "../libsrc/interface/writeuser.hpp" +#ifdef NETGEN_PYTHON +#include +#endif + namespace netgen { DLL_HEADER extern Flags parameters; @@ -33,6 +32,11 @@ using netgen::verbose; using netgen::NgArray; using netgen::RegisterUserFormats; +using std::string; +using std::endl; +using std::cout; +using std::cerr; +using std::ofstream; @@ -60,25 +64,6 @@ int main(int argc, char ** argv) { netgen::netgen_executable_started = true; -#ifdef PARALLEL - int mpi_required = MPI_THREAD_MULTIPLE; -#ifdef VTRACE - mpi_required = MPI_THREAD_SINGLE; -#endif - int mpi_provided; - MPI_Init_thread(&argc, &argv, mpi_required, &mpi_provided); - - MPI_Comm_size(MPI_COMM_WORLD, &netgen::ntasks); - MPI_Comm_rank(MPI_COMM_WORLD, &netgen::id); - - if(netgen::ntasks!=1) - throw ngcore::Exception("Netgen GUI cannot run MPI-parallel"); - - // MPI_COMM_WORLD is just a local communicator - // netgen::ng_comm = ngcore::NgMPI_Comm{MPI_COMM_WORLD, false}; - -#endif - if ( netgen::id == 0 ) { cout << "NETGEN-" << netgen::netgen_version << endl; @@ -105,11 +90,6 @@ int main(int argc, char ** argv) #ifdef DEBUG cout << "You are running the debug version !" << endl; #endif - - -#ifdef PARALLEL - cout << "Including MPI version " << MPI_VERSION << '.' << MPI_SUBVERSION << endl; -#endif } @@ -275,18 +255,13 @@ int main(int argc, char ** argv) // start event-loop Tk_MainLoop(); Tcl_DeleteInterp (myinterp); +#ifdef NETGEN_PYTHON + py::gil_scoped_acquire ensure_gil; +#endif + Tcl_Exit(0); } -#ifdef PARALLEL - else - { - // ParallelRun(); - MPI_Finalize(); - } - -#endif - return 0; } diff --git a/ng/ngpkg.cpp b/ng/ngpkg.cpp index 12bdeaef..4a056d1a 100644 --- a/ng/ngpkg.cpp +++ b/ng/ngpkg.cpp @@ -9,6 +9,7 @@ The interface between the GUI and the netgen library #include #include +#include "../libsrc/meshing/boundarylayer.hpp" #include @@ -194,7 +195,7 @@ namespace netgen if(mesh->GetGeometry()) ng_geometry = mesh->GetGeometry(); } - catch (NgException e) + catch (const NgException & e) { PrintMessage (3, e.What()); return TCL_ERROR; @@ -269,7 +270,7 @@ namespace netgen geometry -> LoadSurfaces(infile); } } - catch (NgException e) + catch (const NgException & e) { PrintMessage (3, e.What()); return TCL_ERROR; @@ -282,17 +283,33 @@ namespace netgen } + int Ng_GetImportFormats (ClientData clientData, + Tcl_Interp * interp, + int argc, tcl_const char *argv[]) + { + ostringstream fstr; + UserFormatRegister::IterateFormats([&](auto & entry) { + fstr << "{ {" << entry.format << "} {" << entry.extensions[0]; + for(auto ext : entry.extensions.Range(1, entry.extensions.Size())) + fstr << ' ' << ext; + fstr << "} }\n"; + }, true, false); + + Tcl_SetResult (interp, const_cast(fstr.str().c_str()), TCL_VOLATILE); + return TCL_OK; + } + int Ng_GetExportFormats (ClientData clientData, Tcl_Interp * interp, int argc, tcl_const char *argv[]) { - NgArray userformats; - NgArray extensions; - RegisterUserFormats (userformats, extensions); - ostringstream fstr; - for (int i = 1; i <= userformats.Size(); i++) - fstr << "{ {" << userformats.Get(i) << "} {" << extensions.Get(i) << "} }\n"; + UserFormatRegister::IterateFormats([&](auto & entry) { + fstr << "{ {" << entry.format << "} {" << entry.extensions[0]; + for(auto ext : entry.extensions.Range(1, entry.extensions.Size())) + fstr << ' ' << ext; + fstr << "} }\n"; + }, false, true); Tcl_SetResult (interp, const_cast(fstr.str().c_str()), TCL_VOLATILE); return TCL_OK; @@ -333,11 +350,12 @@ namespace netgen int argc, tcl_const char *argv[]) { const string filename (argv[1]); + const string format (argv[2]); PrintMessage (1, "import mesh from ", filename); mesh = make_shared(); - ReadFile (*mesh, filename); + ReadUserFormat (*mesh, filename, format); PrintMessage (2, mesh->GetNP(), " Points, ", mesh->GetNE(), " Elements."); @@ -534,7 +552,7 @@ namespace netgen } } - catch (NgException e) + catch (const NgException & e) { Tcl_SetResult (interp, const_cast (e.What().c_str()), TCL_VOLATILE); return TCL_ERROR; @@ -565,7 +583,7 @@ namespace netgen { ng_geometry -> Save (string (cfilename)); } - catch (NgException e) + catch (const NgException & e) { Tcl_SetResult (interp, const_cast (e.What().c_str()), TCL_VOLATILE); return TCL_ERROR; @@ -1091,7 +1109,7 @@ namespace netgen // Use an array to support creation of boundary // layers for multiple surfaces in the future... - Array surfid; + std::vector surfid; int surfinp = 0; int prismlayers = 1; double hfirst = 0.01; @@ -1102,13 +1120,13 @@ namespace netgen { cout << "Enter Surface ID (-1 to end list): "; cin >> surfinp; - if(surfinp >= 0) surfid.Append(surfinp); + if(surfinp >= 0) surfid.push_back(surfinp); } - cout << "Number of surfaces entered = " << surfid.Size() << endl; + cout << "Number of surfaces entered = " << surfid.size() << endl; cout << "Selected surfaces are:" << endl; - for(auto i : Range(surfid)) + for(auto i : Range(surfid.size())) cout << "Surface " << i << ": " << surfid[i] << endl; cout << endl << "Enter number of prism layers: "; @@ -1124,15 +1142,17 @@ namespace netgen if(growthfactor <= 0.0) growthfactor = 0.5; BoundaryLayerParameters blp; - blp.surfid = surfid; + blp.boundary = surfid; + std::vector thickness; for(auto i : Range(prismlayers)) { auto layer = i+1; if(growthfactor == 1) - blp.heights.Append(layer * hfirst); + thickness.push_back(layer * hfirst); else - blp.heights.Append(hfirst * (pow(growthfactor, (layer+1))-1)/(growthfactor-1)); + thickness.push_back(hfirst * (pow(growthfactor, (layer+1))-1)/(growthfactor-1)); } + blp.thickness = thickness; GenerateBoundaryLayer (*mesh, blp); return TCL_OK; } @@ -1421,7 +1441,7 @@ namespace netgen PrintMessage (1, "Meshing done, time = ", GetTime(), " sec"); } - catch (NgException e) + catch (const NgException & e) { cout << e.What() << endl; } @@ -2061,7 +2081,6 @@ namespace netgen return TCL_ERROR; const char * filename = Tcl_GetString(argv[2]); - int len = strlen(filename); int w = Togl_PixelScale(togl)*Togl_Width (togl); int h = Togl_PixelScale(togl)*Togl_Height (togl); @@ -2071,6 +2090,7 @@ namespace netgen glReadPixels (0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, &buffer[0]); #ifdef JPEGLIB + int len = strlen(filename); if (strcmp ("jpg", filename+len-3) == 0) { cout << "Snapshot to file '" << filename << "'" << endl; @@ -2113,19 +2133,15 @@ namespace netgen #endif // JPEGLIB { string command; - string filename2; + std::filesystem::path filepath(filename); - filename2 = filename; + bool need_conversion = filepath.extension() != ".ppm"; + if (need_conversion) + filepath += ".ppm"; - if(filename2.substr(len-3) != ".ppm") - filename2 += ".ppm"; + cout << IM(3) << "Snapshot to file '" << filepath.string() << endl; - cout << "Snapshot to file '" << filename << endl; - - // int w = Togl_Width (togl); - // int h = Togl_Height (togl); - - ofstream outfile(filename2); + ofstream outfile(filepath); outfile << "P6" << endl << "# CREATOR: Netgen" << endl << w << " " << h << endl @@ -2136,12 +2152,10 @@ namespace netgen outfile.put (buffer[k+3*j+3*w*(h-i-1)]); outfile << flush; - if (filename2 == string(filename)) - return TCL_OK; - else + if (need_conversion) { // convert image file (Unix/Linux only): - command = string("convert -quality 100 ") + filename2 + " " + filename; + command = string("convert -quality 100 ") + filepath.string() + " " + filename; int err = system(command.c_str()); if (err != 0) @@ -2150,16 +2164,10 @@ namespace netgen return TCL_ERROR; } - command = string("rm ") + filename2; - err = system(command.c_str()); - - if (err != 0) - { - Tcl_SetResult (Togl_Interp(togl), (char*)"Cannot delete temporary file", TCL_VOLATILE); - return TCL_ERROR; - } - return TCL_OK; + std::filesystem::remove(filepath); } + + return TCL_OK; } } @@ -2644,6 +2652,10 @@ void PlayAnimFile(const char* name, int speed, int maxcnt) atoi (Tcl_GetVar (interp, "::viewoptions.drawfacenumbers", TCL_GLOBAL_ONLY)); vispar.drawelementnumbers = atoi (Tcl_GetVar (interp, "::viewoptions.drawelementnumbers", TCL_GLOBAL_ONLY)); + vispar.drawsurfaceelementnumbers = + atoi (Tcl_GetVar (interp, "::viewoptions.drawsurfaceelementnumbers", TCL_GLOBAL_ONLY)); + vispar.drawsegmentnumbers = + atoi (Tcl_GetVar (interp, "::viewoptions.drawsegmentnumbers", TCL_GLOBAL_ONLY)); vispar.drawdomainsurf = atoi (Tcl_GetVar (interp, "::viewoptions.drawdomainsurf", TCL_GLOBAL_ONLY)); @@ -2873,6 +2885,10 @@ void PlayAnimFile(const char* name, int speed, int maxcnt) (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); + Tcl_CreateCommand (interp, "Ng_GetImportFormats", Ng_GetImportFormats, + (ClientData)NULL, + (Tcl_CmdDeleteProc*) NULL); + Tcl_CreateCommand (interp, "Ng_GetExportFormats", Ng_GetExportFormats, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL); diff --git a/ng/onetcl.cpp b/ng/onetcl.cpp index d25549e4..7e5254c6 100644 --- a/ng/onetcl.cpp +++ b/ng/onetcl.cpp @@ -145,6 +145,8 @@ DLL_HEADER const char * ngscript[] = {"" ,"set viewoptions.drawedgenumbers 0\n" ,"set viewoptions.drawfacenumbers 0\n" ,"set viewoptions.drawelementnumbers 0\n" +,"set viewoptions.drawsegmentnumbers 0\n" +,"set viewoptions.drawsurfaceelementnumbers 0\n" ,"set viewoptions.drawdomainsurf 0\n" ,"set viewoptions.drawededges 1\n" ,"set viewoptions.drawedpoints 1\n" @@ -248,6 +250,7 @@ DLL_HEADER const char * ngscript[] = {"" ,"set status_filename 0\n" ,"set status_tetqualclasses \"10 20 30 40 10 20 30 40 10 20 30 40 10 20 30 40 10 20 30 40\"\n" ,"set exportfiletype \"Neutral Format\"\n" +,"set importfiletype \"Neutral Format\"\n" ,"set preproc.facenr 0\n" ,"set preproc.selectmode query\n" ,"set preproc.numtrig 0\n" @@ -858,8 +861,14 @@ DLL_HEADER const char * ngscript[] = {"" ,"Ng_ReadStatus;\n" ,"}\n" ,"}\n" +,"set meshimportformats [Ng_GetImportFormats]\n" ,".ngmenu.file add command -label \"Import Mesh...\" \\\n" ,"-command {\n" +,"foreach importformat $meshimportformats {\n" +,"if { [lindex $importformat 0] == $importfiletype } {\n" +,"set extension [lindex $importformat 1]\n" +,"}\n" +,"}\n" ,"set types {\n" ,"{\"Neutral format\" {.mesh .emt} }\n" ,"{\"Surface mesh format\" {.surf} }\n" @@ -870,9 +879,9 @@ DLL_HEADER const char * ngscript[] = {"" ,"{\"Pro/ENGINEER neutral format\" {.fnf} }\n" ,"{\"CFD General Notation System\" {.cgns} }\n" ,"}\n" -,"set file [tk_getOpenFile -filetypes $types ]\n" +,"set file [tk_getOpenFile -filetypes $meshimportformats -typevariable importfiletype]\n" ,"if {$file != \"\"} {\n" -,"Ng_ImportMesh $file\n" +,"Ng_ImportMesh $file $importfiletype\n" ,"set selectvisual mesh\n" ,"Ng_SetVisParameters\n" ,"redraw\n" @@ -2183,6 +2192,12 @@ DLL_HEADER const char * ngscript[] = {"" ,"ttk::checkbutton $f.showelementnumbers -text \"Show Element-numbers\" \\\n" ,"-variable viewoptions.drawelementnumbers \\\n" ,"-command { Ng_SetVisParameters; redraw }\n" +,"ttk::checkbutton $f.showsegmentnumbers -text \"Show Segment-numbers\" \\\n" +,"-variable viewoptions.drawsegmentnumbers \\\n" +,"-command { Ng_SetVisParameters; redraw }\n" +,"ttk::checkbutton $f.showsurfaceelementnumbers -text \"Show Surfaceelement-numbers\" \\\n" +,"-variable viewoptions.drawsurfaceelementnumbers \\\n" +,"-command { Ng_SetVisParameters; redraw }\n" ,"ttk::frame $f.frametets\n" ,"ttk::checkbutton $f.frametets.showtets -text \"\" \\\n" ,"-variable viewoptions.drawtets \\\n" @@ -2212,6 +2227,7 @@ DLL_HEADER const char * ngscript[] = {"" ,"grid $f.showedges $f.showbadels -sticky nw\n" ,"grid $f.showpointnumbers $f.showedgenumbers -sticky nw\n" ,"grid $f.showfacenumbers $f.showelementnumbers -sticky nw\n" +,"grid $f.showsurfaceelementnumbers $f.showsegmentnumbers -sticky nw\n" ,"grid $f.showmetispartition $f.showidentified -sticky nw\n" ,"grid $f.showcolor $f.showpyramids -sticky nw\n" ,"grid $f.showprisms $f.showhexes -sticky nw\n" diff --git a/ng/togl_1_7.h b/ng/togl_1_7.h deleted file mode 100644 index 0135c99f..00000000 --- a/ng/togl_1_7.h +++ /dev/null @@ -1,244 +0,0 @@ -/* $Id: togl.h,v 1.28 2005/10/27 07:45:48 gregcouch Exp $ */ - -/* vi:set sw=4: */ - -/* - * Togl - a Tk OpenGL widget - * - * Copyright (C) 1996-1998 Brian Paul and Ben Bederson - * See the LICENSE file for copyright details. - */ - - -#ifndef TOGL_H -# define TOGL_H - -#if !defined TOGL_X11 && !defined TOGL_WGL && !defined TOGL_AGL_CLASSIC && !defined TOGL_AGL -# include "togl_ws.h" -#endif - -# ifdef TOGL_WGL -# define WIN32_LEAN_AND_MEAN -# include -# undef WIN32_LEAN_AND_MEAN -# if defined(_MSC_VER) -# define DllEntryPoint DllMain -# endif -# endif - -# ifdef _WIN32 -# define TOGL_EXTERN __declspec(dllexport) extern -# else -# define TOGL_EXTERN extern -# endif /* _WIN32 */ - -# ifdef TOGL_AGL_CLASSIC -# ifndef MAC_TCL -# define MAC_TCL 1 -# endif -# endif - -# ifdef TOGL_AGL -# ifndef MAC_OSX_TCL -# define MAC_OSX_TCL 1 -# endif -# ifndef MAC_OSX_TK -# define MAC_OSX_TK 1 -# endif -# endif - -# include -# include -# if defined(TOGL_AGL) || defined(TOGL_AGL_CLASSIC) -# include -# else -# include -# endif - -# ifdef __sgi -# include -# include -# endif - -# ifndef CONST84 -# define CONST84 -# endif - -# ifndef NULL -# define NULL 0 -# endif - -# ifndef TOGL_USE_FONTS -# define TOGL_USE_FONTS 1 /* needed for demos */ -# endif - -# ifdef __cplusplus -/* *INDENT-OFF* */ -extern "C" { -/* *INDENT-ON* */ -# endif - -# define TOGL_VERSION "1.7" -# define TOGL_MAJOR_VERSION 1 -# define TOGL_MINOR_VERSION 7 - -/* - * "Standard" fonts which can be specified to Togl_LoadBitmapFont() - */ -# define TOGL_BITMAP_8_BY_13 ((char *) 1) -# define TOGL_BITMAP_9_BY_15 ((char *) 2) -# define TOGL_BITMAP_TIMES_ROMAN_10 ((char *) 3) -# define TOGL_BITMAP_TIMES_ROMAN_24 ((char *) 4) -# define TOGL_BITMAP_HELVETICA_10 ((char *) 5) -# define TOGL_BITMAP_HELVETICA_12 ((char *) 6) -# define TOGL_BITMAP_HELVETICA_18 ((char *) 7) - -/* - * Normal and overlay plane constants - */ -# define TOGL_NORMAL 1 -# define TOGL_OVERLAY 2 - -struct Togl; -typedef struct Togl Togl; - -typedef void (Togl_Callback) (Togl *togl); -typedef int (Togl_CmdProc) (Togl *togl, int argc, CONST84 char *argv[]); - -TOGL_EXTERN int Togl_Init(Tcl_Interp *interp); - -/* - * Default/initial callback setup functions - */ - -TOGL_EXTERN void Togl_CreateFunc(Togl_Callback *proc); -TOGL_EXTERN void Togl_DisplayFunc(Togl_Callback *proc); -TOGL_EXTERN void Togl_ReshapeFunc(Togl_Callback *proc); -TOGL_EXTERN void Togl_DestroyFunc(Togl_Callback *proc); -TOGL_EXTERN void Togl_TimerFunc(Togl_Callback *proc); -TOGL_EXTERN void Togl_ResetDefaultCallbacks(void); - -/* - * Change callbacks for existing widget - */ - -TOGL_EXTERN void Togl_SetCreateFunc(Togl *togl, Togl_Callback *proc); -TOGL_EXTERN void Togl_SetDisplayFunc(Togl *togl, Togl_Callback *proc); -TOGL_EXTERN void Togl_SetReshapeFunc(Togl *togl, Togl_Callback *proc); -TOGL_EXTERN void Togl_SetDestroyFunc(Togl *togl, Togl_Callback *proc); -TOGL_EXTERN void Togl_SetTimerFunc(Togl *togl, Togl_Callback *proc); - -/* - * Miscellaneous - */ - -TOGL_EXTERN int Togl_Configure(Tcl_Interp *interp, Togl *togl, - int argc, const char *argv[], int flags); -TOGL_EXTERN void Togl_MakeCurrent(const Togl *togl); -TOGL_EXTERN void Togl_CreateCommand(char *cmd_name, Togl_CmdProc *cmd_proc); -TOGL_EXTERN void Togl_PostRedisplay(Togl *togl); -TOGL_EXTERN void Togl_SwapBuffers(const Togl *togl); - -/* - * Query functions - */ - -TOGL_EXTERN const char *Togl_Ident(const Togl *togl); -TOGL_EXTERN int Togl_Width(const Togl *togl); -TOGL_EXTERN int Togl_Height(const Togl *togl); -TOGL_EXTERN Tcl_Interp *Togl_Interp(const Togl *togl); -TOGL_EXTERN Tk_Window Togl_TkWin(const Togl *togl); - -/* - * Color Index mode - */ - -TOGL_EXTERN unsigned long Togl_AllocColor(const Togl *togl, float red, - float green, float blue); -TOGL_EXTERN void Togl_FreeColor(const Togl *togl, unsigned long index); -TOGL_EXTERN void Togl_SetColor(const Togl *togl, unsigned long index, - float red, float green, float blue); - -# if TOGL_USE_FONTS == 1 -/* - * Bitmap fonts - */ - -TOGL_EXTERN GLuint Togl_LoadBitmapFont(const Togl *togl, const char *fontname); -TOGL_EXTERN void Togl_UnloadBitmapFont(const Togl *togl, GLuint fontbase); - -# endif -/* - * Overlay functions - */ - -TOGL_EXTERN void Togl_UseLayer(Togl *togl, int layer); -TOGL_EXTERN void Togl_ShowOverlay(Togl *togl); -TOGL_EXTERN void Togl_HideOverlay(Togl *togl); -TOGL_EXTERN void Togl_PostOverlayRedisplay(Togl *togl); -TOGL_EXTERN void Togl_OverlayDisplayFunc(Togl_Callback *proc); -TOGL_EXTERN int Togl_ExistsOverlay(const Togl *togl); -TOGL_EXTERN int Togl_GetOverlayTransparentValue(const Togl *togl); -TOGL_EXTERN int Togl_IsMappedOverlay(const Togl *togl); -TOGL_EXTERN unsigned long Togl_AllocColorOverlay(const Togl *togl, - float red, float green, float blue); -TOGL_EXTERN void Togl_FreeColorOverlay(const Togl *togl, unsigned long index); - -/* - * User client data - */ - -TOGL_EXTERN void Togl_ClientData(ClientData clientData); -TOGL_EXTERN ClientData Togl_GetClientData(const Togl *togl); -TOGL_EXTERN void Togl_SetClientData(Togl *togl, ClientData clientData); - -# ifdef TOGL_X11 -/* - * X11-only commands. - * Contributed by Miguel A. De Riera Pasenau (miguel@DALILA.UPC.ES) - */ - -TOGL_EXTERN Display *Togl_Display(const Togl *togl); -TOGL_EXTERN Screen *Togl_Screen(const Togl *togl); -TOGL_EXTERN int Togl_ScreenNumber(const Togl *togl); -TOGL_EXTERN Colormap Togl_Colormap(const Togl *togl); - -# endif -# ifdef __sgi -/* - * SGI stereo-only commands. - * Contributed by Ben Evans (Ben.Evans@anusf.anu.edu.au) - */ - -TOGL_EXTERN void Togl_OldStereoDrawBuffer(GLenum mode); -TOGL_EXTERN void Togl_OldStereoClear(GLbitfield mask); -# endif - -TOGL_EXTERN void Togl_StereoFrustum(GLfloat left, GLfloat right, GLfloat bottom, - GLfloat top, GLfloat near, GLfloat far, GLfloat eyeDist, - GLfloat eyeOffset); - -/* - * Generate EPS file. - * Contributed by Miguel A. De Riera Pasenau (miguel@DALILA.UPC.ES) - */ - -TOGL_EXTERN int Togl_DumpToEpsFile(const Togl *togl, const char *filename, - int inColor, void (*user_redraw) (const Togl *)); - -# ifdef TOGL_AGL_CLASSIC -/* - * Mac-specific setup functions - */ -extern int Togl_MacInit(void); -extern int Togl_MacSetupMainInterp(Tcl_Interp *interp); -# endif - -# ifdef __cplusplus -/* *INDENT-OFF* */ -} -/* *INDENT-ON* */ -# endif - - -#endif diff --git a/ng/variables.tcl b/ng/variables.tcl index cc7042fc..0ef9bdb2 100644 --- a/ng/variables.tcl +++ b/ng/variables.tcl @@ -112,6 +112,8 @@ set viewoptions.drawpointnumbers 0 set viewoptions.drawedgenumbers 0 set viewoptions.drawfacenumbers 0 set viewoptions.drawelementnumbers 0 +set viewoptions.drawsegmentnumbers 0 +set viewoptions.drawsurfaceelementnumbers 0 set viewoptions.drawdomainsurf 0 set viewoptions.drawededges 1 @@ -230,6 +232,7 @@ set status_filename 0 set status_tetqualclasses "10 20 30 40 10 20 30 40 10 20 30 40 10 20 30 40 10 20 30 40" set exportfiletype "Neutral Format" +set importfiletype "Neutral Format" set preproc.facenr 0 set preproc.selectmode query diff --git a/nglib/CMakeLists.txt b/nglib/CMakeLists.txt index 370b670b..cebdaeb7 100644 --- a/nglib/CMakeLists.txt +++ b/nglib/CMakeLists.txt @@ -5,9 +5,14 @@ if(USE_OCC) install(FILES nglib_occ.h DESTINATION ${NG_INSTALL_DIR_INCLUDE} COMPONENT netgen_devel) endif(USE_OCC) -target_link_libraries(nglib PUBLIC ngcore) +target_link_libraries(nglib PUBLIC ngcore PRIVATE ${ZLIB_LIBRARIES}) -target_link_libraries( nglib PRIVATE ${MPI_CXX_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${JPEG_LIBRARIES} ${MKL_LIBRARIES} ${ZLIB_LIBRARIES} ${OCC_LIBRARIES} netgen_cgns ) +if(EMSCRIPTEN) + target_include_directories(nglib PRIVATE $) + target_link_libraries(nglib PRIVATE $>) +else(EMSCRIPTEN) + target_link_libraries( nglib PRIVATE ${CMAKE_THREAD_LIBS_INIT} ${JPEG_LIBRARIES} ${MKL_LIBRARIES} occ_libs netgen_cgns ) +endif(EMSCRIPTEN) install(TARGETS nglib netgen_cgns ${NG_INSTALL_DIR}) install(FILES nglib.h DESTINATION ${NG_INSTALL_DIR_INCLUDE} COMPONENT netgen_devel) diff --git a/nglib/nglib.cpp b/nglib/nglib.cpp index d75bb529..e5bf7057 100644 --- a/nglib/nglib.cpp +++ b/nglib/nglib.cpp @@ -32,11 +32,6 @@ namespace netgen { -#ifdef PARALLEL -#include - -#endif - /* namespace netgen { @@ -410,7 +405,7 @@ namespace nglib NGLIB_API Ng_Surface_Element_Type Ng_GetSurfaceElement (Ng_Mesh * mesh, int num, int * pi, int * facenr) { - const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num); + const Element2d & el = ((Mesh*)mesh)->SurfaceElement(SurfaceElementIndex(num-1)); for (int i = 1; i <= el.GetNP(); i++) pi[i-1] = el.PNum(i); Ng_Surface_Element_Type et; @@ -443,7 +438,7 @@ namespace nglib NGLIB_API Ng_Volume_Element_Type Ng_GetVolumeElement (Ng_Mesh * mesh, int num, int * pi, int * domain) { - const Element & el = ((Mesh*)mesh)->VolumeElement(num); + const Element & el = ((Mesh*)mesh)->VolumeElement(ElementIndex(num-1)); for (int i = 1; i <= el.GetNP(); i++) pi[i-1] = el.PNum(i); Ng_Volume_Element_Type et; @@ -604,7 +599,7 @@ namespace nglib NGLIB_API Ng_Surface_Element_Type Ng_GetElement_2D (Ng_Mesh * mesh, int num, int * pi, int * matnum) { - const Element2d & el = ((Mesh*)mesh)->SurfaceElement(num); + const Element2d & el = ((Mesh*)mesh)->SurfaceElement(SurfaceElementIndex(num-1)); for (int i = 1; i <= el.GetNP(); i++) pi[i-1] = el.PNum(i); @@ -1322,7 +1317,7 @@ namespace netgen { #ifdef PARALLEL int id = 0; - MPI_Comm_rank(MPI_COMM_WORLD, &id); + NG_MPI_Comm_rank(NG_MPI_COMM_WORLD, &id); if (id != 0) return; #endif (*mycout) << s << flush; diff --git a/nglib/nglib_occ.cpp b/nglib/nglib_occ.cpp index 58ee4d8f..8b26081d 100644 --- a/nglib/nglib_occ.cpp +++ b/nglib/nglib_occ.cpp @@ -148,13 +148,15 @@ namespace nglib numpoints = me->GetNP(); // Initially set up only for surface meshing without any optimisation - int perfstepsend = MESHCONST_MESHSURFACE; + // int perfstepsend = MESHCONST_MESHSURFACE; // Check and if required, enable surface mesh optimisation step + /* if(mp->optsurfmeshenable) { - perfstepsend = MESHCONST_OPTSURFACE; + perfstepsend = MESHCONST_OPTSURFACE; } + */ occgeom->MeshSurface(*me, mparam); occgeom->OptimizeSurface(*me, mparam); diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index ccab5494..c95c4430 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -4,11 +4,18 @@ if(have_options) get_target_property(ngcore_compile_options ngcore INTERFACE_COMPILE_OPTIONS) endif(have_options) -configure_file(config_template.py ${CMAKE_CURRENT_BINARY_DIR}/config.py @ONLY) +configure_file(config/config_template.py ${CMAKE_CURRENT_BINARY_DIR}/config.py @ONLY) configure_file(version_template.py ${CMAKE_CURRENT_BINARY_DIR}/version.py @ONLY) install(FILES + config/__init__.py + config/__main__.py ${CMAKE_CURRENT_BINARY_DIR}/config.py + DESTINATION ${NG_INSTALL_DIR_PYTHON}/${NG_INSTALL_SUFFIX}/config/ + COMPONENT netgen + ) + +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/version.py __main__.py __init__.py meshing.py csg.py geom2d.py stl.py gui.py NgOCC.py occ.py @@ -26,13 +33,21 @@ install(FILES # build stub files for pybind11 packages if(BUILD_STUB_FILES) -execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import pybind11_stubgen; print(pybind11_stubgen.__file__)" OUTPUT_VARIABLE stubgen_path RESULT_VARIABLE pybind11_stubgen) +execute_process(COMMAND ${Python3_EXECUTABLE} -c "from importlib.metadata import version; print(version('pybind11-stubgen'))" OUTPUT_VARIABLE stubgen_version RESULT_VARIABLE pybind11_stubgen) if(pybind11_stubgen AND NOT ${pybind11_stubgen} EQUAL 0) message(WARNING "pybind11-stubgen not found, if you want to create stub files for better autocompletion support install it with pip.") else() - message("-- Found pybind11-stubgen: ${stubgen_path}") - install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m pybind11_stubgen --no-setup-py --ignore-invalid=all netgen)") - install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../stubs/netgen-stubs/ DESTINATION ${NG_INSTALL_DIR_PYTHON}/netgen/ COMPONENT netgen) + if(stubgen_version LESS "1.0") + message(WARNING "pybind11-stubgen version is too old, if you want to create stub files for better autocompletion support upgrade it with pip.") + else() + message("-- Found pybind11-stubgen version: ${stubgen_version}") + install(CODE "\ + set(ENV{PYTHONPATH} ${CMAKE_INSTALL_PREFIX}/${NG_INSTALL_DIR_PYTHON})\n \ + execute_process(COMMAND ${Python3_EXECUTABLE} -m pybind11_stubgen --ignore-all-errors netgen)\n \ + execute_process(COMMAND ${Python3_EXECUTABLE} -m pybind11_stubgen --ignore-all-errors pyngcore)\n \ + ") + install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../stubs/ DESTINATION ${NG_INSTALL_DIR_PYTHON} COMPONENT netgen) + endif() endif() endif(BUILD_STUB_FILES) diff --git a/python/__init__.py b/python/__init__.py index 527a2ed2..510b371a 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -1,10 +1,65 @@ import os import sys +from pathlib import Path from . import config _netgen_bin_dir=os.path.realpath(os.path.join(os.path.dirname(__file__),'..',config.NETGEN_PYTHON_RPATH_BIN)) _netgen_lib_dir=os.path.realpath(os.path.join(os.path.dirname(__file__),'..',config.NETGEN_PYTHON_RPATH)) +def load_occ_libs(): + try: + try: + import importlib.metadata as metadata + except ImportError: + import importlib_metadata as metadata + import ctypes + metadata.metadata('netgen-occt') + lib_names = [ + "TKOffset", + "TKFillet", + "TKDEIGES", + "TKBool", + "TKDESTEP", + "TKXSBase", + "TKDESTL", + "TKXCAF", + "TKVCAF", + "TKCAF", + "TKBO", + "TKPrim", + "TKLCAF", + "TKCDF", + "TKV3d", + "TKHLR", + "TKMesh", + "TKService", + "TKShHealing", + "TKTopAlgo", + "TKGeomAlgo", + "TKBRep", + "TKGeomBase", + "TKG3d", + "TKG2d", + "TKMath", + "TKDE", + "TKernel", + ] + lib_names.reverse() + lib_paths = {} + for f in metadata.files('netgen-occt'): + if f.match('*libTK*') or f.match("*.dll"): + p = f.locate() + name = p.name.split('.')[0].lower().replace("lib","") + lib_paths[name] = str(p) + for lib_name in lib_names: + p = lib_paths[lib_name.lower()] + ctypes.CDLL(p, mode=ctypes.RTLD_GLOBAL) + + except metadata.PackageNotFoundError: + pass + +load_occ_libs() + __diagnostics_template = """ Netgen diagnostics: sys.platform: {sys.platform} @@ -35,15 +90,25 @@ if sys.platform.startswith('win'): v = sys.version_info if v.major == 3 and v.minor >= 8: os.add_dll_directory(_netgen_bin_dir) - else: - os.environ['PATH'] += ';'+_netgen_bin_dir + os.environ['PATH'] += ';'+_netgen_bin_dir del sys del os +from pyngcore import Timer from . import libngpy from netgen.libngpy._meshing import _Redraw def Redraw(*args, **kwargs): return _Redraw(*args, **kwargs) + +def TimeFunction(func, name=None): + name = name or func.__qualname__ + timer = Timer(name) + def retfunc(*args,**kwargs): + with timer: + ret = func(*args, **kwargs) + return ret + return retfunc + diff --git a/python/config/__init__.py b/python/config/__init__.py new file mode 100644 index 00000000..27c9ec62 --- /dev/null +++ b/python/config/__init__.py @@ -0,0 +1 @@ +from .config import * diff --git a/python/config/__main__.py b/python/config/__main__.py new file mode 100644 index 00000000..6760d400 --- /dev/null +++ b/python/config/__main__.py @@ -0,0 +1,4 @@ +from .config import get_cmake_dir + +if __name__ == '__main__': + print(get_cmake_dir()) diff --git a/python/config_template.py b/python/config/config_template.py similarity index 85% rename from python/config_template.py rename to python/config/config_template.py index 38991567..153336b6 100644 --- a/python/config_template.py +++ b/python/config/config_template.py @@ -52,8 +52,17 @@ NETGEN_VERSION_TWEAK = "@NETGEN_VERSION_TWEAK@" NETGEN_VERSION_PATCH = "@NETGEN_VERSION_PATCH@" NETGEN_VERSION_HASH = "@NETGEN_VERSION_HASH@" -PYTHON_VERSION = "@PYTHON_VERSION@" -PYTHON_VERSION_MAJOR = "@PYTHON_VERSION_MAJOR@" -PYTHON_VERSION_MINOR = "@PYTHON_VERSION_MINOR@" +PYTHON_VERSION = "@Python3_VERSION@" +PYTHON_VERSION_MAJOR = "@Python3_VERSION_MAJOR@" +PYTHON_VERSION_MINOR = "@Python3_VERSION_MINOR@" version = NETGEN_VERSION_GIT + +def get_cmake_dir(): + import os.path as p + d_python = p.dirname(p.dirname(p.dirname(__file__))) + py_to_cmake = p.relpath( + NG_INSTALL_DIR_CMAKE, + NG_INSTALL_DIR_PYTHON + ) + return p.normpath(p.join(d_python,py_to_cmake)) diff --git a/python/meshing.py b/python/meshing.py index 9b912b66..72be7947 100644 --- a/python/meshing.py +++ b/python/meshing.py @@ -1,4 +1,5 @@ from .libngpy._meshing import * +from pyngcore import MPI_Comm class _MeshsizeObject: @property diff --git a/python/occ.py b/python/occ.py index 666c91ed..38d313ef 100644 --- a/python/occ.py +++ b/python/occ.py @@ -14,7 +14,7 @@ if not USE_OCC: raise ImportError("Netgen was not built with Opencascade support") from .libngpy._NgOCC import * -from .meshing import meshsize +from .meshing import meshsize, IdentificationType gp_Ax3 = Axes diff --git a/python/read_gmsh.py b/python/read_gmsh.py index 23a7ec52..1b57144e 100644 --- a/python/read_gmsh.py +++ b/python/read_gmsh.py @@ -22,7 +22,10 @@ def ReadGmsh(filename): pointmap = {} facedescriptormap = {} - namemap = { 0 : "default" } + namemap = { 0 : { 0 : "default" }, + 1: { 0 : "default" }, + 2: { 0 : "default" }, + 3: { 0 : "default" } } materialmap = {} bbcmap = {} @@ -80,7 +83,7 @@ def ReadGmsh(filename): for i in range(numnames): f.readline line = f.readline() - namemap[int(line.split()[1])] = line.split()[2][1:-1] + namemap[int(line.split()[0])][int(line.split()[1])] = line.split()[2][1:-1] if line.split()[0] == "$Nodes": num = int(f.readline().split()[0]) @@ -115,7 +118,7 @@ def ReadGmsh(filename): else: index = len(bbcmap) + 1 if len(namemap): - mesh.SetCD2Name(index, namemap[tags[0]]) + mesh.SetCD2Name(index, namemap[1][tags[0]]) else: mesh.SetCD2Name(index, "line" + str(tags[1])) bbcmap[tags[1]] = index @@ -127,7 +130,7 @@ def ReadGmsh(filename): index = len(facedescriptormap) + 1 fd = FaceDescriptor(bc=index) if len(namemap): - fd.bcname = namemap[tags[0]] + fd.bcname = namemap[1][tags[0]] else: fd.bcname = 'line' + str(tags[1]) mesh.SetBCName(index - 1, fd.bcname) @@ -139,7 +142,7 @@ def ReadGmsh(filename): else: index = len(materialmap) + 1 if len(namemap): - mesh.SetMaterial(index, namemap[tags[0]]) + mesh.SetMaterial(index, namemap[1][tags[0]]) else: mesh.SetMaterial(index, "line" + str(tags[1])) materialmap[tags[1]] = index @@ -154,7 +157,7 @@ def ReadGmsh(filename): index = len(facedescriptormap) + 1 fd = FaceDescriptor(bc=index) if len(namemap): - fd.bcname = namemap[tags[0]] + fd.bcname = namemap[2][tags[0]] else: fd.bcname = "surf" + str(tags[1]) mesh.SetBCName(index - 1, fd.bcname) @@ -166,7 +169,7 @@ def ReadGmsh(filename): else: index = len(materialmap) + 1 if len(namemap): - mesh.SetMaterial(index, namemap[tags[0]]) + mesh.SetMaterial(index, namemap[2][tags[0]]) else: mesh.SetMaterial(index, "surf" + str(tags[1])) materialmap[tags[1]] = index @@ -187,7 +190,7 @@ def ReadGmsh(filename): else: index = len(materialmap) + 1 if len(namemap): - mesh.SetMaterial(index, namemap[tags[0]]) + mesh.SetMaterial(index, namemap[3][tags[0]]) else: mesh.SetMaterial(index, "vol" + str(tags[1])) materialmap[tags[1]] = index diff --git a/python/webgui.py b/python/webgui.py index a093b635..7d5ce705 100644 --- a/python/webgui.py +++ b/python/webgui.py @@ -3,248 +3,491 @@ import numpy as np from time import time import os -from webgui_jupyter_widgets import BaseWebGuiScene, encodeData, WebGuiDocuWidget -import webgui_jupyter_widgets.widget as wg +try: + import webgui_jupyter_widgets + from webgui_jupyter_widgets import BaseWebGuiScene, WebGuiDocuWidget + import webgui_jupyter_widgets.widget as wg +except ImportError: + class BaseWebGuiScene: + pass + + wg = None + +def encodeData( data, dtype=None, encoding='b64' ): + import numpy as np + from base64 import b64encode + dtype = dtype or data.dtype + values = np.array(data.flatten(), dtype=dtype) + if encoding=='b64': + return b64encode(values).decode("ascii") + elif encoding=='binary': + return values.tobytes() + else: + raise RuntimeError("unknown encoding" + str(encoding)) + +from packaging.version import parse + +import netgen.meshing as ng + +if wg is not None and parse(webgui_jupyter_widgets.__version__) >= parse("0.2.18"): + _default_width = None + _default_height = None +else: + _default_width = "100%" + _default_height = "50vh" + + +_registered_draw_types = {} + + +def register_draw_type(*types): + def inner(func): + for typ in types: + _registered_draw_types[typ] = func + + return inner + + +_bernstein_cache = {} + + +def GetIBernsteinBasis(etype, order): + if (etype, order) in _bernstein_cache: + return _bernstein_cache[(etype, order)] + bvals = None + + if etype == "segment": + + def Binomial(n, i): + return math.factorial(n) / math.factorial(i) / math.factorial(n - i) + + def Bernstein(x, i, n): + return Binomial(n, i) * x**i * (1 - x) ** (n - i) + + bvals = np.zeros( + (order + 1, order + 1), dtype=float + ) # .Matrix(order+1,order+1) + for i in range(order + 1): + for j in range(order + 1): + bvals[i, j] = Bernstein(i / order, j, order) + + if etype == "trig": + + def BernsteinTrig(x, y, i, j, n): + return ( + math.factorial(n) + / math.factorial(i) + / math.factorial(j) + / math.factorial(n - i - j) + * x**i + * y**j + * (1 - x - y) ** (n - i - j) + ) + + og = order + ndtrig = int((og + 1) * (og + 2) / 2) + bvals = np.zeros((ndtrig, ndtrig)) + ii = 0 + for ix in range(og + 1): + for iy in range(og + 1 - ix): + jj = 0 + for jx in range(og + 1): + for jy in range(og + 1 - jx): + bvals[ii, jj] = BernsteinTrig(ix / og, iy / og, jx, jy, og) + jj += 1 + ii += 1 + + if bvals is None: + raise RuntimeError(f"Unkown element type {etype}") + + ibvals = _bernstein_cache[(etype, order)] = np.linalg.inv(bvals) + return ibvals + + +def GetWireframePoints(etype, order): + n = order + if etype == "trig": + return np.array( + [(i / n, 0) for i in range(n + 1)] + + [(0, i / n) for i in range(n + 1)] + + [(i / n, 1.0 - i / n) for i in range(n + 1)] + ) + if etype == "quad": + return np.array( + [(i / n, 0) for i in range(n + 1)] + + [(0, i / n) for i in range(n + 1)] + + [(i / n, 1.0) for i in range(n + 1)] + + [(1.0, i / n) for i in range(n + 1)] + ) + + raise RuntimeError(f"Unknown element type {etype}") + + +def GetElementPoints(etype, order): + n = order + if etype == "trig": + return np.array( + [(i / n, j / n) for j in range(n + 1) for i in range(n + 1 - j)] + ) + if etype == "quad": + return np.array( + [(i / n, j / n) for j in range(n + 1) for i in range(n + 1 - j)] + + [(1 - i / n, 1 - j / n) for j in range(n + 1) for i in range(n + 1 - j)] + ) + + raise RuntimeError(f"Unknown element type {etype}") + + +def MapBernstein(pnts, etype, order): + """ + Maps function values at equidistant control points to the Bernstein basis function. + Parameters: + pnts (numpy.ndarray): The input control points with shape (number_of_elements, points_per_element, function_dimension) + point_per_element must be a multiple of the basis size + etype (str): Element type (currently ignored and trig assumed) + order (int): Polynomial order + + Returns: + numpy.ndarray: The mapped points with the shape (points_per_element, number_of_elements, function_dimension) + """ + ibvals = GetIBernsteinBasis(etype, order) + # for wireframe or subdivided elements, we have multiple point sets per element + # so do a reshape to simulate more elements with correct number of control points per element instead + if pnts.shape[1] != ibvals.shape[0]: + pnts = pnts.reshape((-1, ibvals.shape[0], pnts.shape[2])) + + points = np.zeros(pnts.shape, dtype=np.float32).transpose(1, 0, 2) + for i in range(points.shape[2]): + points[:, :, i] = np.tensordot(ibvals, pnts[:, :, i], axes=(1, 1)) + return points + + +@register_draw_type(ng.Mesh) +def GetData(mesh, args, kwargs): + d = {} + d["gui_settings"] = kwargs["settings"] + d["mesh_dim"] = mesh.dim + + pmin, pmax = mesh.bounding_box + diag = pmax - pmin + pmid = pmin + 0.5 * diag + d["mesh_center"] = [pmid[i] for i in range(3)] + d["mesh_radius"] = diag.Norm() + + d["funcdim"] = 0 + d["show_mesh"] = True + d["draw_surf"] = True + d["funcmin"] = 0.0 + d["funcmax"] = 1.0 + + # Generate surface element data + # webgui code assumes 4 scalar fields (x,y,z, mesh_index) + # TODO: other element types than trigs + order = kwargs["order"] + refpts = GetElementPoints("trig", order) + pnts = np.ndarray((len(mesh.Elements2D()), refpts.shape[0], 4)) + mesh.CalcElementMapping(refpts, pnts) + + # set mesh_index + for i, el in enumerate(mesh.Elements2D()): + pnts[i, :, 3] = el.index - 1 + fds = mesh.FaceDescriptors() + d["colors"] = [fd.color +(fd.transparency,) for fd in fds] + d["mesh_regions_2d"] = len(fds) + d["names"] = [fd.bcname for fd in fds] + + d["Bezier_trig_points"] = MapBernstein(pnts, "trig", order) + d["order2d"] = order + + # Generate wireframe data + refpts = GetWireframePoints("trig", order) + pnts = np.ndarray((len(mesh.Elements2D()), refpts.shape[0], 4)) + mesh.CalcElementMapping(refpts, pnts) + d["Bezier_points"] = MapBernstein(pnts, "segment", order) + d["show_wireframe"] = True + + # TODO: Generate edge data + d["edges"] = [] + + # encode data as b64 + for name in ["Bezier_trig_points", "edges", "Bezier_points"]: + pnew = [] + for plist in d[name]: + pnew.append(encodeData(np.array(plist, dtype=np.float32))) + d[name] = pnew + return d class WebGLScene(BaseWebGuiScene): - def __init__(self, mesh, clipping, on_init): - from IPython.display import display, Javascript - import threading - self.mesh = mesh - self.clipping = clipping - self.on_init = on_init + class Widget: + def __init__(self): + self.value = {} + + def __init__(self, obj, args=[], kwargs={}): + self.widget = self.Widget() + self.obj = obj + self.args = args + self.kwargs = kwargs + self.encoding = "b64" + + def Redraw(self, *args, **kwargs): + if args or kwargs: + if 'show' not in kwargs: + kwargs['show'] = False + + new_scene = Draw(*args, **kwargs) + self.obj = new_scene.obj + self.args = new_scene.args + self.kwargs = new_scene.kwargs + super().Redraw() def GetData(self, set_minmax=True): - import json - # d = BuildRenderData(self.mesh, self.cf, self.order, draw_surf=self.draw_surf, draw_vol=self.draw_vol, deformation=self.deformation, region=self.region) - d = self.mesh._webgui_data() - bp = d['Bezier_trig_points'] - for i in range(len(bp)): - bp[i] = encodeData(np.array(bp[i], dtype=np.float32)) + self.kwargs["encoding"] = self.encoding + typ = type(self.obj) + d = None + if type(self.obj) in _registered_draw_types: + d = _registered_draw_types[typ](self.obj, self.args, self.kwargs) + else: + import inspect - ep = d['edges'] - for i in range(len(ep)): - ep[i] = encodeData(np.array(ep[i], dtype=np.float32)) + for t in inspect.getmro(typ): + if t in _registered_draw_types: + d = _registered_draw_types[t](self.obj, self.args, self.kwargs) + break + if d is None and hasattr(self.obj, "_webgui_data"): + d = self.obj._webgui_data() + bp = d["Bezier_trig_points"] + for i in range(len(bp)): + bp[i] = encodeData(np.array(bp[i], dtype=np.float32)) - if self.clipping is not None: - d['clipping'] = True - if isinstance(self.clipping, dict): + ep = d["edges"] + for i in range(len(ep)): + ep[i] = encodeData(np.array(ep[i], dtype=np.float32)) + + if d is None: + raise RuntimeError(f"Cannot draw object of type {typ}") + + args = self.args + kwargs = self.kwargs + if "clipping" in kwargs: + clipping = kwargs["clipping"] + d["clipping"] = True + if isinstance(clipping, dict): allowed_args = ("x", "y", "z", "dist", "function", "pnt", "vec") - if "vec" in self.clipping: - vec = self.clipping["vec"] - self.clipping["x"] = vec[0] - self.clipping["y"] = vec[1] - self.clipping["z"] = vec[2] - if "pnt" in self.clipping: - d['mesh_center'] = list(self.clipping["pnt"]) - for name, val in self.clipping.items(): + if "vec" in clipping: + vec = clipping["vec"] + clipping["x"] = vec[0] + clipping["y"] = vec[1] + clipping["z"] = vec[2] + if "pnt" in clipping: + d["mesh_center"] = list(clipping["pnt"]) + for name, val in clipping.items(): if not (name in allowed_args): - raise Exception('Only {} allowed as arguments for clipping!'.format(", ".join(allowed_args))) - d['clipping_' + name] = val + raise Exception( + "Only {} allowed as arguments for clipping!".format( + ", ".join(allowed_args) + ) + ) + d["clipping_" + name] = val - if self.on_init: - d['on_init'] = self.on_init + if "js_code" in kwargs: + d["on_init"] = kwargs["js_code"] + + if "min" in kwargs: + d["funcmin"] = kwargs["min"] + if "max" in kwargs: + d["funcmax"] = kwargs["max"] + d["autoscale"] = kwargs["autoscale"] + + if "vectors" in kwargs: + d["vectors"] = True + if isinstance(kwargs["vectors"], dict): + for name, val in kwargs["vectors"].items(): + if not (name in ("grid_size", "offset")): + raise Exception( + 'Only "grid_size" and "offset" allowed as arguments for vectors!' + ) + d["vectors_" + name] = val + + if "eval_function" in kwargs: + d["user_eval_function"] = kwargs["eval_function"] + + # see shaders/utils.h for value explanation (function_mode) + if "eval_" in kwargs: + eval_ = kwargs["eval"] + if isinstance(eval_, int): + d["eval"] = eval_ + elif eval_ == "norm": + d["eval"] = 3 + elif eval_ == "real": + d["eval"] = 5 + elif eval_ == "imag": + d["eval"] = 6 + + if "fullscreen" in kwargs: + d["fullscreen"] = kwargs["fullscreen"] + if "gui_settings" not in d: + d["gui_settings"] = self.kwargs["settings"] + + if "euler_angles" in kwargs: + camera = d["gui_settings"].get("camera", {}) + camera["euler_angles"] = kwargs["euler_angles"] + d["gui_settings"]['camera'] = camera + + d["objects"] = [] + for obj in kwargs["objects"]: + if isinstance(obj, dict): + d["objects"].append(obj) + else: + d["objects"].append(obj._GetWebguiData()) + + if 'center' in kwargs: + center = list(kwargs['center']) + if len(center) == 2: + center.append(0.) + d["mesh_center"] = center + + if 'radius' in kwargs: + d["mesh_radius"] = kwargs['radius'] return d -bezier_trig_trafos = { } # cache trafos for different orders +bezier_trig_trafos = {} # cache trafos for different orders -def BuildRenderData(mesh, func, order=2, draw_surf=True, draw_vol=True, deformation=None, region=True): - d = {} - d['ngsolve_version'] = "Netgen" - d['mesh_dim'] = 3 # mesh.dim TODO +# def Draw(shape, clipping=None, js_code=None, filename=""): +# # todo: also handle occ geometry, list of shapes, etc. - d['order2d'] = 1 - d['order3d'] = 0 +# scene = WebGLScene(shape, clipping=clipping, on_init=js_code) - d['draw_vol'] = False - d['draw_surf'] = True - d['funcdim'] = 1 - - func2 = None - if func and func.is_complex: - d['is_complex'] = True - func1 = func[0].real - func2 = ngs.CoefficientFunction( (func[0].imag, 0.0) ) - elif func and func.dim>1: - func1 = func[0] - func2 = ngs.CoefficientFunction( tuple(func[i] if i we are just drawing a mesh, eval mesh element index instead - mats = mesh.GetMaterials() - bnds = mesh.GetBoundaries() - nmats = len(mesh.GetMaterials()) - nbnds = len(mesh.GetBoundaries()) - n = max(nmats, nbnds) - func1 = ngs.CoefficientFunction(list(range(n))) - n_regions = [0, 0, nmats, nbnds] - d['mesh_regions_2d'] = n_regions[mesh.dim] - d['mesh_regions_3d'] = nmats if mesh.dim==3 else 0 - d['funcdim'] = 0 - func1 = ngs.CoefficientFunction( (ngs.x, ngs.y, ngs.z, func1 ) ) - func0 = ngs.CoefficientFunction( (ngs.x, ngs.y, ngs.z, 0.0 ) ) - if deformation is not None: - func1 += ngs.CoefficientFunction((deformation, 0.0)) - func0 += ngs.CoefficientFunction((deformation, 0.0)) - - d['show_wireframe'] = False - d['show_mesh'] = True - if order2d>0: - og = order2d - d['show_wireframe'] = True - d['show_mesh'] = True - timer2.Start() - - timer3Bvals.Start() - - # transform point-values to Bernsteinbasis - def Binomial(n,i): return math.factorial(n) / math.factorial(i) / math.factorial(n-i) - def Bernstein(x, i, n): return Binomial(n,i) * x**i*(1-x)**(n-i) - Bvals = ngs.Matrix(og+1,og+1) - for i in range(og+1): - for j in range(og+1): - Bvals[i,j] = Bernstein(i/og, j, og) - iBvals = Bvals.I - timer3Bvals.Stop() - # print (Bvals) - # print (iBvals) - - - Bezier_points = [] - - ipts = [(i/og,0) for i in range(og+1)] + [(0, i/og) for i in range(og+1)] + [(i/og,1.0-i/og) for i in range(og+1)] - ir_trig = ngs.IntegrationRule(ipts, [0,]*len(ipts)) - ipts = [(i/og,0) for i in range(og+1)] + [(0, i/og) for i in range(og+1)] + [(i/og,1.0) for i in range(og+1)] + [(1.0, i/og) for i in range(og+1)] - ir_quad = ngs.IntegrationRule(ipts, [0,]*len(ipts)) - - vb = [ngs.VOL, ngs.BND][mesh.dim-2] - if region and region.VB() == vb: - vb = region - cf = func1 if draw_surf else func0 - timer2map.Start() - pts = mesh.MapToAllElements({ngs.ET.TRIG: ir_trig, ngs.ET.QUAD: ir_quad}, vb) - timer2map.Stop() - pmat = cf(pts) - - timermult.Start() - pmat = pmat.reshape(-1, og+1, 4) - if False: - BezierPnts = np.tensordot(iBvals.NumPy(), pmat, axes=(1,1)) - else: - BezierPnts = np.zeros( (og+1, pmat.shape[0], 4) ) - for i in range(4): - ngsmat = ngs.Matrix(pmat[:,:,i].transpose()) - BezierPnts[:,:,i] = iBvals * ngsmat - timermult.Stop() - - timer2list.Start() - for i in range(og+1): - Bezier_points.append(encodeData(BezierPnts[i], dtype=np.float32)) - timer2list.Stop() - - d['Bezier_points'] = Bezier_points - - ipts = [(i/og,0) for i in range(og+1)] - ir_seg = ngs.IntegrationRule(ipts, [0,]*len(ipts)) - vb = [ngs.VOL, ngs.BND, ngs.BBND][mesh.dim-1] - if region and region.VB() == vb: - vb = region - pts = mesh.MapToAllElements(ir_seg, vb) - pmat = func0(pts) - pmat = pmat.reshape(-1, og+1, 4) - edge_data = np.tensordot(iBvals.NumPy(), pmat, axes=(1,1)) - edges = [] - for i in range(og+1): - edges.append(encodeData(edge_data[i], dtype=np.float32)) - d['edges'] = edges - - ndtrig = int((og+1)*(og+2)/2) - - if og in bezier_trig_trafos.keys(): - iBvals_trig = bezier_trig_trafos[og] - else: - def BernsteinTrig(x, y, i, j, n): - return math.factorial(n)/math.factorial(i)/math.factorial(j)/math.factorial(n-i-j) \ - * x**i*y**j*(1-x-y)**(n-i-j) - Bvals = ngs.Matrix(ndtrig, ndtrig) - ii = 0 - for ix in range(og+1): - for iy in range(og+1-ix): - jj = 0 - for jx in range(og+1): - for jy in range(og+1-jx): - Bvals[ii,jj] = BernsteinTrig(ix/og, iy/og, jx, jy, og) - jj += 1 - ii += 1 - iBvals_trig = Bvals.I - bezier_trig_trafos[og] = iBvals_trig - - - # Bezier_points = [ [] for i in range(ndtrig) ] - Bezier_points = [] - - ipts = [(i/og,j/og) for j in range(og+1) for i in range(og+1-j)] - ir_trig = ngs.IntegrationRule(ipts, [0,]*len(ipts)) - ipts = ([(i/og,j/og) for j in range(og+1) for i in range(og+1-j)] + - [(1-i/og,1-j/og) for j in range(og+1) for i in range(og+1-j)]) - ir_quad = ngs.IntegrationRule(ipts, [0,]*len(ipts)) - - vb = [ngs.VOL, ngs.BND][mesh.dim-2] - if region and region.VB() == vb: - vb = region - pts = mesh.MapToAllElements({ngs.ET.TRIG: ir_trig, ngs.ET.QUAD: ir_quad}, vb) - - pmat = ngs.CoefficientFunction( func1 if draw_surf else func0 ) (pts) - - - funcmin = np.min(pmat[:,3]) - funcmax = np.max(pmat[:,3]) - pmin = np.min(pmat[:,0:3], axis=0) - pmax = np.max(pmat[:,0:3], axis=0) - - mesh_center = 0.5*(pmin+pmax) - mesh_radius = np.linalg.norm(pmax-pmin)/2 - - pmat = pmat.reshape(-1, len(ir_trig), 4) - - BezierPnts = np.tensordot(iBvals_trig.NumPy(), pmat, axes=(1,1)) - - for i in range(ndtrig): - Bezier_points.append(encodeData(BezierPnts[i], dtype=np.float32)) +# if wg._IN_IPYTHON: +# if wg._IN_GOOGLE_COLAB: +# from IPython.display import display, HTML +# html = scene.GenerateHTML() +# display(HTML(html)) +# else: +# # render scene using widgets.DOMWidget +# scene.Draw() +# return scene +# else: +# if filename: +# scene.GenerateHTML(filename=filename) +# return scene - d['Bezier_trig_points'] = Bezier_points - d['mesh_center'] = list(mesh_center) - d['mesh_radius'] = mesh_radius +def _get_draw_default_args(): + return dict( + name="function", + order=2, + draw_vol=True, + draw_surf=True, + autoscale=True, + deformation=False, + interpolate_multidim=False, + animate=False, + objects=[], + nodal_p1=False, + settings={}, + fullscreen=False, + scale=1.0, + width=_default_width, + height=_default_height, + ) +def Draw(obj, *args, show=True, **kwargs): + kwargs_with_defaults = _get_draw_default_args() + kwargs_with_defaults.update(kwargs) - if func: - d['funcmin'] = funcmin - d['funcmax'] = funcmax - return d - -def Draw(shape, clipping=None, js_code=None, filename=""): - # todo: also handle occ geometry, list of shapes, etc. - - scene = WebGLScene(shape, clipping=clipping, on_init=js_code) - - if wg._IN_IPYTHON: + scene = WebGLScene(obj, args, kwargs_with_defaults) + if show and wg is not None and wg._IN_IPYTHON: if wg._IN_GOOGLE_COLAB: from IPython.display import display, HTML + html = scene.GenerateHTML() display(HTML(html)) + return else: - # render scene using widgets.DOMWidget - scene.Draw() - return scene - else: - if filename: - scene.GenerateHTML(filename=filename) - return scene + import webgui_jupyter_widgets as wjw + from packaging.version import parse + # render scene using widgets.DOMWidget + if parse(wjw.__version__) < parse("0.2.15"): + scene.Draw() + else: + scene.Draw( + kwargs_with_defaults["width"], kwargs_with_defaults["height"] + ) + if "filename" in kwargs_with_defaults: + scene.GenerateHTML(filename=kwargs_with_defaults["filename"]) + return scene + +async def _MakeScreenshot(data, png_file, width=1200, height=600): + """Uses playwright to make a screenshot of the given html file.""" + # pylint: disable=import-outside-toplevel + from playwright.async_api import async_playwright + from webgui_jupyter_widgets.html import GenerateHTML, getScreenshotHTML + + html_file = png_file + ".html" + GenerateHTML(data, filename=html_file, template=getScreenshotHTML()) + + async with async_playwright() as play: + browser = await play.chromium.launch() + page = await browser.new_page(viewport={"width": width, "height": height}) + await page.goto(f"file://{os.path.abspath(html_file)}") + await page.screenshot(path=png_file) + await browser.close() + +def _DrawDocu(obj, *args, **kwargs): + import json + import asyncio + + kwargs_with_defaults = _get_draw_default_args() + kwargs_with_defaults.update(kwargs) + scene = WebGLScene(obj, args, kwargs_with_defaults) + + docu_path = os.environ["NETGEN_DOCUMENTATION_OUT_DIR"] + src_path = os.environ["NETGEN_DOCUMENTATION_SRC_DIR"] + cwd_path = os.path.abspath(".") + rel_path = os.path.relpath(".", src_path) + path = os.path.join(docu_path, rel_path) + + if not os.path.exists(path): + os.makedirs(path) + counter_file = os.path.join(docu_path, ".counter") + if os.path.exists(counter_file): + file_counter = int(open(counter_file, "r").read()) + 1 + else: + file_counter = 0 + + open(counter_file, "w").write(str(file_counter)) + + data_file = "render_data_{}.json".format(file_counter) + data_file_abs = os.path.join(path, data_file) + preview_file = "preview_{}.png".format(file_counter) + preview_file_abs = os.path.join(path, preview_file) + + widget = WebGuiDocuWidget() + widget.value = {"render_data": data_file, "preview": preview_file} + scene.widget = widget + data = scene.GetData() + json.dump(data, open(data_file_abs, "w")) + asyncio.run(_MakeScreenshot(data, preview_file_abs, 1200, 600)) + scene.Redraw = lambda: None + from IPython.display import display, HTML + + display(widget) + return scene + + +if "NETGEN_DOCUMENTATION_SRC_DIR" in os.environ: + # use nest_asyncio to allow reentrant asyncio when executing jupyter notebooks + import nest_asyncio + nest_asyncio.apply() + + # we are buiding the documentation, some things are handled differently: + # 1) Draw() is generating a .png (using headless chromium via selenium) and a render_data.json + # to show a preview image and load the render_data only when requested by user + # 2) return a NGSDocuWebGuiWidget instead of NGSWebGuiWidget implementing the preview/load on demand of webgui + + _Draw = Draw + Draw = _DrawDocu diff --git a/rules/CMakeLists.txt b/rules/CMakeLists.txt index 82dad7e7..355644e0 100644 --- a/rules/CMakeLists.txt +++ b/rules/CMakeLists.txt @@ -1,7 +1,18 @@ # this file is included from the parent directory (otherwise generated source files are not recognized properly by cmake) # generate .cpp files containing the string of the .rls meshing rule files -add_executable(makerls rules/makerlsfile.cpp) +if(EMSCRIPTEN) + add_custom_command(OUTPUT makerls + COMMAND g++ ${CMAKE_CURRENT_SOURCE_DIR}/rules/makerlsfile.cpp -o ${CMAKE_CURRENT_BINARY_DIR}/makerls + ) + set(rules_command ${CMAKE_BINARY_DIR}/makerls) +else(EMSCRIPTEN) + add_executable(makerls rules/makerlsfile.cpp) + if(USE_CCACHE) + set_target_properties(makerls PROPERTIES RULE_LAUNCH_COMPILE "") + endif(USE_CCACHE) + set(rules_command makerls) +endif() set(rules hexrules @@ -21,7 +32,7 @@ foreach(rule ${rules}) set(rule_cpp ${CMAKE_CURRENT_BINARY_DIR}/rules/rule_${rule}.cpp) add_custom_command(OUTPUT ${rule_cpp} - COMMAND makerls ${rule_file} ${rule_cpp} ${rule} + COMMAND ${rules_command} ${rule_file} ${rule_cpp} ${rule} DEPENDS makerls ${rule_file} ) endforeach() diff --git a/rules/makerlsfile.cpp b/rules/makerlsfile.cpp index 822c721d..18b7d512 100644 --- a/rules/makerlsfile.cpp +++ b/rules/makerlsfile.cpp @@ -15,10 +15,10 @@ int main (int argc, char ** argv) exit(1); } - - char line[maxlen], infile[maxlen], outfile[maxlen];\ + + char line[maxlen]; // , infile[maxlen], outfile[maxlen]; char ch; - int i, j; + int i; /* cout << "infile: "; diff --git a/rules/tetrules.rls b/rules/tetrules.rls index faad6c43..53eb6058 100644 --- a/rules/tetrules.rls +++ b/rules/tetrules.rls @@ -139,7 +139,7 @@ endrule rule "Tetrahedron Vis a Vis Point (1)" -quality 100 +quality 20 mappoints (0, 0, 0); diff --git a/setup.py b/setup.py index bea48af3..892dc956 100644 --- a/setup.py +++ b/setup.py @@ -1,14 +1,23 @@ import glob +import os.path import os import sys import pathlib +import sysconfig +import importlib.metadata from skbuild import setup import skbuild.cmaker from subprocess import check_output -from distutils.sysconfig import get_python_lib; -setup_requires = [] +setup_requires = ['pybind11-stubgen>=2.5', 'netgen-occt-devel'] + +pyprefix = pathlib.Path(sys.prefix).as_posix() + +def find_occt_dir(): + for f in importlib.metadata.files("netgen-occt-devel"): + if f.match("OpenCASCADEConfig.cmake"): + return f.locate().parent.resolve().absolute().as_posix() def install_filter(cmake_manifest): print(cmake_manifest) @@ -26,22 +35,24 @@ def _patched_parse_manifests(self): # patch the parse_manifests function to point to the actual netgen cmake project within the superbuild skbuild.cmaker.CMaker._parse_manifests = _patched_parse_manifests -git_version = check_output(['git', 'describe', '--tags']).decode('utf-8').strip() -version = git_version[1:].split('-') -if len(version)>2: - version = version[:2] -if len(version)>1: - version = '.post'.join(version) + '.dev' -else: - version = version[0] +def is_dev_build(): + if 'NG_NO_DEV_PIP_VERSION' in os.environ: + return False + if 'CI_COMMIT_REF_NAME' in os.environ and os.environ['CI_COMMIT_REF_NAME'] == 'release': + return False + return True -py_install_dir = get_python_lib(1,0,'').replace('\\','/') +git_version = check_output([sys.executable, os.path.join('tests', 'utils.py'), '--get-git-version']).decode('utf-8').strip() +version = check_output([sys.executable, os.path.join('tests', 'utils.py'), '--get-version']).decode('utf-8').strip() + +py_install_dir = os.path.relpath(sysconfig.get_path('platlib'), sysconfig.get_path('data')).replace('\\','/') name = "netgen-mesher" arch = None cmake_args = [ f'-DNETGEN_VERSION_GIT={git_version}', f'-DNETGEN_VERSION_PYTHON={version}', + f'-DOpenCascade_DIR={find_occt_dir()}', ] if 'NETGEN_ARCH' in os.environ and os.environ['NETGEN_ARCH'] == 'avx2': @@ -49,7 +60,7 @@ if 'NETGEN_ARCH' in os.environ and os.environ['NETGEN_ARCH'] == 'avx2': if 'darwin' in sys.platform: flag = "'-Xarch_x86_64;-march=core-avx2'" elif 'win' in sys.platform: - flag = '/AVX2' + flag = '/arch:AVX2' else: flag = '-march=core-avx2' cmake_args += [f'-DNG_COMPILE_FLAGS={flag}'] @@ -59,6 +70,7 @@ if 'NETGEN_CCACHE' in os.environ: packages = ['netgen', 'pyngcore'] +have_mpi = False if 'darwin' in sys.platform: cmake_args += [ '-DNG_INSTALL_DIR_LIB=netgen', @@ -68,6 +80,11 @@ if 'darwin' in sys.platform: '-DNG_INSTALL_DIR_INCLUDE=netgen/include', '-DNG_INSTALL_DIR_RES=share', ] + if os.path.exists('/usr/local/include/mpi.h'): + have_mpi = True + cmake_args += [ + '-DOPENMPI_INCLUDE_DIR=/usr/local/include', + ] elif 'win' in sys.platform: cmake_args += [ '-A Win64', @@ -77,6 +94,15 @@ elif 'win' in sys.platform: '-DNG_INSTALL_DIR_CMAKE=netgen/cmake', '-DNG_INSTALL_DIR_INCLUDE=netgen/include', ] + py_libdir = pathlib.Path(sys.prefix) / 'Library' + lib_file = py_libdir / 'lib' / 'impi.lib' + include_dir = py_libdir / 'include' + if lib_file.exists(): + have_mpi = True + cmake_args += [ + f'-DINTEL_MPI_INCLUDE_DIR={include_dir.as_posix()}', + f'-DINTEL_MPI_LIBRARY={lib_file.as_posix()}', + ] elif 'linux' in sys.platform: name_dir = name.replace('-','_') cmake_args += [ @@ -86,23 +112,41 @@ elif 'linux' in sys.platform: '-DTCL_INCLUDE_PATH=/usr/include', '-DTK_INCLUDE_PATH=/usr/include', ] + mpich_include = '/opt/mpich/include' + openmpi_include = '/opt/openmpi/include' + if os.path.exists(mpich_include+'/mpi.h'): + have_mpi = True + cmake_args += [ + f'-DMPICH_INCLUDE_DIR={mpich_include}', + ] + if os.path.exists(openmpi_include+'/mpi.h'): + have_mpi = True + cmake_args += [ + f'-DOPENMPI_INCLUDE_DIR={openmpi_include}', + ] packages = [] +if have_mpi: + cmake_args += [ + '-DUSE_MPI=ON', + '-DUSE_MPI_WRAPPER=ON', + ] + cmake_args += [ '-DUSE_SUPERBUILD:BOOL=ON', '-DUSE_CCACHE:BOOL=ON', '-DUSE_GUI=ON', '-DUSE_NATIVE_ARCH=OFF', '-DBUILD_ZLIB=ON', - '-DBUILD_OCC=ON', + '-DZLIB_USE_STATIC_LIBS=ON', + '-DBUILD_OCC=OFF', '-DUSE_OCC=ON', '-DBUILD_FOR_CONDA=ON', f'-DNETGEN_PYTHON_PACKAGE_NAME={name}', - '-DBUILD_STUB_FILES=OFF', + '-DBUILD_STUB_FILES=ON', ] -pyprefix = pathlib.Path(sys.prefix).as_posix() -cmake_args += [f'-DCMAKE_PREFIX_PATH={pyprefix}'] +cmake_args += [f'-DCMAKE_PREFIX_PATH={pyprefix}', f'-DPython3_ROOT_DIR={pyprefix}'] setup( name=name, @@ -112,6 +156,7 @@ setup( license="LGPL2.1", packages=packages, #package_dir={'netgen': 'python'}, + install_requires=[f"netgen-occt=={importlib.metadata.version('netgen-occt-devel')}"], tests_require=['pytest'], #include_package_data=True, cmake_process_manifest_hook=install_filter, diff --git a/tests/build_mpi.sh b/tests/build_mpi.sh index 0e26af94..64f627df 100644 --- a/tests/build_mpi.sh +++ b/tests/build_mpi.sh @@ -5,6 +5,7 @@ cmake ../../src/netgen \ -DCHECK_RANGE=ON \ -DUSE_CCACHE=ON \ -DUSE_MPI=ON \ + -DUSE_OCC=OFF \ -DENABLE_UNIT_TESTS=ON make -j12 make install diff --git a/tests/build_pip.ps1 b/tests/build_pip.ps1 index 909b5b3e..c665edcb 100644 --- a/tests/build_pip.ps1 +++ b/tests/build_pip.ps1 @@ -10,6 +10,12 @@ $env:NETGEN_ARCH = 'avx2' $pydir=$args[0] & $pydir\python.exe --version +& $pydir\python.exe -m pip install packaging requests +& $pydir\python.exe tests\utils.py --check-pip +if ($LASTEXITCODE -ne 0) { + exit 0 +} & $pydir\python.exe -m pip install scikit-build wheel numpy twine pybind11-stubgen +& $pydir\python.exe -m pip install --upgrade netgen-occt==7.8.1 netgen-occt-devel==7.8.1 & $pydir\python setup.py bdist_wheel -G"Visual Studio 16 2019" & $pydir\python -m twine upload dist\*.whl diff --git a/tests/build_pip.sh b/tests/build_pip.sh index 09c6d8d2..76075351 100755 --- a/tests/build_pip.sh +++ b/tests/build_pip.sh @@ -1,29 +1,38 @@ set -e ulimit -n 1024000 # lower open file limit, seems to affect performance yum -y update -yum -y install ninja-build fontconfig-devel tk-devel tcl-devel libXmu-devel mesa-libGLU-devel ccache +yum -y install ninja-build fontconfig-devel tk-devel tcl-devel libXmu-devel mesa-libGLU-devel openmpi-devel mpich-devel + +mkdir -p /opt/openmpi/include /opt/mpich/include +cp -a /usr/include/openmpi-x86_64/* /opt/openmpi/include/ +cp -a /usr/include/mpich-x86_64/* /opt/mpich/include/ + +curl https://dl.fedoraproject.org/pub/epel/8/Everything/x86_64/Packages/c/ccache-3.7.7-1.el8.x86_64.rpm -o ccache.rpm +dnf -y install ccache.rpm rm -rf wheelhouse export NETGEN_CCACHE=1 -/opt/python/cp39-cp39/bin/python tests/fix_auditwheel_policy.py - -for pyversion in 38 39 310 311 +for pyversion in 313 312 311 310 39 do export PYDIR="/opt/python/cp${pyversion}-cp${pyversion}/bin" echo $PYDIR - $PYDIR/pip install -U pytest-check numpy wheel scikit-build pybind11-stubgen + $PYDIR/pip install requests packaging + $PYDIR/python3 ./tests/utils.py --check-pip || continue + $PYDIR/pip install -U pytest-check numpy wheel scikit-build pybind11-stubgen netgen-occt==7.8.1 netgen-occt-devel==7.8.1 + $PYDIR/pip install -i https://pypi.anaconda.org/mpi4py/simple/ --pre mpi4py rm -rf _skbuild NETGEN_ARCH=avx2 $PYDIR/pip wheel . - auditwheel repair netgen_mesher*-cp${pyversion}-*.whl - rm netgen_mesher-*.whl + mkdir -p wheelhouse + rename linux_x86_64 manylinux_2_17_x86_64.manylinux2014_x86_64 netgen_mesher*-cp${pyversion}-*.whl + mv netgen_mesher*-cp${pyversion}-*.whl wheelhouse/ $PYDIR/pip install wheelhouse/netgen_mesher*-cp${pyversion}-*.whl $PYDIR/python3 -c 'import netgen' + $PYDIR/pip install -U twine + $PYDIR/twine upload --skip-existing wheelhouse/netgen_mesher*-cp${pyversion}*manylinux*.whl #cd ../tests/pytest #$PYDIR/python3 -m pytest done -$PYDIR/pip install -U twine -$PYDIR/twine upload wheelhouse/*manylinux*.whl diff --git a/tests/build_pip_mac.sh b/tests/build_pip_mac.sh index 22ea0d4f..1824ea9a 100755 --- a/tests/build_pip_mac.sh +++ b/tests/build_pip_mac.sh @@ -1,12 +1,16 @@ set -e + rm -rf _skbuild dist -export PATH=/Applications/CMake.app/Contents/bin:$PATH +export PYDIR=/Library/Frameworks/Python.framework/Versions/$1/bin +export PATH=$PYDIR:/Applications/CMake.app/Contents/bin:$PATH export NETGEN_CCACHE=1 -export PYDIR=/Library/Frameworks/Python.framework/Versions/$1/bin $PYDIR/python3 --version -$PYDIR/pip3 install --user numpy twine scikit-build wheel pybind11-stubgen +$PYDIR/python3 -m pip install packaging requests +$PYDIR/python3 tests/utils.py --check-pip || exit 0 +$PYDIR/python3 -m pip install --user numpy twine scikit-build wheel pybind11-stubgen +$PYDIR/python3 -m pip install --user -U netgen-occt==7.8.1 netgen-occt-devel==7.8.1 export CMAKE_OSX_ARCHITECTURES='arm64;x86_64' export NETGEN_ARCH='avx2' diff --git a/tests/catch/archive.cpp b/tests/catch/archive.cpp index 8c436697..62f6df46 100644 --- a/tests/catch/archive.cpp +++ b/tests/catch/archive.cpp @@ -2,6 +2,8 @@ #include #include <../core/ngcore.hpp> #include +#include +#include using namespace ngcore; using namespace std; @@ -84,12 +86,34 @@ public: const int* getPtr() { return ptr; } }; -class OneMoreDerivedClass : public SharedPtrAndPtrHolder {}; +class ClassWithoutDefaultConstructor +{ +public: + int a; + double b; + double c; + ClassWithoutDefaultConstructor(int aa, double c) : a(aa), c(c) {} + + void DoArchive(Archive& ar) + { + ar & b; + } + + auto GetCArgs() + { + return make_tuple(a, c); + } +}; + +static RegisterClassForArchive regwdc; + +class OneMoreDerivedClass : public SharedPtrAndPtrHolder { +}; static RegisterClassForArchive regb; static RegisterClassForArchive regsp; static RegisterClassForArchive regp; -static RegisterClassForArchive regspp; +static RegisterClassForArchive> regspp; static RegisterClassForArchive regom; void testNullPtr(Archive& in, Archive& out) @@ -332,6 +356,19 @@ void testArchive(Archive& in, Archive& out) SharedPtrAndPtrHolder* p = new NotRegisteredForArchive; REQUIRE_THROWS(out & p, Catch::Contains("not registered for archive")); } + SECTION("Non-default constructor") + { + ClassWithoutDefaultConstructor c(5, 2.2); + c.b = 3.2; + auto p = &c; + out & p; + out.FlushBuffer(); + ClassWithoutDefaultConstructor* cin; + in & cin; + CHECK(cin->a == 5); + CHECK(cin->b == 3.2); + CHECK(cin->c == 2.2); + } SECTION("nullptr") { testNullPtr(in, out); @@ -365,3 +402,35 @@ TEST_CASE("TextArchive") TextInArchive in(stream); testArchive(in, out); } + + +template +auto CheckCopyWithArchive(const T * v) { + T * tcopy = nullptr; + auto tstream = make_shared(); + TextOutArchive tout(tstream); + tout & v; + TextInArchive tin(tstream); + tin & tcopy; + + T *bcopy = nullptr; + auto bstream = make_shared(); + BinaryOutArchive bout(bstream); + bout & v; + bout.FlushBuffer(); + BinaryInArchive in(bstream); + in & bcopy; + + CHECK(*v == *tcopy); + CHECK(*v == *bcopy); + CHECK(*bcopy == *bcopy); +} + +TEST_CASE("CopyWithArchive") +{ + Array aint{1,2,5,67,23252}; + CheckCopyWithArchive(&aint); + + std::vector abyte{byte(1), byte(3), byte(255), byte(0), byte(76)}; + CheckCopyWithArchive(&abyte); +} diff --git a/tests/catch/array.cpp b/tests/catch/array.cpp index c21aa800..63011533 100644 --- a/tests/catch/array.cpp +++ b/tests/catch/array.cpp @@ -70,12 +70,12 @@ TEST_CASE("Array") // pointindex is still 1 based Array piarray(2); - i = 1; + netgen::PointIndex pi = IndexBASE(); for(auto j : Range(piarray)) - CHECK(j == i++); - i = 1; + CHECK(j == pi++); + pi = IndexBASE(); for(auto j : piarray.Range()) - CHECK(j == i++); + CHECK(j == pi++); // a class can implement index_type and Size as well. ClsWithIndexType clsi(3); CHECK(typeid(Range(clsi)) == typeid(T_Range)); diff --git a/tests/fix_auditwheel_policy.py b/tests/fix_auditwheel_policy.py deleted file mode 100644 index 1b0329f9..00000000 --- a/tests/fix_auditwheel_policy.py +++ /dev/null @@ -1,26 +0,0 @@ -import json - -policy_file = "/opt/_internal/pipx/venvs/auditwheel/lib/python3.10/site-packages/auditwheel/policy/manylinux-policy.json" -data = json.load(open(policy_file)) -additional_libs = [ - "libbz2.so.1.0.6", - "libfontconfig.so.1.11.1", - "libfreetype.so.6.14.0", - "libGLU.so.1.3.1", - "libpng15.so.15.13.0", - "libtcl8.so", - "libtk8.so", - "libuuid.so.1.3.0", - "libz.so.1.2.7", - "libXmu.so.6", - "libOpenGL.so.0", - "libGLdispatch.so.0", - "libGLX.so.0", - "libGLU.so.1", - ] - -for entry in data: - if 'manylinux' in entry['name']: - entry['lib_whitelist'] += additional_libs - -json.dump(data, open(policy_file, 'w')) diff --git a/tests/pytest/CMakeLists.txt b/tests/pytest/CMakeLists.txt index 26c7d22f..375bd420 100644 --- a/tests/pytest/CMakeLists.txt +++ b/tests/pytest/CMakeLists.txt @@ -1,8 +1,8 @@ if(USE_PYTHON) - add_test(NAME pytest COMMAND ${PYTHON_EXECUTABLE} -m pytest WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - add_custom_target(pytest ${PYTHON_EXECUTABLE} -m pytest WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_test(NAME pytest COMMAND ${Python3_EXECUTABLE} -m pytest WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_custom_target(pytest ${Python3_EXECUTABLE} -m pytest WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) set_tests_properties ( pytest PROPERTIES TIMEOUT 1800 ) if(USE_MPI AND USE_MPI4PY) - add_test(NAME pytest-mpi COMMAND ${MPIEXEC_EXECUTABLE} --allow-run-as-root -np 4 ${PYTHON_EXECUTABLE} -m pytest --with-mpi test_mpi4py.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_test(NAME pytest-mpi COMMAND ${MPIEXEC_EXECUTABLE} --allow-run-as-root -np 4 ${Python3_EXECUTABLE} -m pytest --with-mpi test_mpi4py.py WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endif(USE_MPI AND USE_MPI4PY) endif(USE_PYTHON) diff --git a/tests/pytest/compare_results.py b/tests/pytest/compare_results.py index 1015be34..5a5f9538 100644 --- a/tests/pytest/compare_results.py +++ b/tests/pytest/compare_results.py @@ -14,6 +14,8 @@ def readData(a, files): ne3d=[] file=[] for f in files: + if f == 'cylinder.geo': + continue for t in a[f]: if t['ne1d']>0: ne1d.append(t['ne1d']) @@ -88,29 +90,34 @@ for bad1,bad2, f1, f2 in zip(data['#trigs'], data2['#trigs'], data['file'], data if bad2>0 and bad2<0.8*bad1: print(f"{GREEN}ntrigs {f1} got better: {bad1} -> {bad2}".ljust(w) + diff + RESET) -n = len(data)+1 -fig,ax = plt.subplots(figsize=(10,7)) -for i,d in enumerate(['min trig angle','min tet angle','max trig angle','max tet angle']): - ax = plt.subplot(2,5,i+1) +n = len(data) + 1 +fig, ax = plt.subplots(figsize=(15, 7)) # Adjust figsize as needed +plt.xticks([]) +plt.yticks([]) +ax.yaxis.grid(False) +ax.xaxis.grid(False) +for i, d in enumerate(['min trig angle', 'min tet angle', 'max trig angle', 'max tet angle']): + plt.subplot(2, 4, i + 1) # Remove ax = plt.title(d) - ax.set_xticks([1,2]) - if len(data[d])==0 or len(data2[d])==0: + # plt.xticks([1, 2]) + if len(data[d]) == 0 or len(data2[d]) == 0: continue - plt.violinplot([data[d],data2[d]], showmedians=True) + plt.violinplot([data[d], data2[d]], showmedians=True) med = statistics.median(data[d]) - plt.hlines(med, 1,2, linestyle='dotted') - if d=='badness': - ax.set_yscale('log') - ax.set_xticklabels([ref, ref2]) + plt.hlines(med, 1, 2, linestyle='dotted') + if d == 'badness': + plt.yscale('log') + plt.xticks([1, 2], [ref, ref2]) +for i, d in enumerate(['badness', '#edges', '#trigs', '#tets']): + plt.xticks([]) + plt.subplot(2, 4, 5 + i) + plt.title('difference ' + d + ' (in %)') + plt.boxplot([100.0 * (y - x) / x for x, y in zip(data[d], data2[d])]) + plt.hlines(0.0, 0.5, 1.5, linestyle='dotted') -for i,d in enumerate(['badness','#edges','#trigs','#tets']): - ax = plt.subplot(2,5,6+i) - plt.title('difference '+d+' (in %)') -# plt.violinplot([(y-x)/x for x,y in zip(data[d],data2[d])], showmedians=True) - plt.boxplot([100.0*(y-x)/x for x,y in zip(data[d],data2[d])]) - plt.hlines(0.0, 0.5,1.5, linestyle='dotted') +plt.tight_layout() # Adjust layout # plt.savefig('comparison.png', dpi=100) diff --git a/tests/pytest/results.json b/tests/pytest/results.json index 3cdc607c..d079b4ed 100644 --- a/tests/pytest/results.json +++ b/tests/pytest/results.json @@ -2,18 +2,18 @@ "boundarycondition.geo": [ { "angles_tet": [ - 27.291, - 136.38 + 22.08, + 143.36 ], "angles_trig": [ - 23.577, - 123.09 + 18.539, + 142.35 ], "ne1d": 74, "ne2d": 52, - "ne3d": 48, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 7, 7, 16, 3, 6, 1, 1, 0, 1]", - "total_badness": 74.651719788 + "ne3d": 41, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 3, 1, 0, 11, 5, 14, 1, 4, 0, 0, 0, 0]", + "total_badness": 69.280452693 }, { "angles_tet": [ @@ -47,18 +47,18 @@ }, { "angles_tet": [ - 27.292, - 136.38 + 30.893, + 127.37 ], "angles_trig": [ - 23.578, - 123.09 + 26.565, + 91.094 ], "ne1d": 74, "ne2d": 52, - "ne3d": 48, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 7, 7, 16, 3, 6, 1, 1, 0, 1]", - "total_badness": 74.651710944 + "ne3d": 36, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 5, 15, 1, 4, 0, 0, 0, 0]", + "total_badness": 55.902432365 }, { "angles_tet": [ @@ -71,14 +71,14 @@ ], "ne1d": 118, "ne2d": 126, - "ne3d": 141, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 18, 11, 17, 30, 19, 19, 14, 7, 2]", - "total_badness": 196.01215512 + "ne3d": 136, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 22, 10, 15, 29, 16, 19, 13, 7, 1]", + "total_badness": 190.84531317 }, { "angles_tet": [ - 26.405, - 131.02 + 28.55, + 131.21 ], "angles_trig": [ 24.196, @@ -86,26 +86,26 @@ ], "ne1d": 181, "ne2d": 291, - "ne3d": 459, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 9, 18, 30, 44, 69, 111, 100, 54, 18]", - "total_badness": 575.46697618 + "ne3d": 423, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 9, 22, 27, 54, 71, 81, 87, 57, 10]", + "total_badness": 535.77438972 } ], "boxcyl.geo": [ { "angles_tet": [ - 21.213, - 142.56 + 21.224, + 142.43 ], "angles_trig": [ - 22.379, + 22.403, 121.98 ], "ne1d": 190, "ne2d": 450, - "ne3d": 834, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 3, 24, 93, 74, 76, 85, 110, 106, 100, 99, 45, 19]", - "total_badness": 1200.3294639 + "ne3d": 751, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 16, 46, 55, 75, 83, 71, 89, 84, 91, 87, 39, 15]", + "total_badness": 1107.3889231 }, { "angles_tet": [ @@ -118,14 +118,14 @@ ], "ne1d": 94, "ne2d": 108, - "ne3d": 112, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 4, 5, 15, 14, 6, 14, 6, 10, 7, 10, 3, 15, 2, 0]", - "total_badness": 200.73145455 + "ne3d": 111, + "quality_histogram": "[0, 0, 0, 0, 1, 1, 2, 5, 13, 15, 5, 14, 6, 11, 7, 11, 3, 15, 2, 0]", + "total_badness": 196.51870279 }, { "angles_tet": [ - 14.751, - 158.04 + 13.199, + 159.74 ], "angles_trig": [ 19.228, @@ -133,238 +133,238 @@ ], "ne1d": 136, "ne2d": 204, - "ne3d": 326, - "quality_histogram": "[0, 0, 0, 2, 2, 7, 8, 10, 14, 12, 12, 22, 26, 34, 50, 43, 45, 26, 10, 3]", - "total_badness": 530.84214658 + "ne3d": 298, + "quality_histogram": "[0, 0, 0, 2, 3, 4, 9, 12, 12, 19, 23, 12, 26, 30, 36, 38, 35, 26, 11, 0]", + "total_badness": 500.45563074 }, { "angles_tet": [ - 21.211, - 138.67 + 21.222, + 131.85 ], "angles_trig": [ - 22.376, + 22.403, 121.98 ], "ne1d": 190, "ne2d": 450, - "ne3d": 833, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 24, 86, 78, 71, 79, 124, 107, 92, 99, 51, 21]", - "total_badness": 1192.8552253 + "ne3d": 743, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 15, 46, 50, 70, 84, 67, 88, 85, 93, 92, 39, 14]", + "total_badness": 1090.2554152 }, { "angles_tet": [ - 26.153, - 141.36 + 24.636, + 138.29 ], "angles_trig": [ - 25.575, - 114.94 + 23.311, + 117.05 ], "ne1d": 284, "ne2d": 922, - "ne3d": 3853, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 15, 42, 118, 219, 455, 671, 787, 798, 574, 170]", - "total_badness": 4779.2253231 + "ne3d": 3028, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 16, 43, 81, 218, 369, 489, 604, 623, 449, 132]", + "total_badness": 3768.3794003 }, { "angles_tet": [ - 25.158, - 143.56 + 29.0, + 138.89 ], "angles_trig": [ - 26.346, - 116.86 + 28.033, + 111.86 ], "ne1d": 456, "ne2d": 2480, - "ne3d": 18633, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 17, 93, 295, 810, 1622, 2827, 3994, 4471, 3391, 1108]", - "total_badness": 22509.04709 + "ne3d": 14520, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 9, 44, 181, 508, 1170, 2162, 3142, 3510, 2863, 930]", + "total_badness": 17404.36259 } ], "circle_on_cube.geo": [ { "angles_tet": [ - 25.073, - 134.64 + 26.444, + 133.76 ], "angles_trig": [ - 20.125, - 122.26 + 22.641, + 113.83 ], "ne1d": 94, "ne2d": 162, - "ne3d": 616, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 4, 13, 15, 36, 61, 59, 78, 112, 98, 85, 43, 12]", - "total_badness": 838.94349075 + "ne3d": 537, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 13, 19, 49, 60, 66, 109, 95, 68, 44, 11]", + "total_badness": 714.42871623 }, { "angles_tet": [ - 15.603, - 140.66 + 16.709, + 142.87 ], "angles_trig": [ 19.788, - 123.88 + 124.53 ], "ne1d": 40, "ne2d": 30, - "ne3d": 43, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 0, 2, 5, 9, 7, 5, 5, 3, 3, 2, 0, 0, 1, 0]", - "total_badness": 82.109638474 + "ne3d": 37, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 2, 0, 1, 11, 8, 5, 4, 3, 0, 2, 0, 0, 0, 0]", + "total_badness": 72.253422388 }, { "angles_tet": [ - 20.678, - 133.74 + 26.508, + 128.24 ], "angles_trig": [ 23.119, - 112.86 + 117.29 ], "ne1d": 62, "ne2d": 76, - "ne3d": 155, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 9, 16, 26, 34, 29, 13, 10, 8, 0]", - "total_badness": 220.46268417 + "ne3d": 131, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 8, 22, 16, 30, 20, 15, 8, 5, 1]", + "total_badness": 185.23356052 }, { "angles_tet": [ - 25.158, - 131.6 + 28.726, + 134.02 ], "angles_trig": [ - 23.161, - 113.1 + 22.971, + 114.54 ], "ne1d": 94, "ne2d": 162, - "ne3d": 587, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 22, 44, 62, 62, 114, 104, 94, 57, 15]", - "total_badness": 769.56121713 + "ne3d": 490, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 10, 15, 38, 45, 73, 110, 83, 74, 34, 7]", + "total_badness": 645.37905468 }, { "angles_tet": [ - 22.472, - 138.67 + 28.79, + 135.96 ], "angles_trig": [ - 26.461, - 115.01 + 28.056, + 112.66 ], "ne1d": 138, "ne2d": 370, - "ne3d": 2009, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 13, 21, 56, 130, 220, 339, 438, 428, 295, 67]", - "total_badness": 2495.8001047 + "ne3d": 1534, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 11, 35, 83, 172, 256, 337, 351, 220, 68]", + "total_badness": 1884.7047242 }, { "angles_tet": [ - 25.429, - 141.91 + 26.5, + 141.58 ], "angles_trig": [ - 26.66, - 115.7 + 26.328, + 110.62 ], "ne1d": 224, "ne2d": 922, - "ne3d": 12168, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 8, 17, 52, 227, 553, 1180, 1901, 2590, 2911, 2091, 637]", - "total_badness": 14779.532725 + "ne3d": 9117, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 10, 31, 123, 329, 741, 1263, 1954, 2214, 1832, 618]", + "total_badness": 10924.299533 } ], "cone.geo": [ { "angles_tet": [ - 14.938, - 141.57 + 18.902, + 142.51 ], "angles_trig": [ - 16.548, - 122.02 + 15.975, + 122.42 ], "ne1d": 64, "ne2d": 718, - "ne3d": 1191, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 2, 18, 41, 51, 83, 122, 133, 145, 163, 130, 138, 89, 60, 15]", - "total_badness": 1802.9323748 + "ne3d": 1145, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 7, 17, 40, 54, 82, 124, 129, 158, 136, 126, 116, 97, 46, 12]", + "total_badness": 1753.9631189 }, { "angles_tet": [ - 8.3849, - 167.59 + 3.7664, + 169.51 ], "angles_trig": [ - 10.826, - 151.58 + 12.979, + 139.05 ], "ne1d": 32, "ne2d": 208, - "ne3d": 486, - "quality_histogram": "[0, 0, 1, 4, 5, 16, 34, 28, 32, 34, 49, 35, 37, 42, 39, 42, 26, 28, 26, 8]", - "total_badness": 915.87761832 + "ne3d": 267, + "quality_histogram": "[0, 1, 3, 3, 6, 18, 38, 40, 18, 12, 16, 10, 11, 20, 12, 25, 14, 12, 8, 0]", + "total_badness": 624.33828402 }, { "angles_tet": [ - 7.5064, - 168.59 + 10.844, + 163.33 ], "angles_trig": [ - 9.0552, - 153.87 + 9.6496, + 150.01 ], "ne1d": 48, "ne2d": 420, - "ne3d": 618, - "quality_histogram": "[0, 0, 4, 11, 7, 17, 9, 23, 39, 60, 71, 85, 85, 55, 56, 27, 42, 19, 8, 0]", - "total_badness": 1183.5702625 + "ne3d": 537, + "quality_histogram": "[0, 0, 2, 4, 11, 22, 11, 10, 28, 66, 77, 68, 73, 55, 45, 29, 14, 14, 8, 0]", + "total_badness": 1034.0221247 }, { "angles_tet": [ - 17.166, - 143.86 + 18.484, + 140.51 ], "angles_trig": [ - 19.54, - 120.27 + 17.408, + 122.16 ], "ne1d": 64, "ne2d": 718, - "ne3d": 1186, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 8, 22, 42, 92, 106, 123, 168, 148, 166, 127, 103, 62, 17]", - "total_badness": 1745.7492969 + "ne3d": 1129, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 7, 32, 45, 98, 114, 134, 146, 153, 132, 115, 92, 48, 10]", + "total_badness": 1702.0762407 }, { "angles_tet": [ - 25.516, - 138.4 + 18.863, + 137.16 ], "angles_trig": [ - 25.119, - 121.58 + 22.582, + 119.38 ], "ne1d": 96, "ne2d": 1648, - "ne3d": 4372, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 16, 60, 127, 237, 407, 551, 707, 802, 764, 543, 156]", - "total_badness": 5622.2033105 + "ne3d": 3805, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 0, 4, 29, 65, 158, 271, 388, 475, 646, 674, 591, 396, 107]", + "total_badness": 4995.2199245 }, { "angles_tet": [ - 20.726, - 143.6 + 23.624, + 143.07 ], "angles_trig": [ - 23.171, - 123.6 + 24.84, + 120.86 ], "ne1d": 160, "ne2d": 4738, - "ne3d": 27128, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 6, 18, 86, 216, 621, 1451, 2693, 4334, 5762, 5891, 4576, 1473]", - "total_badness": 33206.092666 + "ne3d": 21358, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 20, 69, 206, 492, 1110, 2071, 3275, 4433, 4701, 3671, 1308]", + "total_badness": 26097.176833 } ], "cube.geo": [ @@ -430,33 +430,33 @@ }, { "angles_tet": [ - 27.354, - 136.27 + 33.549, + 129.66 ], "angles_trig": [ - 21.671, - 126.93 + 27.158, + 119.33 ], "ne1d": 48, "ne2d": 36, - "ne3d": 57, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 1, 10, 12, 9, 12, 4, 1, 2, 0]", - "total_badness": 83.840161698 + "ne3d": 38, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 5, 1, 13, 0, 2, 5, 0]", + "total_badness": 53.231047857 }, { "angles_tet": [ - 31.709, - 132.62 + 31.794, + 132.85 ], "angles_trig": [ 28.796, - 108.23 + 105.01 ], "ne1d": 72, "ne2d": 92, - "ne3d": 138, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 11, 8, 8, 25, 23, 30, 17, 10]", - "total_badness": 173.92559042 + "ne3d": 132, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 11, 5, 13, 26, 18, 30, 15, 9]", + "total_badness": 166.4958056 } ], "cubeandring.geo": [ @@ -466,44 +466,44 @@ 170.37 ], "angles_trig": [ - 11.614, + 11.709, 156.34 ], "ne1d": 262, "ne2d": 652, - "ne3d": 2038, - "quality_histogram": "[0, 2, 7, 27, 57, 102, 101, 108, 81, 61, 60, 83, 136, 187, 241, 238, 234, 170, 107, 36]", - "total_badness": 3798.8151666 + "ne3d": 1831, + "quality_histogram": "[0, 2, 4, 16, 42, 82, 88, 111, 82, 36, 58, 73, 138, 172, 211, 238, 191, 161, 97, 29]", + "total_badness": 3327.3635018 }, { "angles_tet": [ - 17.294, - 155.18 + 25.216, + 134.34 ], "angles_trig": [ 22.715, - 110.61 + 115.73 ], "ne1d": 134, "ne2d": 142, - "ne3d": 205, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 0, 1, 0, 3, 7, 17, 26, 37, 30, 28, 34, 15, 2, 4]", - "total_badness": 293.89415407 + "ne3d": 186, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 8, 19, 24, 28, 20, 28, 31, 15, 7, 2]", + "total_badness": 265.13433105 }, { "angles_tet": [ - 14.206, - 159.84 + 20.8, + 134.83 ], "angles_trig": [ - 20.057, + 19.613, 131.52 ], "ne1d": 190, "ne2d": 242, - "ne3d": 501, - "quality_histogram": "[0, 0, 0, 0, 2, 0, 0, 5, 4, 14, 39, 54, 41, 82, 64, 82, 54, 37, 23, 0]", - "total_badness": 745.18627676 + "ne3d": 437, + "quality_histogram": "[0, 0, 0, 0, 1, 0, 0, 4, 3, 15, 34, 53, 36, 68, 71, 58, 42, 38, 11, 3]", + "total_badness": 652.96404483 }, { "angles_tet": [ @@ -516,39 +516,39 @@ ], "ne1d": 262, "ne2d": 652, - "ne3d": 1894, - "quality_histogram": "[0, 2, 5, 20, 38, 79, 95, 106, 70, 32, 41, 60, 94, 145, 217, 266, 250, 198, 121, 55]", - "total_badness": 3344.7627877 + "ne3d": 1641, + "quality_histogram": "[0, 0, 3, 13, 35, 76, 82, 101, 77, 29, 36, 54, 101, 133, 179, 232, 215, 148, 102, 25]", + "total_badness": 2926.5758078 }, { "angles_tet": [ - 21.707, - 139.77 + 19.908, + 142.77 ], "angles_trig": [ - 23.443, - 118.77 + 21.306, + 123.5 ], "ne1d": 378, "ne2d": 1360, - "ne3d": 7586, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 9, 46, 126, 290, 603, 925, 1250, 1521, 1436, 1062, 317]", - "total_badness": 9530.8442156 + "ne3d": 6102, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 9, 23, 54, 104, 215, 426, 700, 994, 1167, 1210, 918, 281]", + "total_badness": 7655.9055733 }, { "angles_tet": [ - 23.791, - 144.45 + 22.179, + 143.43 ], "angles_trig": [ - 26.716, - 123.99 + 24.189, + 120.95 ], "ne1d": 624, "ne2d": 3860, - "ne3d": 38096, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 2, 26, 61, 218, 722, 1809, 3652, 6020, 8063, 8757, 6666, 2099]", - "total_badness": 46320.985555 + "ne3d": 29147, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 3, 11, 37, 154, 453, 1172, 2338, 4202, 6083, 6991, 5792, 1911]", + "total_badness": 35056.080141 } ], "cubeandspheres.geo": [ @@ -646,294 +646,202 @@ "cubemcyl.geo": [ { "angles_tet": [ - 17.552, - 149.02 + 16.556, + 148.15 ], "angles_trig": [ - 19.505, - 129.13 - ], - "ne1d": 142, - "ne2d": 2400, - "ne3d": 20169, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 5, 25, 79, 231, 483, 876, 1588, 2360, 2911, 3368, 3435, 2711, 1628, 469]", - "total_badness": 27089.560986 - }, - { - "angles_tet": [ - 15.294, - 163.36 - ], - "angles_trig": [ - 13.852, - 128.58 - ], - "ne1d": 64, - "ne2d": 556, - "ne3d": 3011, - "quality_histogram": "[0, 0, 0, 1, 3, 1, 14, 25, 40, 85, 116, 209, 333, 406, 462, 445, 441, 279, 120, 31]", - "total_badness": 4347.4002113 - }, - { - "angles_tet": [ - 17.198, - 146.78 - ], - "angles_trig": [ - 19.119, - 125.8 - ], - "ne1d": 102, - "ne2d": 1280, - "ne3d": 8063, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 5, 27, 79, 200, 404, 723, 1075, 1303, 1418, 1197, 941, 556, 133]", - "total_badness": 10967.392706 - }, - { - "angles_tet": [ - 19.398, - 141.79 - ], - "angles_trig": [ - 21.638, + 18.399, 126.55 ], "ne1d": 142, "ne2d": 2400, - "ne3d": 19151, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 3, 14, 55, 170, 418, 1024, 1805, 2657, 3451, 3664, 3317, 2042, 530]", - "total_badness": 24613.208269 + "ne3d": 17834, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 14, 68, 173, 414, 797, 1367, 2161, 2671, 3007, 2954, 2394, 1433, 378]", + "total_badness": 23946.045345 }, { "angles_tet": [ - 21.795, - 146.06 + 13.826, + 163.36 ], "angles_trig": [ - 22.867, - 125.23 + 13.852, + 130.91 + ], + "ne1d": 64, + "ne2d": 556, + "ne3d": 2511, + "quality_histogram": "[0, 0, 0, 1, 3, 4, 13, 24, 40, 78, 129, 210, 285, 374, 396, 382, 275, 177, 99, 21]", + "total_badness": 3719.5197616 + }, + { + "angles_tet": [ + 21.647, + 145.79 + ], + "angles_trig": [ + 20.886, + 124.66 + ], + "ne1d": 102, + "ne2d": 1280, + "ne3d": 6520, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 7, 9, 78, 150, 366, 638, 856, 1115, 1187, 936, 683, 399, 96]", + "total_badness": 8923.733234 + }, + { + "angles_tet": [ + 21.141, + 143.5 + ], + "angles_trig": [ + 21.506, + 128.13 + ], + "ne1d": 142, + "ne2d": 2400, + "ne3d": 15256, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 2, 23, 47, 126, 348, 812, 1473, 2161, 2716, 2937, 2488, 1665, 457]", + "total_badness": 19641.595824 + }, + { + "angles_tet": [ + 24.461, + 140.07 + ], + "angles_trig": [ + 24.784, + 121.83 ], "ne1d": 210, "ne2d": 5460, - "ne3d": 88820, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 11, 51, 248, 703, 2183, 5117, 9583, 14386, 18836, 19401, 14091, 4209]", - "total_badness": 109216.91549 + "ne3d": 66203, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 3, 39, 143, 429, 1353, 3166, 6206, 10234, 14000, 15463, 11581, 3586]", + "total_badness": 80546.827457 }, { "angles_tet": [ - 23.058, - 143.66 + 24.097, + 146.01 ], "angles_trig": [ - 23.971, - 124.25 + 23.902, + 124.4 ], "ne1d": 362, "ne2d": 15082, - "ne3d": 520159, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 9, 85, 499, 2149, 7346, 21113, 47200, 79734, 110083, 123828, 97201, 30912]", - "total_badness": 627466.22084 + "ne3d": 386834, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 5, 41, 188, 908, 3408, 10433, 25534, 49310, 79289, 100324, 87513, 29881]", + "total_badness": 457691.39756 } ], "cubemsphere.geo": [ { "angles_tet": [ - 22.156, - 150.39 + 22.162, + 142.52 ], "angles_trig": [ - 20.064, - 125.29 + 20.547, + 128.1 ], "ne1d": 90, "ne2d": 570, - "ne3d": 4523, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 9, 41, 75, 170, 331, 494, 702, 821, 761, 645, 383, 89]", - "total_badness": 6000.2419679 + "ne3d": 3995, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 5, 29, 70, 153, 269, 429, 644, 736, 713, 553, 301, 92]", + "total_badness": 5295.1664299 }, { "angles_tet": [ - 10.055, - 158.35 + 2.8131, + 175.86 ], "angles_trig": [ - 7.7708, - 147.23 + 10.214, + 139.62 ], "ne1d": 44, "ne2d": 142, - "ne3d": 313, - "quality_histogram": "[0, 0, 1, 2, 9, 23, 31, 23, 34, 37, 31, 32, 22, 30, 18, 10, 4, 3, 1, 2]", - "total_badness": 701.96510542 + "ne3d": 344, + "quality_histogram": "[1, 0, 3, 6, 6, 20, 30, 33, 37, 44, 40, 32, 20, 22, 23, 12, 8, 3, 4, 0]", + "total_badness": 801.60189009 }, { "angles_tet": [ - 13.22, - 146.51 + 21.441, + 137.91 ], "angles_trig": [ - 16.161, - 132.51 + 15.758, + 131.36 ], "ne1d": 68, "ne2d": 272, - "ne3d": 1429, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 0, 2, 7, 15, 38, 92, 155, 214, 253, 241, 169, 143, 76, 23]", - "total_badness": 1985.519867 + "ne3d": 1115, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 3, 4, 14, 31, 67, 113, 183, 202, 178, 149, 99, 58, 13]", + "total_badness": 1554.8534163 }, { "angles_tet": [ - 24.16, - 139.58 + 23.799, + 135.59 ], "angles_trig": [ - 20.668, - 120.71 + 25.09, + 118.46 ], "ne1d": 90, "ne2d": 570, - "ne3d": 4315, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 12, 36, 65, 214, 404, 593, 811, 842, 765, 470, 102]", - "total_badness": 5519.2080716 + "ne3d": 3360, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 16, 48, 146, 270, 503, 620, 661, 596, 397, 96]", + "total_badness": 4265.8200532 }, { "angles_tet": [ - 25.558, - 139.27 + 28.171, + 133.52 ], "angles_trig": [ - 21.95, - 123.73 + 26.253, + 118.16 ], "ne1d": 146, "ne2d": 1366, - "ne3d": 17357, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 8, 45, 131, 383, 1002, 1818, 2868, 3691, 3818, 2778, 814]", - "total_badness": 21308.513568 + "ne3d": 13140, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 87, 221, 636, 1253, 2150, 2862, 3060, 2218, 641]", + "total_badness": 15990.17626 }, { "angles_tet": [ - 24.327, - 140.29 + 26.132, + 136.98 ], "angles_trig": [ - 25.758, - 120.76 + 25.57, + 116.53 ], "ne1d": 248, "ne2d": 4248, - "ne3d": 112960, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 17, 100, 493, 1726, 4923, 10719, 17771, 23842, 26353, 20492, 6522]", - "total_badness": 136671.30101 - } - ], - "cylinder.geo": [ - { - "angles_tet": [ - 19.076, - 144.67 - ], - "angles_trig": [ - 25.583, - 111.5 - ], - "ne1d": 52, - "ne2d": 286, - "ne3d": 407, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 2, 4, 10, 32, 48, 50, 81, 56, 52, 42, 14, 14]", - "total_badness": 567.546292 - }, - { - "angles_tet": [ - 24.676, - 151.98 - ], - "angles_trig": [ - 24.811, - 126.7 - ], - "ne1d": 24, - "ne2d": 66, - "ne3d": 70, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 0, 6, 5, 5, 2, 6, 5, 3, 5, 14, 17, 1, 0]", - "total_badness": 105.64076027 - }, - { - "angles_tet": [ - 8.4923, - 161.34 - ], - "angles_trig": [ - 20.122, - 127.45 - ], - "ne1d": 36, - "ne2d": 152, - "ne3d": 358, - "quality_histogram": "[0, 0, 1, 0, 0, 2, 5, 11, 21, 19, 22, 22, 31, 29, 35, 39, 57, 37, 17, 10]", - "total_badness": 559.67848726 - }, - { - "angles_tet": [ - 19.058, - 144.69 - ], - "angles_trig": [ - 25.588, - 111.45 - ], - "ne1d": 52, - "ne2d": 286, - "ne3d": 407, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 0, 3, 10, 31, 45, 55, 73, 61, 53, 46, 15, 13]", - "total_badness": 563.90833945 - }, - { - "angles_tet": [ - 21.985, - 136.08 - ], - "angles_trig": [ - 24.141, - 119.73 - ], - "ne1d": 76, - "ne2d": 636, - "ne3d": 1183, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 9, 29, 61, 96, 141, 201, 195, 208, 129, 88, 25]", - "total_badness": 1595.7683733 - }, - { - "angles_tet": [ - 27.151, - 138.19 - ], - "angles_trig": [ - 27.89, - 120.16 - ], - "ne1d": 124, - "ne2d": 1666, - "ne3d": 7963, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 21, 55, 143, 336, 696, 1178, 1725, 1848, 1439, 521]", - "total_badness": 9633.6668545 + "ne3d": 84535, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 38, 239, 826, 2592, 5812, 11280, 17631, 21604, 18465, 6041]", + "total_badness": 100414.60403 } ], "cylsphere.geo": [ { "angles_tet": [ - 16.89, - 146.66 + 16.806, + 141.8 ], "angles_trig": [ - 17.583, - 116.74 + 17.554, + 116.77 ], "ne1d": 104, "ne2d": 494, - "ne3d": 707, - "quality_histogram": "[0, 0, 0, 0, 0, 2, 5, 7, 19, 31, 60, 96, 109, 89, 101, 53, 69, 48, 15, 3]", - "total_badness": 1103.8873525 + "ne3d": 713, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 4, 6, 18, 35, 56, 89, 109, 96, 98, 63, 67, 49, 18, 4]", + "total_badness": 1103.0227656 }, { "angles_tet": [ @@ -946,153 +854,153 @@ ], "ne1d": 48, "ne2d": 100, - "ne3d": 104, - "quality_histogram": "[0, 0, 0, 2, 1, 4, 13, 15, 9, 10, 14, 5, 5, 2, 6, 10, 8, 0, 0, 0]", - "total_badness": 228.55775864 + "ne3d": 94, + "quality_histogram": "[0, 0, 0, 2, 1, 4, 12, 13, 8, 8, 6, 6, 4, 4, 6, 10, 8, 2, 0, 0]", + "total_badness": 203.19030185 }, { "angles_tet": [ - 16.975, - 146.47 + 16.827, + 140.82 ], "angles_trig": [ - 17.533, - 120.59 + 17.531, + 116.44 ], "ne1d": 104, "ne2d": 494, - "ne3d": 706, - "quality_histogram": "[0, 0, 0, 0, 0, 2, 5, 6, 17, 30, 59, 98, 99, 97, 96, 68, 65, 45, 16, 3]", - "total_badness": 1096.9819246 + "ne3d": 685, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 4, 6, 24, 49, 71, 105, 100, 90, 79, 50, 49, 41, 13, 3]", + "total_badness": 1099.947193 }, { "angles_tet": [ - 19.739, - 142.01 + 23.775, + 139.74 ], "angles_trig": [ - 21.005, - 119.84 + 22.07, + 119.33 ], "ne1d": 152, "ne2d": 1082, - "ne3d": 2842, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 5, 22, 43, 84, 156, 233, 309, 459, 535, 529, 378, 87]", - "total_badness": 3653.5906442 + "ne3d": 2428, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 5, 12, 47, 98, 156, 241, 314, 341, 430, 415, 289, 80]", + "total_badness": 3165.0550273 }, { "angles_tet": [ - 25.231, - 139.3 + 25.953, + 137.57 ], "angles_trig": [ - 25.146, - 122.8 + 27.924, + 118.72 ], "ne1d": 248, "ne2d": 2810, - "ne3d": 17714, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 14, 29, 100, 280, 741, 1663, 2724, 3885, 4147, 3098, 1032]", - "total_badness": 21466.883949 + "ne3d": 13898, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 28, 80, 235, 563, 1170, 2020, 2879, 3303, 2681, 930]", + "total_badness": 16757.815083 } ], "ellipsoid.geo": [ { "angles_tet": [ - 18.985, - 146.67 + 19.068, + 144.8 ], "angles_trig": [ - 18.356, - 122.93 + 18.52, + 120.49 ], "ne1d": 0, "ne2d": 694, - "ne3d": 1271, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 7, 34, 67, 108, 149, 145, 161, 175, 147, 107, 92, 59, 18]", - "total_badness": 1927.202371 + "ne3d": 1213, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 17, 36, 66, 102, 149, 134, 147, 166, 129, 104, 106, 35, 20]", + "total_badness": 1859.2508656 }, { "angles_tet": [ - 4.4724, - 169.99 + 5.2584, + 171.14 ], "angles_trig": [ - 9.3765, - 160.0 + 13.512, + 152.22 ], "ne1d": 0, "ne2d": 156, - "ne3d": 536, - "quality_histogram": "[0, 13, 28, 52, 60, 66, 49, 44, 44, 37, 27, 35, 22, 18, 13, 9, 7, 6, 6, 0]", - "total_badness": 1855.3951762 + "ne3d": 264, + "quality_histogram": "[0, 4, 11, 25, 53, 58, 33, 23, 23, 12, 7, 5, 4, 4, 1, 0, 1, 0, 0, 0]", + "total_badness": 995.21455744 }, { "angles_tet": [ - 20.08, - 138.43 + 19.38, + 137.84 ], "angles_trig": [ - 19.842, - 116.21 + 18.638, + 115.93 ], "ne1d": 0, "ne2d": 384, - "ne3d": 588, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 7, 17, 40, 68, 74, 90, 109, 64, 52, 37, 22, 7]", - "total_badness": 870.44417377 + "ne3d": 580, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 5, 16, 43, 63, 83, 89, 100, 57, 57, 32, 23, 10]", + "total_badness": 859.84790156 }, { "angles_tet": [ - 22.423, - 143.66 + 18.382, + 141.28 ], "angles_trig": [ - 19.734, - 119.91 + 19.357, + 122.31 ], "ne1d": 0, "ne2d": 694, - "ne3d": 1259, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 3, 20, 61, 90, 124, 145, 171, 157, 147, 147, 103, 75, 16]", - "total_badness": 1857.1598634 + "ne3d": 1160, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 10, 44, 55, 103, 135, 147, 161, 140, 132, 85, 87, 43, 17]", + "total_badness": 1782.4621003 }, { "angles_tet": [ - 21.995, - 138.77 + 22.541, + 137.85 ], "angles_trig": [ - 25.46, - 115.64 + 23.173, + 122.67 ], "ne1d": 0, "ne2d": 1578, - "ne3d": 5402, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 2, 7, 41, 142, 273, 437, 588, 900, 1031, 1032, 733, 215]", - "total_badness": 6841.327071 + "ne3d": 4459, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 22, 69, 199, 288, 416, 572, 641, 762, 738, 569, 181]", + "total_badness": 5785.6787619 }, { "angles_tet": [ - 21.744, - 144.6 + 26.132, + 137.27 ], "angles_trig": [ - 26.751, - 121.56 + 24.331, + 124.82 ], "ne1d": 0, "ne2d": 4212, - "ne3d": 37347, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 9, 52, 185, 546, 1522, 3262, 5723, 7899, 8903, 6950, 2294]", - "total_badness": 45064.497844 + "ne3d": 28541, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 32, 150, 441, 1024, 2212, 3959, 5845, 7012, 5816, 2045]", + "total_badness": 34195.305763 } ], "ellipticcone.geo": [ { "angles_tet": [ - 23.263, - 146.25 + 21.191, + 143.04 ], "angles_trig": [ 22.188, @@ -1100,176 +1008,176 @@ ], "ne1d": 174, "ne2d": 1492, - "ne3d": 4957, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 8, 34, 88, 187, 310, 511, 694, 881, 895, 745, 469, 135]", - "total_badness": 6507.6297349 + "ne3d": 4458, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 12, 33, 80, 170, 285, 484, 684, 741, 769, 654, 399, 145]", + "total_badness": 5878.2970409 }, { "angles_tet": [ - 20.274, + 18.757, 150.89 ], "angles_trig": [ - 22.128, + 20.597, 124.89 ], "ne1d": 86, "ne2d": 336, - "ne3d": 469, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 0, 6, 20, 36, 44, 66, 67, 67, 47, 50, 44, 16, 5]", - "total_badness": 695.59119444 + "ne3d": 453, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 2, 9, 17, 38, 40, 52, 65, 61, 58, 49, 42, 10, 8]", + "total_badness": 676.43193266 }, { "angles_tet": [ - 16.545, + 16.986, 153.27 ], "angles_trig": [ - 16.861, + 18.22, 134.96 ], "ne1d": 130, "ne2d": 794, - "ne3d": 1476, - "quality_histogram": "[0, 0, 0, 0, 1, 0, 19, 28, 50, 58, 53, 90, 145, 165, 181, 203, 199, 155, 101, 28]", - "total_badness": 2177.7084872 + "ne3d": 1385, + "quality_histogram": "[0, 0, 0, 0, 1, 2, 12, 28, 58, 58, 77, 88, 158, 144, 191, 155, 170, 136, 90, 17]", + "total_badness": 2086.8296552 }, { "angles_tet": [ - 24.549, - 137.43 + 22.207, + 144.22 ], "angles_trig": [ - 22.188, - 117.33 + 20.311, + 124.34 ], "ne1d": 174, "ne2d": 1492, - "ne3d": 4748, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 3, 7, 32, 96, 200, 389, 599, 887, 945, 888, 521, 181]", - "total_badness": 6023.4146593 + "ne3d": 4049, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 1, 10, 30, 77, 193, 316, 526, 717, 820, 721, 488, 148]", + "total_badness": 5141.2657775 }, { "angles_tet": [ - 19.964, - 146.92 + 19.813, + 147.03 ], "angles_trig": [ - 22.162, + 21.794, 126.99 ], "ne1d": 258, "ne2d": 3318, - "ne3d": 13093, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 13, 35, 131, 267, 525, 918, 1525, 2178, 2534, 2516, 1864, 585]", - "total_badness": 16495.184175 + "ne3d": 11071, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 20, 45, 147, 286, 495, 839, 1243, 1701, 2054, 2172, 1580, 487]", + "total_badness": 14040.574161 }, { "angles_tet": [ - 20.933, - 146.0 + 19.674, + 144.72 ], "angles_trig": [ 22.947, - 128.99 + 126.66 ], "ne1d": 432, "ne2d": 9184, - "ne3d": 68625, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 8, 20, 51, 215, 569, 1425, 3426, 6873, 10848, 14353, 15147, 11893, 3795]", - "total_badness": 83844.770837 + "ne3d": 54158, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 8, 18, 54, 221, 535, 1196, 2522, 4466, 7523, 10751, 12523, 10799, 3540]", + "total_badness": 65682.333844 } ], "ellipticcyl.geo": [ { "angles_tet": [ - 20.908, - 145.52 + 17.353, + 144.66 ], "angles_trig": [ - 21.34, - 121.52 + 20.926, + 125.85 ], "ne1d": 156, "ne2d": 942, - "ne3d": 2141, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 3, 8, 29, 62, 101, 159, 256, 306, 360, 377, 282, 155, 43]", - "total_badness": 2890.2110231 + "ne3d": 2034, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 6, 15, 34, 73, 113, 164, 233, 336, 291, 329, 251, 148, 40]", + "total_badness": 2793.4385428 }, { "angles_tet": [ - 16.477, + 16.495, 144.27 ], "angles_trig": [ - 21.842, - 119.59 + 21.861, + 135.25 ], "ne1d": 76, "ne2d": 200, - "ne3d": 241, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 2, 11, 23, 16, 32, 31, 40, 30, 30, 14, 6, 4, 0]", - "total_badness": 387.30490812 + "ne3d": 242, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 3, 14, 22, 16, 31, 31, 36, 30, 32, 15, 6, 4, 0]", + "total_badness": 390.97240271 }, { "angles_tet": [ - 24.683, - 136.88 + 23.926, + 135.29 ], "angles_trig": [ - 24.591, - 114.49 + 24.282, + 116.66 ], "ne1d": 116, "ne2d": 542, - "ne3d": 1031, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 16, 45, 82, 99, 163, 195, 190, 115, 99, 23]", - "total_badness": 1364.8877139 + "ne3d": 942, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 23, 40, 94, 107, 146, 178, 156, 103, 76, 11]", + "total_badness": 1270.1928118 }, { "angles_tet": [ - 21.397, - 134.44 + 21.053, + 142.98 ], "angles_trig": [ - 21.803, - 118.55 + 22.458, + 117.6 ], "ne1d": 156, "ne2d": 942, - "ne3d": 2091, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 15, 36, 73, 126, 232, 306, 377, 391, 305, 180, 48]", - "total_badness": 2749.9153281 + "ne3d": 1931, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 7, 27, 55, 78, 130, 184, 281, 367, 319, 266, 179, 37]", + "total_badness": 2579.9354136 }, { "angles_tet": [ - 21.299, - 145.92 + 23.667, + 138.58 ], "angles_trig": [ - 22.971, - 123.45 + 25.236, + 120.17 ], "ne1d": 232, "ne2d": 2102, - "ne3d": 7936, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 2, 7, 36, 102, 243, 506, 936, 1318, 1618, 1632, 1161, 374]", - "total_badness": 9862.7920315 + "ne3d": 6638, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 7, 45, 118, 262, 475, 812, 1073, 1336, 1300, 923, 285]", + "total_badness": 8335.0561403 }, { "angles_tet": [ - 24.388, - 140.11 + 22.292, + 144.61 ], "angles_trig": [ - 24.731, - 114.31 + 24.768, + 126.3 ], "ne1d": 388, "ne2d": 5914, - "ne3d": 54280, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 57, 235, 715, 1972, 4653, 8290, 11507, 13163, 10250, 3423]", - "total_badness": 65288.837508 + "ne3d": 41917, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 5, 9, 35, 152, 474, 1287, 3020, 5596, 8738, 10547, 9050, 3003]", + "total_badness": 49914.609895 } ], "extrusion.geo": [ @@ -1335,18 +1243,18 @@ }, { "angles_tet": [ - 13.66, - 140.84 + 20.077, + 139.4 ], "angles_trig": [ - 16.325, + 18.634, 118.98 ], "ne1d": 276, "ne2d": 544, - "ne3d": 623, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 4, 11, 18, 30, 47, 70, 73, 69, 81, 73, 75, 52, 17, 3]", - "total_badness": 953.76990304 + "ne3d": 598, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 8, 26, 43, 52, 58, 68, 66, 78, 63, 75, 42, 12, 6]", + "total_badness": 928.42108853 } ], "fichera.geo": [ @@ -1413,38 +1321,38 @@ { "angles_tet": [ 28.158, - 128.52 + 136.35 ], "angles_trig": [ 28.353, - 114.07 + 107.49 ], "ne1d": 96, "ne2d": 108, - "ne3d": 194, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 6, 12, 26, 25, 34, 34, 35, 12, 7]", - "total_badness": 254.28246256 + "ne3d": 177, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 7, 15, 16, 11, 33, 36, 32, 20, 5]", + "total_badness": 228.70758215 }, { "angles_tet": [ - 28.713, - 135.86 + 27.898, + 129.67 ], "angles_trig": [ - 27.552, + 26.954, 105.69 ], "ne1d": 144, "ne2d": 264, - "ne3d": 484, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 12, 23, 37, 65, 105, 72, 87, 59, 23]", - "total_badness": 613.06762292 + "ne3d": 455, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 12, 24, 39, 63, 97, 91, 63, 48, 17]", + "total_badness": 582.04207662 } ], "hinge.stl": [ { "angles_tet": [ - 15.803, + 15.509, 152.56 ], "angles_trig": [ @@ -1453,28 +1361,28 @@ ], "ne1d": 456, "ne2d": 1066, - "ne3d": 1694, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 6, 9, 23, 41, 74, 105, 136, 200, 243, 292, 219, 204, 110, 31]", - "total_badness": 2383.0874819 + "ne3d": 1622, + "quality_histogram": "[0, 0, 0, 0, 0, 2, 4, 13, 26, 35, 66, 106, 137, 214, 232, 260, 226, 173, 103, 25]", + "total_badness": 2297.0354205 }, { "angles_tet": [ - 4.8415, - 163.34 + 4.0123, + 173.21 ], "angles_trig": [ 8.9881, - 149.17 + 142.67 ], "ne1d": 298, "ne2d": 502, - "ne3d": 610, - "quality_histogram": "[0, 0, 3, 5, 10, 16, 27, 39, 43, 38, 55, 65, 64, 51, 49, 62, 38, 24, 16, 5]", - "total_badness": 1160.8468965 + "ne3d": 600, + "quality_histogram": "[0, 1, 1, 4, 10, 14, 27, 40, 49, 43, 56, 62, 63, 49, 43, 59, 36, 24, 14, 5]", + "total_badness": 1150.0886518 }, { "angles_tet": [ - 12.929, + 11.259, 152.0 ], "angles_trig": [ @@ -1483,24 +1391,24 @@ ], "ne1d": 370, "ne2d": 758, - "ne3d": 982, - "quality_histogram": "[0, 0, 0, 0, 0, 7, 6, 25, 33, 29, 47, 79, 112, 128, 147, 142, 96, 68, 50, 13]", - "total_badness": 1492.3556478 + "ne3d": 970, + "quality_histogram": "[0, 0, 0, 0, 1, 10, 9, 24, 34, 28, 49, 77, 110, 126, 142, 142, 93, 64, 49, 12]", + "total_badness": 1491.287287 }, { "angles_tet": [ - 17.097, - 147.54 + 17.038, + 147.66 ], "angles_trig": [ 18.124, - 131.28 + 134.43 ], "ne1d": 516, "ne2d": 1454, - "ne3d": 2329, - "quality_histogram": "[0, 0, 0, 0, 0, 2, 2, 13, 22, 39, 68, 145, 210, 272, 358, 330, 328, 308, 185, 47]", - "total_badness": 3218.2251987 + "ne3d": 2242, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 2, 14, 24, 45, 74, 121, 218, 278, 348, 301, 321, 297, 156, 42]", + "total_badness": 3117.2593361 }, { "angles_tet": [ @@ -1513,24 +1421,24 @@ ], "ne1d": 722, "ne2d": 2768, - "ne3d": 6516, - "quality_histogram": "[0, 0, 0, 0, 1, 0, 0, 3, 16, 30, 61, 162, 306, 578, 835, 999, 1088, 1188, 967, 282]", - "total_badness": 8307.9517383 + "ne3d": 5826, + "quality_histogram": "[0, 0, 0, 0, 1, 0, 0, 2, 15, 30, 56, 149, 329, 578, 796, 904, 973, 983, 757, 253]", + "total_badness": 7499.63097 }, { "angles_tet": [ - 19.776, - 144.38 + 18.259, + 142.44 ], "angles_trig": [ - 22.289, - 122.14 + 21.873, + 123.52 ], "ne1d": 1862, "ne2d": 18540, - "ne3d": 125397, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 4, 21, 93, 374, 1009, 2638, 6483, 12401, 19519, 26284, 28157, 21536, 6877]", - "total_badness": 153172.81544 + "ne3d": 97369, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 18, 73, 250, 659, 1775, 4369, 8501, 14086, 20127, 22811, 18498, 6200]", + "total_badness": 117806.4728 } ], "lense.in2d": [ @@ -1632,14 +1540,14 @@ 125.39 ], "angles_trig": [ - 35.225, - 109.34 + 35.264, + 90.0 ], "ne1d": 44, "ne2d": 28, - "ne3d": 24, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 20, 0, 2, 0, 0, 0, 0]", - "total_badness": 36.197580222 + "ne3d": 18, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 12, 0, 3, 0, 0, 0, 0]", + "total_badness": 27.2783989 }, { "angles_tet": [ @@ -1677,98 +1585,98 @@ 125.39 ], "angles_trig": [ - 35.225, - 109.34 + 35.264, + 90.0 ], "ne1d": 44, "ne2d": 28, - "ne3d": 24, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 20, 0, 2, 0, 0, 0, 0]", - "total_badness": 36.197580222 + "ne3d": 18, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 12, 0, 3, 0, 0, 0, 0]", + "total_badness": 27.2783989 }, { "angles_tet": [ - 31.097, - 125.11 + 30.544, + 123.51 ], "angles_trig": [ 28.101, - 92.426 + 92.749 ], "ne1d": 80, "ne2d": 66, - "ne3d": 73, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 7, 9, 20, 13, 2, 3, 6]", - "total_badness": 97.336071703 + "ne3d": 68, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 8, 8, 11, 12, 12, 4, 7, 3]", + "total_badness": 90.370075048 }, { "angles_tet": [ 25.594, - 129.87 + 131.82 ], "angles_trig": [ 24.835, - 109.77 + 108.97 ], "ne1d": 122, "ne2d": 192, - "ne3d": 302, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 10, 16, 35, 31, 45, 51, 66, 34, 10]", - "total_badness": 388.25333392 + "ne3d": 291, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 10, 18, 35, 39, 40, 54, 58, 24, 9]", + "total_badness": 378.51475956 } ], "manyholes.geo": [ { "angles_tet": [ - 17.962, - 147.8 + 17.695, + 153.3 ], "angles_trig": [ - 17.912, + 17.033, 139.33 ], "ne1d": 5886, "ne2d": 45882, - "ne3d": 174631, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 7, 64, 229, 668, 1859, 5592, 10791, 18495, 26482, 29904, 31051, 26889, 18192, 4407]", - "total_badness": 227663.03541 + "ne3d": 154731, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 8, 66, 223, 738, 2099, 5794, 10308, 16876, 23404, 25577, 26145, 23113, 16306, 4073]", + "total_badness": 202956.41935 }, { "angles_tet": [ - 13.226, + 11.57, 153.55 ], "angles_trig": [ 14.377, - 130.91 + 134.8 ], "ne1d": 2746, "ne2d": 10428, - "ne3d": 23614, - "quality_histogram": "[0, 0, 0, 1, 2, 8, 39, 141, 333, 732, 1350, 2122, 2750, 3219, 3149, 3069, 2743, 2192, 1438, 326]", - "total_badness": 34314.343654 + "ne3d": 22190, + "quality_histogram": "[0, 0, 0, 1, 2, 10, 37, 144, 313, 674, 1311, 2118, 2650, 3080, 2854, 2712, 2432, 2069, 1426, 357]", + "total_badness": 32325.6857 }, { "angles_tet": [ - 12.344, - 154.1 + 13.279, + 151.1 ], "angles_trig": [ 12.439, - 133.91 + 137.16 ], "ne1d": 4106, "ne2d": 23238, - "ne3d": 63123, - "quality_histogram": "[0, 0, 0, 0, 31, 60, 174, 310, 596, 1169, 2077, 3620, 5748, 7925, 9100, 9947, 9228, 7455, 4552, 1131]", - "total_badness": 87899.222784 + "ne3d": 56938, + "quality_histogram": "[0, 0, 0, 0, 31, 62, 209, 334, 665, 1195, 2198, 3630, 5732, 7498, 8341, 8581, 7870, 6084, 3580, 928]", + "total_badness": 80610.741802 } ], "manyholes2.geo": [ { "angles_tet": [ 10.467, - 152.55 + 151.97 ], "angles_trig": [ 16.373, @@ -1776,9 +1684,9 @@ ], "ne1d": 10202, "ne2d": 41054, - "ne3d": 104058, - "quality_histogram": "[0, 0, 0, 0, 2, 14, 88, 229, 686, 1719, 3645, 6682, 9826, 12717, 14060, 15164, 15249, 13389, 8410, 2178]", - "total_badness": 143298.73232 + "ne3d": 97025, + "quality_histogram": "[0, 0, 0, 0, 3, 15, 78, 230, 659, 1718, 3706, 6461, 9551, 12155, 13121, 13548, 13473, 12121, 8033, 2153]", + "total_badness": 134274.87401 } ], "matrix.geo": [ @@ -1793,24 +1701,24 @@ ], "ne1d": 174, "ne2d": 1070, - "ne3d": 4599, - "quality_histogram": "[0, 0, 10, 93, 172, 67, 25, 59, 126, 165, 272, 371, 440, 515, 548, 537, 528, 411, 204, 56]", - "total_badness": 7959.8830096 + "ne3d": 4238, + "quality_histogram": "[0, 0, 10, 93, 172, 69, 17, 64, 120, 159, 270, 354, 421, 464, 502, 490, 450, 338, 202, 43]", + "total_badness": 7468.5968987 }, { "angles_tet": [ - 6.4945, - 166.83 + 5.0793, + 171.79 ], "angles_trig": [ - 8.2716, - 155.6 + 8.2262, + 162.29 ], "ne1d": 106, "ne2d": 314, - "ne3d": 872, - "quality_histogram": "[0, 0, 4, 34, 45, 54, 80, 72, 92, 87, 91, 73, 67, 53, 44, 32, 21, 20, 3, 0]", - "total_badness": 2091.3790714 + "ne3d": 843, + "quality_histogram": "[0, 1, 7, 36, 52, 60, 74, 75, 96, 90, 86, 69, 55, 39, 34, 27, 22, 18, 2, 0]", + "total_badness": 2121.4782246 }, { "angles_tet": [ @@ -1818,14 +1726,14 @@ 170.81 ], "angles_trig": [ - 10.133, - 155.67 + 9.9701, + 158.6 ], "ne1d": 132, "ne2d": 588, - "ne3d": 1799, - "quality_histogram": "[0, 0, 2, 17, 33, 76, 152, 120, 84, 98, 127, 150, 170, 203, 187, 133, 118, 64, 55, 10]", - "total_badness": 3522.631959 + "ne3d": 1725, + "quality_histogram": "[0, 0, 3, 20, 32, 73, 142, 129, 87, 119, 123, 154, 148, 190, 160, 126, 96, 72, 43, 8]", + "total_badness": 3442.5980879 }, { "angles_tet": [ @@ -1838,39 +1746,39 @@ ], "ne1d": 174, "ne2d": 1070, - "ne3d": 4497, - "quality_histogram": "[0, 0, 10, 93, 172, 65, 16, 60, 101, 137, 258, 314, 387, 500, 529, 561, 555, 411, 252, 76]", - "total_badness": 7683.1109366 + "ne3d": 4026, + "quality_histogram": "[0, 0, 10, 93, 172, 65, 16, 58, 113, 142, 247, 319, 399, 438, 476, 449, 435, 315, 219, 60]", + "total_badness": 7109.2735591 }, { "angles_tet": [ - 13.101, - 145.56 + 13.107, + 146.96 ], "angles_trig": [ - 15.887, + 15.013, 143.02 ], "ne1d": 248, "ne2d": 2256, - "ne3d": 16133, - "quality_histogram": "[0, 0, 0, 0, 0, 7, 22, 55, 90, 186, 318, 576, 969, 1526, 2057, 2534, 2791, 2579, 1841, 582]", - "total_badness": 21280.729551 + "ne3d": 13057, + "quality_histogram": "[0, 0, 0, 0, 0, 7, 21, 59, 107, 184, 339, 556, 907, 1254, 1664, 1962, 2127, 2012, 1415, 443]", + "total_badness": 17482.312294 }, { "angles_tet": [ - 18.113, - 145.19 + 18.203, + 144.77 ], "angles_trig": [ 17.821, - 130.51 + 128.91 ], "ne1d": 418, "ne2d": 5914, - "ne3d": 101287, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 6, 8, 42, 111, 349, 979, 2418, 5321, 10105, 15903, 20923, 22509, 17204, 5408]", - "total_badness": 124144.15591 + "ne3d": 76880, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 5, 9, 44, 92, 254, 708, 1634, 3644, 6877, 10969, 15598, 17976, 14366, 4704]", + "total_badness": 93472.477243 } ], "ortho.geo": [ @@ -1936,117 +1844,117 @@ }, { "angles_tet": [ - 27.31, + 27.314, 136.31 ], "angles_trig": [ - 32.958, - 102.54 + 32.951, + 102.55 ], "ne1d": 48, "ne2d": 36, "ne3d": 57, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 2, 9, 11, 10, 12, 4, 1, 2, 0]", - "total_badness": 83.838340747 + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 2, 9, 11, 10, 12, 4, 1, 2, 0]", + "total_badness": 83.838443301 }, { "angles_tet": [ 27.731, - 134.89 + 129.3 ], "angles_trig": [ 28.064, - 104.8 + 103.04 ], "ne1d": 72, "ne2d": 104, - "ne3d": 157, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 7, 9, 22, 17, 29, 25, 28, 10, 6]", - "total_badness": 206.30371107 + "ne3d": 150, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 7, 6, 23, 14, 31, 21, 29, 13, 5]", + "total_badness": 194.78642472 } ], "part1.stl": [ { "angles_tet": [ - 22.083, - 138.04 + 25.638, + 135.18 ], "angles_trig": [ - 24.223, - 119.8 + 21.656, + 124.67 ], "ne1d": 170, "ne2d": 400, - "ne3d": 1023, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 16, 55, 75, 124, 152, 176, 176, 136, 86, 20]", - "total_badness": 1363.6686182 + "ne3d": 928, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 5, 31, 48, 72, 93, 157, 155, 145, 124, 83, 13]", + "total_badness": 1245.5581222 }, { "angles_tet": [ - 10.722, + 11.063, 160.47 ], "angles_trig": [ - 13.01, + 16.003, 146.61 ], "ne1d": 134, "ne2d": 254, - "ne3d": 457, - "quality_histogram": "[0, 0, 0, 4, 1, 3, 9, 7, 11, 19, 29, 44, 53, 56, 60, 63, 43, 31, 20, 4]", - "total_badness": 726.0384133 + "ne3d": 413, + "quality_histogram": "[0, 0, 0, 3, 3, 5, 11, 7, 15, 24, 31, 33, 54, 43, 65, 44, 36, 19, 17, 3]", + "total_badness": 687.15227784 }, { "angles_tet": [ 20.846, - 134.73 + 149.16 ], "angles_trig": [ - 22.401, - 115.69 + 23.195, + 113.89 ], "ne1d": 194, "ne2d": 554, - "ne3d": 1600, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 17, 63, 93, 166, 229, 275, 308, 246, 159, 37]", - "total_badness": 2088.862264 + "ne3d": 1389, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 4, 2, 17, 54, 101, 149, 220, 252, 241, 203, 120, 25]", + "total_badness": 1832.7921849 }, { "angles_tet": [ 21.368, - 141.27 + 141.1 ], "angles_trig": [ - 26.65, - 112.07 + 23.927, + 117.02 ], "ne1d": 266, "ne2d": 958, - "ne3d": 4158, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 5, 9, 19, 53, 126, 298, 501, 705, 822, 870, 591, 159]", - "total_badness": 5194.9903517 + "ne3d": 3403, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 5, 9, 18, 52, 114, 269, 399, 601, 676, 646, 459, 155]", + "total_badness": 4278.0682013 }, { "angles_tet": [ - 24.374, - 139.79 + 26.383, + 142.98 ], "angles_trig": [ - 25.767, - 121.5 + 24.47, + 122.53 ], "ne1d": 674, "ne2d": 6330, - "ne3d": 73017, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 3, 15, 118, 382, 1197, 3223, 6772, 11399, 15438, 17121, 13196, 4153]", - "total_badness": 88445.46456 + "ne3d": 55920, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 14, 65, 218, 755, 1964, 4266, 7694, 11351, 13972, 11855, 3765]", + "total_badness": 66850.851051 } ], "period.geo": [ { "angles_tet": [ - 14.172, - 145.15 + 15.419, + 145.84 ], "angles_trig": [ 17.555, @@ -2054,44 +1962,44 @@ ], "ne1d": 344, "ne2d": 1040, - "ne3d": 3043, - "quality_histogram": "[0, 0, 0, 0, 0, 6, 18, 25, 51, 71, 144, 251, 302, 421, 423, 407, 390, 306, 179, 49]", - "total_badness": 4402.5390324 + "ne3d": 2859, + "quality_histogram": "[0, 0, 0, 0, 0, 5, 20, 25, 47, 80, 148, 264, 299, 418, 368, 359, 360, 281, 151, 34]", + "total_badness": 4186.5926357 }, { "angles_tet": [ - 7.025, - 170.6 + 8.8923, + 165.12 ], "angles_trig": [ - 11.507, + 10.412, 140.67 ], "ne1d": 160, "ne2d": 234, - "ne3d": 417, - "quality_histogram": "[0, 0, 2, 4, 4, 12, 17, 17, 26, 32, 44, 44, 48, 39, 27, 37, 33, 20, 8, 3]", - "total_badness": 780.76742775 + "ne3d": 372, + "quality_histogram": "[0, 0, 0, 7, 6, 15, 27, 17, 25, 30, 34, 36, 43, 38, 18, 24, 27, 17, 7, 1]", + "total_badness": 738.96263535 }, { "angles_tet": [ - 9.6632, - 163.12 + 10.154, + 164.25 ], "angles_trig": [ - 13.809, - 147.97 + 15.73, + 145.3 ], "ne1d": 232, "ne2d": 494, - "ne3d": 1159, - "quality_histogram": "[0, 0, 1, 5, 14, 20, 42, 39, 60, 72, 87, 117, 127, 158, 104, 117, 72, 73, 42, 9]", - "total_badness": 2023.1948662 + "ne3d": 1001, + "quality_histogram": "[0, 0, 0, 2, 16, 39, 50, 69, 58, 62, 85, 92, 106, 102, 99, 91, 59, 49, 18, 4]", + "total_badness": 1873.6285579 }, { "angles_tet": [ - 14.172, - 145.15 + 16.492, + 144.95 ], "angles_trig": [ 17.555, @@ -2099,29 +2007,29 @@ ], "ne1d": 344, "ne2d": 1040, - "ne3d": 3001, - "quality_histogram": "[0, 0, 0, 0, 0, 6, 17, 24, 42, 58, 124, 222, 276, 398, 439, 428, 393, 327, 202, 45]", - "total_badness": 4283.328223 + "ne3d": 2771, + "quality_histogram": "[0, 0, 0, 0, 0, 5, 18, 24, 45, 65, 145, 235, 301, 377, 387, 348, 358, 291, 137, 35]", + "total_badness": 4034.1944956 }, { "angles_tet": [ - 20.132, - 145.06 + 20.66, + 144.93 ], "angles_trig": [ - 23.036, + 21.848, 125.82 ], "ne1d": 480, "ne2d": 2200, - "ne3d": 11579, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 5, 6, 37, 79, 241, 508, 972, 1450, 2025, 2203, 2142, 1482, 429]", - "total_badness": 14696.222297 + "ne3d": 9786, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 3, 7, 34, 96, 223, 474, 870, 1287, 1671, 1844, 1743, 1220, 314]", + "total_badness": 12506.441418 }, { "angles_tet": [ - 20.751, - 144.48 + 21.073, + 143.43 ], "angles_trig": [ 20.259, @@ -2129,71 +2037,71 @@ ], "ne1d": 820, "ne2d": 6174, - "ne3d": 68319, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 4, 13, 57, 176, 519, 1477, 3598, 7004, 10873, 14367, 15055, 11494, 3682]", - "total_badness": 83579.590629 + "ne3d": 53126, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 10, 50, 164, 402, 1067, 2405, 4682, 7754, 10857, 12296, 10143, 3294]", + "total_badness": 64419.90251 } ], "plane.stl": [ { "angles_tet": [ - 1.2146, - 170.22 + 1.2182, + 165.85 ], "angles_trig": [ - 1.8906, - 147.74 + 1.8555, + 160.04 ], "ne1d": 892, - "ne2d": 2226, - "ne3d": 7016, - "quality_histogram": "[3, 12, 31, 39, 43, 61, 53, 62, 97, 110, 236, 389, 555, 829, 983, 1053, 1003, 852, 486, 119]", - "total_badness": 10717.291909 + "ne2d": 2220, + "ne3d": 6361, + "quality_histogram": "[4, 14, 29, 34, 42, 56, 52, 60, 94, 131, 241, 341, 537, 709, 899, 953, 944, 728, 387, 106]", + "total_badness": 9865.9905616 }, { "angles_tet": [ - 1.6463, - 171.19 + 0.11753, + 179.78 ], "angles_trig": [ - 1.7241, - 168.81 + 2.5035, + 155.48 ], "ne1d": 572, - "ne2d": 748, - "ne3d": 932, - "quality_histogram": "[2, 29, 56, 54, 80, 83, 65, 78, 62, 79, 75, 65, 56, 52, 34, 28, 18, 10, 4, 2]", - "total_badness": 3148.0282985 + "ne2d": 742, + "ne3d": 931, + "quality_histogram": "[6, 25, 55, 67, 80, 92, 69, 76, 70, 67, 59, 55, 63, 53, 38, 24, 16, 11, 5, 0]", + "total_badness": 3693.358071 }, { "angles_tet": [ 1.1094, - 171.74 + 172.08 ], "angles_trig": [ - 3.1957, - 172.05 + 3.4703, + 155.55 ], "ne1d": 724, "ne2d": 1340, - "ne3d": 2375, - "quality_histogram": "[2, 17, 32, 56, 42, 52, 55, 65, 90, 131, 177, 192, 236, 274, 291, 265, 213, 124, 54, 7]", - "total_badness": 4744.9473584 + "ne3d": 2183, + "quality_histogram": "[3, 13, 33, 52, 47, 59, 55, 66, 82, 121, 178, 184, 232, 255, 254, 206, 182, 107, 48, 6]", + "total_badness": 4468.3231535 }, { "angles_tet": [ 1.2337, - 165.93 + 165.94 ], "angles_trig": [ - 1.932, - 150.35 + 3.4703, + 149.13 ], "ne1d": 956, - "ne2d": 2328, - "ne3d": 7371, - "quality_histogram": "[3, 8, 27, 48, 50, 50, 51, 60, 73, 92, 154, 275, 478, 757, 1051, 1198, 1207, 995, 647, 147]", - "total_badness": 10885.708005 + "ne2d": 2330, + "ne3d": 6152, + "quality_histogram": "[3, 9, 26, 42, 39, 53, 62, 67, 77, 120, 158, 230, 393, 629, 835, 972, 1018, 839, 453, 127]", + "total_badness": 9316.7379917 }, { "angles_tet": [ @@ -2202,127 +2110,127 @@ ], "angles_trig": [ 4.1049, - 148.28 + 144.93 ], "ne1d": 1554, "ne2d": 5646, - "ne3d": 29373, - "quality_histogram": "[2, 6, 10, 11, 20, 49, 62, 47, 81, 131, 233, 473, 1030, 2096, 3516, 4912, 6007, 5650, 3941, 1096]", - "total_badness": 37671.804771 + "ne3d": 23451, + "quality_histogram": "[2, 5, 10, 10, 20, 55, 63, 51, 78, 135, 197, 409, 833, 1584, 2686, 3853, 4682, 4599, 3278, 901]", + "total_badness": 30195.253166 }, { "angles_tet": [ - 1.2313, - 163.56 + 1.2319, + 163.57 ], "angles_trig": [ - 1.2728, - 155.0 + 1.2732, + 154.91 ], "ne1d": 2992, "ne2d": 22730, - "ne3d": 271701, - "quality_histogram": "[4, 8, 13, 10, 12, 24, 23, 53, 88, 211, 645, 1879, 5291, 12837, 26732, 43337, 57290, 61716, 46823, 14705]", - "total_badness": 331770.62487 + "ne3d": 206391, + "quality_histogram": "[4, 6, 13, 10, 14, 19, 26, 63, 87, 166, 484, 1162, 3348, 7835, 16694, 29391, 42810, 50220, 40636, 13403]", + "total_badness": 249038.12593 } ], "revolution.geo": [ { "angles_tet": [ - 18.192, - 146.62 + 15.496, + 150.31 ], "angles_trig": [ - 16.784, - 125.93 + 17.613, + 132.44 ], "ne1d": 320, "ne2d": 2790, - "ne3d": 7801, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 19, 85, 222, 383, 609, 790, 928, 1072, 1122, 1033, 869, 535, 133]", - "total_badness": 11028.386222 + "ne3d": 7109, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 5, 44, 120, 242, 448, 598, 736, 862, 895, 957, 916, 720, 473, 93]", + "total_badness": 10273.473799 }, { "angles_tet": [ - 15.884, - 148.19 + 17.504, + 138.44 ], "angles_trig": [ - 16.462, - 128.75 + 16.273, + 128.52 ], "ne1d": 160, "ne2d": 658, - "ne3d": 1014, - "quality_histogram": "[0, 0, 0, 0, 0, 1, 10, 39, 45, 86, 105, 135, 148, 143, 94, 77, 55, 39, 27, 10]", - "total_badness": 1687.852505 + "ne3d": 969, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 11, 38, 67, 99, 115, 151, 138, 110, 85, 50, 39, 36, 24, 6]", + "total_badness": 1667.032894 }, { "angles_tet": [ - 19.465, - 143.15 + 17.637, + 150.4 ], "angles_trig": [ - 21.41, - 127.26 + 17.573, + 134.96 ], "ne1d": 240, "ne2d": 1584, - "ne3d": 3587, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 6, 53, 114, 213, 346, 472, 525, 493, 421, 409, 290, 188, 56]", - "total_badness": 5235.8043244 + "ne3d": 3395, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 12, 54, 120, 224, 382, 446, 488, 441, 388, 346, 275, 178, 39]", + "total_badness": 5015.8391018 }, { "angles_tet": [ - 16.533, - 145.17 + 17.675, + 149.89 ], "angles_trig": [ - 16.65, - 126.12 + 17.528, + 134.16 ], "ne1d": 320, "ne2d": 2790, - "ne3d": 7588, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 3, 53, 130, 283, 474, 732, 845, 1029, 1136, 1138, 955, 650, 157]", - "total_badness": 10417.772443 + "ne3d": 6651, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 28, 97, 207, 395, 531, 662, 765, 862, 919, 864, 740, 472, 108]", + "total_badness": 9492.8483553 }, { "angles_tet": [ - 19.966, - 146.33 + 22.077, + 144.94 ], "angles_trig": [ - 22.508, - 127.48 + 19.919, + 132.01 ], "ne1d": 480, "ne2d": 6314, - "ne3d": 31852, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 4, 10, 39, 160, 534, 1078, 2215, 3774, 5529, 6417, 6291, 4543, 1258]", - "total_badness": 39852.048962 + "ne3d": 24987, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 18, 75, 233, 687, 1234, 1928, 2962, 3929, 4665, 4833, 3480, 941]", + "total_badness": 31722.463309 }, { "angles_tet": [ - 24.204, - 141.06 + 23.899, + 141.25 ], "angles_trig": [ - 25.313, - 123.86 + 25.135, + 121.44 ], "ne1d": 800, "ne2d": 16950, - "ne3d": 198677, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 5, 71, 314, 1001, 3314, 8614, 18130, 30449, 42143, 46676, 36551, 11409]", - "total_badness": 240440.79682 + "ne3d": 150394, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 5, 35, 221, 760, 2295, 5639, 11946, 20906, 30456, 36938, 30789, 10404]", + "total_badness": 180339.45752 } ], "sculpture.geo": [ { "angles_tet": [ - 17.893, - 145.39 + 16.244, + 149.74 ], "angles_trig": [ 26.076, @@ -2330,9 +2238,9 @@ ], "ne1d": 192, "ne2d": 358, - "ne3d": 399, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 2, 5, 7, 20, 31, 46, 60, 68, 73, 56, 20, 8, 2]", - "total_badness": 577.70426627 + "ne3d": 394, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 2, 4, 7, 21, 29, 45, 59, 67, 72, 56, 19, 8, 2]", + "total_badness": 573.04023539 }, { "angles_tet": [ @@ -2366,8 +2274,8 @@ }, { "angles_tet": [ - 17.893, - 145.39 + 16.244, + 149.74 ], "angles_trig": [ 26.076, @@ -2375,9 +2283,9 @@ ], "ne1d": 192, "ne2d": 358, - "ne3d": 399, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 2, 5, 7, 20, 31, 46, 60, 68, 73, 56, 20, 8, 2]", - "total_badness": 577.70426673 + "ne3d": 394, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 3, 2, 4, 7, 21, 29, 45, 59, 67, 72, 56, 19, 8, 2]", + "total_badness": 573.04023539 }, { "angles_tet": [ @@ -2390,41 +2298,41 @@ ], "ne1d": 288, "ne2d": 912, - "ne3d": 1234, - "quality_histogram": "[0, 0, 0, 0, 2, 2, 10, 23, 35, 68, 98, 124, 108, 127, 127, 127, 154, 133, 80, 16]", - "total_badness": 1875.8247719 + "ne3d": 1226, + "quality_histogram": "[0, 0, 0, 0, 2, 2, 8, 22, 36, 70, 100, 124, 113, 128, 123, 129, 149, 132, 72, 16]", + "total_badness": 1867.9891765 }, { "angles_tet": [ 16.0, - 149.5 + 149.43 ], "angles_trig": [ 17.232, - 118.94 + 119.57 ], "ne1d": 480, "ne2d": 2314, - "ne3d": 6590, - "quality_histogram": "[0, 0, 0, 0, 2, 3, 11, 9, 20, 24, 53, 89, 214, 406, 753, 1055, 1353, 1311, 962, 325]", - "total_badness": 8284.1518654 + "ne3d": 5481, + "quality_histogram": "[0, 0, 0, 0, 2, 4, 10, 12, 11, 27, 49, 109, 187, 336, 632, 879, 1085, 1055, 797, 286]", + "total_badness": 6926.9394256 } ], "shaft.geo": [ { "angles_tet": [ - 8.1571, - 162.65 + 6.0597, + 169.09 ], "angles_trig": [ - 9.7076, - 147.95 + 12.711, + 152.57 ], "ne1d": 708, "ne2d": 1656, - "ne3d": 2629, - "quality_histogram": "[0, 0, 2, 4, 12, 13, 24, 56, 76, 149, 278, 365, 333, 240, 233, 285, 255, 188, 94, 22]", - "total_badness": 4239.9806978 + "ne3d": 2463, + "quality_histogram": "[0, 1, 0, 8, 43, 22, 13, 44, 71, 140, 219, 346, 309, 226, 211, 274, 251, 171, 93, 21]", + "total_badness": 4066.8218532 }, { "angles_tet": [ @@ -2433,73 +2341,73 @@ ], "angles_trig": [ 10.094, - 128.25 + 123.18 ], "ne1d": 410, "ne2d": 542, - "ne3d": 688, - "quality_histogram": "[0, 0, 0, 2, 1, 4, 6, 11, 18, 32, 41, 56, 73, 85, 81, 83, 66, 73, 43, 13]", - "total_badness": 1047.4282101 + "ne3d": 615, + "quality_histogram": "[0, 0, 0, 3, 1, 4, 8, 16, 37, 54, 65, 67, 67, 71, 59, 58, 50, 43, 9, 3]", + "total_badness": 1035.1361164 }, { "angles_tet": [ - 9.2737, - 159.17 + 1.088, + 177.95 ], "angles_trig": [ - 13.813, - 149.46 + 9.6019, + 144.68 ], "ne1d": 510, "ne2d": 912, - "ne3d": 1645, - "quality_histogram": "[0, 0, 0, 3, 5, 17, 16, 48, 65, 87, 108, 139, 179, 177, 238, 195, 186, 104, 53, 25]", - "total_badness": 2610.9306806 + "ne3d": 1258, + "quality_histogram": "[3, 0, 0, 0, 16, 51, 82, 87, 46, 39, 68, 93, 108, 122, 155, 141, 136, 64, 36, 11]", + "total_badness": 2595.8155702 }, { "angles_tet": [ - 13.139, - 162.65 + 9.1633, + 166.59 ], "angles_trig": [ - 15.194, - 147.25 + 13.405, + 152.57 ], "ne1d": 708, "ne2d": 1656, - "ne3d": 2585, - "quality_histogram": "[0, 0, 0, 1, 4, 4, 10, 22, 43, 120, 259, 375, 332, 266, 243, 291, 287, 189, 115, 24]", - "total_badness": 3972.0391087 + "ne3d": 2373, + "quality_histogram": "[0, 0, 0, 5, 27, 11, 8, 21, 73, 176, 231, 322, 270, 221, 213, 267, 244, 177, 88, 19]", + "total_badness": 3823.4326841 }, { "angles_tet": [ 15.284, - 147.53 + 148.46 ], "angles_trig": [ - 20.193, - 122.49 + 20.071, + 124.88 ], "ne1d": 1138, "ne2d": 4104, - "ne3d": 10879, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 2, 22, 68, 162, 312, 550, 917, 1327, 1807, 2027, 1905, 1346, 433]", - "total_badness": 13982.205496 + "ne3d": 9546, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 2, 28, 76, 174, 335, 494, 811, 1246, 1522, 1737, 1579, 1215, 325]", + "total_badness": 12378.481139 }, { "angles_tet": [ - 23.051, - 146.15 + 25.194, + 141.19 ], "angles_trig": [ - 26.463, - 118.44 + 26.218, + 120.33 ], "ne1d": 1792, "ne2d": 10502, - "ne3d": 63623, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 3, 36, 112, 441, 1261, 3055, 6105, 9988, 13378, 14460, 11103, 3679]", - "total_badness": 77412.92414 + "ne3d": 49939, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 4, 32, 102, 299, 875, 2257, 4260, 7493, 10376, 11747, 9497, 2997]", + "total_badness": 60403.701968 } ], "sphere.geo": [ @@ -2565,33 +2473,33 @@ }, { "angles_tet": [ - 22.983, - 128.09 + 21.731, + 133.96 ], "angles_trig": [ - 22.196, - 111.76 + 22.177, + 111.5 ], "ne1d": 0, "ne2d": 256, "ne3d": 363, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 19, 33, 58, 54, 54, 32, 38, 31, 24, 12, 6]", - "total_badness": 551.13017475 + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 3, 16, 42, 53, 45, 56, 40, 34, 30, 27, 11, 6]", + "total_badness": 551.54194668 }, { "angles_tet": [ - 30.456, - 130.64 + 26.252, + 135.65 ], "angles_trig": [ - 29.846, - 110.98 + 25.494, + 116.09 ], "ne1d": 0, "ne2d": 658, - "ne3d": 2272, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 24, 67, 135, 263, 417, 457, 440, 354, 113]", - "total_badness": 2808.9045443 + "ne3d": 1871, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 6, 23, 65, 131, 218, 295, 389, 366, 286, 90]", + "total_badness": 2324.6823999 } ], "sphereincube.geo": [ @@ -2623,12 +2531,12 @@ "ne2d": 34, "ne3d": 79, "quality_histogram": "[0, 0, 2, 2, 10, 6, 15, 12, 9, 9, 5, 5, 1, 1, 0, 0, 2, 0, 0, 0]", - "total_badness": 239.01564453 + "total_badness": 239.01564452 }, { "angles_tet": [ - 6.4483, - 169.86 + 5.8125, + 172.01 ], "angles_trig": [ 9.6618, @@ -2636,9 +2544,9 @@ ], "ne1d": 30, "ne2d": 100, - "ne3d": 242, - "quality_histogram": "[0, 0, 6, 15, 20, 43, 45, 12, 21, 10, 21, 8, 12, 4, 4, 6, 4, 7, 3, 1]", - "total_badness": 732.39744465 + "ne3d": 236, + "quality_histogram": "[0, 1, 6, 15, 19, 40, 50, 12, 19, 9, 16, 8, 12, 4, 4, 6, 4, 7, 3, 1]", + "total_badness": 725.69720862 }, { "angles_tet": [ @@ -2658,32 +2566,32 @@ { "angles_tet": [ 14.198, - 139.87 + 139.21 ], "angles_trig": [ - 16.51, - 128.49 + 16.856, + 130.65 ], "ne1d": 74, "ne2d": 412, - "ne3d": 1683, - "quality_histogram": "[0, 0, 0, 0, 0, 5, 3, 12, 21, 29, 71, 92, 153, 214, 236, 260, 224, 186, 131, 46]", - "total_badness": 2358.043084 + "ne3d": 1469, + "quality_histogram": "[0, 0, 0, 0, 0, 4, 4, 14, 19, 35, 47, 97, 138, 175, 212, 219, 185, 176, 116, 28]", + "total_badness": 2074.3086016 }, { "angles_tet": [ - 24.367, - 140.35 + 27.095, + 137.84 ], "angles_trig": [ - 22.231, - 124.31 + 24.237, + 119.8 ], "ne1d": 122, "ne2d": 1066, - "ne3d": 13989, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 7, 23, 83, 256, 466, 907, 1562, 2200, 2835, 2874, 2099, 676]", - "total_badness": 17429.478381 + "ne3d": 10660, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 43, 130, 314, 601, 1086, 1736, 2144, 2330, 1732, 538]", + "total_badness": 13133.278179 } ], "square.in2d": [ @@ -2965,93 +2873,93 @@ "torus.geo": [ { "angles_tet": [ - 19.194, - 148.12 + 16.222, + 149.63 ], "angles_trig": [ - 19.92, - 127.08 + 16.3, + 128.3 ], "ne1d": 0, "ne2d": 2526, - "ne3d": 5587, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 9, 75, 208, 373, 547, 678, 782, 752, 738, 585, 470, 285, 83]", - "total_badness": 8168.6605532 + "ne3d": 5259, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 8, 21, 96, 235, 434, 542, 643, 705, 671, 631, 542, 406, 252, 73]", + "total_badness": 7849.7741851 }, { "angles_tet": [ - 2.7079, - 172.97 + 2.2624, + 174.01 ], "angles_trig": [ - 4.6723, - 166.19 + 9.0702, + 156.78 ], "ne1d": 0, "ne2d": 648, - "ne3d": 3007, - "quality_histogram": "[8, 144, 319, 360, 402, 367, 276, 245, 184, 169, 139, 98, 83, 58, 46, 41, 31, 22, 10, 5]", - "total_badness": 12976.808797 + "ne3d": 1316, + "quality_histogram": "[4, 69, 112, 154, 262, 273, 143, 70, 53, 27, 33, 27, 23, 20, 14, 11, 7, 6, 3, 5]", + "total_badness": 5967.2368224 }, { "angles_tet": [ - 17.153, - 145.79 + 19.703, + 139.32 ], "angles_trig": [ - 21.25, - 118.2 + 20.821, + 122.02 ], "ne1d": 0, "ne2d": 1430, - "ne3d": 2733, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 4, 11, 39, 130, 214, 321, 436, 454, 400, 279, 240, 155, 49]", - "total_badness": 3874.9869154 + "ne3d": 2519, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 4, 16, 62, 155, 260, 318, 383, 374, 317, 258, 186, 137, 49]", + "total_badness": 3649.6105593 }, { "angles_tet": [ - 21.147, - 145.15 + 16.948, + 148.0 ], "angles_trig": [ - 20.446, - 123.07 + 17.058, + 126.19 ], "ne1d": 0, "ne2d": 2526, - "ne3d": 5473, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 2, 34, 119, 265, 466, 597, 763, 810, 767, 682, 534, 342, 92]", - "total_badness": 7745.4881518 + "ne3d": 4966, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 4, 12, 46, 172, 335, 478, 615, 629, 669, 610, 546, 485, 296, 69]", + "total_badness": 7211.0429386 }, { "angles_tet": [ - 21.754, - 144.45 + 24.543, + 140.91 ], "angles_trig": [ - 23.239, - 124.02 + 24.07, + 122.58 ], "ne1d": 0, "ne2d": 5824, - "ne3d": 25317, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 9, 41, 114, 347, 765, 1598, 2782, 4135, 5379, 5234, 3786, 1126]", - "total_badness": 31434.764854 + "ne3d": 20486, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 2, 42, 154, 470, 959, 1582, 2370, 3177, 3804, 3967, 3038, 921]", + "total_badness": 25818.784377 }, { "angles_tet": [ - 21.699, - 145.02 + 23.266, + 139.23 ], "angles_trig": [ - 23.154, - 120.78 + 25.162, + 124.18 ], "ne1d": 0, "ne2d": 16198, - "ne3d": 174686, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 4, 58, 234, 858, 2518, 6918, 15184, 26272, 37074, 41964, 33110, 10491]", - "total_badness": 210586.77039 + "ne3d": 132598, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 4, 35, 203, 607, 1786, 4546, 9911, 18029, 26777, 32913, 28265, 9522]", + "total_badness": 158396.27588 } ], "trafo.geo": [ @@ -3062,18 +2970,18 @@ ], "angles_trig": [ 14.916, - 132.02 + 130.79 ], "ne1d": 690, "ne2d": 1662, - "ne3d": 5132, - "quality_histogram": "[0, 0, 1, 0, 2, 12, 24, 42, 108, 200, 269, 367, 431, 571, 685, 733, 586, 527, 446, 128]", - "total_badness": 7423.4819931 + "ne3d": 4993, + "quality_histogram": "[0, 0, 1, 0, 1, 12, 24, 42, 104, 208, 261, 358, 446, 538, 653, 688, 584, 516, 431, 126]", + "total_badness": 7234.6713061 }, { "angles_tet": [ 2.8238, - 174.1 + 175.21 ], "angles_trig": [ 7.7605, @@ -3081,9 +2989,9 @@ ], "ne1d": 390, "ne2d": 516, - "ne3d": 1342, - "quality_histogram": "[0, 1, 5, 13, 16, 44, 80, 117, 122, 153, 159, 135, 123, 113, 85, 80, 54, 28, 11, 3]", - "total_badness": 2768.1650274 + "ne3d": 1332, + "quality_histogram": "[0, 2, 5, 14, 16, 42, 76, 118, 126, 153, 159, 133, 121, 106, 87, 80, 53, 27, 11, 3]", + "total_badness": 2769.107096 }, { "angles_tet": [ @@ -3096,9 +3004,9 @@ ], "ne1d": 512, "ne2d": 864, - "ne3d": 2363, - "quality_histogram": "[0, 0, 0, 3, 9, 11, 42, 63, 119, 151, 184, 204, 316, 393, 341, 237, 138, 87, 42, 23]", - "total_badness": 3893.8304292 + "ne3d": 2356, + "quality_histogram": "[0, 0, 0, 3, 9, 13, 43, 64, 120, 144, 192, 205, 312, 383, 344, 235, 134, 88, 43, 24]", + "total_badness": 3889.9503966 }, { "angles_tet": [ @@ -3107,13 +3015,13 @@ ], "angles_trig": [ 14.916, - 132.02 + 130.79 ], "ne1d": 690, "ne2d": 1662, - "ne3d": 5067, - "quality_histogram": "[0, 0, 1, 0, 1, 8, 17, 35, 109, 188, 260, 357, 413, 536, 678, 734, 604, 538, 451, 137]", - "total_badness": 7266.2053478 + "ne3d": 4895, + "quality_histogram": "[0, 0, 1, 0, 1, 7, 20, 38, 102, 204, 242, 344, 426, 519, 643, 703, 569, 514, 435, 127]", + "total_badness": 7049.258721 }, { "angles_tet": [ @@ -3126,41 +3034,41 @@ ], "ne1d": 1050, "ne2d": 3670, - "ne3d": 17479, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 13, 27, 55, 173, 512, 1412, 2098, 2269, 2479, 2612, 2725, 2398, 704]", - "total_badness": 22725.68654 + "ne3d": 15310, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 2, 13, 27, 60, 163, 450, 1302, 1909, 2002, 2169, 2215, 2318, 2083, 597]", + "total_badness": 19985.425031 }, { "angles_tet": [ - 13.821, - 149.28 + 14.338, + 149.48 ], "angles_trig": [ - 19.234, + 19.874, 128.69 ], "ne1d": 1722, "ne2d": 9990, - "ne3d": 84843, - "quality_histogram": "[0, 0, 0, 0, 1, 3, 47, 1412, 705, 384, 688, 1183, 2414, 5544, 8737, 13008, 16461, 17017, 12962, 4277]", - "total_badness": 108418.01981 + "ne3d": 69009, + "quality_histogram": "[0, 0, 0, 0, 0, 2, 49, 1398, 718, 359, 607, 997, 1786, 4101, 6360, 9955, 13187, 14433, 11280, 3777]", + "total_badness": 88274.805093 } ], "twobricks.geo": [ { "angles_tet": [ - 26.301, - 137.72 + 29.453, + 134.56 ], "angles_trig": [ - 24.205, - 111.42 + 26.574, + 91.538 ], "ne1d": 72, "ne2d": 50, - "ne3d": 46, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 5, 4, 14, 7, 6, 3, 1, 0, 0]", - "total_badness": 70.226764001 + "ne3d": 36, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 2, 18, 2, 4, 0, 0, 0, 0]", + "total_badness": 55.618194358 }, { "angles_tet": [ @@ -3194,37 +3102,37 @@ }, { "angles_tet": [ - 26.301, - 137.72 + 29.453, + 134.56 ], "angles_trig": [ - 24.205, - 111.42 + 26.574, + 91.538 ], "ne1d": 72, "ne2d": 50, - "ne3d": 46, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 5, 4, 14, 7, 6, 3, 1, 0, 0]", - "total_badness": 70.226762635 + "ne3d": 36, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 2, 18, 2, 4, 0, 0, 0, 0]", + "total_badness": 55.618194358 }, { "angles_tet": [ - 23.292, - 131.34 + 24.096, + 132.78 ], "angles_trig": [ 27.682, - 108.04 + 109.77 ], "ne1d": 116, "ne2d": 132, - "ne3d": 174, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 10, 12, 17, 36, 23, 30, 18, 15, 8]", - "total_badness": 232.20307583 + "ne3d": 167, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 13, 9, 17, 36, 21, 29, 17, 14, 7]", + "total_badness": 223.72156428 }, { "angles_tet": [ - 28.202, + 26.164, 131.83 ], "angles_trig": [ @@ -3233,26 +3141,26 @@ ], "ne1d": 186, "ne2d": 330, - "ne3d": 561, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 22, 35, 52, 81, 98, 100, 102, 55, 12]", - "total_badness": 726.84401009 + "ne3d": 548, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 18, 38, 50, 82, 90, 102, 102, 51, 11]", + "total_badness": 709.67012072 } ], "twocubes.geo": [ { "angles_tet": [ - 26.301, - 137.72 + 29.453, + 134.56 ], "angles_trig": [ - 24.205, - 111.42 + 26.574, + 91.538 ], "ne1d": 72, "ne2d": 50, - "ne3d": 46, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 5, 4, 14, 7, 6, 3, 1, 0, 0]", - "total_badness": 70.226764001 + "ne3d": 36, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 2, 18, 2, 4, 0, 0, 0, 0]", + "total_badness": 55.618194358 }, { "angles_tet": [ @@ -3286,37 +3194,37 @@ }, { "angles_tet": [ - 26.301, - 137.72 + 29.453, + 134.56 ], "angles_trig": [ - 24.205, - 111.42 + 26.574, + 91.538 ], "ne1d": 72, "ne2d": 50, - "ne3d": 46, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 5, 4, 14, 7, 6, 3, 1, 0, 0]", - "total_badness": 70.226762635 + "ne3d": 36, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 8, 2, 18, 2, 4, 0, 0, 0, 0]", + "total_badness": 55.618194358 }, { "angles_tet": [ - 23.292, - 131.34 + 24.096, + 132.78 ], "angles_trig": [ 27.682, - 108.04 + 109.77 ], "ne1d": 116, "ne2d": 132, - "ne3d": 174, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 10, 12, 17, 36, 23, 30, 18, 15, 8]", - "total_badness": 232.20307583 + "ne3d": 167, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 13, 9, 17, 36, 21, 29, 17, 14, 7]", + "total_badness": 223.72156428 }, { "angles_tet": [ - 28.202, + 26.164, 131.83 ], "angles_trig": [ @@ -3325,101 +3233,101 @@ ], "ne1d": 186, "ne2d": 330, - "ne3d": 561, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 22, 35, 52, 81, 98, 100, 102, 55, 12]", - "total_badness": 726.84401009 + "ne3d": 548, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 18, 38, 50, 82, 90, 102, 102, 51, 11]", + "total_badness": 709.67012072 } ], "twocyl.geo": [ { "angles_tet": [ - 17.425, - 151.3 + 18.71, + 143.19 ], "angles_trig": [ - 21.178, - 117.72 + 21.37, + 119.53 ], "ne1d": 144, "ne2d": 408, - "ne3d": 577, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 6, 9, 16, 24, 56, 67, 84, 115, 83, 63, 36, 11, 6]", - "total_badness": 849.57493713 + "ne3d": 568, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 4, 7, 23, 29, 54, 63, 93, 104, 78, 63, 33, 16, 0]", + "total_badness": 840.05938749 }, { "angles_tet": [ - 19.604, - 153.38 + 18.044, + 142.71 ], "angles_trig": [ - 25.599, - 115.69 + 25.435, + 118.39 ], "ne1d": 68, "ne2d": 98, - "ne3d": 138, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 0, 3, 2, 6, 8, 8, 17, 22, 22, 25, 15, 7, 2]", - "total_badness": 193.53502944 + "ne3d": 106, + "quality_histogram": "[0, 0, 0, 0, 0, 1, 0, 4, 6, 5, 5, 13, 5, 15, 7, 9, 15, 18, 3, 0]", + "total_badness": 164.37650945 }, { "angles_tet": [ - 12.305, - 161.08 + 9.1027, + 161.67 ], "angles_trig": [ - 11.495, - 149.57 + 15.302, + 141.93 ], "ne1d": 102, "ne2d": 234, - "ne3d": 412, - "quality_histogram": "[0, 0, 0, 1, 7, 7, 15, 28, 44, 24, 19, 33, 36, 36, 36, 28, 56, 26, 12, 4]", - "total_badness": 744.59871397 + "ne3d": 334, + "quality_histogram": "[0, 1, 4, 9, 7, 28, 26, 36, 48, 26, 13, 7, 13, 21, 14, 19, 37, 14, 8, 3]", + "total_badness": 774.94126931 }, { "angles_tet": [ - 17.51, - 141.43 + 20.964, + 136.15 ], "angles_trig": [ - 21.505, - 117.52 + 21.946, + 111.07 ], "ne1d": 144, "ne2d": 408, - "ne3d": 575, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 4, 7, 10, 20, 57, 65, 76, 116, 90, 74, 40, 14, 2]", - "total_badness": 830.26839459 + "ne3d": 565, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 4, 11, 31, 40, 67, 86, 118, 92, 59, 48, 8, 0]", + "total_badness": 814.48177255 }, { "angles_tet": [ - 20.993, - 137.7 + 19.587, + 141.43 ], "angles_trig": [ - 22.158, - 117.49 + 20.612, + 120.68 ], "ne1d": 214, "ne2d": 904, - "ne3d": 1847, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 8, 28, 77, 127, 199, 270, 350, 335, 247, 164, 41]", - "total_badness": 2434.6179175 + "ne3d": 1687, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 4, 17, 23, 82, 133, 171, 267, 295, 262, 238, 160, 34]", + "total_badness": 2245.8031773 }, { "angles_tet": [ - 21.528, - 142.94 + 24.217, + 137.42 ], "angles_trig": [ - 26.329, - 116.56 + 23.842, + 128.3 ], "ne1d": 350, "ne2d": 2358, - "ne3d": 13357, - "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 23, 78, 239, 564, 1230, 2137, 2846, 3149, 2364, 721]", - "total_badness": 16204.662169 + "ne3d": 10723, + "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 17, 64, 177, 444, 931, 1609, 2183, 2523, 2108, 661]", + "total_badness": 12938.174838 } ] } \ No newline at end of file diff --git a/tests/pytest/test_array.py b/tests/pytest/test_array.py index fc3efd09..98bd13dd 100644 --- a/tests/pytest/test_array.py +++ b/tests/pytest/test_array.py @@ -1,3 +1,4 @@ +import netgen from pyngcore import * from numpy import sort, array diff --git a/tests/pytest/test_bitarray.py b/tests/pytest/test_bitarray.py index ed3d6fd8..4d1d9f98 100644 --- a/tests/pytest/test_bitarray.py +++ b/tests/pytest/test_bitarray.py @@ -1,3 +1,4 @@ +import netgen from pyngcore import BitArray def test_bitarray(): diff --git a/tests/pytest/test_boundarylayer.py b/tests/pytest/test_boundarylayer.py index e0208c14..91ae7159 100644 --- a/tests/pytest/test_boundarylayer.py +++ b/tests/pytest/test_boundarylayer.py @@ -1,6 +1,7 @@ import pytest from netgen.csg import * +from netgen.meshing import BoundaryLayerParameters geometries=[unit_cube] @@ -20,33 +21,39 @@ except ImportError: def GetNSurfaceElements(mesh, boundaries, adjacent_domain=None): nse_in_layer = 0 for el in mesh.Elements2D(): - if mesh.GetBCName(el.index-1) in boundaries: + if len(el.vertices)==3 and mesh.GetBCName(el.index-1) in boundaries: if adjacent_domain is None: + print("add el", el.vertices) nse_in_layer += 1 else: if (mesh.FaceDescriptor(el.index).domin > 0 and mesh.GetMaterial(mesh.FaceDescriptor(el.index).domin) == adjacent_domain) or (mesh.FaceDescriptor(el.index).domout > 0 and mesh.GetMaterial(mesh.FaceDescriptor(el.index).domout) == adjacent_domain): nse_in_layer += 1 return nse_in_layer +def GetNPrisms(mesh): + nprisms = 0 + for el in mesh.Elements3D(): + if len(el.vertices) == 6: + nprisms += 1 + return nprisms + @pytest.mark.parametrize("outside", [True, False]) @pytest.mark.parametrize("geo", geometries) def test_boundarylayer(outside, geo, capfd): - mesh = geo.GenerateMesh(maxh=0.3) - ne_before = mesh.ne layer_surfacenames = ["right", "top", "left", "back", "bottom"] - mesh.BoundaryLayer("|".join(layer_surfacenames), [0.01, 0.01], "layer", outside=outside) - - should_ne = ne_before + 2 * GetNSurfaceElements(mesh, layer_surfacenames) - assert mesh.ne == should_ne + blayer_params = [BoundaryLayerParameters('|'.join(layer_surfacenames), [0.01, 0.01], "layer", outside=outside)] + mesh = geo.GenerateMesh(maxh=0.3, boundary_layers=blayer_params) + should_n_prisms = 2 * GetNSurfaceElements(mesh, layer_surfacenames) + assert GetNPrisms(mesh) == should_n_prisms capture = capfd.readouterr() assert not "elements are not matching" in capture.out - for side in ["front"]: - mesh.BoundaryLayer(side, [0.001, 0.001], "layer", outside=outside) - should_ne += 2 * GetNSurfaceElements(mesh, [side]) - assert mesh.ne == should_ne - capture = capfd.readouterr() - assert not "elements are not matching" in capture.out + blayer_params.append(BoundaryLayerParameters("front", [0.01, 0.01], "layer", outside=True)) # outside=outside not working... + mesh = geo.GenerateMesh(maxh=0.3, boundary_layers=blayer_params) + should_n_prisms += 2 * GetNSurfaceElements(mesh, ["front"]) + assert GetNPrisms(mesh) == should_n_prisms + capture = capfd.readouterr() + assert not "elements are not matching" in capture.out @pytest.mark.parametrize("outside", [True, False]) @pytest.mark.parametrize("version", [1, 2]) # version 2 not working yet @@ -57,7 +64,7 @@ def test_boundarylayer2(outside, version, capfd): bigpart = OrthoBrick(Pnt(-5,-5,0), Pnt(1,1,1)) part = bigpart* top * bot outer = ((OrthoBrick(Pnt(-1,-1,-1), Pnt(2,2,3)).bc("outer") * Plane(Pnt(2,2,2), Vec(0,0,1)).bc("outertop"))) - + geo.Add((part * outer).mat("part")) if version == 1: geo.Add((outer-part).mat("rest")) @@ -67,11 +74,11 @@ def test_boundarylayer2(outside, version, capfd): geo.Add((outer*top*bot-bigpart).mat("rest")) geo.CloseSurfaces(top, bot, []) - mesh = geo.GenerateMesh() - should_ne = mesh.ne + 2 * GetNSurfaceElements(mesh, ["default"], "part") layersize = 0.025 - mesh.BoundaryLayer("default", [layersize, layersize], "part", domains="part", outside=outside) - assert mesh.ne == should_ne + mesh = geo.GenerateMesh(boundary_layers=[BoundaryLayerParameters("default", [layersize, layersize], "part", domain="part", outside=outside)]) + + should_n_prisms = 2 * GetNSurfaceElements(mesh, ["default"], "part") + # assert GetNPrisms(mesh) == should_n_prisms assert not "elements are not matching" in capfd.readouterr().out # import netgen.gui ngs = pytest.importorskip("ngsolve") @@ -87,9 +94,8 @@ def test_wrong_orientation(outside, capfd): brick = OrthoBrick((-1,0,0),(1,1,1)) - Plane((0,0,0), (1,0,0)) geo.Add(brick.mat("air")) - mesh = geo.GenerateMesh() + mesh = geo.GenerateMesh(boundary_layers=[BoundaryLayerParameters(".*", [0.1], "air", domain="air", outside=outside)]) - mesh.BoundaryLayer(".*", 0.1, "air", domains="air", outside=outside) ngs = pytest.importorskip("ngsolve") mesh = ngs.Mesh(mesh) assert ngs.Integrate(1, mesh) == pytest.approx(1.2**3 if outside else 1) @@ -102,8 +108,7 @@ def test_splitted_surface(): geo.Add((brick-slots).mat("block")) geo.Add((brick*slots).mat("slot")) - mesh = geo.GenerateMesh() - mesh.BoundaryLayer(".*", [0.001, 0.001], "block", "block", outside=False) + mesh = geo.GenerateMesh(boundary_layers=[BoundaryLayerParameters(".*", [0.001, 0.001], "block", domain="block", outside=False)]) ngs = pytest.importorskip("ngsolve") mesh = ngs.Mesh(mesh) assert ngs.Integrate(1, mesh) == pytest.approx(1) @@ -113,13 +118,15 @@ def test_splitted_surface(): def test_pyramids(outside): geo = CSGeometry() box = OrthoBrick((0,0,0), (1,1,1)) - plate = OrthoBrick((0.3,0.3,0.4),(0.7,0.7,1)) * Plane((0,0,0.6), (0,0,1)).bc("top") + dist = 0.3 + plate = OrthoBrick((dist,dist,0.4),(1-dist,1-dist,1)) * Plane((0,0,0.6), (0,0,1)).bc("top") geo.Add((box-plate).mat("air")) geo.Add(plate.mat("plate")) - mesh = geo.GenerateMesh() - mesh.BoundaryLayer("top", [0.01], "layer", "plate", outside=outside) + blayers = [BoundaryLayerParameters("top", [0.01], "layer", domain="plate", outside=outside)] + mesh = geo.GenerateMesh(boundary_layers=blayers) ngs = pytest.importorskip("ngsolve") mesh = ngs.Mesh(mesh) + assert ngs.Integrate(1, mesh.Materials("plate")) == pytest.approx(0.032 if outside else 0.0304) assert ngs.Integrate(1, mesh.Materials("layer")) == pytest.approx(0.0016) assert ngs.Integrate(1, mesh.Materials("air")) == pytest.approx(0.9664 if outside else 0.968) @@ -167,8 +174,8 @@ def _test_with_inner_corner(outside, capfd): geo.Add(coil1, col=(0.72, 0.45, 0.2)) geo.Add(coil2, col=(0.72, 0.45, 0.2)) geo.Add(oil.mat("oil"), transparent=True) - mesh = geo.GenerateMesh() - mesh.BoundaryLayer("core_front", [0.001, 0.002], "core", "core", outside=outside) + blayers = [BoundaryLayerParameters("core_front", [0.001, 0.002], "core", domain="core", outside=outside)] + mesh = geo.GenerateMesh(boundary_layers = blayers) ngs = pytest.importorskip("ngsolve") mesh = ngs.Mesh(mesh) capture = capfd.readouterr() diff --git a/tests/pytest/test_meshclass.py b/tests/pytest/test_meshclass.py index 0144422f..ca50a1f9 100644 --- a/tests/pytest/test_meshclass.py +++ b/tests/pytest/test_meshclass.py @@ -1,16 +1,19 @@ import pyngcore import netgen +import pytest +import tempfile from meshes import unit_mesh_3d + def test_element_arrays(unit_mesh_3d): mesh = unit_mesh_3d - el0 = mesh.Elements0D() el1 = mesh.Elements1D() el2 = mesh.Elements2D() el3 = mesh.Elements3D() p = mesh.Points() + assert len(el1) > 0 assert len(el2) > 0 assert len(el3) > 0 assert len(p) > 0 @@ -20,3 +23,43 @@ def test_element_arrays(unit_mesh_3d): for el in el3: assert len(el.vertices) == 4 + + +def test_copy_mesh(): + pytest.importorskip("netgen.occ") + import netgen.occ as occ + + box1 = occ.Box((0, 0, 0), (1, 1, 1)) + box2 = occ.Box((1, 0, 0), (2, 1, 1)) + box1.faces.name = "bnd1" + box1.name = "mat1" + box2.faces.name = "bnd2" + box2.name = "mat1" + + geo = occ.OCCGeometry(occ.Glue([box1, box2])) + m3d = geo.GenerateMesh(maxh=99) + + plane1 = occ.WorkPlane(occ.Axes((0, 0, 0), occ.X, occ.Y)).Rectangle(1, 1).Face() + plane1.name = "mat1" + plane1.edges.name = "bnd1" + + plane2 = occ.WorkPlane(occ.Axes((0, 0, 0), occ.X, occ.Y)).Rectangle(2, 2).Face() + plane2.name = "mat2" + plane2.edges.name = "bnd2" + + geo2 = occ.OCCGeometry(occ.Glue([plane1, plane2]), dim=2) + m2d = geo2.GenerateMesh(maxh=99) + + for mesh in [m2d, m3d]: + copy = mesh.Copy() + + assert copy.dim == mesh.dim + assert len(copy.Elements0D()) == len(mesh.Elements0D()) + assert len(copy.Elements1D()) == len(mesh.Elements1D()) + assert len(copy.Elements2D()) == len(mesh.Elements2D()) + assert len(copy.Elements3D()) == len(mesh.Elements3D()) + assert copy.GetNDomains() == mesh.GetNDomains() + assert copy.GetNFaceDescriptors() == mesh.GetNFaceDescriptors() + for dim in range(1, mesh.dim + 1): + assert copy.GetRegionNames(dim) == mesh.GetRegionNames(dim) + assert copy.GetIdentifications() == mesh.GetIdentifications() diff --git a/tests/pytest/test_nonnative_master b/tests/pytest/test_nonnative_master new file mode 100644 index 00000000..711623bb --- /dev/null +++ b/tests/pytest/test_nonnative_master @@ -0,0 +1,93 @@ +tstart (must be vertically): (0, 1.82574) +tend (must be vertically): (0, -1.82574) +sin (must not be 0) = 0.447214sin (must not be 0) = 0.447214tstart (must be vertically): (0, 1.82574) +tend (must be vertically): (0, -1.82574) +sin (must not be 0) = 0.447214sin (must not be 0) = 0.447214tstart (must be vertically): (0, 1.82574) +tend (must be vertically): (0, -1.82574) +sin (must not be 0) = 0.447214sin (must not be 0) = 0.447214tstart (must be vertically): (0, 1.82574) +tend (must be vertically): (0, -1.82574) +sin (must not be 0) = 0.447214sin (must not be 0) = 0.447214tstart (must be vertically): (0, 1.82574) +tend (must be vertically): (0, -1.82574) +sin (must not be 0) = 0.447214sin (must not be 0) = 0.447214tstart (must be vertically): (0, 1.82574) +tend (must be vertically): (0, -1.82574) +generate boundarycondition.geo +needed 0.12342000007629395 seconds +generate boxcyl.geo +needed 0.801245927810669 seconds +generate circle_on_cube.geo +needed 0.48620080947875977 seconds +generate cone.geo +needed 1.186929702758789 seconds +generate cube.geo +needed 0.09043073654174805 seconds +generate cubeandring.geo +needed 2.1420021057128906 seconds +generate cubeandspheres.geo +needed 0.26427721977233887 seconds +generate cubemcyl.geo +needed 18.373886108398438 seconds +generate cubemsphere.geo +needed 3.6954052448272705 seconds +generate cylinder.geo +needed 0.44164204597473145 seconds +generate cylsphere.geo +needed 0.8774328231811523 seconds +generate ellipsoid.geo +needed 1.4510962963104248 seconds +generate ellipticcone.geo +needed 3.0906074047088623 seconds +generate ellipticcyl.geo +needed 2.0780415534973145 seconds +generate extrusion.geo +needed 0.40680599212646484 seconds +generate fichera.geo +needed 0.1265270709991455 seconds +generate hinge.stl +needed 5.519087553024292 seconds +generate lense.in2d +needed 0.05641365051269531 seconds +generate lshape3d.geo +needed 0.09937620162963867 seconds +generate manyholes.geo +needed 9.43863034248352 seconds +generate manyholes2.geo +needed 7.40019965171814 seconds +generate matrix.geo +needed 3.734792709350586 seconds +generate ortho.geo +needed 0.09516167640686035 seconds +generate part1.stl +needed 2.6940107345581055 seconds +generate period.geo +needed 2.709449291229248 seconds +generate revolution.geo +needed 7.7064368724823 seconds +generate sculpture.geo +needed 0.6283819675445557 seconds +generate shaft.geo +needed 2.921243190765381 seconds +generate shell.geo +generate sphere.geo +needed 0.18424725532531738 seconds +generate sphereincube.geo +needed 0.6060984134674072 seconds +generate square.in2d +needed 0.021883487701416016 seconds +generate squarecircle.in2d +needed 0.04081606864929199 seconds +generate squarehole.in2d +needed 0.03681302070617676 seconds +generate torus.geo +needed 6.590093612670898 seconds +generate trafo.geo +needed 3.2712368965148926 seconds +generate twobricks.geo +needed 0.13849091529846191 seconds +generate twocubes.geo +needed 0.13361692428588867 seconds +generate twocyl.geo +needed 0.8036918640136719 seconds +generate plane.stl +needed 15.712460041046143 seconds +done +sin (must not be 0) = 0.447214sin (must not be 0) = 0.447214 \ No newline at end of file diff --git a/tests/pytest/test_occ.py b/tests/pytest/test_occ.py index 510775cb..e21eab06 100644 --- a/tests/pytest/test_occ.py +++ b/tests/pytest/test_occ.py @@ -41,3 +41,15 @@ def test_box_and_cyl(): check_volume(cyl, vcyl) fused = box+cyl check_volume(fused, 1+vcyl) + +def test_internal_face(): + occ = pytest.importorskip("netgen.occ") + box = occ.Box((0,0,0), (3, 1, 10)) + + face = occ.WorkPlane(occ.Axes((1.5,0,0), occ.X, occ.Y)).Rectangle(1, 6).Face() + + shape = occ.Glue([box, face]) + geo = occ.OCCGeometry(shape) + mesh = geo.GenerateMesh(maxh=0.5) + assert any(mesh.Elements2D().NumPy()['index'] == 8) + diff --git a/tests/pytest/test_tutorials.py b/tests/pytest/test_tutorials.py index e7c4d81a..2d25804c 100644 --- a/tests/pytest/test_tutorials.py +++ b/tests/pytest/test_tutorials.py @@ -72,6 +72,8 @@ def getMeshingparameters(filename): return standard[:-1] if filename == "screw.step": return standard[3:] # coarser meshes don't work here + if filename == "cylinder.geo": + return [] # gives inconsistent reults if filename == "cylsphere.geo": return standard[0:2] + standard[3:] # coarse gives inconsistent reults (other mesh on MacOS) if filename == "part1.stl": @@ -131,8 +133,8 @@ def test_geoFiles(filename, mp, i, refdata): checkData(mesh, mp, ref[i]) -def generateResultFile(): - import re, time +def generateResultFile(output_file='results.json'): + import time data = {} with TaskManager(): for _file in _geofiles + _additional_testfiles: @@ -153,8 +155,9 @@ def generateResultFile(): print("needed", time.time() - start, "seconds") s = json.dumps(data, sort_keys=True, indent=4) - open("results.json", "w").write(s) + open(output_file, "w").write(s) print("done") if __name__ == "__main__": - generateResultFile() + import sys + generateResultFile(*sys.argv[1:]) diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 00000000..9a79e670 --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,153 @@ +import argparse +import os +import requests +import sys +import time +from subprocess import check_output +from packaging import tags +from packaging.utils import parse_wheel_filename + + +_sys_tags = None + + +def _is_wheel_compatible(wheel_filename: str): + global _sys_tags + try: + if _sys_tags is None: + _sys_tags = set(tags.sys_tags()) + + for tag in parse_wheel_filename(wheel_filename)[-1]: + if tag in _sys_tags: + return True + + return False + except Exception as e: + print(f"Error parsing wheel file: {e}") + return False + + +def is_package_available(package_name, version): + url = f"https://pypi.org/pypi/{package_name}/{version}/json" + + try: + response = requests.get(url) + if response.status_code != 200: + return False + + data = response.json() + + for file_info in data["urls"]: + name = file_info.get("filename", "") + if _is_wheel_compatible(name): + return True + + return False + + except requests.RequestException as e: + print(f"Error checking package: {e}") + return False + + +def is_dev_build(): + if "NG_NO_DEV_PIP_VERSION" in os.environ: + return False + if ( + "CI_COMMIT_REF_NAME" in os.environ + and os.environ["CI_COMMIT_REF_NAME"] == "release" + ): + return False + return True + + +def get_git_version(cwd): + return check_output(["git", "describe", "--tags"], cwd=cwd).decode("utf-8").strip() + + +def get_dev_extension(cwd): + if not is_dev_build(): + return "" + + # if the current commit does not belong to master, build a .dev1 package to avoid name conflicts for subsequent nightly builds from master + try: + check_output(["git", "merge-base", "--is-ancestor", "HEAD", "master"], cwd=cwd) + return ".dev0" + except: + return ".dev1" + + +def get_version(cwd): + git_version = get_git_version(cwd) + + version = git_version[1:].split("-") + if len(version) > 2: + version = version[:2] + if len(version) > 1: + version = ".post".join(version) + version += get_dev_extension(cwd) + else: + version = version[0] + + return version + + +def main(): + parser = argparse.ArgumentParser(description="Netgen pip building utilities") + parser.add_argument( + "--check-pip", + action="store_true", + help="Check if package is on pypi already, fails with exit code 1 if available", + ) + parser.add_argument( + "--wait-pip", + action="store_true", + help="Wait until package is on pypi, fails with exit code 1 if still not available after 300s", + ) + parser.add_argument( + "--get-git-version", + action="store_true", + help="Generate the current package git version string", + ) + parser.add_argument( + "--get-version", + action="store_true", + help="Generate the current package version using git", + ) + parser.add_argument("--dir", type=str, default=".", help="CWD to run git commands") + parser.add_argument( + "--package", + type=str, + default="netgen-mesher", + help="Package name to check on pypi", + ) + + args = parser.parse_args() + + if args.get_git_version: + print(get_git_version(args.dir)) + elif args.get_version: + print(get_version(args.dir)) + elif args.check_pip: + version = get_version(args.dir) + if is_package_available(args.package, version): + print(f"{args.package}=={version} is already on pypi") + sys.exit(1) + elif args.wait_pip: + version = get_version(args.dir) + t0 = time.time() + while time.time() - t0 < 300 and not is_package_available( + args.package, version + ): + time.sleep(20) + + if not is_package_available(args.package, version): + print( + f"Timeout waiting for package {args.package}=={version} to be available on pypi" + ) + sys.exit(1) + else: + print("no action") + + +if __name__ == "__main__": + main()