mirror of
https://github.com/NGSolve/netgen.git
synced 2025-02-06 09:44:17 +05:00
Merge remote-tracking branch 'gitlab/master' into arm
This commit is contained in:
commit
82f817946f
@ -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( USE_SUPERBUILD "use ccache" ON)
|
||||
option( TRACE_MEMORY "Enable memory tracing" OFF)
|
||||
|
||||
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)
|
||||
|
||||
add_subdirectory(windows)
|
||||
add_subdirectory(libsrc)
|
||||
add_subdirectory(ng)
|
||||
add_subdirectory(tutorials)
|
||||
add_subdirectory(py_tutorials)
|
||||
add_subdirectory(doc)
|
||||
add_subdirectory(windows)
|
||||
add_subdirectory(nglib)
|
||||
if (USE_PYTHON)
|
||||
add_subdirectory(python)
|
||||
|
18
CONTRIBUTING.md
Normal file
18
CONTRIBUTING.md
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
# How to Contribute
|
||||
|
||||
## Reporting issues
|
||||
|
||||
If you have a problem using Netgen/NGSolve consider asking a question in our [forum](https://ngsolve.org/forum).
|
||||
|
||||
If you found a bug create an issue in the [Github Issue Tracker](https://github.com/NGSolve/netgen/issues). Please be as specific as possible, issues with a reproducible minimal failing example will get more attention than unspecific one liners :)
|
||||
|
||||
## Contributing patches
|
||||
|
||||
We love and want to encourage community engagement and will review and accept patches and contributions to this project. There are just a few steps to follow:
|
||||
|
||||
On your first contribution, to clear any legal questions, we ask you to sign our [Contributor License Agreement](CLA.pdf). Generally you have to sign this only once for Netgen or NGSolve. Please send the signed agreement to <joachim.schoeberl@tuwien.ac.at>.
|
||||
|
||||
Place a pull request on GitHub. From there we will pull it into our internal testing environment and, if approved, merge it into the main codebase.
|
||||
|
||||
If you have any questions feel free to ask on the [forum](https://ngsolve.org/forum).
|
@ -143,6 +143,7 @@ set_vars( NETGEN_CMAKE_ARGS
|
||||
USE_SPDLOG
|
||||
DEBUG_LOG
|
||||
CHECK_RANGE
|
||||
TRACE_MEMORY
|
||||
BUILD_STUB_FILES
|
||||
BUILD_FOR_CONDA
|
||||
NG_COMPILE_FLAGS
|
||||
|
@ -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)
|
||||
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)
|
||||
include_directories(${SPDLOG_INCLUDE_DIR})
|
||||
install(DIRECTORY ${SPDLOG_INCLUDE_DIR}
|
||||
|
@ -916,7 +916,7 @@ namespace ngcore
|
||||
|
||||
class NGCORE_API HashArchive : public Archive
|
||||
{
|
||||
size_t hash_value;
|
||||
size_t hash_value = 0;
|
||||
char* h;
|
||||
int offset = 0;
|
||||
public:
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "archive.hpp"
|
||||
#include "exception.hpp"
|
||||
#include "localheap.hpp"
|
||||
#include "profiler.hpp"
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace ngcore
|
||||
@ -654,6 +655,7 @@ namespace ngcore
|
||||
/// that's the data we have to delete, nullptr for not owning the memory
|
||||
T * mem_to_delete;
|
||||
|
||||
|
||||
using FlatArray<T,IndexType>::size;
|
||||
using FlatArray<T,IndexType>::data;
|
||||
using FlatArray<T,IndexType>::BASE;
|
||||
@ -698,6 +700,8 @@ namespace ngcore
|
||||
|
||||
NETGEN_INLINE Array (Array && a2)
|
||||
{
|
||||
mt.Swap(sizeof(T) * allocsize, a2.mt, sizeof(T) * a2.allocsize);
|
||||
|
||||
size = a2.size;
|
||||
data = a2.data;
|
||||
allocsize = a2.allocsize;
|
||||
@ -769,6 +773,7 @@ namespace ngcore
|
||||
NETGEN_INLINE ~Array()
|
||||
{
|
||||
delete [] mem_to_delete;
|
||||
mt.Free(sizeof(T)*allocsize);
|
||||
}
|
||||
|
||||
// Only provide this function if T is archivable
|
||||
@ -823,6 +828,7 @@ namespace ngcore
|
||||
NETGEN_INLINE const Array & Assign (size_t asize, LocalHeap & lh)
|
||||
{
|
||||
delete [] mem_to_delete;
|
||||
mt.Free(sizeof(T)*allocsize);
|
||||
size = allocsize = asize;
|
||||
data = lh.Alloc<T> (asize);
|
||||
mem_to_delete = nullptr;
|
||||
@ -930,6 +936,7 @@ namespace ngcore
|
||||
NETGEN_INLINE void DeleteAll ()
|
||||
{
|
||||
delete [] mem_to_delete;
|
||||
mt.Free(sizeof(T)*allocsize);
|
||||
mem_to_delete = NULL;
|
||||
data = 0;
|
||||
size = allocsize = 0;
|
||||
@ -961,6 +968,8 @@ namespace ngcore
|
||||
/// steal array
|
||||
NETGEN_INLINE Array & operator= (Array && a2)
|
||||
{
|
||||
mt.Swap(sizeof(T)*allocsize, a2.mt, sizeof(T)*a2.allocsize);
|
||||
|
||||
ngcore::Swap (size, a2.size);
|
||||
ngcore::Swap (data, a2.data);
|
||||
ngcore::Swap (allocsize, a2.allocsize);
|
||||
@ -1034,16 +1043,26 @@ namespace ngcore
|
||||
|
||||
NETGEN_INLINE void Swap (Array & b)
|
||||
{
|
||||
mt.Swap(sizeof(T) * allocsize, b.mt, sizeof(T) * b.allocsize);
|
||||
|
||||
ngcore::Swap (size, b.size);
|
||||
ngcore::Swap (data, b.data);
|
||||
ngcore::Swap (allocsize, b.allocsize);
|
||||
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:
|
||||
|
||||
/// resize array, at least to size minsize. copy contents
|
||||
NETGEN_INLINE void ReSize (size_t minsize);
|
||||
MemoryTracer mt;
|
||||
};
|
||||
|
||||
|
||||
@ -1056,6 +1075,7 @@ namespace ngcore
|
||||
|
||||
T * hdata = data;
|
||||
data = new T[nsize];
|
||||
mt.Alloc(sizeof(T) * nsize);
|
||||
|
||||
if (hdata)
|
||||
{
|
||||
@ -1069,6 +1089,7 @@ namespace ngcore
|
||||
for (size_t i = 0; i < mins; i++) data[i] = std::move(hdata[i]);
|
||||
#endif
|
||||
delete [] mem_to_delete;
|
||||
mt.Free(sizeof(T) * allocsize);
|
||||
}
|
||||
|
||||
mem_to_delete = data;
|
||||
|
@ -36,10 +36,15 @@ namespace ngcore
|
||||
void BitArray :: SetSize (size_t asize)
|
||||
{
|
||||
if (size == asize) return;
|
||||
if (owns_data) delete [] data;
|
||||
if (owns_data)
|
||||
{
|
||||
delete [] data;
|
||||
mt.Free(Addr(size)+1);
|
||||
}
|
||||
|
||||
size = asize;
|
||||
data = new unsigned char [Addr (size)+1];
|
||||
mt.Alloc(Addr(size)+1);
|
||||
}
|
||||
|
||||
BitArray & BitArray :: Set () throw()
|
||||
@ -136,7 +141,20 @@ namespace ngcore
|
||||
archive & size;
|
||||
if(archive.Input())
|
||||
SetSize(size);
|
||||
archive.Do(data, size/CHAR_BIT+1);
|
||||
if(archive.GetVersion("netgen") < "v6.2.2009-20")
|
||||
archive.Do(data, size/CHAR_BIT+1);
|
||||
else
|
||||
{
|
||||
archive.NeedsVersion("netgen", "v6.2.2009-20");
|
||||
archive.Do(data, size/CHAR_BIT);
|
||||
for(size_t i = 0; i < size%CHAR_BIT; i++)
|
||||
{
|
||||
size_t index = CHAR_BIT * (size/CHAR_BIT) + i;
|
||||
bool b = Test(index);
|
||||
archive & b;
|
||||
b ? SetBit(index) : Clear(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -150,6 +150,14 @@ public:
|
||||
NGCORE_API void DoArchive(Archive& archive);
|
||||
|
||||
NGCORE_API auto * Data() const { return data; }
|
||||
|
||||
const MemoryTracer& GetMemoryTracer() const { return mt; }
|
||||
void StartMemoryTracing() const
|
||||
{
|
||||
if(owns_data)
|
||||
mt.Alloc(Addr(size)+1);
|
||||
}
|
||||
|
||||
private:
|
||||
///
|
||||
unsigned char Mask (size_t i) const
|
||||
@ -159,6 +167,7 @@ private:
|
||||
size_t Addr (size_t i) const
|
||||
{ return (i / CHAR_BIT); }
|
||||
|
||||
MemoryTracer mt;
|
||||
};
|
||||
|
||||
|
||||
|
@ -29,6 +29,8 @@ namespace ngcore
|
||||
#endif // PARALLEL
|
||||
}
|
||||
|
||||
std::vector<PajeTrace::MemoryEvent> PajeTrace::memory_events;
|
||||
|
||||
// Produce no traces by default
|
||||
size_t PajeTrace::max_tracefile_size = 0;
|
||||
|
||||
@ -36,6 +38,7 @@ namespace ngcore
|
||||
// increases trace by a factor of two
|
||||
bool PajeTrace::trace_thread_counter = false;
|
||||
bool PajeTrace::trace_threads = true;
|
||||
bool PajeTrace::mem_tracing_enabled = true;
|
||||
|
||||
PajeTrace :: PajeTrace(int anthreads, std::string aname)
|
||||
{
|
||||
@ -62,6 +65,7 @@ namespace ngcore
|
||||
|
||||
jobs.reserve(reserve_size);
|
||||
timer_events.reserve(reserve_size);
|
||||
memory_events.reserve(1024*1024);
|
||||
|
||||
// sync start time when running in parallel
|
||||
#ifdef PARALLEL
|
||||
@ -72,6 +76,8 @@ namespace ngcore
|
||||
|
||||
start_time = GetTimeCounter();
|
||||
tracing_enabled = true;
|
||||
mem_tracing_enabled = true;
|
||||
n_memory_events_at_start = memory_events.size();
|
||||
}
|
||||
|
||||
PajeTrace :: ~PajeTrace()
|
||||
@ -94,6 +100,9 @@ namespace ngcore
|
||||
for(auto & link : llink)
|
||||
link.time -= start_time;
|
||||
|
||||
for(auto i : IntRange(n_memory_events_at_start, memory_events.size()))
|
||||
memory_events[i].time -= start_time;
|
||||
|
||||
NgMPI_Comm comm(MPI_COMM_WORLD);
|
||||
|
||||
if(comm.Size()==1)
|
||||
@ -237,7 +246,8 @@ namespace ngcore
|
||||
|
||||
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
|
||||
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_timer = container_type_thread; //paje.DefineContainerType( container_type_task_manager, "Timers");
|
||||
const int container_type_jobs = paje.DefineContainerType( container_type_task_manager, "Jobs");
|
||||
const int container_type_memory = paje.DefineContainerType( container_type_task_manager, "Memory usage");
|
||||
|
||||
const int state_type_job = paje.DefineStateType( container_type_jobs, "Job" );
|
||||
const int state_type_task = paje.DefineStateType( container_type_thread, "Task" );
|
||||
@ -433,12 +444,18 @@ namespace ngcore
|
||||
|
||||
int variable_type_active_threads = 0;
|
||||
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_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;
|
||||
std::vector <int> thread_aliases;
|
||||
@ -509,6 +526,30 @@ namespace ngcore
|
||||
paje.PopState( j.stop_time, state_type_job, container_jobs );
|
||||
}
|
||||
|
||||
size_t memory_at_start = 0;
|
||||
|
||||
for(const auto & i : IntRange(0, n_memory_events_at_start))
|
||||
{
|
||||
if(memory_events[i].is_alloc)
|
||||
memory_at_start += memory_events[i].size;
|
||||
else
|
||||
memory_at_start -= memory_events[i].size;
|
||||
}
|
||||
|
||||
paje.SetVariable( 0, variable_type_memory, container_memory, 1.0*memory_at_start/(1024*1024));
|
||||
|
||||
for(const auto & i : IntRange(n_memory_events_at_start, memory_events.size()))
|
||||
{
|
||||
auto & m = memory_events[i];
|
||||
if(m.size==0)
|
||||
continue;
|
||||
double size = 1.0*m.size/(1024*1024);
|
||||
if(m.is_alloc)
|
||||
paje.AddVariable( m.time, variable_type_memory, container_memory, size);
|
||||
else
|
||||
paje.SubVariable( m.time, variable_type_memory, container_memory, size);
|
||||
}
|
||||
|
||||
std::set<int> timer_ids;
|
||||
std::map<int,int> timer_aliases;
|
||||
std::map<int,std::string> timer_names;
|
||||
@ -718,7 +759,10 @@ namespace ngcore
|
||||
}
|
||||
}
|
||||
}
|
||||
WriteSunburstHTML();
|
||||
WriteTimingChart();
|
||||
#ifdef NETGEN_TRACE_MEMORY
|
||||
WriteMemoryChart("");
|
||||
#endif // NETGEN_TRACE_MEMORY
|
||||
paje.WriteEvents();
|
||||
}
|
||||
|
||||
@ -786,24 +830,25 @@ namespace ngcore
|
||||
int id = 0;
|
||||
std::map<int, TreeNode> children;
|
||||
double chart_size = 0.0; // time without children (the chart lib accumulates children sizes again)
|
||||
double time = 0.0;
|
||||
double min_time = 1e99;
|
||||
double max_time = 0.0;
|
||||
size_t calls = 0;
|
||||
double size = 0.0;
|
||||
double min_size = 1e99;
|
||||
double max_size = 0.0;
|
||||
std::string name;
|
||||
|
||||
size_t calls = 0;
|
||||
TTimePoint start_time = 0;
|
||||
};
|
||||
|
||||
void PrintNode (const TreeNode &n, int &level, std::ofstream & f);
|
||||
void PrintNode (const TreeNode &n, int &level, std::ofstream & f)
|
||||
void PrintNode (const TreeNode &n, std::ofstream & f)
|
||||
{
|
||||
f << "{ name: \"" + n.name + "\"";
|
||||
f << ", calls: " << n.calls;
|
||||
f << ", size: " << n.chart_size;
|
||||
f << ", time: " << n.time;
|
||||
f << ", min: " << n.min_time;
|
||||
f << ", max: " << n.max_time;
|
||||
f << ", avg: " << n.time/n.calls;
|
||||
f << ", value: " << n.size;
|
||||
f << ", min: " << n.min_size;
|
||||
f << ", max: " << n.max_size;
|
||||
if(n.calls)
|
||||
f << ", avg: " << n.size/n.calls;
|
||||
int size = n.children.size();
|
||||
if(size>0)
|
||||
{
|
||||
@ -811,7 +856,7 @@ namespace ngcore
|
||||
f << ", children: [";
|
||||
for(auto & c : n.children)
|
||||
{
|
||||
PrintNode(c.second, level, f);
|
||||
PrintNode(c.second, f);
|
||||
if(++i<size)
|
||||
f << " , ";
|
||||
}
|
||||
@ -820,7 +865,220 @@ namespace ngcore
|
||||
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 + " → " + 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;
|
||||
|
||||
@ -861,10 +1119,10 @@ namespace ngcore
|
||||
|
||||
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.min_time = root.time;
|
||||
root.max_time = root.time;
|
||||
root.min_size = root.size;
|
||||
root.max_size = root.size;
|
||||
|
||||
for(auto & event : events)
|
||||
{
|
||||
@ -881,7 +1139,7 @@ namespace ngcore
|
||||
if(need_init)
|
||||
{
|
||||
current->name = is_timer_event ? GetTimerName(id) : job_names[id];
|
||||
current->time = 0.0;
|
||||
current->size = 0.0;
|
||||
current->id = id;
|
||||
}
|
||||
|
||||
@ -893,73 +1151,22 @@ namespace ngcore
|
||||
std::cout << "node stack empty!" << std::endl;
|
||||
break;
|
||||
}
|
||||
double time = 1000.0*static_cast<double>(event.time-current->start_time) * seconds_per_tick;
|
||||
current->time += time;
|
||||
current->chart_size += time;
|
||||
current->min_time = std::min(current->min_time, time);
|
||||
current->max_time = std::max(current->max_time, time);
|
||||
double size = 1000.0*static_cast<double>(event.time-current->start_time) * seconds_per_tick;
|
||||
current->size += size;
|
||||
current->chart_size += size;
|
||||
current->min_size = std::min(current->min_size, size);
|
||||
current->max_size = std::max(current->max_size, size);
|
||||
current->calls++;
|
||||
|
||||
current = node_stack.back();
|
||||
current->chart_size -= time;
|
||||
current->chart_size -= size;
|
||||
node_stack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
root.chart_size = 0.0;
|
||||
|
||||
int level = 0;
|
||||
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 + " → " + 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;
|
||||
ngcore::WriteSunburstHTML( root, tracefile_name, true );
|
||||
}
|
||||
|
||||
} // namespace ngcore
|
||||
|
@ -23,18 +23,28 @@ namespace ngcore
|
||||
NGCORE_API static size_t max_tracefile_size;
|
||||
NGCORE_API static bool trace_thread_counter;
|
||||
NGCORE_API static bool trace_threads;
|
||||
NGCORE_API static bool mem_tracing_enabled;
|
||||
|
||||
bool tracing_enabled;
|
||||
TTimePoint start_time;
|
||||
int nthreads;
|
||||
size_t n_memory_events_at_start;
|
||||
|
||||
public:
|
||||
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
|
||||
// be stopped if any thread reaches this number of events
|
||||
unsigned int max_num_events_per_thread;
|
||||
|
||||
static void SetTraceMemory( bool trace_memory )
|
||||
{
|
||||
mem_tracing_enabled = trace_memory;
|
||||
}
|
||||
|
||||
static void SetTraceThreads( bool atrace_threads )
|
||||
{
|
||||
trace_threads = atrace_threads;
|
||||
@ -96,10 +106,21 @@ namespace ngcore
|
||||
bool operator < (const ThreadLink & other) const { return time < other.time; }
|
||||
};
|
||||
|
||||
struct MemoryEvent
|
||||
{
|
||||
TTimePoint time;
|
||||
size_t size;
|
||||
int id;
|
||||
bool is_alloc;
|
||||
|
||||
bool operator < (const MemoryEvent & other) const { return time < other.time; }
|
||||
};
|
||||
|
||||
std::vector<std::vector<Task> > tasks;
|
||||
std::vector<Job> jobs;
|
||||
std::vector<TimerEvent> timer_events;
|
||||
std::vector<std::vector<ThreadLink> > links;
|
||||
NGCORE_API static std::vector<MemoryEvent> memory_events;
|
||||
|
||||
public:
|
||||
NGCORE_API void StopTracing();
|
||||
@ -129,6 +150,27 @@ namespace ngcore
|
||||
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)
|
||||
{
|
||||
if(!tracing_enabled) return -1;
|
||||
|
@ -113,5 +113,9 @@ namespace ngcore
|
||||
|
||||
NgProfiler prof; // NOLINT
|
||||
|
||||
#ifdef NETGEN_TRACE_MEMORY
|
||||
std::vector<std::string> MemoryTracer::names{"all"};
|
||||
std::vector<int> MemoryTracer::parents{-1};
|
||||
#endif // NETGEN_TRACE_MEMORY
|
||||
|
||||
} // namespace ngcore
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#include "logging.hpp"
|
||||
@ -299,6 +300,161 @@ namespace ngcore
|
||||
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
|
||||
|
||||
// Helper macro to easily add multiple timers in a function for profiling
|
||||
|
@ -247,23 +247,28 @@ threads : int
|
||||
;
|
||||
|
||||
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::SetTraceThreads(threads);
|
||||
PajeTrace::SetTraceMemory(memory);
|
||||
PajeTrace::SetTraceThreadCounter(thread_counter);
|
||||
trace = new PajeTrace(TaskManager::GetMaxThreads(), filename);
|
||||
return trace;
|
||||
}), py::arg("filename")="ng.trace", py::arg("size")=1000,
|
||||
py::arg("threads")=true, py::arg("thread_counter")=false,
|
||||
py::arg("memory")=true,
|
||||
"size in Megabytes"
|
||||
)
|
||||
.def("__enter__", [](PajeTrace & self) { })
|
||||
.def("__exit__", [](PajeTrace & self, py::args) { self.StopTracing(); })
|
||||
.def("__del__", [](PajeTrace & self) { trace = nullptr; })
|
||||
.def("SetTraceThreads", &PajeTrace::SetTraceThreads)
|
||||
.def("SetTraceThreadCounter", &PajeTrace::SetTraceThreadCounter)
|
||||
.def("SetMaxTracefileSize", &PajeTrace::SetMaxTracefileSize)
|
||||
.def_static("SetTraceThreads", &PajeTrace::SetTraceThreads)
|
||||
.def_static("SetTraceThreadCounter", &PajeTrace::SetTraceThreadCounter)
|
||||
.def_static("SetMaxTracefileSize", &PajeTrace::SetMaxTracefileSize)
|
||||
#ifdef NETGEN_TRACE_MEMORY
|
||||
.def_static("WriteMemoryChart", [](string filename){ if(trace) trace->WriteMemoryChart(filename); }, py::arg("filename")="memory" )
|
||||
#endif // NETGEN_TRACE_MEMORY
|
||||
;
|
||||
|
||||
|
||||
|
@ -159,6 +159,7 @@ namespace ngcore
|
||||
NETGEN_INLINE Table (Table && tab2)
|
||||
: FlatTable<T,IndexType>(0, nullptr, nullptr)
|
||||
{
|
||||
tab2.mt.Free(tab2.GetMemUsage());
|
||||
Swap (size, tab2.size);
|
||||
Swap (index, tab2.index);
|
||||
Swap (data, tab2.data);
|
||||
@ -166,6 +167,7 @@ namespace ngcore
|
||||
|
||||
NETGEN_INLINE Table & operator= (Table && tab2)
|
||||
{
|
||||
mt.Swap(GetMemUsage(), tab2.mt, tab2.GetMemUsage());
|
||||
Swap (size, tab2.size);
|
||||
Swap (index, tab2.index);
|
||||
Swap (data, tab2.data);
|
||||
@ -177,6 +179,7 @@ namespace ngcore
|
||||
/// Delete data
|
||||
NETGEN_INLINE ~Table ()
|
||||
{
|
||||
mt.Free(GetMemUsage());
|
||||
delete [] data;
|
||||
delete [] index;
|
||||
}
|
||||
@ -188,6 +191,16 @@ namespace ngcore
|
||||
NETGEN_INLINE size_t NElements() const { return index[size]; }
|
||||
|
||||
using FlatTable<T,IndexType>::operator[];
|
||||
|
||||
NETGEN_INLINE void StartMemoryTracing (int mem_id)
|
||||
{
|
||||
mt.Alloc(GetMemUsage());
|
||||
}
|
||||
const MemoryTracer& GetMemoryTracer() const { return mt; }
|
||||
|
||||
private:
|
||||
size_t GetMemUsage() const { return size == 0 ? 0 : sizeof(T)*index[size] + sizeof(IndexType) * size+1; }
|
||||
MemoryTracer mt;
|
||||
};
|
||||
|
||||
|
||||
|
@ -160,7 +160,7 @@ namespace ngcore
|
||||
|
||||
static int cnt = 0;
|
||||
if (use_paje_trace)
|
||||
trace = new PajeTrace(num_threads, "ng" + ToString(cnt++) + ".trace");
|
||||
trace = new PajeTrace(num_threads, "ng" + ToString(cnt++));
|
||||
}
|
||||
|
||||
|
||||
|
@ -42,12 +42,11 @@ namespace netgen
|
||||
{
|
||||
Point3d p;
|
||||
in >> p.X() >> p.Y() >> p.Z();
|
||||
p.Z() *= 10;
|
||||
mesh.AddPoint (p);
|
||||
}
|
||||
|
||||
mesh.ClearFaceDescriptors();
|
||||
mesh.AddFaceDescriptor (FaceDescriptor(0,1,0,0));
|
||||
mesh.AddFaceDescriptor (FaceDescriptor(1,1,0,0));
|
||||
|
||||
in >> nbe;
|
||||
// int invert = globflags.GetDefineFlag ("invertsurfacemesh");
|
||||
|
@ -90,6 +90,9 @@ namespace netgen
|
||||
|
||||
void GenerateBoundaryLayer(Mesh& mesh, const BoundaryLayerParameters& blp)
|
||||
{
|
||||
static Timer timer("Create Boundarylayers");
|
||||
RegionTimer regt(timer);
|
||||
|
||||
int max_edge_nr = -1;
|
||||
for(const auto& seg : mesh.LineSegments())
|
||||
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++)
|
||||
{
|
||||
// copy because surfaceels array will be resized!
|
||||
@ -436,10 +443,29 @@ namespace netgen
|
||||
newel.SetIndex(si_map[sel.GetIndex()]);
|
||||
mesh.AddSurfaceElement(newel);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool has_moved = false;
|
||||
for(auto p : sel.PNums())
|
||||
if(mapto[p].Size())
|
||||
has_moved = true;
|
||||
if(has_moved)
|
||||
for(auto p : sel.PNums())
|
||||
{
|
||||
if(!mapto[p].Size())
|
||||
{
|
||||
fixed_points.SetBit(p);
|
||||
if(move_boundaries.Test(sel.GetIndex()))
|
||||
moveboundarypoint.SetBit(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(move_boundaries.Test(sel.GetIndex()))
|
||||
for(auto& p : mesh[si].PNums())
|
||||
if(mapto[p].Size())
|
||||
p = mapto[p].Last();
|
||||
{
|
||||
for(auto& p : mesh[si].PNums())
|
||||
if(mapto[p].Size())
|
||||
p = mapto[p].Last();
|
||||
}
|
||||
}
|
||||
|
||||
for(SegmentIndex sei = 0; sei < nseg; sei++)
|
||||
@ -453,13 +479,85 @@ namespace netgen
|
||||
|
||||
for(ElementIndex ei = 0; ei < ne; ei++)
|
||||
{
|
||||
auto& el = mesh[ei];
|
||||
if(!domains[el.GetIndex()])
|
||||
auto el = mesh[ei];
|
||||
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())
|
||||
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))
|
||||
|
@ -772,6 +772,7 @@ namespace netgen
|
||||
// improve delaunay - mesh by swapping !!!!
|
||||
|
||||
Mesh tempmesh;
|
||||
tempmesh.GetMemoryTracer().SetName("delaunay-tempmesh");
|
||||
|
||||
for (auto & meshpoint : mesh.Points())
|
||||
tempmesh.AddPoint (meshpoint);
|
||||
|
@ -3716,6 +3716,18 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI
|
||||
|
||||
|
||||
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++)
|
||||
{
|
||||
ElementIndex eli2 = row[k];
|
||||
@ -3723,7 +3735,6 @@ double MeshOptimize3d :: SwapImprove2 ( Mesh & mesh, OPTIMIZEGOAL goal, ElementI
|
||||
if ( eli1 != eli2 )
|
||||
{
|
||||
Element & elem2 = mesh[eli2];
|
||||
if (elem2.IsDeleted()) continue;
|
||||
if (elem2.GetType() != TET)
|
||||
continue;
|
||||
|
||||
@ -3992,8 +4003,12 @@ void MeshOptimize3d :: SwapImprove2 (Mesh & mesh, OPTIMIZEGOAL goal)
|
||||
QuickSort(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)
|
||||
cnt++;
|
||||
}
|
||||
|
||||
PrintMessage (5, cnt, " swaps performed");
|
||||
|
||||
|
@ -6642,6 +6642,7 @@ namespace netgen
|
||||
paralleltop->UpdateCoarseGrid();
|
||||
}
|
||||
#endif
|
||||
updateSignal.Emit();
|
||||
}
|
||||
|
||||
void Mesh :: BuildCurvedElements (const Refinement * ref, int aorder, bool arational)
|
||||
|
@ -172,6 +172,7 @@ namespace netgen
|
||||
const int element) const;
|
||||
|
||||
public:
|
||||
Signal<> updateSignal;
|
||||
|
||||
// store coarse mesh before hp-refinement
|
||||
unique_ptr<NgArray<HPRefElement>> hpelements;
|
||||
@ -925,6 +926,15 @@ namespace netgen
|
||||
|
||||
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)
|
||||
|
@ -1136,8 +1136,8 @@ project_boundaries : Optional[str] = None
|
||||
|
||||
.def ("Scale", [](Mesh & self, double factor)
|
||||
{
|
||||
for(auto i = 0; i<self.GetNP();i++)
|
||||
self.Point(i).Scale(factor);
|
||||
for(auto & pnt : self.Points())
|
||||
pnt.Scale(factor);
|
||||
})
|
||||
.def ("Copy", [](Mesh & self)
|
||||
{
|
||||
|
@ -4,13 +4,11 @@ else()
|
||||
add_definitions(-DINTERNAL_TCL_DEFAULT=0)
|
||||
endif()
|
||||
|
||||
set(netgen_sources ngappinit.cpp onetcl.cpp)
|
||||
if(WIN32)
|
||||
# add icon to netgen executable
|
||||
enable_language(RC)
|
||||
set(netgen_sources ${netgen_sources} ../windows/netgen.rc)
|
||||
# Don't use ccache here due to incompatibility with the resource compiler
|
||||
set_directory_properties(PROPERTIES RULE_LAUNCH_COMPILE "")
|
||||
# add icon and version info to netgen executable
|
||||
enable_language(RC)
|
||||
# Don't use ccache here due to incompatibility with the resource compiler
|
||||
set_directory_properties(PROPERTIES RULE_LAUNCH_COMPILE "")
|
||||
endif(WIN32)
|
||||
|
||||
if(USE_GUI)
|
||||
@ -23,6 +21,9 @@ if(USE_GUI)
|
||||
)
|
||||
|
||||
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 PRIVATE ${LIBTOGL} ${ZLIB_LIBRARIES} ${JPEG_LIBRARIES} ${FFMPEG_LIBRARIES} ${X11_Xmu_LIB} ${X11_X11_LIB} ${OCC_LIBRARIES} )
|
||||
|
@ -293,18 +293,18 @@
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
14.466,
|
||||
161.38
|
||||
16.89,
|
||||
158.0
|
||||
],
|
||||
"angles_trig": [
|
||||
13.564,
|
||||
150.65
|
||||
16.739,
|
||||
133.14
|
||||
],
|
||||
"ne1d": 32,
|
||||
"ne2d": 220,
|
||||
"ne3d": 563,
|
||||
"quality_histogram": "[0, 0, 0, 3, 3, 7, 24, 22, 35, 34, 40, 43, 45, 60, 61, 53, 58, 41, 27, 7]",
|
||||
"total_badness": 960.07699692
|
||||
"ne3d": 551,
|
||||
"quality_histogram": "[0, 0, 0, 0, 0, 3, 4, 16, 23, 34, 48, 43, 50, 61, 70, 53, 51, 48, 37, 10]",
|
||||
"total_badness": 860.81905284
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
@ -473,7 +473,7 @@
|
||||
"ne2d": 726,
|
||||
"ne3d": 2167,
|
||||
"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": [
|
||||
@ -860,18 +860,18 @@
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
16.061,
|
||||
157.39
|
||||
8.4923,
|
||||
161.34
|
||||
],
|
||||
"angles_trig": [
|
||||
16.851,
|
||||
20.122,
|
||||
127.45
|
||||
],
|
||||
"ne1d": 36,
|
||||
"ne2d": 152,
|
||||
"ne3d": 385,
|
||||
"quality_histogram": "[0, 0, 0, 0, 0, 10, 8, 21, 24, 22, 29, 37, 42, 28, 43, 24, 38, 22, 25, 12]",
|
||||
"total_badness": 647.21940974
|
||||
"ne3d": 358,
|
||||
"quality_histogram": "[0, 0, 1, 0, 0, 2, 5, 11, 21, 19, 22, 22, 31, 29, 35, 39, 57, 37, 17, 10]",
|
||||
"total_badness": 559.67849284
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
@ -1014,18 +1014,18 @@
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
5.7043,
|
||||
170.47
|
||||
5.6074,
|
||||
169.95
|
||||
],
|
||||
"angles_trig": [
|
||||
8.0227,
|
||||
160.66
|
||||
7.5945,
|
||||
159.99
|
||||
],
|
||||
"ne1d": 0,
|
||||
"ne2d": 192,
|
||||
"ne3d": 749,
|
||||
"quality_histogram": "[0, 2, 30, 63, 86, 89, 71, 68, 67, 54, 50, 43, 27, 28, 17, 23, 13, 9, 7, 2]",
|
||||
"total_badness": 2339.9827516
|
||||
"ne3d": 748,
|
||||
"quality_histogram": "[0, 0, 30, 62, 87, 77, 80, 61, 72, 38, 54, 43, 34, 27, 27, 20, 18, 10, 7, 1]",
|
||||
"total_badness": 2287.1659209
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
@ -1391,9 +1391,9 @@
|
||||
],
|
||||
"ne1d": 5988,
|
||||
"ne2d": 11102,
|
||||
"ne3d": 29343,
|
||||
"quality_histogram": "[3, 4, 5, 8, 14, 42, 121, 248, 691, 1040, 1542, 2504, 3118, 3920, 4331, 4281, 3366, 2421, 1367, 317]",
|
||||
"total_badness": 43497.876838
|
||||
"ne3d": 29344,
|
||||
"quality_histogram": "[3, 4, 5, 8, 14, 45, 122, 251, 692, 1044, 1527, 2497, 3115, 3927, 4328, 4293, 3367, 2421, 1363, 318]",
|
||||
"total_badness": 43503.906462
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
@ -1408,7 +1408,7 @@
|
||||
"ne2d": 23964,
|
||||
"ne3d": 80995,
|
||||
"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": [
|
||||
@ -1490,7 +1490,7 @@
|
||||
{
|
||||
"angles_tet": [
|
||||
20.701,
|
||||
144.6
|
||||
141.98
|
||||
],
|
||||
"angles_trig": [
|
||||
22.443,
|
||||
@ -1498,9 +1498,9 @@
|
||||
],
|
||||
"ne1d": 1862,
|
||||
"ne2d": 19474,
|
||||
"ne3d": 136546,
|
||||
"quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 12, 59, 281, 864, 2538, 6435, 13014, 21236, 29154, 31109, 24006, 7837]",
|
||||
"total_badness": 165965.29798
|
||||
"ne3d": 136541,
|
||||
"quality_histogram": "[0, 0, 0, 0, 0, 0, 0, 1, 8, 59, 274, 862, 2533, 6435, 12998, 21248, 29157, 31131, 24003, 7832]",
|
||||
"total_badness": 165944.59425
|
||||
}
|
||||
],
|
||||
"lense.in2d": [
|
||||
@ -1795,7 +1795,7 @@
|
||||
"ne2d": 830,
|
||||
"ne3d": 2488,
|
||||
"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": [
|
||||
@ -2045,18 +2045,18 @@
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
11.213,
|
||||
163.54
|
||||
11.356,
|
||||
162.52
|
||||
],
|
||||
"angles_trig": [
|
||||
13.446,
|
||||
152.87
|
||||
16.741,
|
||||
141.37
|
||||
],
|
||||
"ne1d": 232,
|
||||
"ne2d": 598,
|
||||
"ne3d": 1380,
|
||||
"quality_histogram": "[0, 0, 0, 2, 10, 15, 36, 48, 63, 92, 116, 131, 160, 158, 151, 113, 125, 91, 56, 13]",
|
||||
"total_badness": 2309.6335564
|
||||
"ne3d": 1418,
|
||||
"quality_histogram": "[0, 0, 0, 2, 9, 14, 27, 47, 66, 97, 109, 150, 161, 159, 147, 133, 119, 96, 66, 16]",
|
||||
"total_badness": 2344.2576172
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
@ -2132,8 +2132,8 @@
|
||||
"ne1d": 570,
|
||||
"ne2d": 1202,
|
||||
"ne3d": 1839,
|
||||
"quality_histogram": "[2, 21, 37, 57, 67, 78, 110, 136, 161, 177, 190, 158, 155, 149, 115, 78, 69, 51, 24, 4]",
|
||||
"total_badness": 4553.9697099
|
||||
"quality_histogram": "[2, 21, 37, 57, 66, 75, 111, 134, 161, 173, 193, 158, 151, 145, 117, 81, 73, 54, 25, 5]",
|
||||
"total_badness": 4538.6020288
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
@ -2445,8 +2445,8 @@
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
15.158,
|
||||
158.0
|
||||
15.154,
|
||||
159.78
|
||||
],
|
||||
"angles_trig": [
|
||||
17.101,
|
||||
@ -2454,14 +2454,14 @@
|
||||
],
|
||||
"ne1d": 410,
|
||||
"ne2d": 606,
|
||||
"ne3d": 796,
|
||||
"quality_histogram": "[0, 0, 0, 0, 1, 3, 5, 6, 28, 40, 56, 62, 82, 83, 128, 96, 88, 75, 29, 14]",
|
||||
"total_badness": 1204.2331383
|
||||
"ne3d": 791,
|
||||
"quality_histogram": "[0, 0, 0, 0, 2, 3, 4, 7, 33, 42, 54, 61, 88, 86, 118, 92, 89, 72, 29, 11]",
|
||||
"total_badness": 1208.0636246
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
12.907,
|
||||
159.86
|
||||
158.51
|
||||
],
|
||||
"angles_trig": [
|
||||
11.963,
|
||||
@ -2469,9 +2469,9 @@
|
||||
],
|
||||
"ne1d": 510,
|
||||
"ne2d": 1004,
|
||||
"ne3d": 1838,
|
||||
"quality_histogram": "[0, 0, 0, 4, 9, 30, 35, 80, 75, 109, 121, 152, 156, 200, 242, 206, 210, 105, 80, 24]",
|
||||
"total_badness": 3018.9734455
|
||||
"ne3d": 1859,
|
||||
"quality_histogram": "[0, 0, 0, 3, 7, 29, 43, 74, 68, 95, 115, 158, 153, 213, 250, 232, 206, 107, 81, 25]",
|
||||
"total_badness": 3021.4076425
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
@ -2997,18 +2997,18 @@
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
1.6657,
|
||||
174.24
|
||||
1.9786,
|
||||
173.68
|
||||
],
|
||||
"angles_trig": [
|
||||
4.1081,
|
||||
164.43
|
||||
3.8198,
|
||||
165.45
|
||||
],
|
||||
"ne1d": 0,
|
||||
"ne2d": 692,
|
||||
"ne3d": 2737,
|
||||
"quality_histogram": "[17, 200, 365, 335, 363, 301, 234, 187, 154, 143, 106, 84, 56, 48, 38, 45, 27, 19, 12, 3]",
|
||||
"total_badness": 13234.755766
|
||||
"ne3d": 2726,
|
||||
"quality_histogram": "[19, 190, 366, 339, 352, 304, 237, 182, 157, 143, 110, 86, 53, 46, 34, 43, 30, 24, 10, 1]",
|
||||
"total_badness": 13096.6735
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
@ -3365,33 +3365,33 @@
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
19.944,
|
||||
152.59
|
||||
20.148,
|
||||
153.82
|
||||
],
|
||||
"angles_trig": [
|
||||
25.599,
|
||||
123.4
|
||||
118.3
|
||||
],
|
||||
"ne1d": 68,
|
||||
"ne2d": 100,
|
||||
"ne3d": 130,
|
||||
"quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 1, 3, 6, 7, 9, 5, 13, 21, 16, 21, 19, 7, 1]",
|
||||
"total_badness": 187.02414176
|
||||
"ne3d": 135,
|
||||
"quality_histogram": "[0, 0, 0, 0, 0, 0, 1, 0, 4, 5, 2, 9, 5, 18, 25, 16, 22, 20, 7, 1]",
|
||||
"total_badness": 190.82756065
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
12.268,
|
||||
164.21
|
||||
164.96
|
||||
],
|
||||
"angles_trig": [
|
||||
15.1,
|
||||
144.2
|
||||
15.698,
|
||||
145.1
|
||||
],
|
||||
"ne1d": 102,
|
||||
"ne2d": 238,
|
||||
"ne3d": 468,
|
||||
"quality_histogram": "[0, 0, 1, 10, 5, 27, 33, 42, 51, 36, 38, 28, 35, 40, 29, 26, 37, 24, 4, 2]",
|
||||
"total_badness": 980.42864262
|
||||
"ne3d": 471,
|
||||
"quality_histogram": "[0, 0, 1, 6, 3, 23, 25, 45, 63, 40, 34, 29, 30, 34, 27, 33, 43, 25, 8, 2]",
|
||||
"total_badness": 950.55701299
|
||||
},
|
||||
{
|
||||
"angles_tet": [
|
||||
|
@ -92,3 +92,18 @@ def test_splitted_surface():
|
||||
mesh = ngs.Mesh(mesh)
|
||||
assert ngs.Integrate(1, mesh) == pytest.approx(1)
|
||||
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
1
windows/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
netgen.rc
|
@ -0,0 +1,4 @@
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/netgen.rc.template"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/netgen.rc"
|
||||
IMMEDIATE @ONLY)
|
@ -7,7 +7,7 @@
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
#include <windows.h>
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
@ -35,8 +35,8 @@ LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,1,0,0
|
||||
PRODUCTVERSION 5,1,0,0
|
||||
FILEVERSION @NETGEN_VERSION_MAJOR@,@NETGEN_VERSION_MINOR@,@NETGEN_VERSION_PATCH@,@NETGEN_VERSION_TWEAK@
|
||||
PRODUCTVERSION @NETGEN_VERSION_MAJOR@,@NETGEN_VERSION_MINOR@,@NETGEN_VERSION_PATCH@,@NETGEN_VERSION_TWEAK@
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x3L
|
||||
@ -51,14 +51,14 @@ BEGIN
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Vienna UT"
|
||||
VALUE "CompanyName", "TU Wien"
|
||||
VALUE "FileDescription", "Netgen Meshing Software"
|
||||
VALUE "FileVersion", "5.1-dev"
|
||||
VALUE "FileVersion", "@NETGEN_VERSION@"
|
||||
VALUE "InternalName", "Netgen"
|
||||
VALUE "LegalCopyright", "GNU Public License (GPL)"
|
||||
VALUE "LegalCopyright", "GNU Lesser General Public License (LGPL)"
|
||||
VALUE "OriginalFilename", "Netgen.exe"
|
||||
VALUE "ProductName", "Netgen"
|
||||
VALUE "ProductVersion", "5.1-dev"
|
||||
VALUE "ProductVersion", "@NETGEN_VERSION@"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
Loading…
Reference in New Issue
Block a user