merge master

This commit is contained in:
Michael Neunteufel 2019-02-11 09:16:22 +01:00
commit e8f6ca5c1b
97 changed files with 4054 additions and 1338 deletions

View File

@ -14,8 +14,8 @@ stages:
- x64 - x64
before_script: before_script:
- "echo off" - "echo off"
- 'call "%VS140COMNTOOLS%\..\..\VC\bin\amd64\vcvars64.bat"' - 'call "%VS2017INSTALLDIR%\VC\Auxiliary\Build\vcvars64"'
- set CMAKE_GENERATOR=Visual Studio 14 2015 Win64 - set CMAKE_GENERATOR=Visual Studio 15 2017 Win64
- set CI_DIR=C:\ci\%CI_PIPELINE_ID% - set CI_DIR=C:\ci\%CI_PIPELINE_ID%
- set NETGEN_BUILD_DIR=%CI_DIR%\build - set NETGEN_BUILD_DIR=%CI_DIR%\build
- set INSTALL_DIR=%CI_DIR%\install - set INSTALL_DIR=%CI_DIR%\install
@ -100,6 +100,14 @@ test_guidelines:
script: script:
- docker run -e CCACHE_DIR=/ccache -v /mnt/ccache:/ccache netgen_${CI_BUILD_REF_NAME}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_guidelines.sh - docker run -e CCACHE_DIR=/ccache -v /mnt/ccache:/ccache netgen_${CI_BUILD_REF_NAME}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_guidelines.sh
when: always when: always
allow_failure: true
# check if it compiles without spdlog
test_noSpdlog:
<<: *ubuntu
stage: test
script:
- docker run -e CCACHE_DIR=/ccache -v /mnt/ccache:/ccache netgen_${CI_BUILD_REF_NAME}:${UBUNTU_VERSION} bash /root/src/netgen/tests/build_nospdlog.sh
cleanup_ubuntu: cleanup_ubuntu:
stage: cleanup stage: cleanup

View File

@ -2,7 +2,13 @@ if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING INTERNAL) set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING INTERNAL)
endif(NOT CMAKE_BUILD_TYPE) endif(NOT CMAKE_BUILD_TYPE)
cmake_minimum_required(VERSION 3.1.3) if(WIN32)
# we are linking to object libraries on Windows
cmake_minimum_required(VERSION 3.12)
else(WIN32)
cmake_minimum_required(VERSION 3.1.3)
endif(WIN32)
if(NOT WIN32) if(NOT WIN32)
option( USE_NATIVE_ARCH "build which -march=native" ON) option( USE_NATIVE_ARCH "build which -march=native" ON)
endif(NOT WIN32) endif(NOT WIN32)
@ -19,6 +25,9 @@ option( USE_CCACHE "use ccache")
option( USE_INTERNAL_TCL "Compile tcl files into the code and don't install them" ON) 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_UNIT_TESTS "Enable Catch unit tests")
option( ENABLE_CPP_CORE_GUIDELINES_CHECK "Enable cpp core guideline checks on ngcore" OFF) 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( USE_SUPERBUILD "use ccache" ON) option( USE_SUPERBUILD "use ccache" ON)
@ -258,6 +267,7 @@ endif (USE_GUI)
####################################################################### #######################################################################
if (USE_PYTHON) if (USE_PYTHON)
add_subdirectory(external_dependencies/pybind11)
add_definitions(-DNG_PYTHON) add_definitions(-DNG_PYTHON)
find_path(PYBIND_INCLUDE_DIR pybind11/pybind11.h HINTS ${PYTHON_INCLUDE_DIR}) find_path(PYBIND_INCLUDE_DIR pybind11/pybind11.h HINTS ${PYTHON_INCLUDE_DIR})
if( PYBIND_INCLUDE_DIR ) if( PYBIND_INCLUDE_DIR )
@ -350,6 +360,11 @@ endif(ENABLE_UNIT_TESTS)
####################################################################### #######################################################################
if(USE_SPDLOG)
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/external_projects/spdlog.cmake)
include_directories(${SPDLOG_INCLUDE_DIR})
endif(USE_SPDLOG)
if(ENABLE_CPP_CORE_GUIDELINES_CHECK) if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
find_program( find_program(
CLANG_TIDY_EXE CLANG_TIDY_EXE

View File

@ -142,6 +142,9 @@ set_vars( NETGEN_CMAKE_ARGS
CMAKE_INSTALL_PREFIX CMAKE_INSTALL_PREFIX
ENABLE_UNIT_TESTS ENABLE_UNIT_TESTS
ENABLE_CPP_CORE_GUIDELINES_CHECK ENABLE_CPP_CORE_GUIDELINES_CHECK
USE_SPDLOG
DEBUG_LOG
CHECK_RANGE
) )
# propagate all variables set on the command line using cmake -DFOO=BAR # propagate all variables set on the command line using cmake -DFOO=BAR

View File

@ -0,0 +1,18 @@
include(ExternalProject)
find_program(GIT_EXECUTABLE git)
ExternalProject_Add(
project_spdlog
PREFIX ${CMAKE_BINARY_DIR}/spdlog
GIT_REPOSITORY https://github.com/gabime/spdlog.git
GIT_TAG v1.2.1
TIMEOUT 01
UPDATE_COMMAND ""
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
LOG_DOWNLOAD ON
)
ExternalProject_Get_Property(project_spdlog source_dir)
set(SPDLOG_INCLUDE_DIR ${source_dir}/include)

View File

@ -1,6 +1,6 @@
if(APPLE) if(APPLE)
# use system tcl/tk # use system tcl/tk
if(${PYTHON_VERSION_STRING} STREQUAL "3.7") if((${PYTHON_VERSION_STRING} VERSION_EQUAL "3.7") OR (${PYTHON_VERSION_STRING} VERSION_GREATER "3.7"))
# fetch tcl/tk sources to match the one used in Python 3.7 # fetch tcl/tk sources to match the one used in Python 3.7
ExternalProject_Add(project_tcl ExternalProject_Add(project_tcl
URL "https://prdownloads.sourceforge.net/tcl/tcl8.6.8-src.tar.gz" URL "https://prdownloads.sourceforge.net/tcl/tcl8.6.8-src.tar.gz"

View File

@ -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' 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'
CheckOptions: CheckOptions:
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
value: 1 value: 1

View File

@ -1,16 +1,49 @@
add_library(ngcore SHARED archive.cpp)
target_compile_definitions(ngcore PRIVATE -DNGCORE_EXPORTS) add_library(ngcore SHARED archive.cpp logging.cpp paje_trace.cpp utils.cpp profiler.cpp)
target_compile_definitions(ngcore PRIVATE NGCORE_EXPORTS)
if(NOT WIN32)
target_compile_options(ngcore PRIVATE -fvisibility=hidden)
endif(NOT WIN32)
target_compile_definitions(ngcore PUBLIC $<$<CONFIG:DEBUG>:NETGEN_ENABLE_CHECK_RANGE>)
if(CHECK_RANGE)
target_compile_definitions(ngcore PUBLIC NETGEN_ENABLE_CHECK_RANGE)
endif(CHECK_RANGE)
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)
install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen) install(TARGETS ngcore DESTINATION ${NG_INSTALL_DIR} COMPONENT netgen)
if(USE_PYTHON) if(USE_PYTHON)
target_compile_definitions(ngcore PUBLIC NETGEN_PYTHON)
target_include_directories(ngcore PUBLIC ${PYTHON_INCLUDE_DIRS}) target_include_directories(ngcore PUBLIC ${PYTHON_INCLUDE_DIRS})
target_link_libraries(ngcore PUBLIC ${PYTHON_LIBRARIES})
endif(USE_PYTHON) endif(USE_PYTHON)
install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp install(FILES ngcore.hpp archive.hpp type_traits.hpp version.hpp ngcore_api.hpp logging.hpp
exception.hpp symboltable.hpp paje_trace.hpp utils.hpp profiler.hpp
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel) DESTINATION ${NG_INSTALL_DIR_INCLUDE}/core COMPONENT netgen_devel)
if(ENABLE_CPP_CORE_GUIDELINES_CHECK) if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
set_target_properties(ngcore PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}") set_target_properties(ngcore PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
endif(ENABLE_CPP_CORE_GUIDELINES_CHECK) endif(ENABLE_CPP_CORE_GUIDELINES_CHECK)
if(USE_PYTHON)
pybind11_add_module(pyngcore SHARED python_ngcore.cpp)
target_link_libraries(pyngcore PUBLIC ngcore ${PYTHON_LIBRARIES})
set_target_properties(pyngcore PROPERTIES INSTALL_RPATH "${NG_RPATH_TOKEN}/${NETGEN_PYTHON_RPATH}")
install(TARGETS pyngcore DESTINATION ${NG_INSTALL_DIR_PYTHON} COMPONENT netgen)
endif(USE_PYTHON)

View File

@ -19,16 +19,6 @@ namespace ngcore
void SetLibraryVersion(const std::string& library, const VersionInfo& version) void SetLibraryVersion(const std::string& library, const VersionInfo& version)
{ library_versions[library] = version; } { library_versions[library] = version; }
#ifdef WIN32
// windows does demangling in typeid(T).name()
std::string Demangle(const char* typeinfo) { return typeinfo; }
#else
std::string Demangle(const char* typeinfo) { int status; return abi::__cxa_demangle(typeinfo,
nullptr,
nullptr,
&status); }
#endif
// clang-tidy should ignore this static object // clang-tidy should ignore this static object
static std::unique_ptr<std::map<std::string, detail::ClassArchiveInfo>> type_register; // NOLINT static std::unique_ptr<std::map<std::string, detail::ClassArchiveInfo>> type_register; // NOLINT
const detail::ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname) const detail::ClassArchiveInfo& Archive :: GetArchiveRegister(const std::string& classname)

View File

@ -3,31 +3,32 @@
#include <complex> // for complex #include <complex> // for complex
#include <cstring> // for size_t, strlen #include <cstring> // for size_t, strlen
#include <fstream> // for operator<<, ifstream, ofstream, basic... #include <fstream> // for ifstream, ofstream
#include <functional> // for function #include <functional> // for function
#include <map> // for map, _Rb_tree_iterator #include <map> // for map
#include <memory> // for __shared_ptr_access, __shared_ptr_acc... #include <memory> // for shared_ptr
#include <stdexcept> // for runtime_error #include <string> // for string
#include <string> // for string, operator+
#include <type_traits> // for declval, enable_if, false_type, is_co... #include <type_traits> // for declval, enable_if, false_type, is_co...
#include <typeinfo> // for type_info #include <typeinfo> // for type_info
#include <utility> // for move, swap, pair #include <utility> // for move, swap, pair
#include <vector> // for vector #include <vector> // for vector
#include "ngcore_api.hpp" // for NGCORE_API, unlikely #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 "type_traits.hpp" // for all_of_tmpl
#include "utils.hpp" // for Demangle, unlikely
#include "version.hpp" // for VersionInfo #include "version.hpp" // for VersionInfo
#ifdef NG_PYTHON #ifdef NETGEN_PYTHON
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
#endif // NG_PYTHON #endif // NETGEN_PYTHON
namespace ngcore namespace ngcore
{ {
// Libraries using this archive can store their version here to implement backwards compatibility // Libraries using this archive can store their version here to implement backwards compatibility
NGCORE_API const VersionInfo& GetLibraryVersion(const std::string& library); NGCORE_API const VersionInfo& GetLibraryVersion(const std::string& library);
NGCORE_API void SetLibraryVersion(const std::string& library, const VersionInfo& version); NGCORE_API void SetLibraryVersion(const std::string& library, const VersionInfo& version);
NGCORE_API std::string Demangle(const char* typeinfo);
class NGCORE_API Archive; class NGCORE_API Archive;
@ -36,7 +37,7 @@ namespace ngcore
// create new pointer of type T if it is default constructible, else throw // create new pointer of type T if it is default constructible, else throw
template<typename T, typename ...Rest> template<typename T, typename ...Rest>
T* constructIfPossible_impl(Rest... /*unused*/) T* constructIfPossible_impl(Rest... /*unused*/)
{ throw std::runtime_error(std::string(Demangle(typeid(T).name())) + " is not default constructible!"); } { throw Exception(std::string(Demangle(typeid(T).name())) + " is not default constructible!"); }
template<typename T, typename= typename std::enable_if<std::is_constructible<T>::value>::type> template<typename T, typename= typename std::enable_if<std::is_constructible<T>::value>::type>
T* constructIfPossible_impl(int /*unused*/) { return new T; } // NOLINT T* constructIfPossible_impl(int /*unused*/) { return new T; } // NOLINT
@ -96,28 +97,34 @@ namespace ngcore
{ {
const bool is_output; const bool is_output;
// how many different shared_ptr/pointer have been (un)archived // how many different shared_ptr/pointer have been (un)archived
int shared_ptr_count, ptr_count; int shared_ptr_count{0}, ptr_count{0};
// maps for archived shared pointers and pointers // maps for archived shared pointers and pointers
std::map<void*, int> shared_ptr2nr, ptr2nr; std::map<void*, int> shared_ptr2nr{}, ptr2nr{};
// vectors for storing the unarchived (shared) pointers // vectors for storing the unarchived (shared) pointers
std::vector<std::shared_ptr<void>> nr2shared_ptr; std::vector<std::shared_ptr<void>> nr2shared_ptr{};
std::vector<void*> nr2ptr; std::vector<void*> nr2ptr{};
protected: protected:
bool shallow_to_python = false; bool shallow_to_python = false;
std::map<std::string, VersionInfo> version_map = GetLibraryVersions();
std::shared_ptr<Logger> logger = GetLogger("Archive");
public: public:
Archive() = delete; Archive() = delete;
Archive(const Archive&) = delete; Archive(const Archive&) = delete;
Archive(Archive&&) = delete; Archive(Archive&&) = delete;
Archive (bool ais_output) : Archive (bool ais_output) : is_output(ais_output) { ; }
is_output(ais_output), shared_ptr_count(0), ptr_count(0) { ; }
virtual ~Archive() { ; } virtual ~Archive() { ; }
// If the object is pickled, all shallow archived objects will be pickled as a list,
// instead of written as a binary archive. This allows pickle to serialize every object only
// once and put them together correctly afterwards. Therefore all objects that may live in
// Python should be archived using this Shallow function. If Shallow is called from C++ code
// it archives the object normally.
template<typename T> template<typename T>
Archive& Shallow(T& val) Archive& Shallow(T& val)
{ {
static_assert(detail::is_any_pointer<T>, "ShallowArchive must be given pointer type!"); static_assert(detail::is_any_pointer<T>, "ShallowArchive must be given pointer type!");
#ifdef NG_PYTHON #ifdef NETGEN_PYTHON
if(shallow_to_python) if(shallow_to_python)
{ {
if(is_output) if(is_output)
@ -126,25 +133,28 @@ namespace ngcore
val = pybind11::cast<T>(ShallowInPython()); val = pybind11::cast<T>(ShallowInPython());
} }
else else
#endif // NG_PYTHON #endif // NETGEN_PYTHON
*this & val; *this & val;
return *this; return *this;
} }
#ifdef NG_PYTHON #ifdef NETGEN_PYTHON
virtual void ShallowOutPython(pybind11::object /*unused*/) // NOLINT (copy by val is ok for this virt func) virtual void ShallowOutPython(const pybind11::object& /*unused*/)
{ throw std::runtime_error("Should not get in ShallowToPython base class implementation!"); } { throw UnreachableCodeException{}; }
virtual pybind11::object ShallowInPython() virtual pybind11::object ShallowInPython()
{ throw std::runtime_error("Should not get in ShallowFromPython base class implementation!"); } { throw UnreachableCodeException{}; }
#endif // NG_PYTHON #endif // NETGEN_PYTHON
Archive& operator=(const Archive&) = delete; Archive& operator=(const Archive&) = delete;
Archive& operator=(Archive&&) = delete; Archive& operator=(Archive&&) = delete;
bool Output () const { return is_output; } bool Output () const { return is_output; }
bool Input () const { return !is_output; } bool Input () const { return !is_output; }
virtual const VersionInfo& GetVersion(const std::string& library) const VersionInfo& GetVersion(const std::string& library)
{ return GetLibraryVersions()[library]; } { return version_map[library]; }
// only used for PyArchive
virtual void NeedsVersion(const std::string& /*unused*/, const std::string& /*unused*/) {}
// Pure virtual functions that have to be implemented by In-/OutArchive // Pure virtual functions that have to be implemented by In-/OutArchive
virtual Archive & operator & (double & d) = 0; virtual Archive & operator & (double & d) = 0;
@ -157,7 +167,7 @@ namespace ngcore
virtual Archive & operator & (std::string & str) = 0; virtual Archive & operator & (std::string & str) = 0;
virtual Archive & operator & (char *& str) = 0; virtual Archive & operator & (char *& str) = 0;
virtual Archive & operator & (VersionInfo & version) Archive & operator & (VersionInfo & version)
{ {
if(Output()) if(Output())
(*this) << version.to_string(); (*this) << version.to_string();
@ -198,6 +208,47 @@ namespace ngcore
Do(&v[0], size); Do(&v[0], size);
return (*this); return (*this);
} }
// archive implementation for enums
template<typename T>
auto operator & (T& val) -> typename std::enable_if<std::is_enum<T>::value, Archive&>::type
{
int enumval;
if(Output())
enumval = int(val);
*this & enumval;
if(Input())
val = T(enumval);
return *this;
}
// vector<bool> has special implementation (like a bitarray) therefore
// it needs a special overload (this could probably be more efficient, but we
// don't use it that often anyway)
Archive& operator& (std::vector<bool>& v)
{
logger->debug("In special archive for std::vector<bool>");
size_t size;
if(Output())
size = v.size();
(*this) & size;
if(Input())
{
v.resize(size);
bool b;
for(size_t i=0; i<size; i++)
{
(*this) & b;
v[i] = b;
}
}
else
{
for(bool b : v)
(*this) & b;
}
return *this;
}
template<typename T1, typename T2> template<typename T1, typename T2>
Archive& operator& (std::map<T1, T2>& map) Archive& operator& (std::map<T1, T2>& map)
{ {
@ -261,28 +312,40 @@ namespace ngcore
{ {
if(Output()) if(Output())
{ {
logger->debug("Store shared ptr of type {}", Demangle(typeid(T).name()));
// save -2 for nullptr // save -2 for nullptr
if(!ptr) if(!ptr)
return (*this) << -2; {
logger->debug("Storing nullptr");
return (*this) << -2;
}
void* reg_ptr = ptr.get(); void* reg_ptr = ptr.get();
bool neededDowncast = false; bool neededDowncast = false;
// Downcasting is only possible for our registered classes // Downcasting is only possible for our registered classes
if(typeid(T) != typeid(*ptr)) 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()))) if(!IsRegistered(Demangle(typeid(*ptr).name())))
throw std::runtime_error(std::string("Archive error: Polymorphic type ") throw Exception(std::string("Archive error: Polymorphic type ")
+ Demangle(typeid(*ptr).name()) + Demangle(typeid(*ptr).name())
+ " not registered for archive"); + " not registered for archive");
reg_ptr = GetArchiveRegister(Demangle(typeid(*ptr).name())).downcaster(typeid(T), ptr.get()); 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 there was a true downcast we have to store more information
if(reg_ptr != static_cast<void*>(ptr.get()) ) if(reg_ptr != static_cast<void*>(ptr.get()))
{
logger->debug("Multiple/Virtual inheritance involved, need to cast pointer");
neededDowncast = true; neededDowncast = true;
}
} }
auto pos = shared_ptr2nr.find(reg_ptr); auto pos = shared_ptr2nr.find(reg_ptr);
// if not found store -1 and the pointer // if not found store -1 and the pointer
if(pos == shared_ptr2nr.end()) 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(); auto p = ptr.get();
(*this) << -1; (*this) << -1;
(*this) & neededDowncast & p; (*this) & neededDowncast & p;
@ -293,23 +356,27 @@ namespace ngcore
return *this; return *this;
} }
// if found store the position and if it has to be downcasted and how // 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; (*this) << pos->second << neededDowncast;
if(neededDowncast) if(neededDowncast)
(*this) << Demangle(typeid(*ptr).name()); (*this) << Demangle(typeid(*ptr).name());
} }
else // Input else // Input
{ {
logger->debug("Reading shared_ptr of type {}", Demangle(typeid(T).name()));
int nr; int nr;
(*this) & nr; (*this) & nr;
// -2 restores a nullptr // -2 restores a nullptr
if(nr == -2) if(nr == -2)
{ {
logger->debug("Reading a nullptr");
ptr = nullptr; ptr = nullptr;
return *this; return *this;
} }
// -1 restores a new shared ptr by restoring the inner pointer and creating a shared_ptr to it // -1 restores a new shared ptr by restoring the inner pointer and creating a shared_ptr to it
if (nr == -1) if (nr == -1)
{ {
logger->debug("Createing new shared_ptr");
T* p = nullptr; T* p = nullptr;
bool neededDowncast; bool neededDowncast;
(*this) & neededDowncast & p; (*this) & neededDowncast & p;
@ -317,6 +384,7 @@ namespace ngcore
// if we did downcast we need to store a shared_ptr<void> to the true object // if we did downcast we need to store a shared_ptr<void> to the true object
if(neededDowncast) if(neededDowncast)
{ {
logger->debug("Shared pointer needed downcasting");
std::string name; std::string name;
(*this) & name; (*this) & name;
auto info = GetArchiveRegister(name); auto info = GetArchiveRegister(name);
@ -327,15 +395,20 @@ namespace ngcore
ptr.get()))); ptr.get())));
} }
else else
nr2shared_ptr.push_back(ptr); {
logger->debug("Shared pointer didn't need downcasting");
nr2shared_ptr.push_back(ptr);
}
} }
else else
{ {
logger->debug("Reading already existing pointer at entry {}", nr);
auto other = nr2shared_ptr[nr]; auto other = nr2shared_ptr[nr];
bool neededDowncast; bool neededDowncast;
(*this) & neededDowncast; (*this) & neededDowncast;
if(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 // if there was a downcast we can expect the class to be registered (since archiving
// wouldn't have worked else) // wouldn't have worked else)
std::string name; std::string name;
@ -348,7 +421,10 @@ namespace ngcore
other.get()))); other.get())));
} }
else else
ptr = std::static_pointer_cast<T>(other); {
logger->debug("Shared pointer didn't need pointer casts");
ptr = std::static_pointer_cast<T>(other);
}
} }
} }
return *this; return *this;
@ -360,31 +436,45 @@ namespace ngcore
{ {
if (Output()) if (Output())
{ {
logger->debug("Store pointer of type {}",Demangle(typeid(T).name()));
// if the pointer is null store -2 // if the pointer is null store -2
if (!p) if (!p)
return (*this) << -2; {
logger->debug("Storing nullptr");
return (*this) << -2;
}
auto reg_ptr = static_cast<void*>(p); auto reg_ptr = static_cast<void*>(p);
if(typeid(T) != typeid(*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()))) if(!IsRegistered(Demangle(typeid(*p).name())))
throw std::runtime_error(std::string("Archive error: Polymorphic type ") throw Exception(std::string("Archive error: Polymorphic type ")
+ Demangle(typeid(*p).name()) + Demangle(typeid(*p).name())
+ " not registered for archive"); + " not registered for archive");
reg_ptr = GetArchiveRegister(Demangle(typeid(*p).name())).downcaster(typeid(T), static_cast<void*>(p)); reg_ptr = GetArchiveRegister(Demangle(typeid(*p).name())).downcaster(typeid(T), static_cast<void*>(p));
if(reg_ptr != static_cast<void*>(p))
{
logger->debug("Multiple/Virtual inheritance involved, need to cast pointer");
}
} }
auto pos = ptr2nr.find(reg_ptr); auto pos = ptr2nr.find(reg_ptr);
// if the pointer is not found in the map create a new entry // if the pointer is not found in the map create a new entry
if (pos == ptr2nr.end()) if (pos == ptr2nr.end())
{ {
logger->debug("Didn't find pointer, create new registry entry at {}",
ptr_count);
ptr2nr[reg_ptr] = ptr_count++; ptr2nr[reg_ptr] = ptr_count++;
if(typeid(*p) == typeid(T)) if(typeid(*p) == typeid(T))
if (std::is_constructible<T>::value) if (std::is_constructible<T>::value)
{ {
logger->debug("Store standard class pointer (no virt. inh,...)");
return (*this) << -1 & (*p); return (*this) << -1 & (*p);
} }
else else
throw std::runtime_error(std::string("Archive error: Class ") + throw Exception(std::string("Archive error: Class ") +
Demangle(typeid(*p).name()) + " does not provide a default constructor!"); Demangle(typeid(*p).name()) + " does not provide a default constructor!");
else else
{ {
// if a pointer to a base class is archived, the class hierarchy must be registered // if a pointer to a base class is archived, the class hierarchy must be registered
@ -392,9 +482,10 @@ namespace ngcore
// implement a void DoArchive(Archive&) member function // implement a void DoArchive(Archive&) member function
// To recreate the object we need to store the true type of it // To recreate the object we need to store the true type of it
if(!IsRegistered(Demangle(typeid(*p).name()))) if(!IsRegistered(Demangle(typeid(*p).name())))
throw std::runtime_error(std::string("Archive error: Polymorphic type ") throw Exception(std::string("Archive error: Polymorphic type ")
+ Demangle(typeid(*p).name()) + Demangle(typeid(*p).name())
+ " not registered for archive"); + " not registered for archive");
logger->debug("Store a possibly more complicated pointer");
return (*this) << -3 << Demangle(typeid(*p).name()) & (*p); return (*this) << -3 << Demangle(typeid(*p).name()) & (*p);
} }
} }
@ -402,27 +493,37 @@ namespace ngcore
{ {
(*this) & pos->second; (*this) & pos->second;
bool downcasted = !(reg_ptr == static_cast<void*>(p) ); bool downcasted = !(reg_ptr == static_cast<void*>(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 // store if the class has been downcasted and the name
(*this) << downcasted << Demangle(typeid(*p).name()); (*this) << downcasted << Demangle(typeid(*p).name());
} }
} }
else else
{ {
logger->debug("Reading pointer of type {}", Demangle(typeid(T).name()));
int nr; int nr;
(*this) & nr; (*this) & nr;
if (nr == -2) // restore a nullptr if (nr == -2) // restore a nullptr
{
logger->debug("Loading a nullptr");
p = nullptr; p = nullptr;
}
else if (nr == -1) // create a new pointer of standard type (no virtual or multiple inheritance,...) 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<T>(); p = detail::constructIfPossible<T>();
nr2ptr.push_back(p); nr2ptr.push_back(p);
(*this) & *p; (*this) & *p;
} }
else if(nr == -3) // restore one of our registered classes that can have multiple inheritance,... 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 // As stated above, we want this special behaviour only for our classes that implement DoArchive
std::string name; std::string name;
(*this) & name; (*this) & name;
logger->debug("Name = {}", name);
auto info = GetArchiveRegister(name); auto info = GetArchiveRegister(name);
// the creator creates a new object of type name, and returns a void* pointing // the creator creates a new object of type name, and returns a void* pointing
// to T (which may have an offset) // to T (which may have an offset)
@ -434,9 +535,11 @@ namespace ngcore
} }
else else
{ {
logger->debug("Restoring pointer to already existing object at registry position {}", nr);
bool downcasted; bool downcasted;
std::string name; std::string name;
(*this) & downcasted & name; (*this) & downcasted & name;
logger->debug("{} object of type {}", downcasted ? "Downcasted" : "Not downcasted", name);
if(downcasted) if(downcasted)
{ {
// if the class has been downcasted we can assume it is in the register // if the class has been downcasted we can assume it is in the register
@ -491,11 +594,11 @@ namespace ngcore
{ {
static void* tryUpcast (const std::type_info& /*unused*/, T* /*unused*/) static void* tryUpcast (const std::type_info& /*unused*/, T* /*unused*/)
{ {
throw std::runtime_error("Upcast not successful, some classes are not registered properly for archiving!"); throw Exception("Upcast not successful, some classes are not registered properly for archiving!");
} }
static void* tryDowncast (const std::type_info& /*unused*/, void* /*unused*/) static void* tryDowncast (const std::type_info& /*unused*/, void* /*unused*/)
{ {
throw std::runtime_error("Downcast not successful, some classes are not registered properly for archiving!"); throw Exception("Downcast not successful, some classes are not registered properly for archiving!");
} }
}; };
@ -507,7 +610,7 @@ namespace ngcore
try try
{ return GetArchiveRegister(Demangle(typeid(B1).name())). { return GetArchiveRegister(Demangle(typeid(B1).name())).
upcaster(ti, static_cast<void*>(dynamic_cast<B1*>(p))); } upcaster(ti, static_cast<void*>(dynamic_cast<B1*>(p))); }
catch(std::exception&) catch(const Exception&)
{ return Caster<T, Brest...>::tryUpcast(ti, p); } { return Caster<T, Brest...>::tryUpcast(ti, p); }
} }
@ -520,7 +623,7 @@ namespace ngcore
return dynamic_cast<T*>(static_cast<B1*>(GetArchiveRegister(Demangle(typeid(B1).name())). return dynamic_cast<T*>(static_cast<B1*>(GetArchiveRegister(Demangle(typeid(B1).name())).
downcaster(ti, p))); downcaster(ti, p)));
} }
catch(std::exception&) catch(const Exception&)
{ {
return Caster<T, Brest...>::tryDowncast(ti, p); return Caster<T, Brest...>::tryDowncast(ti, p);
} }
@ -536,7 +639,7 @@ namespace ngcore
{ {
static_assert(detail::all_of_tmpl<std::is_base_of<Bases,T>::value...>, static_assert(detail::all_of_tmpl<std::is_base_of<Bases,T>::value...>,
"Variadic template arguments must be base classes of T"); "Variadic template arguments must be base classes of T");
detail::ClassArchiveInfo info; detail::ClassArchiveInfo info {};
info.creator = [this,&info](const std::type_info& ti) -> void* info.creator = [this,&info](const std::type_info& ti) -> void*
{ return typeid(T) == ti ? detail::constructIfPossible<T>() { return typeid(T) == ti ? detail::constructIfPossible<T>()
: Archive::Caster<T, Bases...>::tryUpcast(ti, detail::constructIfPossible<T>()); }; : Archive::Caster<T, Bases...>::tryUpcast(ti, detail::constructIfPossible<T>()); };
@ -805,7 +908,7 @@ namespace ngcore
} }
}; };
#ifdef NG_PYTHON #ifdef NETGEN_PYTHON
template<typename ARCHIVE> template<typename ARCHIVE>
class PyArchive : public ARCHIVE class PyArchive : public ARCHIVE
@ -813,7 +916,12 @@ namespace ngcore
private: private:
pybind11::list lst; pybind11::list lst;
size_t index = 0; size_t index = 0;
std::map<std::string, VersionInfo> version_needed;
protected:
using ARCHIVE::stream; using ARCHIVE::stream;
using ARCHIVE::version_map;
using ARCHIVE::logger;
using ARCHIVE::GetLibraryVersions;
public: public:
PyArchive(const pybind11::object& alst = pybind11::none()) : PyArchive(const pybind11::object& alst = pybind11::none()) :
ARCHIVE(std::make_shared<std::stringstream>()), ARCHIVE(std::make_shared<std::stringstream>()),
@ -821,8 +929,30 @@ namespace ngcore
{ {
ARCHIVE::shallow_to_python = true; ARCHIVE::shallow_to_python = true;
if(Input()) if(Input())
stream = std::make_shared<std::stringstream> {
(pybind11::cast<pybind11::bytes>(lst[pybind11::len(lst)-1])); stream = std::make_shared<std::stringstream>
(pybind11::cast<pybind11::bytes>(lst[pybind11::len(lst)-1]));
*this & version_needed;
logger->debug("versions needed for unpickling = {}", version_needed);
for(auto& libversion : version_needed)
if(libversion.second > GetLibraryVersion(libversion.first))
throw Exception("Error in unpickling data:\nLibrary " + libversion.first +
" must be at least " + libversion.second.to_string());
stream = std::make_shared<std::stringstream>
(pybind11::cast<pybind11::bytes>(lst[pybind11::len(lst)-2]));
*this & version_map;
stream = std::make_shared<std::stringstream>
(pybind11::cast<pybind11::bytes>(lst[pybind11::len(lst)-3]));
}
}
void NeedsVersion(const std::string& library, const std::string& version) override
{
if(Output())
{
logger->debug("Need version {} of library {}.", version, library);
version_needed[library] = version_needed[library] > version ? version_needed[library] : version;
}
} }
using ARCHIVE::Output; using ARCHIVE::Output;
@ -831,11 +961,20 @@ namespace ngcore
using ARCHIVE::operator&; using ARCHIVE::operator&;
using ARCHIVE::operator<<; using ARCHIVE::operator<<;
using ARCHIVE::GetVersion; using ARCHIVE::GetVersion;
void ShallowOutPython(pybind11::object val) override { lst.append(val); } void ShallowOutPython(const pybind11::object& val) override { lst.append(val); }
pybind11::object ShallowInPython() override { return lst[index++]; } pybind11::object ShallowInPython() override { return lst[index++]; }
pybind11::list WriteOut() pybind11::list WriteOut()
{ {
FlushBuffer();
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
stream = std::make_shared<std::stringstream>();
*this & GetLibraryVersions();
FlushBuffer();
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
stream = std::make_shared<std::stringstream>();
logger->debug("Writeout version needed = {}", version_needed);
*this & version_needed;
FlushBuffer(); FlushBuffer();
lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str())); lst.append(pybind11::bytes(std::static_pointer_cast<std::stringstream>(stream)->str()));
return lst; return lst;
@ -843,27 +982,31 @@ namespace ngcore
}; };
template<typename T, typename T_ARCHIVE_OUT=BinaryOutArchive, typename T_ARCHIVE_IN=BinaryInArchive> template<typename T, typename T_ARCHIVE_OUT=BinaryOutArchive, typename T_ARCHIVE_IN=BinaryInArchive>
auto NGSPickle(bool printoutput=false) auto NGSPickle()
{ {
return pybind11::pickle([printoutput](T* self) return pybind11::pickle([](T* self)
{ {
PyArchive<T_ARCHIVE_OUT> ar; PyArchive<T_ARCHIVE_OUT> ar;
ar & self; ar & self;
auto output = pybind11::make_tuple(ar.WriteOut()); auto output = pybind11::make_tuple(ar.WriteOut());
if(printoutput) GetLogger("Archive")->trace("Pickling output for object of type {} = {}",
pybind11::print("pickle output of", Demangle(typeid(T).name()),"=", output); Demangle(typeid(T).name()),
std::string(pybind11::str(output)));
return output; return output;
}, },
[](pybind11::tuple state) [](pybind11::tuple state)
{ {
T* val = nullptr; T* val = nullptr;
GetLogger("Archive")->trace("State for unpickling of object of type {} = {}",
Demangle(typeid(T).name()),
std::string(pybind11::str(state[0])));
PyArchive<T_ARCHIVE_IN> ar(state[0]); PyArchive<T_ARCHIVE_IN> ar(state[0]);
ar & val; ar & val;
return val; return val;
}); });
} }
#endif // NG_PYTHON #endif // NETGEN_PYTHON
} // namespace ngcore } // namespace ngcore
#endif // NETGEN_CORE_ARCHIVE_HPP #endif // NETGEN_CORE_ARCHIVE_HPP

90
libsrc/core/exception.hpp Normal file
View File

@ -0,0 +1,90 @@
#ifndef NETGEN_CORE_EXCEPTION_HPP
#define NETGEN_CORE_EXCEPTION_HPP
#include <sstream> // for stringstream
#include <stdexcept> // for exception
#include <string> // for string
#include "ngcore_api.hpp" // for NGCORE_API
namespace ngcore
{
// Exception for code that shouldn't be executed
class NGCORE_API UnreachableCodeException : public std::exception
{
const char* what() const noexcept override
{
return "Shouldn't get here, something went wrong!";
}
};
// Default exception class
class NGCORE_API Exception : public std::exception
{
/// a verbal description of the exception
std::string m_what;
public:
Exception() = default;
Exception(const Exception&) = default;
Exception(Exception&&) = default;
Exception(const std::string& s) : m_what(s) {}
Exception(const char* s) : m_what(s) {}
~Exception() override = default;
Exception& operator =(const Exception&) = default;
Exception& operator =(Exception&&) noexcept = default;
/// append string to description
Exception & Append (const std::string & s) { m_what += s; return *this; }
/// append string to description
Exception & Append (const char * s) { m_what += s; return *this; }
/// verbal description of exception
const std::string & What() const { return m_what; }
/// implement virtual function of std::exception
const char* what() const noexcept override { return m_what.c_str(); }
};
// 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("")
{
std::stringstream str;
str << where << ": index " << ind << " out of range [" << imin << "," << imax << "]\n";
Append (str.str());
}
template<typename T>
RangeException(const std::string& where, const T& value)
{
std::stringstream str;
str << where << " called with wrong value " << value << "\n";
Append(str.str());
}
};
// Exception used if no simd implementation is available to fall back to standard evaluation
class NGCORE_API ExceptionNOSIMD : public Exception
{ public: using Exception::Exception; };
} // namespace ngcore
#define NETGEN_CORE_NGEXEPTION_STR_HELPER(x) #x
#define NETGEN_CORE_NGEXEPTION_STR(x) NETGEN_CORE_NGEXEPTION_STR_HELPER(x)
// Convenience macro to append file name and line of exception origin to the string
#define NG_EXCEPTION(s) ngcore::Exception(__FILE__ ":" NETGEN_CORE_NGEXEPTION_STR(__LINE__) "\t"+std::string(s))
#ifdef NETGEN_ENABLE_CHECK_RANGE
#define NETGEN_CHECK_RANGE(value, min, max) \
{ if ((value)<(min) || (value)>=(max)) \
throw ngcore::RangeException(__FILE__ ":" NETGEN_CORE_NGEXEPTION_STR(__LINE__) "\t", (value), (min), (max)); }
#else // NETGEN_ENABLE_CHECK_RANGE
#define NETGEN_CHECK_RANGE(value, min, max)
#endif // NETGEN_ENABLE_CHECK_RANGE
#endif // NETGEN_CORE_EXCEPTION_HPP

137
libsrc/core/logging.cpp Normal file
View File

@ -0,0 +1,137 @@
#include "logging.hpp"
#ifdef NETGEN_USE_SPDLOG
#include <spdlog/spdlog.h>
#include <spdlog/sinks/ansicolor_sink.h>
#include <spdlog/sinks/basic_file_sink.h>
#else // NETGEN_USE_SPDLOG
#include <iostream>
#endif // NETGEN_USE_SPDLOG
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>level::debug)
std::clog << s << '\n';
#endif // NETGEN_USE_SPDLOG
}
#ifdef NETGEN_USE_SPDLOG
namespace detail
{
std::vector<std::shared_ptr<spdlog::sinks::sink>>& GetDefaultSinks()
{
static std::vector<std::shared_ptr<spdlog::sinks::sink>> sinks =
{ std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>() };
return sinks;
}
std::shared_ptr<spdlog::logger> CreateDefaultLogger(const std::string& name)
{
auto& default_sinks = GetDefaultSinks();
auto logger = std::make_shared<spdlog::logger>(name, default_sinks.begin(), default_sinks.end());
spdlog::details::registry::instance().register_and_init(logger);
return logger;
}
} // namespace detail
std::shared_ptr<Logger> GetLogger(const std::string& name)
{
auto logger = spdlog::get(name);
if(!logger)
logger = detail::CreateDefaultLogger(name);
return std::make_shared<Logger>(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<spdlog::sinks::basic_file_sink_mt>(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<spdlog::sinks::ansicolor_stdout_sink_mt>();
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
{
class logger
{
public:
logger() = default;
};
} // namespace spdlog
namespace ngcore
{
// Dummy functions if no spdlog is available
std::shared_ptr<Logger> GetLogger(const std::string& /*unused*/)
{
return std::make_shared<Logger>(std::make_shared<spdlog::logger>());
}
void SetLoggingLevel(level::level_enum /*unused*/, const std::string& /*unused*/) {}
void AddFileSink(const std::string& /*unused*/, level::level_enum /*unused*/,
const std::string& /*unused*/)
{}
void AddConsoleSink(level::level_enum /*unused*/, const std::string& /*unused*/) {}
void ClearLoggingSinks(const std::string& /*unused*/) {}
void FlushOnLoggingLevel(level::level_enum /*unused*/, const std::string& /*unused*/) {}
} //namespace ngcore
#endif // NETGEN_USE_SPDLOG

124
libsrc/core/logging.hpp Normal file
View File

@ -0,0 +1,124 @@
#ifndef NETGEN_CORE_LOGGING_HPP
#define NETGEN_CORE_LOGGING_HPP
#undef NETGEN_USE_SPDLOG
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include "exception.hpp"
#include "ngcore_api.hpp"
#include "utils.hpp"
#ifdef NETGEN_USE_SPDLOG
#include <spdlog/fmt/fmt.h>
#include <spdlog/fmt/ostr.h> // 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
namespace spdlog
{
class logger;
} // namespace spdlog
namespace ngcore
{
namespace level
{
enum level_enum
{
trace = 0,
debug = 1,
info = 2,
warn = 3,
err = 4,
critical = 5,
off = 6
};
} // namespace level
class Logger
{
public:
std::shared_ptr<spdlog::logger> logger;
Logger(std::shared_ptr<spdlog::logger> l) : logger(std::move(l)) {}
void NGCORE_API log( level::level_enum level, std::string && s);
#ifdef NETGEN_USE_SPDLOG
template<typename ... Args>
void log( level::level_enum level, const char* str, Args ... args)
{
log(level, fmt::format(str, args...));
}
#else // NETGEN_USE_SPDLOG
template<typename T>
std::string replace(std::string s, const T & t)
{
auto p0 = s.find_first_of('{');
auto p1 = s.find_first_of('}', p0);
if(p0==std::string::npos || p1==std::string::npos)
throw Exception("invalid format string");
s.replace(p0, p1-p0+1, ToString(t));
return s;
}
std::string log_helper(std::string s)
{
return s;
}
template<typename T>
std::string log_helper(std::string s, const T &t)
{
return replace(s,t);
}
template<typename T, typename ... Args>
std::string log_helper( std::string s, const T &t, Args ... args)
{
return log_helper(replace(s,t), args...);
}
template<typename ... Args>
void log( level::level_enum level, const char* str, Args ... args)
{
log(level, log_helper(std::string(str), args...));
}
#endif // NETGEN_USE_SPDLOG
template<typename ... Args>
void trace( const char* str, Args ... args) { log(level::level_enum::trace, str, args...); }
template<typename ... Args>
void debug( const char* str, Args ... args) { log(level::level_enum::debug, str, args...); }
template<typename ... Args>
void info( const char* str, Args ... args) { log(level::level_enum::info, str, args...); }
template<typename ... Args>
void warn( const char* str, Args ... args) { log(level::level_enum::warn, str, args...); }
template<typename ... Args>
void error( const char* str, Args ... args) { log(level::level_enum::err, str, args...); }
template<typename ... Args>
void critical( const char* str, Args ... args) { log(level::level_enum::critical, str, args...); }
};
NGCORE_API std::shared_ptr<Logger> GetLogger(const std::string& name);
NGCORE_API void SetLoggingLevel(level::level_enum level, const std::string& name);
NGCORE_API void AddFileSink(const std::string& filename, level::level_enum level, const std::string& logger);
NGCORE_API void AddConsoleSink(level::level_enum level, const std::string& logger);
NGCORE_API void ClearLoggingSinks(const std::string& logger);
NGCORE_API void FlushOnLoggingLevel(level::level_enum level, const std::string& logger);
} // namespace ngcore
#endif // NETGEN_CORE_LOGGING_HPP

View File

@ -2,6 +2,10 @@
#define NETGEN_CORE_NGCORE_HPP #define NETGEN_CORE_NGCORE_HPP
#include "archive.hpp" #include "archive.hpp"
#include "exception.hpp"
#include "logging.hpp"
#include "profiler.hpp"
#include "symboltable.hpp"
#include "version.hpp" #include "version.hpp"
#endif // NETGEN_CORE_NGCORE_HPP #endif // NETGEN_CORE_NGCORE_HPP

View File

@ -5,8 +5,8 @@
#define NGCORE_API_EXPORT __declspec(dllexport) #define NGCORE_API_EXPORT __declspec(dllexport)
#define NGCORE_API_IMPORT __declspec(dllimport) #define NGCORE_API_IMPORT __declspec(dllimport)
#else #else
#define NGCORE_API_EXPORT #define NGCORE_API_EXPORT __attribute__((visibility("default")))
#define NGCORE_API_IMPORT #define NGCORE_API_IMPORT __attribute__((visibility("default")))
#endif #endif
#ifdef NGCORE_EXPORTS #ifdef NGCORE_EXPORTS
@ -15,15 +15,23 @@
#define NGCORE_API NGCORE_API_IMPORT #define NGCORE_API NGCORE_API_IMPORT
#endif #endif
namespace ngcore #ifdef __INTEL_COMPILER
{ #ifdef WIN32
#if defined(__GNUC__) #define NETGEN_INLINE __forceinline inline
inline bool likely (bool x) { return bool(__builtin_expect(long(x), 1L)); } #define NETGEN_LAMBDA_INLINE
inline bool unlikely (bool x) { return bool(__builtin_expect(long(x), 0L)); } #else
#define NETGEN_INLINE __forceinline inline
#define NETGEN_LAMBDA_INLINE __attribute__ ((__always_inline__))
#endif
#else #else
inline bool likely (bool x) { return x; } #ifdef __GNUC__
inline bool unlikely (bool x) { return x; } #define NETGEN_INLINE __attribute__ ((__always_inline__)) inline
#define NETGEN_LAMBDA_INLINE __attribute__ ((__always_inline__))
#define NETGEN_VLA
#else
#define NETGEN_INLINE inline
#define NETGEN_LAMBDA_INLINE
#endif
#endif #endif
} // namespace ngcore
#endif // NETGEN_CORE_NGCORE_API_HPP #endif // NETGEN_CORE_NGCORE_API_HPP

667
libsrc/core/paje_trace.cpp Normal file
View File

@ -0,0 +1,667 @@
#include <algorithm>
#include <atomic>
#include <iostream>
#include <map>
#include <set>
#include <thread>
#include "archive.hpp" // for Demangle
#include "paje_trace.hpp"
#include "profiler.hpp"
extern const char *header;
namespace ngcore
{
// Produce no traces by default
size_t PajeTrace::max_tracefile_size = 0;
// If true, produce variable counting active threads
// increases trace by a factor of two
bool PajeTrace::trace_thread_counter = true;
bool PajeTrace::trace_threads = true;
PajeTrace :: PajeTrace(int anthreads, std::string aname)
{
start_time = GetTimeCounter();
nthreads = anthreads;
tracefile_name = std::move(aname);
int bytes_per_event=33;
max_num_events_per_thread = std::min( static_cast<size_t>(std::numeric_limits<int>::max()), max_tracefile_size/bytes_per_event/(2*nthreads+1)*10/7);
if(max_num_events_per_thread>0)
{
logger->info( "Tracefile size = {}MB", max_tracefile_size/1024/1024);
logger->info( "Tracing {} events per thread", max_num_events_per_thread);
}
tasks.resize(nthreads);
int reserve_size = std::min(1000000U, max_num_events_per_thread);
for(auto & t : tasks)
t.reserve(reserve_size);
links.resize(nthreads);
for(auto & l : links)
l.reserve(reserve_size);
jobs.reserve(reserve_size);
timer_events.reserve(reserve_size);
tracing_enabled = true;
}
PajeTrace :: ~PajeTrace()
{
if(!tracefile_name.empty())
Write(tracefile_name);
}
void PajeTrace::StopTracing()
{
if(tracing_enabled && max_num_events_per_thread>0)
{
logger->warn("Maximum number of traces reached, tracing is stopped now.");
}
tracing_enabled = false;
}
class PajeFile
{
public:
static void Hue2RGB ( double x, double &r, double &g, double &b )
{
double d = 1.0/6.0;
if(x<d)
r=1, g=6*x,b=0;
else if (x<2*d)
r=1.0-6*(x-d),g=1,b=0;
else if (x<3*d)
r=0, g=1,b=6*(x-2*d);
else if (x<4*d)
r=0, g=1-6*(x-3*d),b=1;
else if (x<5*d)
r=6*(x-4*d), g=0,b=1;
else
r=1, g=0,b=1-5*(x-d);
};
int alias_counter;
FILE * ctrace_stream;
TTimePoint start_time;
std::shared_ptr<Logger> logger = GetLogger("PajeTrace");
double ConvertTime(TTimePoint t) {
// return time in milliseconds as double
// return std::chrono::duration<double>(t-start_time).count()*1000.0;
// return std::chrono::duration<double>(t-start_time).count() / 2.7e3;
return (t-start_time) / 2.7e6;
}
enum PType
{
SET_VARIABLE=1,
ADD_VARIABLE,
SUB_VARIABLE,
PUSH_STATE,
POP_STATE,
START_LINK,
STOP_LINK
};
struct PajeEvent
{
PajeEvent( int aevent_type, double atime, int atype, int acontainer, double avar_value )
: time(atime), var_value(avar_value), event_type(aevent_type), type(atype), container(acontainer)
{ }
PajeEvent( int aevent_type, double atime, int atype, int acontainer, int avalue = 0, int aid = 0, bool avalue_is_alias = true )
: time(atime), event_type(aevent_type), type(atype), container(acontainer), value(avalue), id(aid), value_is_alias(avalue_is_alias)
{ }
PajeEvent( int aevent_type, double atime, int atype, int acontainer, int avalue, int astart_container, int akey )
: time(atime), event_type(aevent_type), type(atype), container(acontainer), value(avalue), start_container(astart_container), id(akey)
{ }
double time;
double var_value = 0.0;
int event_type;
int type;
int container;
int value = 0;
int start_container = 0;
int id = 0;
bool value_is_alias = true;
bool operator < (const PajeEvent & other) const {
// Same start and stop times can occur for very small tasks -> take "starting" events first (eg. PajePushState before PajePopState)
if(time == other.time)
return event_type < other.event_type;
return (time < other.time);
}
int write(FILE *stream)
{
const int &key = id;
const int &end_container = start_container;
switch(event_type)
{
case PajeSetVariable:
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%.15g\n", PajeSetVariable, time, type, container, var_value ); // NOLINT
case PajeAddVariable:
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%.15g\n", PajeAddVariable, time, type, container, var_value ); // NOLINT
case PajeSubVariable:
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%.15g\n", PajeSubVariable, time, type, container, var_value ); // NOLINT
case PajePushState:
if(value_is_alias)
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\ta%d\t%d\n", PajePushState, time, type, container, value, id); // NOLINT
else
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%d\t%d\n", PajePushState, time, type, container, value, id); // NOLINT
case PajePopState:
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\n", PajePopState, time, type, container ); // NOLINT
case PajeStartLink:
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%d\ta%d\t%d\n", PajeStartLink, time, type, container, value, start_container, key ); // NOLINT
case PajeEndLink:
return fprintf( stream, "%d\t%.15g\ta%d\ta%d\t%d\ta%d\t%d\n", PajeEndLink, time, type, container, value, end_container, key ); // NOLINT
}
return 0;
}
};
std::vector<PajeEvent> events;
public:
PajeFile() = delete;
PajeFile(const PajeFile &) = delete;
PajeFile(PajeFile &&) = delete;
void operator=(const PajeFile &) = delete;
void operator=(PajeFile &&) = delete;
PajeFile( const std::string & filename, TTimePoint astart_time )
{
start_time = astart_time;
ctrace_stream = fopen (filename.c_str(),"w"); // NOLINT
fprintf(ctrace_stream, "%s", header ); // NOLINT
alias_counter = 0;
}
~PajeFile()
{
fclose (ctrace_stream); // NOLINT
}
int DefineContainerType ( int parent_type, const std::string & name )
{
int alias = ++alias_counter;
if(parent_type!=0)
fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\n", PajeDefineContainerType, alias, parent_type, name.c_str() ); // NOLINT
else
fprintf( ctrace_stream, "%d\ta%d\t%d\t\"%s\"\n", PajeDefineContainerType, alias, parent_type, name.c_str() ); // NOLINT
return alias;
}
int DefineVariableType ( int container_type, const std::string & name )
{
int alias = ++alias_counter;
fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\t\"1.0 1.0 1.0\"\n", PajeDefineVariableType, alias, container_type, name.c_str() ); // NOLINT
return alias;
}
int DefineStateType ( int type, const std::string & name )
{
int alias = ++alias_counter;
fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\n", PajeDefineStateType, alias, type, name.c_str() ); // NOLINT
return alias;
}
// int DefineEventType ()
// {
// Write("event not implemented");
// }
int DefineLinkType (int parent_container_type, int start_container_type, int stop_container_type, const std::string & name)
{
int alias = ++alias_counter;
fprintf( ctrace_stream, "%d\ta%d\ta%d\ta%d\ta%d\t\"%s\"\n", PajeDefineLinkType, alias, parent_container_type, start_container_type, stop_container_type, name.c_str() ); // NOLINT
return alias;
}
int DefineEntityValue (int type, const std::string & name, double hue = -1)
{
if(hue==-1)
{
std::hash<std::string> shash;
size_t h = shash(name);
h ^= h>>32U;
h = static_cast<uint32_t>(h);
hue = h*1.0/std::numeric_limits<uint32_t>::max();
}
int alias = ++alias_counter;
double r,g,b;
Hue2RGB( hue, r, g, b );
fprintf( ctrace_stream, "%d\ta%d\ta%d\t\"%s\"\t\"%.15g %.15g %.15g\"\n", PajeDefineEntityValue, alias, type, name.c_str(), r,g,b ); // NOLINT
return alias;
}
int CreateContainer ( int type, int parent, const std::string & name )
{
int alias = ++alias_counter;
if(parent!=0)
fprintf( ctrace_stream, "%d\t0\ta%d\ta%d\ta%d\t\"%s\"\n", PajeCreateContainer, alias, type, parent, name.c_str() ); // NOLINT
else
fprintf( ctrace_stream, "%d\t0\ta%d\ta%d\t%d\t\"%s\"\n", PajeCreateContainer, alias, type, parent, name.c_str() ); // NOLINT
return alias;
}
void DestroyContainer ()
{}
void SetVariable (TTimePoint time, int type, int container, double value )
{
events.emplace_back( PajeEvent( PajeSetVariable, ConvertTime(time), type, container, value ) );
}
void AddVariable (TTimePoint time, int type, int container, double value )
{
events.emplace_back( PajeEvent( PajeAddVariable, ConvertTime(time), type, container, value ) );
}
void SubVariable (TTimePoint time, int type, int container, double value )
{
events.emplace_back( PajeEvent( PajeSubVariable, ConvertTime(time), type, container, value ) );
}
void SetState ()
{}
void PushState ( TTimePoint time, int type, int container, int value, int id = 0, bool value_is_alias = true )
{
events.emplace_back( PajeEvent( PajePushState, ConvertTime(time), type, container, value, id, value_is_alias) );
}
void PopState ( TTimePoint time, int type, int container )
{
events.emplace_back( PajeEvent( PajePopState, ConvertTime(time), type, container ) );
}
void ResetState ()
{}
void StartLink ( TTimePoint time, int type, int container, int value, int start_container, int key )
{
events.emplace_back( PajeEvent( PajeStartLink, ConvertTime(time), type, container, value, start_container, key ) );
}
void EndLink ( TTimePoint time, int type, int container, int value, int end_container, int key )
{
events.emplace_back( PajeEvent( PajeEndLink, ConvertTime(time), type, container, value, end_container, key ) );
}
void NewEvent ()
{}
void WriteEvents()
{
logger->info("Sorting traces...");
std::sort (events.begin(), events.end());
logger->info("Writing traces... ");
for (auto & event : events)
{
event.write( ctrace_stream );
// fprintf( ctrace_stream, "%s", buf ); // NOLINT
}
logger->info("Done");
}
private:
enum
{
PajeDefineContainerType = 0,
PajeDefineVariableType = 1,
PajeDefineStateType = 2,
PajeDefineEventType = 3,
PajeDefineLinkType = 4,
PajeDefineEntityValue = 5,
PajeCreateContainer = 6,
PajeDestroyContainer = 7,
PajeSetVariable = 8,
PajeAddVariable = 9,
PajeSubVariable = 10,
PajeSetState = 11,
PajePushState = 12,
PajePopState = 13,
PajeResetState = 14,
PajeStartLink = 15,
PajeEndLink = 16,
PajeNewEvent = 17
};
};
NGCORE_API PajeTrace *trace;
void PajeTrace::Write( const std::string & filename )
{
int n_events = jobs.size() + timer_events.size();
for(auto & vtasks : tasks)
n_events += vtasks.size();
logger->info("{} events traced", n_events);
if(n_events==0)
{
logger->info("No data traced, skip writing trace file");
return;
}
if(!tracing_enabled)
{
logger->warn("Tracing stopped during computation due to tracefile size limit of {} megabytes.", max_tracefile_size/1024/1024);
}
PajeFile paje(filename, start_time);
const int container_type_task_manager = paje.DefineContainerType( 0, "Task Manager" );
const int container_type_node = paje.DefineContainerType( container_type_task_manager, "Node");
const int container_type_thread = paje.DefineContainerType( container_type_task_manager, "Thread");
const int container_type_timer = container_type_thread; //paje.DefineContainerType( container_type_task_manager, "Timers");
const int container_type_jobs = paje.DefineContainerType( container_type_task_manager, "Jobs");
const int state_type_job = paje.DefineStateType( container_type_jobs, "Job" );
const int state_type_task = paje.DefineStateType( container_type_thread, "Task" );
const int state_type_timer = paje.DefineStateType( container_type_timer, "Timer state" );
const int variable_type_active_threads = paje.DefineVariableType( container_type_jobs, "Active threads" );
const int container_task_manager = paje.CreateContainer( container_type_task_manager, 0, "The task manager" );
const int container_jobs = paje.CreateContainer( container_type_jobs, container_task_manager, "Jobs" );
paje.SetVariable( start_time, variable_type_active_threads, container_jobs, 0.0 );
const int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1;
std::vector<int> container_nodes;
container_nodes.reserve(num_nodes);
for(int i=0; i<num_nodes; i++)
container_nodes.emplace_back( paje.CreateContainer( container_type_node, container_task_manager, "Node " + ToString(i)) );
std::vector <int> thread_aliases;
thread_aliases.reserve(nthreads);
if(trace_threads)
for (int i=0; i<nthreads; i++)
{
auto name = "Timer level " + ToString(i);
thread_aliases.emplace_back( paje.CreateContainer( container_type_thread, container_nodes[i*num_nodes/nthreads], name ) );
}
std::map<const std::type_info *, int> job_map;
std::map<const std::type_info *, int> job_task_map;
for(Job & j : jobs)
if(job_map.find(j.type) == job_map.end())
{
std::string name = Demangle(j.type->name());
job_map[j.type] = paje.DefineEntityValue( state_type_job, name, -1 );
job_task_map[j.type] = paje.DefineEntityValue( state_type_task, name, -1 );
}
for(Job & j : jobs)
{
paje.PushState( j.start_time, state_type_job, container_jobs, job_map[j.type] );
paje.PopState( j.stop_time, state_type_job, container_jobs );
}
std::set<int> timer_ids;
std::map<int,int> timer_aliases;
for(auto & event : timer_events)
timer_ids.insert(event.timer_id);
for(auto & vtasks : tasks)
for (Task & t : vtasks)
if(t.id_type==Task::ID_TIMER)
timer_ids.insert(t.id);
for(auto id : timer_ids)
timer_aliases[id] = paje.DefineEntityValue( state_type_timer, NgProfiler::GetName(id), -1 );
int timerdepth = 0;
int maxdepth = 0;
for(auto & event : timer_events)
{
if(event.is_start)
{
timerdepth++;
maxdepth = timerdepth>maxdepth ? timerdepth : maxdepth;
}
else
timerdepth--;
}
std::vector<int> timer_container_aliases;
timer_container_aliases.resize(maxdepth);
for(int i=0; i<maxdepth; i++)
{
auto name = "Timer level " + ToString(i);
timer_container_aliases[i] = paje.CreateContainer( container_type_timer, container_task_manager, name );
}
timerdepth = 0;
for(auto & event : timer_events)
{
if(event.is_start)
paje.PushState( event.time, state_type_timer, timer_container_aliases[timerdepth++], timer_aliases[event.timer_id] );
else
paje.PopState( event.time, state_type_timer, timer_container_aliases[--timerdepth] );
}
for(auto & vtasks : tasks)
{
for (Task & t : vtasks) {
int value_id = t.id;
switch(t.id_type)
{
case Task::ID_JOB:
value_id = job_task_map[jobs[t.id-1].type];
if(trace_thread_counter)
{
paje.AddVariable( t.start_time, variable_type_active_threads, container_jobs, 1.0 );
paje.SubVariable( t.stop_time, variable_type_active_threads, container_jobs, 1.0 );
}
if(trace_threads)
{
paje.PushState( t.start_time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, true );
paje.PopState( t.stop_time, state_type_task, thread_aliases[t.thread_id] );
}
break;
case Task::ID_TIMER:
value_id = timer_aliases[t.id];
paje.PushState( t.start_time, state_type_timer, thread_aliases[t.thread_id], value_id, t.additional_value, true );
paje.PopState( t.stop_time, state_type_timer, thread_aliases[t.thread_id] );
break;
default:
paje.PushState( t.start_time, state_type_task, thread_aliases[t.thread_id], value_id, t.additional_value, false );
paje.PopState( t.stop_time, state_type_task, thread_aliases[t.thread_id] );
break;
}
}
}
// Merge link event
int nlinks = 0;
for( auto & l : links)
nlinks += l.size();
std::vector<ThreadLink> links_merged;
links_merged.reserve(nlinks);
std::vector<unsigned int> pos(nthreads);
int nlinks_merged = 0;
while(nlinks_merged < nlinks)
{
int minpos = -1;
TTimePoint mintime = -1;
for (int t = 0; t<nthreads; t++)
{
if(pos[t] < links[t].size() && (minpos==-1 || links[t][pos[t]].time < mintime))
{
minpos = t;
mintime = links[t][pos[t]].time;
}
}
links_merged.push_back( links[minpos][pos[minpos]] );
pos[minpos]++;
nlinks_merged++;
}
std::vector<ThreadLink> started_links;
int link_type = paje.DefineLinkType(container_type_node, container_type_thread, container_type_thread, "links");
// match links
for ( auto & l : links_merged )
{
if(l.is_start)
{
started_links.push_back(l);
}
else
{
unsigned int i = 0;
while(i<started_links.size())
{
while(i<started_links.size() && started_links[i].key == l.key)
{
ThreadLink & sl = started_links[i];
// Avoid links on same thread
if(sl.thread_id != l.thread_id)
{
paje.StartLink( sl.time, link_type, container_nodes[sl.thread_id*num_nodes/nthreads], l.key, thread_aliases[sl.thread_id], l.key);
paje.EndLink( l.time, link_type, container_nodes[l.thread_id*num_nodes/nthreads], l.key, thread_aliases[l.thread_id], l.key);
}
started_links.erase(started_links.begin()+i);
}
i++;
}
}
}
paje.WriteEvents();
}
} // namespace ngcore
const char *header =
"%EventDef PajeDefineContainerType 0 \n"
"% Alias string \n"
"% Type string \n"
"% Name string \n"
"%EndEventDef \n"
"%EventDef PajeDefineVariableType 1 \n"
"% Alias string \n"
"% Type string \n"
"% Name string \n"
"% Color color \n"
"%EndEventDef \n"
"%EventDef PajeDefineStateType 2 \n"
"% Alias string \n"
"% Type string \n"
"% Name string \n"
"%EndEventDef \n"
"%EventDef PajeDefineEventType 3 \n"
"% Alias string \n"
"% Type string \n"
"% Name string \n"
"% Color color \n"
"%EndEventDef \n"
"%EventDef PajeDefineLinkType 4 \n"
"% Alias string \n"
"% Type string \n"
"% StartContainerType string \n"
"% EndContainerType string \n"
"% Name string \n"
"%EndEventDef \n"
"%EventDef PajeDefineEntityValue 5 \n"
"% Alias string \n"
"% Type string \n"
"% Name string \n"
"% Color color \n"
"%EndEventDef \n"
"%EventDef PajeCreateContainer 6 \n"
"% Time date \n"
"% Alias string \n"
"% Type string \n"
"% Container string \n"
"% Name string \n"
"%EndEventDef \n"
"%EventDef PajeDestroyContainer 7 \n"
"% Time date \n"
"% Type string \n"
"% Name string \n"
"%EndEventDef \n"
"%EventDef PajeSetVariable 8 \n"
"% Time date \n"
"% Type string \n"
"% Container string \n"
"% Value double \n"
"%EndEventDef\n"
"%EventDef PajeAddVariable 9 \n"
"% Time date \n"
"% Type string \n"
"% Container string \n"
"% Value double \n"
"%EndEventDef\n"
"%EventDef PajeSubVariable 10 \n"
"% Time date \n"
"% Type string \n"
"% Container string \n"
"% Value double \n"
"%EndEventDef\n"
"%EventDef PajeSetState 11 \n"
"% Time date \n"
"% Type string \n"
"% Container string \n"
"% Value string \n"
"%EndEventDef\n"
"%EventDef PajePushState 12 \n"
"% Time date \n"
"% Type string \n"
"% Container string \n"
"% Value string \n"
"% Id string \n"
"%EndEventDef\n"
"%EventDef PajePopState 13 \n"
"% Time date \n"
"% Type string \n"
"% Container string \n"
"%EndEventDef\n"
"%EventDef PajeResetState 14 \n"
"% Time date \n"
"% Type string \n"
"% Container string \n"
"%EndEventDef\n"
"%EventDef PajeStartLink 15 \n"
"% Time date \n"
"% Type string \n"
"% Container string \n"
"% Value string \n"
"% StartContainer string \n"
"% Key string \n"
"%EndEventDef\n"
"%EventDef PajeEndLink 16 \n"
"% Time date \n"
"% Type string \n"
"% Container string \n"
"% Value string \n"
"% EndContainer string \n"
"% Key string \n"
"%EndEventDef\n"
"%EventDef PajeNewEvent 17 \n"
"% Time date \n"
"% Type string \n"
"% Container string \n"
"% Value string \n"
"%EndEventDef\n";

190
libsrc/core/paje_trace.hpp Normal file
View File

@ -0,0 +1,190 @@
#ifndef NETGEN_CORE_PAJE_TRACE_HPP
#define NETGEN_CORE_PAJE_TRACE_HPP
#include <limits>
#include <vector>
#include "logging.hpp" // for logger
#include "ngcore_api.hpp" // for NGCORE_API
#include "utils.hpp"
namespace ngcore
{
extern NGCORE_API class PajeTrace *trace;
class PajeTrace
{
public:
using TClock = std::chrono::system_clock;
protected:
std::shared_ptr<Logger> logger = GetLogger("PajeTrace");
private:
NGCORE_API static size_t max_tracefile_size;
NGCORE_API static bool trace_thread_counter;
NGCORE_API static bool trace_threads;
bool tracing_enabled;
TTimePoint start_time;
int nthreads;
public:
// Approximate number of events to trace. Tracing will
// be stopped if any thread reaches this number of events
unsigned int max_num_events_per_thread;
static void SetTraceThreads( bool atrace_threads )
{
trace_threads = atrace_threads;
}
static void SetTraceThreadCounter( bool trace_threads )
{
trace_thread_counter = trace_threads;
}
static void SetMaxTracefileSize( size_t max_size )
{
max_tracefile_size = max_size;
}
std::string tracefile_name;
struct Job
{
int job_id;
const std::type_info *type;
TTimePoint start_time;
TTimePoint stop_time;
};
struct Task
{
int thread_id;
int id;
int id_type;
int additional_value;
TTimePoint start_time;
TTimePoint stop_time;
static constexpr int ID_NONE = -1;
static constexpr int ID_JOB = 1;
static constexpr int ID_TIMER = 2;
};
struct TimerEvent
{
int timer_id;
TTimePoint time;
bool is_start;
int thread_id;
bool operator < (const TimerEvent & other) const { return time < other.time; }
};
struct ThreadLink
{
int thread_id;
int key;
TTimePoint time;
bool is_start;
bool operator < (const ThreadLink & other) const { return time < other.time; }
};
std::vector<std::vector<Task> > tasks;
std::vector<Job> jobs;
std::vector<TimerEvent> timer_events;
std::vector<std::vector<ThreadLink> > links;
public:
NGCORE_API void StopTracing();
PajeTrace() = delete;
PajeTrace(const PajeTrace &) = delete;
PajeTrace(PajeTrace &&) = delete;
NGCORE_API PajeTrace(int anthreads, std::string aname = "");
NGCORE_API ~PajeTrace();
void operator=(const PajeTrace &) = delete;
void operator=(PajeTrace &&) = delete;
void StartTimer(int timer_id)
{
if(!tracing_enabled) return;
if(unlikely(timer_events.size() == max_num_events_per_thread))
StopTracing();
timer_events.push_back(TimerEvent{timer_id, GetTimeCounter(), true});
}
void StopTimer(int timer_id)
{
if(!tracing_enabled) return;
if(unlikely(timer_events.size() == max_num_events_per_thread))
StopTracing();
timer_events.push_back(TimerEvent{timer_id, GetTimeCounter(), false});
}
NETGEN_INLINE int StartTask(int thread_id, int id, int id_type = Task::ID_NONE, int additional_value = -1)
{
if(!tracing_enabled) return -1;
if(!trace_threads && !trace_thread_counter) return -1;
if(unlikely(tasks[thread_id].size() == max_num_events_per_thread))
StopTracing();
int task_num = tasks[thread_id].size();
tasks[thread_id].push_back( Task{thread_id, id, id_type, additional_value, GetTimeCounter()} );
return task_num;
}
void StopTask(int thread_id, int task_num)
{
if(!trace_threads && !trace_thread_counter) return;
if(task_num>=0)
tasks[thread_id][task_num].stop_time = GetTimeCounter();
}
void SetTask(int thread_id, int task_num, int additional_value) {
if(!trace_threads && !trace_thread_counter) return;
if(task_num>=0)
tasks[thread_id][task_num].additional_value = additional_value;
}
void StartJob(int job_id, const std::type_info & type)
{
if(!tracing_enabled) return;
if(jobs.size() == max_num_events_per_thread)
StopTracing();
jobs.push_back( Job{job_id, &type, GetTimeCounter()} );
}
void StopJob()
{
if(tracing_enabled)
jobs.back().stop_time = GetTimeCounter();
}
void StartLink(int thread_id, int key)
{
if(!tracing_enabled) return;
if(links[thread_id].size() == max_num_events_per_thread)
StopTracing();
links[thread_id].push_back( ThreadLink{thread_id, key, GetTimeCounter(), true} );
}
void StopLink(int thread_id, int key)
{
if(!tracing_enabled) return;
if(links[thread_id].size() == max_num_events_per_thread)
StopTracing();
links[thread_id].push_back( ThreadLink{thread_id, key, GetTimeCounter(), false} );
}
void Write( const std::string & filename );
};
} // namespace ngcore
#endif // NETGEN_CORE_PAJE_TRACE_HPP

117
libsrc/core/profiler.cpp Normal file
View File

@ -0,0 +1,117 @@
#include <mutex>
#include "profiler.hpp"
namespace ngcore
{
std::vector<NgProfiler::TimerVal> NgProfiler::timers(NgProfiler::SIZE); // NOLINT
std::string NgProfiler::filename;
size_t NgProfiler::dummy_thread_times[NgProfiler::SIZE];
size_t * NgProfiler::thread_times = NgProfiler::dummy_thread_times; // NOLINT
size_t NgProfiler::dummy_thread_flops[NgProfiler::SIZE];
size_t * NgProfiler::thread_flops = NgProfiler::dummy_thread_flops; // NOLINT
std::shared_ptr<Logger> NgProfiler::logger = GetLogger("Profiler"); // NOLINT
NgProfiler :: NgProfiler()
{
for (auto & t : timers)
{
t.tottime = 0.0;
t.usedcounter = 0;
t.flops = 0.0;
}
}
NgProfiler :: ~NgProfiler()
{
if (filename.length())
{
logger->debug( "write profile to file {}", filename );
FILE *prof = fopen(filename.c_str(),"w"); // NOLINT
Print (prof);
fclose(prof); // NOLINT
}
if (getenv ("NGPROFILE"))
{
std::string filename = "netgen.prof";
#ifdef PARALLEL
filename += "."+ToString(id);
#endif
if (id == 0) logger->info( "write profile to file {}", filename );
FILE *prof = fopen(filename.c_str(),"w"); // NOLINT
Print (prof);
fclose(prof); // NOLINT
}
}
void NgProfiler :: Print (FILE * prof)
{
int i = 0;
for (auto & t : timers)
{
if (t.count != 0 || t.usedcounter != 0)
{
fprintf(prof,"job %3i calls %8li, time %6.4f sec",i,t.count,t.tottime); // NOLINT
if(t.flops != 0.0)
fprintf(prof,", MFlops = %6.2f",t.flops / (t.tottime) * 1e-6); // NOLINT
if(t.loads != 0.0)
fprintf(prof,", MLoads = %6.2f",t.loads / (t.tottime) * 1e-6); // NOLINT
if(t.stores != 0.0)
fprintf(prof,", MStores = %6.2f",t.stores / (t.tottime) * 1e-6); // NOLINT
if(t.usedcounter)
fprintf(prof," %s",t.name.c_str()); // NOLINT
fprintf(prof,"\n"); // NOLINT
}
i++;
}
}
int NgProfiler :: CreateTimer (const std::string & name)
{
static std::mutex createtimer_mutex;
int nr = -1;
{
std::lock_guard<std::mutex> guard(createtimer_mutex);
for (int i = SIZE-1; i > 0; i--)
{
auto & t = timers[i];
if (!t.usedcounter)
{
t.usedcounter = 1;
t.name = name;
nr = i;
break;
}
}
}
if (nr > -1) return nr;
static bool first_overflow = true;
if (first_overflow)
{
first_overflow = false;
NgProfiler::logger->warn("no more timer available, reusing last one");
}
return 0;
}
void NgProfiler :: Reset ()
{
for(auto & t : timers)
{
t.tottime = 0.0;
t.count = 0;
t.flops = 0.0;
t.loads = 0;
t.stores = 0;
}
}
NgProfiler prof; // NOLINT
} // namespace ngcore

304
libsrc/core/profiler.hpp Normal file
View File

@ -0,0 +1,304 @@
#ifndef NETGEN_CORE_PROFILER_HPP
#define NETGEN_CORE_PROFILER_HPP
#include <chrono>
#include <string>
#include "logging.hpp"
#include "paje_trace.hpp"
#include "utils.hpp"
namespace ngcore
{
class NgProfiler
{
public:
/// maximal number of timers
enum { SIZE = 8*1024 };
struct TimerVal
{
TimerVal() = default;
double tottime = 0.0;
double starttime = 0.0;
double flops = 0.0;
double loads = 0.0;
double stores = 0.0;
long count = 0;
std::string name = "";
int usedcounter = 0;
};
NGCORE_API static std::vector<TimerVal> timers;
NGCORE_API static TTimePoint * thread_times;
NGCORE_API static TTimePoint * thread_flops;
NGCORE_API static std::shared_ptr<Logger> logger;
NGCORE_API static size_t dummy_thread_times[NgProfiler::SIZE];
NGCORE_API static size_t dummy_thread_flops[NgProfiler::SIZE];
private:
NGCORE_API static std::string filename;
public:
NgProfiler();
~NgProfiler();
NgProfiler(const NgProfiler &) = delete;
NgProfiler(NgProfiler &&) = delete;
void operator=(const NgProfiler &) = delete;
void operator=(NgProfiler &&) = delete;
static void SetFileName (const std::string & afilename) { filename = afilename; }
/// create new timer, use integer index
NGCORE_API static int CreateTimer (const std::string & name);
NGCORE_API static void Reset ();
/// start timer of index nr
static void StartTimer (int nr)
{
timers[nr].starttime = WallTime(); timers[nr].count++;
}
/// stop timer of index nr
static void StopTimer (int nr)
{
timers[nr].tottime += WallTime()-timers[nr].starttime;
}
static void StartThreadTimer (size_t nr, size_t tid)
{
thread_times[tid*SIZE+nr] -= GetTimeCounter(); // NOLINT
}
static void StopThreadTimer (size_t nr, size_t tid)
{
thread_times[tid*SIZE+nr] += GetTimeCounter(); // NOLINT
}
static void AddThreadFlops (size_t nr, size_t tid, size_t flops)
{
thread_flops[tid*SIZE+nr] += flops; // NOLINT
}
/// if you know number of flops, provide them to obtain the MFlop - rate
static void AddFlops (int nr, double aflops) { timers[nr].flops += aflops; }
static void AddLoads (int nr, double aloads) { timers[nr].loads += aloads; }
static void AddStores (int nr, double astores) { timers[nr].stores += astores; }
static int GetNr (const std::string & name)
{
for (int i = SIZE-1; i >= 0; i--)
if (timers[i].name == name)
return i;
return -1;
}
static double GetTime (int nr)
{
return timers[nr].tottime;
}
static double GetTime (const std::string & name)
{
for (int i = SIZE-1; i >= 0; i--)
if (timers[i].name == name)
return GetTime (i);
return 0;
}
static long int GetCounts (int nr)
{
return timers[nr].count;
}
static double GetFlops (int nr)
{
return timers[nr].flops;
}
/// change name
static void SetName (int nr, const std::string & name) { timers[nr].name = name; }
static std::string GetName (int nr) { return timers[nr].name; }
/// print profile
NGCORE_API static void Print (FILE * prof);
class RegionTimer
{
int nr;
public:
/// start timer
RegionTimer (int anr) : nr(anr) { NgProfiler::StartTimer(nr); }
/// stop timer
~RegionTimer () { NgProfiler::StopTimer(nr); }
RegionTimer() = delete;
RegionTimer(const RegionTimer &) = delete;
RegionTimer(RegionTimer &&) = delete;
void operator=(const RegionTimer &) = delete;
void operator=(RegionTimer &&) = delete;
};
};
class NGCORE_API Timer
{
int timernr;
int priority;
public:
Timer (const std::string & name, int apriority = 1)
: priority(apriority)
{
timernr = NgProfiler::CreateTimer (name);
}
void SetName (const std::string & name)
{
NgProfiler::SetName (timernr, name);
}
void Start ()
{
if (priority <= 2)
NgProfiler::StartTimer (timernr);
if (priority <= 1)
if(trace) trace->StartTimer(timernr);
}
void Stop ()
{
if (priority <= 2)
NgProfiler::StopTimer (timernr);
if (priority <= 1)
if(trace) trace->StopTimer(timernr);
}
void AddFlops (double aflops)
{
if (priority <= 2)
NgProfiler::AddFlops (timernr, aflops);
}
double GetTime () { return NgProfiler::GetTime(timernr); }
long int GetCounts () { return NgProfiler::GetCounts(timernr); }
double GetMFlops ()
{ return NgProfiler::GetFlops(timernr)
/ NgProfiler::GetTime(timernr) * 1e-6; }
operator int () { return timernr; }
};
/**
Timer object.
Start / stop timer at constructor / destructor.
*/
class RegionTimer
{
Timer & timer;
public:
/// start timer
RegionTimer (Timer & atimer) : timer(atimer) { timer.Start(); }
/// stop timer
~RegionTimer () { timer.Stop(); }
RegionTimer() = delete;
RegionTimer(const RegionTimer &) = delete;
RegionTimer(RegionTimer &&) = delete;
void operator=(const RegionTimer &) = delete;
void operator=(RegionTimer &&) = delete;
};
class ThreadRegionTimer
{
size_t nr;
size_t tid;
public:
/// start timer
ThreadRegionTimer (size_t _nr, size_t _tid) : nr(_nr), tid(_tid)
{ NgProfiler::StartThreadTimer(nr, tid); }
/// stop timer
~ThreadRegionTimer ()
{ NgProfiler::StopThreadTimer(nr, tid); }
ThreadRegionTimer() = delete;
ThreadRegionTimer(ThreadRegionTimer &&) = delete;
ThreadRegionTimer(const ThreadRegionTimer &) = delete;
void operator=(const ThreadRegionTimer &) = delete;
void operator=(ThreadRegionTimer &&) = delete;
};
class RegionTracer
{
int nr;
int thread_id;
public:
static constexpr int ID_JOB = PajeTrace::Task::ID_JOB;
static constexpr int ID_NONE = PajeTrace::Task::ID_NONE;
static constexpr int ID_TIMER = PajeTrace::Task::ID_TIMER;
RegionTracer() = delete;
RegionTracer(RegionTracer &&) = delete;
RegionTracer(const RegionTracer &) = delete;
void operator=(const RegionTracer &) = delete;
void operator=(RegionTracer &&) = delete;
/// start trace
RegionTracer (int athread_id, int region_id, int id_type = ID_NONE, int additional_value = -1 )
: thread_id(athread_id)
{
if (trace)
nr = trace->StartTask (athread_id, region_id, id_type, additional_value);
}
/// start trace with timer
RegionTracer (int athread_id, Timer & timer, int additional_value = -1 )
: thread_id(athread_id)
{
if (trace)
nr = trace->StartTask (athread_id, static_cast<int>(timer), ID_TIMER, additional_value);
}
/// set user defined value
void SetValue( int additional_value )
{
if (trace)
trace->SetTask( thread_id, nr, additional_value );
}
/// stop trace
~RegionTracer ()
{
if (trace)
trace->StopTask (thread_id, nr);
}
};
// Helper function for timings
// Run f() at least min_iterations times until max_time seconds elapsed
// returns minimum runtime for a call of f()
template<typename TFunc>
double RunTiming( TFunc f, double max_time = 0.5, int min_iterations = 10 )
{
// Make sure the whole test run does not exceed maxtime
double tend = WallTime()+max_time;
// warmup
f();
double tres = std::numeric_limits<double>::max();
int iteration = 0;
while(WallTime()<tend || iteration++ < min_iterations)
{
double t = -WallTime();
f();
t += WallTime();
tres = std::min(tres, t);
}
return tres;
}
} // namespace ngcore
#endif // NETGEN_CORE_PROFILER_HPP

View File

@ -0,0 +1,30 @@
#include <pybind11/pybind11.h>
#include "logging.hpp"
namespace py = pybind11;
using namespace ngcore;
PYBIND11_MODULE(pyngcore, m) // NOLINT
{
py::enum_<level::level_enum>(m, "LOG_LEVEL", "Logging level")
.value("Trace", level::trace)
.value("Debug", level::debug)
.value("Info", level::info)
.value("Warn", level::warn)
.value("Error", level::err)
.value("Critical", level::critical)
.value("Off", level::off);
m.def("SetLoggingLevel", &SetLoggingLevel, py::arg("level"), py::arg("logger")="",
"Set logging level, if name is given only to the specific logger, else set the global logging level");
m.def("AddFileSink", &AddFileSink, py::arg("filename"), py::arg("level"), py::arg("logger")="",
"Add File sink, either only to logger specified or globally to all loggers");
m.def("AddConsoleSink", &AddConsoleSink, py::arg("level"), py::arg("logger")="",
"Add console output for specific logger or all if none given");
m.def("ClearLoggingSinks", &ClearLoggingSinks, py::arg("logger")="",
"Clear sinks of specific logger, or all if none given");
m.def("FlushOnLoggingLevel", &FlushOnLoggingLevel, py::arg("level"), py::arg("logger")="",
"Flush every message with level at least `level` for specific logger or all loggers if none given.");
}

144
libsrc/core/symboltable.hpp Normal file
View File

@ -0,0 +1,144 @@
#ifndef NETGEN_CORE_SYMBOLTABLE_HPP
#define NETGEN_CORE_SYMBOLTABLE_HPP
#include <ostream>
#include <string>
#include <vector>
#include "archive.hpp"
#include "exception.hpp"
#include "ngcore_api.hpp"
namespace ngcore
{
/**
A symbol table.
The symboltable provides a mapping from string identifiers
to the generic type T. The strings are copied.
Complexity by name access is linear, by index is constant.
*/
template <class T>
class SymbolTable
{
std::vector<std::string> names;
std::vector<T> data;
public:
using value_type = T;
using reference = typename std::vector<T>::reference;
using const_reference = typename std::vector<T>::const_reference;
/// Creates a symboltable
SymbolTable () = default;
SymbolTable (const SymbolTable<T> &) = default;
SymbolTable (SymbolTable<T> &&) noexcept = default;
~SymbolTable() = default;
SymbolTable& operator=(const SymbolTable<T>&) = default;
SymbolTable& operator=(SymbolTable<T>&&) = default;
template<typename T2=T>
auto DoArchive(Archive& ar) -> typename std::enable_if<is_archivable<T2>, void>::type
{
ar & names & data;
}
/// INDEX of symbol name, throws exception if unused
size_t Index (const std::string & name) const
{
for (size_t i = 0; i < names.size(); i++)
if (names[i] == name) return i;
throw RangeException("SymbolTable", name);
}
/// Index of symbol name, returns -1 if unused
int CheckIndex (const std::string & name) const
{
for (int i = 0; i < names.size(); i++)
if (names[i] == name) return i;
return -1;
}
/// number of identifiers
size_t Size() const
{
return data.size();
}
/// Returns reference to element. exception for unused identifier
reference operator[] (const std::string & name)
{
return data[Index (name)];
}
const_reference operator[] (const std::string & name) const
{
return data[Index (name)];
}
/// Returns reference to i-th element, range check only in debug build
reference operator[] (size_t i)
{
NETGEN_CHECK_RANGE(i, 0, data.size());
return data[i];
}
/// Returns const reference to i-th element, range check only in debug build
const_reference operator[] (size_t i) const
{
NETGEN_CHECK_RANGE(i, 0, data.size());
return data[i];
}
/// Returns name of i-th element, range check only in debug build
const std::string & GetName (size_t i) const
{
NETGEN_CHECK_RANGE(i, 0, names.size());
return names[i];
}
/// Associates el to the string name, overrides if name is used
void Set (const std::string & name, const T & el)
{
int i = CheckIndex (name);
if (i >= 0)
data[i] = el;
else
{
data.push_back(el);
names.push_back(name);
}
}
bool Used (const std::string & name) const
{
return CheckIndex(name) >= 0;
}
/// Deletes symboltable
inline void DeleteAll ()
{
names.clear();
data.clear();
}
// Adds all elements from other symboltable
SymbolTable<T>& Update(const SymbolTable<T>& tbl2)
{
for (size_t i = 0; i < tbl2.Size(); i++)
Set (tbl2.GetName(i), tbl2[i]);
return *this;
}
};
template <typename T>
std::ostream & operator<< (std::ostream & ost, const SymbolTable<T> & st)
{
for (int i = 0; i < st.Size(); i++)
ost << st.GetName(i) << " : " << st[i] << std::endl;
return ost;
}
} // namespace ngcore
#endif // NETGEN_CORE_SYMBOLTABLE_HPP

42
libsrc/core/utils.cpp Normal file
View File

@ -0,0 +1,42 @@
#include "utils.hpp"
#include "logging.hpp"
#ifndef WIN32
#include <cxxabi.h>
#endif
#include <iostream>
namespace ngcore
{
// parallel netgen
int id = 0, ntasks = 1;
#ifdef WIN32
// windows does demangling in typeid(T).name()
NGCORE_API std::string Demangle(const char* typeinfo) { return typeinfo; }
#else
NGCORE_API std::string Demangle(const char* typeinfo) { int status; return abi::__cxa_demangle(typeinfo,
nullptr,
nullptr,
&status); }
#endif
double ticks_per_second = [] () noexcept
{
auto tick_start = GetTimeCounter();
double tstart = WallTime();
double tend = WallTime()+0.001;
// wait for 1ms and compare wall time with time counter
while(WallTime()<tend);
auto tick_end = GetTimeCounter();
tend = WallTime();
return (tick_end-tick_start)/(tend-tstart);
}();
const std::chrono::time_point<TClock> wall_time_start = TClock::now();
} // namespace ngcore

70
libsrc/core/utils.hpp Normal file
View File

@ -0,0 +1,70 @@
#ifndef NETGEN_CORE_UTILS_HPP
#define NETGEN_CORE_UTILS_HPP
#include <chrono>
#include <map>
#include <ostream>
#include <sstream>
#include <string>
#ifdef WIN32
#include <intrin.h> // for __rdtsc() CPU time step counter
#else
#include <x86intrin.h> // for __rdtsc() CPU time step counter
#endif // WIN32
#include "ngcore_api.hpp" // for NGCORE_API
namespace ngcore
{
// MPI rank, nranks TODO: Rename
extern NGCORE_API int id, ntasks;
NGCORE_API std::string Demangle(const char* typeinfo);
#if defined(__GNUC__)
inline bool likely (bool x) { return bool(__builtin_expect(long(x), 1L)); }
inline bool unlikely (bool x) { return bool(__builtin_expect(long(x), 0L)); }
#else
inline bool likely (bool x) { return x; }
inline bool unlikely (bool x) { return x; }
#endif
using TClock = std::chrono::system_clock;
extern NGCORE_API const std::chrono::time_point<TClock> wall_time_start;
// Time in seconds since program start
inline double WallTime () noexcept
{
std::chrono::time_point<TClock> now = TClock::now();
std::chrono::duration<double> elapsed_seconds = now-wall_time_start;
return elapsed_seconds.count();
}
// High precision clock counter register
using TTimePoint = size_t;
extern NGCORE_API double ticks_per_second;
inline TTimePoint GetTimeCounter() noexcept
{
return TTimePoint(__rdtsc());
}
template <class T>
inline std::string ToString (const T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
template<typename T1, typename T2>
std::ostream& operator << (std::ostream& ost, const std::map<T1,T2>& map)
{
for(auto& val : map)
ost << "\n" << val.first << ": " << val.second;
return ost;
}
} // namespace ngcore
#endif // NETGEN_CORE_UTILS_HPP

View File

@ -1,6 +1,7 @@
#ifndef NETGEN_CORE_VERSION_HPP #ifndef NETGEN_CORE_VERSION_HPP
#define NETGEN_CORE_VERSION_HPP #define NETGEN_CORE_VERSION_HPP
#include <ostream>
#include <string> #include <string>
#include <tuple> #include <tuple>
@ -83,6 +84,11 @@ namespace ngcore
bool operator <=(const VersionInfo& other) const { return !((*this) > other); } bool operator <=(const VersionInfo& other) const { return !((*this) > other); }
bool operator >=(const VersionInfo& other) const { return !((*this) < other); } bool operator >=(const VersionInfo& other) const { return !((*this) < other); }
}; };
inline std::ostream& operator << (std::ostream& ost, const VersionInfo& version)
{
return ost << version.to_string();
}
} // namespace ngcore } // namespace ngcore
#endif // NETGEN_CORE_VERSION_HPP #endif // NETGEN_CORE_VERSION_HPP

View File

@ -11,12 +11,10 @@ if(APPLE)
set_target_properties( csg PROPERTIES SUFFIX ".so") set_target_properties( csg PROPERTIES SUFFIX ".so")
endif(APPLE) endif(APPLE)
if(NOT WIN32) target_link_libraries(csg PUBLIC mesh ${PYTHON_LIBRARIES})
target_link_libraries(csg mesh ${PYTHON_LIBRARIES}) install( TARGETS csg ${NG_INSTALL_DIR})
target_link_libraries(csg ${PYTHON_LIBRARIES})
install( TARGETS csg ${NG_INSTALL_DIR})
endif(NOT WIN32)
target_link_libraries(csg PUBLIC ngcore)
if(USE_GUI) if(USE_GUI)
add_library(csgvis ${NG_LIB_TYPE} vscsg.cpp ) add_library(csgvis ${NG_LIB_TYPE} vscsg.cpp )

View File

@ -562,7 +562,7 @@ namespace netgen
const Surface * CSGeometry :: GetSurface (const char * name) const const Surface * CSGeometry :: GetSurface (const char * name) const
{ {
if (surfaces.Used(name)) if (surfaces.Used(name))
return surfaces.Get(name); return surfaces[name];
else else
return NULL; return NULL;
} }
@ -585,7 +585,7 @@ namespace netgen
Solid * oldsol = NULL; Solid * oldsol = NULL;
if (solids.Used (name)) if (solids.Used (name))
oldsol = solids.Get(name); oldsol = solids[name];
solids.Set (name, sol); solids.Set (name, sol);
sol->SetName (name); sol->SetName (name);
@ -605,7 +605,7 @@ namespace netgen
const Solid * CSGeometry :: GetSolid (const char * name) const const Solid * CSGeometry :: GetSolid (const char * name) const
{ {
if (solids.Used(name)) if (solids.Used(name))
return solids.Get(name); return solids[name];
else else
return NULL; return NULL;
} }
@ -616,8 +616,8 @@ namespace netgen
const Solid * CSGeometry :: GetSolid (const string & name) const const Solid * CSGeometry :: GetSolid (const string & name) const
{ {
if (solids.Used(name.c_str())) if (solids.Used(name))
return solids.Get(name.c_str()); return solids[name];
else else
return NULL; return NULL;
} }
@ -637,15 +637,15 @@ namespace netgen
const SplineGeometry<2> * CSGeometry :: GetSplineCurve2d (const string & name) const const SplineGeometry<2> * CSGeometry :: GetSplineCurve2d (const string & name) const
{ {
if (splinecurves2d.Used(name.c_str())) if (splinecurves2d.Used(name))
return splinecurves2d.Get(name.c_str()); return splinecurves2d[name];
else else
return NULL; return NULL;
} }
const SplineGeometry<3> * CSGeometry :: GetSplineCurve3d (const string & name) const const SplineGeometry<3> * CSGeometry :: GetSplineCurve3d (const string & name) const
{ {
if (splinecurves3d.Used(name.c_str())) if (splinecurves3d.Used(name))
return splinecurves3d.Get(name.c_str()); return splinecurves3d[name];
else else
return NULL; return NULL;
} }
@ -721,7 +721,7 @@ namespace netgen
void CSGeometry :: SetFlags (const char * solidname, const Flags & flags) void CSGeometry :: SetFlags (const char * solidname, const Flags & flags)
{ {
Solid * solid = solids.Elem(solidname); Solid * solid = solids[solidname];
Array<int> surfind; Array<int> surfind;
int i; int i;

View File

@ -102,7 +102,7 @@ namespace netgen
{ {
private: private:
/// all surfaces /// all surfaces
SYMBOLTABLE<Surface*> surfaces; SymbolTable<Surface*> surfaces;
public: public:
/// primitive of surface /// primitive of surface
@ -112,12 +112,12 @@ namespace netgen
Array<Surface*> delete_them; Array<Surface*> delete_them;
/// all named solids /// all named solids
SYMBOLTABLE<Solid*> solids; SymbolTable<Solid*> solids;
/// all 2d splinecurves /// all 2d splinecurves
SYMBOLTABLE< SplineGeometry<2>* > splinecurves2d; SymbolTable< SplineGeometry<2>* > splinecurves2d;
/// all 3d splinecurves /// all 3d splinecurves
SYMBOLTABLE< SplineGeometry<3>* > splinecurves3d; SymbolTable< SplineGeometry<3>* > splinecurves3d;
/// all top level objects: solids and surfaces /// all top level objects: solids and surfaces
Array<TopLevelObject*> toplevelobjects; Array<TopLevelObject*> toplevelobjects;
@ -203,7 +203,7 @@ namespace netgen
const Solid * GetSolid (const string & name) const; const Solid * GetSolid (const string & name) const;
int GetNSolids () const { return solids.Size(); } int GetNSolids () const { return solids.Size(); }
const Solid * GetSolid (int i) const { return solids[i]; } const Solid * GetSolid (int i) const { return solids[i]; }
const SYMBOLTABLE<Solid*> & GetSolids () const { return solids; } const SymbolTable<Solid*> & GetSolids () const { return solids; }
void SetSplineCurve (const char * name, SplineGeometry<2> * spl); void SetSplineCurve (const char * name, SplineGeometry<2> * spl);

View File

@ -469,6 +469,17 @@ However, when r = 0, the top part becomes a point(tip) and meshing fails!
self.AddSplineSurface(surf); self.AddSplineSurface(surf);
}), }),
py::arg("SplineSurface")) py::arg("SplineSurface"))
.def("SingularFace", [] (CSGeometry & self, shared_ptr<SPSolid> sol, shared_ptr<SPSolid> surfaces, double factor)
{
int tlonum = -1;
for (int i = 0; i < self.GetNTopLevelObjects(); i++)
if (self.GetTopLevelObject(i)->GetSolid() == sol->GetSolid())
tlonum = i;
if (tlonum == -1) throw NgException("not a top-level-object");
if (!surfaces) surfaces = sol;
auto singface = new SingularFace(tlonum+1, surfaces->GetSolid(), factor);
self.singfaces.Append(singface);
}, py::arg("solid"), py::arg("surfaces")=nullptr, py::arg("factor")=0.25)
.def("SingularEdge", [] (CSGeometry & self, shared_ptr<SPSolid> s1,shared_ptr<SPSolid> s2, double factor) .def("SingularEdge", [] (CSGeometry & self, shared_ptr<SPSolid> s1,shared_ptr<SPSolid> s2, double factor)
{ {
auto singedge = new SingularEdge(1, -1, self, s1->GetSolid(), s2->GetSolid(), factor); auto singedge = new SingularEdge(1, -1, self, s1->GetSolid(), s2->GetSolid(), factor);

View File

@ -419,9 +419,9 @@ namespace netgen
static Solid * CreateSolidExpr (istream & ist, const SYMBOLTABLE<Solid*> & solids); static Solid * CreateSolidExpr (istream & ist, const SymbolTable<Solid*> & solids);
static Solid * CreateSolidTerm (istream & ist, const SYMBOLTABLE<Solid*> & solids); static Solid * CreateSolidTerm (istream & ist, const SymbolTable<Solid*> & solids);
static Solid * CreateSolidPrim (istream & ist, const SYMBOLTABLE<Solid*> & solids); static Solid * CreateSolidPrim (istream & ist, const SymbolTable<Solid*> & solids);
static void ReadString (istream & ist, char * str) static void ReadString (istream & ist, char * str)
{ {
@ -461,7 +461,7 @@ namespace netgen
} }
Solid * CreateSolidExpr (istream & ist, const SYMBOLTABLE<Solid*> & solids) Solid * CreateSolidExpr (istream & ist, const SymbolTable<Solid*> & solids)
{ {
// cout << "create expr" << endl; // cout << "create expr" << endl;
@ -484,7 +484,7 @@ namespace netgen
return s1; return s1;
} }
Solid * CreateSolidTerm (istream & ist, const SYMBOLTABLE<Solid*> & solids) Solid * CreateSolidTerm (istream & ist, const SymbolTable<Solid*> & solids)
{ {
// cout << "create term" << endl; // cout << "create term" << endl;
@ -508,7 +508,7 @@ namespace netgen
return s1; return s1;
} }
Solid * CreateSolidPrim (istream & ist, const SYMBOLTABLE<Solid*> & solids) Solid * CreateSolidPrim (istream & ist, const SymbolTable<Solid*> & solids)
{ {
Solid * s1; Solid * s1;
char ch; char ch;
@ -533,7 +533,7 @@ namespace netgen
} }
(*testout) << "get terminal " << str << endl; (*testout) << "get terminal " << str << endl;
s1 = solids.Get(str); s1 = solids[str];
if (s1) if (s1)
{ {
// cout << "primitive: " << str << endl; // cout << "primitive: " << str << endl;
@ -545,7 +545,7 @@ namespace netgen
} }
Solid * Solid :: CreateSolid (istream & ist, const SYMBOLTABLE<Solid*> & solids) Solid * Solid :: CreateSolid (istream & ist, const SymbolTable<Solid*> & solids)
{ {
Solid * nsol = CreateSolidExpr (ist, solids); Solid * nsol = CreateSolidExpr (ist, solids);
nsol = new Solid (ROOT, nsol); nsol = new Solid (ROOT, nsol);

View File

@ -158,7 +158,7 @@ namespace netgen
{ return maxh; } { return maxh; }
void GetSolidData (ostream & ost, int first = 1) const; void GetSolidData (ostream & ost, int first = 1) const;
static Solid * CreateSolid (istream & ist, const SYMBOLTABLE<Solid*> & solids); static Solid * CreateSolid (istream & ist, const SymbolTable<Solid*> & solids);
static BlockAllocator ball; static BlockAllocator ball;

View File

@ -1,21 +1,19 @@
add_definitions(-DNGINTERFACE_EXPORTS) add_definitions(-DNGINTERFACE_EXPORTS)
add_library(gen OBJECT add_library(gen INTERFACE)
array.cpp bitarray.cpp dynamicmem.cpp flags.cpp set(sdir ${CMAKE_CURRENT_SOURCE_DIR})
hashtabl.cpp mystring.cpp ngexception.cpp optmem.cpp parthreads.cpp target_sources(gen INTERFACE
profiler.cpp seti.cpp sort.cpp spbita2d.cpp symbolta.cpp table.cpp ${sdir}/array.cpp ${sdir}/bitarray.cpp ${sdir}/dynamicmem.cpp ${sdir}/flags.cpp
mpi_interface.cpp gzstream.cpp ${sdir}/hashtabl.cpp ${sdir}/mystring.cpp ${sdir}/optmem.cpp ${sdir}/parthreads.cpp
${sdir}/seti.cpp ${sdir}/sort.cpp ${sdir}/spbita2d.cpp ${sdir}/table.cpp
${sdir}/mpi_interface.cpp ${sdir}/gzstream.cpp
) )
set_target_properties( gen PROPERTIES POSITION_INDEPENDENT_CODE ON )
install( FILES ngexception.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE} COMPONENT netgen_devel )
install(FILES install(FILES
array.hpp autodiff.hpp autoptr.hpp bitarray.hpp array.hpp autodiff.hpp autoptr.hpp bitarray.hpp
dynamicmem.hpp flags.hpp hashtabl.hpp mpi_interface.hpp myadt.hpp dynamicmem.hpp flags.hpp hashtabl.hpp mpi_interface.hpp myadt.hpp
ngsimd.hpp mystring.hpp netgenout.hpp ngexception.hpp ngpython.hpp ngsimd.hpp mystring.hpp netgenout.hpp ngpython.hpp
optmem.hpp parthreads.hpp profiler.hpp seti.hpp sort.hpp optmem.hpp parthreads.hpp seti.hpp sort.hpp
spbita2d.hpp stack.hpp symbolta.hpp table.hpp template.hpp spbita2d.hpp stack.hpp table.hpp template.hpp
gzstream.h gzstream.h
DESTINATION ${NG_INSTALL_DIR_INCLUDE}/general COMPONENT netgen_devel DESTINATION ${NG_INSTALL_DIR_INCLUDE}/general COMPONENT netgen_devel
) )

View File

@ -243,10 +243,11 @@ namespace netgen
} }
explicit Array(size_t asize) explicit Array(size_t asize)
: FlatArray<T, BASE, TIND> (asize, new T[asize]) : FlatArray<T, BASE, TIND> (asize, asize ? new T[asize] : nullptr)
{ {
allocsize = asize; allocsize = asize;
ownmem = 1; if(asize)
ownmem = 1;
} }
/// Generate array in user data /// Generate array in user data

View File

@ -83,7 +83,7 @@ namespace netgen
Flags :: GetStringFlag (const char * name, const char * def) const Flags :: GetStringFlag (const char * name, const char * def) const
{ {
if (strflags.Used (name)) if (strflags.Used (name))
return strflags.Get(name); return strflags[name];
else else
return def; return def;
} }
@ -91,7 +91,7 @@ namespace netgen
double Flags :: GetNumFlag (const char * name, double def) const double Flags :: GetNumFlag (const char * name, double def) const
{ {
if (numflags.Used (name)) if (numflags.Used (name))
return numflags.Get(name); return numflags[name];
else else
return def; return def;
} }
@ -99,7 +99,7 @@ namespace netgen
const double * Flags :: GetNumFlagPtr (const char * name) const const double * Flags :: GetNumFlagPtr (const char * name) const
{ {
if (numflags.Used (name)) if (numflags.Used (name))
return & ((SYMBOLTABLE<double>&)numflags).Elem(name); return & ((SymbolTable<double>&)numflags)[name];
else else
return NULL; return NULL;
} }
@ -107,7 +107,7 @@ namespace netgen
double * Flags :: GetNumFlagPtr (const char * name) double * Flags :: GetNumFlagPtr (const char * name)
{ {
if (numflags.Used (name)) if (numflags.Used (name))
return & ((SYMBOLTABLE<double>&)numflags).Elem(name); return & ((SymbolTable<double>&)numflags)[name];
else else
return NULL; return NULL;
} }
@ -122,7 +122,7 @@ namespace netgen
Flags :: GetStringListFlag (const char * name) const Flags :: GetStringListFlag (const char * name) const
{ {
if (strlistflags.Used (name)) if (strlistflags.Used (name))
return *strlistflags.Get(name); return *strlistflags[name];
else else
{ {
static Array<char*> dummy_array(0); static Array<char*> dummy_array(0);
@ -134,7 +134,7 @@ namespace netgen
Flags ::GetNumListFlag (const char * name) const Flags ::GetNumListFlag (const char * name) const
{ {
if (numlistflags.Used (name)) if (numlistflags.Used (name))
return *numlistflags.Get(name); return *numlistflags[name];
else else
{ {
static Array<double> dummy_array(0); static Array<double> dummy_array(0);
@ -170,9 +170,9 @@ namespace netgen
ofstream outfile (filename); ofstream outfile (filename);
for (i = 1; i <= strflags.Size(); i++) for (i = 1; i <= strflags.Size(); i++)
outfile << strflags.GetName(i) << " = " << strflags.Get(i) << endl; outfile << strflags.GetName(i) << " = " << strflags[i] << endl;
for (i = 1; i <= numflags.Size(); i++) for (i = 1; i <= numflags.Size(); i++)
outfile << numflags.GetName(i) << " = " << numflags.Get(i) << endl; outfile << numflags.GetName(i) << " = " << numflags[i] << endl;
for (i = 1; i <= defflags.Size(); i++) for (i = 1; i <= defflags.Size(); i++)
outfile << defflags.GetName(i) << endl; outfile << defflags.GetName(i) << endl;
} }
@ -184,9 +184,9 @@ namespace netgen
int i; int i;
for (i = 1; i <= strflags.Size(); i++) for (i = 1; i <= strflags.Size(); i++)
ost << strflags.GetName(i) << " = " << strflags.Get(i) << endl; ost << strflags.GetName(i) << " = " << strflags[i] << endl;
for (i = 1; i <= numflags.Size(); i++) for (i = 1; i <= numflags.Size(); i++)
ost << numflags.GetName(i) << " = " << numflags.Get(i) << endl; ost << numflags.GetName(i) << " = " << numflags[i] << endl;
for (i = 1; i <= defflags.Size(); i++) for (i = 1; i <= defflags.Size(); i++)
ost << defflags.GetName(i) << endl; ost << defflags.GetName(i) << endl;
} }

View File

@ -19,15 +19,15 @@ namespace netgen
class Flags class Flags
{ {
/// ///
SYMBOLTABLE<char *> strflags; SymbolTable<char *> strflags;
/// ///
SYMBOLTABLE<double> numflags; SymbolTable<double> numflags;
/// ///
SYMBOLTABLE<int> defflags; SymbolTable<int> defflags;
/// ///
SYMBOLTABLE<Array<char*>*> strlistflags; SymbolTable<Array<char*>*> strlistflags;
/// ///
SYMBOLTABLE<Array<double>*> numlistflags; SymbolTable<Array<double>*> numlistflags;
public: public:
/// ///
DLL_HEADER Flags (); DLL_HEADER Flags ();

View File

@ -14,101 +14,172 @@
namespace netgen namespace netgen
{ {
using ngcore::id;
using ngcore::ntasks;
extern DLL_HEADER int id, ntasks; #ifndef PARALLEL
/** without MPI, we need a dummy typedef **/
typedef int MPI_Comm;
#endif
/** This is the "standard" communicator that will be used for netgen-objects. **/
extern DLL_HEADER MPI_Comm ng_comm;
#ifdef PARALLEL #ifdef PARALLEL
inline int MyMPI_GetNTasks (MPI_Comm comm = ng_comm)
{
int ntasks;
MPI_Comm_size(comm, &ntasks);
return ntasks;
}
inline int MyMPI_GetId (MPI_Comm comm = ng_comm)
{
int id;
MPI_Comm_rank(comm, &id);
return id;
}
#else
enum { MPI_COMM_WORLD = 12345, MPI_COMM_NULL = 0};
inline int MyMPI_GetNTasks (MPI_Comm comm = ng_comm) { return 1; }
inline int MyMPI_GetId (MPI_Comm comm = ng_comm) { return 0; }
#endif
#ifdef PARALLEL
// For python wrapping of communicators
struct PyMPI_Comm {
MPI_Comm comm;
bool owns_comm;
PyMPI_Comm (MPI_Comm _comm, bool _owns_comm = false) : comm(_comm), owns_comm(_owns_comm) { }
PyMPI_Comm (const PyMPI_Comm & c) = delete;
~PyMPI_Comm () {
if (owns_comm)
MPI_Comm_free(&comm);
}
inline int Rank() const { return MyMPI_GetId(comm); }
inline int Size() const { return MyMPI_GetNTasks(comm); }
};
#else
// dummy without MPI
struct PyMPI_Comm {
MPI_Comm comm = 0;
PyMPI_Comm (MPI_Comm _comm, bool _owns_comm = false) { }
~PyMPI_Comm () { }
inline int Rank() const { return 0; }
inline int Size() const { return 1; }
};
#endif
#ifdef PARALLEL
template <class T>
inline MPI_Datatype MyGetMPIType ( )
{ cerr << "ERROR in GetMPIType() -- no type found" << endl;return 0; }
template <>
inline MPI_Datatype MyGetMPIType<int> ( )
{ return MPI_INT; }
template <>
inline MPI_Datatype MyGetMPIType<double> ( )
{ return MPI_DOUBLE; }
template <>
inline MPI_Datatype MyGetMPIType<char> ( )
{ return MPI_CHAR; }
template<>
inline MPI_Datatype MyGetMPIType<size_t> ( )
{ return MPI_UINT64_T; }
#else
typedef int MPI_Datatype;
template <class T> inline MPI_Datatype MyGetMPIType ( ) { return 0; }
#endif
#ifdef PARALLEL
inline MPI_Comm MyMPI_SubCommunicator(MPI_Comm comm, Array<int> & procs)
{
MPI_Comm subcomm;
MPI_Group gcomm, gsubcomm;
MPI_Comm_group(comm, &gcomm);
MPI_Group_incl(gcomm, procs.Size(), &(procs[0]), &gsubcomm);
MPI_Comm_create_group(comm, gsubcomm, 6969, &subcomm);
return subcomm;
}
#else
inline MPI_Comm MyMPI_SubCommunicator(MPI_Comm comm, Array<int> & procs)
{ return comm; }
#endif
#ifdef PARALLEL
enum { MPI_TAG_CMD = 110 }; enum { MPI_TAG_CMD = 110 };
enum { MPI_TAG_MESH = 210 }; enum { MPI_TAG_MESH = 210 };
enum { MPI_TAG_VIS = 310 }; enum { MPI_TAG_VIS = 310 };
extern MPI_Comm mesh_comm; inline void MyMPI_Send (int i, int dest, int tag, MPI_Comm comm = ng_comm)
template <class T>
MPI_Datatype MyGetMPIType ( )
{ cerr << "ERROR in GetMPIType() -- no type found" << endl;return 0; }
template <>
inline MPI_Datatype MyGetMPIType<int> ( )
{ return MPI_INT; }
template <>
inline MPI_Datatype MyGetMPIType<double> ( )
{ return MPI_DOUBLE; }
inline void MyMPI_Send (int i, int dest, int tag)
{ {
int hi = i; int hi = i;
MPI_Send( &hi, 1, MPI_INT, dest, tag, MPI_COMM_WORLD); MPI_Send( &hi, 1, MPI_INT, dest, tag, comm);
} }
inline void MyMPI_Recv (int & i, int src, int tag) inline void MyMPI_Recv (int & i, int src, int tag, MPI_Comm comm = ng_comm)
{ {
MPI_Status status; MPI_Status status;
MPI_Recv( &i, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status); MPI_Recv( &i, 1, MPI_INT, src, tag, comm, &status);
} }
inline void MyMPI_Send (const string & s, int dest, int tag) inline void MyMPI_Send (const string & s, int dest, int tag, MPI_Comm comm = ng_comm)
{ {
MPI_Send( const_cast<char*> (s.c_str()), s.length(), MPI_CHAR, dest, tag, MPI_COMM_WORLD); MPI_Send( const_cast<char*> (s.c_str()), s.length(), MPI_CHAR, dest, tag, comm);
} }
inline void MyMPI_Recv (string & s, int src, int tag) inline void MyMPI_Recv (string & s, int src, int tag, MPI_Comm comm = ng_comm)
{ {
MPI_Status status; MPI_Status status;
int len; int len;
MPI_Probe (src, tag, MPI_COMM_WORLD, &status); MPI_Probe (src, tag, MPI_COMM_WORLD, &status);
MPI_Get_count (&status, MPI_CHAR, &len); MPI_Get_count (&status, MPI_CHAR, &len);
s.assign (len, ' '); s.assign (len, ' ');
MPI_Recv( &s[0], len, MPI_CHAR, src, tag, MPI_COMM_WORLD, &status); MPI_Recv( &s[0], len, MPI_CHAR, src, tag, comm, &status);
} }
template <class T, int BASE> template <class T, int BASE>
inline void MyMPI_Send (FlatArray<T, BASE> s, int dest, int tag) inline void MyMPI_Send (FlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm = ng_comm)
{ {
MPI_Send( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, MPI_COMM_WORLD); MPI_Send( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, comm);
} }
template <class T, int BASE> template <class T, int BASE>
inline void MyMPI_Recv ( FlatArray<T, BASE> s, int src, int tag) inline void MyMPI_Recv ( FlatArray<T, BASE> s, int src, int tag, MPI_Comm comm = ng_comm)
{ {
MPI_Status status; MPI_Status status;
MPI_Recv( &s.First(), s.Size(), MyGetMPIType<T>(), src, tag, MPI_COMM_WORLD, &status); MPI_Recv( &s.First(), s.Size(), MyGetMPIType<T>(), src, tag, comm, &status);
} }
template <class T, int BASE> template <class T, int BASE>
inline void MyMPI_Recv ( Array <T, BASE> & s, int src, int tag) inline void MyMPI_Recv ( Array <T, BASE> & s, int src, int tag, MPI_Comm comm = ng_comm)
{ {
MPI_Status status; MPI_Status status;
int len; int len;
MPI_Probe (src, tag, MPI_COMM_WORLD, &status); MPI_Probe (src, tag, comm, &status);
MPI_Get_count (&status, MyGetMPIType<T>(), &len); MPI_Get_count (&status, MyGetMPIType<T>(), &len);
s.SetSize (len); s.SetSize (len);
MPI_Recv( &s.First(), len, MyGetMPIType<T>(), src, tag, MPI_COMM_WORLD, &status); MPI_Recv( &s.First(), len, MyGetMPIType<T>(), src, tag, comm, &status);
} }
template <class T, int BASE> template <class T, int BASE>
inline int MyMPI_Recv ( Array <T, BASE> & s, int tag) inline int MyMPI_Recv ( Array <T, BASE> & s, int tag, MPI_Comm comm = ng_comm)
{ {
MPI_Status status; MPI_Status status;
int len; int len;
MPI_Probe (MPI_ANY_SOURCE, tag, MPI_COMM_WORLD, &status); MPI_Probe (MPI_ANY_SOURCE, tag, comm, &status);
int src = status.MPI_SOURCE; int src = status.MPI_SOURCE;
MPI_Get_count (&status, MyGetMPIType<T>(), &len); MPI_Get_count (&status, MyGetMPIType<T>(), &len);
s.SetSize (len); s.SetSize (len);
MPI_Recv( &s.First(), len, MyGetMPIType<T>(), src, tag, MPI_COMM_WORLD, &status); MPI_Recv( &s.First(), len, MyGetMPIType<T>(), src, tag, comm, &status);
return src; return src;
} }
@ -130,7 +201,7 @@ namespace netgen
*/ */
template <class T, int BASE> template <class T, int BASE>
inline MPI_Request MyMPI_ISend (FlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm = MPI_COMM_WORLD) inline MPI_Request MyMPI_ISend (FlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm = ng_comm)
{ {
MPI_Request request; MPI_Request request;
MPI_Isend( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, comm, &request); MPI_Isend( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, comm, &request);
@ -139,7 +210,7 @@ namespace netgen
template <class T, int BASE> template <class T, int BASE>
inline MPI_Request MyMPI_IRecv (FlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm = MPI_COMM_WORLD) inline MPI_Request MyMPI_IRecv (FlatArray<T, BASE> s, int dest, int tag, MPI_Comm comm = ng_comm)
{ {
MPI_Request request; MPI_Request request;
MPI_Irecv( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, comm, &request); MPI_Irecv( &s.First(), s.Size(), MyGetMPIType<T>(), dest, tag, comm, &request);
@ -204,11 +275,10 @@ namespace netgen
template <typename T> template <typename T>
inline void MyMPI_ExchangeTable (TABLE<T> & send_data, inline void MyMPI_ExchangeTable (TABLE<T> & send_data,
TABLE<T> & recv_data, int tag, TABLE<T> & recv_data, int tag,
MPI_Comm comm = MPI_COMM_WORLD) MPI_Comm comm = ng_comm)
{ {
int ntasks, rank; int rank = MyMPI_GetId(comm);
MPI_Comm_size(comm, &ntasks); int ntasks = MyMPI_GetNTasks(comm);
MPI_Comm_rank(comm, &rank);
Array<int> send_sizes(ntasks); Array<int> send_sizes(ntasks);
Array<int> recv_sizes(ntasks); Array<int> recv_sizes(ntasks);
@ -252,22 +322,22 @@ namespace netgen
template <class T> template <class T>
inline void MyMPI_Bcast (T & s, MPI_Comm comm = MPI_COMM_WORLD) inline void MyMPI_Bcast (T & s, MPI_Comm comm = ng_comm)
{ {
MPI_Bcast (&s, 1, MyGetMPIType<T>(), 0, comm); MPI_Bcast (&s, 1, MyGetMPIType<T>(), 0, comm);
} }
template <class T> template <class T>
inline void MyMPI_Bcast (Array<T, 0> & s, MPI_Comm comm = MPI_COMM_WORLD) inline void MyMPI_Bcast (Array<T, 0> & s, MPI_Comm comm = ng_comm)
{ {
int size = s.Size(); int size = s.Size();
MyMPI_Bcast (size, comm); MyMPI_Bcast (size, comm);
if (id != 0) s.SetSize (size); if (MyMPI_GetId(comm) != 0) s.SetSize (size);
MPI_Bcast (&s[0], size, MyGetMPIType<T>(), 0, comm); MPI_Bcast (&s[0], size, MyGetMPIType<T>(), 0, comm);
} }
template <class T> template <class T>
inline void MyMPI_Bcast (Array<T, 0> & s, int root, MPI_Comm comm = MPI_COMM_WORLD) inline void MyMPI_Bcast (Array<T, 0> & s, int root, MPI_Comm comm = ng_comm)
{ {
int id; int id;
MPI_Comm_rank(comm, &id); MPI_Comm_rank(comm, &id);
@ -280,19 +350,19 @@ namespace netgen
} }
template <class T, class T2> template <class T, class T2>
inline void MyMPI_Allgather (const T & send, FlatArray<T2> recv, MPI_Comm comm) inline void MyMPI_Allgather (const T & send, FlatArray<T2> recv, MPI_Comm comm = ng_comm)
{ {
MPI_Allgather( const_cast<T*> (&send), 1, MyGetMPIType<T>(), &recv[0], 1, MyGetMPIType<T2>(), comm); MPI_Allgather( const_cast<T*> (&send), 1, MyGetMPIType<T>(), &recv[0], 1, MyGetMPIType<T2>(), comm);
} }
template <class T, class T2> template <class T, class T2>
inline void MyMPI_Alltoall (FlatArray<T> send, FlatArray<T2> recv, MPI_Comm comm) inline void MyMPI_Alltoall (FlatArray<T> send, FlatArray<T2> recv, MPI_Comm comm = ng_comm)
{ {
MPI_Alltoall( &send[0], 1, MyGetMPIType<T>(), &recv[0], 1, MyGetMPIType<T2>(), comm); MPI_Alltoall( &send[0], 1, MyGetMPIType<T>(), &recv[0], 1, MyGetMPIType<T2>(), comm);
} }
// template <class T, class T2> // template <class T, class T2>
// inline void MyMPI_Alltoall_Block (FlatArray<T> send, FlatArray<T2> recv, int blocklen, MPI_Comm comm) // inline void MyMPI_Alltoall_Block (FlatArray<T> send, FlatArray<T2> recv, int blocklen, MPI_Comm comm = ng_comm)
// { // {
// MPI_Alltoall( &send[0], blocklen, MyGetMPIType<T>(), &recv[0], blocklen, MyGetMPIType<T2>(), comm); // MPI_Alltoall( &send[0], blocklen, MyGetMPIType<T>(), &recv[0], blocklen, MyGetMPIType<T2>(), comm);
// } // }

View File

@ -21,8 +21,8 @@
namespace netgen namespace netgen
{ {
using namespace ngcore; using namespace ngcore;
using NgException = Exception;
} }
#include "ngexception.hpp"
#include "parthreads.hpp" #include "parthreads.hpp"
// #include "moveablemem.hpp" // #include "moveablemem.hpp"
#include "dynamicmem.hpp" #include "dynamicmem.hpp"
@ -33,7 +33,6 @@ namespace netgen
#include "hashtabl.hpp" #include "hashtabl.hpp"
#include "symbolta.hpp"
#include "bitarray.hpp" #include "bitarray.hpp"
#include "flags.hpp" #include "flags.hpp"
#include "spbita2d.hpp" #include "spbita2d.hpp"
@ -44,7 +43,6 @@ namespace netgen
#include "sort.hpp" #include "sort.hpp"
#include "stack.hpp" #include "stack.hpp"
#include "mystring.hpp" #include "mystring.hpp"
#include "profiler.hpp"
#include "mpi_interface.hpp" #include "mpi_interface.hpp"
#include "netgenout.hpp" #include "netgenout.hpp"

View File

@ -4,14 +4,11 @@
// #include <ostream> // #include <ostream>
// #include <mystdlib.h> // #include <mystdlib.h>
// #include <meshing.hpp> // #include <meshing.hpp>
#include "mpi_interface.hpp"
namespace netgen namespace netgen
{ {
#ifdef PARALLEL
extern int id;
extern int ntasks;
#endif
DLL_HEADER extern int printmessage_importance; DLL_HEADER extern int printmessage_importance;
DLL_HEADER extern int printdots; DLL_HEADER extern int printdots;

View File

@ -1,33 +0,0 @@
/**************************************************************************/
/* File: ngexception.cpp */
/* Author: Joachim Schoeberl */
/* Date: 16. Jan. 02 */
/**************************************************************************/
#include <myadt.hpp>
namespace netgen
{
//using namespace netgen;
NgException :: NgException (const string & s)
: m_what(s)
{
;
}
NgException :: ~NgException ()
{
;
}
/// append string to description
void NgException :: Append (const string & s)
{
m_what += s;
}
}

View File

@ -1,34 +0,0 @@
#ifndef FILE_NGEXCEPTION
#define FILE_NGEXCEPTION
/**************************************************************************/
/* File: ngexception.hpp */
/* Author: Joachim Schoeberl */
/* Date: 16. Jan. 2002 */
/**************************************************************************/
namespace netgen
{
/// Base class for all ng exceptions
class NgException : public std::exception
{
/// verbal description of exception
string m_what;
public:
///
DLL_HEADER NgException (const string & s);
///
DLL_HEADER virtual ~NgException ();
/// append string to description
DLL_HEADER void Append (const string & s);
// void Append (const char * s);
/// verbal description of exception
const string & What() const { return m_what; }
virtual const char* what() const noexcept override { return m_what.c_str(); }
};
}
#endif

View File

@ -3,6 +3,7 @@
#include <pybind11/pybind11.h> #include <pybind11/pybind11.h>
#include <pybind11/operators.h> #include <pybind11/operators.h>
#include <pybind11/numpy.h> #include <pybind11/numpy.h>
#include <pybind11/stl.h>
namespace py = pybind11; namespace py = pybind11;
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
@ -66,16 +67,7 @@ namespace netgen
return static_cast<typename function_traits<Function>::pointer>(lambda); return static_cast<typename function_traits<Function>::pointer>(lambda);
} }
} // namespace netgen
template <class T>
inline std::string ToString (const T& t)
{
std::stringstream ss;
ss << t;
return ss.str();
}
}
#endif #endif

View File

@ -1,131 +0,0 @@
/**************************************************************************/
/* File: profiler.cpp */
/* Author: Joachim Schoeberl */
/* Date: 19. Apr. 2002 */
/**************************************************************************/
#include <myadt.hpp>
namespace netgen
{
//using namespace netgen;
long int NgProfiler::tottimes[SIZE];
long int NgProfiler::starttimes[SIZE];
long int NgProfiler::counts[SIZE];
string NgProfiler::names[SIZE];
int NgProfiler::usedcounter[SIZE];
NgProfiler :: NgProfiler()
{
for (int i = 0; i < SIZE; i++)
{
tottimes[i] = 0;
usedcounter[i] = 0;
}
total_timer = CreateTimer ("total CPU time");
StartTimer (total_timer);
}
NgProfiler :: ~NgProfiler()
{
#ifndef PARALLEL
StopTimer (total_timer);
#endif
//ofstream prof;
//prof.open("ng.prof");
// ofstream-constructor may be called after STL-stuff is destructed,
// which leads to an "order of destruction"-problem,
// thus we use the C-variant:
if (getenv ("NGPROFILE"))
{
char filename[100];
#ifdef PARALLEL
sprintf (filename, "netgen.prof.%d", id);
#else
sprintf (filename, "netgen.prof");
#endif
if (id == 0) printf ("write profile to file netgen.prof\n");
FILE *prof = fopen(filename,"w");
Print (prof);
fclose(prof);
}
}
// void NgProfiler :: Print (ostream & prof)
// {
// for (int i = 0; i < SIZE; i++)
// if (counts[i] != 0 || usedcounter[i] != 0)
// {
// prof.setf (ios::fixed, ios::floatfield);
// prof.setf (ios::showpoint);
// prof // << "job " << setw(3) << i
// << "calls " << setw(8) << counts[i]
// << ", time " << setprecision(2) << setw(6) << double(tottimes[i]) / CLOCKS_PER_SEC << " sec";
// if (usedcounter[i])
// prof << " " << names[i];
// else
// prof << " " << i;
// prof << endl;
// }
// }
void NgProfiler :: Print (FILE * prof)
{
for (int i = 0; i < SIZE; i++)
if (counts[i] != 0 || usedcounter[i] != 0)
{
//fprintf(prof,"job %3i calls %8i, time %6.2f sec",i,counts[i],double(tottimes[i]) / CLOCKS_PER_SEC);
#ifndef USE_TSC
fprintf(prof,"calls %8li, time %6.2f sec",counts[i],double(tottimes[i]) / CLOCKS_PER_SEC);
#else
fprintf(prof,"calls %8li, time %6.2f sec",counts[i],double(tottimes[i]) / 2.7e9);
#endif
if(usedcounter[i])
fprintf(prof," %s",names[i].c_str());
else
fprintf(prof," %i",i);
fprintf(prof,"\n");
}
}
int NgProfiler :: CreateTimer (const string & name)
{
for (int i = SIZE-1; i > 0; i--)
if(names[i] == name)
return i;
for (int i = SIZE-1; i > 0; i--)
if (!usedcounter[i])
{
usedcounter[i] = 1;
names[i] = name;
return i;
}
return -1;
}
void NgProfiler :: ClearTimers ()
{
for (int i = 0; i < SIZE; i++)
{
tottimes[i] = 0;
counts[i] = 0;
}
}
NgProfiler prof;
}

View File

@ -1,88 +0,0 @@
#ifndef FILE_NG_PROFILER
#define FILE_NG_PROFILER
/**************************************************************************/
/* File: profiler.hpp */
/* Author: Joachim Schoeberl */
/* Date: 5. Jan. 2005 */
/**************************************************************************/
#ifdef VTRACE
#include "vt_user.h"
#else
#define VT_USER_START(n)
#define VT_USER_END(n)
#define VT_TRACER(n)
#endif
// #define USE_TSC
#ifdef USE_TSC
#include <x86intrin.h> // for __rdtsc() CPU time step counter
#endif
namespace netgen
{
class NgProfiler
{
enum { SIZE = 1000 };
static long int tottimes[SIZE];
static long int starttimes[SIZE];
static long int counts[SIZE];
static string names[SIZE];
static int usedcounter[SIZE];
int total_timer;
public:
NgProfiler();
~NgProfiler();
static int CreateTimer (const string & name);
#ifndef USE_TSC
static void StartTimer (int nr)
{
starttimes[nr] = clock(); counts[nr]++;
// VT_USER_START (const_cast<char*> (names[nr].c_str()));
VT_USER_START ( (char * const) (names[nr].c_str()));
}
static void StopTimer (int nr)
{
tottimes[nr] += clock()-starttimes[nr];
VT_USER_END (const_cast<char*> (names[nr].c_str()));
}
#else
static void StartTimer (int nr)
{
starttimes[nr] = __rdtsc(); counts[nr]++;
// VT_USER_START (const_cast<char*> (names[nr].c_str()));
// VT_USER_START ( (char * const) (names[nr].c_str()));
}
static void StopTimer (int nr)
{
tottimes[nr] += __rdtsc()-starttimes[nr];
VT_USER_END (const_cast<char*> (names[nr].c_str()));
}
#endif
//static void Print (ostream & ost);
static void Print (FILE * prof);
static void ClearTimers ();
class RegionTimer
{
int nr;
public:
RegionTimer (int anr) : nr(anr)
{ StartTimer (nr); }
~RegionTimer () { StopTimer (nr); }
};
};
}
#endif

View File

@ -1,52 +0,0 @@
/**************************************************************************/
/* File: symbolta.cc */
/* Author: Joachim Schoeberl */
/* Date: 01. Jun. 95 */
/**************************************************************************/
/*
Abstract data type Symbol Table
*/
#include <mystdlib.h>
#include <myadt.hpp>
#ifndef FILE_SYMBOLTABLECC
#define FILE_SYMBOLTABLECC
// necessary for SGI ????
namespace netgen
{
//using namespace netgen;
BASE_SYMBOLTABLE :: BASE_SYMBOLTABLE ()
{
;
}
BASE_SYMBOLTABLE :: ~BASE_SYMBOLTABLE()
{
DelNames();
}
void BASE_SYMBOLTABLE :: DelNames()
{
for (int i = 0; i < names.Size(); i++)
delete [] names[i];
names.SetSize (0);
}
int BASE_SYMBOLTABLE :: Index (const char * name) const
{
if (!name) return 0;
for (int i = 0; i < names.Size(); i++)
if (strcmp (names[i], name) == 0) return i+1;
return 0;
}
}
#endif

View File

@ -1,163 +0,0 @@
#ifndef FILE_SYMBOLTA
#define FILE_SYMBOLTA
/**************************************************************************/
/* File: symbolta.hh */
/* Author: Joachim Schoeberl */
/* Date: 01. Jun. 95 */
/**************************************************************************/
namespace netgen
{
/**
Base class for the generic SYMBOLTABLE.
An array of identifiers is maintained.
*/
class DLL_HEADER BASE_SYMBOLTABLE
{
protected:
/// identifiers
Array <char*> names;
public:
/// Constructor
BASE_SYMBOLTABLE ();
///
~BASE_SYMBOLTABLE ();
///
void DelNames ();
/// Index of symbol name, returns 0 if not used.
int Index (const char * name) const;
};
/**
Abstract data type Symbol Table.
To a string an value of the generic type T is associated.
The string is not copied into the symbol table class!
*/
template <class T>
class SYMBOLTABLE : public BASE_SYMBOLTABLE
{
private:
/// Associated data
Array <T> data;
public:
/// Creates a symboltable
inline SYMBOLTABLE ();
/// Returns size of symboltable
inline INDEX Size() const;
/// Returns reference to element, error if not used
inline T & Elem (const char * name);
/// Returns reference to i-th element
inline T & Elem (int i)
{ return data.Elem(i); }
/// Returns element, error if not used
inline const T & Get (const char * name) const;
/// Returns i-th element
inline const T & Get (int i) const;
/// Returns name of i-th element
inline const char* GetName (int i) const;
/// Associates el to the string name, overrides if name is used
inline void Set (const char * name, const T & el);
/// Checks whether name is used
inline bool Used (const char * name) const;
/// Deletes symboltable
inline void DeleteAll ();
void DoArchive(Archive& archive) { archive & names & data;}
inline T & operator[] (int i)
{ return data[i]; }
inline const T & operator[] (int i) const
{ return data[i]; }
private:
/// Prevents from copying symboltable by pointer assignment
SYMBOLTABLE<T> & operator= (SYMBOLTABLE<T> &);
};
template <class T>
inline SYMBOLTABLE<T> :: SYMBOLTABLE ()
{
;
}
template <class T>
inline INDEX SYMBOLTABLE<T> :: Size() const
{
return data.Size();
}
template <class T>
inline T & SYMBOLTABLE<T> :: Elem (const char * name)
{
int i = Index (name);
if (i)
return data.Elem (i);
else
return data.Elem(1);
}
template <class T>
inline const T & SYMBOLTABLE<T> :: Get (const char * name) const
{
int i;
i = Index (name);
if (i)
return data.Get(i);
else
return data.Get(1);
}
template <class T>
inline const T & SYMBOLTABLE<T> :: Get (int i) const
{
return data.Get(i);
}
template <class T>
inline const char* SYMBOLTABLE<T> :: GetName (int i) const
{
return names.Get(i);
}
template <class T>
inline void SYMBOLTABLE<T> :: Set (const char * name, const T & el)
{
int i;
i = Index (name);
if (i)
data.Set(i, el);
else
{
data.Append (el);
char * hname = new char [strlen (name) + 1];
strcpy (hname, name);
names.Append (hname);
}
}
template <class T>
inline bool SYMBOLTABLE<T> :: Used (const char * name) const
{
return (Index(name)) ? true : false;
}
template <class T>
inline void SYMBOLTABLE<T> :: DeleteAll ()
{
DelNames();
data.DeleteAll();
}
}
#endif

View File

@ -4,10 +4,10 @@ if(APPLE)
set_target_properties( geom2d PROPERTIES SUFFIX ".so") set_target_properties( geom2d PROPERTIES SUFFIX ".so")
endif(APPLE) endif(APPLE)
if(NOT WIN32) target_link_libraries(geom2d mesh ${PYTHON_LIBRARIES})
target_link_libraries(geom2d mesh ${PYTHON_LIBRARIES}) install( TARGETS geom2d ${NG_INSTALL_DIR})
install( TARGETS geom2d ${NG_INSTALL_DIR})
endif(NOT WIN32) target_link_libraries(geom2d ngcore)
if(USE_GUI) if(USE_GUI)
add_library(geom2dvis ${NG_LIB_TYPE} vsgeom2d.cpp) add_library(geom2dvis ${NG_LIB_TYPE} vsgeom2d.cpp)

View File

@ -55,7 +55,8 @@ namespace netgen
sum += dt / fun; sum += dt / fun;
} }
int nel = int (sum+1); int nel = int (sum+0.5);
if (nel == 0) nel = 1;
fperel = sum / nel; fperel = sum / nel;
points.Append (0); points.Append (0);
@ -457,9 +458,9 @@ namespace netgen
for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)
if ( (*mesh)[si].si > maxsegmentindex) maxsegmentindex = (*mesh)[si].si; if ( (*mesh)[si].si > maxsegmentindex) maxsegmentindex = (*mesh)[si].si;
mesh->SetNBCNames(maxsegmentindex+1); mesh->SetNBCNames(maxsegmentindex);
for ( int sindex = 0; sindex <= maxsegmentindex; sindex++ ) for ( int sindex = 0; sindex < maxsegmentindex; sindex++ )
mesh->SetBCName ( sindex, geometry.GetBCName( sindex+1 ) ); mesh->SetBCName ( sindex, geometry.GetBCName( sindex+1 ) );
for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++) for (SegmentIndex si = 0; si < mesh->GetNSeg(); si++)

View File

@ -175,6 +175,7 @@ namespace netgen
void CopyEdgeMesh (int from, int to, Mesh & mesh2d, Point3dTree & searchtree); void CopyEdgeMesh (int from, int to, Mesh & mesh2d, Point3dTree & searchtree);
size_t GetNDomains() const { return materials.Size(); }
void GetMaterial (int domnr, char* & material ); void GetMaterial (int domnr, char* & material );
void SetMaterial (int domnr, const string & material); void SetMaterial (int domnr, const string & material);

View File

@ -15,6 +15,22 @@ namespace netgen
DLL_HEADER void ExportGeom2d(py::module &m) DLL_HEADER void ExportGeom2d(py::module &m)
{ {
py::class_<SplineSegExt, shared_ptr<SplineSegExt>>
(m, "Spline", "Spline of a SplineGeometry object")
.def_property("leftdom", [] (SplineSegExt& self) { return self.leftdom; },
[](SplineSegExt& self, int dom) { self.leftdom = dom; })
.def_property("rightdom", [] (SplineSegExt& self) { return self.rightdom; },
[](SplineSegExt& self, int dom) { self.rightdom = dom; })
.def_property_readonly("bc", [] (SplineSegExt& self) { return self.bc; })
.def("GetNormal", [](SplineSegExt& self, double t)
{
auto tang = self.GetTangent(t).Normalize();
return Vec<2>(tang[1], -tang[0]);
})
.def("StartPoint", [](SplineSegExt& self) { return Point<2>(self.StartPI()); })
.def("EndPoint", [](SplineSegExt& self) { return Point<2>(self.EndPI()); })
;
py::class_<SplineGeometry2d, NetgenGeometry, shared_ptr<SplineGeometry2d>> py::class_<SplineGeometry2d, NetgenGeometry, shared_ptr<SplineGeometry2d>>
(m, "SplineGeometry", (m, "SplineGeometry",
"a 2d boundary representation geometry model by lines and splines", "a 2d boundary representation geometry model by lines and splines",
@ -121,37 +137,20 @@ DLL_HEADER void ExportGeom2d(py::module &m)
seg->copyfrom = -1; seg->copyfrom = -1;
self.AppendSegment(seg); self.AppendSegment(seg);
}), py::arg("point_indices"), py::arg("leftdomain") = 1, py::arg("rightdomain") = py::int_(0)) }), py::arg("point_indices"), py::arg("leftdomain") = 1, py::arg("rightdomain") = py::int_(0))
//.def("AppendSegment", FunctionPointer([](SplineGeometry2d &self, int point_index1, int point_index2)//, int leftdomain, int rightdomain)
// {
// LineSeg<2> * l = new LineSeg<2>(self.GetPoint(point_index1), self.GetPoint(point_index2));
// SplineSegExt * seg = new SplineSegExt(*l);
// seg->leftdom = 1;// leftdomain;
// seg->rightdom = 0;// rightdomain;
// seg->hmax = 1e99;
// seg->reffak = 1;
// seg->copyfrom = -1;
// self.AppendSegment(seg);
// }))//, (py::arg("self"), py::arg("point_index1"), py::arg("point_index2"), py::arg("leftdomain") = 1, py::arg("rightdomain") = 0) )
//.def("AppendSegment", FunctionPointer([](SplineGeometry2d &self, int point_index1, int point_index2, int point_index3)//, int leftdomain, int rightdomain)
// {
// SplineSeg3<2> * seg3 = new SplineSeg3<2>(self.GetPoint(point_index1), self.GetPoint(point_index2), self.GetPoint(point_index3));
// SplineSegExt * seg = new SplineSegExt(*seg3);
// seg->leftdom = 1;// leftdomain;
// seg->rightdom = 0;// rightdomain;
// seg->hmax = 1e99;
// seg->reffak = 1;
// seg->copyfrom = -1;
// self.AppendSegment(seg);
// }))//, (py::arg("self"), py::arg("point_index1"), py::arg("point_index2"), py::arg("point_index3"), py::arg("leftdomain") = 1, py::arg("rightdomain") = 0 ) )
.def("SetMaterial", &SplineGeometry2d::SetMaterial) .def("SetMaterial", &SplineGeometry2d::SetMaterial)
.def("SetDomainMaxH", &SplineGeometry2d::SetDomainMaxh) .def("SetDomainMaxH", &SplineGeometry2d::SetDomainMaxh)
.def("GetBCName", [](SplineGeometry2d& self, size_t index) { return self.GetBCName(index); })
.def("GetNDomains", [](SplineGeometry2d& self) { return self.GetNDomains(); })
.def("GetNSplines", [](SplineGeometry2d& self) { return self.splines.Size(); })
.def("GetSpline", [](SplineGeometry2d& self, size_t index)
{ return shared_ptr<SplineSegExt>(&self.GetSpline(index), NOOP_Deleter); },
py::return_value_policy::reference_internal)
.def("GetNPoints", [](SplineGeometry2d& self) { return self.GetNP(); })
.def("GetPoint", [](SplineGeometry2d& self, size_t index) { return Point<2>(self.GetPoint(index)); })
.def("PlotData", FunctionPointer([](SplineGeometry2d &self) .def("PlotData", FunctionPointer([](SplineGeometry2d &self)
{ {

View File

@ -1,11 +1,11 @@
add_definitions(-DNGINTERFACE_EXPORTS) add_definitions(-DNGINTERFACE_EXPORTS)
add_library(gprim OBJECT add_library(gprim INTERFACE)
adtree.cpp geom2d.cpp geom3d.cpp geomfuncs.cpp set(sdir ${CMAKE_CURRENT_SOURCE_DIR})
geomtest3d.cpp transform3d.cpp spline.cpp splinegeometry.cpp target_sources(gprim INTERFACE
${sdir}/adtree.cpp ${sdir}/geom2d.cpp ${sdir}/geom3d.cpp ${sdir}/geomfuncs.cpp
${sdir}/geomtest3d.cpp ${sdir}/transform3d.cpp ${sdir}/spline.cpp ${sdir}/splinegeometry.cpp
) )
set_target_properties( gprim PROPERTIES POSITION_INDEPENDENT_CODE ON )
install(FILES install(FILES
adtree.hpp geom2d.hpp geom3d.hpp geomfuncs.hpp geomobjects2.hpp adtree.hpp geom2d.hpp geom3d.hpp geomfuncs.hpp geomobjects2.hpp
geomobjects.hpp geomops2.hpp geomops.hpp geomtest3d.hpp gprim.hpp geomobjects.hpp geomops2.hpp geomops.hpp geomtest3d.hpp gprim.hpp

View File

@ -2400,13 +2400,13 @@ namespace netgen
Array<T> & pis) const Array<T> & pis) const
{ {
Point<2*dim> tpmin, tpmax; Point<2*dim> tpmin, tpmax;
double tol = Tolerance();
for (size_t i = 0; i < dim; i++) for (size_t i = 0; i < dim; i++)
{ {
tpmin(i) = boxpmin(i); tpmin(i) = boxpmin(i);
tpmax(i) = pmax(i); tpmax(i) = pmax(i)+tol;
tpmin(i+dim) = pmin(i); tpmin(i+dim) = pmin(i)-tol;
tpmax(i+dim) = boxpmax(i); tpmax(i+dim) = boxpmax(i);
} }

View File

@ -570,9 +570,9 @@ public:
{ tree->DeleteElement(pi); } { tree->DeleteElement(pi); }
void GetIntersecting (const Point<dim> & pmin, const Point<dim> & pmax, void GetIntersecting (const Point<dim> & pmin, const Point<dim> & pmax,
Array<T> & pis) const; Array<T> & pis) const;
double Tolerance() const { return 1e-7 * Dist(boxpmax, boxpmin); } // single precision
// const T_ADTree<2*dim> & Tree() const { return *tree; }; const auto & Tree() const { return *tree; };
// T_ADTree<2*dim> & Tree() { return *tree; }; auto & Tree() { return *tree; };
}; };
} }

View File

@ -270,7 +270,8 @@ namespace netgen
for (int i = 0; i < D; i++) for (int i = 0; i < D; i++)
{ {
if (p(i) < pmin(i)) pmin(i) = p(i); if (p(i) < pmin(i)) pmin(i) = p(i);
else if (p(i) > pmax(i)) pmax(i) = p(i); /* else */ if (p(i) > pmax(i)) pmax(i) = p(i);
// optimization invalid for empty-box !
} }
} }

View File

@ -32,21 +32,25 @@
// max number of nodes per element // max number of nodes per element
#define NG_ELEMENT_MAXPOINTS 12 #define NG_ELEMENT_MAXPOINTS 20
// max number of nodes per surface element // max number of nodes per surface element
#define NG_SURFACE_ELEMENT_MAXPOINTS 8 #define NG_SURFACE_ELEMENT_MAXPOINTS 8
#ifndef PARALLEL
typedef int MPI_Comm;
#endif
namespace netgen { extern DLL_HEADER MPI_Comm ng_comm; }
// implemented element types: // implemented element types:
enum NG_ELEMENT_TYPE { enum NG_ELEMENT_TYPE {
NG_PNT = 0, NG_PNT = 0,
NG_SEGM = 1, NG_SEGM3 = 2, NG_SEGM = 1, NG_SEGM3 = 2,
NG_TRIG = 10, NG_QUAD=11, NG_TRIG6 = 12, NG_QUAD6 = 13, NG_TRIG = 10, NG_QUAD=11, NG_TRIG6 = 12, NG_QUAD6 = 13, NG_QUAD8 = 14,
NG_TET = 20, NG_TET10 = 21, NG_TET = 20, NG_TET10 = 21,
NG_PYRAMID = 22, NG_PRISM = 23, NG_PRISM12 = 24, NG_PYRAMID = 22, NG_PRISM = 23, NG_PRISM12 = 24, NG_PRISM15 = 27, NG_PYRAMID13 = 28,
NG_HEX = 25 NG_HEX = 25, NG_HEX20 = 26
}; };
typedef double NG_POINT[3]; // coordinates typedef double NG_POINT[3]; // coordinates
@ -62,7 +66,7 @@ extern "C" {
DLL_HEADER void Ng_LoadGeometry (const char * filename); DLL_HEADER void Ng_LoadGeometry (const char * filename);
// load netgen mesh // load netgen mesh
DLL_HEADER void Ng_LoadMesh (const char * filename); DLL_HEADER void Ng_LoadMesh (const char * filename, MPI_Comm comm = netgen::ng_comm);
// load netgen mesh // load netgen mesh
DLL_HEADER void Ng_LoadMeshFromString (const char * mesh_as_string); DLL_HEADER void Ng_LoadMeshFromString (const char * mesh_as_string);
@ -312,7 +316,7 @@ extern "C" {
struct Ng_SolutionData struct Ng_SolutionData
{ {
string name; // name of gridfunction std::string name; // name of gridfunction
double * data; // solution values double * data; // solution values
int components; // relevant (double) components in solution vector int components; // relevant (double) components in solution vector
int dist; // # doubles per entry alignment! int dist; // # doubles per entry alignment!
@ -333,7 +337,7 @@ extern "C" {
// redraw // redraw
DLL_HEADER void Ng_Redraw(bool blocking = false); DLL_HEADER void Ng_Redraw(bool blocking = false);
/// ///
DLL_HEADER void Ng_TclCmd(string cmd); DLL_HEADER void Ng_TclCmd(std::string cmd);
/// ///
DLL_HEADER void Ng_SetMouseEventHandler (netgen::MouseEventHandler * handler); DLL_HEADER void Ng_SetMouseEventHandler (netgen::MouseEventHandler * handler);
/// ///

View File

@ -12,8 +12,31 @@
C++ interface to Netgen C++ interface to Netgen
*/ */
#ifndef NGINTERFACE
// implemented element types:
enum NG_ELEMENT_TYPE {
NG_PNT = 0,
NG_SEGM = 1, NG_SEGM3 = 2,
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
};
enum NG_REFINEMENT_TYPE { NG_REFINE_H = 0, NG_REFINE_P = 1, NG_REFINE_HP = 2 };
#endif
#ifndef PARALLEL
typedef int MPI_Comm;
#endif
namespace netgen namespace netgen
{ {
using namespace std;
using namespace ngcore;
extern DLL_HEADER MPI_Comm ng_comm;
static constexpr int POINTINDEX_BASE = 1; static constexpr int POINTINDEX_BASE = 1;
@ -45,6 +68,19 @@ namespace netgen
T * Release() { T * hd = data; data = nullptr; return hd; } T * Release() { T * hd = data; data = nullptr; return hd; }
}; };
template <typename T, int S>
class Ng_BufferMS
{
size_t s;
T data[S];
public:
Ng_BufferMS (size_t as) : s(as) { ; }
size_t Size() const { return s; }
T & operator[] (size_t i) { return data[i]; }
T operator[] (size_t i) const { return data[i]; }
};
class Ng_Element class Ng_Element
{ {
@ -185,6 +221,7 @@ namespace netgen
int operator[] (size_t i) const { return ptr[i]-POINTINDEX_BASE; } int operator[] (size_t i) const { return ptr[i]-POINTINDEX_BASE; }
}; };
/*
class Ng_Edges class Ng_Edges
{ {
public: public:
@ -194,11 +231,11 @@ namespace netgen
size_t Size() const { return ned; } size_t Size() const { return ned; }
int operator[] (size_t i) const { return ptr[i]-1; } int operator[] (size_t i) const { return ptr[i]-1; }
}; };
*/
public: public:
Ng_Vertices vertices; Ng_Vertices vertices;
Ng_Edges edges; // Ng_Edges edges;
int surface_el; // -1 if face not on surface int surface_el; // -1 if face not on surface
}; };
@ -224,17 +261,24 @@ namespace netgen
public: public:
// Ngx_Mesh () { ; } // Ngx_Mesh () { ; }
// Ngx_Mesh(class Mesh * amesh) : mesh(amesh) { ; } // Ngx_Mesh(class Mesh * amesh) : mesh(amesh) { ; }
Ngx_Mesh(shared_ptr<Mesh> amesh = NULL);
void LoadMesh (const string & filename);
void LoadMesh (istream & str); /** reuse a netgen-mesh **/
Ngx_Mesh (shared_ptr<Mesh> amesh);
/** load a new mesh **/
Ngx_Mesh (string filename, MPI_Comm acomm = netgen::ng_comm);
void LoadMesh (const string & filename, MPI_Comm comm = netgen::ng_comm);
void LoadMesh (istream & str, MPI_Comm comm = netgen::ng_comm);
void SaveMesh (ostream & str) const; void SaveMesh (ostream & str) const;
void UpdateTopology (); void UpdateTopology ();
void DoArchive (Archive & archive); void DoArchive (Archive & archive);
MPI_Comm GetCommunicator() const;
virtual ~Ngx_Mesh(); virtual ~Ngx_Mesh();
bool Valid () { return mesh != NULL; } bool Valid () const { return mesh != NULL; }
int GetDimension() const; int GetDimension() const;
int GetNLevels() const; int GetNLevels() const;
@ -283,6 +327,7 @@ namespace netgen
template <int DIM> template <int DIM>
const Ng_Node<DIM> GetNode (int nr) const; const Ng_Node<DIM> GetNode (int nr) const;
Ng_BufferMS<int,4> GetFaceEdges (int fnr) const;
template <int DIM> template <int DIM>
int GetNNodes (); int GetNNodes ();
@ -291,11 +336,17 @@ namespace netgen
// 3D only // 3D only
// std::pair<int,int> GetBoundaryNeighbouringDomains (int bnr); // std::pair<int,int> GetBoundaryNeighbouringDomains (int bnr);
template <int DIM>
void SetRefinementFlag (size_t elnr, bool flag);
void Curve (int order); void Curve (int order);
void Refine (NG_REFINEMENT_TYPE reftype, void Refine (NG_REFINEMENT_TYPE reftype,
void (*taskmanager)(function<void(int,int)>) = &DummyTaskManager2, void (*taskmanager)(function<void(int,int)>) = &DummyTaskManager2,
void (*tracer)(string, bool) = &DummyTracer2); void (*tracer)(string, bool) = &DummyTracer2);
int GetHPElementLevel (int ei, int dir) const;
void GetParentNodes (int ni, int * parents) const; void GetParentNodes (int ni, int * parents) const;
int GetParentElement (int ei) const; int GetParentElement (int ei) const;
int GetParentSElement (int ei) const; int GetParentSElement (int ei) const;
@ -312,13 +363,33 @@ namespace netgen
int * const indices = NULL, int numind = 0) const; int * const indices = NULL, int numind = 0) const;
#ifdef PARALLEL // for MPI-parallel
std::tuple<int,int*> GetDistantProcs (int nodetype, int locnum) const; std::tuple<int,int*> GetDistantProcs (int nodetype, int locnum) const;
#endif
shared_ptr<Mesh> GetMesh () const { return mesh; } shared_ptr<Mesh> GetMesh () const { return mesh; }
shared_ptr<Mesh> SelectMesh () const; shared_ptr<Mesh> SelectMesh () const;
inline auto GetTimeStamp() const; inline auto GetTimeStamp() const;
// 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);
size_t GetNP() const;
int GetSurfaceElementSurfaceNumber (size_t ei) const;
int GetSurfaceElementFDNumber (size_t ei) const;
int GetElementOrder (int enr) const;
void GetElementOrders (int enr, int * ox, int * oy, int * oz) const;
void SetElementOrder (int enr, int order);
void SetElementOrders (int enr, int ox, int oy, int oz);
int GetSurfaceElementOrder (int enr) const;
void GetSurfaceElementOrders (int enr, int * ox, int * oy) const;
void SetSurfaceElementOrder (int enr, int order);
void SetSurfaceElementOrders (int enr, int ox, int oy);
int GetClusterRepVertex (int vi) const;
int GetClusterRepEdge (int edi) const;
int GetClusterRepFace (int fai) const;
int GetClusterRepElement (int eli) const;
}; };

View File

@ -65,6 +65,13 @@ NGX_INLINE DLL_HEADER Ng_Element Ngx_Mesh :: GetElement<0> (size_t nr) const
ret.facets.base = 1; ret.facets.base = 1;
ret.facets.ptr = (int*)&el.pnum; ret.facets.ptr = (int*)&el.pnum;
if (mesh->GetDimension() == 1)
ret.mat = mesh->GetBCNamePtr(el.index-1);
else if (mesh->GetDimension() == 2)
ret.mat = mesh->GetCD2NamePtr(el.index-1);
else
ret.mat = mesh->GetCD3NamePtr(el.index-1);
return ret; return ret;
} }

View File

@ -7,11 +7,9 @@ add_library(interface ${NG_LIB_TYPE}
wuchemnitz.cpp writegmsh2.cpp writeOpenFOAM15x.cpp wuchemnitz.cpp writegmsh2.cpp writeOpenFOAM15x.cpp
) )
if(NOT WIN32) target_link_libraries(interface mesh csg geom2d)
target_link_libraries(interface mesh csg geom2d) target_link_libraries(interface visual)
target_link_libraries(interface visual) install( TARGETS interface ${NG_INSTALL_DIR})
install( TARGETS interface ${NG_INSTALL_DIR})
endif(NOT WIN32)
install(FILES install(FILES
writeuser.hpp writeuser.hpp

View File

@ -117,14 +117,10 @@ void Ng_LoadMeshFromStream ( istream & input )
} }
void Ng_LoadMesh (const char * filename, MPI_Comm comm)
void Ng_LoadMesh (const char * filename)
{ {
#ifdef PARALLEL int id = MyMPI_GetId(comm);
MPI_Comm_size(MPI_COMM_WORLD, &ntasks); int ntasks = MyMPI_GetNTasks(comm);
MPI_Comm_rank(MPI_COMM_WORLD, &id);
#endif
{ {
ifstream infile(filename); ifstream infile(filename);
@ -134,11 +130,10 @@ void Ng_LoadMesh (const char * filename)
if ( string(filename).find(".vol") == string::npos ) if ( string(filename).find(".vol") == string::npos )
{ {
#ifdef PARALLEL
if(ntasks>1) if(ntasks>1)
throw NgException("Not sure what to do with this?? Does this work with MPI??"); throw NgException("Not sure what to do with this?? Does this work with MPI??");
#endif
mesh.reset (new Mesh()); mesh.reset (new Mesh());
mesh->SetCommunicator(comm);
ReadFile(*mesh,filename); ReadFile(*mesh,filename);
//mesh->SetGlobalH (mparam.maxh); //mesh->SetGlobalH (mparam.maxh);
//mesh->CalcLocalH(); //mesh->CalcLocalH();
@ -146,12 +141,10 @@ void Ng_LoadMesh (const char * filename)
} }
istream * infile; istream * infile;
char* buf; // for distributing geometry! Array<char> buf; // for distributing geometry!
int strs; int strs;
#ifdef PARALLEL
if( id == 0) { if( id == 0) {
#endif
string fn(filename); string fn(filename);
if (fn.substr (fn.length()-3, 3) == ".gz") if (fn.substr (fn.length()-3, 3) == ".gz")
@ -159,6 +152,7 @@ void Ng_LoadMesh (const char * filename)
else else
infile = new ifstream (filename); infile = new ifstream (filename);
mesh.reset (new Mesh()); mesh.reset (new Mesh());
mesh->SetCommunicator(comm);
mesh -> Load(*infile); mesh -> Load(*infile);
SetGlobalMesh (mesh); SetGlobalMesh (mesh);
@ -168,12 +162,12 @@ void Ng_LoadMesh (const char * filename)
geom_part << infile->rdbuf(); geom_part << infile->rdbuf();
string geom_part_string = geom_part.str(); string geom_part_string = geom_part.str();
strs = geom_part_string.size(); strs = geom_part_string.size();
buf = new char[strs]; // buf = new char[strs];
memcpy(buf, geom_part_string.c_str(), strs*sizeof(char)); buf.SetSize(strs);
memcpy(&buf[0], geom_part_string.c_str(), strs*sizeof(char));
} }
delete infile; delete infile;
#ifdef PARALLEL
if (ntasks > 1) if (ntasks > 1)
{ {
@ -239,21 +233,21 @@ void Ng_LoadMesh (const char * filename)
} // id==0 end } // id==0 end
else { else {
mesh.reset (new Mesh()); mesh.reset (new Mesh());
mesh->SetCommunicator(comm);
SetGlobalMesh (mesh); SetGlobalMesh (mesh);
mesh->SendRecvMesh(); mesh->SendRecvMesh();
} }
if(!ng_geometry && ntasks>1) { if(!ng_geometry && ntasks>1) {
/** Scatter the geometry-string **/ #ifdef PARALLEL
MPI_Bcast(&strs, 1, MPI_INT, 0, MPI_COMM_WORLD); /** Scatter the geometry-string (no dummy-implementation in mpi_interface) **/
if(id!=0) buf = new char[strs]; MyMPI_Bcast(buf, comm);
MPI_Bcast(buf, strs, MPI_CHAR, 0, MPI_COMM_WORLD);
}
#endif #endif
}
if(!ng_geometry) { if(!ng_geometry) {
infile = new istringstream(string((const char*)buf, (size_t)strs)); infile = new istringstream(string((const char*)&buf[0], (size_t)strs));
delete[] buf; // delete[] buf;
for (int i = 0; i < geometryregister.Size(); i++) for (int i = 0; i < geometryregister.Size(); i++)
{ {
NetgenGeometry * hgeom = geometryregister[i]->LoadFromMeshFile (*infile); NetgenGeometry * hgeom = geometryregister[i]->LoadFromMeshFile (*infile);

View File

@ -31,39 +31,39 @@ namespace netgen
return hmesh; return hmesh;
} }
Ngx_Mesh :: Ngx_Mesh (shared_ptr<Mesh> amesh) Ngx_Mesh :: Ngx_Mesh (shared_ptr<Mesh> amesh)
{ { mesh = amesh ? amesh : netgen::mesh; }
if (amesh) Ngx_Mesh :: Ngx_Mesh (string filename, MPI_Comm acomm)
mesh = amesh; { LoadMesh(filename, acomm); }
else
mesh = netgen::mesh;
}
Ngx_Mesh * LoadMesh (const string & filename) Ngx_Mesh * LoadMesh (const string & filename, MPI_Comm comm = netgen::ng_comm)
{ {
netgen::mesh.reset(); netgen::mesh.reset();
Ng_LoadMesh (filename.c_str()); Ng_LoadMesh (filename.c_str(), comm);
return new Ngx_Mesh (netgen::mesh); return new Ngx_Mesh (netgen::mesh);
} }
void Ngx_Mesh :: LoadMesh (const string & filename) void Ngx_Mesh :: LoadMesh (const string & filename, MPI_Comm comm)
{ {
netgen::mesh.reset(); netgen::mesh.reset();
Ng_LoadMesh (filename.c_str()); Ng_LoadMesh (filename.c_str(), comm);
// mesh = move(netgen::mesh); // mesh = move(netgen::mesh);
mesh = netgen::mesh; mesh = netgen::mesh;
} }
void Ngx_Mesh :: LoadMesh (istream & ist) void Ngx_Mesh :: LoadMesh (istream & ist, MPI_Comm comm)
{ {
netgen::mesh = make_shared<Mesh>(); netgen::mesh = make_shared<Mesh>();
netgen::mesh->SetCommunicator(comm);
netgen::mesh -> Load (ist); netgen::mesh -> Load (ist);
// mesh = move(netgen::mesh); // mesh = move(netgen::mesh);
mesh = netgen::mesh; mesh = netgen::mesh;
SetGlobalMesh (mesh); SetGlobalMesh (mesh);
} }
MPI_Comm Ngx_Mesh :: GetCommunicator() const
{ return Valid() ? mesh->GetCommunicator() : MPI_COMM_NULL; }
void Ngx_Mesh :: SaveMesh (ostream & ost) const void Ngx_Mesh :: SaveMesh (ostream & ost) const
{ {
mesh -> Save (ost); mesh -> Save (ost);
@ -71,7 +71,12 @@ namespace netgen
void Ngx_Mesh :: DoArchive (Archive & archive) void Ngx_Mesh :: DoArchive (Archive & archive)
{ {
if (archive.Input()) mesh = make_shared<Mesh>(); #ifdef PARALLEL
if (archive.Input()) {
mesh = make_shared<Mesh>();
mesh->SetCommunicator(GetCommunicator());
}
#endif
mesh->DoArchive(archive); mesh->DoArchive(archive);
if (archive.Input()) if (archive.Input())
{ {
@ -675,6 +680,37 @@ namespace netgen
} }
int Ngx_Mesh :: GetHPElementLevel (int ei, int dir) const
{
ei++;
int level = -1;
if (mesh->hpelements)
{
int hpelnr = -1;
if (mesh->GetDimension() == 2)
hpelnr = mesh->SurfaceElement(ei).hp_elnr;
else
hpelnr = mesh->VolumeElement(ei).hp_elnr;
if (hpelnr < 0)
throw NgException("Ngx_Mesh::GetHPElementLevel: Wrong hp-element number!");
if (dir == 1)
level = (*mesh->hpelements)[hpelnr].levelx;
else if (dir == 2)
level = (*mesh->hpelements)[hpelnr].levely;
else if (dir == 3)
level = (*mesh->hpelements)[hpelnr].levelz;
else
throw NgException("Ngx_Mesh::GetHPElementLevel: dir has to be 1, 2 or 3!");
}
//else
// throw NgException("Ngx_Mesh::GetHPElementLevel only for HPRefinement implemented!");
return level;
}
int Ngx_Mesh :: GetParentElement (int ei) const int Ngx_Mesh :: GetParentElement (int ei) const
{ {
ei++; ei++;
@ -717,6 +753,16 @@ namespace netgen
return mesh->GetIdentifications().GetType(idnr+1); return mesh->GetIdentifications().GetType(idnr+1);
} }
Ng_BufferMS<int,4> Ngx_Mesh::GetFaceEdges (int fnr) const
{
const MeshTopology & topology = mesh->GetTopology();
ArrayMem<int,4> ia;
topology.GetFaceEdges (fnr+1, ia);
Ng_BufferMS<int,4> res(ia.Size());
for (size_t i = 0; i < ia.Size(); i++)
res[i] = ia[i]-1;
return res;
}
@ -1043,6 +1089,19 @@ namespace netgen
mesh->BuildCurvedElements(order); mesh->BuildCurvedElements(order);
} }
template <>
DLL_HEADER void Ngx_Mesh :: SetRefinementFlag<2> (size_t elnr, bool flag)
{
mesh->SurfaceElement(elnr+1).SetRefinementFlag(flag);
}
template <>
DLL_HEADER void Ngx_Mesh :: SetRefinementFlag<3> (size_t elnr, bool flag)
{
mesh->VolumeElement(elnr+1).SetRefinementFlag(flag);
}
void Ngx_Mesh :: Refine (NG_REFINEMENT_TYPE reftype, void Ngx_Mesh :: Refine (NG_REFINEMENT_TYPE reftype,
void (*task_manager)(function<void(int,int)>), void (*task_manager)(function<void(int,int)>),
Tracer tracer) Tracer tracer)
@ -1072,11 +1131,125 @@ namespace netgen
#ifdef PARALLEL
// just copied with redesign
size_t Ngx_Mesh::GetNP() const
{
return mesh->GetNP();
}
int Ngx_Mesh::GetSurfaceElementSurfaceNumber (size_t ei) const
{
if (mesh->GetDimension() == 3)
return mesh->GetFaceDescriptor(mesh->SurfaceElement(ei).GetIndex()).SurfNr();
else
return mesh->LineSegment(ei).si;
}
int Ngx_Mesh::GetSurfaceElementFDNumber (size_t ei) const
{
if (mesh->GetDimension() == 3)
return mesh->SurfaceElement(ei).GetIndex();
else
return -1;
}
void Ngx_Mesh::HPRefinement (int levels, double parameter, bool setorders,
bool ref_level)
{
NgLock meshlock (mesh->MajorMutex(), true);
Refinement & ref = const_cast<Refinement&> (mesh->GetGeometry()->GetRefinement());
::netgen::HPRefinement (*mesh, &ref, levels, parameter, setorders, ref_level);
}
int Ngx_Mesh::GetElementOrder (int enr) const
{
if (mesh->GetDimension() == 3)
return mesh->VolumeElement(enr).GetOrder();
else
return mesh->SurfaceElement(enr).GetOrder();
}
void Ngx_Mesh::GetElementOrders (int enr, int * ox, int * oy, int * oz) const
{
if (mesh->GetDimension() == 3)
mesh->VolumeElement(enr).GetOrder(*ox, *oy, *oz);
else
mesh->SurfaceElement(enr).GetOrder(*ox, *oy, *oz);
}
void Ngx_Mesh::SetElementOrder (int enr, int order)
{
if (mesh->GetDimension() == 3)
return mesh->VolumeElement(enr).SetOrder(order);
else
return mesh->SurfaceElement(enr).SetOrder(order);
}
void Ngx_Mesh::SetElementOrders (int enr, int ox, int oy, int oz)
{
if (mesh->GetDimension() == 3)
mesh->VolumeElement(enr).SetOrder(ox, oy, oz);
else
mesh->SurfaceElement(enr).SetOrder(ox, oy);
}
int Ngx_Mesh::GetSurfaceElementOrder (int enr) const
{
return mesh->SurfaceElement(enr).GetOrder();
}
int Ngx_Mesh::GetClusterRepVertex (int pi) const
{
return mesh->GetClusters().GetVertexRepresentant(pi);
}
int Ngx_Mesh::GetClusterRepEdge (int pi) const
{
return mesh->GetClusters().GetEdgeRepresentant(pi);
}
int Ngx_Mesh::GetClusterRepFace (int pi) const
{
return mesh->GetClusters().GetFaceRepresentant(pi);
}
int Ngx_Mesh::GetClusterRepElement (int pi) const
{
return mesh->GetClusters().GetElementRepresentant(pi);
}
//HERBERT: falsche Anzahl von Argumenten
//void Ngx_Mesh::GetSurfaceElementOrders (int enr, int * ox, int * oy, int * oz)
void Ngx_Mesh::GetSurfaceElementOrders (int enr, int * ox, int * oy) const
{
int d;
mesh->SurfaceElement(enr).GetOrder(*ox, *oy, d);
}
void Ngx_Mesh::SetSurfaceElementOrder (int enr, int order)
{
return mesh->SurfaceElement(enr).SetOrder(order);
}
void Ngx_Mesh::SetSurfaceElementOrders (int enr, int ox, int oy)
{
mesh->SurfaceElement(enr).SetOrder(ox, oy);
}
std::tuple<int,int*> Ngx_Mesh :: GetDistantProcs (int nodetype, int locnum) const std::tuple<int,int*> Ngx_Mesh :: GetDistantProcs (int nodetype, int locnum) const
{ {
#ifdef PARALLEL
switch (nodetype) switch (nodetype)
{ {
case 0: case 0:
@ -1097,10 +1270,10 @@ namespace netgen
default: default:
return std::tuple<int,int*>(0,nullptr); return std::tuple<int,int*>(0,nullptr);
} }
} #else
return std::tuple<int,int*>(0,nullptr);
#endif #endif
}
} }

View File

@ -1,8 +1,8 @@
add_library( la OBJECT add_library( la INTERFACE )
densemat.cpp polynomial.cpp bfgs.cpp linopt.cpp linsearch.cpp set(sdir ${CMAKE_CURRENT_SOURCE_DIR})
) target_sources( la INTERFACE
${sdir}/densemat.cpp ${sdir}/polynomial.cpp ${sdir}/bfgs.cpp ${sdir}/linopt.cpp ${sdir}/linsearch.cpp
set_target_properties(la PROPERTIES POSITION_INDEPENDENT_CODE ON ) )
install(FILES install(FILES
densemat.hpp linalg.hpp opti.hpp densemat.hpp linalg.hpp opti.hpp

View File

@ -1,12 +1,4 @@
add_definitions(-DNGINTERFACE_EXPORTS) add_definitions(-DNGINTERFACE_EXPORTS)
if(NOT WIN32)
set(mesh_object_libs
$<TARGET_OBJECTS:la>
$<TARGET_OBJECTS:gprim>
$<TARGET_OBJECTS:gen>
)
endif(NOT WIN32)
add_library(mesh ${NG_LIB_TYPE} add_library(mesh ${NG_LIB_TYPE}
adfront2.cpp adfront3.cpp bisect.cpp boundarylayer.cpp adfront2.cpp adfront3.cpp bisect.cpp boundarylayer.cpp
clusters.cpp curvedelems.cpp delaunay.cpp delaunay2d.cpp clusters.cpp curvedelems.cpp delaunay.cpp delaunay2d.cpp
@ -29,10 +21,10 @@ if(APPLE)
set_target_properties( mesh PROPERTIES SUFFIX ".so") set_target_properties( mesh PROPERTIES SUFFIX ".so")
endif(APPLE) endif(APPLE)
if(NOT WIN32) target_link_libraries( mesh PUBLIC ngcore PRIVATE gprim la gen )
target_link_libraries( mesh ngcore ${ZLIB_LIBRARIES} ${MPI_CXX_LIBRARIES} ${PYTHON_LIBRARIES} ${METIS_LIBRARY})
install( TARGETS mesh ${NG_INSTALL_DIR}) target_link_libraries( mesh PUBLIC ${ZLIB_LIBRARIES} ${MPI_CXX_LIBRARIES} ${PYTHON_LIBRARIES} ${METIS_LIBRARY})
endif(NOT WIN32) install( TARGETS mesh ${NG_INSTALL_DIR})
install(FILES install(FILES
adfront2.hpp adfront3.hpp basegeom.hpp bcfunctions.hpp bisect.hpp adfront2.hpp adfront3.hpp basegeom.hpp bcfunctions.hpp bisect.hpp

View File

@ -233,6 +233,7 @@ public:
/// ///
const MiniElement2d & GetFace (int i) const const MiniElement2d & GetFace (int i) const
{ return faces.Get(i).Face(); } { return faces.Get(i).Face(); }
const auto & Faces() const { return faces; }
/// ///
void Print () const; void Print () const;
/// ///

View File

@ -3398,6 +3398,7 @@ namespace netgen
size_t nsel = mtris.Size(); size_t nsel = mtris.Size();
NgProfiler::StartTimer (timer_bisecttrig); NgProfiler::StartTimer (timer_bisecttrig);
(*opt.tracer)("Bisect trigs", false);
for (size_t i = 0; i < nsel; i++) for (size_t i = 0; i < nsel; i++)
if (mtris[i].marked) if (mtris[i].marked)
{ {
@ -3440,7 +3441,7 @@ namespace netgen
} }
NgProfiler::StopTimer (timer_bisecttrig); NgProfiler::StopTimer (timer_bisecttrig);
(*opt.tracer)("Bisect trigs", true);
int nquad = mquads.Size(); int nquad = mquads.Size();
for (int i = 1; i <= nquad; i++) for (int i = 1; i <= nquad; i++)

View File

@ -553,14 +553,18 @@ namespace netgen
order = 1; order = 1;
MPI_Comm curve_comm;
#ifdef PARALLEL #ifdef PARALLEL
enum { MPI_TAG_CURVE = MPI_TAG_MESH+20 }; enum { MPI_TAG_CURVE = MPI_TAG_MESH+20 };
const ParallelMeshTopology & partop = mesh.GetParallelTopology (); const ParallelMeshTopology & partop = mesh.GetParallelTopology ();
MPI_Comm curve_comm; MPI_Comm_dup (mesh.GetCommunicator(), &curve_comm);
MPI_Comm_dup (MPI_COMM_WORLD, &curve_comm);
Array<int> procs; Array<int> procs;
#else
curve_comm = ng_comm; // dummy!
#endif #endif
int rank = MyMPI_GetId(curve_comm);
int ntasks = MyMPI_GetNTasks(curve_comm);
if (working) if (working)
order = aorder; order = aorder;
@ -1708,6 +1712,7 @@ namespace netgen
case TRIG : info.nv = 3; break; case TRIG : info.nv = 3; break;
case QUAD : info.nv = 4; break; case QUAD : info.nv = 4; break;
case TRIG6: info.nv = 6; break; case TRIG6: info.nv = 6; break;
case QUAD8 : info.nv = 8; break;
default: default:
cerr << "undef element in CalcSurfaceTrafo" << endl; cerr << "undef element in CalcSurfaceTrafo" << endl;
} }
@ -1928,6 +1933,24 @@ namespace netgen
break; break;
} }
case QUAD8:
{
auto x = xi(0), y = xi(1);
shapes(0) = (1-x)*(1-y);
shapes(1) = x*(1-y);
shapes(2) = x*y;
shapes(3) = (1-x)*y;
shapes(4) = 4*(1-x)*x*(1-y);
shapes(5) = 4*(1-x)*x*y;
shapes(6) = 4*(1-y)*y*(1-x);
shapes(7) = 4*(1-y)*y*x;
shapes(0) -= 0.5*(shapes(4)+shapes(6));
shapes(1) -= 0.5*(shapes(4)+shapes(7));
shapes(2) -= 0.5*(shapes(5)+shapes(7));
shapes(3) -= 0.5*(shapes(5)+shapes(6));
break;
}
default: default:
throw NgException("CurvedElements::CalcShape 2d, element type not handled"); throw NgException("CurvedElements::CalcShape 2d, element type not handled");
}; };
@ -2278,6 +2301,33 @@ namespace netgen
} }
break; break;
} }
case QUAD8:
{
// AutoDiff<2,T> lami[4] = { (1-x)*(1-y), x*(1-y), x*y, (1-x)*y };
AutoDiff<2,T> lami[8] =
{ (1-x)*(1-y),
x*(1-y),
x*y,
(1-x)*y,
4*(1-x)*x*(1-y),
4*(1-x)*x*y,
4*(1-y)*y*(1-x),
4*(1-y)*y*x };
lami[0] -= 0.5*(lami[4]+lami[6]);
lami[1] -= 0.5*(lami[4]+lami[7]);
lami[2] -= 0.5*(lami[5]+lami[7]);
lami[3] -= 0.5*(lami[5]+lami[6]);
for (int j = 0; j < 8; j++)
{
Point<3> p = mesh[el[j]];
for (int k = 0; k < DIM_SPACE; k++)
mapped_x[k] += p(k) * lami[j];
}
break;
}
default: default:
return false; return false;
} }
@ -2740,6 +2790,32 @@ namespace netgen
break; break;
} }
case PRISM15:
{
shapes = 0.0;
T x = xi(0);
T y = xi(1);
T z = xi(2);
T lam = 1-x-y;
T lamz = 1-z;
shapes[0] = (2*x*x-x) * (2*lamz*lamz-lamz);
shapes[1] = (2*y*y-y) * (2*lamz*lamz-lamz);
shapes[2] = (2*lam*lam-lam) * (2*lamz*lamz-lamz);
shapes[3] = (2*x*x-x) * (2*z*z-z);
shapes[4] = (2*y*y-y) * (2*z*z-z);
shapes[5] = (2*lam*lam-lam) * (2*z*z-z);
shapes[6] = 4 * x * y * (2*lamz*lamz-lamz);
shapes[7] = 4 * x * lam * (2*lamz*lamz-lamz);
shapes[8] = 4 * y * lam * (2*lamz*lamz-lamz);
shapes[9] = x * 4 * z * (1-z);
shapes[10] = y * 4 * z * (1-z);
shapes[11] = lam * 4 * z * (1-z);
shapes[12] = 4 * x * y * (2*z*z-z);
shapes[13] = 4 * x * lam * (2*z*z-z);
shapes[14] = 4 * y * lam * (2*z*z-z);
break;
}
case PYRAMID: case PYRAMID:
{ {
shapes = 0.0; shapes = 0.0;
@ -2789,6 +2865,29 @@ namespace netgen
break; break;
} }
case PYRAMID13:
{
shapes = 0.0;
T x = xi(0);
T y = xi(1);
T z = xi(2);
z *= 1-1e-12;
shapes[0] = (-z + z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (-2*x - z + 2)*(-2*y - z + 2))*(-0.5*x - 0.5*y - 0.5*z + 0.25);
shapes[1] = (0.5*x - 0.5*y - 0.25)*(-z - z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*x + z)*(-2*y - z + 2));
shapes[2] = (-z + z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*x + z)*(2*y + z))*(0.5*x + 0.5*y + 0.5*z - 0.75);
shapes[3] = (-0.5*x + 0.5*y - 0.25)*(-z - z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*y + z)*(-2*x - z + 2));
shapes[4] = z*(2*z - 1);
shapes[5] = 2*x*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2);
shapes[6] = 4*x*y*(-2*x - 2*z + 2)/(-2*z + 2);
shapes[7] = 2*y*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2);
shapes[8] = 4*x*y*(-2*y - 2*z + 2)/(-2*z + 2);
shapes[9] = z*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-z + 1);
shapes[10] = 2*x*z*(-2*y - 2*z + 2)/(-z + 1);
shapes[11] = 4*x*y*z/(-z + 1);
shapes[12] = 2*y*z*(-2*x - 2*z + 2)/(-z + 1);
break;
}
case HEX: case HEX:
{ {
shapes = 0.0; shapes = 0.0;
@ -2839,6 +2938,46 @@ namespace netgen
break; break;
}
case HEX20:
{
shapes = 0.0;
T x = xi(0);
T y = xi(1);
T z = xi(2);
shapes[0] = (1-x)*(1-y)*(1-z);
shapes[1] = x *(1-y)*(1-z);
shapes[2] = x * y *(1-z);
shapes[3] = (1-x)* y *(1-z);
shapes[4] = (1-x)*(1-y)*(z);
shapes[5] = x *(1-y)*(z);
shapes[6] = x * y *(z);
shapes[7] = (1-x)* y *(z);
T sigma[8]={(1-x)+(1-y)+(1-z),x+(1-y)+(1-z),x+y+(1-z),(1-x)+y+(1-z),
(1-x)+(1-y)+z,x+(1-y)+z,x+y+z,(1-x)+y+z};
static const int e[12][2] =
{
{ 0, 1 }, { 2, 3 }, { 3, 0 }, { 1, 2 },
{ 4, 5 }, { 6, 7 }, { 7, 4 }, { 5, 6 },
{ 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 },
};
for (int i = 0; i < 12; i++)
{
T lame = shapes[e[i][0]]+shapes[e[i][1]];
T xi = sigma[e[i][1]]-sigma[e[i][0]];
shapes[8+i] = (1-xi*xi)*lame;
}
for (int i = 0; i < 12; i++)
{
shapes[e[i][0]] -= 0.5 * shapes[8+i];
shapes[e[i][1]] -= 0.5 * shapes[8+i];
}
break;
} }
default: default:
@ -3210,6 +3349,36 @@ namespace netgen
} }
case PRISM15:
{
AutoDiff<3,T> x(xi(0), 0);
AutoDiff<3,T> y(xi(1), 1);
AutoDiff<3,T> z(xi(2), 2);
AutoDiff<3,T> ad[15];
AutoDiff<3,T> lam = 1-x-y;
AutoDiff<3,T> lamz = 1-z;
ad[0] = (2*x*x-x) * (2*lamz*lamz-lamz);
ad[1] = (2*y*y-y) * (2*lamz*lamz-lamz);
ad[2] = (2*lam*lam-lam) * (2*lamz*lamz-lamz);
ad[3] = (2*x*x-x) * (2*z*z-z);
ad[4] = (2*y*y-y) * (2*z*z-z);
ad[5] = (2*lam*lam-lam) * (2*z*z-z);
ad[6] = 4 * x * y * (2*lamz*lamz-lamz);
ad[7] = 4 * x * lam * (2*lamz*lamz-lamz);
ad[8] = 4 * y * lam * (2*lamz*lamz-lamz);
ad[9] = x * 4 * z * (1-z);
ad[10] = y * 4 * z * (1-z);
ad[11] = lam * 4 * z * (1-z);
ad[12] = 4 * x * y * (2*z*z-z);
ad[13] = 4 * x * lam * (2*z*z-z);
ad[14] = 4 * y * lam * (2*z*z-z);
for(int i=0; i<15; i++)
for(int j=0; j<3; j++)
dshapes(i,j) = ad[i].DValue(j);
break;
}
case PYRAMID: case PYRAMID:
{ {
// if (typeid(T) == typeid(SIMD<double>)) return; // if (typeid(T) == typeid(SIMD<double>)) return;
@ -3307,6 +3476,54 @@ namespace netgen
break; break;
} }
case PYRAMID13:
{
T x = xi(0);
T y = xi(1);
T z = xi(2);
z *= 1-1e-12;
dshapes(0,0) = 0.5*z - 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) - 0.5*(-2*x - z + 2)*(-2*y - z + 2) + (-0.5*x - 0.5*y - 0.5*z + 0.25)*(4*y + 2*z + 2*z*(2*y + z - 1)/(-z + 1) - 4);
dshapes(0,1) = 0.5*z - 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) - 0.5*(-2*x - z + 2)*(-2*y - z + 2) + (-0.5*x - 0.5*y - 0.5*z + 0.25)*(4*x + 2*z + 2*z*(2*x + z - 1)/(-z + 1) - 4);
dshapes(0,2) = 0.5*z - 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) - 0.5*(-2*x - z + 2)*(-2*y - z + 2) + (-0.5*x - 0.5*y - 0.5*z + 0.25)*(2*x + 2*y + 2*z + z*(2*x + z - 1)/(-z + 1) + z*(2*y + z - 1)/(-z + 1) + z*(2*x + z - 1)*(2*y + z - 1)/((-z + 1)*(-z + 1)) - 5 + (2*x + z - 1)*(2*y + z - 1)/(-z + 1));
dshapes(1,0) = -0.5*z - 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + 0.5*(2*x + z)*(-2*y - z + 2) + (0.5*x - 0.5*y - 0.25)*(-4*y - 2*z - 2*z*(2*y + z - 1)/(-z + 1) + 4);
dshapes(1,1) = 0.5*z + 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) - 0.5*(2*x + z)*(-2*y - z + 2) + (-4*x - 2*z - 2*z*(2*x + z - 1)/(-z + 1))*(0.5*x - 0.5*y - 0.25);
dshapes(1,2) = (0.5*x - 0.5*y - 0.25)*(-2*x - 2*y - 2*z - z*(2*x + z - 1)/(-z + 1) - z*(2*y + z - 1)/(-z + 1) - z*(2*x + z - 1)*(2*y + z - 1)/((-z + 1)*(-z + 1)) + 1 - (2*x + z - 1)*(2*y + z - 1)/(-z + 1));
dshapes(2,0) = -0.5*z + 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + 0.5*(2*x + z)*(2*y + z) + (4*y + 2*z + 2*z*(2*y + z - 1)/(-z + 1))*(0.5*x + 0.5*y + 0.5*z - 0.75);
dshapes(2,1) = -0.5*z + 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + 0.5*(2*x + z)*(2*y + z) + (4*x + 2*z + 2*z*(2*x + z - 1)/(-z + 1))*(0.5*x + 0.5*y + 0.5*z - 0.75);
dshapes(2,2) = -0.5*z + 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + 0.5*(2*x + z)*(2*y + z) + (0.5*x + 0.5*y + 0.5*z - 0.75)*(2*x + 2*y + 2*z + z*(2*x + z - 1)/(-z + 1) + z*(2*y + z - 1)/(-z + 1) + z*(2*x + z - 1)*(2*y + z - 1)/((-z + 1)*(-z + 1)) - 1 + (2*x + z - 1)*(2*y + z - 1)/(-z + 1));
dshapes(3,0) = 0.5*z + 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) - 0.5*(2*y + z)*(-2*x - z + 2) + (-0.5*x + 0.5*y - 0.25)*(-4*y - 2*z - 2*z*(2*y + z - 1)/(-z + 1));
dshapes(3,1) = -0.5*z - 0.5*z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + 0.5*(2*y + z)*(-2*x - z + 2) + (-0.5*x + 0.5*y - 0.25)*(-4*x - 2*z - 2*z*(2*x + z - 1)/(-z + 1) + 4);
dshapes(3,2) = (-0.5*x + 0.5*y - 0.25)*(-2*x - 2*y - 2*z - z*(2*x + z - 1)/(-z + 1) - z*(2*y + z - 1)/(-z + 1) - z*(2*x + z - 1)*(2*y + z - 1)/((-z + 1)*(-z + 1)) + 1 - (2*x + z - 1)*(2*y + z - 1)/(-z + 1));
dshapes(4,0) = 0;
dshapes(4,1) = 0;
dshapes(4,2) = 4*z - 1;
dshapes(5,0) = -4*x*(-2*y - 2*z + 2)/(-2*z + 2) + 2*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2);
dshapes(5,1) = -4*x*(-2*x - 2*z + 2)/(-2*z + 2);
dshapes(5,2) = -4*x*(-2*x - 2*z + 2)/(-2*z + 2) - 4*x*(-2*y - 2*z + 2)/(-2*z + 2) + 4*x*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/((-2*z + 2)*(-2*z + 2));
dshapes(6,0) = -8*x*y/(-2*z + 2) + 4*y*(-2*x - 2*z + 2)/(-2*z + 2);
dshapes(6,1) = 4*x*(-2*x - 2*z + 2)/(-2*z + 2);
dshapes(6,2) = -8*x*y/(-2*z + 2) + 8*x*y*(-2*x - 2*z + 2)/((-2*z + 2)*(-2*z + 2));
dshapes(7,0) = -4*y*(-2*y - 2*z + 2)/(-2*z + 2);
dshapes(7,1) = -4*y*(-2*x - 2*z + 2)/(-2*z + 2) + 2*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2);
dshapes(7,2) = -4*y*(-2*x - 2*z + 2)/(-2*z + 2) - 4*y*(-2*y - 2*z + 2)/(-2*z + 2) + 4*y*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/((-2*z + 2)*(-2*z + 2));
dshapes(8,0) = 4*y*(-2*y - 2*z + 2)/(-2*z + 2);
dshapes(8,1) = -8*x*y/(-2*z + 2) + 4*x*(-2*y - 2*z + 2)/(-2*z + 2);
dshapes(8,2) = -8*x*y/(-2*z + 2) + 8*x*y*(-2*y - 2*z + 2)/((-2*z + 2)*(-2*z + 2));
dshapes(9,0) = -2*z*(-2*y - 2*z + 2)/(-z + 1);
dshapes(9,1) = -2*z*(-2*x - 2*z + 2)/(-z + 1);
dshapes(9,2) = -2*z*(-2*x - 2*z + 2)/(-z + 1) - 2*z*(-2*y - 2*z + 2)/(-z + 1) + z*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/((-z + 1)*(-z + 1)) + (-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-z + 1);
dshapes(10,0) = 2*z*(-2*y - 2*z + 2)/(-z + 1);
dshapes(10,1) = -4*x*z/(-z + 1);
dshapes(10,2) = -4*x*z/(-z + 1) + 2*x*z*(-2*y - 2*z + 2)/((-z + 1)*(-z + 1)) + 2*x*(-2*y - 2*z + 2)/(-z + 1);
dshapes(11,0) = 4*y*z/(-z + 1);
dshapes(11,1) = 4*x*z/(-z + 1);
dshapes(11,2) = 4*x*y*z/((-z + 1)*(-z + 1)) + 4*x*y/(-z + 1);
dshapes(12,0) = -4*y*z/(-z + 1);
dshapes(12,1) = 2*z*(-2*x - 2*z + 2)/(-z + 1);
dshapes(12,2) = -4*y*z/(-z + 1) + 2*y*z*(-2*x - 2*z + 2)/((-z + 1)*(-z + 1)) + 2*y*(-2*x - 2*z + 2)/(-z + 1);
break;
}
case HEX: case HEX:
{ {
// if (typeid(T) == typeid(SIMD<double>)) return; // if (typeid(T) == typeid(SIMD<double>)) return;
@ -3443,12 +3660,49 @@ namespace netgen
*testout << "quad, num dshape = " << endl << dshapes << endl; *testout << "quad, num dshape = " << endl << dshapes << endl;
*/ */
break; break;
break;
} }
case HEX20:
{
AutoDiff<3,T> x(xi(0), 0);
AutoDiff<3,T> y(xi(1), 1);
AutoDiff<3,T> z(xi(2), 2);
AutoDiff<3,T> ad[20];
ad[0] = (1-x)*(1-y)*(1-z);
ad[1] = x *(1-y)*(1-z);
ad[2] = x * y *(1-z);
ad[3] = (1-x)* y *(1-z);
ad[4] = (1-x)*(1-y)*(z);
ad[5] = x *(1-y)*(z);
ad[6] = x * y *(z);
ad[7] = (1-x)* y *(z);
AutoDiff<3,T> sigma[8]={(1-x)+(1-y)+(1-z),x+(1-y)+(1-z),x+y+(1-z),(1-x)+y+(1-z),
(1-x)+(1-y)+z,x+(1-y)+z,x+y+z,(1-x)+y+z};
static const int e[12][2] =
{
{ 0, 1 }, { 2, 3 }, { 3, 0 }, { 1, 2 },
{ 4, 5 }, { 6, 7 }, { 7, 4 }, { 5, 6 },
{ 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 },
};
for (int i = 0; i < 12; i++)
{
auto lame = ad[e[i][0]]+ad[e[i][1]];
auto xi = sigma[e[i][1]]-sigma[e[i][0]];
ad[8+i] = (1-xi*xi)*lame;
}
for (int i = 0; i < 12; i++)
{
ad[e[i][0]] -= 0.5 * ad[8+i];
ad[e[i][1]] -= 0.5 * ad[8+i];
}
for (int i = 0; i < 20; i++)
for (int j = 0; j < 3; j++)
dshapes(i,j) = ad[i].DValue(j);
break;
}
default: default:
throw NgException("CurvedElements::CalcDShape 3d, element type not handled"); throw NgException("CurvedElements::CalcDShape 3d, element type not handled");
} }
@ -3854,8 +4108,9 @@ namespace netgen
case TRIG : info.nv = 3; break; case TRIG : info.nv = 3; break;
case QUAD : info.nv = 4; break; case QUAD : info.nv = 4; break;
case TRIG6: info.nv = 6; break; case TRIG6: info.nv = 6; break;
case QUAD8 : info.nv = 8; break;
default: default:
cerr << "undef element in CalcMultPointSurfaceTrao" << endl; cerr << "undef element in CalcMultPointSurfaceTrafo" << endl;
} }
info.ndof = info.nv; info.ndof = info.nv;

View File

@ -6,7 +6,6 @@
namespace netgen namespace netgen
{ {
static const int deltetfaces[][3] = static const int deltetfaces[][3] =
{ { 1, 2, 3 }, { { 1, 2, 3 },
{ 2, 0, 3 }, { 2, 0, 3 },
@ -14,10 +13,6 @@ namespace netgen
{ 1, 0, 2 } }; { 1, 0, 2 } };
class DelaunayTet class DelaunayTet
{ {
PointIndex pnums[4]; PointIndex pnums[4];
@ -41,9 +36,6 @@ namespace netgen
PointIndex & operator[] (int i) { return pnums[i]; } PointIndex & operator[] (int i) { return pnums[i]; }
PointIndex operator[] (int i) const { return pnums[i]; } PointIndex operator[] (int i) const { return pnums[i]; }
int & NB1(int i) { return nb[i-1]; }
int NB1(int i) const { return nb[i-1]; }
int & NB(int i) { return nb[i]; } int & NB(int i) { return nb[i]; }
int NB(int i) const { return nb[i]; } int NB(int i) const { return nb[i]; }
@ -58,27 +50,6 @@ namespace netgen
return 3; return 3;
} }
void GetFace1 (int i, INDEX_3 & face) const
{
face.I(1) = pnums[deltetfaces[i-1][0]];
face.I(2) = pnums[deltetfaces[i-1][1]];
face.I(3) = pnums[deltetfaces[i-1][2]];
}
void GetFace (int i, INDEX_3 & face) const
{
face.I(1) = pnums[deltetfaces[i][0]];
face.I(2) = pnums[deltetfaces[i][1]];
face.I(3) = pnums[deltetfaces[i][2]];
}
INDEX_3 GetFace1 (int i) const
{
return INDEX_3 (pnums[deltetfaces[i-1][0]],
pnums[deltetfaces[i-1][1]],
pnums[deltetfaces[i-1][2]]);
}
INDEX_3 GetFace (int i) const INDEX_3 GetFace (int i) const
{ {
return INDEX_3 (pnums[deltetfaces[i][0]], return INDEX_3 (pnums[deltetfaces[i][0]],
@ -86,12 +57,12 @@ namespace netgen
pnums[deltetfaces[i][2]]); pnums[deltetfaces[i][2]]);
} }
void GetFace1 (int i, Element2d & face) const void GetFace (int i, Element2d & face) const
{ {
// face.SetType(TRIG); // face.SetType(TRIG);
face[0] = pnums[deltetfaces[i-1][0]]; face[0] = pnums[deltetfaces[i][0]];
face[1] = pnums[deltetfaces[i-1][1]]; face[1] = pnums[deltetfaces[i][1]];
face[2] = pnums[deltetfaces[i-1][2]]; face[2] = pnums[deltetfaces[i][2]];
} }
}; };
@ -101,8 +72,6 @@ namespace netgen
/* /*
Table to maintain neighbour elements Table to maintain neighbour elements
*/ */
@ -135,7 +104,7 @@ namespace netgen
// get neighbour of element elnr in direction fnr // get neighbour of element elnr in direction fnr
int GetNB (int elnr, int fnr) int GetNB (int elnr, int fnr)
{ {
return tets.Get(elnr).NB1(fnr); return tets.Get(elnr).NB(fnr);
} }
// //
@ -181,7 +150,6 @@ namespace netgen
/* /*
connected lists of cosphereical elements connected lists of cosphereical elements
*/ */
@ -253,24 +221,23 @@ namespace netgen
Array<int> & freelist, SphereList & list, Array<int> & freelist, SphereList & list,
IndexSet & insphere, IndexSet & closesphere) IndexSet & insphere, IndexSet & closesphere)
{ {
// static Timer t("Meshing3::AddDelaunayPoint"); RegionTimer reg(t);
/* /*
find any sphere, such that newp is contained in find any sphere, such that newp is contained in
*/ */
DelaunayTet el; DelaunayTet el;
int cfelind = -1; int cfelind = -1;
const Point<3> * pp[4]; const Point<3> * pp[4];
Point<3> pc; Point<3> pc;
double r2;
Point3d tpmin, tpmax; Point3d tpmin, tpmax;
tettree.GetIntersecting (newp, newp, treesearch); tettree.GetIntersecting (newp, newp, treesearch);
double quot,minquot(1e20); double quot,minquot(1e20);
for (int j = 0; j < treesearch.Size(); j++) for (auto jjj : treesearch)
{ {
int jjj = treesearch[j];
quot = Dist2 (centers.Get(jjj), newp) / radi2.Get(jjj); quot = Dist2 (centers.Get(jjj), newp) / radi2.Get(jjj);
if((cfelind == -1 || quot < 0.99*minquot) && quot < 1) if((cfelind == -1 || quot < 0.99*minquot) && quot < 1)
@ -284,46 +251,12 @@ namespace netgen
} }
/*
int i, j, k, l;
if (!felind)
{
cerr << "not in any sphere, 1" << endl;
// old, non tree search
double mindist = 1e10;
for (j = 1; j <= tempels.Size(); j++)
{
if (tempels.Get(j).PNum(1))
{
double toofar =
Dist2 (centers.Get(j), newp) - radi2.Get(j);
if (toofar < mindist || toofar < 1e-7)
{
mindist = toofar;
cout << " dist2 = " << Dist2 (centers.Get(j), newp)
<< " radi2 = " << radi2.Get(j) << endl;
}
if (toofar < 0)
{
el = tempels.Get(j);
felind = j;
cout << "sphere found !" << endl;
break;
}
}
}
cout << "point is too far from sheres: " << mindist << endl;
}
*/
if (cfelind == -1) if (cfelind == -1)
{ {
PrintWarning ("Delaunay, point not in any sphere"); PrintWarning ("Delaunay, point not in any sphere");
return; return;
} }
/* /*
insphere: point is in sphere -> delete element insphere: point is in sphere -> delete element
closesphere: point is close to sphere -> considered for same center closesphere: point is close to sphere -> considered for same center
@ -376,7 +309,7 @@ namespace netgen
// check neighbour-tets // check neighbour-tets
for (int j = starti; j < nstarti; j++) for (int j = starti; j < nstarti; j++)
for (int k = 1; k <= 4; k++) for (int k = 0; k < 4; k++)
{ {
int helind = insphere.GetArray().Get(j); int helind = insphere.GetArray().Get(j);
int nbind = meshnb.GetNB (helind, k); int nbind = meshnb.GetNB (helind, k);
@ -404,61 +337,48 @@ namespace netgen
} }
else else
{ {
/* INDEX_3 i3 = tempels.Get(helind).GetFace (k);
Element2d face;
tempels.Get(helind).GetFace (k, face);
const Point3d & p1 = mesh.Point (face.PNum(1)); const Point<3> & p1 = mesh.Point ( PointIndex (i3.I1()) );
const Point3d & p2 = mesh.Point (face[1]); const Point<3> & p2 = mesh.Point ( PointIndex (i3.I2()) );
const Point3d & p3 = mesh.Point (face[2]); const Point<3> & p3 = mesh.Point ( PointIndex (i3.I3()) );
*/
INDEX_3 i3 = tempels.Get(helind).GetFace (k-1); Vec<3> v1 = p2-p1;
Vec<3> v2 = p3-p1;
const Point3d & p1 = mesh.Point ( PointIndex (i3.I1()) ); Vec<3> n = Cross (v1, v2);
const Point3d & p2 = mesh.Point ( PointIndex (i3.I2()) );
const Point3d & p3 = mesh.Point ( PointIndex (i3.I3()) );
Vec3d v1(p1, p2);
Vec3d v2(p1, p3);
Vec3d n = Cross (v1, v2);
n /= n.Length(); n /= n.Length();
if (n * Vec3d (p1, mesh.Point (tempels.Get(helind)[k-1])) > 0) if (n * Vec3d (p1, mesh.Point (tempels.Get(helind)[k])) > 0)
n *= -1; n *= -1;
double dist = n * Vec3d (p1, newp); double dist = n * Vec3d (p1, newp);
if (dist > -1e-10) // 1e-10 if (dist > -1e-10) // 1e-10
{ {
insphere.Add (nbind); insphere.Add (nbind);
changed = 1; changed = 1;
} }
} }
} }
} }
} // while (changed) } // while (changed)
// (*testout) << "newels: " << endl;
Array<Element> newels; // Array<Element> newels;
Array<DelaunayTet> newels;
Element2d face(TRIG); Element2d face(TRIG);
for (int j = 1; j <= insphere.GetArray().Size(); j++) for (int celind : insphere.GetArray())
for (int k = 1; k <= 4; k++) for (int k = 0; k < 4; k++)
{ {
// int elind = insphere.GetArray().Get(j);
int celind = insphere.GetArray().Get(j);
int nbind = meshnb.GetNB (celind, k); int nbind = meshnb.GetNB (celind, k);
if (!nbind || !insphere.IsIn (nbind)) if (!nbind || !insphere.IsIn (nbind))
{ {
tempels.Get (celind).GetFace1 (k, face); tempels.Get (celind).GetFace (k, face);
Element newel(TET); // Element newel(TET);
DelaunayTet newel;
for (int l = 0; l < 3; l++) for (int l = 0; l < 3; l++)
newel[l] = face[l]; newel[l] = face[l];
newel[3] = newpi; newel[3] = newpi;
@ -471,7 +391,7 @@ namespace netgen
n.Normalize(); n.Normalize();
if (n * Vec3d(mesh.Point (face[0]), if (n * Vec3d(mesh.Point (face[0]),
mesh.Point (tempels.Get(insphere.GetArray().Get(j))[k-1])) mesh.Point (tempels.Get(celind)[k]))
> 0) > 0)
n *= -1; n *= -1;
@ -492,38 +412,36 @@ namespace netgen
meshnb.ResetFaceHT (10*insphere.GetArray().Size()+1); meshnb.ResetFaceHT (10*insphere.GetArray().Size()+1);
for (int j = 1; j <= insphere.GetArray().Size(); j++) for (auto celind : insphere.GetArray())
{ {
// int elind =
int celind = insphere.GetArray().Get(j);
meshnb.Delete (celind); meshnb.Delete (celind);
list.DeleteElement (celind); list.DeleteElement (celind);
for (int k = 0; k < 4; k++) for (int k = 0; k < 4; k++)
tempels.Elem(celind)[k] = -1; tempels.Elem(celind)[k] = -1;
// ((ADTree6&)tettree.Tree()).DeleteElement (celind);
tettree.DeleteElement (celind); tettree.DeleteElement (celind);
freelist.Append (celind); freelist.Append (celind);
} }
int hasclose = 0;
for (int j = 1; j <= closesphere.GetArray().Size(); j++)
bool hasclose = false;
for (int ind : closesphere.GetArray())
{ {
int ind = closesphere.GetArray().Get(j);
if (!insphere.IsIn(ind) && if (!insphere.IsIn(ind) &&
fabs (Dist2 (centers.Get (ind), newp) - radi2.Get(ind)) < 1e-8 ) fabs (Dist2 (centers.Get (ind), newp) - radi2.Get(ind)) < 1e-8 )
hasclose = 1; hasclose = true;
} }
for (int j = 1; j <= newels.Size(); j++) for (int j = 1; j <= newels.Size(); j++)
{ {
const auto & newel = newels.Get(j);
int nelind; int nelind;
if (!freelist.Size()) if (!freelist.Size())
{ {
tempels.Append (newels.Get(j)); tempels.Append (newel);
nelind = tempels.Size(); nelind = tempels.Size();
} }
else else
@ -531,29 +449,29 @@ namespace netgen
nelind = freelist.Last(); nelind = freelist.Last();
freelist.DeleteLast(); freelist.DeleteLast();
tempels.Elem(nelind) = newels.Get(j); tempels.Elem(nelind) = newel;
} }
meshnb.Add (nelind); meshnb.Add (nelind);
list.AddElement (nelind); list.AddElement (nelind);
for (int k = 0; k < 4; k++) for (int k = 0; k < 4; k++)
pp[k] = &mesh.Point (newels.Get(j)[k]); pp[k] = &mesh.Point (newel[k]);
if (CalcSphereCenter (&pp[0], pc) ) if (CalcSphereCenter (&pp[0], pc) )
{ {
PrintSysError ("Delaunay: New tet is flat"); PrintSysError ("Delaunay: New tet is flat");
(*testout) << "new tet is flat" << endl; (*testout) << "new tet is flat" << endl;
for (int k = 1; k <= 4; k++) for (int k = 0; k < 4; k++)
(*testout) << newels.Get(j).PNum(k) << " "; (*testout) << newel[k] << " ";
(*testout) << endl; (*testout) << endl;
for (int k = 1; k <= 4; k++) for (int k = 0; k < 4; k++)
(*testout) << *pp[k-1] << " "; (*testout) << *pp[k-1] << " ";
(*testout) << endl; (*testout) << endl;
} }
r2 = Dist2 (*pp[0], pc); double r2 = Dist2 (*pp[0], pc);
if (hasclose) if (hasclose)
for (int k = 1; k <= closesphere.GetArray().Size(); k++) for (int k = 1; k <= closesphere.GetArray().Size(); k++)
{ {
@ -602,50 +520,41 @@ namespace netgen
Array<DelaunayTet> & tempels, Array<DelaunayTet> & tempels,
int oldnp, DelaunayTet & startel, Point3d & pmin, Point3d & pmax) int oldnp, DelaunayTet & startel, Point3d & pmin, Point3d & pmax)
{ {
Array<Point<3> > centers; static Timer t("Meshing3::Delaunay1"); RegionTimer reg(t);
static Timer tloop("Meshing3::Delaunay1 loop");
Array<Point<3>> centers;
Array<double> radi2; Array<double> radi2;
Point3d tpmin, tpmax; Box<3> bbox(Box<3>::EMPTY_BOX);
for (auto & face : adfront->Faces())
// new: local box for (PointIndex pi : face.Face().PNums())
mesh.GetBox (pmax, pmin); // lower bound for pmax, upper for pmin bbox.Add (mesh.Point(pi));
for (int i = 1; i <= adfront->GetNF(); i++)
{
const MiniElement2d & face = adfront->GetFace(i);
for (PointIndex pi : face.PNums())
{
pmin.SetToMin (mesh.Point (pi));
pmax.SetToMax (mesh.Point (pi));
}
}
for (PointIndex pi : mesh.LockedPoints()) for (PointIndex pi : mesh.LockedPoints())
{ bbox.Add (mesh.Point (pi));
pmin.SetToMin (mesh.Point (pi));
pmax.SetToMax (mesh.Point (pi)); pmin = bbox.PMin();
} pmax = bbox.PMax();
Vec<3> vdiag = pmax-pmin;
Vec3d vdiag(pmin, pmax);
// double r1 = vdiag.Length(); // double r1 = vdiag.Length();
double r1 = sqrt (3.0) * max3(vdiag.X(), vdiag.Y(), vdiag.Z()); double r1 = sqrt (3.0) * max3(vdiag(0), vdiag(1), vdiag(2));
vdiag = Vec3d (r1, r1, r1); vdiag = Vec<3> (r1, r1, r1);
//double r2; //double r2;
Point3d pmin2 = pmin - 8 * vdiag; Point<3> pmin2 = pmin - 8 * vdiag;
Point3d pmax2 = pmax + 8 * vdiag; Point<3> pmax2 = pmax + 8 * vdiag;
Point3d cp1(pmin2), cp2(pmax2), cp3(pmax2), cp4(pmax2); Point<3> cp1(pmin2), cp2(pmax2), cp3(pmax2), cp4(pmax2);
cp2.X() = pmin2.X(); cp2(0) = pmin2(0);
cp3.Y() = pmin2.Y(); cp3(1) = pmin2(1);
cp4.Z() = pmin2.Z(); cp4(2) = pmin2(2);
size_t np = mesh.GetNP();
int np = mesh.GetNP();
startel[0] = mesh.AddPoint (cp1); startel[0] = mesh.AddPoint (cp1);
startel[1] = mesh.AddPoint (cp2); startel[1] = mesh.AddPoint (cp2);
@ -655,24 +564,21 @@ namespace netgen
// flag points to use for Delaunay: // flag points to use for Delaunay:
BitArrayChar<PointIndex::BASE> usep(np); BitArrayChar<PointIndex::BASE> usep(np);
usep.Clear(); usep.Clear();
for (int i = 1; i <= adfront->GetNF(); i++)
{
const MiniElement2d & face = adfront->GetFace(i);
for (int j = 0; j < face.GetNP(); j++)
usep.Set (face[j]);
}
for (int i = oldnp + PointIndex::BASE; for (auto & face : adfront->Faces())
for (PointIndex pi : face.Face().PNums())
usep.Set (pi);
for (size_t i = oldnp + PointIndex::BASE;
i < np + PointIndex::BASE; i++) i < np + PointIndex::BASE; i++)
usep.Set (i); usep.Set (i);
for (int i = 0; i < mesh.LockedPoints().Size(); i++) for (PointIndex pi : mesh.LockedPoints())
usep.Set (mesh.LockedPoints()[i]); usep.Set (pi);
Array<int> freelist; Array<int> freelist;
int cntp = 0; int cntp = 0;
MeshNB meshnb (tempels, mesh.GetNP() + 5); MeshNB meshnb (tempels, mesh.GetNP() + 5);
@ -689,13 +595,12 @@ namespace netgen
list.AddElement (1); list.AddElement (1);
Array<int> connected, treesearch; Array<int> connected, treesearch;
Box<3> tbox(Box<3>::EMPTY_BOX);
for (size_t k = 0; k < 4; k++)
tbox.Add (mesh.Point(startel[k]));
Point<3> tpmin = tbox.PMin();
Point<3> tpmax = tbox.PMax();
tpmin = tpmax = mesh.Point(startel[0]);
for (int k = 1; k < 4; k++)
{
tpmin.SetToMin (mesh.Point (startel[k]));
tpmax.SetToMax (mesh.Point (startel[k]));
}
tpmax = tpmax + 0.01 * (tpmax - tpmin); tpmax = tpmax + 0.01 * (tpmax - tpmin);
tettree.Insert (tpmin, tpmax, 1); tettree.Insert (tpmin, tpmax, 1);
@ -727,6 +632,7 @@ namespace netgen
for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End()-4; pi++) for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End()-4; pi++)
mixed[pi] = PointIndex ( (prim * pi) % np + PointIndex::BASE ); mixed[pi] = PointIndex ( (prim * pi) % np + PointIndex::BASE );
tloop.Start();
for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End()-4; pi++) for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End()-4; pi++)
{ {
if (pi % 1000 == 0) if (pi % 1000 == 0)
@ -755,6 +661,7 @@ namespace netgen
connected, treesearch, freelist, list, insphere, closesphere); connected, treesearch, freelist, list, insphere, closesphere);
} }
tloop.Stop();
for (int i = tempels.Size(); i >= 1; i--) for (int i = tempels.Size(); i >= 1; i--)
if (tempels.Get(i)[0] <= 0) if (tempels.Get(i)[0] <= 0)
@ -783,6 +690,8 @@ namespace netgen
void Meshing3 :: Delaunay (Mesh & mesh, int domainnr, const MeshingParameters & mp) void Meshing3 :: Delaunay (Mesh & mesh, int domainnr, const MeshingParameters & mp)
{ {
static Timer t("Meshing3::Delaunay"); RegionTimer reg(t);
int np, ne; int np, ne;
PrintMessage (1, "Delaunay meshing"); PrintMessage (1, "Delaunay meshing");
@ -810,26 +719,27 @@ namespace netgen
// improve delaunay - mesh by swapping !!!! // improve delaunay - mesh by swapping !!!!
Mesh tempmesh; Mesh tempmesh;
for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End(); pi++)
tempmesh.AddPoint (mesh[pi]);
for (int i = 1; i <= tempels.Size(); i++) for (auto & meshpoint : mesh.Points())
tempmesh.AddPoint (meshpoint);
for (auto & tempel : tempels)
{ {
Element el(4); Element el(4);
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
el[j] = tempels.Elem(i)[j]; el[j] = tempel[j];
el.SetIndex (1); el.SetIndex (1);
const Point3d & lp1 = mesh.Point (el[0]); const Point<3> & lp1 = mesh.Point (el[0]);
const Point3d & lp2 = mesh.Point (el[1]); const Point<3> & lp2 = mesh.Point (el[1]);
const Point3d & lp3 = mesh.Point (el[2]); const Point<3> & lp3 = mesh.Point (el[2]);
const Point3d & lp4 = mesh.Point (el[3]); const Point<3> & lp4 = mesh.Point (el[3]);
Vec3d v1(lp1, lp2); Vec<3> v1 = lp2-lp1;
Vec3d v2(lp1, lp3); Vec<3> v2 = lp3-lp1;
Vec3d v3(lp1, lp4); Vec<3> v3 = lp4-lp1;
Vec3d n = Cross (v1, v2); Vec<3> n = Cross (v1, v2);
double vol = n * v3; double vol = n * v3;
if (vol > 0) swap (el[2], el[3]); if (vol > 0) swap (el[2], el[3]);
@ -858,7 +768,7 @@ namespace netgen
{ {
Element2d self(TRIG); Element2d self(TRIG);
self.SetIndex (1); self.SetIndex (1);
startel.GetFace1 (i, self); startel.GetFace (i-1, self);
tempmesh.AddSurfaceElement (self); tempmesh.AddSurfaceElement (self);
} }
@ -1232,6 +1142,7 @@ namespace netgen
INDEX_3_HASHTABLE<int> boundaryfaces(mesh.GetNOpenElements()/3+1); INDEX_3_HASHTABLE<int> boundaryfaces(mesh.GetNOpenElements()/3+1);
/*
for (int i = 1; i <= mesh.GetNOpenElements(); i++) for (int i = 1; i <= mesh.GetNOpenElements(); i++)
{ {
const Element2d & tri = mesh.OpenElement(i); const Element2d & tri = mesh.OpenElement(i);
@ -1239,6 +1150,13 @@ namespace netgen
i3.Sort(); i3.Sort();
boundaryfaces.PrepareSet (i3); boundaryfaces.PrepareSet (i3);
} }
*/
for (const Element2d & tri : mesh.OpenElements())
{
INDEX_3 i3 (tri[0], tri[1], tri[2]);
i3.Sort();
boundaryfaces.PrepareSet (i3);
}
boundaryfaces.AllocateElements(); boundaryfaces.AllocateElements();
for (int i = 1; i <= mesh.GetNOpenElements(); i++) for (int i = 1; i <= mesh.GetNOpenElements(); i++)
{ {
@ -1248,14 +1166,23 @@ namespace netgen
boundaryfaces.Set (i3, 1); boundaryfaces.Set (i3, 1);
} }
/*
for (int i = 0; i < tempels.Size(); i++) for (int i = 0; i < tempels.Size(); i++)
for (int j = 0; j < 4; j++) for (int j = 0; j < 4; j++)
tempels[i].NB(j) = 0; tempels[i].NB(j) = 0;
*/
for (auto & el : tempels)
for (int j = 0; j < 4; j++)
el.NB(j) = 0;
TABLE<int,PointIndex::BASE> elsonpoint(mesh.GetNP()); TABLE<int,PointIndex::BASE> elsonpoint(mesh.GetNP());
/*
for (int i = 0; i < tempels.Size(); i++) for (int i = 0; i < tempels.Size(); i++)
{ {
const DelaunayTet & el = tempels[i]; const DelaunayTet & el = tempels[i];
*/
for (const DelaunayTet & el : tempels)
{
INDEX_4 i4(el[0], el[1], el[2], el[3]); INDEX_4 i4(el[0], el[1], el[2], el[3]);
i4.Sort(); i4.Sort();
elsonpoint.IncSizePrepare (i4.I1()); elsonpoint.IncSizePrepare (i4.I1());
@ -1279,7 +1206,8 @@ namespace netgen
INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht(100); INDEX_3_CLOSED_HASHTABLE<INDEX_2> faceht(100);
Element2d hel(TRIG); Element2d hel(TRIG);
for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End(); pi++) // for (PointIndex pi = mesh.Points().Begin(); pi < mesh.Points().End(); pi++)
for (PointIndex pi : mesh.Points().Range())
{ {
faceht.SetSize (4 * elsonpoint[pi].Size()); faceht.SetSize (4 * elsonpoint[pi].Size());
for (int ii = 0; ii < elsonpoint[pi].Size(); ii++) for (int ii = 0; ii < elsonpoint[pi].Size(); ii++)
@ -1289,7 +1217,7 @@ namespace netgen
for (int j = 1; j <= 4; j++) for (int j = 1; j <= 4; j++)
{ {
el.GetFace1 (j, hel); el.GetFace (j-1, hel);
hel.Invert(); hel.Invert();
hel.NormalizeNumbering(); hel.NormalizeNumbering();
@ -1303,8 +1231,8 @@ namespace netgen
{ {
INDEX_2 i2 = faceht.Get(i3); INDEX_2 i2 = faceht.Get(i3);
tempels.Elem(i).NB1(j) = i2.I1(); tempels.Elem(i).NB(j-1) = i2.I1();
tempels.Elem(i2.I1()).NB1(i2.I2()) = i; tempels.Elem(i2.I1()).NB(i2.I2()-1) = i;
} }
else else
{ {
@ -1464,7 +1392,7 @@ namespace netgen
for (int j = 1; j <= 4; j++) for (int j = 1; j <= 4; j++)
{ {
INDEX_3 i3 = tempels.Get(ei).GetFace1(j); INDEX_3 i3 = tempels.Get(ei).GetFace(j-1);
/* /*
Element2d face; Element2d face;
tempels.Get(ei).GetFace(j, face); tempels.Get(ei).GetFace(j, face);
@ -1474,8 +1402,8 @@ namespace netgen
i3.Sort(); i3.Sort();
if (tempels.Get(ei).NB1(j)) if (tempels.Get(ei).NB(j-1))
elstack.Append (tempels.Get(ei).NB1(j)); elstack.Append (tempels.Get(ei).NB(j-1));
/* /*
if (innerfaces.Used(i3)) if (innerfaces.Used(i3))

View File

@ -31,6 +31,9 @@ namespace netgen
DLL_HEADER shared_ptr<NetgenGeometry> ng_geometry; DLL_HEADER shared_ptr<NetgenGeometry> ng_geometry;
// TraceGlobal glob2("global2"); // TraceGlobal glob2("global2");
// global communicator for netgen
DLL_HEADER MPI_Comm ng_comm = MPI_COMM_WORLD;
weak_ptr<Mesh> global_mesh; weak_ptr<Mesh> global_mesh;
void SetGlobalMesh (shared_ptr<Mesh> m) void SetGlobalMesh (shared_ptr<Mesh> m)
{ {
@ -50,10 +53,6 @@ namespace netgen
string ngdir = "."; string ngdir = ".";
// parallel netgen
int id = 0, ntasks = 1;
void Ng_PrintDest(const char * s) void Ng_PrintDest(const char * s)
{ {
if (id == 0) if (id == 0)

View File

@ -59,6 +59,10 @@ namespace netgen
DLL_HEADER extern weak_ptr<Mesh> global_mesh; DLL_HEADER extern weak_ptr<Mesh> global_mesh;
DLL_HEADER void SetGlobalMesh (shared_ptr<Mesh> m); DLL_HEADER void SetGlobalMesh (shared_ptr<Mesh> m);
// global communicator for netgen (dummy if no MPI)
extern DLL_HEADER MPI_Comm ng_comm;
} }
#endif #endif

View File

@ -22,8 +22,9 @@ namespace netgen
{ {
pnums[i] = -1; pnums[i] = -1;
param[i][0] = param[i][1] = param[i][2] = 0; param[i][0] = param[i][1] = param[i][2] = 0;
domin=-1; domout=-1; // he:
} }
domin=-1; domout=-1; // he:
levelx = 0; levely = 0; levelz = 0;
} }
HPRefElement :: HPRefElement () HPRefElement :: HPRefElement ()
@ -31,46 +32,40 @@ namespace netgen
Reset(); Reset();
} }
HPRefElement :: HPRefElement(Element & el) HPRefElement :: HPRefElement(Element & el) :
np(el.GetNV()), index(el.GetIndex()), levelx(0), levely(0), levelz(0), type(HP_NONE), domin(-1), domout(-1) //domin,out for segements
{ {
//Reset(); //Reset();
np = el.GetNV();
for (int i=0; i<np ; i++) for (int i=0; i<np ; i++)
pnums[i] = el[i]; pnums[i] = el[i];
index = el.GetIndex();
const Point3d * points = const Point3d * points =
MeshTopology :: GetVertices (el.GetType()); MeshTopology :: GetVertices (el.GetType());
for(int i=0;i<np;i++) for(int i=0;i<np;i++)
for(int l=0;l<3;l++) for(int l=0;l<3;l++)
param[i][l] = points[i].X(l+1); param[i][l] = points[i].X(l+1);
type = HP_NONE;
domin=-1; domout=-1; // he: needed for segments
} }
HPRefElement :: HPRefElement(Element2d & el) HPRefElement :: HPRefElement(Element2d & el) :
levelx(0), levely(0), levelz(0), type(HP_NONE), index(el.GetIndex()), np(el.GetNV()), domin(-1), domout(-1) //domin,out for segements
{ {
//Reset(); //Reset();
np = el.GetNV();
for (int i=0; i<np ; i++) for (int i=0; i<np ; i++)
pnums[i] = el[i]; pnums[i] = el[i];
index = el.GetIndex();
const Point3d * points = const Point3d * points =
MeshTopology :: GetVertices (el.GetType()); MeshTopology :: GetVertices (el.GetType());
for(int i=0;i<np;i++) for(int i=0;i<np;i++)
for(int l=0;l<3;l++) for(int l=0;l<3;l++)
param[i][l] = points[i].X(l+1); param[i][l] = points[i].X(l+1);
type = HP_NONE;
domin=-1; domout=-1; // he: needed for segments
} }
HPRefElement :: HPRefElement(Segment & el) HPRefElement :: HPRefElement(Segment & el) :
levelx(0), levely(0), levelz(0), type(HP_NONE), np(2), domin(el.domin), domout(el.domout), singedge_left(el.singedge_left), singedge_right(el.singedge_right)
{ {
//Reset(); //Reset();
np = 2;
for (int i=0; i<np ; i++) for (int i=0; i<np ; i++)
pnums[i] = el[i]; pnums[i] = el[i];
const Point3d * points = const Point3d * points =
@ -86,35 +81,18 @@ namespace netgen
param[i][1] = -1; param[i][2] = -1; param[i][1] = -1; param[i][2] = -1;
} }
*/ */
singedge_left = el.singedge_left;
singedge_right = el.singedge_right;
type = HP_NONE;
// he: needed for orientation!
domin = el.domin;
domout = el.domout;
} }
HPRefElement :: HPRefElement(HPRefElement & el) HPRefElement :: HPRefElement(HPRefElement & el) :
np(el.np), levelx(el.levelx), levely(el.levely), levelz(el.levelz), type(el.type), domin(el.domin), domout(el.domout), index(el.index), coarse_elnr(el.coarse_elnr), singedge_left(el.singedge_left), singedge_right(el.singedge_right)
{ {
//Reset(); //Reset();
np = el.np;
for (int i=0; i<np ; i++) for (int i=0; i<np ; i++)
{ {
pnums[i] = el[i]; pnums[i] = el[i];
for(int l=0; l<3; l++) param[i][l] = el.param[i][l]; for(int l=0; l<3; l++) param[i][l] = el.param[i][l];
} }
index = el.index;
levelx = el.levelx;
levely = el.levely;
levelz = el.levelz;
type = el.type;
coarse_elnr = el.coarse_elnr;
singedge_left = el.singedge_left;
singedge_right = el.singedge_right;
domin = el.domin; // he: needed for segments
domout=el.domout;
} }
void HPRefElement :: SetType (HPREF_ELEMENT_TYPE t) void HPRefElement :: SetType (HPREF_ELEMENT_TYPE t)
@ -706,8 +684,7 @@ namespace netgen
{ {
HPRefElement el = elements[i]; HPRefElement el = elements[i];
HPRef_Struct * hprs = Get_HPRef_Struct (el.type); HPRef_Struct * hprs = Get_HPRef_Struct (el.type);
int newlevel = el.levelx + 1; int newlevel = el.levelx;
int oldnp = 0; int oldnp = 0;
switch (hprs->geom) switch (hprs->geom)
{ {
@ -829,18 +806,27 @@ namespace netgen
HPRefElement newel(el); HPRefElement newel(el);
newel.type = hprs->neweltypes[j]; newel.type = hprs->neweltypes[j];
// newel.index = elements[i].index; // newel.index = elements[i].index;
// newel.coarse_elnr = elements[i].coarse_elnr; // newel.coarse_elnr = elements[i].coarse_elnr;
newel.levelx = newel.levely = newel.levelz = newlevel; if (newel.type == HP_SEGM ||
newel.type == HP_TRIG ||
newel.type == HP_QUAD ||
newel.type == HP_TET ||
newel.type == HP_PRISM ||
newel.type == HP_HEX ||
newel.type == HP_PYRAMID)
newel.levelx = newel.levely = newel.levelz = newlevel;
else
newel.levelx = newel.levely = newel.levelz = newlevel+1;
switch(hprsnew->geom) switch(hprsnew->geom)
{ {
case HP_SEGM: newel.np=2; break; case HP_SEGM: newel.np=2; break;
case HP_QUAD: newel.np=4; break; case HP_QUAD: newel.np=4; break;
case HP_TRIG: newel.np=3; break; case HP_TRIG: newel.np=3; break;
case HP_HEX: newel.np=8; break; case HP_HEX: newel.np=8; break;
case HP_PRISM: newel.np=6; break; case HP_PRISM: newel.np=6; break;
case HP_TET: newel.np=4; break; case HP_TET: newel.np=4; break;
case HP_PYRAMID: newel.np=5; break; case HP_PYRAMID: newel.np=5; break;
default: default:
throw NgException (string("hprefinement.cpp: illegal type")); throw NgException (string("hprefinement.cpp: illegal type"));

View File

@ -22,6 +22,8 @@ namespace netgen
void MeshOptimize3d :: CombineImprove (Mesh & mesh, void MeshOptimize3d :: CombineImprove (Mesh & mesh,
OPTIMIZEGOAL goal) OPTIMIZEGOAL goal)
{ {
static Timer t("MeshOptimize3d::CombineImprove"); RegionTimer reg(t);
int np = mesh.GetNP(); int np = mesh.GetNP();
int ne = mesh.GetNE(); int ne = mesh.GetNE();
@ -274,6 +276,8 @@ void MeshOptimize3d :: CombineImprove (Mesh & mesh,
void MeshOptimize3d :: SplitImprove (Mesh & mesh, void MeshOptimize3d :: SplitImprove (Mesh & mesh,
OPTIMIZEGOAL goal) OPTIMIZEGOAL goal)
{ {
static Timer t("MeshOptimize3d::SplitImprove"); RegionTimer reg(t);
double bad1, bad2, badmax, badlimit; double bad1, bad2, badmax, badlimit;
int cnt = 0; int cnt = 0;
@ -569,6 +573,8 @@ void MeshOptimize3d :: SplitImprove (Mesh & mesh,
void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal, void MeshOptimize3d :: SwapImprove (Mesh & mesh, OPTIMIZEGOAL goal,
const BitArray * working_elements) const BitArray * working_elements)
{ {
static Timer t("MeshOptimize3d::SwapImprove"); RegionTimer reg(t);
PointIndex pi3(0), pi4(0), pi5(0), pi6(0); PointIndex pi3(0), pi4(0), pi5(0), pi6(0);
int cnt = 0; int cnt = 0;
@ -2303,6 +2309,8 @@ void MeshOptimize3d :: SwapImproveSurface (Mesh & mesh, OPTIMIZEGOAL goal,
void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal) void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal)
{ {
static Timer t("MeshOptimize3d::SwapImprove2"); RegionTimer reg(t);
PointIndex pi1(0), pi2(0), pi3(0), pi4(0), pi5(0); PointIndex pi1(0), pi2(0), pi3(0), pi4(0), pi5(0);
Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET); Element el21(TET), el22(TET), el31(TET), el32(TET), el33(TET);

View File

@ -4988,6 +4988,10 @@ namespace netgen
bool build_searchtree, bool build_searchtree,
const bool allowindex) const const bool allowindex) const
{ {
// const double pointtol = 1e-12;
// netgen::Point<3> pmin = p - Vec<3> (pointtol, pointtol, pointtol);
// netgen::Point<3> pmax = p + Vec<3> (pointtol, pointtol, pointtol);
if (dimension == 2 || (dimension==3 && !GetNE() && GetNSE())) if (dimension == 2 || (dimension==3 && !GetNE() && GetNSE()))
{ {
int ne; int ne;

View File

@ -32,10 +32,8 @@ namespace netgen
/// point coordinates /// point coordinates
T_POINTS points; T_POINTS points;
#ifdef PARALLEL // The communicator for this mesh. Just a dummy if compiled without MPI.
// The communicator for this mesh. (more or less dummy for now!)
MPI_Comm comm; MPI_Comm comm;
#endif
/// line-segments at edges /// line-segments at edges
Array<Segment, 0, size_t> segments; Array<Segment, 0, size_t> segments;
@ -132,8 +130,8 @@ namespace netgen
/// mesh access semaphors. /// mesh access semaphors.
NgMutex majormutex; NgMutex majormutex;
SYMBOLTABLE< Array<int>* > userdata_int; SymbolTable< Array<int>* > userdata_int;
SYMBOLTABLE< Array<double>* > userdata_double; SymbolTable< Array<double>* > userdata_double;
mutable Array< Point3d > pointcurves; mutable Array< Point3d > pointcurves;
@ -223,7 +221,7 @@ namespace netgen
DLL_HEADER PointIndex AddPoint (const Point3d & p, int layer = 1); DLL_HEADER PointIndex AddPoint (const Point3d & p, int layer = 1);
DLL_HEADER PointIndex AddPoint (const Point3d & p, int layer, POINTTYPE type); DLL_HEADER PointIndex AddPoint (const Point3d & p, int layer, POINTTYPE type);
int GetNP () const { return points.Size(); } auto GetNP () const { return points.Size(); }
// [[deprecated("Use Point(PointIndex) instead of int !")]] // [[deprecated("Use Point(PointIndex) instead of int !")]]
MeshPoint & Point(int i) { return points.Elem(i); } MeshPoint & Point(int i) { return points.Elem(i); }
@ -293,7 +291,7 @@ namespace netgen
timestamp = NextTimeStamp(); timestamp = NextTimeStamp();
} }
int GetNSE () const { return surfelements.Size(); } auto GetNSE () const { return surfelements.Size(); }
// [[deprecated("Use SurfaceElement(SurfaceElementIndex) instead of int !")]] // [[deprecated("Use SurfaceElement(SurfaceElementIndex) instead of int !")]]
Element2d & SurfaceElement(int i) { return surfelements.Elem(i); } Element2d & SurfaceElement(int i) { return surfelements.Elem(i); }
@ -318,7 +316,7 @@ namespace netgen
// write to pre-allocated container, thread-safe // write to pre-allocated container, thread-safe
DLL_HEADER void SetVolumeElement (ElementIndex sei, const Element & el); DLL_HEADER void SetVolumeElement (ElementIndex sei, const Element & el);
int GetNE () const { return volelements.Size(); } auto GetNE () const { return volelements.Size(); }
// [[deprecated("Use VolumeElement(ElementIndex) instead of int !")]] // [[deprecated("Use VolumeElement(ElementIndex) instead of int !")]]
Element & VolumeElement(int i) { return volelements.Elem(i); } Element & VolumeElement(int i) { return volelements.Elem(i); }
@ -456,6 +454,7 @@ namespace netgen
const Element2d & OpenElement(int i) const const Element2d & OpenElement(int i) const
{ return openelements.Get(i); } { return openelements.Get(i); }
auto & OpenElements() const { return openelements; }
/// are also quads open elements /// are also quads open elements
bool HasOpenQuads () const; bool HasOpenQuads () const;
@ -606,6 +605,9 @@ namespace netgen
int AddEdgeDescriptor(const EdgeDescriptor & fd) int AddEdgeDescriptor(const EdgeDescriptor & fd)
{ edgedecoding.Append(fd); return edgedecoding.Size() - 1; } { edgedecoding.Append(fd); return edgedecoding.Size() - 1; }
MPI_Comm GetCommunicator() const { return this->comm; }
void SetCommunicator(MPI_Comm acomm);
/// ///
DLL_HEADER void SetMaterial (int domnr, const string & mat); DLL_HEADER void SetMaterial (int domnr, const string & mat);
/// ///
@ -858,7 +860,11 @@ namespace netgen
void SendMesh ( ) const; // Mesh * mastermesh, Array<int> & neloc) const; void SendMesh ( ) const; // Mesh * mastermesh, Array<int> & neloc) const;
/// loads a mesh sent from master processor /// loads a mesh sent from master processor
void ReceiveParallelMesh (); void ReceiveParallelMesh ();
#else
void Distribute () {}
void SendRecvMesh () {}
void Distribute (Array<int> & volume_weights, Array<int> & surface_weights,
Array<int> & segment_weights){ }
#endif #endif

View File

@ -14,6 +14,8 @@ namespace netgen
// extern double teterrpow; // extern double teterrpow;
MESHING3_RESULT MeshVolume (MeshingParameters & mp, Mesh& mesh3d) MESHING3_RESULT MeshVolume (MeshingParameters & mp, Mesh& mesh3d)
{ {
static Timer t("MeshVolume"); RegionTimer reg(t);
int oldne; int oldne;
int meshed; int meshed;
@ -639,6 +641,8 @@ namespace netgen
Mesh & mesh3d) Mesh & mesh3d)
// const CSGeometry * geometry) // const CSGeometry * geometry)
{ {
static Timer t("OptimizeVolume"); RegionTimer reg(t);
int i; int i;
PrintMessage (1, "Volume Optimization"); PrintMessage (1, "Volume Optimization");
@ -698,6 +702,8 @@ namespace netgen
void RemoveIllegalElements (Mesh & mesh3d) void RemoveIllegalElements (Mesh & mesh3d)
{ {
static Timer t("RemoveIllegalElements"); RegionTimer reg(t);
int it = 10; int it = 10;
int nillegal, oldn; int nillegal, oldn;

View File

@ -168,12 +168,17 @@ int Meshing3 :: AddConnectedPair (const INDEX_2 & apair)
MESHING3_RESULT Meshing3 :: MESHING3_RESULT Meshing3 ::
GenerateMesh (Mesh & mesh, const MeshingParameters & mp) GenerateMesh (Mesh & mesh, const MeshingParameters & mp)
{ {
static int meshing3_timer = NgProfiler::CreateTimer ("Meshing3::GenerateMesh"); static Timer t("Meshing3::GenerateMesh"); RegionTimer reg(t);
static int meshing3_timer_a = NgProfiler::CreateTimer ("Meshing3::GenerateMesh a"); static Timer meshing3_timer_a("Meshing3::GenerateMesh a", 2);
static int meshing3_timer_b = NgProfiler::CreateTimer ("Meshing3::GenerateMesh b"); static Timer meshing3_timer_b("Meshing3::GenerateMesh b", 2);
static int meshing3_timer_c = NgProfiler::CreateTimer ("Meshing3::GenerateMesh c"); static Timer meshing3_timer_c("Meshing3::GenerateMesh c", 1);
static int meshing3_timer_d = NgProfiler::CreateTimer ("Meshing3::GenerateMesh d"); static Timer meshing3_timer_d("Meshing3::GenerateMesh d", 2);
NgProfiler::RegionTimer reg (meshing3_timer); // static int meshing3_timer = NgProfiler::CreateTimer ("Meshing3::GenerateMesh");
// static int meshing3_timer_a = NgProfiler::CreateTimer ("Meshing3::GenerateMesh a");
// static int meshing3_timer_b = NgProfiler::CreateTimer ("Meshing3::GenerateMesh b");
// static int meshing3_timer_c = NgProfiler::CreateTimer ("Meshing3::GenerateMesh c");
// static int meshing3_timer_d = NgProfiler::CreateTimer ("Meshing3::GenerateMesh d");
// NgProfiler::RegionTimer reg (meshing3_timer);
Array<Point3d, PointIndex::BASE> locpoints; // local points Array<Point3d, PointIndex::BASE> locpoints; // local points
@ -269,19 +274,15 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp)
} }
const MiniElement2d & bel = adfront->GetFace (baseelem); const MiniElement2d & bel = adfront->GetFace (baseelem);
const Point3d & p1 = adfront->GetPoint (bel[0]); const Point<3> p1 = adfront->GetPoint (bel[0]);
const Point3d & p2 = adfront->GetPoint (bel[1]); const Point<3> p2 = adfront->GetPoint (bel[1]);
const Point3d & p3 = adfront->GetPoint (bel[2]); const Point<3> p3 = adfront->GetPoint (bel[2]);
// (*testout) << endl << "base = " << bel << endl;
Point3d pmid = Center (p1, p2, p3); Point<3> pmid = Center (p1, p2, p3);
double his = (Dist (p1, p2) + Dist(p1, p3) + Dist(p2, p3)) / 3; double his = (Dist (p1, p2) + Dist(p1, p3) + Dist(p2, p3)) / 3;
double hshould; double hshould = mesh.GetH (pmid);
hshould = mesh.GetH (pmid);
if (adfront->GetFace (baseelem).GetNP() == 4) if (adfront->GetFace (baseelem).GetNP() == 4)
hshould = max2 (his, hshould); hshould = max2 (his, hshould);
@ -292,13 +293,13 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp)
double hinner = hmax * (1 + stat.qualclass); double hinner = hmax * (1 + stat.qualclass);
double houter = hmax * (1 + 2 * stat.qualclass); double houter = hmax * (1 + 2 * stat.qualclass);
NgProfiler::StartTimer (meshing3_timer_a); meshing3_timer_a.Start();
stat.qualclass = stat.qualclass =
adfront -> GetLocals (baseelem, locpoints, locfaces, adfront -> GetLocals (baseelem, locpoints, locfaces,
pindex, findex, connectedpairs, pindex, findex, connectedpairs,
houter, hinner, houter, hinner,
locfacesplit); locfacesplit);
NgProfiler::StopTimer (meshing3_timer_a); meshing3_timer_a.Stop();
// (*testout) << "locfaces = " << endl << locfaces << endl; // (*testout) << "locfaces = " << endl << locfaces << endl;
@ -320,9 +321,6 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp)
} }
if (testmode) if (testmode)
{ {
(*testout) << "baseelem = " << baseelem << " qualclass = " << stat.qualclass << endl; (*testout) << "baseelem = " << baseelem << " qualclass = " << stat.qualclass << endl;
@ -479,7 +477,8 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp)
(*testout) << endl; (*testout) << endl;
} }
NgProfiler::StartTimer (meshing3_timer_c); // NgProfiler::StartTimer (meshing3_timer_c);
meshing3_timer_c.Start();
found = ApplyRules (plainpoints, allowpoint, found = ApplyRules (plainpoints, allowpoint,
locfaces, locfacesplit, connectedpairs, locfaces, locfacesplit, connectedpairs,
@ -489,8 +488,8 @@ GenerateMesh (Mesh & mesh, const MeshingParameters & mp)
if (found >= 0) impossible = 0; if (found >= 0) impossible = 0;
if (found < 0) found = 0; if (found < 0) found = 0;
meshing3_timer_c.Stop();
NgProfiler::StopTimer (meshing3_timer_c); // NgProfiler::StopTimer (meshing3_timer_c);
if (!found) loktestmode = 0; if (!found) loktestmode = 0;

View File

@ -1028,6 +1028,9 @@ namespace netgen
case 6: typ = PRISM; break; case 6: typ = PRISM; break;
case 8: typ = HEX; break; case 8: typ = HEX; break;
case 10: typ = TET10; break; case 10: typ = TET10; break;
case 13: typ = PYRAMID13; break;
case 15: typ = PRISM15; break;
case 20: typ = HEX20; break;
default: cerr << "Element::Element: unknown element with " << np << " points" << endl; default: cerr << "Element::Element: unknown element with " << np << " points" << endl;
} }
orderx = ordery = orderz = 1; orderx = ordery = orderz = 1;
@ -1108,6 +1111,9 @@ namespace netgen
case 6: typ = PRISM; break; case 6: typ = PRISM; break;
case 8: typ = HEX; break; case 8: typ = HEX; break;
case 10: typ = TET10; break; case 10: typ = TET10; break;
case 13: typ = PYRAMID13; break;
case 15: typ = PRISM15; break;
case 20: typ = HEX20; break;
// //
default: break; default: break;
cerr << "Element::SetNP unknown element with " << np << " points" << endl; cerr << "Element::SetNP unknown element with " << np << " points" << endl;
@ -1126,7 +1132,10 @@ namespace netgen
case PRISM: np = 6; break; case PRISM: np = 6; break;
case HEX: np = 8; break; case HEX: np = 8; break;
case TET10: np = 10; break; case TET10: np = 10; break;
case PYRAMID13: np = 13; break;
case PRISM12: np = 12; break; case PRISM12: np = 12; break;
case PRISM15: np = 15; break;
case HEX20: np = 20; break;
default: break; default: break;
cerr << "Element::SetType unknown type " << int(typ) << endl; cerr << "Element::SetType unknown type " << int(typ) << endl;
@ -1955,7 +1964,27 @@ namespace netgen
shape(4) = p(2); shape(4) = p(2);
break; break;
} }
case PYRAMID13:
{
T x = p(0);
T y = p(1);
T z = p(2);
z *= 1-1e-12;
shape[0] = (-z + z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (-2*x - z + 2)*(-2*y - z + 2))*(-0.5*x - 0.5*y - 0.5*z + 0.25);
shape[1] = (0.5*x - 0.5*y - 0.25)*(-z - z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*x + z)*(-2*y - z + 2));
shape[2] = (-z + z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*x + z)*(2*y + z))*(0.5*x + 0.5*y + 0.5*z - 0.75);
shape[3] = (-0.5*x + 0.5*y - 0.25)*(-z - z*(2*x + z - 1)*(2*y + z - 1)/(-z + 1) + (2*y + z)*(-2*x - z + 2));
shape[4] = z*(2*z - 1);
shape[5] = 2*x*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2);
shape[6] = 4*x*y*(-2*x - 2*z + 2)/(-2*z + 2);
shape[7] = 2*y*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-2*z + 2);
shape[8] = 4*x*y*(-2*y - 2*z + 2)/(-2*z + 2);
shape[9] = z*(-2*x - 2*z + 2)*(-2*y - 2*z + 2)/(-z + 1);
shape[10] = 2*x*z*(-2*y - 2*z + 2)/(-z + 1);
shape[11] = 4*x*y*z/(-z + 1);
shape[12] = 2*y*z*(-2*x - 2*z + 2)/(-z + 1);
break;
}
case PRISM: case PRISM:
{ {
shape(0) = p(0) * (1-p(2)); shape(0) = p(0) * (1-p(2));
@ -1966,6 +1995,30 @@ namespace netgen
shape(5) = (1-p(0)-p(1)) * p(2); shape(5) = (1-p(0)-p(1)) * p(2);
break; break;
} }
case PRISM15:
{
T x = p(0);
T y = p(1);
T z = p(2);
T lam = 1-x-y;
T lamz = 1-z;
shape[0] = (2*x*x-x) * (2*lamz*lamz-lamz);
shape[1] = (2*y*y-y) * (2*lamz*lamz-lamz);
shape[2] = (2*lam*lam-lam) * (2*lamz*lamz-lamz);
shape[3] = (2*x*x-x) * (2*z*z-z);
shape[4] = (2*y*y-y) * (2*z*z-z);
shape[5] = (2*lam*lam-lam) * (2*z*z-z);
shape[6] = 4 * x * y * (2*lamz*lamz-lamz);
shape[7] = 4 * x * lam * (2*lamz*lamz-lamz);
shape[8] = 4 * y * lam * (2*lamz*lamz-lamz);
shape[9] = x * 4 * z * (1-z);
shape[10] = y * 4 * z * (1-z);
shape[11] = lam * 4 * z * (1-z);
shape[12] = 4 * x * y * (2*z*z-z);
shape[13] = 4 * x * lam * (2*z*z-z);
shape[14] = 4 * y * lam * (2*z*z-z);
break;
}
case HEX: case HEX:
{ {
shape(0) = (1-p(0))*(1-p(1))*(1-p(2)); shape(0) = (1-p(0))*(1-p(1))*(1-p(2));
@ -1978,6 +2031,43 @@ namespace netgen
shape(7) = (1-p(0))*( p(1))*( p(2)); shape(7) = (1-p(0))*( p(1))*( p(2));
break; break;
} }
case HEX20:
{
T x = p(0);
T y = p(1);
T z = p(2);
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] = x * y *(z);
shape[7] = (1-x)* y *(z);
T sigma[8]={(1-x)+(1-y)+(1-z),x+(1-y)+(1-z),x+y+(1-z),(1-x)+y+(1-z),
(1-x)+(1-y)+z,x+(1-y)+z,x+y+z,(1-x)+y+z};
static const int e[12][2] =
{
{ 0, 1 }, { 2, 3 }, { 3, 0 }, { 1, 2 },
{ 4, 5 }, { 6, 7 }, { 7, 4 }, { 5, 6 },
{ 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 },
};
for (int i = 0; i < 12; i++)
{
T lame = shape[e[i][0]]+shape[e[i][1]];
T xi = sigma[e[i][1]]-sigma[e[i][0]];
shape[8+i] = (1-xi*xi)*lame;
}
for (int i = 0; i < 12; i++)
{
shape[e[i][0]] -= 0.5 * shape[8+i];
shape[e[i][1]] -= 0.5 * shape[8+i];
}
break;
}
default: default:
throw NgException("Element :: GetNewShape not implemented for that element"); throw NgException("Element :: GetNewShape not implemented for that element");
} }

View File

@ -21,8 +21,8 @@ namespace netgen
SEGMENT = 1, SEGMENT3 = 2, SEGMENT = 1, SEGMENT3 = 2,
TRIG = 10, QUAD=11, TRIG6 = 12, QUAD6 = 13, QUAD8 = 14, TRIG = 10, QUAD=11, TRIG6 = 12, QUAD6 = 13, QUAD8 = 14,
TET = 20, TET10 = 21, TET = 20, TET10 = 21,
PYRAMID = 22, PRISM = 23, PRISM12 = 24, PYRAMID = 22, PRISM = 23, PRISM12 = 24, PRISM15 = 27, PYRAMID13 = 28,
HEX = 25 HEX = 25, HEX20 = 26
}; };
/* /*
@ -45,7 +45,7 @@ namespace netgen
}; };
#define ELEMENT_MAXPOINTS 12 #define ELEMENT_MAXPOINTS 20
#define ELEMENT2D_MAXPOINTS 8 #define ELEMENT2D_MAXPOINTS 8
@ -647,7 +647,7 @@ namespace netgen
/// ///
ELEMENT_TYPE typ; ELEMENT_TYPE typ;
/// number of points (4..tet, 5..pyramid, 6..prism, 8..hex, 10..quad tet, 12..quad prism) /// number of points (4..tet, 5..pyramid, 6..prism, 8..hex, 10..quad tet, 12..quad prism)
int np:5; int np:6;
/// ///
class flagstruct { class flagstruct {
public: public:
@ -708,18 +708,21 @@ namespace netgen
/// ///
uint8_t GetNV() const uint8_t GetNV() const
{ {
__assume(typ >= TET && typ <= HEX); __assume(typ >= TET && typ <= PYRAMID13);
switch (typ) switch (typ)
{ {
case TET: case TET:
case TET10: case TET10:
return 4; return 4;
case PRISM12: case PRISM12:
case PRISM15:
case PRISM: case PRISM:
return 6; return 6;
case PYRAMID: case PYRAMID:
case PYRAMID13:
return 5; return 5;
case HEX: case HEX:
case HEX20:
return 8; return 8;
default: // not a 3D element default: // not a 3D element
#ifdef DEBUG #ifdef DEBUG
@ -794,10 +797,12 @@ namespace netgen
{ {
case TET: case TET:
case TET10: return 4; case TET10: return 4;
case PYRAMID: return 5; case PYRAMID: case PYRAMID13: return 5;
case PRISM: case PRISM:
case PRISM15:
case PRISM12: return 5; case PRISM12: return 5;
case HEX: return 6; case HEX: case HEX20:
return 6;
default: default:
#ifdef DEBUG #ifdef DEBUG
PrintSysError ("element3d::GetNFaces not implemented for typ", typ) PrintSysError ("element3d::GetNFaces not implemented for typ", typ)

View File

@ -35,9 +35,8 @@ namespace netgen
void Mesh :: SendRecvMesh () void Mesh :: SendRecvMesh ()
{ {
int id, np; int id = MyMPI_GetId(GetCommunicator());
MPI_Comm_rank(this->comm, &id); int np = MyMPI_GetNTasks(GetCommunicator());
MPI_Comm_size(this->comm, &np);
if (np == 1) { if (np == 1) {
throw NgException("SendRecvMesh called, but only one rank in communicator!!"); throw NgException("SendRecvMesh called, but only one rank in communicator!!");
@ -73,16 +72,18 @@ namespace netgen
{ {
Array<MPI_Request> sendrequests; Array<MPI_Request> sendrequests;
MPI_Comm comm = GetCommunicator();
int id = MyMPI_GetId(comm);
int ntasks = MyMPI_GetNTasks(comm);
int dim = GetDimension(); int dim = GetDimension();
MyMPI_Bcast(dim); MyMPI_Bcast(dim, comm);
const_cast<MeshTopology&>(GetTopology()).Update(); const_cast<MeshTopology&>(GetTopology()).Update();
PrintMessage ( 3, "Sending nr of elements"); PrintMessage ( 3, "Sending nr of elements");
MPI_Comm comm = this->comm;
Array<int> num_els_on_proc(ntasks); Array<int> num_els_on_proc(ntasks);
num_els_on_proc = 0; num_els_on_proc = 0;
for (ElementIndex ei = 0; ei < GetNE(); ei++) for (ElementIndex ei = 0; ei < GetNE(); ei++)
@ -285,7 +286,7 @@ namespace netgen
for (int dest = 1; dest < ntasks; dest++) for (int dest = 1; dest < ntasks; dest++)
{ {
FlatArray<PointIndex> verts = verts_of_proc[dest]; FlatArray<PointIndex> verts = verts_of_proc[dest];
sendrequests.Append (MyMPI_ISend (verts, dest, MPI_TAG_MESH+1)); sendrequests.Append (MyMPI_ISend (verts, dest, MPI_TAG_MESH+1, comm));
MPI_Datatype mptype = MeshPoint::MyGetMPIType(); MPI_Datatype mptype = MeshPoint::MyGetMPIType();
@ -301,7 +302,7 @@ namespace netgen
MPI_Type_commit (&newtype); MPI_Type_commit (&newtype);
MPI_Request request; MPI_Request request;
MPI_Isend( &points[0], 1, newtype, dest, MPI_TAG_MESH+1, MPI_COMM_WORLD, &request); MPI_Isend( &points[0], 1, newtype, dest, MPI_TAG_MESH+1, comm, &request);
sendrequests.Append (request); sendrequests.Append (request);
} }
@ -367,7 +368,7 @@ namespace netgen
} }
Array<MPI_Request> req_per; Array<MPI_Request> req_per;
for(int dest = 1; dest < ntasks; dest++) for(int dest = 1; dest < ntasks; dest++)
req_per.Append(MyMPI_ISend(pp_data[dest], dest, MPI_TAG_MESH+1)); req_per.Append(MyMPI_ISend(pp_data[dest], dest, MPI_TAG_MESH+1, comm));
MPI_Waitall(req_per.Size(), &req_per[0], MPI_STATUS_IGNORE); MPI_Waitall(req_per.Size(), &req_per[0], MPI_STATUS_IGNORE);
PrintMessage ( 3, "Sending Vertices - distprocs"); PrintMessage ( 3, "Sending Vertices - distprocs");
@ -395,7 +396,7 @@ namespace netgen
} }
for ( int dest = 1; dest < ntasks; dest ++ ) for ( int dest = 1; dest < ntasks; dest ++ )
sendrequests.Append (MyMPI_ISend (distpnums[dest], dest, MPI_TAG_MESH+1)); sendrequests.Append (MyMPI_ISend (distpnums[dest], dest, MPI_TAG_MESH+1, comm));
@ -425,7 +426,7 @@ namespace netgen
} }
for (int dest = 1; dest < ntasks; dest ++ ) for (int dest = 1; dest < ntasks; dest ++ )
sendrequests.Append (MyMPI_ISend (elementarrays[dest], dest, MPI_TAG_MESH+2)); sendrequests.Append (MyMPI_ISend (elementarrays[dest], dest, MPI_TAG_MESH+2, comm));
PrintMessage ( 3, "Sending Face Descriptors" ); PrintMessage ( 3, "Sending Face Descriptors" );
@ -442,7 +443,7 @@ namespace netgen
} }
for (int dest = 1; dest < ntasks; dest++) for (int dest = 1; dest < ntasks; dest++)
sendrequests.Append (MyMPI_ISend (fddata, dest, MPI_TAG_MESH+3)); sendrequests.Append (MyMPI_ISend (fddata, dest, MPI_TAG_MESH+3, comm));
/** Surface Elements **/ /** Surface Elements **/
@ -526,7 +527,7 @@ namespace netgen
}); });
// distribute sel data // distribute sel data
for (int dest = 1; dest < ntasks; dest++) for (int dest = 1; dest < ntasks; dest++)
sendrequests.Append (MyMPI_ISend(selbuf[dest], dest, MPI_TAG_MESH+4)); sendrequests.Append (MyMPI_ISend(selbuf[dest], dest, MPI_TAG_MESH+4, comm));
/** Segments **/ /** Segments **/
@ -577,8 +578,8 @@ namespace netgen
osegs_both.Append(osegs1[l]); osegs_both.Append(osegs1[l]);
} }
for(int l = 0; l<osegs_both.Size(); l++) { for(int l = 0; l<osegs_both.Size(); l++) {
int segnp = (*this)[osegs_both[l]].GetNP(); int segnp2 = (*this)[osegs_both[l]].GetNP();
if(segnp!=segnp) if(segnp!=segnp2)
throw NgException("Tried to identify non-curved and curved Segment!"); throw NgException("Tried to identify non-curved and curved Segment!");
} }
for(int l = 0; l<osegs_both.Size(); l++) { for(int l = 0; l<osegs_both.Size(); l++) {
@ -676,7 +677,7 @@ namespace netgen
}); });
// distrubute segment data // distrubute segment data
for (int dest = 1; dest < ntasks; dest++) for (int dest = 1; dest < ntasks; dest++)
sendrequests.Append (MyMPI_ISend(segm_buf[dest], dest, MPI_TAG_MESH+5)); sendrequests.Append (MyMPI_ISend(segm_buf[dest], dest, MPI_TAG_MESH+5, comm));
PrintMessage ( 3, "now wait ..."); PrintMessage ( 3, "now wait ...");
@ -700,9 +701,9 @@ namespace netgen
compiled_bcnames[tot_bcsize++] = (*bcnames[k])[j]; compiled_bcnames[tot_bcsize++] = (*bcnames[k])[j];
for(int k=1;k<ntasks;k++) { for(int k=1;k<ntasks;k++) {
sendrequests[6*(k-1)] = MyMPI_ISend(FlatArray<int>(1, &nbcs), k, MPI_TAG_MESH+6); sendrequests[6*(k-1)] = MyMPI_ISend(FlatArray<int>(1, &nbcs), k, MPI_TAG_MESH+6, comm);
sendrequests[6*(k-1)+1] = MyMPI_ISend(bcname_sizes, k, MPI_TAG_MESH+6); sendrequests[6*(k-1)+1] = MyMPI_ISend(bcname_sizes, k, MPI_TAG_MESH+6, comm);
(void) MPI_Isend(compiled_bcnames, tot_bcsize, MPI_CHAR, k, MPI_TAG_MESH+6, MPI_COMM_WORLD, &sendrequests[6*(k-1)+2]); (void) MPI_Isend(compiled_bcnames, tot_bcsize, MPI_CHAR, k, MPI_TAG_MESH+6, comm, &sendrequests[6*(k-1)+2]);
} }
/** Send mat-names **/ /** Send mat-names **/
@ -719,9 +720,9 @@ namespace netgen
for(int j=0;j<mat_sizes[k];j++) for(int j=0;j<mat_sizes[k];j++)
compiled_mats[tot_matsize++] = (*materials[k])[j]; compiled_mats[tot_matsize++] = (*materials[k])[j];
for(int k=1;k<ntasks;k++) { for(int k=1;k<ntasks;k++) {
sendrequests[6*(k-1)+3] = MyMPI_ISend(FlatArray<int>(1, &nmats), k, MPI_TAG_MESH+6); sendrequests[6*(k-1)+3] = MyMPI_ISend(FlatArray<int>(1, &nmats), k, MPI_TAG_MESH+6, comm);
sendrequests[6*(k-1)+4] = MyMPI_ISend(mat_sizes, k, MPI_TAG_MESH+6); sendrequests[6*(k-1)+4] = MyMPI_ISend(mat_sizes, k, MPI_TAG_MESH+6, comm);
(void) MPI_Isend(compiled_mats, tot_matsize, MPI_CHAR, k, MPI_TAG_MESH+6, MPI_COMM_WORLD, &sendrequests[6*(k-1)+5]); (void) MPI_Isend(compiled_mats, tot_matsize, MPI_CHAR, k, MPI_TAG_MESH+6, comm, &sendrequests[6*(k-1)+5]);
} }
/* now wait ... **/ /* now wait ... **/
@ -731,7 +732,7 @@ namespace netgen
PrintMessage( 3, "send mesh complete"); PrintMessage( 3, "send mesh complete");
MPI_Barrier(MPI_COMM_WORLD); MPI_Barrier(comm);
} }
@ -750,14 +751,17 @@ namespace netgen
int timer_sels = NgProfiler::CreateTimer ("Receive surface elements"); int timer_sels = NgProfiler::CreateTimer ("Receive surface elements");
NgProfiler::RegionTimer reg(timer); NgProfiler::RegionTimer reg(timer);
int id = MyMPI_GetId(GetCommunicator());
int ntasks = MyMPI_GetNTasks(GetCommunicator());
int dim; int dim;
MyMPI_Bcast(dim); MyMPI_Bcast(dim, comm);
SetDimension(dim); SetDimension(dim);
// Receive number of local elements // Receive number of local elements
int nelloc; int nelloc;
MPI_Scatter (NULL, 0, MPI_INT, MPI_Scatter (NULL, 0, MPI_INT,
&nelloc, 1, MPI_INT, 0, MPI_COMM_WORLD); &nelloc, 1, MPI_INT, 0, comm);
paralleltop -> SetNE (nelloc); paralleltop -> SetNE (nelloc);
// string st; // string st;
@ -766,8 +770,7 @@ namespace netgen
NgProfiler::StartTimer (timer_pts); NgProfiler::StartTimer (timer_pts);
Array<int> verts; Array<int> verts;
MyMPI_Recv (verts, 0, MPI_TAG_MESH+1); MyMPI_Recv (verts, 0, MPI_TAG_MESH+1, comm);
int numvert = verts.Size(); int numvert = verts.Size();
paralleltop -> SetNV (numvert); paralleltop -> SetNV (numvert);
@ -787,11 +790,10 @@ namespace netgen
MPI_Datatype mptype = MeshPoint::MyGetMPIType(); MPI_Datatype mptype = MeshPoint::MyGetMPIType();
MPI_Status status; MPI_Status status;
MPI_Recv( &points[1], numvert, mptype, 0, MPI_TAG_MESH+1, MPI_COMM_WORLD, &status); MPI_Recv( &points[1], numvert, mptype, 0, MPI_TAG_MESH+1, comm, &status);
Array<int> pp_data; Array<int> pp_data;
MyMPI_Recv(pp_data, 0, MPI_TAG_MESH+1); MyMPI_Recv(pp_data, 0, MPI_TAG_MESH+1, comm);
int maxidentnr = pp_data[0]; int maxidentnr = pp_data[0];
auto & idents = GetIdentifications(); auto & idents = GetIdentifications();
@ -815,7 +817,7 @@ namespace netgen
} }
Array<int> dist_pnums; Array<int> dist_pnums;
MyMPI_Recv (dist_pnums, 0, MPI_TAG_MESH+1); MyMPI_Recv (dist_pnums, 0, MPI_TAG_MESH+1, comm);
for (int hi = 0; hi < dist_pnums.Size(); hi += 3) for (int hi = 0; hi < dist_pnums.Size(); hi += 3)
paralleltop -> paralleltop ->
@ -828,7 +830,7 @@ namespace netgen
Element el; Element el;
Array<int> elarray; Array<int> elarray;
MyMPI_Recv (elarray, 0, MPI_TAG_MESH+2); MyMPI_Recv (elarray, 0, MPI_TAG_MESH+2, comm);
NgProfiler::RegionTimer reg(timer_els); NgProfiler::RegionTimer reg(timer_els);
@ -848,7 +850,7 @@ namespace netgen
{ {
Array<double> fddata; Array<double> fddata;
MyMPI_Recv (fddata, 0, MPI_TAG_MESH+3); MyMPI_Recv (fddata, 0, MPI_TAG_MESH+3, comm);
for (int i = 0; i < fddata.Size(); i += 6) for (int i = 0; i < fddata.Size(); i += 6)
{ {
int faceind = AddFaceDescriptor int faceind = AddFaceDescriptor
@ -863,7 +865,7 @@ namespace netgen
NgProfiler::RegionTimer reg(timer_sels); NgProfiler::RegionTimer reg(timer_sels);
Array<int> selbuf; Array<int> selbuf;
MyMPI_Recv ( selbuf, 0, MPI_TAG_MESH+4); MyMPI_Recv ( selbuf, 0, MPI_TAG_MESH+4, comm);
int ii = 0; int ii = 0;
int sel = 0; int sel = 0;
@ -894,7 +896,7 @@ namespace netgen
{ {
Array<double> segmbuf; Array<double> segmbuf;
MyMPI_Recv ( segmbuf, 0, MPI_TAG_MESH+5); MyMPI_Recv ( segmbuf, 0, MPI_TAG_MESH+5, comm);
Segment seg; Segment seg;
int globsegi; int globsegi;
@ -939,14 +941,14 @@ namespace netgen
/** Recv bc-names **/ /** Recv bc-names **/
int nbcs; int nbcs;
MyMPI_Recv(nbcs, 0, MPI_TAG_MESH+6); MyMPI_Recv(nbcs, 0, MPI_TAG_MESH+6, comm);
Array<int> bcs(nbcs); Array<int> bcs(nbcs);
MyMPI_Recv(bcs, 0, MPI_TAG_MESH+6); MyMPI_Recv(bcs, 0, MPI_TAG_MESH+6, comm);
int size_bc = 0; int size_bc = 0;
for(int k=0;k<nbcs;k++) for(int k=0;k<nbcs;k++)
size_bc += bcs[k]; size_bc += bcs[k];
char compiled_bcnames[size_bc]; char compiled_bcnames[size_bc];
MPI_Recv(compiled_bcnames, size_bc, MPI_CHAR, 0, MPI_TAG_MESH+6, MPI_COMM_WORLD, MPI_STATUS_IGNORE); MPI_Recv(compiled_bcnames, size_bc, MPI_CHAR, 0, MPI_TAG_MESH+6, comm, MPI_STATUS_IGNORE);
SetNBCNames(nbcs); SetNBCNames(nbcs);
int cnt = 0; int cnt = 0;
@ -957,14 +959,14 @@ namespace netgen
/** Recv mat-names **/ /** Recv mat-names **/
int nmats; int nmats;
MyMPI_Recv(nmats, 0, MPI_TAG_MESH+6); MyMPI_Recv(nmats, 0, MPI_TAG_MESH+6, comm);
Array<int> matsz(nmats); Array<int> matsz(nmats);
MyMPI_Recv(matsz, 0, MPI_TAG_MESH+6); MyMPI_Recv(matsz, 0, MPI_TAG_MESH+6, comm);
int size_mats = 0; int size_mats = 0;
for(int k=0;k<nmats;k++) for(int k=0;k<nmats;k++)
size_mats += matsz[k]; size_mats += matsz[k];
char compiled_mats[size_mats]; char compiled_mats[size_mats];
MPI_Recv(compiled_mats, size_mats, MPI_CHAR, 0, MPI_TAG_MESH+6, MPI_COMM_WORLD, MPI_STATUS_IGNORE); MPI_Recv(compiled_mats, size_mats, MPI_CHAR, 0, MPI_TAG_MESH+6, comm, MPI_STATUS_IGNORE);
cnt = 0; cnt = 0;
materials.SetSize(nmats); materials.SetSize(nmats);
for(int k=0;k<nmats;k++) { for(int k=0;k<nmats;k++) {
@ -973,7 +975,7 @@ namespace netgen
cnt += matsz[k]; cnt += matsz[k];
} }
MPI_Barrier(MPI_COMM_WORLD); MPI_Barrier(comm);
int timerloc = NgProfiler::CreateTimer ("Update local mesh"); int timerloc = NgProfiler::CreateTimer ("Update local mesh");
int timerloc2 = NgProfiler::CreateTimer ("CalcSurfacesOfNode"); int timerloc2 = NgProfiler::CreateTimer ("CalcSurfacesOfNode");
@ -982,7 +984,8 @@ namespace netgen
stringstream str; stringstream str;
str << "p" << id << ": got " << GetNE() << " elements and " str << "p" << id << ": got " << GetNE() << " elements and "
<< GetNSE() << " surface elements"; << GetNSE() << " surface elements";
cout << str.str() << endl; PrintMessage(2, str.str());
// cout << str.str() << endl;
// PrintMessage (2, "Got ", GetNE(), " elements and ", GetNSE(), " surface elements"); // PrintMessage (2, "Got ", GetNE(), " elements and ", GetNSE(), " surface elements");
// PrintMessage (2, "Got ", GetNSE(), " surface elements"); // PrintMessage (2, "Got ", GetNSE(), " surface elements");
@ -1008,8 +1011,9 @@ namespace netgen
// call it only for the master ! // call it only for the master !
void Mesh :: Distribute () void Mesh :: Distribute ()
{ {
MPI_Comm_size(MPI_COMM_WORLD, &ntasks); MPI_Comm comm = GetCommunicator();
MPI_Comm_rank(MPI_COMM_WORLD, &id); int id = MyMPI_GetId(comm);
int ntasks = MyMPI_GetNTasks(comm);
if (id != 0 || ntasks == 1 ) return; if (id != 0 || ntasks == 1 ) return;
@ -1068,28 +1072,44 @@ namespace netgen
eptr.Append (eind.Size()); eptr.Append (eind.Size());
Array<idx_t> epart(ne), npart(nn); Array<idx_t> epart(ne), npart(nn);
idxtype nparts = ntasks-1; idxtype nparts = MyMPI_GetNTasks(GetCommunicator())-1;
idxtype edgecut;
idxtype ncommon = 3; if (nparts == 1)
METIS_PartMeshDual (&ne, &nn, &eptr[0], &eind[0], NULL, NULL, &ncommon, &nparts, {
NULL, NULL, for (int i = 0; i < GetNE(); i++)
&edgecut, &epart[0], &npart[0]); VolumeElement(i+1).SetPartition(1);
for (int i = 0; i < GetNSE(); i++)
SurfaceElement(i+1).SetPartition(1);
for (int i = 0; i < GetNSeg(); i++)
LineSegment(i+1).SetPartition(1);
}
/* else
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);
for (int i = 0; i < GetNSE(); i++) idxtype edgecut;
SurfaceElement(i+1).SetPartition(epart[i+GetNE()] + 1);
for (int i = 0; i < GetNSeg(); i++) idxtype ncommon = 3;
LineSegment(i+1).SetPartition(epart[i+GetNE()+GetNSE()] + 1); METIS_PartMeshDual (&ne, &nn, &eptr[0], &eind[0], NULL, NULL, &ncommon, &nparts,
NULL, NULL,
&edgecut, &epart[0], &npart[0]);
/*
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);
for (int i = 0; i < GetNSE(); i++)
SurfaceElement(i+1).SetPartition(epart[i+GetNE()] + 1);
for (int i = 0; i < GetNSeg(); i++)
LineSegment(i+1).SetPartition(epart[i+GetNE()+GetNSE()] + 1);
}
// surface elements attached to volume elements // surface elements attached to volume elements
@ -1120,12 +1140,9 @@ namespace netgen
for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++) for (SurfaceElementIndex sei = 0; sei < GetNSE(); sei++)
{ {
const Element2d & el = (*this)[sei]; const Element2d & el = (*this)[sei];
cout << "surf-el " << sei << " verts: " << endl;
for (int j = 0; j < el.GetNP(); j++) { for (int j = 0; j < el.GetNP(); j++) {
cout << el[j] << " ";
f(el[j], sei); f(el[j], sei);
} }
cout << endl;
} }
}; };
auto loop_els_3d = [&](auto f) { auto loop_els_3d = [&](auto f) {
@ -1150,7 +1167,6 @@ namespace netgen
if(boundarypoints[vertex]) if(boundarypoints[vertex])
cnt[vertex]++; cnt[vertex]++;
}); });
cout << "count: " << endl << cnt << endl;
TABLE<int, PointIndex::BASE> pnt2el(cnt); TABLE<int, PointIndex::BASE> pnt2el(cnt);
loop_els([&](auto vertex, int index) loop_els([&](auto vertex, int index)
{ {
@ -1277,8 +1293,9 @@ namespace netgen
// call it only for the master ! // call it only for the master !
void Mesh :: Distribute (Array<int> & volume_weights , Array<int> & surface_weights, Array<int> & segment_weights) void Mesh :: Distribute (Array<int> & volume_weights , Array<int> & surface_weights, Array<int> & segment_weights)
{ {
MPI_Comm_size(MPI_COMM_WORLD, &ntasks); MPI_Comm comm = GetCommunicator();
MPI_Comm_rank(MPI_COMM_WORLD, &id); int id = MyMPI_GetId(comm);
int ntasks = MyMPI_GetNTasks(comm);
if (id != 0 || ntasks == 1 ) return; if (id != 0 || ntasks == 1 ) return;
@ -1368,7 +1385,20 @@ namespace netgen
eptr.Append (eind.Size()); eptr.Append (eind.Size());
Array<idx_t> epart(ne), npart(nn); Array<idx_t> epart(ne), npart(nn);
idxtype nparts = ntasks-1; idxtype nparts = MyMPI_GetNTasks(GetCommunicator())-1;
if (nparts == 1)
{
for (int i = 0; i < GetNE(); i++)
VolumeElement(i+1).SetPartition(1);
for (int i = 0; i < GetNSE(); i++)
SurfaceElement(i+1).SetPartition(1);
for (int i = 0; i < GetNSeg(); i++)
LineSegment(i+1).SetPartition(1);
return;
}
idxtype edgecut; idxtype edgecut;

View File

@ -25,6 +25,9 @@ namespace netgen
{ {
*testout << "ParallelMeshTopology::Reset" << endl; *testout << "ParallelMeshTopology::Reset" << endl;
int id = MyMPI_GetId(mesh.GetCommunicator());
int ntasks = MyMPI_GetNTasks(mesh.GetCommunicator());
if ( ntasks == 1 ) return; if ( ntasks == 1 ) return;
int ned = mesh.GetTopology().GetNEdges(); int ned = mesh.GetTopology().GetNEdges();
@ -206,6 +209,10 @@ namespace netgen
// cout << "UpdateCoarseGrid" << endl; // cout << "UpdateCoarseGrid" << endl;
// if (is_updated) return; // if (is_updated) return;
MPI_Comm comm = mesh.GetCommunicator();
int id = MyMPI_GetId(comm);
int ntasks = MyMPI_GetNTasks(comm);
Reset(); Reset();
static int timer = NgProfiler::CreateTimer ("UpdateCoarseGrid"); static int timer = NgProfiler::CreateTimer ("UpdateCoarseGrid");
NgProfiler::RegionTimer reg(timer); NgProfiler::RegionTimer reg(timer);
@ -222,14 +229,14 @@ namespace netgen
// MPI_Barrier (MPI_COMM_WORLD); // MPI_Barrier (MPI_COMM_WORLD);
MPI_Group MPI_GROUP_WORLD; MPI_Group MPI_GROUP_comm;
MPI_Group MPI_LocalGroup; MPI_Group MPI_LocalGroup;
MPI_Comm MPI_LocalComm; MPI_Comm MPI_LocalComm;
int process_ranks[] = { 0 }; int process_ranks[] = { 0 };
MPI_Comm_group (MPI_COMM_WORLD, &MPI_GROUP_WORLD); MPI_Comm_group (comm, &MPI_GROUP_comm);
MPI_Group_excl (MPI_GROUP_WORLD, 1, process_ranks, &MPI_LocalGroup); MPI_Group_excl (MPI_GROUP_comm, 1, process_ranks, &MPI_LocalGroup);
MPI_Comm_create (MPI_COMM_WORLD, MPI_LocalGroup, &MPI_LocalComm); MPI_Comm_create (comm, MPI_LocalGroup, &MPI_LocalComm);
if (id == 0) return; if (id == 0) return;

View File

@ -17,6 +17,22 @@ namespace netgen
{ {
extern bool netgen_executable_started; extern bool netgen_executable_started;
extern shared_ptr<NetgenGeometry> ng_geometry; extern shared_ptr<NetgenGeometry> ng_geometry;
#ifdef PARALLEL
/** we need allreduce in python-wrapped communicators **/
template <typename T>
inline T MyMPI_AllReduceNG (T d, const MPI_Op & op = MPI_SUM, MPI_Comm comm = ng_comm)
{
T global_d;
MPI_Allreduce ( &d, &global_d, 1, MyGetMPIType<T>(), op, comm);
return global_d;
}
#else
enum { MPI_SUM = 0, MPI_MIN = 1, MPI_MAX = 2 };
typedef int MPI_Op;
template <typename T>
inline T MyMPI_AllReduceNG (T d, const MPI_Op & op = MPI_SUM, MPI_Comm comm = ng_comm)
{ return d; }
#endif
} }
@ -80,6 +96,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
.def(py::self-py::self) .def(py::self-py::self)
.def(py::self+Vec<2>()) .def(py::self+Vec<2>())
.def(py::self-Vec<2>()) .def(py::self-Vec<2>())
.def("__getitem__", [](Point<2>& self, int index) { return self[index]; })
; ;
py::class_<Point<3>> (m, "Point3d") py::class_<Point<3>> (m, "Point3d")
@ -88,6 +105,7 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
.def(py::self-py::self) .def(py::self-py::self)
.def(py::self+Vec<3>()) .def(py::self+Vec<3>())
.def(py::self-Vec<3>()) .def(py::self-Vec<3>())
.def("__getitem__", [](Point<2>& self, int index) { return self[index]; })
; ;
m.def ("Pnt", FunctionPointer m.def ("Pnt", FunctionPointer
@ -111,6 +129,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
.def(-py::self) .def(-py::self)
.def(double()*py::self) .def(double()*py::self)
.def("Norm", &Vec<2>::Length) .def("Norm", &Vec<2>::Length)
.def("__getitem__", [](Vec<2>& vec, int index) { return vec[index]; })
.def("__len__", [](Vec<2>& /*unused*/) { return 2; })
; ;
py::class_<Vec<3>> (m, "Vec3d") py::class_<Vec<3>> (m, "Vec3d")
@ -121,6 +141,8 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
.def(-py::self) .def(-py::self)
.def(double()*py::self) .def(double()*py::self)
.def("Norm", &Vec<3>::Length) .def("Norm", &Vec<3>::Length)
.def("__getitem__", [](Vec<3>& vec, int index) { return vec[index]; })
.def("__len__", [](Vec<3>& /*unused*/) { return 3; })
; ;
m.def ("Vec", FunctionPointer m.def ("Vec", FunctionPointer
@ -234,37 +256,19 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
py::class_<Element>(m, "Element3D") py::class_<Element>(m, "Element3D")
.def(py::init([](int index, py::list vertices) .def(py::init([](int index, py::list vertices)
{ {
Element * newel = nullptr; std::map<int, ELEMENT_TYPE> types = {{4, TET},
if (py::len(vertices) == 4) {5, PYRAMID},
{ {6, PRISM},
newel = new Element(TET); {8, HEX},
for (int i = 0; i < 4; i++) {10, TET10},
(*newel)[i] = py::extract<PointIndex>(vertices[i])(); {13, PYRAMID13},
newel->SetIndex(index); {15, PRISM15},
} {20, HEX20}};
else if (py::len(vertices) == 5) int np = py::len(vertices);
{ auto newel = new Element(types[np]);
newel = new Element(PYRAMID); for(int i=0; i<np; i++)
for (int i = 0; i < 5; i++) (*newel)[i] = py::cast<PointIndex>(vertices[i]);
(*newel)[i] = py::extract<PointIndex>(vertices[i])(); newel->SetIndex(index);
newel->SetIndex(index);
}
else if (py::len(vertices) == 6)
{
newel = new Element(PRISM);
for (int i = 0; i < 6; i++)
(*newel)[i] = py::extract<PointIndex>(vertices[i])();
newel->SetIndex(index);
}
else if (py::len(vertices) == 8)
{
newel = new Element(HEX);
for (int i = 0; i < 8; i++)
(*newel)[i] = py::extract<PointIndex>(vertices[i])();
newel->SetIndex(index);
}
else
throw NgException ("cannot create element");
return newel; return newel;
}), }),
py::arg("index")=1,py::arg("vertices"), py::arg("index")=1,py::arg("vertices"),
@ -316,6 +320,13 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
(*newel)[i] = py::extract<PointIndex>(vertices[i])(); (*newel)[i] = py::extract<PointIndex>(vertices[i])();
newel->SetIndex(index); newel->SetIndex(index);
} }
else if (py::len(vertices) == 8)
{
newel = new Element2d(QUAD8);
for(int i = 0; i<8; i++)
(*newel)[i] = py::extract<PointIndex>(vertices[i])();
newel->SetIndex(index);
}
else else
throw NgException("Inconsistent number of vertices in Element2D"); throw NgException("Inconsistent number of vertices in Element2D");
return newel; return newel;
@ -483,18 +494,21 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
py::class_<Mesh,shared_ptr<Mesh>>(m, "Mesh") py::class_<Mesh,shared_ptr<Mesh>>(m, "Mesh")
// .def(py::init<>("create empty mesh")) // .def(py::init<>("create empty mesh"))
.def(py::init( [] (int dim) .def(py::init( [] (int dim, shared_ptr<PyMPI_Comm> pycomm)
{ {
auto mesh = make_shared<Mesh>(); auto mesh = make_shared<Mesh>();
mesh->SetCommunicator(pycomm!=nullptr ? pycomm->comm : netgen::ng_comm);
mesh -> SetDimension(dim); mesh -> SetDimension(dim);
SetGlobalMesh(mesh); // for visualization SetGlobalMesh(mesh); // for visualization
mesh -> SetGeometry (nullptr); mesh -> SetGeometry (nullptr);
return mesh; return mesh;
} ), } ),
py::arg("dim")=3 py::arg("dim")=3, py::arg("comm")=nullptr
) )
.def(NGSPickle<Mesh>()) .def(NGSPickle<Mesh>())
.def_property_readonly("comm", [](const Mesh & amesh)
{ return make_shared<PyMPI_Comm>(amesh.GetCommunicator()); },
"MPI-communicator the Mesh lives in")
/* /*
.def("__init__", .def("__init__",
[](Mesh *instance, int dim) [](Mesh *instance, int dim)
@ -506,17 +520,33 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
) )
*/ */
.def("__str__", &ToString<Mesh>)
.def_property_readonly("_timestamp", &Mesh::GetTimeStamp) .def_property_readonly("_timestamp", &Mesh::GetTimeStamp)
.def("Distribute", [](shared_ptr<Mesh> self, shared_ptr<PyMPI_Comm> pycomm) {
MPI_Comm comm = pycomm!=nullptr ? pycomm->comm : self->GetCommunicator();
self->SetCommunicator(comm);
if(MyMPI_GetNTasks(comm)==1) return self;
// if(MyMPI_GetNTasks(comm)==2) throw NgException("Sorry, cannot handle communicators with NP=2!");
// cout << " rank " << MyMPI_GetId(comm) << " of " << MyMPI_GetNTasks(comm) << " called Distribute " << endl;
if(MyMPI_GetId(comm)==0) self->Distribute();
else self->SendRecvMesh();
return self;
}, py::arg("comm")=nullptr)
.def("Receive", [](shared_ptr<PyMPI_Comm> pycomm) {
auto mesh = make_shared<Mesh>();
mesh->SetCommunicator(pycomm->comm);
mesh->SendRecvMesh();
return mesh;
})
.def("Load", FunctionPointer .def("Load", FunctionPointer
([](Mesh & self, const string & filename) ([](Mesh & self, const string & filename)
{ {
istream * infile; istream * infile;
#ifdef PARALLEL MPI_Comm comm = self.GetCommunicator();
MPI_Comm_rank(MPI_COMM_WORLD, &id); id = MyMPI_GetId(comm);
MPI_Comm_size(MPI_COMM_WORLD, &ntasks); ntasks = MyMPI_GetNTasks(comm);
#ifdef PARALLEL
char* buf = nullptr; char* buf = nullptr;
int strs = 0; int strs = 0;
if(id==0) { if(id==0) {
@ -544,10 +574,10 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
} }
/** Scatter the geometry-string **/ /** Scatter the geometry-string **/
MPI_Bcast(&strs, 1, MPI_INT, 0, MPI_COMM_WORLD); MPI_Bcast(&strs, 1, MPI_INT, 0, comm);
if(id!=0) if(id!=0)
buf = new char[strs]; buf = new char[strs];
MPI_Bcast(buf, strs, MPI_CHAR, 0, MPI_COMM_WORLD); MPI_Bcast(buf, strs, MPI_CHAR, 0, comm);
if(id==0) if(id==0)
delete infile; delete infile;
infile = new istringstream(string((const char*)buf, (size_t)strs)); infile = new istringstream(string((const char*)buf, (size_t)strs));
@ -902,6 +932,61 @@ DLL_HEADER void ExportNetgenMeshing(py::module &m)
printmessage_importance = importance; printmessage_importance = importance;
return old; return old;
})); }));
py::class_<PyMPI_Comm, shared_ptr<PyMPI_Comm>> (m, "MPI_Comm")
.def_property_readonly ("rank", &PyMPI_Comm::Rank)
.def_property_readonly ("size", &PyMPI_Comm::Size)
// .def_property_readonly ("rank", [](PyMPI_Comm & c) { cout << "rank for " << c.comm << endl; return c.Rank(); })
// .def_property_readonly ("size", [](PyMPI_Comm & c) { cout << "size for " << c.comm << endl; return c.Size(); })
#ifdef PARALLEL
.def("Barrier", [](PyMPI_Comm & c) { MPI_Barrier(c.comm); })
.def("WTime", [](PyMPI_Comm & c) { return MPI_Wtime(); })
#else
.def("Barrier", [](PyMPI_Comm & c) { })
.def("WTime", [](PyMPI_Comm & c) { return -1.0; })
#endif
.def("Sum", [](PyMPI_Comm & c, double x) { return MyMPI_AllReduceNG(x, MPI_SUM, c.comm); })
.def("Min", [](PyMPI_Comm & c, double x) { return MyMPI_AllReduceNG(x, MPI_MIN, c.comm); })
.def("Max", [](PyMPI_Comm & c, double x) { return MyMPI_AllReduceNG(x, MPI_MAX, c.comm); })
.def("Sum", [](PyMPI_Comm & c, int x) { return MyMPI_AllReduceNG(x, MPI_SUM, c.comm); })
.def("Min", [](PyMPI_Comm & c, int x) { return MyMPI_AllReduceNG(x, MPI_MIN, c.comm); })
.def("Max", [](PyMPI_Comm & c, int x) { return MyMPI_AllReduceNG(x, MPI_MAX, c.comm); })
.def("Sum", [](PyMPI_Comm & c, size_t x) { return MyMPI_AllReduceNG(x, MPI_SUM, c.comm); })
.def("Min", [](PyMPI_Comm & c, size_t x) { return MyMPI_AllReduceNG(x, MPI_MIN, c.comm); })
.def("Max", [](PyMPI_Comm & c, size_t x) { return MyMPI_AllReduceNG(x, MPI_MAX, c.comm); })
.def("SubComm", [](PyMPI_Comm & c, std::vector<int> proc_list) {
Array<int> 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");
MPI_Comm subcomm = MyMPI_SubCommunicator(c.comm, procs);
return make_shared<PyMPI_Comm>(subcomm, true);
/*
Array<int> procs;
if (py::extract<py::list> (proc_list).check()) {
py::list pylist = py::extract<py::list> (proc_list)();
procs.SetSize(py::len(pyplist));
for (int i = 0; i < py::len(pylist); i++)
procs[i] = py::extract<int>(pylist[i])();
}
else {
throw Exception("SubComm needs a list!");
}
if(!procs.Size()) {
cout << "warning, tried to construct empty communicator, returning MPI_COMM_NULL" << endl;
return make_shared<PyMPI_Comm>(MPI_COMM_NULL);
}
else if(procs.Size()==2) {
throw Exception("Sorry, NGSolve cannot handle NP=2.");
}
MPI_Comm subcomm = MyMPI_SubCommunicator(c.comm, procs);
return make_shared<PyMPI_Comm>(subcomm, true);
*/
}, py::arg("procs"));
;
} }
PYBIND11_MODULE(libmesh, m) { PYBIND11_MODULE(libmesh, m) {

View File

@ -223,6 +223,45 @@ namespace netgen
{ 3, 4, 10 }, { 3, 4, 10 },
{ 4, 5, 11 }, { 4, 5, 11 },
}; };
static int betw_prism15[9][3] =
{
{ 0, 1, 6 },
{ 0, 2, 7 },
{ 1, 2, 8 },
{ 0, 3, 9 },
{ 1, 4, 10 },
{ 2, 5, 11 },
{ 3, 4, 12 },
{ 3, 5, 13 },
{ 4, 5, 14 }
};
static int betw_pyramid[8][3] =
{
{ 0, 1, 5 },
{ 3, 2, 6 },
{ 3, 0, 7 },
{ 1, 2, 8 },
{ 0, 4, 9 },
{ 1, 4, 10 },
{ 2, 4, 11 },
{ 3, 4, 12 }
};
static int betw_hex[12][3] =
{
{ 0, 1, 8 },
{ 2, 3, 9 },
{ 3, 0, 10 },
{ 1, 2, 11 },
{ 4, 5, 12 },
{ 6, 7, 13 },
{ 7, 4, 14 },
{ 5, 6, 15 },
{ 0, 4, 16 },
{ 1, 5, 17 },
{ 2, 6, 18 },
{ 3, 7, 19 },
};
int (*betw)[3] = NULL; int (*betw)[3] = NULL;
switch (el.GetType()) switch (el.GetType())
@ -243,6 +282,29 @@ namespace netgen
onp = 6; onp = 6;
break; break;
} }
case PRISM15:
{
betw = betw_prism15;
newel.SetType(PRISM15);
onp = 6;
break;
}
case PYRAMID:
case PYRAMID13:
{
betw = betw_pyramid;
newel.SetType(PYRAMID13);
onp = 5;
break;
}
case HEX:
case HEX20:
{
betw = betw_hex;
newel.SetType (HEX20);
onp = 8;
break;
}
default: default:
PrintSysError ("MakeSecondOrder, illegal vol type ", int(el.GetType())); PrintSysError ("MakeSecondOrder, illegal vol type ", int(el.GetType()));
} }

View File

@ -1353,6 +1353,8 @@ void Mesh :: ImproveMesh (const CSG eometry & geometry, OPTIMIZEGOAL goal)
void Mesh :: ImproveMesh (const MeshingParameters & mp, OPTIMIZEGOAL goal) void Mesh :: ImproveMesh (const MeshingParameters & mp, OPTIMIZEGOAL goal)
{ {
static Timer t("Mesh::ImproveMesh"); RegionTimer reg(t);
int typ = 1; int typ = 1;
(*testout) << "Improve Mesh" << "\n"; (*testout) << "Improve Mesh" << "\n";

View File

@ -543,7 +543,7 @@ namespace netgen
cnt = 0; cnt = 0;
ParallelForRange ParallelForRange
(tm, mesh->Points().Size(), (tm, mesh->GetNV(), // Points().Size(),
[&] (size_t begin, size_t end) [&] (size_t begin, size_t end)
{ {
INDEX_CLOSED_HASHTABLE<int> v2eht(2*max_edge_on_vertex+10); INDEX_CLOSED_HASHTABLE<int> v2eht(2*max_edge_on_vertex+10);
@ -581,7 +581,9 @@ namespace netgen
// accumulate number of edges // accumulate number of edges
int ned = edge2vert.Size(); int ned = edge2vert.Size();
for (auto v : mesh->Points().Range())
// for (size_t v = 0; v < mesh->GetNV(); v++)
for (size_t v : cnt.Range())
{ {
auto hv = cnt[v]; auto hv = cnt[v];
cnt[v] = ned; cnt[v] = ned;
@ -595,7 +597,7 @@ namespace netgen
// for (PointIndex v = PointIndex::BASE; v < nv+PointIndex::BASE; v++) // for (PointIndex v = PointIndex::BASE; v < nv+PointIndex::BASE; v++)
ParallelForRange ParallelForRange
(tm, mesh->Points().Size(), (tm, mesh->GetNV(), // Points().Size(),
[&] (size_t begin, size_t end) [&] (size_t begin, size_t end)
{ {
INDEX_CLOSED_HASHTABLE<int> v2eht(2*max_edge_on_vertex+10); INDEX_CLOSED_HASHTABLE<int> v2eht(2*max_edge_on_vertex+10);
@ -719,7 +721,7 @@ namespace netgen
// for (auto v : mesh.Points().Range()) // for (auto v : mesh.Points().Range())
NgProfiler::StartTimer (timer2b1); NgProfiler::StartTimer (timer2b1);
ParallelForRange ParallelForRange
(tm, mesh->Points().Size(), (tm, mesh->GetNV(), // Points().Size(),
[&] (size_t begin, size_t end) [&] (size_t begin, size_t end)
{ {
INDEX_3_CLOSED_HASHTABLE<int> vert2face(2*max_face_on_vertex+10); INDEX_3_CLOSED_HASHTABLE<int> vert2face(2*max_face_on_vertex+10);
@ -754,7 +756,9 @@ namespace netgen
// accumulate number of faces // accumulate number of faces
int nfa = oldnfa; int nfa = oldnfa;
for (auto v : mesh->Points().Range()) // for (auto v : Range(mesh->GetNV())) // Points().Range())
// for (size_t v = 0; v < mesh->GetNV(); v++)
for (auto v : cnt.Range())
{ {
auto hv = cnt[v]; auto hv = cnt[v];
cnt[v] = nfa; cnt[v] = nfa;
@ -765,7 +769,7 @@ namespace netgen
// for (auto v : mesh.Points().Range()) // for (auto v : mesh.Points().Range())
ParallelForRange ParallelForRange
(tm, mesh->Points().Size(), (tm, mesh->GetNV(), // Points().Size(),
[&] (size_t begin, size_t end) [&] (size_t begin, size_t end)
{ {
INDEX_3_CLOSED_HASHTABLE<int> vert2face(2*max_face_on_vertex+10); INDEX_3_CLOSED_HASHTABLE<int> vert2face(2*max_face_on_vertex+10);

View File

@ -212,13 +212,16 @@ inline short int MeshTopology :: GetNVertices (ELEMENT_TYPE et)
return 4; return 4;
case PYRAMID: case PYRAMID:
case PYRAMID13:
return 5; return 5;
case PRISM: case PRISM:
case PRISM12: case PRISM12:
case PRISM15:
return 6; return 6;
case HEX: case HEX:
case HEX20:
return 8; return 8;
// default: // default:
@ -244,9 +247,11 @@ inline short int MeshTopology :: GetNPoints (ELEMENT_TYPE et)
case QUAD: case QUAD:
case QUAD6: case QUAD6:
case QUAD8:
return 4; return 4;
case QUAD8:
return 8;
case TET: case TET:
return 4; return 4;
case TET10: case TET10:
@ -254,14 +259,21 @@ inline short int MeshTopology :: GetNPoints (ELEMENT_TYPE et)
case PYRAMID: case PYRAMID:
return 5; return 5;
case PYRAMID13:
return 13;
case PRISM: case PRISM:
case PRISM12:
return 6; return 6;
case PRISM12:
return 12;
case PRISM15:
return 15;
case HEX: case HEX:
return 8; return 8;
case HEX20:
return 20;
// default: // default:
// cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl; // cerr << "Ng_ME_GetNVertices, illegal element type " << et << endl;
} }
@ -272,7 +284,7 @@ inline short int MeshTopology :: GetNPoints (ELEMENT_TYPE et)
inline short int MeshTopology :: GetNEdges (ELEMENT_TYPE et) inline short int MeshTopology :: GetNEdges (ELEMENT_TYPE et)
{ {
__assume(et >= SEGMENT && et <= HEX); __assume(et >= SEGMENT && et <= PYRAMID13);
switch (et) switch (et)
{ {
case SEGMENT: case SEGMENT:
@ -293,13 +305,16 @@ inline short int MeshTopology :: GetNEdges (ELEMENT_TYPE et)
return 6; return 6;
case PYRAMID: case PYRAMID:
case PYRAMID13:
return 8; return 8;
case PRISM: case PRISM:
case PRISM12: case PRISM12:
case PRISM15:
return 9; return 9;
case HEX: case HEX:
case HEX20:
return 12; return 12;
default: default:
return 0; return 0;
@ -312,7 +327,7 @@ inline short int MeshTopology :: GetNEdges (ELEMENT_TYPE et)
inline short int MeshTopology :: GetNFaces (ELEMENT_TYPE et) inline short int MeshTopology :: GetNFaces (ELEMENT_TYPE et)
{ {
__assume(et >= SEGMENT && et <= HEX); __assume(et >= SEGMENT && et <= PYRAMID13);
switch (et) switch (et)
{ {
case SEGMENT: case SEGMENT:
@ -333,13 +348,16 @@ inline short int MeshTopology :: GetNFaces (ELEMENT_TYPE et)
return 4; return 4;
case PYRAMID: case PYRAMID:
case PYRAMID13:
return 5; return 5;
case PRISM: case PRISM:
case PRISM12: case PRISM12:
case PRISM15:
return 5; return 5;
case HEX: case HEX:
case HEX20:
return 6; return 6;
default: default:
@ -436,13 +454,16 @@ const ELEMENT_EDGE * MeshTopology :: GetEdges1 (ELEMENT_TYPE et)
return tet_edges; return tet_edges;
case PYRAMID: case PYRAMID:
case PYRAMID13:
return pyramid_edges; return pyramid_edges;
case PRISM: case PRISM:
case PRISM12: case PRISM12:
case PRISM15:
return prism_edges; return prism_edges;
case HEX: case HEX:
case HEX20:
return hex_edges; return hex_edges;
// default: // default:
// cerr << "Ng_ME_GetEdges, illegal element type " << et << endl; // cerr << "Ng_ME_GetEdges, illegal element type " << et << endl;
@ -534,13 +555,16 @@ const ELEMENT_EDGE * MeshTopology :: GetEdges0 (ELEMENT_TYPE et)
return tet_edges; return tet_edges;
case PYRAMID: case PYRAMID:
case PYRAMID13:
return pyramid_edges; return pyramid_edges;
case PRISM: case PRISM:
case PRISM12: case PRISM12:
case PRISM15:
return prism_edges; return prism_edges;
case HEX: case HEX:
case HEX20:
return hex_edges; return hex_edges;
// default: // default:
// cerr << "Ng_ME_GetEdges, illegal element type " << et << endl; // cerr << "Ng_ME_GetEdges, illegal element type " << et << endl;
@ -618,15 +642,18 @@ inline const ELEMENT_FACE * MeshTopology :: GetFaces1 (ELEMENT_TYPE et)
case PRISM: case PRISM:
case PRISM12: case PRISM12:
case PRISM15:
return prism_faces; return prism_faces;
case PYRAMID: case PYRAMID:
case PYRAMID13:
return pyramid_faces; return pyramid_faces;
case SEGMENT: case SEGMENT:
case SEGMENT3: case SEGMENT3:
case HEX: case HEX:
case HEX20:
return hex_faces; return hex_faces;
// default: // default:
@ -700,15 +727,18 @@ inline const ELEMENT_FACE * MeshTopology :: GetFaces0 (ELEMENT_TYPE et)
case PRISM: case PRISM:
case PRISM12: case PRISM12:
case PRISM15:
return prism_faces; return prism_faces;
case PYRAMID: case PYRAMID:
case PYRAMID13:
return pyramid_faces; return pyramid_faces;
case SEGMENT: case SEGMENT:
case SEGMENT3: case SEGMENT3:
case HEX: case HEX:
case HEX20:
return hex_faces; return hex_faces;
// default: // default:

View File

@ -8,11 +8,13 @@ if(USE_GUI)
add_library(occvis ${NG_LIB_TYPE} vsocc.cpp) add_library(occvis ${NG_LIB_TYPE} vsocc.cpp)
endif(USE_GUI) endif(USE_GUI)
target_link_libraries(occ PUBLIC ngcore)
if(NOT WIN32) if(NOT WIN32)
target_link_libraries( occ ${OCC_LIBRARIES} ${PYTHON_LIBRARIES}) target_link_libraries( occ PUBLIC ${OCC_LIBRARIES} ${PYTHON_LIBRARIES})
install( TARGETS occ ${NG_INSTALL_DIR}) install( TARGETS occ ${NG_INSTALL_DIR})
if (USE_GUI) if (USE_GUI)
target_link_libraries( occvis occ ) target_link_libraries( occvis PUBLIC occ )
install( TARGETS occvis ${NG_INSTALL_DIR}) install( TARGETS occvis ${NG_INSTALL_DIR})
endif(USE_GUI) endif(USE_GUI)
endif(NOT WIN32) endif(NOT WIN32)

View File

@ -673,13 +673,14 @@ namespace netgen
if (surfi > 0) if (surfi > 0)
{ {
double u = gi1.u+secpoint*(gi2.u-gi1.u); double u = gi1.u+secpoint*(gi2.u-gi1.u);
double v = gi1.v+secpoint*(gi2.v-gi1.v); double v = gi1.v+secpoint*(gi2.v-gi1.v);
if (!geometry.FastProject (surfi, hnewp, u, v)) auto savept = hnewp;
if (!geometry.FastProject (surfi, hnewp, u, v) || Dist(hnewp, savept) > Dist(p1,p2))
{ {
// cout << "Fast projection to surface fails! Using OCC projection" << endl; // cout << "Fast projection to surface fails! Using OCC projection" << endl;
hnewp = savept;
geometry.Project (surfi, hnewp); geometry.Project (surfi, hnewp);
} }

View File

@ -4,11 +4,13 @@ add_library(stl ${NG_LIB_TYPE}
) )
if(NOT WIN32) if(NOT WIN32)
target_link_libraries( stl mesh ${PYTHON_LIBRARIES}) target_link_libraries( stl mesh ${PYTHON_LIBRARIES})
target_link_libraries( stl ${PYTHON_LIBRARIES})
install( TARGETS stl ${NG_INSTALL_DIR}) install( TARGETS stl ${NG_INSTALL_DIR})
endif(NOT WIN32) endif(NOT WIN32)
target_link_libraries( stl ngcore )
if(USE_GUI) if(USE_GUI)
add_library(stlvis ${NG_LIB_TYPE} add_library(stlvis ${NG_LIB_TYPE}
vsstl.cpp vsstl.cpp

View File

@ -598,7 +598,6 @@ void STLSurfaceMeshing1 (STLGeometry & geom,
for (int fnr = 1; fnr <= mesh.GetNFD(); fnr++) for (int fnr = 1; fnr <= mesh.GetNFD(); fnr++)
{ {
if (fnr == 100) NgProfiler::ClearTimers();
if (!opensegsperface[fnr]) continue; if (!opensegsperface[fnr]) continue;
if (multithread.terminate) return; if (multithread.terminate) return;

View File

@ -9,10 +9,8 @@ endif(USE_GUI)
add_library(visual ${NG_LIB_TYPE} ${LIB_VISUAL_SOURCES}) add_library(visual ${NG_LIB_TYPE} ${LIB_VISUAL_SOURCES})
if(NOT WIN32) target_link_libraries( visual ngcore ${PYTHON_LIBRARIES} ${MPI_CXX_LIBRARIES} ${OPENGL_LIBRARIES} )
target_link_libraries( visual ${PYTHON_LIBRARIES} ${MPI_CXX_LIBRARIES} ${OPENGL_LIBRARIES} ) install( TARGETS visual ${NG_INSTALL_DIR})
install( TARGETS visual ${NG_INSTALL_DIR})
endif(NOT WIN32)
install(FILES install(FILES
meshdoc.hpp mvdraw.hpp meshdoc.hpp mvdraw.hpp

View File

@ -1,7 +1,7 @@
#ifndef FILE_SOLDATA #ifndef FILE_SOLDATA
#define FILE_SOLDATA #define FILE_SOLDATA
#include <myadt.hpp> // for tAVX
namespace netgen namespace netgen
{ {
@ -103,10 +103,10 @@ namespace netgen
#ifdef __SSE__ #ifdef __SSE__
virtual bool GetMultiSurfValue (size_t selnr, size_t facetnr, size_t npts, virtual bool GetMultiSurfValue (size_t selnr, size_t facetnr, size_t npts,
const tAVXd * xref, const ngsimd::tAVXd * xref,
const tAVXd * x, const ngsimd::tAVXd * x,
const tAVXd * dxdxref, const ngsimd::tAVXd * dxdxref,
tAVXd * values) ngsimd::tAVXd * values)
{ {
cerr << "GetMultiSurfVaue not overloaded for SIMD<double>" << endl; cerr << "GetMultiSurfVaue not overloaded for SIMD<double>" << endl;
return false; return false;

View File

@ -2682,7 +2682,7 @@ namespace netgen
for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++) for (ElementIndex ei = 0; ei < mesh->GetNE(); ei++)
{ {
const Element & el = (*mesh)[ei]; const Element & el = (*mesh)[ei];
if (el.GetType() == PYRAMID && !el.IsDeleted()) if ((el.GetType() == PYRAMID || el.GetType() == PYRAMID13) && !el.IsDeleted())
{ {
int i = ei + 1; int i = ei + 1;

View File

@ -1373,7 +1373,7 @@ namespace netgen
if ( el.GetType() == QUAD || el.GetType() == QUAD6 ) if ( el.GetType() == QUAD || el.GetType() == QUAD6 || el.GetType() == QUAD8 )
{ {
bool curved = curv.IsSurfaceElementCurved (sei); bool curved = curv.IsSurfaceElementCurved (sei);
@ -2857,6 +2857,7 @@ namespace netgen
} }
case PRISM: case PRISM:
case PRISM12: case PRISM12:
case PRISM15:
{ {
lami[0] = (1-lam3) * (1-lam1-lam2); lami[0] = (1-lam3) * (1-lam1-lam2);
lami[1] = (1-lam3) * lam1; lami[1] = (1-lam3) * lam1;
@ -2907,6 +2908,7 @@ namespace netgen
} }
case PRISM: case PRISM:
case PRISM12: case PRISM12:
case PRISM15:
{ {
lami[0] = (1-lam3) * (1-lam1-lam2); lami[0] = (1-lam3) * (1-lam1-lam2);
lami[1] = (1-lam3) * lam1; lami[1] = (1-lam3) * lam1;
@ -2918,6 +2920,7 @@ namespace netgen
break; break;
} }
case PYRAMID: case PYRAMID:
case PYRAMID13:
{ {
if (lam3 > 1-1e-5) if (lam3 > 1-1e-5)
{ {
@ -3482,6 +3485,7 @@ namespace netgen
case QUAD: case QUAD:
case QUAD6: case QUAD6:
case QUAD8:
lami[0] = (1-lam1)*(1-lam2); lami[0] = (1-lam1)*(1-lam2);
lami[1] = lam1 * (1-lam2); lami[1] = lam1 * (1-lam2);
lami[2] = lam1 * lam2; lami[2] = lam1 * lam2;
@ -3723,6 +3727,7 @@ namespace netgen
case QUAD: case QUAD:
case QUAD6: case QUAD6:
case QUAD8:
lami[0] = (1-lam1)*(1-lam2); lami[0] = (1-lam1)*(1-lam2);
lami[1] = lam1 * (1-lam2); lami[1] = lam1 * (1-lam2);
lami[2] = lam1 * lam2; lami[2] = lam1 * lam2;
@ -4017,7 +4022,7 @@ namespace netgen
if(vispar.donotclipdomain > 0 && vispar.donotclipdomain == (*mesh)[ei].GetIndex()) continue; if(vispar.donotclipdomain > 0 && vispar.donotclipdomain == (*mesh)[ei].GetIndex()) continue;
ELEMENT_TYPE type = (*mesh)[ei].GetType(); ELEMENT_TYPE type = (*mesh)[ei].GetType();
if (type == HEX || type == PRISM || type == TET || type == TET10 || type == PYRAMID) if (type == HEX || type == PRISM || type == TET || type == TET10 || type == PYRAMID || type == PYRAMID13 || type == PRISM15 || type == HEX20)
{ {
const Element & el = (*mesh)[ei]; const Element & el = (*mesh)[ei];
@ -4076,6 +4081,8 @@ namespace netgen
switch (type) switch (type)
{ {
case PRISM: case PRISM:
case PRISM12:
case PRISM15:
if (ix+iy <= n) if (ix+iy <= n)
{ {
ploc = Point<3> (double(ix) / n, double(iy) / n, double(iz) / n); ploc = Point<3> (double(ix) / n, double(iy) / n, double(iz) / n);
@ -4086,9 +4093,11 @@ namespace netgen
compress[ii] = -1; compress[ii] = -1;
break; break;
case HEX: case HEX:
case HEX20:
ploc = Point<3> (double(ix) / n, double(iy) / n, double(iz) / n); ploc = Point<3> (double(ix) / n, double(iy) / n, double(iz) / n);
break; break;
case PYRAMID: case PYRAMID:
case PYRAMID13:
ploc = Point<3> (double(ix) / n * (1-double(iz)/n), ploc = Point<3> (double(ix) / n * (1-double(iz)/n),
double(iy) / n * (1-double(iz)/n), double(iy) / n * (1-double(iz)/n),
double(iz)/n); double(iz)/n);
@ -4102,7 +4111,7 @@ namespace netgen
locgrid[compress[ii]] = ploc; locgrid[compress[ii]] = ploc;
} }
if (type != TET && type != TET10 && type != PRISM) cnt_valid = n3; if (type != TET && type != TET10 && type != PRISM && type != PRISM12 && type != PRISM15) cnt_valid = n3;
locgrid.SetSize(cnt_valid); locgrid.SetSize(cnt_valid);

View File

@ -1840,9 +1840,9 @@ namespace netgen
SYMBOLTABLE<VisualScene*> & GetVisualizationScenes () SymbolTable<VisualScene*> & GetVisualizationScenes ()
{ {
static SYMBOLTABLE<VisualScene*> vss; static SymbolTable<VisualScene*> vss;
return vss; return vss;
} }
@ -1860,7 +1860,7 @@ namespace netgen
vs = &vscross; vs = &vscross;
if (GetVisualizationScenes().Used(vismode)) if (GetVisualizationScenes().Used(vismode))
{ {
vs = GetVisualizationScenes().Get(vismode); vs = GetVisualizationScenes()[vismode];
} }
else if (vismode) else if (vismode)
{ {

View File

@ -8,9 +8,6 @@ if(WIN32)
$<TARGET_OBJECTS:geom2d> $<TARGET_OBJECTS:geom2d>
$<TARGET_OBJECTS:csg> $<TARGET_OBJECTS:csg>
$<TARGET_OBJECTS:stl> $<TARGET_OBJECTS:stl>
$<TARGET_OBJECTS:gen>
$<TARGET_OBJECTS:la>
$<TARGET_OBJECTS:gprim>
$<TARGET_OBJECTS:visual> $<TARGET_OBJECTS:visual>
$<TARGET_OBJECTS:occ> $<TARGET_OBJECTS:occ>
@ -32,6 +29,7 @@ if(NOT WIN32)
endif(USE_GUI) endif(USE_GUI)
endif(NOT WIN32) endif(NOT WIN32)
# target_link_libraries(nglib PRIVATE gen la gprim PUBLIC ngcore)
target_link_libraries(nglib PUBLIC ngcore) target_link_libraries(nglib PUBLIC ngcore)
target_link_libraries( nglib PRIVATE ${OCC_LIBRARIES} ${MPI_CXX_LIBRARIES} ${OPENGL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${X11_Xmu_LIB} ${JPEG_LIBRARIES} ${MKL_LIBRARIES} ${ZLIB_LIBRARIES} ${OCC_LIBRARIES} ) target_link_libraries( nglib PRIVATE ${OCC_LIBRARIES} ${MPI_CXX_LIBRARIES} ${OPENGL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${X11_Xmu_LIB} ${JPEG_LIBRARIES} ${MKL_LIBRARIES} ${ZLIB_LIBRARIES} ${OCC_LIBRARIES} )

View File

@ -1211,14 +1211,14 @@ namespace netgen
} }
*/ */
/*
#ifndef WIN32 #ifndef WIN32
void ResetTime () void ResetTime ()
{ {
; ;
} }
#endif #endif
*/
void MyBeep (int i) void MyBeep (int i)

View File

@ -39,11 +39,107 @@ def MakeCircle (geo, c, r, **args):
geo.Append( ["spline3", pts[p1], pts[p2], pts[p3]], **args) geo.Append( ["spline3", pts[p1], pts[p2], pts[p3]], **args)
def CreatePML(geo, pml_size, tol=1e-12):
"""Create a pml layer around the geometry. This function works only on convex geometries and
the highest existing domain number must be named by using the function geo.SetMaterial(domnr, name).
Points in the geometry are assumed to be the same if (pt1 - pt2).Norm() < tol.
Returned is a dict with information to create the pml layer:
normals: A dict from the names of the linear pml domains to the normal vectors pointing inside the pml."""
def Start(spline):
if spline.rightdom == 0:
return spline.StartPoint()
return spline.EndPoint()
def End(spline):
if spline.rightdom == 0:
return spline.EndPoint()
return spline.StartPoint()
splines = []
for i in range(geo.GetNSplines()):
splines.append(geo.GetSpline(i))
border = []
is_closed = False
current_endpoint = None
while not is_closed:
for spline in splines:
if spline.leftdom == 0 or spline.rightdom == 0:
if current_endpoint is not None:
if (Start(spline)-current_endpoint).Norm() < tol:
border.append(spline)
current_endpoint = End(spline)
if (current_endpoint - startpoint).Norm() < tol:
is_closed = True
break
else:
startpoint = Start(spline)
current_endpoint = End(spline)
border.append(spline)
break
else:
raise Exception("Couldn't find closed spline around domain")
endpointindex_map = []
for spline in border:
pnt = End(spline)
for i in range(geo.GetNPoints()):
if (pnt - geo.GetPoint(i)).Norm() < tol:
endpointindex_map.append(i)
break
else:
raise Exception("Couldn't find endpoint of spline in geometry")
start_ndoms = ndoms = geo.GetNDomains() + 1
new_spline_domains = []
normals = {}
for i, spline in enumerate(border):
if i == 0:
global_start = Start(spline) + pml_size * spline.GetNormal(0)
global_start_pnt = current_start = geo.AppendPoint(global_start[0], global_start[1])
next_spline = border[(i+1)%len(border)]
new_end = End(spline) + pml_size * spline.GetNormal(1)
spline_name = geo.GetBCName(spline.bc)
if (new_end - global_start).Norm() < tol:
new_spline_domains.append(ndoms)
geo.Append(["line", current_start, global_start_pnt], bc="outer_" + spline_name, leftdomain = ndoms)
geo.Append(["line", global_start_pnt, endpointindex_map[i]], leftdomain=ndoms, rightdomain=start_ndoms)
geo.SetMaterial(ndoms, "pml_" + spline_name)
normals["pml_" + spline_name] = spline.GetNormal(0)
ndoms += 1
break
end = geo.AppendPoint(new_end[0], new_end[1])
new_spline_domains.append(ndoms)
geo.Append(["line", current_start, end], bc="outer_" + spline_name, leftdomain = ndoms)
geo.Append(["line", end, endpointindex_map[i]], leftdomain=ndoms, rightdomain=ndoms+1)
geo.SetMaterial(ndoms, "pml_" + spline_name)
normals["pml_" + spline_name] = spline.GetNormal(0)
ndoms += 1
new_start = Start(next_spline) + pml_size * next_spline.GetNormal(0)
if (new_start - global_start).Norm() < tol:
geo.Append(["line", end, global_start_pnt], bc="outer", leftdomain = ndoms)
geo.Append(["line", global_start_pnt, endpointindex_map[i]], leftdomain=ndoms, rightdomain=start_ndoms)
geo.SetMaterial(ndoms, "pml_corner")
ndoms += 1
break
if (new_end - new_start).Norm() < tol:
current_start = end
else:
current_start = geo.AppendPoint(new_start[0], new_start[1])
geo.Append(["line", end, current_start], bc="outer", leftdomain = ndoms)
geo.Append(["line", current_start, endpointindex_map[i]], leftdomain=ndoms, rightdomain=ndoms+1)
geo.SetMaterial(ndoms, "pml_corner")
ndoms += 1
for spline, domnr in zip(border, new_spline_domains):
if spline.leftdom == 0:
spline.leftdom = domnr
else:
spline.rightdom = domnr
return {"normals" : normals}
SplineGeometry.AddCircle = lambda geo, c, r, **args : MakeCircle(geo, c, r, **args) SplineGeometry.AddCircle = lambda geo, c, r, **args : MakeCircle(geo, c, r, **args)
SplineGeometry.AddRectangle = lambda geo, p1, p2, **args : MakeRectangle(geo, p1, p2, **args) SplineGeometry.AddRectangle = lambda geo, p1, p2, **args : MakeRectangle(geo, p1, p2, **args)
SplineGeometry.AddSegment = lambda *args, **kwargs : SplineGeometry.Append(*args, **kwargs) SplineGeometry.AddSegment = lambda *args, **kwargs : SplineGeometry.Append(*args, **kwargs)
SplineGeometry.AddPoint = lambda *args, **kwargs : SplineGeometry.AppendPoint(*args, **kwargs) SplineGeometry.AddPoint = lambda *args, **kwargs : SplineGeometry.AppendPoint(*args, **kwargs)
SplineGeometry.CreatePML = CreatePML
__all__ = ['SplineGeometry', 'unit_square'] __all__ = ['SplineGeometry', 'unit_square']

View File

@ -1,9 +1,10 @@
from netgen.meshing import * from netgen.meshing import *
def ReadGmsh(filename): def ReadGmsh(filename):
if not filename.endswith(".msh"):
filename += ".msh"
meshdim = 1 meshdim = 1
with open(filename + ".msh", 'r') as f: with open(filename, 'r') as f:
while f.readline().split()[0] != "$Elements": while f.readline().split()[0] != "$Elements":
pass pass
nelem = int(f.readline()) nelem = int(f.readline())
@ -16,15 +17,58 @@ def ReadGmsh(filename):
meshdim = 3 meshdim = 3
break break
f = open(filename + ".msh", 'r') f = open(filename, 'r')
mesh = Mesh(dim=meshdim) mesh = Mesh(dim=meshdim)
pointmap = {} pointmap = {}
facedescriptormap = {} facedescriptormap = {}
namemap = {} namemap = { 0 : "default" }
materialmap = {} materialmap = {}
bbcmap = {} bbcmap = {}
segm = 1
trig = 2
quad = 3
tet = 4
hex = 5
prism = 6
pyramid = 7
segm3 = 8 # 2nd order line
trig6 = 9 # 2nd order trig
tet10 = 11 # 2nd order tet
point = 15
quad8 = 16 # 2nd order quad
hex20 = 17 # 2nd order hex
prism15 = 18 # 2nd order prism
pyramid13 = 19 # 2nd order pyramid
segms = [segm, segm3]
trigs = [trig, trig6]
quads = [quad, quad8]
tets = [tet, tet10]
hexes = [hex, hex20]
prisms = [prism, prism15]
pyramids = [pyramid, pyramid13]
elem0d = [point]
elem1d = segms
elem2d = trigs + quads
elem3d = tets + hexes + prisms + pyramids
num_nodes_map = { segm : 2,
trig : 3,
quad : 4,
tet : 4,
hex : 8,
prism : 6,
pyramid : 5,
segm3 : 3,
trig6 : 6,
tet10 : 10,
point : 1,
quad8 : 8,
hex20 : 20,
prism15 : 18,
pyramid13 : 19 }
while True: while True:
line = f.readline() line = f.readline()
if line == "": if line == "":
@ -57,29 +101,14 @@ def ReadGmsh(filename):
# the first tag is the physical group nr, the second tag is the group nr of the dim # the first tag is the physical group nr, the second tag is the group nr of the dim
tags = [int(line[3 + k]) for k in range(numtags)] tags = [int(line[3 + k]) for k in range(numtags)]
if elmtype == 1: # 2-node line if elmtype not in num_nodes_map:
num_nodes = 2
elif elmtype == 2: # 3-node trig
num_nodes = 3
elif elmtype == 3: # 4-node quad
num_nodes = 4
elif elmtype == 4: # 4-node tet
num_nodes = 4
elif elmtype == 5: # 8-node hex
num_nodes = 8
elif elmtype == 6: # 6-node prism
num_nodes = 6
elif elmtype == 7: # 5-node pyramid
num_nodes = 5
elif elmtype == 15: # 1-node point
num_nodes = 1
else:
raise Exception("element type", elmtype, "not implemented") raise Exception("element type", elmtype, "not implemented")
num_nodes = num_nodes_map[elmtype]
nodenums = line[3 + numtags:3 + numtags + num_nodes] nodenums = line[3 + numtags:3 + numtags + num_nodes]
nodenums2 = [pointmap[int(nn)] for nn in nodenums] nodenums2 = [pointmap[int(nn)] for nn in nodenums]
if elmtype == 1: if elmtype in elem1d:
if meshdim == 3: if meshdim == 3:
if tags[1] in bbcmap: if tags[1] in bbcmap:
index = bbcmap[tags[1]] index = bbcmap[tags[1]]
@ -117,7 +146,7 @@ def ReadGmsh(filename):
mesh.Add(Element1D(index=index, vertices=nodenums2)) mesh.Add(Element1D(index=index, vertices=nodenums2))
if elmtype in [2, 3]: # 2d elements if elmtype in elem2d: # 2d elements
if meshdim == 3: if meshdim == 3:
if tags[1] in facedescriptormap.keys(): if tags[1] in facedescriptormap.keys():
index = facedescriptormap[tags[1]] index = facedescriptormap[tags[1]]
@ -142,9 +171,17 @@ def ReadGmsh(filename):
mesh.SetMaterial(index, "surf" + str(tags[1])) mesh.SetMaterial(index, "surf" + str(tags[1]))
materialmap[tags[1]] = index materialmap[tags[1]] = index
mesh.Add(Element2D(index, nodenums2)) if elmtype in trigs:
ordering = [i for i in range(3)]
if elmtype == trig6:
ordering += [4,5,3]
if elmtype in quads:
ordering = [i for i in range(4)]
if elmtype == quad8:
ordering += [4, 6, 7, 5]
mesh.Add(Element2D(index, [nodenums2[i] for i in ordering]))
if elmtype in [4, 5, 6, 7]: # volume elements if elmtype in elem3d: # volume elements
if tags[1] in materialmap: if tags[1] in materialmap:
index = materialmap[tags[1]] index = materialmap[tags[1]]
else: else:
@ -157,9 +194,22 @@ def ReadGmsh(filename):
nodenums2 = [pointmap[int(nn)] for nn in nodenums] nodenums2 = [pointmap[int(nn)] for nn in nodenums]
if elmtype == 4: if elmtype in tets:
mesh.Add(Element3D(index, [nodenums2[0], nodenums2[1], nodenums2[3], nodenums2[2]])) ordering = [0,1,2,3]
elif elmtype in [5, 6, 7]: if elmtype == tet10:
mesh.Add(Element3D(index, nodenums2)) ordering += [4,6,7,5,9,8]
elif elmtype in hexes:
ordering = [0,1,5,4,3,2,6,7]
if elmtype == hex20:
ordering += [8,16,10,12,13,19,15,14,9,11,18,17]
elif elmtype in prisms:
ordering = [0,2,1,3,5,4]
if elmtype == prism15:
ordering += [7,6,9,8,11,10,13,12,14]
elif elmtype in pyramids:
ordering = [3,2,1,0,4]
if elmtype == pyramid13:
ordering += [10,5,6,8,12,11,9,7]
mesh.Add(Element3D(index, [nodenums2[i] for i in ordering]))
return mesh return mesh

8
tests/build_nospdlog.sh Normal file
View File

@ -0,0 +1,8 @@
cd
mkdir -p build/netgen
cd build/netgen
cmake ../../src/netgen -DUSE_CCACHE=ON -DUSE_SPDLOG=OFF -DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER=clang
make -j12
make install

View File

@ -3,8 +3,7 @@ if(ENABLE_UNIT_TESTS)
add_custom_target(unit_tests) add_custom_target(unit_tests)
# Build catch_main test object # Build catch_main test object
message("netgen include dir = ${NETGEN_INCLUDE_DIR_ABSOLUTE} --------------------------------------") include_directories(${CATCH_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../libsrc/include ${SPDLOG_INCLUDE_DIR})
include_directories(${CATCH_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/../../libsrc/include})
add_library(catch_main STATIC main.cpp) add_library(catch_main STATIC main.cpp)
set_target_properties(catch_main PROPERTIES CXX_STANDARD 17) set_target_properties(catch_main PROPERTIES CXX_STANDARD 17)
add_dependencies(unit_tests catch_main) add_dependencies(unit_tests catch_main)
@ -15,23 +14,19 @@ add_test(NAME unit_tests_built COMMAND ${CMAKE_COMMAND} --build . --target unit_
macro(add_unit_test name sources) macro(add_unit_test name sources)
add_executable(test_${name} ${sources} ) add_executable(test_${name} ${sources} )
if (WIN32) target_link_libraries(test_${name} ngcore catch_main)
target_link_libraries(test_${name} ngcore catch_main)
else(WIN32)
target_link_libraries(test_${name} ngcore catch_main)
endif(WIN32)
add_dependencies(unit_tests test_${name}) add_dependencies(unit_tests test_${name})
add_test(NAME unit_${name} COMMAND test_${name}) add_test(NAME unit_${name} COMMAND test_${name})
set_tests_properties(unit_${name} PROPERTIES DEPENDS unit_tests_built) set_tests_properties(unit_${name} PROPERTIES DEPENDS unit_tests_built)
if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
set_target_properties(test_${name} PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
endif(ENABLE_CPP_CORE_GUIDELINES_CHECK)
endmacro() endmacro()
add_unit_test(archive archive.cpp) add_unit_test(archive archive.cpp)
add_unit_test(symboltable symboltable.cpp)
add_unit_test(version version.cpp) add_unit_test(version version.cpp)
if(ENABLE_CPP_CORE_GUIDELINES_CHECK)
set_target_properties(test_archive PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
set_target_properties(test_version PROPERTIES CXX_CLANG_TIDY "${DO_CLANG_TIDY}")
endif(ENABLE_CPP_CORE_GUIDELINES_CHECK)
endif(ENABLE_UNIT_TESTS) endif(ENABLE_UNIT_TESTS)

View File

@ -236,6 +236,34 @@ void testMultipleInheritance(Archive& in, Archive& out)
} }
} }
void testMap(Archive& in, Archive& out)
{
map<string, VersionInfo> map1;
map1["netgen"] = "v6.2.1901";
out & map1;
out.FlushBuffer();
map<string, VersionInfo> map2;
in & map2;
CHECK(map2.size() == 1);
CHECK(map2["netgen"] == "v6.2.1901");
}
enum MyEnum
{
CASE1,
CASE2
};
void testEnum(Archive& in, Archive& out)
{
MyEnum en = CASE2;
out & en;
out.FlushBuffer();
MyEnum enin;
in & enin;
CHECK(enin == CASE2);
}
void testArchive(Archive& in, Archive& out) void testArchive(Archive& in, Archive& out)
{ {
SECTION("Empty String") SECTION("Empty String")
@ -285,11 +313,18 @@ void testArchive(Archive& in, Archive& out)
{ {
testNullPtr(in, out); testNullPtr(in, out);
} }
SECTION("map")
{
testMap(in, out);
}
SECTION("enum")
{
testEnum(in, out);
}
} }
TEST_CASE("BinaryArchive") TEST_CASE("BinaryArchive")
{ {
SetLibraryVersion("netgen","v6.2.1811");
auto stream = make_shared<stringstream>(); auto stream = make_shared<stringstream>();
BinaryOutArchive out(stream); BinaryOutArchive out(stream);
BinaryInArchive in(stream); BinaryInArchive in(stream);
@ -298,7 +333,6 @@ TEST_CASE("BinaryArchive")
TEST_CASE("TextArchive") TEST_CASE("TextArchive")
{ {
SetLibraryVersion("netgen","v6.2.1811");
auto stream = make_shared<stringstream>(); auto stream = make_shared<stringstream>();
TextOutArchive out(stream); TextOutArchive out(stream);
TextInArchive in(stream); TextInArchive in(stream);

View File

@ -0,0 +1,64 @@
#include "catch.hpp"
#include <../core/ngcore.hpp>
using namespace ngcore;
using namespace std;
TEST_CASE("Symboltable")
{
SymbolTable<int> table;
CHECK_THROWS_AS(table["test"], RangeException);
table.Set("first", 1);
CHECK(table["first"] == 1);
table["first"] = 2;
CHECK(table["first"] == 2);
auto index = table.Index("first");
CHECK(index == 0);
CHECK(table[index] == 2);
table[index] = 3;
CHECK(table["first"] == 3);
#ifndef NDEBUG
int a;
CHECK_THROWS_AS(a = table[5], RangeException);
CHECK_THROWS_AS(table.GetName(5), RangeException);
#endif
CHECK(table.Used("first"));
CHECK(!table.Used("second"));
SymbolTable<int> another;
another.Set("first", 1);
another.Set("second", 2);
table.Update(another);
CHECK(table["first"] == 1);
CHECK(table["second"] == 2);
std::stringstream s;
s << table;
CHECK(s.str() == "first : 1\nsecond : 2\n");
auto ss = std::make_shared<std::stringstream>();
BinaryOutArchive ao(ss);
ao & table;
ao.FlushBuffer();
BinaryInArchive ai(ss);
SymbolTable<int> read;
ai & read;
for(size_t i = 0; i<table.Size(); i++)
{
CHECK(read[i] == table[i]);
CHECK(read.GetName(i) == table.GetName(i));
}
table.DeleteAll();
CHECK(table.Size() == 0);
// SymbolTable<bool> is special because of vector<bool> is special...
SymbolTable<bool> btable;
btable.Set("true", true);
btable.Set("false", false);
CHECK(btable[0]);
CHECK(!btable[1]);
CHECK(btable["true"]);
CHECK(!btable["false"]);
ao & btable;
ao.FlushBuffer();
SymbolTable<bool> bread;
ai & bread;
CHECK(bread["true"]);
CHECK(!bread["false"]);
}