Merge remote-tracking branch 'gitlab/master' into arm

This commit is contained in:
Matthias Hochsteger 2020-12-04 16:57:24 +01:00
commit 82f817946f
29 changed files with 825 additions and 180 deletions

BIN
CLA.pdf Normal file

Binary file not shown.

View File

@ -33,6 +33,7 @@ option( BUILD_STUB_FILES "Build stub files for better autocompletion" ON)
option( BUILD_FOR_CONDA "Link python libraries only to executables" OFF) option( BUILD_FOR_CONDA "Link python libraries only to executables" OFF)
option( USE_SUPERBUILD "use ccache" ON) option( USE_SUPERBUILD "use ccache" ON)
option( TRACE_MEMORY "Enable memory tracing" OFF)
set(NG_COMPILE_FLAGS "" CACHE STRING "Additional compile flags") set(NG_COMPILE_FLAGS "" CACHE STRING "Additional compile flags")
@ -420,12 +421,12 @@ endif(USE_CGNS)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/netgen_version.hpp ${CMAKE_CURRENT_BINARY_DIR}/netgen_config.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/include COMPONENT netgen_devel) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/netgen_version.hpp ${CMAKE_CURRENT_BINARY_DIR}/netgen_config.hpp DESTINATION ${NG_INSTALL_DIR_INCLUDE}/include COMPONENT netgen_devel)
add_subdirectory(windows)
add_subdirectory(libsrc) add_subdirectory(libsrc)
add_subdirectory(ng) add_subdirectory(ng)
add_subdirectory(tutorials) add_subdirectory(tutorials)
add_subdirectory(py_tutorials) add_subdirectory(py_tutorials)
add_subdirectory(doc) add_subdirectory(doc)
add_subdirectory(windows)
add_subdirectory(nglib) add_subdirectory(nglib)
if (USE_PYTHON) if (USE_PYTHON)
add_subdirectory(python) add_subdirectory(python)

18
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,18 @@
# How to Contribute
## Reporting issues
If you have a problem using Netgen/NGSolve consider asking a question in our [forum](https://ngsolve.org/forum).
If you found a bug create an issue in the [Github Issue Tracker](https://github.com/NGSolve/netgen/issues). Please be as specific as possible, issues with a reproducible minimal failing example will get more attention than unspecific one liners :)
## Contributing patches
We love and want to encourage community engagement and will review and accept patches and contributions to this project. There are just a few steps to follow:
On your first contribution, to clear any legal questions, we ask you to sign our [Contributor License Agreement](CLA.pdf). Generally you have to sign this only once for Netgen or NGSolve. Please send the signed agreement to <joachim.schoeberl@tuwien.ac.at>.
Place a pull request on GitHub. From there we will pull it into our internal testing environment and, if approved, merge it into the main codebase.
If you have any questions feel free to ask on the [forum](https://ngsolve.org/forum).

View File

@ -143,6 +143,7 @@ set_vars( NETGEN_CMAKE_ARGS
USE_SPDLOG USE_SPDLOG
DEBUG_LOG DEBUG_LOG
CHECK_RANGE CHECK_RANGE
TRACE_MEMORY
BUILD_STUB_FILES BUILD_STUB_FILES
BUILD_FOR_CONDA BUILD_FOR_CONDA
NG_COMPILE_FLAGS NG_COMPILE_FLAGS

View File

@ -42,6 +42,11 @@ if(CHECK_RANGE OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL
target_compile_definitions(ngcore PUBLIC NETGEN_ENABLE_CHECK_RANGE) target_compile_definitions(ngcore PUBLIC NETGEN_ENABLE_CHECK_RANGE)
endif(CHECK_RANGE OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG") endif(CHECK_RANGE OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG")
if(TRACE_MEMORY OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG")
target_compile_definitions(ngcore PUBLIC NETGEN_TRACE_MEMORY)
endif(TRACE_MEMORY OR CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "DEBUG")
if(USE_SPDLOG) if(USE_SPDLOG)
include_directories(${SPDLOG_INCLUDE_DIR}) include_directories(${SPDLOG_INCLUDE_DIR})
install(DIRECTORY ${SPDLOG_INCLUDE_DIR} install(DIRECTORY ${SPDLOG_INCLUDE_DIR}

View File

@ -916,7 +916,7 @@ namespace ngcore
class NGCORE_API HashArchive : public Archive class NGCORE_API HashArchive : public Archive
{ {
size_t hash_value; size_t hash_value = 0;
char* h; char* h;
int offset = 0; int offset = 0;
public: public:

View File

@ -11,6 +11,7 @@
#include "archive.hpp" #include "archive.hpp"
#include "exception.hpp" #include "exception.hpp"
#include "localheap.hpp" #include "localheap.hpp"
#include "profiler.hpp"
#include "utils.hpp" #include "utils.hpp"
namespace ngcore namespace ngcore
@ -654,6 +655,7 @@ namespace ngcore
/// that's the data we have to delete, nullptr for not owning the memory /// that's the data we have to delete, nullptr for not owning the memory
T * mem_to_delete; T * mem_to_delete;
using FlatArray<T,IndexType>::size; using FlatArray<T,IndexType>::size;
using FlatArray<T,IndexType>::data; using FlatArray<T,IndexType>::data;
using FlatArray<T,IndexType>::BASE; using FlatArray<T,IndexType>::BASE;
@ -698,6 +700,8 @@ namespace ngcore
NETGEN_INLINE Array (Array && a2) NETGEN_INLINE Array (Array && a2)
{ {
mt.Swap(sizeof(T) * allocsize, a2.mt, sizeof(T) * a2.allocsize);
size = a2.size; size = a2.size;
data = a2.data; data = a2.data;
allocsize = a2.allocsize; allocsize = a2.allocsize;
@ -769,6 +773,7 @@ namespace ngcore
NETGEN_INLINE ~Array() NETGEN_INLINE ~Array()
{ {
delete [] mem_to_delete; delete [] mem_to_delete;
mt.Free(sizeof(T)*allocsize);
} }
// Only provide this function if T is archivable // Only provide this function if T is archivable
@ -823,6 +828,7 @@ namespace ngcore
NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh) NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh)
{ {
delete [] mem_to_delete; delete [] mem_to_delete;
mt.Free(sizeof(T)*allocsize);
size = allocsize = asize; size = allocsize = asize;
data = lh.Alloc<T> (asize); data = lh.Alloc<T> (asize);
mem_to_delete = nullptr; mem_to_delete = nullptr;
@ -930,6 +936,7 @@ namespace ngcore
NETGEN_INLINE void DeleteAll () NETGEN_INLINE void DeleteAll ()
{ {
delete [] mem_to_delete; delete [] mem_to_delete;
mt.Free(sizeof(T)*allocsize);
mem_to_delete = NULL; mem_to_delete = NULL;
data = 0; data = 0;
size = allocsize = 0; size = allocsize = 0;
@ -961,6 +968,8 @@ namespace ngcore
/// steal array /// steal array
NETGEN_INLINE Array & operator= (Array && a2) NETGEN_INLINE Array & operator= (Array && a2)
{ {
mt.Swap(sizeof(T)*allocsize, a2.mt, sizeof(T)*a2.allocsize);
ngcore::Swap (size, a2.size); ngcore::Swap (size, a2.size);
ngcore::Swap (data, a2.data); ngcore::Swap (data, a2.data);
ngcore::Swap (allocsize, a2.allocsize); ngcore::Swap (allocsize, a2.allocsize);
@ -1034,16 +1043,26 @@ namespace ngcore
NETGEN_INLINE void Swap (Array & b) NETGEN_INLINE void Swap (Array & b)
{ {
mt.Swap(sizeof(T) * allocsize, b.mt, sizeof(T) * b.allocsize);
ngcore::Swap (size, b.size); ngcore::Swap (size, b.size);
ngcore::Swap (data, b.data); ngcore::Swap (data, b.data);
ngcore::Swap (allocsize, b.allocsize); ngcore::Swap (allocsize, b.allocsize);
ngcore::Swap (mem_to_delete, b.mem_to_delete); ngcore::Swap (mem_to_delete, b.mem_to_delete);
} }
NETGEN_INLINE void StartMemoryTracing () const
{
mt.Alloc(sizeof(T) * allocsize);
}
const MemoryTracer& GetMemoryTracer() const { return mt; }
private: private:
/// resize array, at least to size minsize. copy contents /// resize array, at least to size minsize. copy contents
NETGEN_INLINE void ReSize (size_t minsize); NETGEN_INLINE void ReSize (size_t minsize);
MemoryTracer mt;
}; };
@ -1056,6 +1075,7 @@ namespace ngcore
T * hdata = data; T * hdata = data;
data = new T[nsize]; data = new T[nsize];
mt.Alloc(sizeof(T) * nsize);
if (hdata) if (hdata)
{ {
@ -1069,6 +1089,7 @@ namespace ngcore
for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]); for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]);
#endif #endif
delete [] mem_to_delete; delete [] mem_to_delete;
mt.Free(sizeof(T) * allocsize);
} }
mem_to_delete = data; mem_to_delete = data;

View File

@ -36,10 +36,15 @@ namespace ngcore
void BitArray :: SetSize (size_t asize) void BitArray :: SetSize (size_t asize)
{ {
if (size == asize) return; if (size == asize) return;
if (owns_data) delete [] data; if (owns_data)
{
delete [] data;
mt.Free(Addr(size)+1);
}
size = asize; size = asize;
data = new unsigned char [Addr (size)+1]; data = new unsigned char [Addr (size)+1];
mt.Alloc(Addr(size)+1);
} }
BitArray & BitArray :: Set () throw() BitArray & BitArray :: Set () throw()
@ -136,7 +141,20 @@ namespace ngcore
archive & size; archive & size;
if(archive.Input()) if(archive.Input())
SetSize(size); SetSize(size);
if(archive.GetVersion("netgen") < "v6.2.2009-20")
archive.Do(data, size/CHAR_BIT+1); archive.Do(data, size/CHAR_BIT+1);
else
{
archive.NeedsVersion("netgen", "v6.2.2009-20");
archive.Do(data, size/CHAR_BIT);
for(size_t i = 0; i < size%CHAR_BIT; i++)
{
size_t index = CHAR_BIT * (size/CHAR_BIT) + i;
bool b = Test(index);
archive & b;
b ? SetBit(index) : Clear(index);
}
}
} }
else else
{ {

View File

@ -150,6 +150,14 @@ public:
NGCORE_API void DoArchive(Archive& archive); NGCORE_API void DoArchive(Archive& archive);
NGCORE_API auto * Data() const { return data; } NGCORE_API auto * Data() const { return data; }
const MemoryTracer& GetMemoryTracer() const { return mt; }
void StartMemoryTracing() const
{
if(owns_data)
mt.Alloc(Addr(size)+1);
}
private: private:
/// ///
unsigned char Mask (size_t i) const unsigned char Mask (size_t i) const
@ -159,6 +167,7 @@ private:
size_t Addr (size_t i) const size_t Addr (size_t i) const
{ return (i / CHAR_BIT); } { return (i / CHAR_BIT); }
MemoryTracer mt;
}; };

View File

@ -29,6 +29,8 @@ namespace ngcore
#endif // PARALLEL #endif // PARALLEL
} }
std::vector<PajeTrace::MemoryEvent> PajeTrace::memory_events;
// Produce no traces by default // Produce no traces by default
size_t PajeTrace::max_tracefile_size = 0; size_t PajeTrace::max_tracefile_size = 0;
@ -36,6 +38,7 @@ namespace ngcore
// increases trace by a factor of two // increases trace by a factor of two
bool PajeTrace::trace_thread_counter = false; bool PajeTrace::trace_thread_counter = false;
bool PajeTrace::trace_threads = true; bool PajeTrace::trace_threads = true;
bool PajeTrace::mem_tracing_enabled = true;
PajeTrace :: PajeTrace(int anthreads, std::string aname) PajeTrace :: PajeTrace(int anthreads, std::string aname)
{ {
@ -62,6 +65,7 @@ namespace ngcore
jobs.reserve(reserve_size); jobs.reserve(reserve_size);
timer_events.reserve(reserve_size); timer_events.reserve(reserve_size);
memory_events.reserve(1024*1024);
// sync start time when running in parallel // sync start time when running in parallel
#ifdef PARALLEL #ifdef PARALLEL
@ -72,6 +76,8 @@ namespace ngcore
start_time = GetTimeCounter(); start_time = GetTimeCounter();
tracing_enabled = true; tracing_enabled = true;
mem_tracing_enabled = true;
n_memory_events_at_start = memory_events.size();
} }
PajeTrace :: ~PajeTrace() PajeTrace :: ~PajeTrace()
@ -94,6 +100,9 @@ namespace ngcore
for(auto & link : llink) for(auto & link : llink)
link.time -= start_time; link.time -= start_time;
for(auto i : IntRange(n_memory_events_at_start, memory_events.size()))
memory_events[i].time -= start_time;
NgMPI_Comm comm(MPI_COMM_WORLD); NgMPI_Comm comm(MPI_COMM_WORLD);
if(comm.Size()==1) if(comm.Size()==1)
@ -237,7 +246,8 @@ namespace ngcore
PajeFile( const std::string & filename) PajeFile( const std::string & filename)
{ {
ctrace_stream = fopen (filename.c_str(),"w"); // NOLINT std::string fname = filename + ".trace";
ctrace_stream = fopen (fname.c_str(),"w"); // NOLINT
fprintf(ctrace_stream, "%s", header ); // NOLINT fprintf(ctrace_stream, "%s", header ); // NOLINT
alias_counter = 0; alias_counter = 0;
} }
@ -426,6 +436,7 @@ namespace ngcore
const int container_type_thread = paje.DefineContainerType( container_type_task_manager, "Thread"); 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_timer = container_type_thread; //paje.DefineContainerType( container_type_task_manager, "Timers");
const int container_type_jobs = paje.DefineContainerType( container_type_task_manager, "Jobs"); const int container_type_jobs = paje.DefineContainerType( container_type_task_manager, "Jobs");
const int container_type_memory = paje.DefineContainerType( container_type_task_manager, "Memory usage");
const int state_type_job = paje.DefineStateType( container_type_jobs, "Job" ); const int state_type_job = paje.DefineStateType( container_type_jobs, "Job" );
const int state_type_task = paje.DefineStateType( container_type_thread, "Task" ); const int state_type_task = paje.DefineStateType( container_type_thread, "Task" );
@ -433,12 +444,18 @@ namespace ngcore
int variable_type_active_threads = 0; int variable_type_active_threads = 0;
if(trace_thread_counter) if(trace_thread_counter)
paje.DefineVariableType( container_type_jobs, "Active threads" ); 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_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" ); const int container_jobs = paje.CreateContainer( container_type_jobs, container_task_manager, "Jobs" );
if(trace_thread_counter)
paje.SetVariable( 0, variable_type_active_threads, container_jobs, 0.0 ); int variable_type_memory = 0;
const int container_memory = paje.CreateContainer( container_type_memory, container_task_manager, "Memory" );
if(mem_tracing_enabled)
{
variable_type_memory = paje.DefineVariableType( container_type_task_manager, "Memory [MB]" );
}
int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1; int num_nodes = 1; //task_manager ? task_manager->GetNumNodes() : 1;
std::vector <int> thread_aliases; std::vector <int> thread_aliases;
@ -509,6 +526,30 @@ namespace ngcore
paje.PopState( j.stop_time, state_type_job, container_jobs ); paje.PopState( j.stop_time, state_type_job, container_jobs );
} }
size_t memory_at_start = 0;
for(const auto & i : IntRange(0, n_memory_events_at_start))
{
if(memory_events[i].is_alloc)
memory_at_start += memory_events[i].size;
else
memory_at_start -= memory_events[i].size;
}
paje.SetVariable( 0, variable_type_memory, container_memory, 1.0*memory_at_start/(1024*1024));
for(const auto & i : IntRange(n_memory_events_at_start, memory_events.size()))
{
auto & m = memory_events[i];
if(m.size==0)
continue;
double size = 1.0*m.size/(1024*1024);
if(m.is_alloc)
paje.AddVariable( m.time, variable_type_memory, container_memory, size);
else
paje.SubVariable( m.time, variable_type_memory, container_memory, size);
}
std::set<int> timer_ids; std::set<int> timer_ids;
std::map<int,int> timer_aliases; std::map<int,int> timer_aliases;
std::map<int,std::string> timer_names; std::map<int,std::string> timer_names;
@ -718,7 +759,10 @@ namespace ngcore
} }
} }
} }
WriteSunburstHTML(); WriteTimingChart();
#ifdef NETGEN_TRACE_MEMORY
WriteMemoryChart("");
#endif // NETGEN_TRACE_MEMORY
paje.WriteEvents(); paje.WriteEvents();
} }
@ -786,24 +830,25 @@ namespace ngcore
int id = 0; int id = 0;
std::map<int, TreeNode> children; std::map<int, TreeNode> children;
double chart_size = 0.0; // time without children (the chart lib accumulates children sizes again) double chart_size = 0.0; // time without children (the chart lib accumulates children sizes again)
double time = 0.0; double size = 0.0;
double min_time = 1e99; double min_size = 1e99;
double max_time = 0.0; double max_size = 0.0;
size_t calls = 0;
std::string name; std::string name;
size_t calls = 0;
TTimePoint start_time = 0; TTimePoint start_time = 0;
}; };
void PrintNode (const TreeNode &n, int &level, std::ofstream & f); void PrintNode (const TreeNode &n, std::ofstream & f)
void PrintNode (const TreeNode &n, int &level, std::ofstream & f)
{ {
f << "{ name: \"" + n.name + "\""; f << "{ name: \"" + n.name + "\"";
f << ", calls: " << n.calls; f << ", calls: " << n.calls;
f << ", size: " << n.chart_size; f << ", size: " << n.chart_size;
f << ", time: " << n.time; f << ", value: " << n.size;
f << ", min: " << n.min_time; f << ", min: " << n.min_size;
f << ", max: " << n.max_time; f << ", max: " << n.max_size;
f << ", avg: " << n.time/n.calls; if(n.calls)
f << ", avg: " << n.size/n.calls;
int size = n.children.size(); int size = n.children.size();
if(size>0) if(size>0)
{ {
@ -811,7 +856,7 @@ namespace ngcore
f << ", children: ["; f << ", children: [";
for(auto & c : n.children) for(auto & c : n.children)
{ {
PrintNode(c.second, level, f); PrintNode(c.second, f);
if(++i<size) if(++i<size)
f << " , "; f << " , ";
} }
@ -820,7 +865,220 @@ namespace ngcore
f << '}'; f << '}';
} }
void PajeTrace::WriteSunburstHTML( ) void WriteSunburstHTML( TreeNode & root, std::string filename, bool time_or_memory )
{
std::ofstream f(filename+".html");
f.precision(4);
f << R"CODE_(
<head>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/sunburst-chart"></script>
<style>body { margin: 0 }</style>
)CODE_";
if(!time_or_memory)
f << "<title>Maximum Memory Consumption</title>\n";
f << R"CODE_(
</head>
<body>
<div id="chart"></div>
<script>
const data =
)CODE_";
PrintNode(root, f);
f << ";\n\n";
if(time_or_memory)
f << "const chart_type = 'time';\n";
else
f << "const chart_type = 'memory';\n";
f << R"CODE_(
const color = d3.scaleOrdinal(d3.schemePaired);
let getTime = (t) =>
{
if(t>=1000) return (t/1000).toPrecision(4) + ' s';
if(t>=0.1) return t.toPrecision(4) + ' ms';
if(t>=1e-4) return (t*1e3).toPrecision(4) + ' us';
return (t/1e6).toPrecision(4) + ' ns';
};
const KB_ = 1024;
const MB_ = KB_*1024;
const GB_ = MB_*1024;
let getMemory = (m) =>
{
if(m>=GB_) return (m/GB_).toPrecision(4) + ' GB';
if(m>=MB_) return (m/MB_).toPrecision(4) + ' MB';
if(m>=KB_) return (m/KB_).toPrecision(4) + ' KB';
return m.toPrecision(4) + ' B';
};
Sunburst()
.data(data)
.size('size')
.color(d => color(d.name))
.tooltipTitle((d, node) => { return node.parent ? node.parent.data.name + " &rarr; " + d.name : d.name; })
.tooltipContent((d, node) => {
if(chart_type=="memory")
{
return `Total Memory: <i>${getMemory(d.value)}</i> <br>`
+ `Memory: <i>${getMemory(d.size)}</i>`
}
else
{
return `Time: <i>${getTime(d.value)}</i> <br>`
+ `calls: <i>${d.calls}</i> <br>`
+ `min: <i>${getTime(d.min)}</i> <br>`
+ `max: <i>${getTime(d.max)}</i> <br>`
+ `avg: <i>${getTime(d.avg)}</i>`
}
})
(document.getElementById('chart'));
// Line breaks in tooltip
var all = document.getElementsByClassName('sunbirst-tooltip');
for (var i = 0; i < all.length; i++) {
all[i].white_space = "";
}
</script>
</body>
)CODE_" << std::endl;
}
#ifdef NETGEN_TRACE_MEMORY
void PajeTrace::WriteMemoryChart( std::string fname )
{
if(fname=="")
fname = tracefile_name + "_memory";
size_t mem_allocated = 0;
size_t max_mem_allocated = 0;
size_t imax_mem_allocated = 0;
const auto & names = MemoryTracer::GetNames();
const auto & parents = MemoryTracer::GetParents();
size_t N = names.size();
Array<size_t> mem_allocated_id;
mem_allocated_id.SetSize(N);
mem_allocated_id = 0;
// Find point with maximum memory allocation, check for missing allocs/frees
for(auto i : IntRange(memory_events.size()))
{
const auto & ev = memory_events[i];
if(ev.is_alloc)
{
mem_allocated += ev.size;
mem_allocated_id[ev.id] += ev.size;
if(mem_allocated > max_mem_allocated && i>=n_memory_events_at_start)
{
imax_mem_allocated = i;
max_mem_allocated = mem_allocated;
}
}
else
{
if(ev.size > mem_allocated)
{
std::cerr << "Error in memory tracer: have total allocated memory < 0" << std::endl;
mem_allocated = 0;
}
else
mem_allocated -= ev.size;
if(ev.size > mem_allocated_id[ev.id])
{
std::cerr << "Error in memory tracer: have allocated memory < 0 in tracer " << names[ev.id] << std::endl;
mem_allocated_id[ev.id] = 0;
}
else
mem_allocated_id[ev.id] -= ev.size;
}
}
// reconstruct again the memory consumption after event imax_mem_allocated
mem_allocated_id = 0;
for(auto i : IntRange(imax_mem_allocated+1))
{
const auto & ev = memory_events[i];
if(ev.is_alloc)
mem_allocated_id[ev.id] += ev.size;
else
{
if(ev.size > mem_allocated_id[ev.id])
mem_allocated_id[ev.id] = 0;
else
mem_allocated_id[ev.id] -= ev.size;
}
}
TreeNode root;
root.name="all";
Array<TreeNode*> nodes;
nodes.SetSize(N);
nodes = nullptr;
nodes[0] = &root;
Array<Array<int>> children(N);
Array<size_t> sorting; // topological sorting (parents before children)
sorting.SetAllocSize(N);
for(auto i : IntRange(1, N))
children[parents[i]].Append(i);
ArrayMem<size_t, 100> stack;
sorting.Append(0);
stack.Append(0);
while(stack.Size())
{
auto current = stack.Last();
stack.DeleteLast();
for(const auto child : children[current])
{
sorting.Append(child);
if(children[child].Size())
stack.Append(child);
}
}
for(auto i : sorting)
{
if(i==0)
continue;
TreeNode * parent = nodes[parents[i]];
auto & node = parent->children[i];
nodes[i] = &node;
node.id = i;
node.chart_size = mem_allocated_id[i];
node.size = mem_allocated_id[i];
node.name = names[i];
}
for(auto i_ : Range(sorting))
{
// reverse topological order to accumulate total memory usage of all children
auto i = sorting[sorting.Size()-1-i_];
if(i==0)
continue;
nodes[parents[i]]->size += nodes[i]->size;
}
WriteSunburstHTML( root, fname, false );
}
#endif // NETGEN_TRACE_MEMORY
void PajeTrace::WriteTimingChart( )
{ {
std::vector<TimerEvent> events; std::vector<TimerEvent> events;
@ -861,10 +1119,10 @@ namespace ngcore
std::sort (events.begin(), events.end()); std::sort (events.begin(), events.end());
root.time = 1000.0*static_cast<double>(stop_time) * seconds_per_tick; root.size = 1000.0*static_cast<double>(stop_time) * seconds_per_tick;
root.calls = 1; root.calls = 1;
root.min_time = root.time; root.min_size = root.size;
root.max_time = root.time; root.max_size = root.size;
for(auto & event : events) for(auto & event : events)
{ {
@ -881,7 +1139,7 @@ namespace ngcore
if(need_init) if(need_init)
{ {
current->name = is_timer_event ? GetTimerName(id) : job_names[id]; current->name = is_timer_event ? GetTimerName(id) : job_names[id];
current->time = 0.0; current->size = 0.0;
current->id = id; current->id = id;
} }
@ -893,73 +1151,22 @@ namespace ngcore
std::cout << "node stack empty!" << std::endl; std::cout << "node stack empty!" << std::endl;
break; break;
} }
double time = 1000.0*static_cast<double>(event.time-current->start_time) * seconds_per_tick; double size = 1000.0*static_cast<double>(event.time-current->start_time) * seconds_per_tick;
current->time += time; current->size += size;
current->chart_size += time; current->chart_size += size;
current->min_time = std::min(current->min_time, time); current->min_size = std::min(current->min_size, size);
current->max_time = std::max(current->max_time, time); current->max_size = std::max(current->max_size, size);
current->calls++; current->calls++;
current = node_stack.back(); current = node_stack.back();
current->chart_size -= time; current->chart_size -= size;
node_stack.pop_back(); node_stack.pop_back();
} }
} }
root.chart_size = 0.0; root.chart_size = 0.0;
int level = 0; ngcore::WriteSunburstHTML( root, tracefile_name, true );
std::ofstream f(tracefile_name+".html");
f.precision(4);
f << R"CODE_(
<head>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/sunburst-chart"></script>
<style>body { margin: 0 }</style>
</head>
<body>
<div id="chart"></div>
<script>
const data =
)CODE_";
PrintNode(root, level, f);
f << R"CODE_( ;
const color = d3.scaleOrdinal(d3.schemePaired);
let getTime = (t) =>
{
if(t>=1000) return (t/1000).toPrecision(4) + ' s';
if(t>=0.1) return t.toPrecision(4) + ' ms';
if(t>=1e-4) return (t*1e3).toPrecision(4) + ' us';
return (t/1e6).toPrecision(4) + ' ns';
};
Sunburst()
.data(data)
.size('size')
.color(d => color(d.name))
.tooltipTitle((d, node) => { return node.parent ? node.parent.data.name + " &rarr; " + d.name : d.name; })
.tooltipContent((d, node) => {
return `Time: <i>${getTime(d.time)}</i> <br>`
+ `calls: <i>${d.calls}</i> <br>`
+ `min: <i>${getTime(d.min)}</i> <br>`
+ `max: <i>${getTime(d.max)}</i> <br>`
+ `avg: <i>${getTime(d.avg)}</i>`
})
(document.getElementById('chart'));
// Line breaks in tooltip
var all = document.getElementsByClassName('sunbirst-tooltip');
for (var i = 0; i < all.length; i++) {
all[i].white_space = "";
}
</script>
</body>
)CODE_" << std::endl;
} }
} // namespace ngcore } // namespace ngcore

View File

@ -23,18 +23,28 @@ namespace ngcore
NGCORE_API static size_t max_tracefile_size; NGCORE_API static size_t max_tracefile_size;
NGCORE_API static bool trace_thread_counter; NGCORE_API static bool trace_thread_counter;
NGCORE_API static bool trace_threads; NGCORE_API static bool trace_threads;
NGCORE_API static bool mem_tracing_enabled;
bool tracing_enabled; bool tracing_enabled;
TTimePoint start_time; TTimePoint start_time;
int nthreads; int nthreads;
size_t n_memory_events_at_start;
public: public:
void WriteSunburstHTML(); NGCORE_API void WriteTimingChart();
#ifdef NETGEN_TRACE_MEMORY
NGCORE_API void WriteMemoryChart( std::string fname );
#endif // NETGEN_TRACE_MEMORY
// Approximate number of events to trace. Tracing will // Approximate number of events to trace. Tracing will
// be stopped if any thread reaches this number of events // be stopped if any thread reaches this number of events
unsigned int max_num_events_per_thread; unsigned int max_num_events_per_thread;
static void SetTraceMemory( bool trace_memory )
{
mem_tracing_enabled = trace_memory;
}
static void SetTraceThreads( bool atrace_threads ) static void SetTraceThreads( bool atrace_threads )
{ {
trace_threads = atrace_threads; trace_threads = atrace_threads;
@ -96,10 +106,21 @@ namespace ngcore
bool operator < (const ThreadLink & other) const { return time < other.time; } bool operator < (const ThreadLink & other) const { return time < other.time; }
}; };
struct MemoryEvent
{
TTimePoint time;
size_t size;
int id;
bool is_alloc;
bool operator < (const MemoryEvent & other) const { return time < other.time; }
};
std::vector<std::vector<Task> > tasks; std::vector<std::vector<Task> > tasks;
std::vector<Job> jobs; std::vector<Job> jobs;
std::vector<TimerEvent> timer_events; std::vector<TimerEvent> timer_events;
std::vector<std::vector<ThreadLink> > links; std::vector<std::vector<ThreadLink> > links;
NGCORE_API static std::vector<MemoryEvent> memory_events;
public: public:
NGCORE_API void StopTracing(); NGCORE_API void StopTracing();
@ -129,6 +150,27 @@ namespace ngcore
timer_events.push_back(TimerEvent{timer_id, GetTimeCounter(), false}); timer_events.push_back(TimerEvent{timer_id, GetTimeCounter(), false});
} }
void AllocMemory(int id, size_t size)
{
if(!mem_tracing_enabled) return;
memory_events.push_back(MemoryEvent{GetTimeCounter(), size, id, true});
}
void FreeMemory(int id, size_t size)
{
if(!mem_tracing_enabled) return;
memory_events.push_back(MemoryEvent{GetTimeCounter(), size, id, false});
}
void ChangeMemory(int id, long long size)
{
if(size>0)
AllocMemory(id, size);
if(size<0)
FreeMemory(id, -size);
}
NETGEN_INLINE int StartTask(int thread_id, int id, int id_type = Task::ID_NONE, int additional_value = -1) 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(!tracing_enabled) return -1;

View File

@ -113,5 +113,9 @@ namespace ngcore
NgProfiler prof; // NOLINT NgProfiler prof; // NOLINT
#ifdef NETGEN_TRACE_MEMORY
std::vector<std::string> MemoryTracer::names{"all"};
std::vector<int> MemoryTracer::parents{-1};
#endif // NETGEN_TRACE_MEMORY
} // namespace ngcore } // namespace ngcore

View File

@ -3,6 +3,7 @@
#include <array> #include <array>
#include <chrono> #include <chrono>
#include <functional>
#include <string> #include <string>
#include "logging.hpp" #include "logging.hpp"
@ -299,6 +300,161 @@ namespace ngcore
return tres; return tres;
} }
class MemoryTracer;
namespace detail
{
//Type trait to check if a class implements a 'void SetMemoryTacing(int)' function
template<typename T>
struct has_StartMemoryTracing
{
private:
template<typename T2>
static constexpr auto check(T2*) ->
typename std::is_same<decltype(std::declval<T2>().StartMemoryTracing()),void>::type;
template<typename>
static constexpr std::false_type check(...);
using type = decltype(check<T>(nullptr)); // NOLINT
public:
static constexpr bool value = type::value;
};
} // namespace detail
class MemoryTracer
{
#ifdef NETGEN_TRACE_MEMORY
NGCORE_API static std::vector<std::string> names;
NGCORE_API static std::vector<int> parents;
static int CreateId(const std::string& name)
{
int id = names.size();
names.push_back(name);
parents.push_back(0);
if(id==10*NgProfiler::SIZE)
std::cerr << "Allocated " << id << " MemoryTracer objects" << std::endl;
return id;
}
int id;
public:
MemoryTracer( std::string name )
{
id = CreateId(name);
}
// not tracing
MemoryTracer() : id(0) {}
template <typename... TRest>
MemoryTracer( std::string name, TRest & ... rest )
{
id = CreateId(name);
Track(rest...);
}
NETGEN_INLINE void Alloc(size_t size) const
{
if(id && trace)
trace->AllocMemory(id, size);
}
void Free(size_t size) const
{
if(id && trace)
trace->FreeMemory(id, size);
}
void Swap(size_t mysize, MemoryTracer& other, size_t other_size) const
{
if(!trace || (id == 0 && other.id == 0))
return;
if(id == 0)
return trace->ChangeMemory(other.id, mysize - other_size);
if(other.id == 0)
return trace->ChangeMemory(id, other_size - mysize);
// first decrease memory, otherwise have artificial/wrong high peak memory usage
if(mysize<other_size)
{
trace->ChangeMemory(other.id, mysize-other_size);
trace->ChangeMemory(id, other_size-mysize);
}
else
{
trace->ChangeMemory(id, other_size-mysize);
trace->ChangeMemory(other.id, mysize-other_size);
}
}
int GetId() const { return id; }
template <typename T1, typename... TRest>
void Track( T1 & obj, const std::string& name, TRest & ... rest ) const
{
Track(obj, name);
Track(rest...);
}
template<typename T>
void Track( T & obj, const std::string& name ) const
{
obj.GetMemoryTracer().Activate(obj, name);
parents[obj.GetMemoryTracer().GetId()] = id;
}
static std::string GetName(int id)
{
return names[id];
}
std::string GetName() const
{
return names[id];
}
template<typename T>
void Activate(T& me, const std::string& name) const
{
if(!id)
{
const_cast<MemoryTracer*>(this)->id = CreateId(name);
if constexpr(detail::has_StartMemoryTracing<T>::value)
me.StartMemoryTracing();
}
else
SetName(name);
}
void SetName(const std::string& name) const
{
names[id] = name;
}
static const std::vector<std::string> & GetNames() { return names; }
static const std::vector<int> & GetParents() { return parents; }
#else // NETGEN_TRACE_MEMORY
public:
MemoryTracer() {}
MemoryTracer( std::string name ) {}
template <typename... TRest>
MemoryTracer( std::string name, TRest & ... ) {}
void Alloc(size_t size) const {}
void Free(size_t size) const {}
void Swap(...) const {}
int GetId() const { return 0; }
template <typename... TRest>
void Track(TRest&...) const {}
static std::string GetName(int id) { return ""; }
std::string GetName() const { return ""; }
void SetName(std::string name) const {}
#endif // NETGEN_TRACE_MEMORY
};
} // namespace ngcore } // namespace ngcore
// Helper macro to easily add multiple timers in a function for profiling // Helper macro to easily add multiple timers in a function for profiling

View File

@ -247,23 +247,28 @@ threads : int
; ;
py::class_<PajeTrace>(m, "PajeTrace") py::class_<PajeTrace>(m, "PajeTrace")
.def(py::init( [] (string filename, size_t size_mb, bool threads, bool thread_counter) .def(py::init( [] (string filename, size_t size_mb, bool threads, bool thread_counter, bool memory)
{ {
PajeTrace::SetMaxTracefileSize(size_mb*1014*1024); PajeTrace::SetMaxTracefileSize(size_mb*1014*1024);
PajeTrace::SetTraceThreads(threads); PajeTrace::SetTraceThreads(threads);
PajeTrace::SetTraceMemory(memory);
PajeTrace::SetTraceThreadCounter(thread_counter); PajeTrace::SetTraceThreadCounter(thread_counter);
trace = new PajeTrace(TaskManager::GetMaxThreads(), filename); trace = new PajeTrace(TaskManager::GetMaxThreads(), filename);
return trace; return trace;
}), py::arg("filename")="ng.trace", py::arg("size")=1000, }), py::arg("filename")="ng.trace", py::arg("size")=1000,
py::arg("threads")=true, py::arg("thread_counter")=false, py::arg("threads")=true, py::arg("thread_counter")=false,
py::arg("memory")=true,
"size in Megabytes" "size in Megabytes"
) )
.def("__enter__", [](PajeTrace & self) { }) .def("__enter__", [](PajeTrace & self) { })
.def("__exit__", [](PajeTrace & self, py::args) { self.StopTracing(); }) .def("__exit__", [](PajeTrace & self, py::args) { self.StopTracing(); })
.def("__del__", [](PajeTrace & self) { trace = nullptr; }) .def("__del__", [](PajeTrace & self) { trace = nullptr; })
.def("SetTraceThreads", &PajeTrace::SetTraceThreads) .def_static("SetTraceThreads", &PajeTrace::SetTraceThreads)
.def("SetTraceThreadCounter", &PajeTrace::SetTraceThreadCounter) .def_static("SetTraceThreadCounter", &PajeTrace::SetTraceThreadCounter)
.def("SetMaxTracefileSize", &PajeTrace::SetMaxTracefileSize) .def_static("SetMaxTracefileSize", &PajeTrace::SetMaxTracefileSize)
#ifdef NETGEN_TRACE_MEMORY
.def_static("WriteMemoryChart", [](string filename){ if(trace) trace->WriteMemoryChart(filename); }, py::arg("filename")="memory" )
#endif // NETGEN_TRACE_MEMORY
; ;

View File

@ -159,6 +159,7 @@ namespace ngcore
NETGEN_INLINE Table (Table && tab2) NETGEN_INLINE Table (Table && tab2)
: FlatTable<T,IndexType>(0, nullptr, nullptr) : FlatTable<T,IndexType>(0, nullptr, nullptr)
{ {
tab2.mt.Free(tab2.GetMemUsage());
Swap (size, tab2.size); Swap (size, tab2.size);
Swap (index, tab2.index); Swap (index, tab2.index);
Swap (data, tab2.data); Swap (data, tab2.data);
@ -166,6 +167,7 @@ namespace ngcore
NETGEN_INLINE Table & operator= (Table && tab2) NETGEN_INLINE Table & operator= (Table && tab2)
{ {
mt.Swap(GetMemUsage(), tab2.mt, tab2.GetMemUsage());
Swap (size, tab2.size); Swap (size, tab2.size);
Swap (index, tab2.index); Swap (index, tab2.index);
Swap (data, tab2.data); Swap (data, tab2.data);
@ -177,6 +179,7 @@ namespace ngcore
/// Delete data /// Delete data
NETGEN_INLINE ~Table () NETGEN_INLINE ~Table ()
{ {
mt.Free(GetMemUsage());
delete [] data; delete [] data;
delete [] index; delete [] index;
} }
@ -188,6 +191,16 @@ namespace ngcore
NETGEN_INLINE size_t NElements() const { return index[size]; } NETGEN_INLINE size_t NElements() const { return index[size]; }
using FlatTable<T,IndexType>::operator[]; using FlatTable<T,IndexType>::operator[];
NETGEN_INLINE void StartMemoryTracing (int mem_id)
{
mt.Alloc(GetMemUsage());
}
const MemoryTracer& GetMemoryTracer() const { return mt; }
private:
size_t GetMemUsage() const { return size == 0 ? 0 : sizeof(T)*index[size] + sizeof(IndexType) * size+1; }
MemoryTracer mt;
}; };

View File

@ -160,7 +160,7 @@ namespace ngcore
static int cnt = 0; static int cnt = 0;
if (use_paje_trace) if (use_paje_trace)
trace = new PajeTrace(num_threads, "ng" + ToString(cnt++) + ".trace"); trace = new PajeTrace(num_threads, "ng" + ToString(cnt++));
} }

View File

@ -42,12 +42,11 @@ namespace netgen
{ {
Point3d p; Point3d p;
in >> p.X() >> p.Y() >> p.Z(); in >> p.X() >> p.Y() >> p.Z();
p.Z() *= 10;
mesh.AddPoint (p); mesh.AddPoint (p);
} }
mesh.ClearFaceDescriptors(); mesh.ClearFaceDescriptors();
mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0)); mesh.AddFaceDescriptor (FaceDescriptor(1,1,0,0));
in >> nbe; in >> nbe;
// int invert = globflags.GetDefineFlag ("invertsurfacemesh"); // int invert = globflags.GetDefineFlag ("invertsurfacemesh");

View File

@ -90,6 +90,9 @@ namespace netgen
void GenerateBoundaryLayer(Mesh& mesh, const BoundaryLayerParameters& blp) void GenerateBoundaryLayer(Mesh& mesh, const BoundaryLayerParameters& blp)
{ {
static Timer timer("Create Boundarylayers");
RegionTimer regt(timer);
int max_edge_nr = -1; int max_edge_nr = -1;
for(const auto& seg : mesh.LineSegments()) for(const auto& seg : mesh.LineSegments())
if(seg.edgenr > max_edge_nr) if(seg.edgenr > max_edge_nr)
@ -408,6 +411,10 @@ namespace netgen
} }
} }
BitArray fixed_points(np+1);
fixed_points.Clear();
BitArray moveboundarypoint(np+1);
moveboundarypoint.Clear();
for(SurfaceElementIndex si = 0; si < nse; si++) for(SurfaceElementIndex si = 0; si < nse; si++)
{ {
// copy because surfaceels array will be resized! // copy because surfaceels array will be resized!
@ -436,11 +443,30 @@ namespace netgen
newel.SetIndex(si_map[sel.GetIndex()]); newel.SetIndex(si_map[sel.GetIndex()]);
mesh.AddSurfaceElement(newel); mesh.AddSurfaceElement(newel);
} }
else
{
bool has_moved = false;
for(auto p : sel.PNums())
if(mapto[p].Size())
has_moved = true;
if(has_moved)
for(auto p : sel.PNums())
{
if(!mapto[p].Size())
{
fixed_points.SetBit(p);
if(move_boundaries.Test(sel.GetIndex())) if(move_boundaries.Test(sel.GetIndex()))
moveboundarypoint.SetBit(p);
}
}
}
if(move_boundaries.Test(sel.GetIndex()))
{
for(auto& p : mesh[si].PNums()) for(auto& p : mesh[si].PNums())
if(mapto[p].Size()) if(mapto[p].Size())
p = mapto[p].Last(); p = mapto[p].Last();
} }
}
for(SegmentIndex sei = 0; sei < nseg; sei++) for(SegmentIndex sei = 0; sei < nseg; sei++)
{ {
@ -453,13 +479,85 @@ namespace netgen
for(ElementIndex ei = 0; ei < ne; ei++) for(ElementIndex ei = 0; ei < ne; ei++)
{ {
auto& el = mesh[ei]; auto el = mesh[ei];
if(!domains[el.GetIndex()]) ArrayMem<PointIndex,4> fixed;
ArrayMem<PointIndex,4> moved;
bool moved_bnd = false;
for(const auto& p : el.PNums())
{ {
for(auto& p : el.PNums()) if(fixed_points.Test(p))
fixed.Append(p);
if(mapto[p].Size())
moved.Append(p);
if(moveboundarypoint.Test(p))
moved_bnd = true;
}
bool do_move, do_insert;
if(domains.Test(el.GetIndex()))
{
do_move = fixed.Size() && moved_bnd;
do_insert = do_move;
}
else
{
do_move = !fixed.Size() || moved_bnd;
do_insert = !do_move;
}
if(do_move)
{
for(auto& p : mesh[ei].PNums())
if(mapto[p].Size()) if(mapto[p].Size())
p = mapto[p].Last(); p = mapto[p].Last();
} }
if(do_insert)
{
if(el.GetType() != TET)
throw Exception("Boundarylayer only implemented for tets outside yet!");
if(moved.Size() == 2)
{
if(fixed.Size() == 2)
throw Exception("This should not be possible!");
PointIndex p1 = moved[0];
PointIndex p2 = moved[1];
for(auto i : Range(blp.heights))
{
PointIndex p3 = mapto[moved[1]][i];
PointIndex p4 = mapto[moved[0]][i];
Element nel(PYRAMID);
nel[0] = p1;
nel[1] = p2;
nel[2] = p3;
nel[3] = p4;
nel[4] = el[0] + el[1] + el[2] + el[3] - fixed[0] - moved[0] - moved[1];
if(Cross(mesh[p2]-mesh[p1], mesh[p4]-mesh[p1]) * (mesh[nel[4]]-mesh[nel[1]]) > 0)
Swap(nel[1], nel[3]);
nel.SetIndex(el.GetIndex());
mesh.AddVolumeElement(nel);
p1 = p4;
p2 = p3;
}
}
if(moved.Size() == 1 && fixed.Size() == 1)
{
PointIndex p1 = moved[0];
for(auto i : Range(blp.heights))
{
Element nel = el;
PointIndex p2 = mapto[moved[0]][i];
for(auto& p : nel.PNums())
{
if(p == moved[0])
p = p1;
else if(p == fixed[0])
p = p2;
}
p1 = p2;
mesh.AddVolumeElement(nel);
}
}
}
} }
for(auto i : Range(1, fd_old+1)) for(auto i : Range(1, fd_old+1))

View File

@ -772,6 +772,7 @@ namespace netgen
// improve delaunay - mesh by swapping !!!! // improve delaunay - mesh by swapping !!!!
Mesh tempmesh; Mesh tempmesh;
tempmesh.GetMemoryTracer().SetName("delaunay-tempmesh");
for (auto & meshpoint : mesh.Points()) for (auto & meshpoint : mesh.Points())
tempmesh.AddPoint (meshpoint); tempmesh.AddPoint (meshpoint);

View File

@ -3716,6 +3716,18 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI
FlatArray<ElementIndex> row = elementsonnode[pi1]; FlatArray<ElementIndex> row = elementsonnode[pi1];
for(auto ei : row)
if (mesh[ei].IsDeleted()) return 0.0;
for(auto ei : elementsonnode[pi2])
if (mesh[ei].IsDeleted()) return 0.0;
for(auto ei : elementsonnode[pi3])
if (mesh[ei].IsDeleted()) return 0.0;
for(auto ei : elementsonnode[pi4])
if (mesh[ei].IsDeleted()) return 0.0;
for (int k = 0; k < row.Size(); k++) for (int k = 0; k < row.Size(); k++)
{ {
ElementIndex eli2 = row[k]; ElementIndex eli2 = row[k];
@ -3723,7 +3735,6 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI
if ( eli1 != eli2 ) if ( eli1 != eli2 )
{ {
Element & elem2 = mesh[eli2]; Element & elem2 = mesh[eli2];
if (elem2.IsDeleted()) continue;
if (elem2.GetType() != TET) if (elem2.GetType() != TET)
continue; continue;
@ -3992,8 +4003,12 @@ void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal)
QuickSort(faces_with_improvement); QuickSort(faces_with_improvement);
for (auto [dummy, eli,j] : faces_with_improvement) for (auto [dummy, eli,j] : faces_with_improvement)
{
if(mesh[eli].IsDeleted())
continue;
if(SwapImprove2( mesh, goal, eli, j, elementsonnode, belementsonnode, false) < 0.0) if(SwapImprove2( mesh, goal, eli, j, elementsonnode, belementsonnode, false) < 0.0)
cnt++; cnt++;
}
PrintMessage (5, cnt, " swaps performed"); PrintMessage (5, cnt, " swaps performed");

View File

@ -6642,6 +6642,7 @@ namespace netgen
paralleltop->UpdateCoarseGrid(); paralleltop->UpdateCoarseGrid();
} }
#endif #endif
updateSignal.Emit();
} }
void Mesh :: BuildCurvedElements (const Refinement * ref, int aorder, bool arational) void Mesh :: BuildCurvedElements (const Refinement * ref, int aorder, bool arational)

View File

@ -172,6 +172,7 @@ namespace netgen
const int element) const; const int element) const;
public: public:
Signal<> updateSignal;
// store coarse mesh before hp-refinement // store coarse mesh before hp-refinement
unique_ptr<NgArray<HPRefElement>> hpelements; unique_ptr<NgArray<HPRefElement>> hpelements;
@ -925,6 +926,15 @@ namespace netgen
shared_ptr<Mesh> Mirror( netgen::Point<3> p, Vec<3> n ); shared_ptr<Mesh> Mirror( netgen::Point<3> p, Vec<3> n );
private:
MemoryTracer mem_tracer = {"Mesh",
points, "points",
segments, "segments",
surfelements, "surfelements",
volelements, "volelements"
};
public:
const MemoryTracer & GetMemoryTracer() { return mem_tracer; }
}; };
inline ostream& operator<<(ostream& ost, const Mesh& mesh) inline ostream& operator<<(ostream& ost, const Mesh& mesh)

View File

@ -1136,8 +1136,8 @@ project_boundaries : Optional[str] = None
.def ("Scale", [](Mesh & self, double factor) .def ("Scale", [](Mesh & self, double factor)
{ {
for(auto i = 0; i<self.GetNP();i++) for(auto & pnt : self.Points())
self.Point(i).Scale(factor); pnt.Scale(factor);
}) })
.def ("Copy", [](Mesh & self) .def ("Copy", [](Mesh & self)
{ {

View File

@ -4,11 +4,9 @@ else()
add_definitions(-DINTERNAL_TCL_DEFAULT=0) add_definitions(-DINTERNAL_TCL_DEFAULT=0)
endif() endif()
set(netgen_sources ngappinit.cpp onetcl.cpp)
if(WIN32) if(WIN32)
# add icon to netgen executable # add icon and version info to netgen executable
enable_language(RC) enable_language(RC)
set(netgen_sources ${netgen_sources} ../windows/netgen.rc)
# Don't use ccache here due to incompatibility with the resource compiler # Don't use ccache here due to incompatibility with the resource compiler
set_directory_properties(PROPERTIES RULE_LAUNCH_COMPILE "") set_directory_properties(PROPERTIES RULE_LAUNCH_COMPILE "")
endif(WIN32) endif(WIN32)
@ -23,6 +21,9 @@ if(USE_GUI)
) )
add_executable(netgen ngappinit.cpp) add_executable(netgen ngappinit.cpp)
if(WIN32)
target_sources(netgen PRIVATE ../windows/netgen.rc)
endif(WIN32)
target_link_libraries( gui PUBLIC nglib ) target_link_libraries( gui PUBLIC nglib )
target_link_libraries( gui PRIVATE ${LIBTOGL} ${ZLIB_LIBRARIES} ${JPEG_LIBRARIES} ${FFMPEG_LIBRARIES} ${X11_Xmu_LIB} ${X11_X11_LIB} ${OCC_LIBRARIES} ) target_link_libraries( gui PRIVATE ${LIBTOGL} ${ZLIB_LIBRARIES} ${JPEG_LIBRARIES} ${FFMPEG_LIBRARIES} ${X11_Xmu_LIB} ${X11_X11_LIB} ${OCC_LIBRARIES} )

View File

@ -293,18 +293,18 @@
}, },
{ {
"angles_tet": [ "angles_tet": [
14.466, 16.89,
161.38 158.0
], ],
"angles_trig": [ "angles_trig": [
13.564, 16.739,
150.65 133.14
], ],
"ne1d": 32, "ne1d": 32,
"ne2d": 220, "ne2d": 220,
"ne3d": 563, "ne3d": 551,
"quality_histogram": "[0, 0, 0, 3, 3, 7, 24, 22, 35, 34, 40, 43, 45, 60, 61, 53, 58, 41, 27, 7]", "quality_histogram": "[0, 0, 0, 0, 0, 3, 4, 16, 23, 34, 48, 43, 50, 61, 70, 53, 51, 48, 37, 10]",
"total_badness": 960.07699692 "total_badness": 860.81905284
}, },
{ {
"angles_tet": [ "angles_tet": [
@ -473,7 +473,7 @@
"ne2d": 726, "ne2d": 726,
"ne3d": 2167, "ne3d": 2167,
"quality_histogram": "[0, 4, 17, 35, 75, 117, 114, 112, 77, 51, 58, 86, 115, 177, 248, 293, 239, 204, 118, 27]", "quality_histogram": "[0, 4, 17, 35, 75, 117, 114, 112, 77, 51, 58, 86, 115, 177, 248, 293, 239, 204, 118, 27]",
"total_badness": 4176.9278168 "total_badness": 4176.9284057
}, },
{ {
"angles_tet": [ "angles_tet": [
@ -860,18 +860,18 @@
}, },
{ {
"angles_tet": [ "angles_tet": [
16.061, 8.4923,
157.39 161.34
], ],
"angles_trig": [ "angles_trig": [
16.851, 20.122,
127.45 127.45
], ],
"ne1d": 36, "ne1d": 36,
"ne2d": 152, "ne2d": 152,
"ne3d": 385, "ne3d": 358,
"quality_histogram": "[0, 0, 0, 0, 0, 10, 8, 21, 24, 22, 29, 37, 42, 28, 43, 24, 38, 22, 25, 12]", "quality_histogram": "[0, 0, 1, 0, 0, 2, 5, 11, 21, 19, 22, 22, 31, 29, 35, 39, 57, 37, 17, 10]",
"total_badness": 647.21940974 "total_badness": 559.67849284
}, },
{ {
"angles_tet": [ "angles_tet": [
@ -1014,18 +1014,18 @@
}, },
{ {
"angles_tet": [ "angles_tet": [
5.7043, 5.6074,
170.47 169.95
], ],
"angles_trig": [ "angles_trig": [
8.0227, 7.5945,
160.66 159.99
], ],
"ne1d": 0, "ne1d": 0,
"ne2d": 192, "ne2d": 192,
"ne3d": 749, "ne3d": 748,
"quality_histogram": "[0, 2, 30, 63, 86, 89, 71, 68, 67, 54, 50, 43, 27, 28, 17, 23, 13, 9, 7, 2]", "quality_histogram": "[0, 0, 30, 62, 87, 77, 80, 61, 72, 38, 54, 43, 34, 27, 27, 20, 18, 10, 7, 1]",
"total_badness": 2339.9827516 "total_badness": 2287.1659209
}, },
{ {
"angles_tet": [ "angles_tet": [
@ -1391,9 +1391,9 @@
], ],
"ne1d": 5988, "ne1d": 5988,
"ne2d": 11102, "ne2d": 11102,
"ne3d": 29343, "ne3d": 29344,
"quality_histogram": "[3, 4, 5, 8, 14, 42, 121, 248, 691, 1040, 1542, 2504, 3118, 3920, 4331, 4281, 3366, 2421, 1367, 317]", "quality_histogram": "[3, 4, 5, 8, 14, 45, 122, 251, 692, 1044, 1527, 2497, 3115, 3927, 4328, 4293, 3367, 2421, 1363, 318]",
"total_badness": 43497.876838 "total_badness": 43503.906462
}, },
{ {
"angles_tet": [ "angles_tet": [
@ -1408,7 +1408,7 @@
"ne2d": 23964, "ne2d": 23964,
"ne3d": 80995, "ne3d": 80995,
"quality_histogram": "[2, 14, 4, 20, 18, 40, 94, 225, 485, 1115, 2415, 4537, 7493, 10248, 12753, 13190, 12020, 9207, 5660, 1455]", "quality_histogram": "[2, 14, 4, 20, 18, 40, 94, 225, 485, 1115, 2415, 4537, 7493, 10248, 12753, 13190, 12020, 9207, 5660, 1455]",
"total_badness": 111934.52308 "total_badness": 111934.5334
} }
], ],
"hinge.stl": [ "hinge.stl": [
@ -1490,7 +1490,7 @@
{ {
"angles_tet": [ "angles_tet": [
20.701, 20.701,
144.6 141.98
], ],
"angles_trig": [ "angles_trig": [
22.443, 22.443,
@ -1498,9 +1498,9 @@
], ],
"ne1d": 1862, "ne1d": 1862,
"ne2d": 19474, "ne2d": 19474,
"ne3d": 136546, "ne3d": 136541,
"quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 12, 59, 281, 864, 2538, 6435, 13014, 21236, 29154, 31109, 24006, 7837]", "quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 8, 59, 274, 862, 2533, 6435, 12998, 21248, 29157, 31131, 24003, 7832]",
"total_badness": 165965.29798 "total_badness": 165944.59425
} }
], ],
"lense.in2d": [ "lense.in2d": [
@ -1795,7 +1795,7 @@
"ne2d": 830, "ne2d": 830,
"ne3d": 2488, "ne3d": 2488,
"quality_histogram": "[0, 0, 3, 37, 71, 155, 161, 102, 158, 211, 284, 276, 249, 203, 195, 139, 108, 79, 42, 15]", "quality_histogram": "[0, 0, 3, 37, 71, 155, 161, 102, 158, 211, 284, 276, 249, 203, 195, 139, 108, 79, 42, 15]",
"total_badness": 5146.3098744 "total_badness": 5146.3098762
}, },
{ {
"angles_tet": [ "angles_tet": [
@ -2045,18 +2045,18 @@
}, },
{ {
"angles_tet": [ "angles_tet": [
11.213, 11.356,
163.54 162.52
], ],
"angles_trig": [ "angles_trig": [
13.446, 16.741,
152.87 141.37
], ],
"ne1d": 232, "ne1d": 232,
"ne2d": 598, "ne2d": 598,
"ne3d": 1380, "ne3d": 1418,
"quality_histogram": "[0, 0, 0, 2, 10, 15, 36, 48, 63, 92, 116, 131, 160, 158, 151, 113, 125, 91, 56, 13]", "quality_histogram": "[0, 0, 0, 2, 9, 14, 27, 47, 66, 97, 109, 150, 161, 159, 147, 133, 119, 96, 66, 16]",
"total_badness": 2309.6335564 "total_badness": 2344.2576172
}, },
{ {
"angles_tet": [ "angles_tet": [
@ -2132,8 +2132,8 @@
"ne1d": 570, "ne1d": 570,
"ne2d": 1202, "ne2d": 1202,
"ne3d": 1839, "ne3d": 1839,
"quality_histogram": "[2, 21, 37, 57, 67, 78, 110, 136, 161, 177, 190, 158, 155, 149, 115, 78, 69, 51, 24, 4]", "quality_histogram": "[2, 21, 37, 57, 66, 75, 111, 134, 161, 173, 193, 158, 151, 145, 117, 81, 73, 54, 25, 5]",
"total_badness": 4553.9697099 "total_badness": 4538.6020288
}, },
{ {
"angles_tet": [ "angles_tet": [
@ -2445,8 +2445,8 @@
}, },
{ {
"angles_tet": [ "angles_tet": [
15.158, 15.154,
158.0 159.78
], ],
"angles_trig": [ "angles_trig": [
17.101, 17.101,
@ -2454,14 +2454,14 @@
], ],
"ne1d": 410, "ne1d": 410,
"ne2d": 606, "ne2d": 606,
"ne3d": 796, "ne3d": 791,
"quality_histogram": "[0, 0, 0, 0, 1, 3, 5, 6, 28, 40, 56, 62, 82, 83, 128, 96, 88, 75, 29, 14]", "quality_histogram": "[0, 0, 0, 0, 2, 3, 4, 7, 33, 42, 54, 61, 88, 86, 118, 92, 89, 72, 29, 11]",
"total_badness": 1204.2331383 "total_badness": 1208.0636246
}, },
{ {
"angles_tet": [ "angles_tet": [
12.907, 12.907,
159.86 158.51
], ],
"angles_trig": [ "angles_trig": [
11.963, 11.963,
@ -2469,9 +2469,9 @@
], ],
"ne1d": 510, "ne1d": 510,
"ne2d": 1004, "ne2d": 1004,
"ne3d": 1838, "ne3d": 1859,
"quality_histogram": "[0, 0, 0, 4, 9, 30, 35, 80, 75, 109, 121, 152, 156, 200, 242, 206, 210, 105, 80, 24]", "quality_histogram": "[0, 0, 0, 3, 7, 29, 43, 74, 68, 95, 115, 158, 153, 213, 250, 232, 206, 107, 81, 25]",
"total_badness": 3018.9734455 "total_badness": 3021.4076425
}, },
{ {
"angles_tet": [ "angles_tet": [
@ -2997,18 +2997,18 @@
}, },
{ {
"angles_tet": [ "angles_tet": [
1.6657, 1.9786,
174.24 173.68
], ],
"angles_trig": [ "angles_trig": [
4.1081, 3.8198,
164.43 165.45
], ],
"ne1d": 0, "ne1d": 0,
"ne2d": 692, "ne2d": 692,
"ne3d": 2737, "ne3d": 2726,
"quality_histogram": "[17, 200, 365, 335, 363, 301, 234, 187, 154, 143, 106, 84, 56, 48, 38, 45, 27, 19, 12, 3]", "quality_histogram": "[19, 190, 366, 339, 352, 304, 237, 182, 157, 143, 110, 86, 53, 46, 34, 43, 30, 24, 10, 1]",
"total_badness": 13234.755766 "total_badness": 13096.6735
}, },
{ {
"angles_tet": [ "angles_tet": [
@ -3365,33 +3365,33 @@
}, },
{ {
"angles_tet": [ "angles_tet": [
19.944, 20.148,
152.59 153.82
], ],
"angles_trig": [ "angles_trig": [
25.599, 25.599,
123.4 118.3
], ],
"ne1d": 68, "ne1d": 68,
"ne2d": 100, "ne2d": 100,
"ne3d": 130, "ne3d": 135,
"quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 3, 6, 7, 9, 5, 13, 21, 16, 21, 19, 7, 1]", "quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 0, 4, 5, 2, 9, 5, 18, 25, 16, 22, 20, 7, 1]",
"total_badness": 187.02414176 "total_badness": 190.82756065
}, },
{ {
"angles_tet": [ "angles_tet": [
12.268, 12.268,
164.21 164.96
], ],
"angles_trig": [ "angles_trig": [
15.1, 15.698,
144.2 145.1
], ],
"ne1d": 102, "ne1d": 102,
"ne2d": 238, "ne2d": 238,
"ne3d": 468, "ne3d": 471,
"quality_histogram": "[0, 0, 1, 10, 5, 27, 33, 42, 51, 36, 38, 28, 35, 40, 29, 26, 37, 24, 4, 2]", "quality_histogram": "[0, 0, 1, 6, 3, 23, 25, 45, 63, 40, 34, 29, 30, 34, 27, 33, 43, 25, 8, 2]",
"total_badness": 980.42864262 "total_badness": 950.55701299
}, },
{ {
"angles_tet": [ "angles_tet": [

View File

@ -92,3 +92,18 @@ def test_splitted_surface():
mesh = ngs.Mesh(mesh) mesh = ngs.Mesh(mesh)
assert ngs.Integrate(1, mesh) == pytest.approx(1) assert ngs.Integrate(1, mesh) == pytest.approx(1)
assert ngs.Integrate(1, mesh.Materials("slot")) == pytest.approx(0.4) assert ngs.Integrate(1, mesh.Materials("slot")) == pytest.approx(0.4)
@pytest.mark.parametrize("outside", [True, False])
def test_pyramids(outside):
geo = CSGeometry()
box = OrthoBrick((0,0,0), (1,1,1))
plate = OrthoBrick((0.3,0.3,0.4),(0.7,0.7,1)) * Plane((0,0,0.6), (0,0,1)).bc("top")
geo.Add((box-plate).mat("air"))
geo.Add(plate.mat("plate"))
mesh = geo.GenerateMesh()
mesh.BoundaryLayer("top", [0.01], "layer", "plate", outside=outside)
ngs = pytest.importorskip("ngsolve")
mesh = ngs.Mesh(mesh)
assert ngs.Integrate(1, mesh.Materials("plate")) == pytest.approx(0.032 if outside else 0.0304)
assert ngs.Integrate(1, mesh.Materials("layer")) == pytest.approx(0.0016)
assert ngs.Integrate(1, mesh.Materials("air")) == pytest.approx(0.9664 if outside else 0.968)

1
windows/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
netgen.rc

View File

@ -0,0 +1,4 @@
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/netgen.rc.template"
"${CMAKE_CURRENT_SOURCE_DIR}/netgen.rc"
IMMEDIATE @ONLY)

View File

@ -7,7 +7,7 @@
// //
// Generated from the TEXTINCLUDE 2 resource. // Generated from the TEXTINCLUDE 2 resource.
// //
#include "afxres.h" #include <windows.h>
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS #undef APSTUDIO_READONLY_SYMBOLS
@ -35,8 +35,8 @@ LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,1,0,0 FILEVERSION @NETGEN_VERSION_MAJOR@,@NETGEN_VERSION_MINOR@,@NETGEN_VERSION_PATCH@,@NETGEN_VERSION_TWEAK@
PRODUCTVERSION 5,1,0,0 PRODUCTVERSION @NETGEN_VERSION_MAJOR@,@NETGEN_VERSION_MINOR@,@NETGEN_VERSION_PATCH@,@NETGEN_VERSION_TWEAK@
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x3L FILEFLAGS 0x3L
@ -51,14 +51,14 @@ BEGIN
BEGIN BEGIN
BLOCK "040904b0" BLOCK "040904b0"
BEGIN BEGIN
VALUE "CompanyName", "Vienna UT" VALUE "CompanyName", "TU Wien"
VALUE "FileDescription", "Netgen Meshing Software" VALUE "FileDescription", "Netgen Meshing Software"
VALUE "FileVersion", "5.1-dev" VALUE "FileVersion", "@NETGEN_VERSION@"
VALUE "InternalName", "Netgen" VALUE "InternalName", "Netgen"
VALUE "LegalCopyright", "GNU Public License (GPL)" VALUE "LegalCopyright", "GNU Lesser General Public License (LGPL)"
VALUE "OriginalFilename", "Netgen.exe" VALUE "OriginalFilename", "Netgen.exe"
VALUE "ProductName", "Netgen" VALUE "ProductName", "Netgen"
VALUE "ProductVersion", "5.1-dev" VALUE "ProductVersion", "@NETGEN_VERSION@"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"